diff --git a/api/src/main/java/jakarta/security/jacc/PolicyConfigurationFactory.java b/api/src/main/java/jakarta/security/jacc/PolicyConfigurationFactory.java index 07f89e5..9e87289 100755 --- a/api/src/main/java/jakarta/security/jacc/PolicyConfigurationFactory.java +++ b/api/src/main/java/jakarta/security/jacc/PolicyConfigurationFactory.java @@ -26,8 +26,8 @@ * Provider. * *

- * Implementation classes must have a public no argument constructor that may be used to create an operational instance - * of the factory implementation class. + * Usage: extend this class and push the implementation being wrapped to the constructor and use {@link #getWrapped} to + * access the instance being wrapped. * * @see Permission * @see PolicyConfiguration @@ -43,6 +43,8 @@ public abstract class PolicyConfigurationFactory { private static volatile PolicyConfigurationFactory policyConfigurationFactory; + private PolicyConfigurationFactory wrapped; + /** * This static method uses a system property to find and instantiate (via a public constructor) a provider specific * factory implementation class. @@ -148,6 +150,30 @@ public static PolicyConfigurationFactory get() { } } + /** + * Default constructor for if no wrapping is needed + */ + public PolicyConfigurationFactory() { + } + + /** + * If this factory has been decorated, the implementation doing the decorating should push the implementation being + * wrapped to this constructor. The {@link #getWrapped()} will then return the implementation being wrapped. + * + * @param wrapped The implementation being wrapped. + */ + public PolicyConfigurationFactory(PolicyConfigurationFactory wrapped) { + this.wrapped = wrapped; + } + + /** + * If this factory has been decorated, the implementation doing the decorating may override this method to provide + * access to the implementation being wrapped. + */ + public PolicyConfigurationFactory getWrapped() { + return wrapped; + } + /** * 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 diff --git a/api/src/main/java/jakarta/security/jacc/PolicyFactory.java b/api/src/main/java/jakarta/security/jacc/PolicyFactory.java index e3e04e0..9183a93 100644 --- a/api/src/main/java/jakarta/security/jacc/PolicyFactory.java +++ b/api/src/main/java/jakarta/security/jacc/PolicyFactory.java @@ -32,6 +32,8 @@ public abstract class PolicyFactory { private static volatile PolicyFactory policyFactory; + private PolicyFactory wrapped; + /** * Get the system-wide PolicyFactory implementation. * @@ -87,6 +89,30 @@ public static synchronized void setPolicyFactory(PolicyFactory policyFactory) { PolicyFactory.policyFactory = policyFactory; } + /** + * Default constructor for if no wrapping is needed + */ + public PolicyFactory() { + } + + /** + * If this factory has been decorated, the implementation doing the decorating should push the implementation being + * wrapped to this constructor. The {@link #getWrapped()} will then return the implementation being wrapped. + * + * @param wrapped The implementation being wrapped. + */ + public PolicyFactory(PolicyFactory wrapped) { + this.wrapped = wrapped; + } + + /** + * If this factory has been decorated, the implementation doing the decorating may override this method to provide + * access to the implementation being wrapped. + */ + public PolicyFactory getWrapped() { + return wrapped; + } + /** * This method is used to obtain an instance of the provider specific class that implements the {@link Policy} * interface that corresponds to policy context within the provider. The policy context is identified by diff --git a/spec/src/main/asciidoc/chapters/2_provider-configuration.adoc b/spec/src/main/asciidoc/chapters/2_provider-configuration.adoc index 3a3eacc..8873a96 100644 --- a/spec/src/main/asciidoc/chapters/2_provider-configuration.adoc +++ b/spec/src/main/asciidoc/chapters/2_provider-configuration.adoc @@ -28,10 +28,14 @@ although for most common uses this should not be needed. Replacement is done via the `jakarta.security.jacc.PolicyConfigurationFactory` abstract factory class. A default static method, `getPolicyConfigurationFactory` is provided that uses the system property `jakarta.security.jacc.PolicyConfigurationFactory.provider` to locate a concrete implementation. The -application server can alternatively set a custom `PolicyConfigurationFactory` using the +container can alternatively set a custom `PolicyConfigurationFactory` using the `setPolicyConfigurationFactory` method. In that case the `PolicyConfigurationFactory` implementation -can come from an application server specific configuration, or in case of the Servlet Container -from the context property `jakarta.security.jacc.PolicyConfigurationFactory.provider`. +can come from a container specific configuration, or in case of the Servlet Container +from the context property `jakarta.security.jacc.PolicyConfigurationFactory.provider`. If the +`PolicyConfigurationFactory` has a public constructor with one argument of type `PolicyConfigurationFactory`, +then the container should call this constructor with as argument the `PolicyConfigurationFactory` instance +that is being replaced. This allows a replacement `PolicyConfigurationFactory` to wrap the existing one +and selectively provide extra functionality. From this factory class a concrete implementation of the Policy Configuration of type `jakarta.security.jacc.PolicyConfiguration` can be obtained using the method `getPolicyConfiguration`. diff --git a/tck/app-custom-trace-policyconfiguration/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationFactoryImpl.java b/tck/app-custom-trace-policyconfiguration/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationFactoryImpl.java index 792ec27..b25697b 100644 --- a/tck/app-custom-trace-policyconfiguration/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationFactoryImpl.java +++ b/tck/app-custom-trace-policyconfiguration/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationFactoryImpl.java @@ -26,7 +26,6 @@ import static java.util.logging.Level.FINER; import static java.util.logging.Level.INFO; -import static java.util.logging.Level.SEVERE; import ee.jakarta.tck.authorization.util.logging.server.TSLogger; import jakarta.security.jacc.PolicyConfiguration; @@ -45,17 +44,12 @@ public class TSPolicyConfigurationFactoryImpl extends PolicyConfigurationFactory private static String FACTORY_NAME = "vendor.jakarta.security.jacc.PolicyConfigurationFactory.provider"; - private static PolicyConfigurationFactory policyConfigurationFactory; - public TSPolicyConfigurationFactoryImpl() throws PolicyContextException { - try { - policyConfigurationFactory = TSPolicyConfigurationFactoryImpl.getPolicyConfigurationFactory(); - } catch (PolicyContextException pce) { - if (logger != null) { - logger.severe("Failed to get PolicyConfigurationFactory"); - } - - throw new PolicyContextException(pce); + public TSPolicyConfigurationFactoryImpl(PolicyConfigurationFactory policyConfigurationFactory) { + super(policyConfigurationFactory); + logger.log(INFO, "PolicyConfigurationFactory instantiated"); + if (policyConfigurationFactory.getClass().getName().equals(FACTORY_NAME)) { + logger.log(INFO, "policyConfigurationFactory equals expected vendor PolicyConfigurationFactory"); } } @@ -109,55 +103,6 @@ public PolicyConfiguration getPolicyConfiguration(String contextId, boolean remo return policyConfiguration; } - /** - * This static method uses a system property to find and instantiate (via a public constructor) a provider specific - * factory implementation class. The name of the provider specific factory implementation class is obtained from the - * value of the system property, - *

- *

-     *     vendor.jakarta.security.jacc.PolicyConfigurationFactory.provider
-     * 
- *

- * - * @return the singleton instance of the provider specific PolicyConfigurationFactory implementation class. - * - * @throws SecurityException when called by an AccessControlContext that has not been granted the "getPolicy" - * SecurityPermission. - * - * @throws PolicyContextException when the class named by the system property could not be found including because the - * value of the system property has not been set. - */ - - public static PolicyConfigurationFactory getPolicyConfigurationFactory() throws PolicyContextException { - if (policyConfigurationFactory != null) { - return policyConfigurationFactory; - } - - String classname = System.getProperty(FACTORY_NAME); - if (classname == null) { - logger.severe("factory.name.notset"); - throw new PolicyContextException("PolicyConfigurationFactory name not set!"); - } - - try { - policyConfigurationFactory = (PolicyConfigurationFactory) - TSPolicyConfigurationFactoryImpl.class - .getClassLoader() - .loadClass(classname) - .getDeclaredConstructor() - .newInstance(); - - if (policyConfigurationFactory != null) { - logger.log(INFO, "PolicyConfigurationFactory instantiated"); - } - } catch (Exception e) { - logger.log(SEVERE, "factory.instantiation.error", e); - throw new PolicyContextException(e); - } - - return policyConfigurationFactory; - } - /** * This method determines if the identified policy context exists with state "inService" in the Policy provider * associated with the factory. @@ -182,7 +127,7 @@ public boolean inService(String contextId) throws PolicyContextException { logger.log(INFO, "PolicyConfigurationFactory.inService() invoked"); logger.log(FINER, "PolicyConfiguration.inService() invoked for context id = " + contextId); - return policyConfigurationFactory.inService(contextId); + return getWrapped().inService(contextId); } public PolicyConfiguration getPolicyConfiguration(String contextID) { @@ -190,7 +135,7 @@ public PolicyConfiguration getPolicyConfiguration(String contextID) { logger.entering("PolicyConfigurationFactoryImpl", "getPolicyConfiguration(String)"); } - PolicyConfiguration policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextID); + PolicyConfiguration policyConfiguration = getWrapped().getPolicyConfiguration(contextID); logger.log(INFO, "PolicyConfigurationFactory.getPolicyConfiguration(String) invoked"); return policyConfiguration; @@ -202,7 +147,7 @@ public PolicyConfiguration getPolicyConfiguration() { } String contextId = PolicyContext.getContextID(); - PolicyConfiguration policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextId); + PolicyConfiguration policyConfiguration = getWrapped().getPolicyConfiguration(contextId); logger.log(INFO, "PolicyConfigurationFactory.getPolicyConfiguration(String) invoked"); logger.log(FINER, "Getting PolicyConfiguration object with id = " + contextId); diff --git a/tck/app-custom-trace-policyconfiguration/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationImpl.java b/tck/app-custom-trace-policyconfiguration/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationImpl.java index a6b7428..cd01bc6 100644 --- a/tck/app-custom-trace-policyconfiguration/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationImpl.java +++ b/tck/app-custom-trace-policyconfiguration/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationImpl.java @@ -50,8 +50,8 @@ public class TSPolicyConfigurationImpl implements PolicyConfiguration { private static TSLogger logger; - private PolicyConfigurationFactory policyConfigurationFactory; - private PolicyConfiguration policyConfiguration; + private PolicyConfigurationFactory vendorPolicyConfigurationFactory; + private PolicyConfiguration vendorPolicyConfiguration; private String applicationContext; private String appTime; @@ -71,11 +71,11 @@ public TSPolicyConfigurationImpl(String contextId, boolean remove, TSLogger tsLo } // set vendor's PolicyConfigurationFactory - policyConfigurationFactory = TSPolicyConfigurationFactoryImpl.getPolicyConfigurationFactory(); + vendorPolicyConfigurationFactory = PolicyConfigurationFactory.get().getWrapped(); // **** This covers two assertions JACC:SPEC:33 and JACC:SPEC:56 **** // set vendor's PolicyConfiguration - policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextId, remove); + vendorPolicyConfiguration = vendorPolicyConfigurationFactory.getPolicyConfiguration(contextId, remove); // This(appId record) will be used as an identifier // for isolating the logs associated with each test run. @@ -101,9 +101,9 @@ public TSPolicyConfigurationImpl(String contextId, boolean remove, TSLogger tsLo * encapsulated (during construction) in the thrown PolicyContextException. */ public String getContextID() throws PolicyContextException { - boolean wasInService = policyConfiguration.inService(); + boolean wasInService = vendorPolicyConfiguration.inService(); - String contextId = policyConfiguration.getContextID(); + String contextId = vendorPolicyConfiguration.getContextID(); // If the state was inService for our getContextID call, then it must remain // in that state as its next transitional state (per javadoc table) @@ -111,7 +111,7 @@ public String getContextID() throws PolicyContextException { assertIsInserviceState("getContextID"); } else { // state was not inService so make sure it is still NOT in the - // inService state after calling policyConfiguration.getContextID() + // inService state after calling vendorPolicyConfiguration.getContextID() assertStateNotInservice("getContextID"); } @@ -152,8 +152,8 @@ public void addToRole(String roleName, PermissionCollection permissions) throws return; } - policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); - policyConfiguration.addToRole(roleName, permissions); + vendorPolicyConfiguration = vendorPolicyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + vendorPolicyConfiguration.addToRole(roleName, permissions); assertStateNotInservice("addToRole"); if (logger.isLoggable(INFO)) { @@ -226,9 +226,9 @@ public void addToRole(String roleName, Permission permission) throws PolicyConte if (roleName == null || permission == null) return; - policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + vendorPolicyConfiguration = vendorPolicyConfigurationFactory.getPolicyConfiguration(applicationContext, false); - policyConfiguration.addToRole(roleName, permission); + vendorPolicyConfiguration.addToRole(roleName, permission); assertStateNotInservice("addToRole"); // Get the permission type, @@ -282,8 +282,8 @@ public void addToUncheckedPolicy(PermissionCollection permissions) throws Policy return; } - policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); - policyConfiguration.addToUncheckedPolicy(permissions); + vendorPolicyConfiguration = vendorPolicyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + vendorPolicyConfiguration.addToUncheckedPolicy(permissions); assertStateNotInservice("addToUncheckedPolicy"); if (logger.isLoggable(INFO)) { @@ -346,8 +346,8 @@ public void addToUncheckedPolicy(Permission permission) throws PolicyContextExce return; } - policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); - policyConfiguration.addToUncheckedPolicy(permission); + vendorPolicyConfiguration = vendorPolicyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + vendorPolicyConfiguration.addToUncheckedPolicy(permission); assertStateNotInservice("addToUncheckedPolicy"); // Get the permission type, @@ -391,8 +391,8 @@ public void addToExcludedPolicy(PermissionCollection permissions) throws PolicyC if (permissions == null) return; - policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); - policyConfiguration.addToExcludedPolicy(permissions); + vendorPolicyConfiguration = vendorPolicyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + vendorPolicyConfiguration.addToExcludedPolicy(permissions); assertStateNotInservice("addToExcludedPolicy"); if (logger.isLoggable(INFO)) { @@ -451,8 +451,8 @@ public void addToExcludedPolicy(Permission permission) throws PolicyContextExcep return; } - policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); - policyConfiguration.addToExcludedPolicy(permission); + vendorPolicyConfiguration = vendorPolicyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + vendorPolicyConfiguration.addToExcludedPolicy(permission); assertStateNotInservice("addToExcludedPolicy"); // Get the permission type, @@ -496,8 +496,8 @@ public void removeRole(String roleName) throws PolicyContextException { return; } - policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); - policyConfiguration.removeRole(roleName); + vendorPolicyConfiguration = vendorPolicyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + vendorPolicyConfiguration.removeRole(roleName); assertStateNotInservice("removeRole"); if (logger.isLoggable(INFO)) { @@ -526,8 +526,8 @@ public void removeUncheckedPolicy() throws PolicyContextException { logger.entering("TSPolicyConfigurationImpl", "removeUncheckedPolicy"); } - policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); - policyConfiguration.removeUncheckedPolicy(); + vendorPolicyConfiguration = vendorPolicyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + vendorPolicyConfiguration.removeUncheckedPolicy(); assertStateNotInservice("removeUncheckedPolicy"); if (logger.isLoggable(INFO)) { @@ -556,8 +556,8 @@ public void removeExcludedPolicy() throws PolicyContextException { logger.entering("TSPolicyConfigurationImpl", "removeExcludedPolicy"); } - policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); - policyConfiguration.removeExcludedPolicy(); + vendorPolicyConfiguration = vendorPolicyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + vendorPolicyConfiguration.removeExcludedPolicy(); assertStateNotInservice("removeExcludedPolicy"); if (logger.isLoggable(INFO)) { @@ -593,8 +593,8 @@ public void commit() throws PolicyContextException { logger.entering("TSPolicyConfigurationImpl", "commit"); } - policyConfiguration.inService(); - policyConfiguration.commit(); + vendorPolicyConfiguration.inService(); + vendorPolicyConfiguration.commit(); assertIsInserviceState("commit"); @@ -673,7 +673,7 @@ public void linkConfiguration(PolicyConfiguration link) throws PolicyContextExce } } - // policyConfiguration.linkConfiguration(link); + // vendorPolicyConfiguration.linkConfiguration(link); // // Note: // The Passed varibale "link" may be an instance of @@ -686,12 +686,12 @@ public void linkConfiguration(PolicyConfiguration link) throws PolicyContextExce // get vendor's Policy configuration from "link" // Note: pcf is vendor's PolicyConfigurationFactory - PolicyConfiguration vendorPC = policyConfigurationFactory.getPolicyConfiguration(vendorContextId, false); + PolicyConfiguration vendorPC = vendorPolicyConfigurationFactory.getPolicyConfiguration(vendorContextId, false); // Now link the vendor's PolicyConfiguration - policyConfiguration.inService(); - policyConfiguration.linkConfiguration(vendorPC); + vendorPolicyConfiguration.inService(); + vendorPolicyConfiguration.linkConfiguration(vendorPC); assertStateNotInservice("linkConfiguration"); @@ -720,7 +720,7 @@ public void delete() throws PolicyContextException { logger.entering("TSPolicyConfigurationImpl", "delete"); } - policyConfiguration.delete(); + vendorPolicyConfiguration.delete(); assertStateNotInservice("delete"); if (logger.isLoggable(INFO)) { @@ -749,11 +749,11 @@ public boolean inService() throws PolicyContextException { logger.entering("TSPolicyConfigurationImpl", "inService"); } - boolean wasInservice = policyConfiguration.inService(); + boolean wasInservice = vendorPolicyConfiguration.inService(); - boolean ret = policyConfiguration.inService(); + boolean ret = vendorPolicyConfiguration.inService(); - // If the state was inService befor our policyConfiguration.inService() + // If the state was inService befor our vendorPolicyConfiguration.inService() // call, then it must remain in that state as its next transitional // state (per javadoc table) if (wasInservice) { @@ -814,20 +814,20 @@ public static String stuffData(String inputStr) { } public PermissionCollection getExcludedPermissions() { - return policyConfiguration.getExcludedPermissions(); + return vendorPolicyConfiguration.getExcludedPermissions(); } public PermissionCollection getUncheckedPermissions() { - return policyConfiguration.getUncheckedPermissions(); + return vendorPolicyConfiguration.getUncheckedPermissions(); } public Map getPerRolePermissions() { - return policyConfiguration.getPerRolePermissions(); + return vendorPolicyConfiguration.getPerRolePermissions(); } private void assertIsInserviceState(String callingMethod) { try { - if (!policyConfiguration.inService()) { + if (!vendorPolicyConfiguration.inService()) { String msg1 = "ERROR - our policy config should be in the INSERVICE state."; String msg2 = "In the wrong state after having called: " + callingMethod; debugOut(msg1); @@ -835,19 +835,19 @@ private void assertIsInserviceState(String callingMethod) { logger.log(Level.SEVERE, msg1); } } catch (SecurityException ex) { - String err = "ERROR - got securityException calling policyConfiguration.inService()."; + String err = "ERROR - got securityException calling vendorPolicyConfiguration.inService()."; err += " You likely need to have 'setPolicy' grant set"; debugOut(err); debugOut(ex.toString()); } catch (Exception ex) { - debugOut("ERROR - Exception calling policyConfiguration.inService(): " + ex.toString()); + debugOut("ERROR - Exception calling vendorPolicyConfiguration.inService(): " + ex.toString()); ex.printStackTrace(); } } private void assertStateNotInservice(String callingMethod) { try { - if (policyConfiguration.inService()) { + if (vendorPolicyConfiguration.inService()) { String msg1 = "ERROR - our policy config should not be in the INSERVICE state."; String msg2 = "In the wrong state after having called: " + callingMethod; debugOut(msg1); @@ -855,12 +855,12 @@ private void assertStateNotInservice(String callingMethod) { logger.log(Level.SEVERE, msg1); } } catch (SecurityException ex) { - String err = "ERROR - got securityException calling policyConfiguration.inService()."; + String err = "ERROR - got securityException calling vendorPolicyConfiguration.inService()."; err += " You likely need to have 'setPolicy' grant set"; debugOut(err); debugOut(ex.toString()); } catch (Exception ex) { - debugOut("ERROR - Exception calling policyConfiguration.inService(): " + ex.toString()); + debugOut("ERROR - Exception calling vendorPolicyConfiguration.inService(): " + ex.toString()); ex.printStackTrace(); } } diff --git a/tck/app-custom-trace-policyconfigurationfactory/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationFactoryImpl.java b/tck/app-custom-trace-policyconfigurationfactory/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationFactoryImpl.java index 1dc0365..70c1072 100644 --- a/tck/app-custom-trace-policyconfigurationfactory/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationFactoryImpl.java +++ b/tck/app-custom-trace-policyconfigurationfactory/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationFactoryImpl.java @@ -65,6 +65,12 @@ public TSPolicyConfigurationFactoryImpl() throws PolicyContextException { } } + public TSPolicyConfigurationFactoryImpl(PolicyConfigurationFactory policyConfigurationFactory) { + super(policyConfigurationFactory); + TSPolicyConfigurationFactoryImpl.policyConfigurationFactory = policyConfigurationFactory; + logger.log(INFO, "PolicyConfigurationFactory instantiated"); + } + /** * 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