diff --git a/Jenkinsfile b/Jenkinsfile index 1244eb8fa35..1b72b0cc70e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -216,7 +216,7 @@ spec: } post { always { - archiveArtifacts artifacts: "**/server.log", onlyIfSuccessful: false + archiveArtifacts artifacts: "**/server.log*", onlyIfSuccessful: false junit testResults: '**/*-reports/*.xml', allowEmptyResults: false } } diff --git a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/node/runtime/common/DescriptorPrincipalName.java b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/node/runtime/common/DescriptorPrincipalName.java new file mode 100644 index 00000000000..3fa8107baa5 --- /dev/null +++ b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/node/runtime/common/DescriptorPrincipalName.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package com.sun.enterprise.deployment.node.runtime.common; + +import java.io.Serializable; +import java.security.Principal; +import java.util.Objects; + +import org.glassfish.security.common.UserPrincipal; + +/** + * {@link Principal} loaded from XML descriptor. + * When the equals method is used, it compares just principal names and that the other object + * is an {@link Principal} instance too. + */ +// Must be UserPrincipal, because RoleMapper.internalAssignRole knows just that and Group. +public class DescriptorPrincipalName implements UserPrincipal, Serializable { + + private static final long serialVersionUID = -640182254691955451L; + + private final String name; + + /** + * @param name must not be null. + */ + public DescriptorPrincipalName(String name) { + this.name = Objects.requireNonNull(name, "XML principal-name element must not be null."); + } + + + @Override + public String getName() { + return name; + } + + + @Override + public int hashCode() { + return name.hashCode(); + } + + + /** + * We match user principals just by name. + * This is used in Jakarta Security to resolve authorisation. + */ + @Override + public boolean equals(Object o) { + if (o instanceof Principal) { + Principal other = (Principal) o; + return getName().equals(other.getName()); + } + return false; + } + + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + getName() + "]"; + } +} diff --git a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/runtime/common/PrincipalNameDescriptor.java b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/runtime/common/PrincipalNameDescriptor.java index 69a73b56697..99ebf66f7ca 100644 --- a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/runtime/common/PrincipalNameDescriptor.java +++ b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/runtime/common/PrincipalNameDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2022, 2024 Contributors to the Eclipse Foundation * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -17,11 +17,12 @@ package com.sun.enterprise.deployment.runtime.common; +import com.sun.enterprise.deployment.node.runtime.common.DescriptorPrincipalName; + import java.lang.reflect.Constructor; import java.security.Principal; import org.glassfish.deployment.common.Descriptor; -import org.glassfish.security.common.UserNameAndPassword; /** * This is an in memory representation of the principal-name with its name of @@ -53,7 +54,7 @@ public String getName() { */ public String getClassName() { if (className == null) { - return UserNameAndPassword.class.getName(); + return DescriptorPrincipalName.class.getName(); } return className; } diff --git a/appserver/itest-tools/src/main/java/org/glassfish/main/itest/tools/TestUtilities.java b/appserver/itest-tools/src/main/java/org/glassfish/main/itest/tools/TestUtilities.java new file mode 100644 index 00000000000..bb6c4de25c3 --- /dev/null +++ b/appserver/itest-tools/src/main/java/org/glassfish/main/itest/tools/TestUtilities.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.main.itest.tools; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.HashSet; +import java.util.Set; + +/** + * Tools useful just for tests, so they don't belong to any application code. + */ +public final class TestUtilities { + + private TestUtilities() { + // hidden + } + + + /** + * Deletes files if they exist. + * If it existed but was not possible to delete the file, uses NIO to delete it again - NIO + * throws an exception in such case. + *

+ * Attempts to delete all files and throws the {@link IOException} if any of them was not + * possible to delete. Therefore this method should be the last call in your cleanup method (ie. + * AfterEach or AfterAll) + * + * @param files files to delete + * @throws IOException some files were not deleted. + */ + public static void delete(final File... files) throws IOException { + final Set failed = new HashSet<>(files.length); + for (File file : files) { + if (file == null || !file.exists() || file.delete()) { + continue; + } + failed.add(file); + } + if (failed.isEmpty()) { + return; + } + final IOException failures = new IOException("Could not delete files: " + failed); + for (File file : failed) { + try { + Files.delete(file.toPath()); + } catch (IOException e) { + failures.addSuppressed(e); + } + } + throw failures; + } +} diff --git a/appserver/security/core-ee/src/main/java/com/sun/enterprise/security/ee/acl/RoleMapper.java b/appserver/security/core-ee/src/main/java/com/sun/enterprise/security/ee/acl/RoleMapper.java index bc9f1bcf79b..f3b33f55f37 100644 --- a/appserver/security/core-ee/src/main/java/com/sun/enterprise/security/ee/acl/RoleMapper.java +++ b/appserver/security/core-ee/src/main/java/com/sun/enterprise/security/ee/acl/RoleMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2022, 2024 Contributors to the Eclipse Foundation * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -17,17 +17,10 @@ package com.sun.enterprise.security.ee.acl; -import static com.sun.enterprise.util.Utility.isEmpty; -import static java.util.Collections.emptySet; -import static java.util.Collections.enumeration; -import static java.util.logging.Level.FINE; -import static java.util.logging.Level.SEVERE; -import static java.util.logging.Level.WARNING; -import static java.util.stream.Collectors.toSet; - import com.sun.enterprise.config.serverbeans.SecurityService; import com.sun.enterprise.security.auth.login.DistinguishedPrincipalCredential; import com.sun.logging.LogDomains; + import java.io.Serializable; import java.security.Principal; import java.util.Enumeration; @@ -36,9 +29,10 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; -import java.util.logging.Level; import java.util.logging.Logger; + import javax.security.auth.Subject; + import org.glassfish.api.admin.ServerEnvironment; import org.glassfish.deployment.common.RootDeploymentDescriptor; import org.glassfish.deployment.common.SecurityRoleMapper; @@ -48,6 +42,14 @@ import org.glassfish.security.common.UserNameAndPassword; import org.glassfish.security.common.UserPrincipal; +import static com.sun.enterprise.util.Utility.isEmpty; +import static java.util.Collections.emptySet; +import static java.util.Collections.enumeration; +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.SEVERE; +import static java.util.logging.Level.WARNING; +import static java.util.stream.Collectors.toSet; + /** * This Object maintains a mapping of users and groups to application specific Roles. Using this object this mapping * information could be maintained and queried at a later time. This is a complete rewrite of the previous RoleMapper @@ -259,7 +261,6 @@ public void unassignPrincipalFromRole(Role role, Principal principal) { } } - @Override public Iterator getRoles() { return roleToSubject.keySet().iterator(); // All the roles @@ -314,9 +315,6 @@ public String toString() { } s.append(")"); } - - LOG.log(Level.FINER, () -> s.toString()); - return s.toString(); } @@ -355,7 +353,7 @@ private String getDefaultPrincipalToRoleMappingClassName() { return className; } catch (Exception e) { - LOG.log(SEVERE, "pc.getDefaultP2RMappingClass: " + e); + LOG.log(SEVERE, "pc.getDefaultP2RMappingClass: " + className, e); return null; } } @@ -383,8 +381,7 @@ public Principal getCallerPrincipal(Subject subject) { subject.getPublicCredentials() .stream() .filter(DistinguishedPrincipalCredential.class::isInstance) - .map(DistinguishedPrincipalCredential.class::cast) - .map(e -> e.getPrincipal()) + .map(Principal.class::cast) .findAny() .orElse(subject.getPrincipals() .stream() @@ -397,17 +394,15 @@ private Set getCallerPrincipalNames(Subject subject) { return subject.getPrincipals() .stream() - .filter(e -> e instanceof UserNameAndPassword) - .map(e -> e.getName()) + .filter(UserPrincipal.class::isInstance) + .map(Principal::getName) .collect(toSet()); } // The method that does the work for assignRole(). private void internalAssignRole(Principal principal, Role role) { String roleName = role.getName(); - if (LOG.isLoggable(FINE)) { - LOG.log(FINE, "SECURITY:RoleMapper Assigning Role {0} to {1}", new Object[] {roleName, principal}); - } + LOG.log(FINE, "SECURITY:RoleMapper Assigning Role {0} to {1}", new Object[] {roleName, principal}); addRoleToSubject(principal, roleName); @@ -464,9 +459,8 @@ private void checkAndAddMappings() { if (topLevelRoles != null && topLevelRoles.contains(role)) { logConflictWarning(); - LOG.log(FINE, () -> - "Role " + role + " from module " + currentMapping.owner + " is being overridden by top-level mapping."); - + LOG.log(FINE, "Role {0} from module {1} is being overridden by top-level mapping.", + new Object[] {role, currentMapping.owner}); continue; } @@ -474,9 +468,8 @@ private void checkAndAddMappings() { topLevelRoles.add(role); if (roleToSubject.keySet().contains(role.getName())) { logConflictWarning(); - LOG.log(FINE, () -> - "Role " + role + " from top-level mapping descriptor is " + "overriding existing role in sub module."); - + LOG.log(FINE, + "Role {0} from top-level mapping descriptor is overriding existing role in sub module.", role); unassignRole(role); } @@ -501,9 +494,8 @@ private void checkAndAddMappings() { private boolean roleConflicts(Role r, Set ps) { // check to see if there has been a previous conflict if (conflictedRoles != null && conflictedRoles.contains(r)) { - LOG.log(FINE, - () -> "Role " + r + " from module " + currentMapping.owner + " has already had a conflict with other modules."); - + LOG.log(FINE, "Role {0} from module {1} has already had a conflict with other modules.", + new Object[] {r, currentMapping.owner}); return true; } @@ -520,10 +512,8 @@ private boolean roleConflicts(Role r, Set ps) { actualNum += pSet == null ? 0 : pSet.size(); actualNum += gSet == null ? 0 : gSet.size(); if (targetNumPrin != actualNum) { - if (LOG.isLoggable(FINE)) { - LOG.log(FINE, "Module " + currentMapping.owner + " has different number of mappings for role " + r.getName() - + " than other mapping files"); - } + LOG.log(FINE, "Module {0} has different number of mappings for role {1} than other mapping files", + new Object[] {currentMapping.owner, r.getName()}); if (conflictedRoles == null) { conflictedRoles = new HashSet<>(); @@ -546,9 +536,8 @@ private boolean roleConflicts(Role r, Set ps) { } if (fail) { - if (LOG.isLoggable(FINE)) { - LOG.log(FINE, "Role " + r + " in module " + currentMapping.owner + " is not included in other modules."); - } + LOG.log(FINE, "Role {0} in module {1} is not included in other modules.", + new Object[] {r, currentMapping.owner}); if (conflictedRoles == null) { conflictedRoles = new HashSet<>(); diff --git a/appserver/security/webintegration/src/main/java/com/sun/web/security/RealmAdapter.java b/appserver/security/webintegration/src/main/java/com/sun/web/security/RealmAdapter.java index 93609dc8dc2..d410bcb49b2 100644 --- a/appserver/security/webintegration/src/main/java/com/sun/web/security/RealmAdapter.java +++ b/appserver/security/webintegration/src/main/java/com/sun/web/security/RealmAdapter.java @@ -17,40 +17,6 @@ package com.sun.web.security; -import static com.sun.enterprise.security.auth.digest.api.Constants.A1; -import static com.sun.enterprise.security.ee.authentication.glassfish.digest.impl.DigestParameterGenerator.HTTP_DIGEST; -import static com.sun.enterprise.security.ee.jmac.AuthMessagePolicy.WEB_BUNDLE; -import static com.sun.enterprise.security.ee.web.integration.WebSecurityManager.getContextID; -import static com.sun.enterprise.util.Utility.isAllNull; -import static com.sun.enterprise.util.Utility.isAnyNull; -import static com.sun.enterprise.util.Utility.isEmpty; -import static com.sun.web.security.WebSecurityResourceBundle.BUNDLE_NAME; -import static com.sun.web.security.WebSecurityResourceBundle.MSG_FORBIDDEN; -import static com.sun.web.security.WebSecurityResourceBundle.MSG_INVALID_REQUEST; -import static com.sun.web.security.WebSecurityResourceBundle.MSG_MISSING_HOST_HEADER; -import static com.sun.web.security.WebSecurityResourceBundle.MSG_NO_WEB_SECURITY_MGR; -import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST; -import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN; -import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; -import static jakarta.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE; -import static java.util.Arrays.asList; -import static java.util.logging.Level.FINE; -import static java.util.logging.Level.FINEST; -import static java.util.logging.Level.INFO; -import static java.util.logging.Level.SEVERE; -import static java.util.logging.Level.WARNING; -import static org.apache.catalina.ContainerEvent.AFTER_AUTHENTICATION; -import static org.apache.catalina.ContainerEvent.AFTER_LOGOUT; -import static org.apache.catalina.ContainerEvent.AFTER_POST_AUTHENTICATION; -import static org.apache.catalina.ContainerEvent.BEFORE_AUTHENTICATION; -import static org.apache.catalina.ContainerEvent.BEFORE_LOGOUT; -import static org.apache.catalina.ContainerEvent.BEFORE_POST_AUTHENTICATION; -import static org.apache.catalina.Globals.WRAPPED_REQUEST; -import static org.apache.catalina.Globals.WRAPPED_RESPONSE; -import static org.apache.catalina.realm.Constants.FORM_METHOD; -import static org.glassfish.epicyro.config.helper.HttpServletConstants.POLICY_CONTEXT; -import static org.glassfish.epicyro.config.helper.HttpServletConstants.REGISTER_SESSION; - import com.sun.enterprise.deployment.RunAsIdentityDescriptor; import com.sun.enterprise.deployment.WebBundleDescriptor; import com.sun.enterprise.deployment.WebComponentDescriptor; @@ -76,6 +42,7 @@ import com.sun.enterprise.security.ee.web.integration.WebSecurityManagerFactory; import com.sun.enterprise.security.integration.RealmInitializer; import com.sun.enterprise.util.net.NetUtils; + import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.inject.Provider; @@ -88,6 +55,7 @@ import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; + import java.io.IOException; import java.io.UncheckedIOException; import java.net.InetAddress; @@ -110,10 +78,11 @@ import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.logging.Level; import java.util.logging.Logger; + import javax.security.auth.Subject; import javax.security.auth.x500.X500Principal; + import org.apache.catalina.Authenticator; import org.apache.catalina.Container; import org.apache.catalina.Context; @@ -146,6 +115,40 @@ import org.glassfish.security.common.UserNameAndPassword; import org.jvnet.hk2.annotations.Service; +import static com.sun.enterprise.security.auth.digest.api.Constants.A1; +import static com.sun.enterprise.security.ee.authentication.glassfish.digest.impl.DigestParameterGenerator.HTTP_DIGEST; +import static com.sun.enterprise.security.ee.jmac.AuthMessagePolicy.WEB_BUNDLE; +import static com.sun.enterprise.security.ee.web.integration.WebSecurityManager.getContextID; +import static com.sun.enterprise.util.Utility.isAllNull; +import static com.sun.enterprise.util.Utility.isAnyNull; +import static com.sun.enterprise.util.Utility.isEmpty; +import static com.sun.web.security.WebSecurityResourceBundle.BUNDLE_NAME; +import static com.sun.web.security.WebSecurityResourceBundle.MSG_FORBIDDEN; +import static com.sun.web.security.WebSecurityResourceBundle.MSG_INVALID_REQUEST; +import static com.sun.web.security.WebSecurityResourceBundle.MSG_MISSING_HOST_HEADER; +import static com.sun.web.security.WebSecurityResourceBundle.MSG_NO_WEB_SECURITY_MGR; +import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST; +import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN; +import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; +import static jakarta.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE; +import static java.util.Arrays.asList; +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.FINEST; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.SEVERE; +import static java.util.logging.Level.WARNING; +import static org.apache.catalina.ContainerEvent.AFTER_AUTHENTICATION; +import static org.apache.catalina.ContainerEvent.AFTER_LOGOUT; +import static org.apache.catalina.ContainerEvent.AFTER_POST_AUTHENTICATION; +import static org.apache.catalina.ContainerEvent.BEFORE_AUTHENTICATION; +import static org.apache.catalina.ContainerEvent.BEFORE_LOGOUT; +import static org.apache.catalina.ContainerEvent.BEFORE_POST_AUTHENTICATION; +import static org.apache.catalina.Globals.WRAPPED_REQUEST; +import static org.apache.catalina.Globals.WRAPPED_RESPONSE; +import static org.apache.catalina.realm.Constants.FORM_METHOD; +import static org.glassfish.epicyro.config.helper.HttpServletConstants.POLICY_CONTEXT; +import static org.glassfish.epicyro.config.helper.HttpServletConstants.REGISTER_SESSION; + /** * This is the realm adapter used to authenticate users and authorize access to web resources. The authenticate method * is called by Tomcat to authenticate users. The hasRole method is called by Tomcat during the authorization process. @@ -155,14 +158,14 @@ */ @Service @PerLookup -public class RealmAdapter extends RealmBase implements RealmInitializer, PostConstruct { +public final class RealmAdapter extends RealmBase implements RealmInitializer, PostConstruct { public static final String SECURITY_CONTEXT = "SecurityContext"; public static final String BASIC = "BASIC"; public static final String FORM = "FORM"; - private static final Logger _logger = Logger.getLogger(RealmAdapter.class.getName(), BUNDLE_NAME); - private static final ResourceBundle resourceBundle = _logger.getResourceBundle(); + private static final Logger LOG = Logger.getLogger(RealmAdapter.class.getName(), BUNDLE_NAME); + private static final ResourceBundle resourceBundle = LOG.getResourceBundle(); @Deprecated private static final String REGISTER_WITH_AUTHENTICATOR = "com.sun.web.RealmAdapter.register"; @@ -291,11 +294,15 @@ public boolean isSecurityExtensionEnabled(final ServletContext context) { } + /** - * Returns null 1. if there are no security constraints defined on any of the web resources within the context, or 2. if - * the target is a form login related page or target. - * - * otherwise return an empty array of SecurityConstraint. + * @returns null + *

    + *
  1. if there are no security constraints defined on any of the web resources within + * the context + *
  2. or if the target is a form login related page or target. + *
+ * otherwise return an empty array of SecurityConstraint. */ @Override public SecurityConstraint[] findSecurityConstraints(HttpRequest request, Context context) { @@ -303,51 +310,24 @@ public SecurityConstraint[] findSecurityConstraints(HttpRequest request, Context } /** - * Returns null 1. if there are no security constraints defined on any of the web resources within the context, or 2. if - * the target is a form login related page or target. - * - * otherwise return an empty array of SecurityConstraint. + * @returns null + *
    + *
  1. if there are no security constraints defined on any of the web resources within + * the context + *
  2. or if the target is a form login related page or target. + *
+ * otherwise return an empty array of SecurityConstraint. */ @Override public SecurityConstraint[] findSecurityConstraints(String requestPathMB, String httpMethod, Context context) { return findSecurityConstraints(context); } - /** - * Enforce any user data constraint required by the security constraint guarding this request URI. - * - * @param request Request we are processing - * @param response Response we are creating - * @param constraints Security constraint being checked - * - * @exception IOException if an input/output error occurs - * - * @return true if this constraint was not violated and processing should continue, or false - * if we have created a response already - */ @Override public boolean hasUserDataPermission(HttpRequest request, HttpResponse response, SecurityConstraint[] constraints) throws IOException { return hasUserDataPermission(request, response, constraints, null, null); } - /** - * Checks if the given request URI and method are the target of any user-data-constraint with a transport-guarantee of - * CONFIDENTIAL, and whether any such constraint is already satisfied. - * - * If uri and method are null, then the URI and method of the given request are checked. - * - * If a user-data-constraint exists that is not satisfied, then the given request will be redirected to HTTPS. - * - * @param request the request that may be redirected - * @param response the response that may be redirected - * @param constraints the security constraints to check against - * @param uri the request URI (minus the context path) to check - * @param method the request method to check - * - * @return true if the request URI and method are not the target of any unsatisfied user-data-constraint with a - * transport-guarantee of CONFIDENTIAL, and false if they are (in which case the given request will have been redirected - * to HTTPS) - */ @Override public boolean hasUserDataPermission(HttpRequest request, HttpResponse response, SecurityConstraint[] constraints, String uri, String method) throws IOException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; @@ -356,28 +336,26 @@ public boolean hasUserDataPermission(HttpRequest request, HttpResponse response, request.setServletPath(getResourceName(httpServletRequest.getRequestURI(), httpServletRequest.getContextPath())); } - _logger.fine(() -> - "[Web-Security][ hasUserDataPermission ]" + - " Principal: " + httpServletRequest.getUserPrincipal() + - " ContextPath: " + httpServletRequest.getContextPath()); + LOG.log(FINE, "hasUserDataPermission called for principal {0} and context path {1}", + new Object[] {httpServletRequest.getUserPrincipal(), httpServletRequest.getContextPath()}); if (request.getRequest().isSecure()) { - _logger.fine(() -> "[Web-Security] request.getRequest().isSecure(): " + request.getRequest().isSecure()); + LOG.log(FINE, "request.getRequest().isSecure(): {0}", request.getRequest().isSecure()); return true; } - WebSecurityManager webSecurityManager = getWebSecurityManager(true); - if (webSecurityManager == null) { + WebSecurityManager securityManager = getWebSecurityManager(true); + if (securityManager == null) { return false; } int isGranted = 0; try { - isGranted = webSecurityManager.hasUserDataPermission(httpServletRequest, uri, method); + isGranted = securityManager.hasUserDataPermission(httpServletRequest, uri, method); } catch (IllegalArgumentException e) { // end the request after getting IllegalArgumentException while checking // user data permission - _logger.log(WARNING, MSG_INVALID_REQUEST, e); + LOG.log(WARNING, MSG_INVALID_REQUEST, e); ((HttpServletResponse) response.getResponse()).sendError(SC_BAD_REQUEST, resourceBundle.getString(MSG_INVALID_REQUEST)); return false; @@ -392,7 +370,7 @@ public boolean hasUserDataPermission(HttpRequest request, HttpResponse response, // -1 - if the current transport is not granted, but a redirection can occur // so the grand will succeed. if (isGranted == -1) { - _logger.fine(() -> "[Web-Security] redirecting using SSL"); + LOG.log(FINE, "Redirecting using SSL"); return redirect(request, response); } @@ -404,24 +382,6 @@ public boolean hasUserDataPermission(HttpRequest request, HttpResponse response, return true; } - /** - * Checks whether or not authentication is needed. When Jakarta Authentication (and by extension, Jakarta Security) is enabled, - * authentication is always needed. - * - *

- * Returns an int, one of AUTHENTICATE_NOT_NEEDED, AUTHENTICATE_NEEDED, - * or AUTHENTICATED_NOT_AUTHORIZED - * - * @param request Request we are processing - * @param response Response we are creating - * @param constraints Security constraint we are enforcing - * @param disableProxyCaching whether or not to disable proxy caching for protected resources. - * @param securePagesWithPragma true if we add headers which are incompatible with downloading office documents in IE - * under SSL but which fix a caching problem in Mozilla. - * @param ssoEnabled true if sso is enabled - * - * @exception IOException if an input/output error occurs - */ @Override public int preAuthenticateCheck(HttpRequest request, HttpResponse response, SecurityConstraint[] constraints, boolean disableProxyCaching, boolean securePagesWithPragma, boolean ssoEnabled) throws IOException { boolean isGranted = false; @@ -438,7 +398,7 @@ public int preAuthenticateCheck(HttpRequest request, HttpResponse response, Secu } catch (IOException iex) { throw iex; } catch (Throwable ex) { - _logger.log(SEVERE, "Authentication passed, but authorization failed.", ex); + LOG.log(SEVERE, "Authentication passed, but authorization failed.", ex); ((HttpServletResponse) response.getResponse()).sendError(SC_SERVICE_UNAVAILABLE); response.setDetailMessage(resourceBundle.getString(MSG_FORBIDDEN)); @@ -471,17 +431,7 @@ public int preAuthenticateCheck(HttpRequest request, HttpResponse response, Secu return AUTHENTICATE_NEEDED; } - /** - * Authenticates the user making this request, based on the specified login configuration. Return true if - * any specified requirements have been satisfied, or false if we have created a response challenge - * already. - * - * @param request Request we are processing - * @param response Response we are creating - * @param context The Context to which client of this class is attached. - * @param authenticantion the current authenticator. - * @exception IOException if an input/output error occurs - */ + @Override public boolean invokeAuthenticateDelegate(HttpRequest request, HttpResponse response, Context context, Authenticator authenticator, boolean calledFromAuthenticate) throws IOException { LoginConfig config = context.getLoginConfig(); @@ -503,20 +453,11 @@ public boolean invokeAuthenticateDelegate(HttpRequest request, HttpResponse resp return ((AuthenticatorBase) authenticator).authenticate(request, response, config); } - /** - * Return a short name for this Realm Adapter implementation. - */ @Override protected String getName() { return name; } - /** - * Return the name of the realm this RealmAdapter uses. - * - * @return realm name - * - */ @Override public String getRealmName() { return realmName; @@ -547,26 +488,16 @@ public void updateWebSecurityManager() { } webSecurityManager = webSecurityManagerFactory.createManager(webBundleDescriptor, true, serverContext); - _logger.fine(() -> "WebSecurityManager for " + contextId + " has been updated"); + LOG.log(FINE, "WebSecurityManager for {0} has been updated", contextId); } } - /** - * Authenticates and sets the SecurityContext in the TLS. - * - * @return the authenticated principal. - * @param the user name. - * @param the password. - */ @Override public Principal authenticate(HttpRequest request, String username, char[] password) { - _logger.fine(() -> "Tomcat callback for authenticate user/password"); - _logger.fine(() -> "usename = " + username); - + LOG.log(FINE, "Tomcat callback for authenticate user/password. Username: {0}", username); if (authenticate((HttpServletRequest) request, username, password, null, null)) { return new WebPrincipal(username, password, SecurityContext.getCurrent()); } - return null; } @@ -589,17 +520,6 @@ public Principal authenticate(HttpRequest request, X509Certificate certificates[ return null; } - /** - * Perform access control based on the specified authorization constraint. Return true if this constraint - * is satisfied and processing should continue, or false otherwise. - * - * @param request Request we are processing - * @param response Response we are creating - * @param constraint Security constraint we are enforcing - * @param The Context to which client of this class is attached. - * - * @exception IOException if an input/output error occurs - */ @Override public boolean hasResourcePermission(HttpRequest request, HttpResponse response, SecurityConstraint[] constraints, Context context) throws IOException { boolean isGranted = false; @@ -609,7 +529,7 @@ public boolean hasResourcePermission(HttpRequest request, HttpResponse response, } catch (IOException iex) { throw iex; } catch (Throwable ex) { - _logger.log(SEVERE, "Authentication passed, but authorization failed.", ex); + LOG.log(SEVERE, "Authentication passed, but authorization failed.", ex); ((HttpServletResponse) response.getResponse()).sendError(SC_SERVICE_UNAVAILABLE); response.setDetailMessage(resourceBundle.getString(MSG_FORBIDDEN)); @@ -629,14 +549,6 @@ public boolean hasResourcePermission(HttpRequest request, HttpResponse response, return isGranted; } - /** - * Post authentication for given request and response. - * - * @param request Request we are processing - * @param response Response we are creating - * @param context The Context to which client of this class is attached. - * @exception IOException if an input/output error occurs - */ @Override public boolean invokePostAuthenticateDelegate(HttpRequest request, HttpResponse response, Context context) throws IOException { boolean result = false; @@ -675,20 +587,10 @@ public boolean invokePostAuthenticateDelegate(HttpRequest request, HttpResponse return result; } - /** - * Check if the given principal has the provided role. Returns true if the principal has the specified role, false - * otherwise. - * - * @return true if the principal has the specified role. - * @param request Request we are processing - * @param response Response we are creating - * @param the principal - * @param the role - */ @Override public boolean hasRole(HttpRequest request, HttpResponse response, Principal principal, String role) { - WebSecurityManager webSecurityManager = getWebSecurityManager(true); - if (webSecurityManager == null) { + WebSecurityManager manager = getWebSecurityManager(true); + if (manager == null) { return false; } @@ -699,10 +601,10 @@ public boolean hasRole(HttpRequest request, HttpResponse response, Principal pri // currentRequest.getContextPath()); String servletName = getCanonicalName(request); - boolean isGranted = webSecurityManager.hasRoleRefPermission(servletName, role, principal); + boolean isGranted = manager.hasRoleRefPermission(servletName, role, principal); - _logger.fine(() -> "Checking if servlet " + servletName + " with principal " + principal + " has role " + role + " isGranted: " - + isGranted); + LOG.log(FINE, "Checking if servlet {0} with principal {1} has role {2} isGranted: {3}", + new Object[] {servletName, principal, role, isGranted}); return isGranted; } @@ -719,11 +621,16 @@ public WebBundleDescriptor getWebDescriptor() { return webBundleDescriptor; } - // utility method to get web security anager. - // will log warning if the manager is not found in the factory, and - // logNull is true. - // Note: webSecurityManagerFactory can be null the very questionable SOAP code just - // instantiates a RealmAdapter + /** + * Utility method to get web security manager. + * Will log warning if the manager is not found in the factory, and logNull is true. + *

+ * Note: webSecurityManagerFactory can be null the very questionable SOAP code just + * instantiates a RealmAdapter + * + * @param logNull + * @return {@link WebSecurityManager} or null + */ public WebSecurityManager getWebSecurityManager(boolean logNull) { if (webSecurityManager == null && webSecurityManagerFactory != null) { synchronized (this) { @@ -731,7 +638,7 @@ public WebSecurityManager getWebSecurityManager(boolean logNull) { } if (webSecurityManager == null && logNull) { - _logger.log(WARNING, MSG_NO_WEB_SECURITY_MGR, contextId); + LOG.log(WARNING, MSG_NO_WEB_SECURITY_MGR, contextId); } } @@ -774,7 +681,7 @@ public void logout(HttpRequest httpRequest) { subject = new Subject(); } if (subject.isReadOnly()) { - _logger.log(WARNING, "Read-only subject found during logout processing"); + LOG.log(WARNING, "Read-only subject found during logout processing"); } try { @@ -829,7 +736,7 @@ public void logout() { } } - /* + /** * IASRI 4688449 This method was only used by EEInstanceListener to set the security context prior to invocations by * re-authenticating a previously set WebPrincipal. This is now cached so no need. */ @@ -837,7 +744,6 @@ public boolean authenticate(HttpServletRequest request, WebPrincipal principal) if (principal.isUsingCertificate()) { return authenticate(request, null, null, null, principal.getCertificates()); } - return authenticate(request, principal.getName(), principal.getPassword(), null, null); } @@ -858,18 +764,18 @@ private boolean authenticate(HttpServletRequest request, String username, char[] } else { LoginContextDriver.login(username, password, realmName); } - _logger.log(FINE, () -> "Web login succeeded for: " + SecurityContext.getCurrent().getCallerPrincipal()); + LOG.log(FINE, "Web login succeeded for: {0}", SecurityContext.getCurrent().getCallerPrincipal()); - WebSecurityManager webSecurityManager = getWebSecurityManager(false); + WebSecurityManager manager = getWebSecurityManager(false); // Sets the security context for Jakarta Authorization - if (webSecurityManager != null) { - webSecurityManager.onLogin(request); + if (manager != null) { + manager.onLogin(request); } return true; } catch (Exception le) { - _logger.log(WARNING, "WEB9102: Web Login Failed", le); + LOG.log(WARNING, "WEB9102: Web Login Failed", le); return false; } @@ -914,7 +820,7 @@ public void preSetRunAsIdentity(ComponentInvocation componentInvocation) { // Set the run-as principal into SecurityContext loginForRunAs(runAs); - _logger.log(FINE, () -> "run-as principal for " + servletName + " set to: " + runAs); + LOG.log(FINE, "The run-as principal for servlet {0} set to {1}", new Object[] {servletName, runAs}); } } @@ -1025,15 +931,15 @@ protected Principal getPrincipal(String username) { * @return Principal for the user username HERCULES:add */ public Principal createFailOveredPrincipal(String username) { - _logger.log(FINEST, "IN createFailOveredPrincipal ({0})", username); + LOG.log(FINEST, "createFailOveredPrincipal(username={0})", username); loginForRunAs(username); // set the appropriate security context SecurityContext securityContext = SecurityContext.getCurrent(); - _logger.log(FINE, "Security context is {0}", securityContext); + LOG.log(FINE, "Security context is {0}", securityContext); Principal principal = new WebPrincipal(username, (char[]) null, securityContext); - _logger.log(INFO, "Principal created for FailOvered user {0}", principal); + LOG.log(INFO, "Principal created for FailOvered user {0}", principal); return principal; } @@ -1056,7 +962,7 @@ private boolean invokeWebSecurityManager(HttpRequest request, HttpResponse respo setServletPath(request); HttpServletRequest httpServletRequest = (HttpServletRequest) request; - _logger.log(FINE, () -> "[Web-Security] [ hasResourcePermission ]" + + LOG.log(FINE, () -> "[Web-Security] [ hasResourcePermission ]" + " Principal: " + httpServletRequest.getUserPrincipal() + " ContextPath: " + httpServletRequest.getContextPath()); @@ -1076,20 +982,21 @@ private boolean isRequestFormPage(HttpRequest request) { } String requestURI = request.getRequestPathMB().toString(); - _logger.log(FINE, () -> "[Web-Security] requestURI: " + requestURI + " loginPage: " + loginPage); + LOG.log(FINE, "requestURI: {0}, loginPage: {1}, errorPage: {2}", + new Object[] {requestURI, loginPage, errorPage}); if (loginPage != null && loginPage.equals(requestURI)) { - _logger.log(FINE, () -> " Allow access to login page " + loginPage); + LOG.log(FINE, "Allowed access to login page {0}", loginPage); return true; } if (errorPage != null && errorPage.equals(requestURI)) { - _logger.log(FINE, () -> " Allow access to error page " + errorPage); + LOG.log(FINE, "Allowed access to error page {0}", errorPage); return true; } if (requestURI.endsWith(Constants.FORM_ACTION)) { - _logger.fine(" Allow access to username/password submission"); + LOG.log(FINE, "Allowed access to username/password submission ({0})", Constants.FORM_ACTION); return true; } @@ -1243,10 +1150,7 @@ private boolean redirect(HttpRequest request, HttpResponse response) throws IOEx // Is redirecting disabled? if (redirectPort <= 0) { - if (_logger.isLoggable(Level.INFO)) { - _logger.fine("[Web-Security] SSL redirect is disabled"); - } - + LOG.fine("SSL redirect is disabled"); hresponse.sendError(SC_FORBIDDEN, URLEncoder.encode(hrequest.getRequestURI(), "UTF-8")); return (false); } @@ -1271,10 +1175,10 @@ private boolean redirect(HttpRequest request, HttpResponse response) throws IOEx try { url = new URL(protocol, serverHost, redirectPort, file.toString()); hresponse.sendRedirect(url.toString()); - return (false); + return false; } catch (MalformedURLException e) { hresponse.sendError(SC_INTERNAL_SERVER_ERROR, URLEncoder.encode(hrequest.getRequestURI(), "UTF-8")); - return (false); + return false; } } @@ -1334,11 +1238,11 @@ private BaseAuthenticationService createAuthenticationService(final ServletConte */ private String getAppContextID(final ServletContext servletContext) { if (!servletContext.getVirtualServerName().equals(this.virtualServer.getName())) { - _logger.log(WARNING, "Virtual server name from ServletContext: {0} differs from name from virtual.getName(): {1}", + LOG.log(WARNING, "Virtual server name from ServletContext: {0} differs from name from virtual.getName(): {1}", new Object[] { servletContext.getVirtualServerName(), virtualServer.getName() }); } if (!servletContext.getContextPath().equals(webBundleDescriptor.getContextRoot())) { - _logger.log(WARNING, "Context path from ServletContext: {0} differs from path from bundle: {1}", + LOG.log(WARNING, "Context path from ServletContext: {0} differs from path from bundle: {1}", new Object[] { servletContext.getContextPath(), webBundleDescriptor.getContextRoot() }); } return servletContext.getVirtualServerName() + " " + servletContext.getContextPath(); @@ -1357,12 +1261,10 @@ private boolean validate(HttpRequest request, HttpResponse response, LoginConfig Subject subject = new Subject(); MessageInfo messageInfo = new HttpMessageInfo(httpServletRequest, httpServletResponse); - boolean isRequestValidated = false; boolean isMandatory = true; try { - WebSecurityManager webSecurityManager = getWebSecurityManager(true); - isMandatory = !webSecurityManager.permitAll(httpServletRequest); + isMandatory = !getWebSecurityManager(true).permitAll(httpServletRequest); // Issue - 9578 - produce user challenge if call originates from HttpRequest.authenticate if (isMandatory || calledFromAuthenticate) { @@ -1383,10 +1285,10 @@ private boolean validate(HttpRequest request, HttpResponse response, LoginConfig httpServletRequest.setAttribute(MESSAGE_INFO, messageInfo); } } catch (AuthException ae) { - _logger.log(SEVERE, "Jakarta Authentication: http msg authentication fail", ae); + LOG.log(SEVERE, "Jakarta Authentication: http msg authentication fail", ae); httpServletResponse.setStatus(SC_INTERNAL_SERVER_ERROR); } catch (RuntimeException e) { - _logger.log(SEVERE , "Jakarta Authentication: Exception during validateRequest", e); + LOG.log(SEVERE , "Jakarta Authentication: Exception during validateRequest", e); httpServletResponse.sendError(SC_INTERNAL_SERVER_ERROR); } @@ -1449,7 +1351,7 @@ private boolean validate(HttpRequest request, HttpResponse response, LoginConfig request.setUserPrincipal(webPrincipal); } } catch (LifecycleException le) { - _logger.log(SEVERE, "[Web-Security] unable to register session", le); + LOG.log(SEVERE, "Unable to register session", le); } @@ -1910,10 +1812,10 @@ private void collectRunAsPrincipals() { String servlet = componentDescriptor.getCanonicalName(); if (isAnyNull(principal, servlet)) { - _logger.warning("WEB8080: Null run-as principal or servlet, ignoring run-as element."); + LOG.warning("WEB8080: Null run-as principal or servlet, ignoring run-as element."); } else { runAsPrincipals.put(servlet, principal); - _logger.fine(() -> "Servlet " + servlet + " will run-as: " + principal); + LOG.log(FINE, "Servlet {0} will run-as: {1}", new Object[] {servlet, principal}); } } } @@ -1924,8 +1826,8 @@ private SecurityConstraint[] findSecurityConstraints(Context context) { initAuthenticationService(context.getServletContext()); } - WebSecurityManager webSecurityManager = getWebSecurityManager(false); - if (webSecurityManager != null && webSecurityManager.hasNoConstrainedResources() + WebSecurityManager manager = getWebSecurityManager(false); + if (manager != null && manager.hasNoConstrainedResources() && !isSecurityExtensionEnabled(context.getServletContext())) { return null; } @@ -1964,7 +1866,7 @@ private DigestCredentials generateDigestCredentials(HttpServletRequest httpServl return new DigestCredentials(realmName, key.getUsername(), digestParameters); } catch (Exception le) { - _logger.log(WARNING, "WEB9102: Web Login Failed", le); + LOG.log(WARNING, "WEB9102: Web Login Failed", le); } return null; diff --git a/appserver/tests/application/src/main/resources/org/glassfish/main/test/app/security/jmac/https/glassfish-web.xml b/appserver/tests/application/src/main/resources/org/glassfish/main/test/app/security/jmac/https/glassfish-web.xml index 12c21efa9b2..2e2b5ea1f0b 100644 --- a/appserver/tests/application/src/main/resources/org/glassfish/main/test/app/security/jmac/https/glassfish-web.xml +++ b/appserver/tests/application/src/main/resources/org/glassfish/main/test/app/security/jmac/https/glassfish-web.xml @@ -2,7 +2,7 @@