diff --git a/impl/pom.xml b/impl/pom.xml index b7fa559..112680a 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -96,14 +96,14 @@ jakarta.servlet jakarta.servlet-api - 6.1.0-M2 + 6.1.0 provided true jakarta.authorization jakarta.authorization-api - 3.0.0-M2 + 3.0.0-M4 provided true @@ -178,7 +178,7 @@ maven-compiler-plugin - 3.12.1 + 3.13.0 17 diff --git a/impl/src/main/java/org/glassfish/exousia/AuthorizationService.java b/impl/src/main/java/org/glassfish/exousia/AuthorizationService.java index 99453b3..74eda94 100644 --- a/impl/src/main/java/org/glassfish/exousia/AuthorizationService.java +++ b/impl/src/main/java/org/glassfish/exousia/AuthorizationService.java @@ -17,6 +17,15 @@ package org.glassfish.exousia; +import static jakarta.security.jacc.PolicyContext.HTTP_SERVLET_REQUEST; +import static jakarta.security.jacc.PolicyContext.PRINCIPAL_MAPPER; +import static jakarta.security.jacc.PolicyContext.SUBJECT; +import static java.lang.System.Logger.Level.DEBUG; +import static java.lang.System.Logger.Level.ERROR; +import static java.util.Collections.emptySet; +import static org.glassfish.exousia.constraints.transformer.ConstraintsToPermissionsTransformer.createResourceAndDataPermissions; +import static org.glassfish.exousia.permissions.RolesToPermissionsTransformer.createWebRoleRefPermission; + import jakarta.security.jacc.EJBMethodPermission; import jakarta.security.jacc.EJBRoleRefPermission; import jakarta.security.jacc.Policy; @@ -31,7 +40,6 @@ import jakarta.security.jacc.WebUserDataPermission; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpServletRequest; - import java.lang.System.Logger; import java.lang.reflect.Method; import java.security.Permission; @@ -44,9 +52,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; - import javax.security.auth.Subject; - import org.glassfish.exousia.constraints.SecurityConstraint; import org.glassfish.exousia.mapping.DefaultPrincipalMapper; import org.glassfish.exousia.mapping.SecurityRoleRef; @@ -54,15 +60,6 @@ import org.glassfish.exousia.modules.def.DefaultPolicyConfigurationFactory; import org.glassfish.exousia.permissions.JakartaPermissions; -import static jakarta.security.jacc.PolicyContext.HTTP_SERVLET_REQUEST; -import static jakarta.security.jacc.PolicyContext.PRINCIPAL_MAPPER; -import static jakarta.security.jacc.PolicyContext.SUBJECT; -import static java.lang.System.Logger.Level.DEBUG; -import static java.lang.System.Logger.Level.ERROR; -import static java.util.Collections.emptySet; -import static org.glassfish.exousia.constraints.transformer.ConstraintsToPermissionsTransformer.createResourceAndDataPermissions; -import static org.glassfish.exousia.permissions.RolesToPermissionsTransformer.createWebRoleRefPermission; - /** * * @author Arjan Tijms @@ -82,8 +79,8 @@ public class AuthorizationService { */ private final Policy policy; private final PolicyFactory policyFactory; - private final PolicyConfigurationFactory factory; private final PolicyConfiguration policyConfiguration; + private final PolicyConfigurationFactory policyConfigurationFactory; private final Map principalMapper = new ConcurrentHashMap<>(); private String constrainedUriRequestAttribute; @@ -117,7 +114,7 @@ public AuthorizationService( Supplier subjectSupplier, Supplier principalMapperSupplier) { this( - installFactory(factoryClass), installPolicy(policyClass), contextId, + installPolicyConfigurationFactory(factoryClass), installPolicy(policyClass), contextId, subjectSupplier, principalMapperSupplier); } @@ -126,7 +123,7 @@ public AuthorizationService( Supplier subjectSupplier, Supplier principalMapperSupplier) { this( - getConfigurationFactory(), null, contextId, + PolicyConfigurationFactory.get(), null, contextId, subjectSupplier, principalMapperSupplier); } @@ -134,7 +131,7 @@ public AuthorizationService( PolicyConfigurationFactory factory, Policy policy, String contextId, Supplier subjectSupplier, Supplier principalMapperSupplier) { try { - this.factory = factory; + this.policyConfigurationFactory = factory; this.policyConfiguration = factory.getPolicyConfiguration(contextId, false); this.policy = policy; this.contextId = contextId; @@ -242,10 +239,10 @@ public void addPermissionsToPolicy(JakartaPermissions jakartaPermissions) { public void removeStatementsFromPolicy(Set declaredRoles) { try { - boolean inService = factory.inService(contextId); + boolean inService = policyConfigurationFactory.inService(contextId); // Open policy configuration - PolicyConfiguration policyConfiguration = factory.getPolicyConfiguration(contextId, false); + PolicyConfiguration policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextId, false); policyConfiguration.removeUncheckedPolicy(); policyConfiguration.removeExcludedPolicy(); @@ -286,7 +283,7 @@ public void removeStatementsFromPolicy(Set declaredRoles) { */ public boolean linkPolicy(String linkedContextId, boolean lastInService) { try { - boolean inService = factory.inService(contextId); + boolean inService = policyConfigurationFactory.inService(contextId); if (linkedContextId == null) { return inService; @@ -298,8 +295,8 @@ public boolean linkPolicy(String linkedContextId, boolean lastInService) { // Only do the link if the named policyConfiguration is not inService. if (!inService) { - PolicyConfiguration policyConfiguration = factory.getPolicyConfiguration(contextId, false); - PolicyConfiguration linkedPolicyConfiguration = factory.getPolicyConfiguration(linkedContextId, false); + PolicyConfiguration policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextId, false); + PolicyConfiguration linkedPolicyConfiguration = policyConfigurationFactory.getPolicyConfiguration(linkedContextId, false); policyConfiguration.linkConfiguration(linkedPolicyConfiguration); } @@ -340,7 +337,7 @@ public static boolean linkPolicy(String contextId, String linkedContextId, boole public void commitPolicy() { try { - if (!factory.inService(contextId)) { + if (!policyConfigurationFactory.inService(contextId)) { // Note that it is presumed that the policyConfiguration exists, and that // it is populated with the desired policy statements. @@ -380,7 +377,7 @@ public static void commitPolicy(String contextId) { public void refresh() { // Refresh policy if the context was in service try { - if (factory.inService(contextId)) { + if (policyConfigurationFactory.inService(contextId)) { getPolicy().refresh(); } } catch (PolicyContextException e) { @@ -501,7 +498,6 @@ public Object invokeBeanMethod(Object bean, Method beanClassMethod, Object[] met return runInScope(() -> beanClassMethod.invoke(bean, methodParameters)); } - /** * Inform the policy module to take the named policy context out of service. The policy context is transitioned to the * deleted state. @@ -509,10 +505,10 @@ public Object invokeBeanMethod(Object bean, Method beanClassMethod, Object[] met */ public void deletePolicy() { try { - boolean wasInService = factory.inService(contextId); + boolean wasInService = policyConfigurationFactory.inService(contextId); // Find the PolicyConfig and delete it. - factory.getPolicyConfiguration(contextId, false).delete(); + policyConfigurationFactory.getPolicyConfiguration(contextId, false).delete(); // Only do refresh policy if the deleted context was in service if (wasInService) { @@ -543,7 +539,6 @@ public static void deletePolicy(String contextId) { } } - boolean checkPermission(Permission permissionToBeChecked) { LOG.log(DEBUG, "checkPermission(permissionToBeChecked={0})", permissionToBeChecked); return getPolicy().implies(permissionToBeChecked); @@ -590,26 +585,86 @@ public Object runInScope(ThrowableSupplier supplier) throws Throwable { } } - private static PolicyConfigurationFactory installFactory(Class factoryClass) { + public static PolicyConfigurationFactory installPolicyConfigurationFactory(Class factoryClass) { + if (factoryClass == null) { + return null; + } + + PolicyConfigurationFactory existingFactory = PolicyConfigurationFactory.get(); + if (existingFactory.getClass().equals(factoryClass)) { + return existingFactory; // first one + } + + PolicyConfigurationFactory newFactory = null; + try { + newFactory = (PolicyConfigurationFactory) + factoryClass.getDeclaredConstructor(PolicyConfigurationFactory.class) + .newInstance(existingFactory); + } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) { + // not available + } + + if (newFactory == null) { + try { + newFactory = (PolicyConfigurationFactory) + factoryClass.getDeclaredConstructor() + .newInstance(); + } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) { + throw new IllegalStateException(e); + } + } + + PolicyConfigurationFactory.setPolicyConfigurationFactory(newFactory); System.setProperty(PolicyConfigurationFactory.FACTORY_NAME, factoryClass.getName()); - return getConfigurationFactory(); + return PolicyConfigurationFactory.get(); } - private static Policy installPolicy(Class policyClass) { - try { - PolicyFactory.getPolicyFactory().setPolicy(policyClass.getConstructor().newInstance()); + public static PolicyFactory installPolicyFactory(Class factoryClass) { + if (factoryClass == null) { + return null; + } - return PolicyFactory.getPolicyFactory().getPolicy(); + PolicyFactory existingFactory = PolicyFactory.getPolicyFactory(); + if (existingFactory.getClass().equals(factoryClass)) { + return existingFactory; // first one + } + + PolicyFactory newFactory = null; + try { + newFactory = (PolicyFactory) + factoryClass.getDeclaredConstructor(PolicyFactory.class) + .newInstance(existingFactory); } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) { - throw new IllegalStateException(e); + // not available + } + + if (newFactory == null) { + try { + newFactory = (PolicyFactory) + factoryClass.getDeclaredConstructor() + .newInstance(); + } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) { + throw new IllegalStateException(e); + } } + + PolicyFactory.setPolicyFactory(newFactory); + System.setProperty(PolicyFactory.FACTORY_NAME, factoryClass.getName()); + + return PolicyFactory.getPolicyFactory(); } - private static PolicyConfigurationFactory getConfigurationFactory() { + public static Policy installPolicy(Class policyClass) { + if (policyClass == null) { + return null; + } + try { - return PolicyConfigurationFactory.getPolicyConfigurationFactory(); - } catch (ClassNotFoundException | PolicyContextException e) { + PolicyFactory.getPolicyFactory().setPolicy(policyClass.getConstructor().newInstance()); + + return PolicyFactory.getPolicyFactory().getPolicy(); + } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) { throw new IllegalStateException(e); } } @@ -650,7 +705,8 @@ private PrincipalMapper getDefaultRoleMapper(String contextId) { } private static Collection getAllDeclaredRoles() { - return getConfigurationFactory() + return PolicyConfigurationFactory + .get() .getPolicyConfiguration() .getPerRolePermissions() .keySet(); diff --git a/impl/src/main/java/org/glassfish/exousia/modules/def/DefaultPolicyConfigurationFactory.java b/impl/src/main/java/org/glassfish/exousia/modules/def/DefaultPolicyConfigurationFactory.java index 32ac29d..726f6fa 100644 --- a/impl/src/main/java/org/glassfish/exousia/modules/def/DefaultPolicyConfigurationFactory.java +++ b/impl/src/main/java/org/glassfish/exousia/modules/def/DefaultPolicyConfigurationFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Contributors to the Eclipse Foundation. + * Copyright (c) 2023, 2024 Contributors to the Eclipse Foundation. * Copyright (c) 2019, 2021 OmniFaces. All rights reserved. * * This program and the accompanying materials are made available under the @@ -33,6 +33,10 @@ public class DefaultPolicyConfigurationFactory extends PolicyConfigurationFactor private static final ConcurrentMap configurators = new ConcurrentHashMap<>(); + public DefaultPolicyConfigurationFactory() { + super(null); + } + @Override public PolicyConfiguration getPolicyConfiguration(String contextID, boolean remove) throws PolicyContextException { diff --git a/impl/src/main/java/org/glassfish/exousia/modules/def/DefaultPolicyFactory.java b/impl/src/main/java/org/glassfish/exousia/modules/def/DefaultPolicyFactory.java index 18d15da..c37947e 100644 --- a/impl/src/main/java/org/glassfish/exousia/modules/def/DefaultPolicyFactory.java +++ b/impl/src/main/java/org/glassfish/exousia/modules/def/DefaultPolicyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Contributors to the Eclipse Foundation. + * Copyright (c) 2023, 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 @@ -24,6 +24,10 @@ public class DefaultPolicyFactory extends PolicyFactory { private static Map idToPolicyMap = new ConcurrentHashMap<>(); + public DefaultPolicyFactory() { + super(null); + } + // get/set global (system wide) policy? @Override diff --git a/impl/src/main/java/org/glassfish/exousia/modules/locked/SimplePolicyConfigurationFactory.java b/impl/src/main/java/org/glassfish/exousia/modules/locked/SimplePolicyConfigurationFactory.java index d2c07f2..ce61e43 100644 --- a/impl/src/main/java/org/glassfish/exousia/modules/locked/SimplePolicyConfigurationFactory.java +++ b/impl/src/main/java/org/glassfish/exousia/modules/locked/SimplePolicyConfigurationFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Contributors to Eclipse Foundation. + * Copyright (c) 2021, 2024 Contributors to 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 @@ -24,12 +24,12 @@ /** * Abstract factory and finder class for obtaining the instance of the class that implements the - * PolicyConfigurationFactory of a provider. - * + * PolicyConfigurationFactory of a provider. + * *

* The factory will be used to instantiate PolicyConfiguration objects that will be used by the deployment tools of the * container to create and manage policy contexts within the Policy Provider. - * + * *

* Implementation classes must have a public no argument constructor that may be used to create an operational instance * of the factory implementation class. @@ -41,23 +41,27 @@ */ public class SimplePolicyConfigurationFactory extends PolicyConfigurationFactory { + public SimplePolicyConfigurationFactory() { + super(null); + } + /** * This method is used to obtain an instance of the provider specific class that implements the PolicyConfiguration * interface that corresponds to the identified policy context within the provider. The methods of the * PolicyConfiguration interface are used to define the policy statements of the identified policy context. - * + * *

* If at the time of the call, the identified policy context does not exist in the provider, then the policy context * will be created in the provider and the Object that implements the context's PolicyConfiguration Interface will be * returned. If the state of the identified context is "deleted" or "inService" it will be transitioned to the "open" * state as a result of the call. The states in the lifecycle of a policy context are defined by the PolicyConfiguration * interface. - * + * *

* For a given value of policy context identifier, this method must always return the same instance of * PolicyConfiguration and there must be at most one actual instance of a PolicyConfiguration with a given policy * context identifier (during a process context). - * + * *

* To preserve the invariant that there be at most one PolicyConfiguration object for a given policy context, it may be * necessary for this method to be thread safe. diff --git a/spi/tomcat/pom.xml b/spi/tomcat/pom.xml index 37c2cd7..14c64c1 100644 --- a/spi/tomcat/pom.xml +++ b/spi/tomcat/pom.xml @@ -100,13 +100,13 @@ jakarta.servlet jakarta.servlet-api - 6.1.0-M2 + 6.1.0 provided jakarta.authorization jakarta.authorization-api - 3.0.0-M2 + 3.0.0-M4 provided