diff --git a/tck/app-custom-trace-policyconfiguration/pom.xml b/tck/app-custom-trace-policyconfiguration/pom.xml new file mode 100644 index 0000000..704a896 --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/pom.xml @@ -0,0 +1,62 @@ + + + + + 4.0.0 + + + org.eclipse.ee4j.authorization.tck + jakarta-authorization-tck + 4.0.0-SNAPSHOT + + + app-custom-trace-policyconfiguration + war + + + This module installs a tracing PolicyConfiguration that writes to a seperate log file + called "authorization-trace-log.xml". The location where this file will be written can be + set using the "log.file.location" system property for both the server and the client test. + + The test uses the log file to check for specific permissions having been added to the PolicyConfiguration. + The log file is so detailed and eleborate, that it is essentially a serialized database of the permissions + that have been created. + + This therefor tests the Jakarta Authorization implementation to create and send the right permission instances + to the configured PolicyConfiguration. It does not test the behaviour of the default PolicyConfiguration so much, + other than a simple test for the in service state. + + + + false + + + + + org.eclipse.ee4j.authorization.tck + common + ${project.version} + + + + + app-custom-trace-policyconfiguration + + 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 new file mode 100644 index 0000000..792ec27 --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationFactoryImpl.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * Copyright (c) 2007, 2022 Oracle and/or its affiliates. All rights reserved. + * + * 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 + */ + +/** + * $Id$ + * + * @author Raja Perumal + * 08/01/02 + */ + +package ee.jakarta.tck.authorization.test; + +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; +import jakarta.security.jacc.PolicyConfigurationFactory; +import jakarta.security.jacc.PolicyContext; +import jakarta.security.jacc.PolicyContextException; + +/** + * JACC PolicyConfigurationFactory This is a delegating PolicyConfigurationFactory which delegates the policy + * configurations to vendor implementation of PolicyConfigurationFactory class. + * + */ +public class TSPolicyConfigurationFactoryImpl extends PolicyConfigurationFactory { + + private static TSLogger logger = TSLogger.getTSLogger(); + + 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); + } + } + + /** + * 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. + *

+ * + * @param contextId A String identifying the policy context whose PolicyConfiguration interface is to be returned. The + * value passed to this parameter must not be null. + *

+ * @param remove A boolean value that establishes whether or not the policy statements of an existing policy context are + * to be removed before its PolicyConfiguration object is returned. If the value passed to this parameter is true, the + * policy statements of an existing policy context will be removed. If the value is false, they will not be removed. + * + * @return an Object that implements the PolicyConfiguration Interface matched to the Policy provider and corresponding + * to the identified policy context. + * + * @throws java.lang.SecurityException when called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the getPolicyConfiguration method signature. The exception thrown by the implementation class + * will be encapsulated (during construction) in the thrown PolicyContextException. + */ + + public PolicyConfiguration getPolicyConfiguration(String contextId, boolean remove) throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("PolicyConfigurationFactoryImpl", "getPolicyConfiguration"); + } + + PolicyConfiguration policyConfiguration = new TSPolicyConfigurationImpl(contextId, remove, logger); + + logger.log(INFO, "PolicyConfigurationFactory.getPolicyConfiguration() invoked"); + logger.log(FINER, "Getting PolicyConfiguration object with id = " + contextId); + + 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. + *

+ * + * @param contextId A string identifying a policy context + * + * @return true if the identified policy context exists within the provider and its state is "inService", false + * otherwise. + * + * @throws java.lang.SecurityException when called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the inService method signature. The exception thrown by the implementation class will be + * encapsulated (during construction) in the thrown PolicyContextException. + */ + public boolean inService(String contextId) throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("PolicyConfigurationFactoryImpl", "inService"); + } + logger.log(INFO, "PolicyConfigurationFactory.inService() invoked"); + logger.log(FINER, "PolicyConfiguration.inService() invoked for context id = " + contextId); + + return policyConfigurationFactory.inService(contextId); + } + + public PolicyConfiguration getPolicyConfiguration(String contextID) { + if (logger.isLoggable(FINER)) { + logger.entering("PolicyConfigurationFactoryImpl", "getPolicyConfiguration(String)"); + } + + PolicyConfiguration policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextID); + logger.log(INFO, "PolicyConfigurationFactory.getPolicyConfiguration(String) invoked"); + + return policyConfiguration; + } + + public PolicyConfiguration getPolicyConfiguration() { + if (logger.isLoggable(FINER)) { + logger.entering("PolicyConfigurationFactoryImpl", "getPolicyConfiguration()"); + } + + String contextId = PolicyContext.getContextID(); + PolicyConfiguration policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextId); + logger.log(INFO, "PolicyConfigurationFactory.getPolicyConfiguration(String) invoked"); + logger.log(FINER, "Getting PolicyConfiguration object with id = " + contextId); + + return policyConfiguration; + } + +} 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 new file mode 100644 index 0000000..a6b7428 --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationImpl.java @@ -0,0 +1,872 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * Copyright (c) 2007, 2022 Oracle and/or its affiliates. All rights reserved. + * + * 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 + */ + +/* + * $Id$ + * + * @author Raja Perumal + */ + +package ee.jakarta.tck.authorization.test; + +import static java.util.logging.Level.FINER; +import static java.util.logging.Level.INFO; + +import ee.jakarta.tck.authorization.util.logging.server.TSLogger; +import jakarta.security.jacc.EJBMethodPermission; +import jakarta.security.jacc.EJBRoleRefPermission; +import jakarta.security.jacc.PolicyConfiguration; +import jakarta.security.jacc.PolicyConfigurationFactory; +import jakarta.security.jacc.PolicyContextException; +import jakarta.security.jacc.WebResourcePermission; +import jakarta.security.jacc.WebRoleRefPermission; +import jakarta.security.jacc.WebUserDataPermission; +import java.security.Permission; +import java.security.PermissionCollection; +import java.util.Date; +import java.util.Enumeration; +import java.util.Map; +import java.util.Vector; +import java.util.logging.Level; + +/** + * Jakarta Authorization PolicyConfiguration delegates the policy configuration tasks + * to vendor's PolicyConfiguration implementation class. + */ +public class TSPolicyConfigurationImpl implements PolicyConfiguration { + private static TSLogger logger; + + private PolicyConfigurationFactory policyConfigurationFactory; + private PolicyConfiguration policyConfiguration; + + private String applicationContext; + private String appTime; + + private Vector applicationLinkTable = new Vector<>(); + + public TSPolicyConfigurationImpl(String contextId, boolean remove, TSLogger tsLogger) throws PolicyContextException { + Date date = new Date(); + appTime = "" + date.getTime(); + logger = tsLogger; + + // Add timeStamp to the contextId, + applicationContext = contextId; + + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "TSPolicyConfigurationImpl"); + } + + // set vendor's PolicyConfigurationFactory + policyConfigurationFactory = TSPolicyConfigurationFactoryImpl.getPolicyConfigurationFactory(); + + // **** This covers two assertions JACC:SPEC:33 and JACC:SPEC:56 **** + // set vendor's PolicyConfiguration + policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextId, remove); + + // This(appId record) will be used as an identifier + // for isolating the logs associated with each test run. + if (logger.isLoggable(INFO)) { + logger.log(INFO, "appId :: " + stuffData(applicationContext) + " , " + appTime); + } + + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "TSPolicyConfigurationImpl"); + } + } + + /** + * This method returns this object's policy context identifier. + * + * @return this object's policy context identifier. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the getContextID method signature. The exception thrown by the implementation class will be + * encapsulated (during construction) in the thrown PolicyContextException. + */ + public String getContextID() throws PolicyContextException { + boolean wasInService = policyConfiguration.inService(); + + String contextId = policyConfiguration.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) + if (wasInService) { + assertIsInserviceState("getContextID"); + } else { + // state was not inService so make sure it is still NOT in the + // inService state after calling policyConfiguration.getContextID() + assertStateNotInservice("getContextID"); + } + + if (logger.isLoggable(FINER)) { + logger.log(FINER, "contextId =" + contextId); + } + + return contextId; + } + + /** + * Used to add permissions to a named role in this PolicyConfiguration. If the named Role does not exist in the + * PolicyConfiguration, it is created as a result of the call to this function. + * + *

+ * It is the job of the Policy provider to ensure that all the permissions added to a role are granted to principals + * "mapped to the role". + * + * @param roleName the name of the Role to which the permissions are to be added. + * @param permissions the collection of permissions to be added to the role. The collection may be either a homogenous + * or heterogenous collection. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws java.lang.UnsupportedOperationException if the state of the policy context whose interface is this + * PolicyConfiguration Object is "deleted" or "inService" when this method is called. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the addToRole method signature. The exception thrown by the implementation class will be + * encapsulated (during construction) in the thrown PolicyContextException. + */ + public void addToRole(String roleName, PermissionCollection permissions) throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "addToRole"); + } + if (roleName == null || permissions == null) { + return; + } + + policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + policyConfiguration.addToRole(roleName, permissions); + assertStateNotInservice("addToRole"); + + if (logger.isLoggable(INFO)) { + StringBuffer sbuf = new StringBuffer(""); + int bufLength = 0; + for (Enumeration en = permissions.elements(); en.hasMoreElements();) { + sbuf.append("addToRole :: "); + sbuf.append(applicationContext + " , "); + sbuf.append(appTime + " , "); + Permission p = en.nextElement(); + + // Get the permission type, + // valid permission types are + // 1) WebResourcePermission + // 2) WebUserDataPermission + // 3) WebRoleRefPermission + // 4) EJBMethodPermission + // 5) EJBRoleRefPermission + String permissionType = getPermissionType(p); + sbuf.append(permissionType + " , "); + sbuf.append(p.getName() + " , "); + sbuf.append(p.getActions()); + logger.log(INFO, sbuf.toString()); + + // Re-initialize string buffer. + bufLength = sbuf.length(); + sbuf.delete(0, bufLength); + + if (permissionType.equals("WebResourcePermission") || permissionType.equals("WebRoleRefPermission") + || permissionType.equals("EJBMethodPermission") || permissionType.equals("EJBRoleRefPermission")) { + // logged so we can check roleNames and resourcePerms + logger.log(INFO, + "MSG_TAG :: " + permissionType + " :: " + roleName + " :: " + applicationContext + " :: " + p.getName()); + } + } + } + + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "addToRole"); + } + } + + /** + * Used to add a single permission to a named role in this PolicyConfiguration. If the named Role does not exist in the + * PolicyConfiguration, it is created as a result of the call to this function. + *

+ * It is the job of the Policy provider to ensure that all the permissions added to a role are granted to principals + * "mapped to the role". + *

+ * + * @param roleName the name of the Role to which the permission is to be added. + *

+ * @param permission the permission to be added to the role. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws java.lang.UnsupportedOperationException if the state of the policy context whose interface is this + * PolicyConfiguration Object is "deleted" or "inService" when this method is called. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the addToRole method signature. The exception thrown by the implementation class will be + * encapsulated (during construction) in the thrown PolicyContextException. + */ + public void addToRole(String roleName, Permission permission) throws PolicyContextException { + String permissionType = null; + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "addToRole"); + } + if (roleName == null || permission == null) + return; + + policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + + policyConfiguration.addToRole(roleName, permission); + assertStateNotInservice("addToRole"); + + // Get the permission type, + // valid permission types are + // 1) WebResourcePermission + // 2) WebUserDataPermission + // 3) WebRoleRefPermission + // 4) EJBMethodPermission + // 5) EJBRoleRefPermission + permissionType = getPermissionType(permission); + if (logger.isLoggable(INFO)) { + String sbuf = new String("addToRole :: " + applicationContext + " , " + appTime + " , " + permissionType + " , " + + permission.getName() + " , " + permission.getActions()); + logger.log(INFO, sbuf); + } + + if (permissionType.equals("WebResourcePermission") || permissionType.equals("WebRoleRefPermission") + || permissionType.equals("EJBMethodPermission") || permissionType.equals("EJBRoleRefPermission")) { + // logged so we can check roleNames and resourcePerms + logger.log(INFO, + "MSG_TAG :: " + permissionType + " :: " + roleName + " :: " + applicationContext + " :: " + permission.getName()); + } + + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "addToRole"); + } + } + + /** + * Used to add unchecked policy statements to this PolicyConfiguration. + *

+ * + * @param permissions the collection of permissions to be added as unchecked policy statements. The collection may be + * either a homogenous or heterogenous collection. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws java.lang.UnsupportedOperationException if the state of the policy context whose interface is this + * PolicyConfiguration Object is "deleted" or "inService" when this method is called. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the addToUncheckedPolicy method signature. The exception thrown by the implementation class + * will be encapsulated (during construction) in the thrown PolicyContextException. + */ + public void addToUncheckedPolicy(PermissionCollection permissions) throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "addToUncheckedPolicy"); + } + if (permissions == null) { + return; + } + + policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + policyConfiguration.addToUncheckedPolicy(permissions); + assertStateNotInservice("addToUncheckedPolicy"); + + if (logger.isLoggable(INFO)) { + StringBuffer sbuf = new StringBuffer(""); + int bufLength = 0; + + for (Enumeration en = permissions.elements(); en.hasMoreElements();) { + sbuf.append("unchecked :: "); + sbuf.append(applicationContext + " , "); + sbuf.append(appTime + " , "); + + Permission p = en.nextElement(); + // Get the permission type, + // valid permission types are + // 1) WebResourcePermission + // 2) WebUserDataPermission + // 3) WebRoleRefPermission + // 4) EJBMethodPermission + // 5) EJBRoleRefPermission + String permissionType = getPermissionType(p); + + sbuf.append(permissionType + " , "); + sbuf.append(p.getName() + " , "); + sbuf.append(p.getActions()); + + logger.log(INFO, sbuf.toString()); + + // Re-initialize string buffer + bufLength = sbuf.length(); + sbuf.delete(0, bufLength); + } + } + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "addToUncheckedPolicy"); + } + } + + /** + * Used to add a single unchecked policy statement to this PolicyConfiguration. + *

+ * + * @param permission the permission to be added to the unchecked policy statements. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws java.lang.UnsupportedOperationException if the state of the policy context whose interface is this + * PolicyConfiguration Object is "deleted" or "inService" when this method is called. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the addToUncheckedPolicy method signature. The exception thrown by the implementation class + * will be encapsulated (during construction) in the thrown PolicyContextException. + */ + public void addToUncheckedPolicy(Permission permission) throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "addToUncheckedPolicy"); + } + + if (permission == null) { + return; + } + + policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + policyConfiguration.addToUncheckedPolicy(permission); + assertStateNotInservice("addToUncheckedPolicy"); + + // Get the permission type, + // valid permission types are + // 1) WebResourcePermission + // 2) WebUserDataPermission + // 3) WebRoleRefPermission + // 4) EJBMethodPermission + // 5) EJBRoleRefPermission + String permissionType = getPermissionType(permission); + if (logger.isLoggable(INFO)) { + logger.log(INFO, "unchecked :: " + applicationContext + " , " + appTime + " , " + permissionType + " , " + + permission.getName() + " , " + permission.getActions()); + } + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "addToUncheckedPolicy"); + } + } + + /** + * Used to add excluded policy statements to this PolicyConfiguration. + *

+ * + * @param permissions the collection of permissions to be added to the excluded policy statements. The collection may be + * either a homogenous or heterogenous collection. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws java.lang.UnsupportedOperationException if the state of the policy context whose interface is this + * PolicyConfiguration Object is "deleted" or "inService" when this method is called. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the addToExcludedPolicy method signature. The exception thrown by the implementation class will + * be encapsulated (during construction) in the thrown PolicyContextException. + */ + public void addToExcludedPolicy(PermissionCollection permissions) throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "addToExcludedPolicy"); + } + if (permissions == null) + return; + + policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + policyConfiguration.addToExcludedPolicy(permissions); + assertStateNotInservice("addToExcludedPolicy"); + + if (logger.isLoggable(INFO)) { + StringBuffer sbuf = new StringBuffer(""); + int bufLength = 0; + for (Enumeration en = permissions.elements(); en.hasMoreElements();) { + sbuf.append("excluded :: "); + sbuf.append(applicationContext + " , "); + sbuf.append(appTime + " , "); + Permission permission = en.nextElement(); + + // Get the permission type, + // valid permission types are + // 1) WebResourcePermission + // 2) WebUserDataPermission + // 3) WebRoleRefPermission + // 4) EJBMethodPermission + // 5) EJBRoleRefPermission + String permissionType = getPermissionType(permission); + sbuf.append(permissionType + " , "); + sbuf.append(permission.getName() + " , "); + sbuf.append(permission.getActions()); + logger.log(INFO, sbuf.toString()); + + // Re-initialize string buffer. + bufLength = sbuf.length(); + sbuf.delete(0, bufLength); + } + } + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "addToExcludedPolicy"); + } + } + + /** + * Used to add a single excluded policy statement to this PolicyConfiguration. + *

+ * + * @param permission the permission to be added to the excluded policy statements. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws java.lang.UnsupportedOperationException if the state of the policy context whose interface is this + * PolicyConfiguration Object is "deleted" or "inService" when this method is called. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the addToExcludedPolicy method signature. The exception thrown by the implementation class will + * be encapsulated (during construction) in the thrown PolicyContextException. + */ + public void addToExcludedPolicy(Permission permission) throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "addToExcludedPolicy"); + } + if (permission == null) { + return; + } + + policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + policyConfiguration.addToExcludedPolicy(permission); + assertStateNotInservice("addToExcludedPolicy"); + + // Get the permission type, + // valid permission types are + // 1) WebResourcePermission + // 2) WebUserDataPermission + // 3) WebRoleRefPermission + // 4) EJBMethodPermission + // 5) EJBRoleRefPermission + String permissionType = getPermissionType(permission); + if (logger.isLoggable(INFO)) { + logger.log(INFO, "excluded :: " + applicationContext + " , " + appTime + " , " + permissionType + " , " + + permission.getName() + " , " + permission.getActions()); + } + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "addToExcludedPolicy"); + } + } + + /** + * Used to remove a role and all its permissions from this PolicyConfiguration. + *

+ * + * @param roleName the name of the Role to remove from this PolicyConfiguration. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws java.lang.UnsupportedOperationException if the state of the policy context whose interface is this + * PolicyConfiguration Object is "deleted" or "inService" when this method is called. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the removeRole method signature. The exception thrown by the implementation class will be + * encapsulated (during construction) in the thrown PolicyContextException. + */ + public void removeRole(String roleName) throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "removeRole"); + } + if (roleName == null) { + return; + } + + policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + policyConfiguration.removeRole(roleName); + assertStateNotInservice("removeRole"); + + if (logger.isLoggable(INFO)) { + logger.log(INFO, "Removed Role :: " + roleName); + } + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "removeRole"); + } + } + + /** + * Used to remove any unchecked policy statements from this PolicyConfiguration. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws java.lang.UnsupportedOperationException if the state of the policy context whose interface is this + * PolicyConfiguration Object is "deleted" or "inService" when this method is called. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the removeUncheckedPolicy method signature. The exception thrown by the implementation class + * will be encapsulated (during construction) in the thrown PolicyContextException. + */ + public void removeUncheckedPolicy() throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "removeUncheckedPolicy"); + } + + policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + policyConfiguration.removeUncheckedPolicy(); + assertStateNotInservice("removeUncheckedPolicy"); + + if (logger.isLoggable(INFO)) { + logger.log(INFO, "Removed all unchecked policy statements"); + } + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "removeUncheckedPolicy"); + } + } + + /** + * Used to remove any excluded policy statements from this PolicyConfiguration. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws java.lang.UnsupportedOperationException if the state of the policy context whose interface is this + * PolicyConfiguration Object is "deleted" or "inService" when this method is called. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the removeExcludedPolicy method signature. The exception thrown by the implementation class + * will be encapsulated (during construction) in the thrown PolicyContextException. + */ + public void removeExcludedPolicy() throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "removeExcludedPolicy"); + } + + policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(applicationContext, false); + policyConfiguration.removeExcludedPolicy(); + assertStateNotInservice("removeExcludedPolicy"); + + if (logger.isLoggable(INFO)) { + logger.log(INFO, "Removed all excluded policy statements"); + } + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "removeExcludedPolicy"); + } + } + + /** + * This method is used to set to "inService" the state of the policy context whose interface is this PolicyConfiguration + * Object. Only those policy contexts whose state is "inService" will be included in the policy contexts processed by + * the Policy.refresh method. A policy context whose state is "inService" may be returned to the "open" state by calling + * the getPolicyConfiguration method of the PolicyConfiguration factory with the policy context identifier of the policy + * context. + *

+ * When the state of a policy context is "inService", calling any method other than commit, delete, getContextID, or + * inService on its PolicyConfiguration Object will cause an UnsupportedOperationException to be thrown. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws java.lang.UnsupportedOperationException if the state of the policy context whose interface is this + * PolicyConfiguration Object is "deleted" when this method is called. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the commit method signature. The exception thrown by the implementation class will be + * encapsulated (during construction) in the thrown PolicyContextException. + */ + public void commit() throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "commit"); + } + + policyConfiguration.inService(); + policyConfiguration.commit(); + + assertIsInserviceState("commit"); + + if (logger.isLoggable(INFO)) { + logger.log(INFO, "PolicyConfiguration.commit() called"); + } + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "commit"); + } + } + + /** + * Creates a relationship between this configuration and another such that they share the same principal-to-role + * mappings. PolicyConfigurations are linked to apply a common principal-to-role mapping to multiple seperately + * manageable PolicyConfigurations, as is required when an application is composed of multiple modules. + *

+ * Note that the policy statements which comprise a role, or comprise the excluded or unchecked policy collections in a + * PolicyConfiguration are unaffected by the configuration being linked to another. + *

+ * + * @param link a reference to a different PolicyConfiguration than this PolicyConfiguration. + *

+ * The relationship formed by this method is symetric, transitive and idempotent. If the argument PolicyConfiguration + * does not have a different Policy context identifier than this PolicyConfiguration no relationship is formed, and an + * exception, as described below, is thrown. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws java.lang.UnsupportedOperationException if the state of the policy context whose interface is this + * PolicyConfiguration Object is "deleted" or "inService" when this method is called. + * + * @throws java.lang.IllegalArgumentException if called with an argument PolicyConfiguration whose Policy context is + * equivalent to that of this PolicyConfiguration. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the linkConfiguration method signature. The exception thrown by the implementation class will + * be encapsulated (during construction) in the thrown PolicyContextException. + */ + public void linkConfiguration(PolicyConfiguration link) throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "linkConfiguration"); + } + + if (link != null) { + String contextId = link.getContextID(); + + // Check if the application name already exists + if (applicationLinkTable != null) { + + // Now add the contextId that is being linked to applicationLinkTable + if (!applicationLinkTable.contains(contextId)) { + applicationLinkTable.add(contextId); + } + + // Now add this.applicationContextId to applicationLinkTable + if (!applicationLinkTable.contains(applicationContext)) { + applicationLinkTable.add(applicationContext); + } + } + + if (logger.isLoggable(INFO)) { + StringBuffer sbuf = new StringBuffer(""); + sbuf.append("link :: "); + for (Enumeration appEnum = applicationLinkTable.elements(); appEnum.hasMoreElements();) { + String stuffedAppName = stuffData(appEnum.nextElement()); + sbuf.append(stuffedAppName); + if (appEnum.hasMoreElements()) + sbuf.append(","); + } + sbuf.append(" : "); + sbuf.append(appTime); + + // Log all the linked application names + logger.log(INFO, sbuf.toString()); + } + } + + // policyConfiguration.linkConfiguration(link); + // + // Note: + // The Passed varibale "link" may be an instance of + // delegating Provider's PolicyConfiguration, so before + // linking it with Vendor's PolicyConfiguration, first + // get the vendor's equivalent PolicyConfiguration from "link" + + // get contextId from link + String vendorContextId = link.getContextID(); + + // get vendor's Policy configuration from "link" + // Note: pcf is vendor's PolicyConfigurationFactory + PolicyConfiguration vendorPC = policyConfigurationFactory.getPolicyConfiguration(vendorContextId, false); + + // Now link the vendor's PolicyConfiguration + + policyConfiguration.inService(); + policyConfiguration.linkConfiguration(vendorPC); + + assertStateNotInservice("linkConfiguration"); + + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "linkConfiguration"); + } + } + + /** + * Causes all policy statements to be deleted from this PolicyConfiguration and sets its internal state such that + * calling any method, other than delete, getContextID, or inService on the PolicyConfiguration will be rejected and + * cause an UnsupportedOperationException to be thrown. + *

+ * This operation has no affect on any linked PolicyConfigurations other than removing any links involving the deleted + * PolicyConfiguration. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the delete method signature. The exception thrown by the implementation class will be + * encapsulated (during construction) in the thrown PolicyContextException. + */ + public void delete() throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "delete"); + } + + policyConfiguration.delete(); + assertStateNotInservice("delete"); + + if (logger.isLoggable(INFO)) { + logger.log(INFO, "Deleted all policy statements"); + } + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "delete"); + } + } + + /** + * This method is used to determine if the policy context whose interface is this PolicyConfiguration Object is in the + * "inService" state. + * + * @return true if the state of the associated policy context is "inService"; false otherwise. + * + * @throws java.lang.SecurityException if called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the inService method signature. The exception thrown by the implementation class will be + * encapsulated (during construction) in the thrown PolicyContextException. + */ + public boolean inService() throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("TSPolicyConfigurationImpl", "inService"); + } + + boolean wasInservice = policyConfiguration.inService(); + + boolean ret = policyConfiguration.inService(); + + // If the state was inService befor our policyConfiguration.inService() + // call, then it must remain in that state as its next transitional + // state (per javadoc table) + if (wasInservice) { + assertIsInserviceState("inService"); + } else { + // state was not inService so must've been OPEN or DELETED but + // either way, the next state must remain the same so we know + // we should NOT trasition to different state + assertStateNotInservice("inService"); + } + + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "PolicyConfiguration.inService() called"); + } + if (logger.isLoggable(FINER)) { + logger.exiting("TSPolicyConfigurationImpl", "inService"); + } + + return ret; + } + + public String getPermissionType(Permission permission) { + if (permission instanceof WebResourcePermission) + return "WebResourcePermission"; + else if (permission instanceof WebUserDataPermission) + return "WebUserDataPermission"; + else if (permission instanceof WebRoleRefPermission) + return "WebRoleRefPermission"; + else if (permission instanceof EJBMethodPermission) + return "EJBMethodPermission"; + else if (permission instanceof EJBRoleRefPermission) + return "EJBRoleRefPermission"; + else + return null; + } + + // This method process the input string and stuffs the character twice if + // the processed character is not an alphabet + public static String stuffData(String inputStr) { + char[] outStr = new char[2048]; + char[] str = inputStr.toCharArray(); + for (int i = 0, j = 0; i < str.length; i++) { + int a = Character.getNumericValue(str[i]); + + // Don't stuff extra character if the character is an alphabet + // + // Numeric values for alphabets falls in 10 to 35, this includes + // both upper and lower cases + if (a > 9 && a < 36) { + outStr[j++] = str[i]; + + } else { // stuff the character + outStr[j++] = str[i]; + outStr[j++] = str[i]; + } + } + return new String(outStr).trim(); + } + + public PermissionCollection getExcludedPermissions() { + return policyConfiguration.getExcludedPermissions(); + } + + public PermissionCollection getUncheckedPermissions() { + return policyConfiguration.getUncheckedPermissions(); + } + + public Map getPerRolePermissions() { + return policyConfiguration.getPerRolePermissions(); + } + + private void assertIsInserviceState(String callingMethod) { + try { + if (!policyConfiguration.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); + debugOut(msg2); + logger.log(Level.SEVERE, msg1); + } + } catch (SecurityException ex) { + String err = "ERROR - got securityException calling policyConfiguration.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()); + ex.printStackTrace(); + } + } + + private void assertStateNotInservice(String callingMethod) { + try { + if (policyConfiguration.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); + debugOut(msg2); + logger.log(Level.SEVERE, msg1); + } + } catch (SecurityException ex) { + String err = "ERROR - got securityException calling policyConfiguration.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()); + ex.printStackTrace(); + } + } + + private void debugOut(String str) { + System.out.println(str); + } + +} diff --git a/tck/app-custom-trace-policyconfiguration/src/main/webapp/WEB-INF/beans.xml b/tck/app-custom-trace-policyconfiguration/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000..7b7b7ad --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,24 @@ + + + + \ No newline at end of file diff --git a/tck/app-custom-trace-policyconfiguration/src/main/webapp/WEB-INF/web.xml b/tck/app-custom-trace-policyconfiguration/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..4b2d50a --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,193 @@ + + + + + jacc_web_toolsContracts + + + jakarta.security.jacc.PolicyConfigurationFactory.provider + ee.jakarta.tck.authorization.test.TSPolicyConfigurationFactoryImpl + + + + + sslprotected + sslprotected + /sslprotected.jsp + 0 + + ADM + Administrator + + + MGR + Manager + + + + sslprotected + /sslprotected.jsp + + + + MySecureBit6 + /sslprotected.jsp + POST + GET + + + Administrator + + + CONFIDENTIAL + + + + + + + excluded + excluded + /excluded.jsp + 0 + + + excluded + /excluded.jsp + + + + MySecureBit5 + /excluded.jsp + POST + GET + + + + NONE + + + + + + + unchecked + unchecked + /unchecked.jsp + 0 + + + unchecked + /unchecked.jsp + + + + MySecureBit4 + /unchecked.jsp + POST + GET + + + NONE + + + + + + + anyauthuser + anyauthuser + /anyauthuser.jsp + 0 + + + anyauthuser + /anyauthuser.jsp + + + + MySecureBit5 + /anyauthuser.jsp + GET + POST + + + ** + + + NONE + + + + + + + + secured + secured + /secured.jsp + 0 + + ADM + Administrator + + + + secured + /secured.jsp + + + + MySecureBit3 + /secured.jsp + POST + GET + + + Administrator + + + NONE + + + + + + 54 + + + + BASIC + default + + + + Administrator + + + Manager + + + Employee + + diff --git a/tck/app-custom-trace-policyconfiguration/src/main/webapp/accesstoall.jsp b/tck/app-custom-trace-policyconfiguration/src/main/webapp/accesstoall.jsp new file mode 100644 index 0000000..032bded --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/src/main/webapp/accesstoall.jsp @@ -0,0 +1,58 @@ +<%-- + + Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. + + 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 + +--%> + + + +<%@ page language="java" %> + + + JSP with WildCard Auth Constraint + +

JSP with WildCard Auth Constraint

+ + <% + + out.println("The user principal is: " + request.getUserPrincipal().getName() + "
"); + out.println("getRemoteUser(): " + request.getRemoteUser() + "
" ); + + if (request.isUserInRole("ADM")){ + out.println("USR_IN_ROLE_ADM"); + }else + out.println("USR_NOT_IN_ROLE_ADM"); + + if (request.isUserInRole("MGR")){ + out.println("USR_IN_ROLE_MGR"); + }else + out.println("USR_NOT_IN_ROLE_MGR"); + + if (request.isUserInRole("EMP")){ + out.println("USR_IN_ROLE_EMP"); + }else + out.println("USR_NOT_IN_ROLE_EMP"); + + if (request.isUserInRole("VP")){ + out.println("USR_IN_ROLE_VP"); + }else + out.println("USR_NOT_IN_ROLE_VP"); + + %> + + + diff --git a/tck/app-custom-trace-policyconfiguration/src/main/webapp/anyauthuser.jsp b/tck/app-custom-trace-policyconfiguration/src/main/webapp/anyauthuser.jsp new file mode 100644 index 0000000..ab0c426 --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/src/main/webapp/anyauthuser.jsp @@ -0,0 +1,41 @@ +<%-- + + Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved. + + 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 + +--%> + + +<%@ page language="java" %> + + + JSP with Any Authenticated User Auth Constraint + +

JSP with Double-WildCard Auth Constraint

+ + <% + + out.println("The user principal is: " + request.getUserPrincipal().getName() + "
"); + out.println("getRemoteUser(): " + request.getRemoteUser() + "
" ); + + if (request.isUserInRole("**")){ + out.println("USR_IN_ROLE_STARSTAR"); + } else { + out.println("USR_NOT_IN_ROLE_STARSTAR"); + } + + %> + + + diff --git a/tck/app-custom-trace-policyconfiguration/src/main/webapp/excluded.jsp b/tck/app-custom-trace-policyconfiguration/src/main/webapp/excluded.jsp new file mode 100644 index 0000000..06aba36 --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/src/main/webapp/excluded.jsp @@ -0,0 +1,40 @@ +<%-- + + Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. + + 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 + +--%> + + + +<%@ page language="java" %> + + +JSP used for verifying excluded policy statement + +

JSP used for excluded policy statement

+ +<% + +out.println("The user principal is: " + request.getUserPrincipal().getName() + "
"); +out.println("getRemoteUser(): " + request.getRemoteUser() + "
" ); + +%> + + + + + diff --git a/tck/app-custom-trace-policyconfiguration/src/main/webapp/secured.jsp b/tck/app-custom-trace-policyconfiguration/src/main/webapp/secured.jsp new file mode 100644 index 0000000..cd4e79b --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/src/main/webapp/secured.jsp @@ -0,0 +1,48 @@ +<%-- + + Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. + + 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 + +--%> + + + +<%@ page language="java" %> + + +JSP with Security Constraint + +

JSP with Security Constraint

+ +<% + +out.println("The user principal is: " + request.getUserPrincipal().getName() + "
"); +out.println("getRemoteUser(): " + request.getRemoteUser() + "
" ); + +// Surround these with !'s so they are easier to search for. +// (i.e. we can search for !true! or !false!) +out.println("isUserInRole(\"ADM\"): !" + request.isUserInRole("ADM") + "!
"); +out.println("isUserInRole(\"MGR\"): !" + request.isUserInRole("MGR") + "!
"); +out.println("isUserInRole(\"VP\"): !" + request.isUserInRole("VP") + "!
"); +out.println("isUserInRole(\"EMP\"): !" + request.isUserInRole("EMP") + "!
"); +out.println("isUserInRole(\"Administrator\"): !" + request.isUserInRole("Administrator") + "!
"); + +%> + + + + + diff --git a/tck/app-custom-trace-policyconfiguration/src/main/webapp/sslprotected.jsp b/tck/app-custom-trace-policyconfiguration/src/main/webapp/sslprotected.jsp new file mode 100644 index 0000000..74efe76 --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/src/main/webapp/sslprotected.jsp @@ -0,0 +1,40 @@ +<%-- + + Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. + + 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 + +--%> + + + +<%@ page language="java" %> + + +SSL Proteected + +

SSL protected JSP

+ +<% + +out.println("The user principal is: " + request.getUserPrincipal().getName() + "
"); +out.println("getRemoteUser(): " + request.getRemoteUser() + "
" ); + +%> + + + + + diff --git a/tck/app-custom-trace-policyconfiguration/src/main/webapp/unchecked.jsp b/tck/app-custom-trace-policyconfiguration/src/main/webapp/unchecked.jsp new file mode 100644 index 0000000..46537b6 --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/src/main/webapp/unchecked.jsp @@ -0,0 +1,40 @@ +<%-- + + Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. + + 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 + +--%> + + + +<%@ page language="java" %> + + +JSP used for verifying unchecked permission + +

JSP used for unchecked permission

+ +<% + +out.println("The user principal is: " + request.getUserPrincipal().getName() + "
"); +out.println("getRemoteUser(): " + request.getRemoteUser() + "
" ); + +%> + + + + + diff --git a/tck/app-custom-trace-policyconfiguration/src/test/java/ee/jakarta/tck/authorization/test/AppCustomTracePolicyConfigurationIT.java b/tck/app-custom-trace-policyconfiguration/src/test/java/ee/jakarta/tck/authorization/test/AppCustomTracePolicyConfigurationIT.java new file mode 100644 index 0000000..a4d76f1 --- /dev/null +++ b/tck/app-custom-trace-policyconfiguration/src/test/java/ee/jakarta/tck/authorization/test/AppCustomTracePolicyConfigurationIT.java @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2024 Contributors to Eclipse Foundation. + * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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 ee.jakarta.tck.authorization.test; + +import static ee.jakarta.tck.authorization.util.ShrinkWrap.mavenWar; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import ee.jakarta.tck.authorization.util.ArquillianBase; +import ee.jakarta.tck.authorization.util.logging.client.LogFileProcessor; +import jakarta.security.jacc.WebResourcePermission; +import jakarta.security.jacc.WebRoleRefPermission; +import jakarta.security.jacc.WebUserDataPermission; +import java.security.Permissions; +import java.util.logging.Logger; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(Arquillian.class) +public class AppCustomTracePolicyConfigurationIT extends ArquillianBase { + + Logger logger = Logger.getLogger(AppCustomTracePolicyConfigurationIT.class.getName()); + + @Deployment(testable = false) + public static Archive createDeployment() { + return mavenWar(); + } + + /** + * @testName: WebUserDataPermission + * + * @assertion_ids: JACC:SPEC:41; JACC:SPEC:42; JACC:JAVADOC:54; + * JACC:JAVADOC:56; JACC:JAVADOC:58; JACC:SPEC:27; + * JACC:SPEC:28; JACC:SPEC:34; JACC:SPEC:52 + * + * @test_Strategy: 1. Register TS provider with the AppServer. (See User guide + * for Registering TS Provider with your AppServer ). + * + * 2. Deploy the application. + * + * 3. During deployment, appserver generates permissions for + * the J2EE components based on the given deployment + * descriptor + * + * 4. Retrieve server side logs and verify the generated + * unchecked permissions matches the expected permission + * collection + * + * + */ + @Test + public void WebUserDataPermission() { + LogFileProcessor logProcessor = new LogFileProcessor("getAppSpecificRecordCollection|appId", "toolsContracts"); + + + // ----------UNCHECKED----------// + // 1) retrieve server generated unchecked policy statements + // 2) construct expected unchecked policy statements + // 3) verify expected policy statements with generated policy statements + + // Get actual "unchecked" WebUserDataPermissions + Permissions uncheckedWebUserDataPermissions = + logProcessor.getSpecificPermissions( + logProcessor.getAppSpecificUnCheckedPermissions(), "WebUserDataPermission"); + + logger.info("Server generated unchecked WebUserDataPermissions"); + logProcessor.printPermissionCollection(uncheckedWebUserDataPermissions); + + // Construct the expected unchecked WebUserDataPermission + Permissions expectedUnCheckedPermissions = new Permissions(); + expectedUnCheckedPermissions.add(new WebUserDataPermission("/sslprotected.jsp", "GET,POST:CONFIDENTIAL")); + expectedUnCheckedPermissions.add(new WebUserDataPermission("/excluded.jsp", "!GET,POST")); + expectedUnCheckedPermissions.add(new WebUserDataPermission("/sslprotected.jsp", "!GET,POST")); + expectedUnCheckedPermissions.add(new WebUserDataPermission("/secured.jsp", (String) null)); + expectedUnCheckedPermissions.add(new WebUserDataPermission("/anyauthuser.jsp", "!GET,POST")); + expectedUnCheckedPermissions.add(new WebUserDataPermission("/:/unchecked.jsp:/secured.jsp:/sslprotected.jsp:/excluded.jsp:/anyauthuser.jsp", (String) null)); + expectedUnCheckedPermissions.add(new WebUserDataPermission("/unchecked.jsp", (String) null)); + + logger.info("verifying unchecked policy statments:"); + + assertTrue( + "WebUserDataPermission failed: " + "unchecked policy statements verification failed", + logProcessor.verifyLogImplies(expectedUnCheckedPermissions, uncheckedWebUserDataPermissions)); + + + + // ---------EXCLUDED----------// + // 1) retrieve server generated excluded policy statements + // 2) construct expected excluded policy statements + // 3) verify expected policy statements with generated policy statements + + // Get actual "excluded" WebUserDataPermission + Permissions excludedWebUserDataPermissions = + logProcessor.getSpecificPermissions( + logProcessor.getAppSpecificExcludedPermissions(), "WebUserDataPermission"); + + logger.info("Server generated excluded WebUserDataPermission"); + logProcessor.printPermissionCollection(excludedWebUserDataPermissions); + + // Construct the expected excluded WebUserDataPermission + Permissions expectedExcludedPermissions = new Permissions(); + expectedExcludedPermissions.add(new WebUserDataPermission("/excluded.jsp", "GET,POST")); + + logger.info("verifying excluded policy statments:"); + + assertTrue( + "WebUserDataPermission failed: " + "excluded policy statements verification failed", + logProcessor.verifyLogImplies(expectedExcludedPermissions, excludedWebUserDataPermissions)); + } + + + + /** + * @testName: WebResourcePermission + * + * @assertion_ids: JACC:SPEC:36; JACC:SPEC:72; JACC:SPEC:27; JACC:SPEC:28; JACC:SPEC:52; JACC:SPEC:128; + * + * @test_Strategy: 1. Register TS provider with the AppServer. (See User guide for Registering TS Provider with your + * AppServer ). + * + * 2. Deploy the application. + * + * 3. During deployment, appserver generates permissions for the EE components based on the given deployment + * descriptor + * + * 4. Retrieve server side logs and verify the generated permissions matches the expected permission collection + * + */ + @Test + public void WebResourcePermission() { + LogFileProcessor logProcessor = new LogFileProcessor("getAppSpecificRecordCollection|appId", "toolsContracts"); + + // ----------UNCHECKED----------// + // 1) retrieve server generated unchecked policy statements + // 2) construct expected unchecked policy statements + // 3) verify expected policy statements with generated policy statements + + Permissions expectedUnCheckedPermissions = new Permissions(); + + // Get "unchecked" WebResourcePermissions + Permissions uncheckedWebResourcePermissions = + logProcessor.getSpecificPermissions( + logProcessor.getAppSpecificUnCheckedPermissions(), "WebResourcePermission"); + + System.out.println("\n\nServer generated unchecked WebResourcePermissions"); + logProcessor.printPermissionCollection(uncheckedWebResourcePermissions); + + // Construct the expected unchecked WebResourcePermission + expectedUnCheckedPermissions.add(new WebResourcePermission("/unchecked.jsp", (String) null)); + expectedUnCheckedPermissions.add(new WebResourcePermission("/sslprotected.jsp", "!GET,POST")); + expectedUnCheckedPermissions.add(new WebResourcePermission("/:/secured.jsp:/unchecked.jsp:/excluded.jsp:/sslprotected.jsp:/anyauthuser.jsp", (String) null)); + expectedUnCheckedPermissions.add(new WebResourcePermission("/excluded.jsp", "!GET,POST")); + expectedUnCheckedPermissions.add(new WebResourcePermission("/secured.jsp", "!GET,POST")); + expectedUnCheckedPermissions.add(new WebResourcePermission("/anyauthuser.jsp", "!GET,POST")); + + System.out.println("verifying unchecked policy statments:"); + + assertTrue( + "WebResourcePermission failed: " + "unchecked policy statements verification failed", + logProcessor.verifyLogImplies(expectedUnCheckedPermissions, uncheckedWebResourcePermissions)); + + + + + + // ---------EXCLUDED----------// + // 1) Retrieve server generated excluded policy statements + // 2) Construct expected excluded policy statements + // 3) Verify expected policy statements with generated policy statements + + + + // Get actual "excluded" WebResourcePermissions + Permissions excludedWebResourcePermissions = + logProcessor.getSpecificPermissions( + logProcessor.getAppSpecificExcludedPermissions(), "WebResourcePermission"); + + System.out.println("\n\nServer generated excluded WebResourcePermissions"); + logProcessor.printPermissionCollection(excludedWebResourcePermissions); + + // Construct the expected excluded WebResourcePermission + Permissions expectedExcludedPermissions = new Permissions(); + expectedExcludedPermissions.add(new WebResourcePermission("/excluded.jsp", "GET,POST")); + + System.out.println("verifying excluded policy statments:"); + + assertTrue( + "WebResourcePermission failed: " + "excluded policy statements verification failed", + logProcessor.verifyLogImplies(expectedExcludedPermissions, excludedWebResourcePermissions)); + + + + + + // ---------ADDTOROLE----------// + // 1) retrieve server generated addToRole policy statements + // 2) construct expected addToRole policy statements + // 3) verify expected policy statements with generated policy statements + + + // Get actual "addToRole" WebResourcePermissions + Permissions addToRoleWebResourcePermissions = + logProcessor.getSpecificPermissions( + logProcessor.getAppSpecificAddToRolePermissions(), "WebResourcePermission"); + + System.out.println("\n\nServer generated addToRole WebResourcePermissions"); + logProcessor.printPermissionCollection(addToRoleWebResourcePermissions); + + // Construct the expected excluded WebResourcePermission + Permissions expectedAddToRolePermissions = new Permissions(); + expectedAddToRolePermissions.add(new WebResourcePermission("/secured.jsp", "GET,POST")); + expectedAddToRolePermissions.add(new WebResourcePermission("/sslprotected.jsp", "GET,POST")); + expectedAddToRolePermissions.add(new WebResourcePermission("/anyauthuser.jsp", "GET,POST")); + + System.out.println("verifying addToRole policy statments:"); + + assertTrue( + "WebResourcePermission failed: " + "addToRole policy statements verification failed", + logProcessor.verifyLogImplies(expectedAddToRolePermissions, addToRoleWebResourcePermissions)); + } + + /** + * @testName: WebResourcePermissionExcludedPolicy + * + * @assertion_ids: JACC:SPEC:37; JACC:SPEC:114; JACC:SPEC:111; JACC:SPEC:27; + * JACC:SPEC:28; JACC:SPEC:34; JACC:SPEC:52 + * + * @test_Strategy: 1. Register TS provider with the AppServer. (See User guide + * for Registering TS Provider with your AppServer ). + * + * 2. Deploy the application. + * + * 3. During deployment, appserver generates permissions for + * the J2EE components based on the given deployment + * descriptor + * + * 4. Retrieve server side logs and verify the generated + * permissions matches the expected permission collection + * + */ + @Test + public void WebResourcePermissionExcludedPolicy() { + + // ---------EXCLUDED----------// + // 1) retrieve server generated excluded policy statements + // 2) construct expected excluded policy statements + // 3) verify expected policy statements with generated policy statements + + LogFileProcessor logProcessor = new LogFileProcessor("getAppSpecificRecordCollection|appId", "toolsContracts"); + + // Get "excluded" WebResourcePermissions + Permissions excludedWebResourcePermissions = + logProcessor.getSpecificPermissions( + logProcessor.getAppSpecificExcludedPermissions(), "WebResourcePermission"); + + logger.info("Server generated excluded WebResourcePermissions"); + + logProcessor.printPermissionCollection(excludedWebResourcePermissions); + + // Construct the expected excluded WebResourcePermission + Permissions expectedExcludedPermissions = new Permissions(); + expectedExcludedPermissions + .add(new WebResourcePermission("/excluded.jsp", "GET,POST")); + + logger.info("verifying excluded policy statments:"); + + assertTrue( + "WebResourcePermissionExcludedPolicy failed: " + "excluded policy statements verification failed", + logProcessor.verifyLogImplies(expectedExcludedPermissions, excludedWebResourcePermissions)); + } + + /** + * @testName: WebResourcePermissionUnCheckedPolicy + * + * @assertion_ids: JACC:SPEC:36; JACC:SPEC:39; JACC:SPEC:27; JACC:SPEC:28; + * JACC:SPEC:52; JACC:JAVADOC:17 + * + * @test_Strategy: 1. Register TS provider with the AppServer. (See User guide + * for Registering TS Provider with your AppServer ). + * + * 2. Deploy the application. + * + * 3. During deployment, appserver generates permissions for + * the J2EE components based on the given deployment + * descriptor + * + * 4. Retrieve server side logs and verify the generated + * unchecked permissions matches the expected permission + * collection + */ + @Test + public void WebResourcePermissionUnCheckedPolicy() { + LogFileProcessor logProcessor = new LogFileProcessor("getAppSpecificRecordCollection|appId", "toolsContracts"); + + + // Get "unchecked" WebResourcePermissions + Permissions uncheckedWebResourcePermissions = + logProcessor.getSpecificPermissions( + logProcessor.getAppSpecificUnCheckedPermissions(), "WebResourcePermission"); + + logger.info("Server generated unchecked WebResourcePermissions"); + logProcessor.printPermissionCollection(uncheckedWebResourcePermissions); + + // Construct the expected unchecked WebResourcePermission + Permissions expectedPermissions = new Permissions(); + expectedPermissions.add(new WebResourcePermission("/unchecked.jsp", (String) null)); + expectedPermissions.add(new WebResourcePermission("/sslprotected.jsp", "!GET,POST")); + expectedPermissions.add(new WebResourcePermission("/:/secured.jsp:/unchecked.jsp:/excluded.jsp:/sslprotected.jsp:/anyauthuser.jsp", (String) null)); + expectedPermissions.add(new WebResourcePermission("/excluded.jsp", "!GET,POST")); + expectedPermissions.add(new WebResourcePermission("/secured.jsp", "!GET,POST")); + expectedPermissions.add(new WebResourcePermission("/anyauthuser.jsp", "!GET,POST")); + + assertTrue( + "WebResourcePermissionUnCheckedPolicy failed", + logProcessor.verifyLogImplies(expectedPermissions, uncheckedWebResourcePermissions)); + } + + + /** + * @testName: WebRoleRefPermission + * + * @assertion_ids: JACC:SPEC:36; JACC:SPEC:112; JACC:SPEC:38; JACC:SPEC:43; + * JACC:SPEC:44; JACC:JAVADOC:50; JACC:SPEC:27; JACC:SPEC:28; + * JACC:SPEC:45; JACC:SPEC:52; JACC:SPEC:75; JACC:SPEC:128; + * JACC:SPEC:131 + * + * @test_Strategy: 1. Register TS provider with the AppServer. (See User guide + * for Registering TS Provider with your AppServer ). 2. + * Deploy the application. + * + * 3. During deployment, appserver generates permissions for + * the EE components based on the given deployment + * descriptor + * + * 4. Retrieve server side logs and verify the generated + * permissions matches the expected permission collection + */ + @Test + public void WebRoleRefPermission() { + + // ---------ADDTOROLE----------// + // 1) retrieve server generated addToRole policy statements + // 2) construct expected addToRole policy statements + // 3) verify expected policy statements with generated policy statements + + LogFileProcessor logProcessor = new LogFileProcessor("getAppSpecificRecordCollection|appId", "toolsContracts"); + + // Get actual "addToRole" WebRoleRefPermissions + Permissions addToRoleWebRoleRefPermissions = + logProcessor.getSpecificPermissions( + logProcessor.getAppSpecificAddToRolePermissions(), "WebRoleRefPermission"); + + logger.info("Server generated addToRole WebRoleRefPermissions"); + logProcessor.printPermissionCollection(addToRoleWebRoleRefPermissions); + + // Construct the expected excluded WebRoleRefPermission + Permissions expectedAddToRolePermissions = new Permissions(); + expectedAddToRolePermissions.add(new jakarta.security.jacc.WebRoleRefPermission("secured", "ADM")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("secured", "Administrator")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("secured", "Manager")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("secured", "Employee")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("sslprotected", "MGR")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("sslprotected", "ADM")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("sslprotected", "Administrator")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("sslprotected", "Manager")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("sslprotected", "Employee")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("unchecked", "Manager")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("unchecked", "Administrator")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("unchecked", "Employee")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("excluded", "Manager")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("excluded", "Administrator")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("excluded", "Employee")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("anyauthuser", "Employee")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("anyauthuser", "Manager")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("anyauthuser", "Administrator")); + + // JSR115 Maintenance Review changes + expectedAddToRolePermissions.add(new WebRoleRefPermission("", "Administrator")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("", "Manager")); + expectedAddToRolePermissions.add(new WebRoleRefPermission("", "Employee")); + + logger.info("verifying addToRole policy statments:"); + + assertTrue( + "WebRoleRefPermission failed: " + "addToRole policy statements verification failed", + logProcessor.verifyLogImplies(expectedAddToRolePermissions, addToRoleWebRoleRefPermissions)); + } + + + /** + * @testName: AnyAuthUserWebRoleRef + * + * @assertion_ids: JACC:SPEC:130; JACC:SPEC:131; + * + * @test_Strategy: This is testing that: If the any authenticated user + * role-name, **, does not appear in a security-role-ref + * within the servlet, a WebRoleRefPermission must also be + * added for it. The name of each such WebRoleRefPermission + * must be the servlet-name of the corresponding servlet + * element. steps: 1. We have any-authenticated-user + * referenced in a security-constraint in our DD (for + * anyauthuser.jsp) We have a total of 5 servlets defined in + * our DD also. + * + * 2. Deploy the application. + * + * 3. During deployment, appserver generates permissions for + * the EE components based on the given deployment + * descriptor + * + * 4. Retrieve server side logs and verify the generated + * permissions matches the expected permission collection + */ + @Test + public void AnyAuthUserWebRoleRef() { + LogFileProcessor logProcessor = new LogFileProcessor("getAppSpecificRecordCollection|appId", "toolsContracts"); + + // Retrieve server generated addToRole policy statements + Permissions addToRoleWebRoleRefPermissions = + logProcessor.getSpecificPermissions( + logProcessor.getAppSpecificAddToRolePermissions(), "WebRoleRefPermission"); + + // For debug aid, print out server generated addToRole policy statements + logger.info("Server generated addToRole WebRoleRefPermissions"); + logProcessor.printPermissionCollection(addToRoleWebRoleRefPermissions); + + // According to the Jakarta Authorization 1.5 spec (chapter 3, section 3.1.3.3), + // it states that: + // + // "a WebRoleRefPermission must also be added for it" (meaning **) + // and that + // "The name of each such WebRoleRefPermission must be the servlet-name + // of the corresponding servlet element." + // + // This means for each servlet definition in our web.xml, there will need to + // exist a WebRoleRefPermission with that servlet name for the ** role. + // + Permissions expectedAddToRolePerms = new Permissions(); + expectedAddToRolePerms.add(new WebRoleRefPermission("excluded", "**")); + expectedAddToRolePerms.add(new WebRoleRefPermission("unchecked", "**")); + expectedAddToRolePerms.add(new WebRoleRefPermission("sslprotected", "**")); + expectedAddToRolePerms.add(new WebRoleRefPermission("secured", "**")); + expectedAddToRolePerms.add(new WebRoleRefPermission("anyauthuser", "**")); + + logger.info("verifying addToRole policy statments:"); + + assertTrue( + "AnyAuthUserWebRoleRef failed: " + "addToRole policy statements for any-authenticated-user (**) failed", + logProcessor.verifyLogImplies(expectedAddToRolePerms, addToRoleWebRoleRefPermissions)); + } + + /** + * @testName: validateNoInvalidStates + * + * @assertion_ids: JACC:SPEC:60; + * + * @test_Strategy: 1. Register TS provider with the AppServer. (See User guide + * for Registering TS Provider with your AppServer ). + * + * 2. Read the server side log to verify PolicyConfigurationFactory + * is called and instantiated in the server. + * + * Description: + * + * This method looks for occurrences of error + * message within JACCLog.txt where those error messages would + * only appear in JACCLog.txt if there was a + * policyConfiguration lifecycle state that was in the wrong + * state at the wrong time. + * + * This can ONLY test the state for being in the 'inService' + * state or not. So testing is done + * to make sure the PolicyConfigration state is correct wrt + * policyConfiguration.inService() for each of the methods + * defined in the PolicyConfiguration javadoc table. + * + * Again, + * this is not a complete validation of all states, but is + * only able to validate if the state is inService or not at + * each of the method calls based on the javadoc table. + * Occurrence of an ERROR message below would be a flag for a + * method being in an incorrect state. + */ + @Test + public void validateNoInvalidStates() { + LogFileProcessor logProcessor = new LogFileProcessor("getAppSpecificRecordCollection|appId", "toolsContracts"); + + String errorMessage1 = "ERROR - our policy config should not be in the INSERVICE state."; + + // Verify that the log contains no errors related to the inService state + assertFalse( + "validateNoInvalidStates failed : detected error message of: " + errorMessage1, + logProcessor.verifyLogContains(errorMessage1)); + + + String errorMessage2 = "ERROR - our policy config should be in the INSERVICE state."; + + assertFalse( + "validateNoInvalidStates failed : detected error message of: " + errorMessage2, + logProcessor.verifyLogContains(errorMessage2)); + } + + +} diff --git a/tck/app-custom-trace-policyconfigurationfactory/pom.xml b/tck/app-custom-trace-policyconfigurationfactory/pom.xml new file mode 100644 index 0000000..a07ba28 --- /dev/null +++ b/tck/app-custom-trace-policyconfigurationfactory/pom.xml @@ -0,0 +1,56 @@ + + + + + 4.0.0 + + + org.eclipse.ee4j.authorization.tck + jakarta-authorization-tck + 4.0.0-SNAPSHOT + + + app-custom-trace-policyconfigurationfactory + war + + + This module installs a tracing PolicyConfigurationFactory that writes to a seperate log file + called "authorization-trace-log.xml". The location where this file will be written can be + set using the "log.file.location" system property for both the server and the client test. + + The test uses the log file to check for certain calls being made to PolicyConfigurationFactory. + + + + false + + + + + org.eclipse.ee4j.authorization.tck + common + ${project.version} + + + + + app-custom-trace-policyconfigurationfactory + + diff --git a/tck/app-custom-trace-policyconfigurationfactory/src/main/java/ee/jakarta/tck/authorization/test/PublicServlet.java b/tck/app-custom-trace-policyconfigurationfactory/src/main/java/ee/jakarta/tck/authorization/test/PublicServlet.java new file mode 100644 index 0000000..9651411 --- /dev/null +++ b/tck/app-custom-trace-policyconfigurationfactory/src/main/java/ee/jakarta/tck/authorization/test/PublicServlet.java @@ -0,0 +1,39 @@ +/* + * 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 ee.jakarta.tck.authorization.test; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * This servlet only exist so that we have a resource in the application available + * The tests don't actually need to call this. + */ +@WebServlet("/PublicServlet") +public class PublicServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().append("Served at: ").append(request.getContextPath()); + } + +} 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 new file mode 100644 index 0000000..1dc0365 --- /dev/null +++ b/tck/app-custom-trace-policyconfigurationfactory/src/main/java/ee/jakarta/tck/authorization/test/TSPolicyConfigurationFactoryImpl.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * Copyright (c) 2007, 2022 Oracle and/or its affiliates. All rights reserved. + * + * 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 + */ + +/** + * $Id$ + * + * @author Raja Perumal + * 08/01/02 + */ + +package ee.jakarta.tck.authorization.test; + +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; +import jakarta.security.jacc.PolicyConfigurationFactory; +import jakarta.security.jacc.PolicyContext; +import jakarta.security.jacc.PolicyContextException; + +/** + * Jakarta Authorization PolicyConfigurationFactory + * + *

+ * This is a delegating PolicyConfigurationFactory which delegates the policy + * configurations to vendor implementation of PolicyConfigurationFactory class. + * + *

+ * It traces a few operations into a dedicated log, which the tests inspect. + * + */ +public class TSPolicyConfigurationFactoryImpl extends PolicyConfigurationFactory { + + private static TSLogger logger = TSLogger.getTSLogger(); + + 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); + } + } + + /** + * 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. + *

+ * + * @param contextId A String identifying the policy context whose PolicyConfiguration interface is to be returned. The + * value passed to this parameter must not be null. + *

+ * @param remove A boolean value that establishes whether or not the policy statements of an existing policy context are + * to be removed before its PolicyConfiguration object is returned. If the value passed to this parameter is true, the + * policy statements of an existing policy context will be removed. If the value is false, they will not be removed. + * + * @return an Object that implements the PolicyConfiguration Interface matched to the Policy provider and corresponding + * to the identified policy context. + * + * @throws java.lang.SecurityException when called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the getPolicyConfiguration method signature. The exception thrown by the implementation class + * will be encapsulated (during construction) in the thrown PolicyContextException. + */ + + public PolicyConfiguration getPolicyConfiguration(String contextId, boolean remove) throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("PolicyConfigurationFactoryImpl", "getPolicyConfiguration"); + } + + PolicyConfiguration policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextId, remove); + + logger.log(INFO, "PolicyConfigurationFactory.getPolicyConfiguration() invoked"); + logger.log(FINER, "Getting PolicyConfiguration object with id = " + contextId); + + 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. + *

+ * + * @param contextId A string identifying a policy context + * + * @return true if the identified policy context exists within the provider and its state is "inService", false + * otherwise. + * + * @throws java.lang.SecurityException when called by an AccessControlContext that has not been granted the "setPolicy" + * SecurityPermission. + * + * @throws jakarta.security.jacc.PolicyContextException if the implementation throws a checked exception that has not + * been accounted for by the inService method signature. The exception thrown by the implementation class will be + * encapsulated (during construction) in the thrown PolicyContextException. + */ + public boolean inService(String contextId) throws PolicyContextException { + if (logger.isLoggable(FINER)) { + logger.entering("PolicyConfigurationFactoryImpl", "inService"); + } + logger.log(INFO, "PolicyConfigurationFactory.inService() invoked"); + logger.log(FINER, "PolicyConfiguration.inService() invoked for context id = " + contextId); + + return policyConfigurationFactory.inService(contextId); + } + + public PolicyConfiguration getPolicyConfiguration(String contextID) { + if (logger.isLoggable(FINER)) { + logger.entering("PolicyConfigurationFactoryImpl", "getPolicyConfiguration(String)"); + } + + PolicyConfiguration policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextID); + logger.log(INFO, "PolicyConfigurationFactory.getPolicyConfiguration(String) invoked"); + + return policyConfiguration; + } + + public PolicyConfiguration getPolicyConfiguration() { + if (logger.isLoggable(FINER)) { + logger.entering("PolicyConfigurationFactoryImpl", "getPolicyConfiguration()"); + } + + String contextId = PolicyContext.getContextID(); + PolicyConfiguration policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextId); + logger.log(INFO, "PolicyConfigurationFactory.getPolicyConfiguration(String) invoked"); + logger.log(FINER, "Getting PolicyConfiguration object with id = " + contextId); + + return policyConfiguration; + } + +} diff --git a/tck/app-custom-trace-policyconfigurationfactory/src/main/webapp/WEB-INF/beans.xml b/tck/app-custom-trace-policyconfigurationfactory/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000..7b7b7ad --- /dev/null +++ b/tck/app-custom-trace-policyconfigurationfactory/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,24 @@ + + + + \ No newline at end of file diff --git a/tck/app-custom-trace-policyconfigurationfactory/src/main/webapp/WEB-INF/web.xml b/tck/app-custom-trace-policyconfigurationfactory/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..70cdbba --- /dev/null +++ b/tck/app-custom-trace-policyconfigurationfactory/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,26 @@ + + + + jacc_web_toolsContracts + + + jakarta.security.jacc.PolicyConfigurationFactory.provider + ee.jakarta.tck.authorization.test.TSPolicyConfigurationFactoryImpl + + \ No newline at end of file diff --git a/tck/app-custom-trace-policyconfigurationfactory/src/test/java/ee/jakarta/tck/authorization/test/AppCustomTracePolicyConfigurationFactoryIT.java b/tck/app-custom-trace-policyconfigurationfactory/src/test/java/ee/jakarta/tck/authorization/test/AppCustomTracePolicyConfigurationFactoryIT.java new file mode 100644 index 0000000..d9725be --- /dev/null +++ b/tck/app-custom-trace-policyconfigurationfactory/src/test/java/ee/jakarta/tck/authorization/test/AppCustomTracePolicyConfigurationFactoryIT.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024 Contributors to Eclipse Foundation. + * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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 ee.jakarta.tck.authorization.test; + +import static ee.jakarta.tck.authorization.util.ShrinkWrap.mavenWar; +import static org.junit.Assert.assertTrue; + +import ee.jakarta.tck.authorization.util.ArquillianBase; +import ee.jakarta.tck.authorization.util.logging.client.LogFileProcessor; +import java.util.logging.Logger; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(Arquillian.class) +public class AppCustomTracePolicyConfigurationFactoryIT extends ArquillianBase { + + Logger logger = Logger.getLogger(AppCustomTracePolicyConfigurationFactoryIT.class.getName()); + + @Deployment(testable = false) + public static Archive createDeployment() { + return mavenWar(); + } + + /** + * @testName: PolicyConfigurationFactory + * + * @assertion_ids: JACC:SPEC:25; JACC:SPEC:15; JACC:SPEC:63 + * + * @test_Strategy: 1. Register TS provider with the AppServer. (See User guide + * for Registering TS Provider with your AppServer ). + * + * 2. Read the server side log to + * verify PolicyConfigurationFactory is called and + * instantiated in the server. + * + * Description The getPolicyConfigurationFactory method must + * be used in the containers to which the application or + * module are being deployed to find or instantiate + * PolicyConfigurationFactory objects. + * + */ + @Test + public void PolicyConfigurationFactory() { + LogFileProcessor logProcessor = new LogFileProcessor("appId", "toolsContracts"); + + // Verify whether the log contains required messages. + assertTrue( + "PolicyConfigurationFactory failed : " + "PolicyconfigurationFactory not instantiated", + logProcessor.verifyLogContains("PolicyConfigurationFactory instantiated")); + } + + /** + * @testName: GetPolicyConfiguration + * + * @assertion_ids: JACC:SPEC:26; JACC:JAVADOC:28; JACC:JAVADOC:29 + * + * @test_Strategy: 1. Register TS provider with the AppServer. (See User guide + * for Registering TS Provider with your AppServer ). + * + * 2. Read the server side log to + * verify PolicyConfigurationFactory is called and + * instantiated in the server. + * + * Description The getPolicyconfiguration method of the + * factory must be used to find or instantiate + * PolicyConfiguration objects corresponding to the + * application or modules being deployed. + * + */ + @Test + public void GetPolicyConfiguration() { + LogFileProcessor logProcessor = new LogFileProcessor("appId", "toolsContracts"); + + // Verify whether the log contains required messages. + assertTrue( + "GetPolicyConfiguration failed : " + "getPolicyconfiguration() was not invoked", + logProcessor.verifyLogContains("PolicyConfigurationFactory.getPolicyConfiguration() invoked")); + } + +} diff --git a/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/client/LogFileProcessor.java b/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/client/LogFileProcessor.java new file mode 100644 index 0000000..0bff1cf --- /dev/null +++ b/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/client/LogFileProcessor.java @@ -0,0 +1,1336 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * Copyright (c) 2007, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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 ee.jakarta.tck.authorization.util.logging.client; + +import static java.util.logging.Level.SEVERE; + +import jakarta.security.jacc.EJBMethodPermission; +import jakarta.security.jacc.EJBRoleRefPermission; +import jakarta.security.jacc.WebResourcePermission; +import jakarta.security.jacc.WebRoleRefPermission; +import jakarta.security.jacc.WebUserDataPermission; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.SequenceInputStream; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.logging.Logger; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * + * @author Raja Perumal + */ +/** + * LogFileProcessor does the following operations + * + * 1) Fetches log records from authorization-trace-log.xml + * + * 2) Checks for the existence of search string in the log for example to verify whether server log contains a string + * "Java EE rocks" use the following code + * + * LogFileProcessor logProcessor = new LogFileProcessor(properties); boolean contains = + * logProcessor.verifyLogContains("Java EE rocks"); + * + * where "properties" contains the following key value pair 1) log.file.location + * + * 3) Prints the collection of log records. + * + */ +public class LogFileProcessor { + + private static final Logger logger = Logger.getLogger(LogFileProcessor.class.getName()); + + + private Collection recordCollection = new Vector<>(); + private Collection appIdRecordCollection = new Vector<>(); + private Collection linkRecordCollection = new Vector<>(); + private Collection appSpecificRecordCollection = new Vector<>(); + + private Permissions appSpecificUnCheckedPermissions = new Permissions(); + private Permissions appSpecificExcludedPermissions = new Permissions(); + private Permissions appSpecificAddToRolePermissions = new Permissions(); + + public LogFileProcessor() { + } + + public LogFileProcessor(String accessMethod, String appName) { + fetchLogs(accessMethod, appName); + } + + public Permissions getAppSpecificUnCheckedPermissions() { + return appSpecificUnCheckedPermissions; + } + + public Permissions getAppSpecificExcludedPermissions() { + return appSpecificExcludedPermissions; + } + + public Permissions getAppSpecificAddToRolePermissions() { + return appSpecificAddToRolePermissions; + } + + /* + * This is convenience method for pulling out a list of permissions from records that are identified with passed in that + * match all of the following: - permission category (e.g. "excluded", "unchecked", "addToRole") - permission type + * ("WebResourcePermission", etc) - with an appcontext that contains the passed in appContext value. If you want a + * complete matching appContext, then pass the whole thing in. + */ + public Permissions getAppSpecificPermissions(String permCat, String permType, String appContext) { + if (appSpecificRecordCollection == null) { + return null; + } + + Permissions appSpecificPermissions = new Permissions(); + + for (LogRecordEntry recordEntry : appSpecificRecordCollection) { + Permission permission = getPermissionFromRecordEntry(recordEntry, permCat, permType, appContext); + if (permission != null) { + appSpecificPermissions.add(permission); + } + } + + return appSpecificPermissions; + } + + public void fetchLogs(String accessMethod) { + fetchLogs(accessMethod, null); + } + + /** + * FetchLogs pull logs from the server. + * + */ + public void fetchLogs(String accessMethod, String appName) { + + File logfile = null; + + try { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + + String logFileLocation = System.getProperty("log.file.location"); + if (logFileLocation == null) { + throw new IllegalStateException("System property log.file.location not defined"); + } + + logFileLocation += "/authorization-trace-log.xml"; + + logfile = new File(logFileLocation); + + if (logfile == null || !logfile.exists()) { + System.out.println("Log File : " + logFileLocation + " does not exists"); + System.out.println("Check permissions for log file "); + System.out.println("See User guide for Configuring log file permissions"); + } else { + // LogRecords will be added to JACCLog.txt as long as the server is + // up and running. Since TSSLog.txt is continuously updated with + // more record there will not be any end tag at the end of the + // log file. + // + // This will cause the SAXParser to throw fatal error message + // "XML Document structures must start and end with the + // same entity" + // + // In order to avoid this error message the FileInputStream + // should have the end tag , this can be achieved by + // creating a SequenceInputStream which includes a + // FileInputStream and a ByteArrayInputStream, where the + // ByteArrayInputStream contains the bytes for + // + String endLogTag = ""; + ByteArrayInputStream bais = new ByteArrayInputStream(endLogTag.getBytes()); + SequenceInputStream sis = new SequenceInputStream(new FileInputStream(logFileLocation), bais); + + Document document = documentBuilder.parse(sis); + Element rootElement = document.getDocumentElement(); + NodeList nodes = rootElement.getChildNodes(); + + String queryString = "pullAllRecords"; + String queryParams = "fullLog"; + + StringTokenizer strtoken = new StringTokenizer(accessMethod, "|"); + + if (accessMethod.indexOf("|") > 0) { + queryString = strtoken.nextToken(); + queryParams = strtoken.nextToken(); + } + + if (queryString.equals("pullAllRecords")) { + recordCollection = pullAllLogRecords(queryParams, nodes); + } else if (queryString.equals("getAppSpecificRecordCollection")) { + + // Get appId records(appId records are records which identifies + // the records with application name and time stamp ). + // + // for extracting appId records, process each record and + // search whether the record starts with "appId" string. + // + // if the log records starts with "appId" + // i.e if (log records starts with "appId") then + // add the records to appIdRecordCollection + // else if (log records starts with "link") then + // add the records to linkRecordCollection + // else + // add the records to recordCollection + // + // Note: In the process of locating appId records + // the remaining records are also processed and + // stored as "linkRecordCollection" and + // "recordCollection" based on the content of the records + + // This call populates both appIdRecordCollection and + // the rest of record collection + appIdRecordCollection = getAppIdRecordCollection("appId", nodes); + + // Parse through all appId records and + // find the current application name + String applicationName = null; + if (appName == null) { + applicationName = getCurrentApplicationName(); + } else { + applicationName = getCurrentApplicationName(appName); + } + + // Parse all link records and find all the + // applications that are linked to the current application + Vector linkedApplicationNames = getLinkedApplicationNames(); + + // Using the application names, isolate the + // application specific logs from the rest of the logs + Collection newAppSpecificRecordCollection = getAppSpecificRecordCollection(applicationName, linkedApplicationNames); + + } + + // From the record collection read all the records + // and construct list of Permissions such as + // + // 1) appSpecificUnCheckedPermissions + // 2) appSpecificExcludedPermissions + // 3) appSpecificAddToRolePermissions + // + // Where "appSpecificUnCheckedPermissions" contains all the + // application specific unchecked permission collection. + // + // "appSpecificExcludedPermissions" contains all the + // application specific excluded permission collection. + // + // "appSpecificAddToRolePermissions" contains all the + // application specific add to role permission collection. + // + getPermissionCollection(); + } + + } catch (Exception e) { + logger.log(SEVERE, e.getMessage(), e); + } + + } + + public PermissionCollection getPermissionCollection() { + if (appSpecificRecordCollection == null) { + return null; + } + + PermissionCollection permissionCollection = new Permissions(); + + for (LogRecordEntry recordEntry : appSpecificRecordCollection) { + Permission permission = getPermissionFromRecordEntry(recordEntry); + if (permission != null) { + permissionCollection.add(permission); + } + } + + return permissionCollection; + } + + // Parse record entry and extract permissions from the following + // type of log records "unchecked", "excluded" and "addToRole" + // + // unchecked :: appName , 1058323788497 , EJBMethodPermission , MEJBBean , + // getMBeanCount,Remote + // addToRole :: appName3 , 1058323977373 , WebResourcePermission , + // /secured.jsp , GET,POST + // excluded :: appName2 , 1058323977373 , WebUserDataPermission , + // /excluded.jsp , GET,POST + // + // In the above records + // + // 1) First field identifies the category of record + // 2) second field identifies the application name + // 3) thrid field identifies the timestamp in which + // the record was created. + // 4) fourth field identifies the Permission type such as + // a) WebResourcePermission b) WebRoleRefPermission + // c) WebUserDataPermission d) EJBMehodPermission + // e) EJBRoleRefPermission + // 5) fifth field identifies the permission name + // 6) sixth field identifies the permission action. + // + public Permission getPermissionFromRecordEntry(LogRecordEntry recordEntry) { + + String permissionCategory = null; + String applicationContext = null; + String temp = null; + String message = null; + String permissionType = null; + String permissionName = null; + String permissionAction = null; + String permissionNameAndAction = null; + String applicationTimeStamp = null; + String[] tokenArray = new String[2]; + StringTokenizer permCategoryToken = null; + StringTokenizer strtok = null; + boolean isUnChecked = false; + boolean isExcluded = false; + boolean isAddToRole = false; + + Permission p = null; + + if (recordEntry != null) { + message = recordEntry.getMessage(); + // Get permission category + // i.e "unchecked, excluded or addTorole" + permCategoryToken = new StringTokenizer(message, " :: "); + if (message.indexOf(" :: ") > 0) { + permissionCategory = permCategoryToken.nextToken(); + temp = message.substring(permissionCategory.length() + 4, message.length()); + } + // logger.info("PermissionCategory ="+permissionCategory); + + if (permissionCategory != null) { + if (permissionCategory.equals("unchecked")) { + isUnChecked = true; + } else if (permissionCategory.equals("excluded")) { + isExcluded = true; + } else if (permissionCategory.equals("addToRole")) { + isAddToRole = true; + } + } + + // i.e Proceed only if the permission Category is one of the following + // a) unchecked + // b) excluded + // c) addToRole + // else return null + if (isUnChecked || isExcluded || isAddToRole) { + // Get ApplicationContext + tokenArray = getTokens(temp, " , "); + applicationContext = tokenArray[0]; + temp = tokenArray[1]; + logger.fine("Application Context =" + applicationContext); + + // Get Application time stamp + tokenArray = getTokens(temp, " , "); + applicationTimeStamp = tokenArray[0]; + temp = tokenArray[1]; + logger.fine("Application Time stamp =" + applicationTimeStamp); + + // Get permission Type + tokenArray = getTokens(temp, " , "); + permissionType = tokenArray[0]; + permissionNameAndAction = tokenArray[1]; + logger.fine("PermissionType =" + permissionType); + + // extract permission name and action + tokenArray = getTokens(permissionNameAndAction, " , "); + permissionName = tokenArray[0]; + permissionAction = tokenArray[1]; + logger.fine("permissionName = " + permissionName); + logger.fine("permissionAction = " + permissionAction); + + // Change string "null" to just null + // i.e "null" --> null + if (permissionAction.equals("null")) { + permissionAction = null; // Construct permissions based on their + // permission type + } + if (permissionType.equals("WebResourcePermission")) { + p = new WebResourcePermission(permissionName, permissionAction); + } else if (permissionType.equals("WebRoleRefPermission")) { + p = new WebRoleRefPermission(permissionName, permissionAction); + } else if (permissionType.equals("WebUserDataPermission")) { + p = new WebUserDataPermission(permissionName, permissionAction); + } else if (permissionType.equals("EJBMethodPermission")) { + p = new EJBMethodPermission(permissionName, permissionAction); + } else if (permissionType.equals("EJBRoleRefPermission")) { + p = new EJBRoleRefPermission(permissionName, permissionAction); // Add + // permissions + // to + // their + // corresponding + // permission + // collection + // based on their permission category type + } + if (isUnChecked) { + appSpecificUnCheckedPermissions.add(p); + } else if (isExcluded) { + appSpecificExcludedPermissions.add(p); + } else if (isAddToRole) { + appSpecificAddToRolePermissions.add(p); + + } + } + } + + return p; + } + + public Permission getPermissionFromRecordEntry(LogRecordEntry recordEntry, String permCat, String permType, String appContext) { + String permissionCategory = null; + String applicationContext = null; + String temp = null; + String message = null; + String permissionType = null; + String permissionName = null; + String permissionAction = null; + String permissionNameAndAction = null; + String applicationTimeStamp = null; + String[] tokenArray = new String[2]; + StringTokenizer permCategoryToken = null; + + Permission p = null; + + if (recordEntry != null) { + message = recordEntry.getMessage(); + // Get permission category + // i.e "unchecked, excluded or addToRole" + permCategoryToken = new StringTokenizer(message, " :: "); + if (message.indexOf(" :: ") > 0) { + permissionCategory = permCategoryToken.nextToken(); + temp = message.substring(permissionCategory.length() + 4, message.length()); + } + + if (permissionCategory == null || !permissionCategory.equals(permCat)) { + logger.fine(permissionCategory + " != " + permCat); + return null; + } + + logger.fine(permissionCategory + " == " + permCat); + + // Get ApplicationContext + tokenArray = getTokens(temp, " , "); + applicationContext = tokenArray[0]; + temp = tokenArray[1]; + if (!applicationContext.contains(appContext)) { + logger.fine(applicationContext + " != " + appContext); + return null; + } + logger.fine("applicationContext =" + applicationContext); + + // Get Application time stamp + tokenArray = getTokens(temp, " , "); + applicationTimeStamp = tokenArray[0]; + temp = tokenArray[1]; + logger.fine("Application Time stamp =" + applicationTimeStamp); + + // Get permission Type + tokenArray = getTokens(temp, " , "); + permissionType = tokenArray[0]; + permissionNameAndAction = tokenArray[1]; + logger.fine("PermissionType =" + permissionType); + + // extract permission name and action + tokenArray = getTokens(permissionNameAndAction, " , "); + permissionName = tokenArray[0]; + permissionAction = tokenArray[1]; + logger.fine("permissionName = " + permissionName); + logger.fine("permissionAction = " + permissionAction); + + if (permissionAction.equals("null")) { + permissionAction = null; // Construct permissions based on their + // permission type + } + + if (!permissionType.equals(permType)) { + return null; + } + + if (permissionType.equals("WebResourcePermission")) { + p = new WebResourcePermission(permissionName, permissionAction); + } else if (permissionType.equals("WebRoleRefPermission")) { + p = new WebRoleRefPermission(permissionName, permissionAction); + } else if (permissionType.equals("WebUserDataPermission")) { + p = new WebUserDataPermission(permissionName, permissionAction); + } else if (permissionType.equals("EJBMethodPermission")) { + p = new EJBMethodPermission(permissionName, permissionAction); + } else if (permissionType.equals("EJBRoleRefPermission")) { + p = new EJBRoleRefPermission(permissionName, permissionAction); + } + } + + return p; + } + + public Permissions getSpecificPermissions(Permissions suppliedPermCollection, String permissionType) { + Permission p = null; + Permissions expectedPermissionCollection = new Permissions(); + + if (permissionType.equals("WebResourcePermission")) { + for (Enumeration en = suppliedPermCollection.elements(); en.hasMoreElements();) { + p = (Permission) en.nextElement(); + if (p instanceof WebResourcePermission) { + expectedPermissionCollection.add(p); + } + } + } else if (permissionType.equals("WebUserDataPermission")) { + for (Enumeration en = suppliedPermCollection.elements(); en.hasMoreElements();) { + p = (Permission) en.nextElement(); + + if (p instanceof WebUserDataPermission) { + expectedPermissionCollection.add(p); + } + } + } else if (permissionType.equals("WebRoleRefPermission")) { + for (Enumeration en = suppliedPermCollection.elements(); en.hasMoreElements();) { + p = (Permission) en.nextElement(); + if (p instanceof WebRoleRefPermission) { + expectedPermissionCollection.add(p); + } + } + } else if (permissionType.equals("EJBMethodPermission")) { + for (Enumeration en = suppliedPermCollection.elements(); en.hasMoreElements();) { + p = (Permission) en.nextElement(); + if (p instanceof EJBMethodPermission) { + expectedPermissionCollection.add(p); + } + } + } else if (permissionType.equals("EJBRoleRefPermission")) { + for (Enumeration en = suppliedPermCollection.elements(); en.hasMoreElements();) { + p = (Permission) en.nextElement(); + if (p instanceof EJBRoleRefPermission) { + expectedPermissionCollection.add(p); + } + } + } + return expectedPermissionCollection; + } + + /** + * Fetches all JSR196 SPI logs from JACCLog.txt + */ + public static Collection pullAllLogRecords(String queryParams, NodeList nodes) throws Exception { + Collection recordCollection = new Vector<>(); + Node recordNode; + + for (int i = 0; i < nodes.getLength(); i++) { + // Take the first record + recordNode = nodes.item(i); + + if (recordNode.getNodeName().equals("record")) { + LogRecordEntry recordEntry = new LogRecordEntry(recordNode); + recordCollection.add(recordEntry); + + } + } + + return recordCollection; + } + + public void setAppIdRecordCollection(Collection recordCollection) { + this.appIdRecordCollection = recordCollection; + } + + public Collection getAppIdRecordCollection() { + return this.appIdRecordCollection; + } + + public void setRecordCollection(Collection recordCollection) { + this.recordCollection = recordCollection; + } + + public Collection getRecordCollection() { + return this.recordCollection; + } + + public void setAppSpecificRecordCollection(Collection recordCollection) { + this.appSpecificRecordCollection = recordCollection; + } + + public Collection getAppSpecificRecordCollection() { + return this.appSpecificRecordCollection; + } + + /** + * Checks for the existence of search string in the log. For example to verify whether server log contains a string + * "Java EE rocks" use the following code + * + * LogFileProcessor logProcessor = new LogFileProcessor(properties); boolean contains = + * logProcessor.verifyLogContains("Java EE rocks"); + * + * where "properties" contains the key value pair for 1) log.file.location + */ + public boolean verifyLogContains(String... args) { + LogRecordEntry recordEntry = null; + logger.info("Searching log records for record :" + args[0]); + if (recordCollection == null) { + logger.info("Record collection empty : No log records found"); + return false; + } else { + logger.info("Record collection has: " + recordCollection.size() + " records."); + } + + int numberOfArgs = args.length; + int numberOfMatches = 0; + + boolean argsMatchIndex[] = new boolean[args.length]; + for (int i = 0; i < args.length; i++) { + // initialize all argsMatchIndex to "false" (i.e no match) + argsMatchIndex[i] = false; + + // From the given string array(args) if there is a record match + // for the search string, then the corresponding argsMatchIndex[i] + // will be set to true(to indicate a match) + // i.e argsMatchIndex[i] = true; + // + // For example if the string array contains + // String args[]={"JK", "EMERSON", "J.B.Shaw}; + // + // And if the string "JK" and "J.B.Shaw" are found in the records + // then the argsMatchIndex will be set as shown below + // argsMatchIndex[] ={true, false, true}; + // + } + + Iterator iterator = recordCollection.iterator(); + while (iterator.hasNext()) { + // loop thru all message tag/entries in the log file + recordEntry = (LogRecordEntry) iterator.next(); + String message = recordEntry.getMessage(); + // loop through all arguments to search for a match + for (int i = 0; i < numberOfArgs; i++) { + + // Search only unique record matches ignore repeat occurances + if (!argsMatchIndex[i]) { + // see if one of the search argument matches with + // the logfile message entry and if so return true + if ((message != null) && message.equals(args[i])) { + logger.info("Matching Record :"); + logger.info(recordEntry.getMessage()); + + // Increment match count + numberOfMatches++; + + // Mark the matches in argsMatchIndex + argsMatchIndex[i] = true; + + continue; + } + } + + } + + // Return true if, we found matches for all strings + // in the given string array + if (numberOfMatches == numberOfArgs) { + return true; + } + } + + // Print unmatched Strings(i.e no matches were found for these strings) + logger.info("No Matching log Record(s) found for the following String(s) :"); + for (int i = 0; i < numberOfArgs; i++) { + if (!argsMatchIndex[i]) { + logger.info(args[i]); + } + } + + return false; + } + + /** + * Checks for the existance of one of the search string(from a given String array. + * + * For example to verify whether server log contains one of the following String String[] arr ={"aaa", "bbb", "ccc"}; + * + * LogFileProcessor logProcessor = new LogFileProcessor(properties); boolean contains = + * logProcessor.verifyLogContainsOneOf(arr); + * + * This method will return true if the log file contains one of the specified String (say "aaa" ) + * + * where "properties" contains the key value pair for 1) log.file.location + */ + public boolean verifyLogContainsOneOf(String args[]) { + LogRecordEntry recordEntry = null; + boolean result = false; + + logger.info("Searching log records for the presence of one of the String" + " from a given string array"); + if (recordCollection == null) { + logger.info("Record collection empty : No log records found"); + return false; + } else { + logger.info("Record collection has: " + recordCollection.size() + " records."); + } + + int numberOfArgs = args.length; + + Iterator iterator = recordCollection.iterator(); + searchLabel: while (iterator.hasNext()) { + + // loop thru all message tag/entries in the log file + recordEntry = iterator.next(); + String message = recordEntry.getMessage(); + + // loop through all arguments to search for a match + for (int i = 0; i < numberOfArgs; i++) { + + // see if one of the search argument matches with + // the logfile message entry and if so return true + if ((message != null) && message.equals(args[i])) { + logger.info("Matching Record :"); + logger.info(recordEntry.getMessage()); + result = true; + + // If a match is found no need to search further + break searchLabel; + } + } + + } + + if (!result) { + // Print unmatched Strings(i.e no matches were found for these strings) + logger.info("No Matching log Record(s) found for the following String(s) :"); + for (int i = 0; i < numberOfArgs; i++) { + logger.info(args[i]); + } + } + + return result; + } + + /** + * This method looks for the presence of the given substring (from the array of strings "args") in the serverlog, which + * starts with the given "srchStrPrefix" search-string-prefix. + * + * + * For example to verify whether server log contains one of the following Strings in a server log with appContextId as + * the message prefix we can issue the following command + * + * String[] arr ={"aaa", "bbb", "ccc"}; String srchStrPrefix ="appContextId"; + * + * LogFileProcessor logProcessor = new LogFileProcessor(properties); boolean contains = + * logProcessor.verifyLogContainsOneOf(arr); + * + * "appContextId= xxxx aaa yyyyyyyyyyyyyyyyy" "appContextId= yyyy bbb xxxxxxxxxxxxxxxxx" + * + * This method will return true if the log file contains one of the specified String (say "aaa" ) in the message log + * with "appContextId" as its message prefix. + * + * where "properties" contains the key value pair for 1) log.file.location + */ + public boolean verifyLogContainsOneOfSubString(String args[], String srchStrPrefix) { + LogRecordEntry recordEntry = null; + boolean result = false; + + logger.info("Searching log records for the presence of one of the String" + " from a given string array"); + if (recordCollection == null) { + logger.info("Record collection empty : No log records found"); + return false; + } else { + logger.info("Record collection has: " + recordCollection.size() + " records."); + } + + int numberOfArgs = args.length; + + Iterator iterator = recordCollection.iterator(); + searchLabel: while (iterator.hasNext()) { + // loop thru all message tag/entries in the log file + recordEntry = iterator.next(); + String message = recordEntry.getMessage(); + // loop through all arguments to search for a match + for (int i = 0; i < numberOfArgs; i++) { + + // see if one of the search argument matches with + // the logfile message entry and if so return true + if ((message != null) && (message.startsWith(srchStrPrefix, 0)) && (message.indexOf(args[i]) > 0)) { + logger.info("Matching Record :"); + logger.info(recordEntry.getMessage()); + result = true; + + // If a match is found no need to search further + break searchLabel; + } + } + + } + + if (!result) { + // Print unmatched Strings(i.e no matches were found for these strings) + logger.info("No Matching log Record(s) found for the following String(s) :"); + for (int i = 0; i < numberOfArgs; i++) { + logger.info(args[i]); + } + } + + return result; + } + + /** + * verifyLogImplies() takes the individual expectedPermissions and and checks whether the generatedPermissions.implies() + * is true. + */ + public boolean verifyLogImplies(Permissions expectedPermissions, Permissions generatedPermissions) { + boolean verified = false; + Permission p; + + for (Enumeration en = expectedPermissions.elements(); en.hasMoreElements();) { + p = en.nextElement(); + + verified = generatedPermissions.implies(p); + if (!verified) { + logger.severe("The following permission doesn't match with server generated Permissions"); + logger.severe("permissionName = " + p.getName()); + logger.severe("permissionAction = " + p.getActions()); + + logger.severe("\n\n"); + logger.severe("Print Expected Permissions :"); + printPermissions(expectedPermissions); + logger.severe("\n\n"); + logger.severe("Print Generated Permissions :"); + printPermissions(generatedPermissions); + return false; + } + } + + // following code compares each generatedPermission with + // expectedPermissionCollection and lists the extra permissions + for (Enumeration en = generatedPermissions.elements(); en.hasMoreElements();) { + p = en.nextElement(); + verified = expectedPermissions.implies(p); + if (!verified) { + logger.info("The following server generated permission doesn't match with the expected Permissions"); + logger.info("permissionName = " + p.getName()); + logger.info("permissionAction = " + p.getActions()); + } + } + + return true; + } + + public void printCollection(Collection recordCollection) { + LogRecordEntry recordEntry = null; + Iterator iterator = recordCollection.iterator(); + + while (iterator.hasNext()) { + recordEntry = iterator.next(); + printRecordEntry(recordEntry); + } + } + + // Print heterogeneous collection of permissions + public void printPermissions(Permissions perms) { + int count = 0; + for (Enumeration en = perms.elements(); en.hasMoreElements();) { + count++; + Permission p = (Permission) en.nextElement(); + logger.info("-------------"); + logger.info(count + ") permissionType = " + p.getClass().getName()); + logger.info(count + ") permissionName = " + p.getName()); + logger.info(count + ") permissionAction = " + p.getActions()); + } + + } + + public void printPermissionCollection(PermissionCollection permCollection) { + String permissionType = null; + int count = 0; + + for (Enumeration en = permCollection.elements(); en.hasMoreElements();) { + count++; + + Permission p = (Permission) en.nextElement(); + if (p instanceof WebResourcePermission) { + permissionType = "WebResourcePermission"; + } else if (p instanceof WebUserDataPermission) { + permissionType = "WebUserDataPermission"; + } else if (p instanceof WebRoleRefPermission) { + permissionType = "WebRoleRefPermission"; + } else if (p instanceof EJBMethodPermission) { + permissionType = "EJBMethodPermission"; + } else if (p instanceof EJBRoleRefPermission) { + permissionType = "EJBRoleRefPermission"; + } + logger.info("-------------"); + logger.info(count + ") permissionType = " + permissionType); + logger.info(count + ") permissionName = " + p.getName()); + logger.info(count + ") permissionAction = " + p.getActions()); + } + } + + public void printRecordEntry(LogRecordEntry rec) { + logger.info("*******Log Content*******"); + + logger.info("Milli Seconds =" + rec.getMilliSeconds()); + logger.info("Seqence no =" + rec.getSequenceNumber()); + logger.info("Message =" + rec.getMessage()); + if (rec.getClassName() != null) { + logger.info("Class name =" + rec.getClassName()); + } + if (rec.getMethodName() != null) { + logger.info("Method name =" + rec.getMethodName()); + } + if (rec.getLevel() != null) { + logger.info("Level =" + rec.getLevel()); + } + if (rec.getThrown() != null) { + logger.info("Thrown =" + rec.getThrown()); + } + logger.info(""); + } + + public String extractQueryToken(String str, String ContextId) { + StringTokenizer strtok; + String DELIMETER = "|"; + String qstring = null; + String qparams = null; + + strtok = new StringTokenizer(ContextId, DELIMETER); + if (ContextId.indexOf(DELIMETER) > 0) { + qstring = strtok.nextToken(); + if (strtok.hasMoreTokens()) { + qparams = strtok.nextToken(); + } + } + + // return query string or query params based on the content + // of the string str + if (str.equals("LogQueryString")) { + return qstring; + } else { + return qparams; + } + } + + // This method tokenize the given string and + // return first token and the remaining + // string a string array based on the given delimeter + public static String[] getTokens(String str, String delimeter) { + String[] array = new String[2]; + StringTokenizer strtoken; + + // Get first token and the remaining string + strtoken = new StringTokenizer(str, delimeter); + if (str.indexOf(delimeter) > 0) { + array[0] = strtoken.nextToken(); + array[1] = str.substring(array[0].length() + 3, str.length()); + } else { + // With JSR115 Maintenance review change the permission name + // for WebRoleRefPermission can be an empty string. + // this results in permissionName="" + // i.e the input string will have a value such as + // str=" , " + array[0] = ""; + array[1] = strtoken.nextToken(); + } + + // logger.info("Input String ="+str); + // logger.info("array[0] ="+array[0]); + // logger.info("array[1] ="+array[1]); + return array; + } + + // + // Locates the logs based on the given prefix string + // + // For example to locate all commit records i.e records such as + // + // commit :: MyApp1058312446320 , recordTimeStamp=1058312446598 + // + // Use the following method to pull all the commit records + // + // fingLogsByPrefix("commit", nodes); + public Collection findLogsByPrefix(String queryParams, NodeList nodes) throws Exception { + Collection recordCollection = new Vector(); + String nodeName; + String nodeValue; + Node childNode; + Node recordNode; + NodeList recordNodeChildren; + + for (int i = 0; i < nodes.getLength(); i++) { + // Take the first record + recordNode = nodes.item(i); + + // get all the child nodes for the first record + recordNodeChildren = recordNode.getChildNodes(); + + for (int j = 0; j < recordNodeChildren.getLength(); j++) { + childNode = recordNodeChildren.item(j); + nodeName = childNode.getNodeName(); + if (nodeName.equals("message")) { + nodeValue = getText(childNode); + if (nodeValue.startsWith(queryParams)) { + // create a new record entry and + // add it to the collection + LogRecordEntry recordEntry = new LogRecordEntry(recordNode); + + recordCollection.add(recordEntry); + } + } + } + } + return recordCollection; + } + + public String getText(Node textNode) { + String result = ""; + NodeList nodes = textNode.getChildNodes(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + + if (node.getNodeType() == Node.TEXT_NODE) { + result = node.getNodeValue(); + break; + } + } + return result; + } + + /** + * This method retrieves the appId records. + * + * i.e if (log records starts with "appId") then add the records to appIdRecordCollection else add the records to + * recordCollection + * + * Note: In the process of locating appId records the remaining records are also isolated and stored in a collection + * called "recordCollection" + */ + public Collection getAppIdRecordCollection(String queryParams, NodeList nodes) throws Exception { + String nodeName; + String nodeValue; + Node childNode; + Node recordNode; + NodeList recordNodeChildren; + + for (int i = 0; i < nodes.getLength(); i++) { + // Take the first record + recordNode = nodes.item(i); + // get all the child nodes for the first record + recordNodeChildren = recordNode.getChildNodes(); + for (int j = 0; j < recordNodeChildren.getLength(); j++) { + childNode = recordNodeChildren.item(j); + nodeName = childNode.getNodeName(); + if (nodeName.equals("message")) { + nodeValue = getText(childNode); + if (nodeValue.startsWith(queryParams)) { + // create a new record entry that matches the + // query criteria i.e "appId" + LogRecordEntry matchingRecordEntry = new LogRecordEntry(recordNode); + this.appIdRecordCollection.add(matchingRecordEntry); + } else if (nodeValue.startsWith("link")) { + // create a new record entry for link records + LogRecordEntry linkRecordEntry = new LogRecordEntry(recordNode); + this.linkRecordCollection.add(linkRecordEntry); + } else { + // create a new record entry that do not + // match the query criteria + LogRecordEntry nonMatchingRecordEntry = new LogRecordEntry(recordNode); + this.recordCollection.add(nonMatchingRecordEntry); + } + } + } + } + return appIdRecordCollection; + } + + public String getCurrentApplicationName() { + return getCurrentAppName(null); + } + + public String getCurrentApplicationName(String appName) { + return getCurrentAppName(appName); + } + + // This method returns the current application name by analysing + // all the appId log records. + // + // The appId log record contains the Application name and the timeStamp + // For example, let us examine the following 3 appId log records. + // + // appId :: MyApp , 1058312446598 + // appId :: App , 1058312463706 + // appId :: adminapp , 1058312480593 + // + // In the above 3 appId records + // a) the first field "appId :: " identifies this as a appId record + // b) the second field indicates the application name + // c) the third field refers to the timestamp at which the record was + // created. + // + // By comparing the timestamps we can locate the latest of all appId records + // and return the application name associated with it. + private String getCurrentAppName(String matchAppName) { + String timeStampString = null; + String appName = null; + String prevAppName = null; + long prevRecordTimeStamp = 0; + long recordTimeStamp = 0; + + if ((appIdRecordCollection == null) || (appIdRecordCollection.isEmpty())) { + logger.info("Record collection empty : No appId records found"); + return null; + } + + for (LogRecordEntry recordEntry : appIdRecordCollection) { + String message = recordEntry.getMessage(); + + // Remove the string "appId :: " from the message + String temp = message.substring(9, message.length()); + + // Get appName and timeStampString + String[] tokenArray = temp.split(" , "); + appName = tokenArray[0]; + timeStampString = tokenArray[1]; + + // Now unstuff application name + appName = unStuffData(appName); + + logger.info("appName =" + appName); + logger.info("timeStampString =" + timeStampString); + + // Get long value from the string + if (matchAppName == null) { + // warning: what this does is look for the newest record + // and use that as the appname. If multiple apps + // are deployed at same time - this could return + // a record that belongs to a different app. + recordTimeStamp = Long.parseLong(timeStampString); + if (recordTimeStamp < prevRecordTimeStamp) { + recordTimeStamp = prevRecordTimeStamp; + appName = prevAppName; + } + } else { + // we want an appname that matches/contains the passed in appName + if (appName.contains(matchAppName)) { + break; + } + } + } + + return appName; + } + + // This method returns the linked application names by analysing + // all the link log records. + // + // The link log record contains the list of Application names + // and the timeStamp. + // For example, let us examine the following 2 link log records. + // + // link :: MyApp,SecondApp : 1058312446598 + // link :: App,SecondApp,ThirdApp : 1058312463706 + // + // In the above 3 link records + // a) the first field "link :: " identifies this as a link record + // b) the second field indicates the application names that are + // linked to. + // Note: Linked application names are idenified using + // the comma separator. + // c) the last field indicates the timestamp at which the record was + // created. + // + // By comparing the timestamps we can locate the latest link records + // and return the application names linked to it. + public Vector getLinkedApplicationNames() { + LogRecordEntry recordEntry = null; + String temp = null; + String timeStampString = null; + String appNames = null; + String prevAppName = null; + long prevRecordTimeStamp = 0; + long recordTimeStamp = 0; + String[] tokenArray = new String[2]; + Vector applicationNames = new Vector<>(); + + if (linkRecordCollection == null) { + logger.info("Record collection empty : No link records found"); + return null; + } + + Iterator iterator = linkRecordCollection.iterator(); + while (iterator.hasNext()) { + recordEntry = (LogRecordEntry) iterator.next(); + String message = recordEntry.getMessage(); + + // Remove the string "link :: " from the message + temp = message.substring(8, message.length()); + + // Get appName and timeStampString + tokenArray = temp.split(" : "); + appNames = tokenArray[0]; + timeStampString = tokenArray[1]; + + // now unstuff application name + appNames = unStuffData(appNames); + + // Get long value from the string + recordTimeStamp = Long.parseLong(timeStampString); + if (recordTimeStamp < prevRecordTimeStamp) { + recordTimeStamp = prevRecordTimeStamp; + appNames = prevAppName; + } + } + + StringTokenizer strtoken; + + if (appNames != null) { + // create a vector with applicationNames + strtoken = new StringTokenizer(appNames, ","); + if (appNames.indexOf(",") > 0) { + // if the appNames string contains multiple applications + // add all of them to the vector applicationNames + while (strtoken.hasMoreTokens()) { + applicationNames.add(strtoken.nextToken()); + } + } else if (appNames != null) { + // if the appNames string contains only one application + // add it to the vector applicationNames + applicationNames.add(appNames); + } + } else { + return null; + } + + return applicationNames; + } + + /* + * This returns the collection of records that have a message field that contains the keyword "MSG_TAG". This is a + * generic flag used to put a phrase or info into a records message field so that we can easily search on those MSG_TAG + * fields later on. + */ + public Collection getMsgTagRecordCollection() { + LogRecordEntry recordEntry = null; + Collection msgTagRecordCollection = new Vector(); + + logger.fine("getMsgTagRecordCollection(): Record collection size : " + recordCollection.size()); + if (recordCollection == null) { + logger.fine("Record collection empty : No records found"); + return null; + } + + Iterator iterator = this.recordCollection.iterator(); + while (iterator.hasNext()) { + recordEntry = (LogRecordEntry) iterator.next(); + String message = recordEntry.getMessage(); + + if (message.indexOf("MSG_TAG") > -1) { + logger.fine("getMsgTagRecordCollection(): message = " + message); + msgTagRecordCollection.add(recordEntry); + } + } + logger.fine("getMsgTagRecordCollection(): returning collection size of: " + msgTagRecordCollection.size()); + return msgTagRecordCollection; + } + + /* + * This method reads all non-appId records from the record collection and isolates current appSpecific records from the + * rest using the given applicationName and the linkedApplicationNames. + */ + public Collection getAppSpecificRecordCollection(String applicationName, Vector linkedApplicationNames) { + LogRecordEntry recordEntry = null; + + if (recordCollection == null) { + logger.info("Record collection empty : No records found"); + return null; + } + Iterator iterator = this.recordCollection.iterator(); + while (iterator.hasNext()) { + recordEntry = (LogRecordEntry) iterator.next(); + String message = recordEntry.getMessage(); + + // if recordEntry contains the specified applicationName + // Add the record to appSpecificRecordCollection + if (message.indexOf(applicationName) > 0) { + appSpecificRecordCollection.add(recordEntry); + } + } + + if (linkedApplicationNames != null) { + // retrieve all the records associated with + // linked applications. + for (Enumeration appEnum = linkedApplicationNames.elements(); appEnum.hasMoreElements();) { + applicationName = (String) appEnum.nextElement(); + + iterator = this.recordCollection.iterator(); + while (iterator.hasNext()) { + recordEntry = (LogRecordEntry) iterator.next(); + String message = recordEntry.getMessage(); + + // if recordEntry contains the specified applicationName + // Add the record to appSpecificRecordCollection + if (message.indexOf(applicationName) > 0) { + appSpecificRecordCollection.add(recordEntry); + } + } + + } + } + return appSpecificRecordCollection; + } + + // This will remove the stuffed characters in the input string + // Note: The non-alphabets in the input string was already stuffed by + // the same character, this method unstuff those characters + public static String unStuffData(String inputStr) { + char[] outStr = new char[2048]; + char[] str = inputStr.toCharArray(); + + logger.info("unStuffData called with: " + inputStr); + + for (int i = 0, j = 0; i < str.length;) { + + int a = Character.getNumericValue(str[i]); + + // Don't stuff extra character if the character is an alphabet + // + // Numeric values for alphabets falls in 10 to 35, this includes + // both upper and lower cases + if ((a > 9) && (a < 36)) { + outStr[j++] = str[i++]; + } else { // unstuff the character + outStr[j] = str[i]; // just skip the next character + // Remove only the stuffed characters not data separators + if (((i + 1) < str.length) && (str[i + 1] == str[i])) { + // just skip the next character + i++; + } + i++; + j++; + } + } + + logger.info("unStuffData returning: " + (new String(outStr)).trim()); + return ((new String(outStr)).trim()); + } +} diff --git a/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/client/LogRecordEntry.java b/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/client/LogRecordEntry.java new file mode 100644 index 0000000..09d5018 --- /dev/null +++ b/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/client/LogRecordEntry.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2007, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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 ee.jakarta.tck.authorization.util.logging.client; + +import java.io.Serializable; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class LogRecordEntry implements Serializable { + + private static final long serialVersionUID = 1L; + + private long milliSeconds; + private long sequenceNumber; + + private String level; + private String className; + private String methodName; + private String message; + private String thrown; + + public LogRecordEntry(Node recordNode) throws Exception { + if (!recordNode.getNodeName().equals("record")) { + throw new Exception("Unexpected tag :" + recordNode.getNodeName()); + } + + NodeList nodes = recordNode.getChildNodes(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + String childNode = node.getNodeName(); + + if (childNode.equals("millis")) { + milliSeconds = Long.parseLong(getText(node)); + + } else if (childNode.equals("sequence")) { + sequenceNumber = Long.parseLong(getText(node)); + + } else if (childNode.equals("level")) { + level = getText(node); + + } else if (childNode.equals("class")) { + className = getText(node); + + } else if (childNode.equals("method")) { + methodName = getText(node); + + } else if (childNode.equals("message")) { + message = getText(node); + + } else if (childNode.equals("exception")) { + thrown = getText(node); + } + } + } + + public long getMilliSeconds() { + return this.milliSeconds; + } + + public void setMilliSeconds(long milliSec) { + milliSeconds = milliSec; + } + + public long getSequenceNumber() { + return this.sequenceNumber; + } + + public void setSequenceNumber(long seqNum) { + sequenceNumber = seqNum; + } + + public String getMessage() { + return this.message; + } + + public void setMessage(String msg) { + message = msg; + } + + public String getLevel() { + return this.level; + } + + public void setLevel(String lvl) { + level = lvl; + } + + public String getClassName() { + return this.className; + } + + public void setClassName(String cName) { + className = cName; + } + + public String getMethodName() { + return this.methodName; + } + + public void setMethodName(String mName) { + methodName = mName; + } + + public String getThrown() { + return this.thrown; + } + + public void setThrown(String thrwn) { + thrown = thrwn; + } + + public String getText(Node textNode) { + String result = ""; + NodeList nodes = textNode.getChildNodes(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + + if (node.getNodeType() == Node.TEXT_NODE) { + result = node.getNodeValue(); + break; + } + } + + return result; + } + +} diff --git a/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/server/TSLogRecord.java b/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/server/TSLogRecord.java new file mode 100644 index 0000000..ca0c465 --- /dev/null +++ b/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/server/TSLogRecord.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2007, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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 + */ + +/** + * $Id$ + * + * @author Raja Perumal + * 07/12/02 + */ + +package ee.jakarta.tck.authorization.util.logging.server; + +import java.util.logging.Level; +import java.util.logging.LogRecord; + +/** + * TSLogRecord is the custom LogRecord which has one additional logging field ContextId, in addition to the regular + * Logging fields. The Log fields of TSLogRecord are 1) sequence number 2) context Id (The logging context) 3) message + * 4) class name (The class which logs the log message) 5) method name ( The method which logs the log message) + **/ +public class TSLogRecord extends LogRecord { + + private static final long serialVersionUID = 1L; + + /** + * @serial The logging context Id + */ + private String contextId; + + /** + * Construct a LogRecord with the given level, message and context values. + * + * @param level a logging level value + * @param contextId the logging contextId + * @param msg the raw non-localized logging message + * + */ + TSLogRecord(Level level, String message, String contextId) { + // set the rest of the fields using parent constructor + super(level, message); + this.contextId = contextId; + + } + + /** + * Construct a LogRecord with the given level and message + * + * @param level a logging level value + * @param msg the raw non-localized logging message + * + */ + TSLogRecord(Level level, String message) { + super(level, message); + // Add jacc_ctx for default contextId + this.contextId = "jacc_ctx"; + } + + /** + * Get the contextId + * + * @ return contextId + */ + public String getContextId() { + return contextId; + } + + /** + * Set the contextId + * + * @param contextId the logging context Id + */ + public void setContextId(String cId) { + contextId = cId; + } + +} diff --git a/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/server/TSLogger.java b/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/server/TSLogger.java new file mode 100644 index 0000000..1cc248b --- /dev/null +++ b/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/server/TSLogger.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * Copyright (c) 2007, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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 + */ + +/** + * $Id$ + * + * @author Raja Perumal + * 07/13/02 + */ + +package ee.jakarta.tck.authorization.util.logging.server; + +import static java.util.logging.Level.SEVERE; + +import java.io.File; +import java.util.logging.FileHandler; +import java.util.logging.Filter; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.Logger; + +/** + * TSLogger is the custom Logger which extends java.util.Logger + * + **/ +public class TSLogger extends Logger { + + private int levelValue = Level.INFO.intValue(); + private int offValue = Level.OFF.intValue(); + private Filter filter; + + // Note : The logger instance should not be + // stored in this instance variable, + // it should be kept at the log Manager using + // + // LogManager.addLogger(TSlogger); + // + // and it can be retrieved using + // + // LogManager.getLogger(name); + // + // Since Logger and TSLogger are of different types + // we cannot use the above logic and hence we have + // no choice except to store it here. + // + private static TSLogger tsLogger = null; + public static TSLogger logger; + + private static FileHandler fileHandler; + + protected TSLogger(String name) { + super(name, null); + levelValue = Level.INFO.intValue(); + } + + public static TSLogger getTSLogger() { + initializeTSLogger(); + return logger; + } + + public static void initializeTSLogger() { + if (logger != null) { + return; + } + + try { + String logFileLocation = System.getProperty("log.file.location"); + if (logFileLocation != null) { + logger = TSLogger.getTSLogger("jacc"); + boolean appendMode = true; + + // Clean the content of authorization-trace-log.xml if it exists + File file = new File(logFileLocation + "/authorization-trace-log.xml"); + if (file.exists()) { + // Delete the file, if it exists + file.delete(); + } + + File fileLock = new File(logFileLocation + "/authorization-trace-log.xml.lck"); + if (fileLock.exists()) { + // Delete the file, if it exists + fileLock.delete(); + } + + // Create a new file + System.out.println("XXXX: in initializeTSLogger() - about to create authorization-trace-log.xml"); + fileHandler = new FileHandler(logFileLocation + "/authorization-trace-log.xml", appendMode); + fileHandler.setFormatter(new TSXMLFormatter()); + logger.addHandler(fileHandler); + setTSLogger(logger); + } else { + // use default logging mechanism + logger = TSLogger.getTSLogger("jacc"); + setTSLogger(logger); + logger.log(SEVERE, "log.file.location not set: Using default logger"); + } + } catch (Exception e) { + throw new RuntimeException("TSLogger Initialization failed", e); + } + } + + public static void setTSLogger(TSLogger lgr) { + logger = lgr; + } + + public static void close() { + fileHandler.close(); + } + + + /** + * Find or create a logger for a named subsystem. If a logger has already been created with the given name it is + * returned. Otherwise a new logger is created. + *

+ * If a new logger is created its log level will be configured based on the LogManager configuration and it will + * configured to also send logging output to its parent's handlers. It will be registered in the LogManager global + * namespace. + * + * @param name A name for the logger. This should be a dot-separated name and should normally be based on the package + * name or class name of the subsystem, such as java.net or javax.swing + * @return a suitable Logger + */ + public static synchronized TSLogger getTSLogger(String name) { + TSLogger result = null; + + LogManager manager = LogManager.getLogManager(); + + if (tsLogger != null) { + if (tsLogger.getName().equals(name)) { + result = tsLogger; + } + } else { + result = new TSLogger(name); + manager.addLogger(result); + } + + return result; + } + + /** + * Log a message, with no arguments. + *

+ * If the logger is currently enabled for the given message level then the given message is forwarded to all the + * registered output Handler objects. + *

+ * + * @param level One of the message level identifiers, e.g. SEVERE + * @param msg The string message (or a key in the message catalog) + */ + @Override + public void log(Level level, String msg) { + // assign default context (jacc_ctx) to all messages ??? + log(level, msg, "jacc_ctx"); + } + + /** + * Log a message, with no arguments. + *

+ * If the logger is currently enabled for the given message level then the given message is forwarded to all the + * registered output Handler objects. + *

+ * + * @param level One of the message level identifiers, e.g. SEVERE + * @param msg The string message (or a key in the message catalog) + * @param contextId the logging context Id + */ + public void log(Level level, String msg, String contextId) { + if (level.intValue() < levelValue || levelValue == offValue) { + return; + } + + TSLogRecord lr = new TSLogRecord(level, msg, contextId); + String rbn = null; + + Logger target = this; + while (target != null) { + rbn = target.getResourceBundleName(); + if (rbn != null) { + break; + } + target = target.getParent(); + } + + if (rbn != null) { + lr.setResourceBundleName(rbn); + } + + log(lr); + } + + /** + * Log a TSLogRecord. + * + * @param record the TSLogRecord to be published + */ + public void log(TSLogRecord record) { + if (record.getLevel().intValue() < levelValue || levelValue == offValue) { + return; + } + + synchronized (this) { + if (filter != null && !filter.isLoggable(record)) { + return; + } + } + + // Post the LogRecord to all our Handlers, and then to + // our parents' handlers, all the way up the tree. + + TSLogger logger = this; + while (logger != null) { + Handler targets[] = logger.getHandlers(); + + if (targets != null) { + for (int i = 0; i < targets.length; i++) { + // targets[i].publish(record); + + // Publish record only if the + // handler is of type FileHandler + // Do not publish to all parent handler + // Parent handler may not be able to + // Format the TSLogRecord, because + // TSLogRecord is the custom record. + if (targets[i] instanceof FileHandler) { + targets[i].publish(record); + } + } + } + + if (!logger.getUseParentHandlers()) { + break; + } + + logger = null; + } + } + +} diff --git a/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/server/TSXMLFormatter.java b/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/server/TSXMLFormatter.java new file mode 100644 index 0000000..67056b2 --- /dev/null +++ b/tck/common/src/main/java/ee/jakarta/tck/authorization/util/logging/server/TSXMLFormatter.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2007, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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 + */ + +/** + * $Id$ + * + * @author Raja Perumal + * 07/13/02 + */ + +package ee.jakarta.tck.authorization.util.logging.server; + +import java.util.ResourceBundle; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.XMLFormatter; + +/** + * TSXMLFormatter formats TSLogRecord in XML format. + * + */ +public class TSXMLFormatter extends XMLFormatter { + + private String contextId; + + /** + * Override parent class format method + * + * @param lrecord the LogRecord to be formatted. + * @return a formatted log record + */ + @Override + public String format(LogRecord lrecord) { + + String message = lrecord.getMessage(); + Level level = lrecord.getLevel(); + TSLogRecord record = new TSLogRecord(level, message); + + return format(record); + } + + /** + * Format the given message to XML. + * + * @param record the log record to be formatted. + * @return a formatted log record + */ + public String format(TSLogRecord record) { + + // TSLogRecord record = (TSLogRecord)lrecord; + StringBuffer sb = new StringBuffer(500); + sb.append("\n"); + + sb.append(" "); + sb.append(record.getSequenceNumber()); + sb.append("\n"); + + sb.append(" "); + sb.append(record.getContextId()); + sb.append("\n"); + + sb.append(" "); + escape(sb, record.getLevel().toString()); + sb.append("\n"); + + if (record.getSourceClassName() != null) { + sb.append(" "); + escape(sb, record.getSourceClassName()); + sb.append("\n"); + } + + if (record.getSourceMethodName() != null) { + sb.append(" "); + escape(sb, record.getSourceMethodName()); + sb.append("\n"); + + } + + sb.append(" "); + sb.append(record.getThreadID()); + sb.append("\n"); + + if (record.getMessage() != null) { + // Format the message string and its accompanying parameters. + String message = formatMessage(record); + sb.append(" "); + escape(sb, message); + sb.append(""); + sb.append("\n"); + } + + // If the message is being localized, output the key, resource + // bundle name, and params. + ResourceBundle bundle = record.getResourceBundle(); + try { + if (bundle != null && bundle.getString(record.getMessage()) != null) { + sb.append(" "); + escape(sb, record.getMessage()); + sb.append("\n"); + + sb.append(" "); + escape(sb, record.getResourceBundleName()); + sb.append("\n"); + + Object parameters[] = record.getParameters(); + for (int i = 0; i < parameters.length; i++) { + sb.append(" "); + try { + escape(sb, parameters[i].toString()); + } catch (Exception ex) { + sb.append("???"); + } + sb.append("\n"); + } + } + } catch (Exception ex) { + // The message is not in the catalog. Drop through. + } + + if (record.getThrown() != null) { + // Report on the state of the throwable. + Throwable th = record.getThrown(); + sb.append(" \n"); + sb.append(" "); + escape(sb, th.toString()); + sb.append("\n"); + + StackTraceElement trace[] = th.getStackTrace(); + for (int i = 0; i < trace.length; i++) { + StackTraceElement frame = trace[i]; + sb.append(" \n"); + sb.append(" "); + escape(sb, frame.getClassName()); + sb.append("\n"); + + sb.append(" "); + escape(sb, frame.getMethodName()); + sb.append("\n"); + + // Check for a line number. + if (frame.getLineNumber() >= 0) { + sb.append(" "); + sb.append(frame.getLineNumber()); + sb.append("\n"); + } + sb.append(" \n"); + } + sb.append(" \n"); + } + + sb.append("\n"); + return sb.toString(); + } + + // Append to the given StringBuffer an escaped version of the + // given text string where XML special characters have been escaped. + // For a null string we appebd "" + private void escape(StringBuffer sb, String text) { + if (text == null) { + text = ""; + } + + for (int i = 0; i < text.length(); i++) { + char ch = text.charAt(i); + if (ch == '<') { + sb.append("<"); + } else if (ch == '>') { + sb.append(">"); + } else if (ch == '&') { + sb.append("&"); + } else { + sb.append(ch); + } + } + } + + /** + * Return the header string for a set of XML formatted records. + * + * @param h The target handler. + * @return header string + */ + @Override + public String getHead(Handler h) { + StringBuffer sb = new StringBuffer(); + sb.append("\n"); + // sb.append("\n"); + sb.append("\n"); + return sb.toString(); + } + +} diff --git a/tck/pom.xml b/tck/pom.xml index 3052078..26ebaa6 100644 --- a/tck/pom.xml +++ b/tck/pom.xml @@ -58,6 +58,9 @@ app-custom-policy app-custom-policy2 + app-custom-trace-policyconfiguration + app-custom-trace-policyconfigurationfactory + app-policy-within-servlet @@ -344,6 +347,14 @@ ${glassfish.root}/glassfish8 + + ${glassfish.root}/glassfish8/glassfish/domains/domain1/logs + + + log.file.location=${glassfish.root}/glassfish8/glassfish/domains/domain1/logs + vendor.jakarta.security.jacc.PolicyConfigurationFactory.provider=org.glassfish.exousia.modules.def.DefaultPolicyConfigurationFactory + + create-file-user --groups foo:bar --passwordfile ${maven.multiModuleProjectDirectory}/reza.pass reza create-file-user --groups Administrator:Manager:Employee --passwordfile ${maven.multiModuleProjectDirectory}/javajoe.pass javajoe