From b1918813854db703b8d99e4fd6bf9854d71d8b6b Mon Sep 17 00:00:00 2001 From: Manfred Riem Date: Mon, 30 Dec 2024 12:45:42 -0600 Subject: [PATCH] Fixes #4441 - Add security role refs to SecurityManager API (#4442) --- .../piranha/core/api/SecurityManager.java | 15 ++++ .../core/api/SecurityRoleReference.java | 82 +++++++++++++++++++ .../core/impl/DefaultSecurityManager.java | 19 +++++ extension/exousia/pom.xml | 7 -- .../exousia/AuthorizationPostInitializer.java | 7 +- .../exousia/PiranhaToExousiaConverter.java | 66 +++++---------- .../exousia/src/main/java/module-info.java | 1 - .../servlet/ServletSecurityManager.java | 21 ++++- .../extension/webxml/WebXmlExtension.java | 6 ++ .../extension/webxml/WebXmlInitializer.java | 6 ++ .../internal/InternalWebXmlProcessor.java | 17 ++++ .../src/test/webxml/parse4/WEB-INF/web.xml | 18 ++++ 12 files changed, 203 insertions(+), 62 deletions(-) create mode 100644 core/api/src/main/java/cloud/piranha/core/api/SecurityRoleReference.java diff --git a/core/api/src/main/java/cloud/piranha/core/api/SecurityManager.java b/core/api/src/main/java/cloud/piranha/core/api/SecurityManager.java index b5612e7d25..52ad124c30 100644 --- a/core/api/src/main/java/cloud/piranha/core/api/SecurityManager.java +++ b/core/api/src/main/java/cloud/piranha/core/api/SecurityManager.java @@ -33,6 +33,7 @@ import java.io.IOException; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -209,6 +210,13 @@ default String getRealmName() { * @return the security constraints. */ List getSecurityConstraints(); + + /** + * Get the security role references. + * + * @return the security role references. + */ + Map> getSecurityRoleReferences(); /** * Get the handler that may be used by the login method to contact an @@ -365,6 +373,13 @@ default void setRealmName(String realmName) { * @param securityConstraints the security constraints. */ void setSecurityConstraints(List securityConstraints); + + /** + * Set the security role references. + * + * @param securityRoleReferences the security role references. + */ + void setSecurityRoleReferences(Map> securityRoleReferences); /** * Set the handler that may be used by the login method to contact an diff --git a/core/api/src/main/java/cloud/piranha/core/api/SecurityRoleReference.java b/core/api/src/main/java/cloud/piranha/core/api/SecurityRoleReference.java new file mode 100644 index 0000000000..360649ee7e --- /dev/null +++ b/core/api/src/main/java/cloud/piranha/core/api/SecurityRoleReference.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.core.api; + +/** + * A security role ref(erence). + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public class SecurityRoleReference { + + /** + * Stores the role link. + */ + private String roleLink; + + /** + * Stores the role name. + */ + private String roleName; + + /** + * Get the role link. + * + * @return the role link. + */ + public String getRoleLink() { + return roleLink; + } + + /** + * Get the role name. + * + * @return the role name. + */ + public String getRoleName() { + return roleName; + } + + /** + * Set the role link. + * + * @param roleLink the role link. + */ + public void setRoleLink(String roleLink) { + this.roleLink = roleLink; + } + + /** + * Set the role name. + * + * @param roleName the role name. + */ + public void setRoleName(String roleName) { + this.roleName = roleName; + } +} diff --git a/core/impl/src/main/java/cloud/piranha/core/impl/DefaultSecurityManager.java b/core/impl/src/main/java/cloud/piranha/core/impl/DefaultSecurityManager.java index fd9ac8d4cd..d123936b59 100644 --- a/core/impl/src/main/java/cloud/piranha/core/impl/DefaultSecurityManager.java +++ b/core/impl/src/main/java/cloud/piranha/core/impl/DefaultSecurityManager.java @@ -28,6 +28,7 @@ package cloud.piranha.core.impl; import cloud.piranha.core.api.SecurityConstraint; +import cloud.piranha.core.api.SecurityRoleReference; import cloud.piranha.core.api.WebApplication; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -35,7 +36,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -53,12 +56,18 @@ public class DefaultSecurityManager implements cloud.piranha.core.api.SecurityMa * Stores the security constraints. */ private List securityConstraints; + + /** + * Stores the security role references. + */ + private Map> securityRoleReferences; /** * Constructor. */ public DefaultSecurityManager() { securityConstraints = new ArrayList<>(); + securityRoleReferences = new HashMap<>(); } @Override @@ -80,6 +89,11 @@ public List getSecurityConstraints() { return securityConstraints; } + @Override + public Map> getSecurityRoleReferences() { + return securityRoleReferences; + } + @Override public WebApplication getWebApplication() { return null; @@ -104,6 +118,11 @@ public void setSecurityConstraints(List securityConstraints) this.securityConstraints = securityConstraints; } + @Override + public void setSecurityRoleReferences(Map> securityRoleReferences) { + this.securityRoleReferences = securityRoleReferences; + } + @Override public void setWebApplication(WebApplication webApplication) { } diff --git a/extension/exousia/pom.xml b/extension/exousia/pom.xml index c949eb60ce..dec28b43c3 100644 --- a/extension/exousia/pom.xml +++ b/extension/exousia/pom.xml @@ -52,12 +52,5 @@ javassist 3.29.2-GA - - - cloud.piranha.extension - piranha-extension-webxml - ${project.version} - provided - diff --git a/extension/exousia/src/main/java/cloud/piranha/extension/exousia/AuthorizationPostInitializer.java b/extension/exousia/src/main/java/cloud/piranha/extension/exousia/AuthorizationPostInitializer.java index a3ca42645d..33e7e571c7 100644 --- a/extension/exousia/src/main/java/cloud/piranha/extension/exousia/AuthorizationPostInitializer.java +++ b/extension/exousia/src/main/java/cloud/piranha/extension/exousia/AuthorizationPostInitializer.java @@ -51,7 +51,6 @@ import org.glassfish.exousia.mapping.SecurityRoleRef; import cloud.piranha.core.api.WebApplication; -import cloud.piranha.extension.webxml.WebXmlManager; import jakarta.security.jacc.PolicyConfiguration; import jakarta.security.jacc.PolicyContextException; import jakarta.servlet.FilterRegistration; @@ -232,13 +231,9 @@ private List getConstraintsFromSecurityManager(WebApplicatio * @throws ServletException when a Servlet error occurs. */ public Map> getSecurityRoleRefsFromWebXml(WebApplication webApplication) throws ServletException { - WebXmlManager manager = (WebXmlManager) webApplication.getAttribute("cloud.piranha.extension.webxml.WebXmlManager"); - return piranhaToExousiaConverter.getSecurityRoleRefsFromWebXml(webApplication.getServletRegistrations().keySet(), manager.getWebXml()); + return piranhaToExousiaConverter.getSecurityRoleRefsFromSecurityManager(webApplication.getServletRegistrations().keySet(), webApplication); } - - - private boolean hasPermissionsSet(ServletContext servletContext) { return getOptionalAttribute(servletContext, UNCHECKED_PERMISSIONS) != null || getOptionalAttribute(servletContext, PERROLE_PERMISSIONS) != null; diff --git a/extension/exousia/src/main/java/cloud/piranha/extension/exousia/PiranhaToExousiaConverter.java b/extension/exousia/src/main/java/cloud/piranha/extension/exousia/PiranhaToExousiaConverter.java index 0bd831f4c8..cfd3942177 100644 --- a/extension/exousia/src/main/java/cloud/piranha/extension/exousia/PiranhaToExousiaConverter.java +++ b/extension/exousia/src/main/java/cloud/piranha/extension/exousia/PiranhaToExousiaConverter.java @@ -29,16 +29,12 @@ import cloud.piranha.core.api.SecurityManager; import cloud.piranha.core.api.SecurityWebResourceCollection; -import cloud.piranha.extension.webxml.WebXmlServletSecurityRoleRef; -import cloud.piranha.extension.webxml.WebXml; -import cloud.piranha.extension.webxml.WebXmlServlet; +import cloud.piranha.core.api.WebApplication; import jakarta.servlet.ServletSecurityElement; import jakarta.servlet.annotation.ServletSecurity; import static jakarta.servlet.annotation.ServletSecurity.TransportGuarantee.CONFIDENTIAL; import static jakarta.servlet.annotation.ServletSecurity.TransportGuarantee.NONE; import java.util.ArrayList; -import java.util.Collections; -import static java.util.Collections.emptyList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -112,7 +108,7 @@ public List getConstraintsFromSecurityManager(SecurityManage List constraints = new ArrayList<>(); - for (cloud.piranha.core.api.SecurityConstraint xmlConstraint + for (cloud.piranha.core.api.SecurityConstraint xmlConstraint : securityManager.getSecurityConstraints()) { List webResourceCollections = new ArrayList<>(); @@ -135,55 +131,31 @@ public List getConstraintsFromSecurityManager(SecurityManage } /** - * Get the security role refs from web.xml + * Get the security role refs from the web application. * * @param servletNames the servlet names. - * @param webXml the web.xml. + * @param webApplication the web application. * @return the security role refs. */ - public Map> getSecurityRoleRefsFromWebXml(Set servletNames, WebXml webXml) { + public Map> getSecurityRoleRefsFromSecurityManager(Set servletNames, WebApplication webApplication) { Map> securityRoleRefs = new HashMap<>(); + SecurityManager securityManager = webApplication.getManager().getSecurityManager(); for (String servletName : servletNames) { - securityRoleRefs.put(servletName, webXml == null ? emptyList() : getSecurityRoleRefsByServletName(webXml, servletName)); - } - - return securityRoleRefs; - } - - private List getSecurityRoleRefsByServletName(WebXml webXml, String servletName) { - List piranhaSecurityRoleRefs = getWebXmlSecurityRoleRefsByServletName(webXml, servletName); - if (piranhaSecurityRoleRefs.isEmpty()) { - return Collections.emptyList(); - } - - List exousiaSecurityRoleRefs = new ArrayList<>(); - - for (WebXmlServletSecurityRoleRef piranhaSecurityRoleRef : piranhaSecurityRoleRefs) { - exousiaSecurityRoleRefs.add(new SecurityRoleRef( - piranhaSecurityRoleRef.roleName(), - piranhaSecurityRoleRef.roleLink())); - } - - return exousiaSecurityRoleRefs; - } - - private List getWebXmlSecurityRoleRefsByServletName(WebXml webXml, String servletName) { - WebXmlServlet servlet = getServletByName(webXml, servletName); - if (servlet == null) { - return emptyList(); - } - - return servlet.getSecurityRoleRefs(); - } - - private WebXmlServlet getServletByName(WebXml webXml, String servletName) { - for (WebXmlServlet servlet : webXml.getServlets()) { - if (servlet.getServletName().equals(servletName)) { - return servlet; + List securityRoleRefList = new ArrayList<>(); + if (securityManager.getSecurityRoleReferences().get(servletName) != null) { + securityManager.getSecurityRoleReferences().get(servletName).forEach( + roleReference -> { + SecurityRoleRef securityRole = new SecurityRoleRef( + roleReference.getRoleName(), + roleReference.getRoleLink()); + securityRoleRefList.add(securityRole); + } + ); } + securityRoleRefs.put(servletName, securityRoleRefList); } - return null; + return securityRoleRefs; } -} \ No newline at end of file +} diff --git a/extension/exousia/src/main/java/module-info.java b/extension/exousia/src/main/java/module-info.java index 824faa0229..dafd7d667c 100644 --- a/extension/exousia/src/main/java/module-info.java +++ b/extension/exousia/src/main/java/module-info.java @@ -45,6 +45,5 @@ requires cloud.piranha.core.impl; requires jakarta.security.jacc; requires jakarta.servlet; - requires static cloud.piranha.extension.webxml; requires transitive org.glassfish.exousia; } diff --git a/extension/security-servlet/src/main/java/cloud/piranha/extension/security/servlet/ServletSecurityManager.java b/extension/security-servlet/src/main/java/cloud/piranha/extension/security/servlet/ServletSecurityManager.java index 6cc449eac5..a9595a3383 100644 --- a/extension/security-servlet/src/main/java/cloud/piranha/extension/security/servlet/ServletSecurityManager.java +++ b/extension/security-servlet/src/main/java/cloud/piranha/extension/security/servlet/ServletSecurityManager.java @@ -44,6 +44,7 @@ import cloud.piranha.core.api.AuthenticatedIdentity; import cloud.piranha.core.api.SecurityConstraint; import cloud.piranha.core.api.SecurityManager; +import cloud.piranha.core.api.SecurityRoleReference; import cloud.piranha.core.api.WebApplication; import cloud.piranha.core.api.WebApplicationRequest; import cloud.piranha.core.impl.DefaultAuthenticatedIdentity; @@ -54,7 +55,9 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.glassfish.epicyro.config.helper.Caller; import org.glassfish.epicyro.services.DefaultAuthenticationService; @@ -101,6 +104,11 @@ public class ServletSecurityManager implements SecurityManager { */ protected List securityConstraints; + /** + * Stores the security role references. + */ + protected Map> securityRoleReferences; + /** * Handler for the specific HttpServletRequest#login method call */ @@ -115,7 +123,8 @@ public class ServletSecurityManager implements SecurityManager { * Constructor. */ public ServletSecurityManager() { - this.securityConstraints = new ArrayList<>(); + securityConstraints = new ArrayList<>(); + securityRoleReferences = new HashMap<>(); } @Override @@ -236,6 +245,11 @@ public List getSecurityConstraints() { return securityConstraints; } + @Override + public Map> getSecurityRoleReferences() { + return securityRoleReferences; + } + private String getServletName(HttpServletRequest request) { ServletConfig servletConfig = (ServletConfig) request.getAttribute(DefaultServletEnvironment.class.getName()); if (servletConfig != null && servletConfig.getServletName() != null) { @@ -347,6 +361,11 @@ public void setSecurityConstraints(List securityConstraints) this.securityConstraints = securityConstraints; } + @Override + public void setSecurityRoleReferences(Map> securityRoleReferences) { + this.securityRoleReferences = securityRoleReferences; + } + @Override public void setUsernamePasswordLoginHandler(UsernamePasswordLoginHandler usernamePasswordLoginHandler) { this.usernamePasswordLoginHandler = usernamePasswordLoginHandler; diff --git a/extension/webxml/src/main/java/cloud/piranha/extension/webxml/WebXmlExtension.java b/extension/webxml/src/main/java/cloud/piranha/extension/webxml/WebXmlExtension.java index 1f6295efea..daa12d96f1 100644 --- a/extension/webxml/src/main/java/cloud/piranha/extension/webxml/WebXmlExtension.java +++ b/extension/webxml/src/main/java/cloud/piranha/extension/webxml/WebXmlExtension.java @@ -48,6 +48,12 @@ public class WebXmlExtension implements WebApplicationExtension { */ private static final Logger LOGGER = System.getLogger(WebXmlExtension.class.getName()); + /** + * Constructor. + */ + public WebXmlExtension() { + } + /** * Configure the web application. * diff --git a/extension/webxml/src/main/java/cloud/piranha/extension/webxml/WebXmlInitializer.java b/extension/webxml/src/main/java/cloud/piranha/extension/webxml/WebXmlInitializer.java index 00d581da9e..18e1618640 100644 --- a/extension/webxml/src/main/java/cloud/piranha/extension/webxml/WebXmlInitializer.java +++ b/extension/webxml/src/main/java/cloud/piranha/extension/webxml/WebXmlInitializer.java @@ -57,6 +57,12 @@ public class WebXmlInitializer implements ServletContainerInitializer { */ private static final Logger LOGGER = System.getLogger(WebXmlInitializer.class.getName()); + /** + * Constructor. + */ + public WebXmlInitializer() { + } + /** * On startup. * diff --git a/extension/webxml/src/main/java/cloud/piranha/extension/webxml/internal/InternalWebXmlProcessor.java b/extension/webxml/src/main/java/cloud/piranha/extension/webxml/internal/InternalWebXmlProcessor.java index e555af3e4a..8feeeb3df6 100644 --- a/extension/webxml/src/main/java/cloud/piranha/extension/webxml/internal/InternalWebXmlProcessor.java +++ b/extension/webxml/src/main/java/cloud/piranha/extension/webxml/internal/InternalWebXmlProcessor.java @@ -49,6 +49,7 @@ import cloud.piranha.core.api.LocaleEncodingManager; import cloud.piranha.core.api.SecurityConstraint; import cloud.piranha.core.api.SecurityManager; +import cloud.piranha.core.api.SecurityRoleReference; import cloud.piranha.core.api.SecurityWebResourceCollection; import cloud.piranha.core.api.WebApplication; import cloud.piranha.extension.webxml.WebXml; @@ -67,11 +68,13 @@ import cloud.piranha.core.impl.DefaultJspConfigDescriptor; import cloud.piranha.core.impl.DefaultTaglibDescriptor; import cloud.piranha.extension.webxml.WebXmlSecurityConstraint; +import cloud.piranha.extension.webxml.WebXmlServletSecurityRoleRef; import jakarta.servlet.DispatcherType; import jakarta.servlet.FilterRegistration; import jakarta.servlet.MultipartConfigElement; import jakarta.servlet.ServletRegistration; import jakarta.servlet.descriptor.JspConfigDescriptor; +import java.util.ArrayList; /** * The web.xml / web-fragment.xml processor. @@ -540,6 +543,20 @@ private void processServlets(WebApplication webApplication, WebXml webXml) { servletRegistration.setInitParameter(initParam.name(), initParam.value()); } }); + + SecurityManager securityManager = webApplication.getManager().getSecurityManager(); + for(WebXmlServletSecurityRoleRef roleRef : servlet.getSecurityRoleRefs()) { + String servletName = servlet.getServletName(); + List roleReferences = securityManager.getSecurityRoleReferences().get(servletName); + if (roleReferences == null) { + roleReferences = new ArrayList<>(); + securityManager.getSecurityRoleReferences().put(servletName, roleReferences); + } + SecurityRoleReference roleReference = new SecurityRoleReference(); + roleReference.setRoleName(roleRef.roleName()); + roleReference.setRoleLink(roleRef.roleLink()); + roleReferences.add(roleReference); + } LOGGER.log(DEBUG, () -> "Configured Servlet: " + servlet.getServletName()); } diff --git a/extension/webxml/src/test/webxml/parse4/WEB-INF/web.xml b/extension/webxml/src/test/webxml/parse4/WEB-INF/web.xml index 6e56c3cc12..b1dba0c803 100644 --- a/extension/webxml/src/test/webxml/parse4/WEB-INF/web.xml +++ b/extension/webxml/src/test/webxml/parse4/WEB-INF/web.xml @@ -4,10 +4,28 @@ Test Servlet cloud.piranha.extension.webxml.tests.TestServlet + + mydescription + myrole + myrole + Test Servlet /foo /bar + + myrole + + + + mywebresourcename + mydescription + /* + + + myrole + +