Skip to content

Commit

Permalink
Fix #23933 by adding a proxy for the Policy when Security Managed used
Browse files Browse the repository at this point in the history
Signed-off-by: Arjan Tijms <arjan.tijms@gmail.com>
  • Loading branch information
arjantijms committed May 11, 2022
1 parent bca432a commit 26eba02
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 11 deletions.
66 changes: 63 additions & 3 deletions appserver/tests/tck/authorization/pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2021 Contributors to the Eclipse Foundation. All rights reserved.
Copyright (c) 2021, 2022 Contributors to the Eclipse Foundation. 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
Expand All @@ -15,6 +15,43 @@
SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-->

<!--
Usage:
Run full TCK:
mvn clean clean
Run full TCK, debugging remote GlassFish (suspends on port 9009)
mvn clean install -Dglassfish.suspend
Run full TCK, debugging client TCK
mvn clean install -Dsuspend-tck
Run full TCK with security manager (deprecated in principal, but still needed for EE 10 to pass)
mvn clean install -Dglassfish.security.manager
Run all tests in test class
mvn clean install -Drun.test="com/sun/ts/tests/el/api/jakarta_el/methodexpression/ELClient.java"
Run single test:
mvn clean install -Drun.test="com/sun/ts/tests/jacc/web/toolsContracts/Client.java#validateNoInvalidStates_from_standalone"
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
Expand Down Expand Up @@ -185,6 +222,10 @@
<replaceregexp file="${tck.home}/bin/ts.jte" byline="true"
match="work\.dir=.*"
replace="work\.dir=${tck.home}/jacctckwork/jacctck" />

<replaceregexp file="${tck.home}/bin/ts.jte" byline="true"
match="work\.dir=.*"
replace="work\.dir=${tck.home}/jacctckwork/jacctck" />

<!-- Run just selected subset tests -->
<replaceregexp file="${tck.home}/bin/build.xml" byline="true"
Expand All @@ -206,6 +247,12 @@
<exec executable="${glassfish.asadmin}" dir="${glassfish.home}/glassfish/bin">
<arg value="start-domain"/>
</exec>

<exec executable="${glassfish.asadmin}" dir="${glassfish.home}/glassfish/bin" if:set="glassfish.security.manager">
<arg value="create-jvm-options" />
<arg value="--port=${port.admin}" />
<arg value="&quot;-Djava.security.manager&quot;" />
</exec>

<if>
<isset property="jacoco.version" />
Expand Down Expand Up @@ -250,7 +297,7 @@
<goal>run</goal>
</goals>
<configuration>
<target>
<target xmlns:if="ant:if" xmlns:unless="ant:unless">
<taskdef resource="net/sf/antcontrib/antcontrib.properties"
classpathref="maven.plugin.classpath" />
<limit maxwait="20">
Expand All @@ -266,6 +313,18 @@
<arg value="enable.jacc" />
<env key="tck.home" value="${tck.home}"/>
</exec>

<!-- Restart GlassFish in debug mode if so requested -->
<sequential if:set="glassfish.suspend">
<exec executable="${glassfish.asadmin}" dir="${glassfish.home}/glassfish/bin">
<arg value="stop-domain" />
</exec>
<echo message="Starting GlassFish in suspended mode, waiting on port 9009" />
<exec executable="${glassfish.asadmin}" dir="${glassfish.home}/glassfish/bin">
<arg value="start-domain"/>
<arg value="--suspend" if:set="glassfish.suspend"/>
</exec>
</sequential>
</target>
</configuration>
</execution>
Expand All @@ -285,7 +344,8 @@
<exec executable="${ant.home}/bin/ant" dir="${tck.tests.home}" resultproperty="testResult">
<arg value="-Dmultiple.tests=${run.test}" if:set="run.test" />
<arg value="deploy"/>
<arg value="run.all"/>
<arg value="run.all" unless:set="run.test"/>
<arg value="runclient" if:set="run.test" />
<env key="LC_ALL" value="C" />
</exec>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*
* Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation.
* Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -27,9 +28,13 @@
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Level.WARNING;
import static javassist.Modifier.PUBLIC;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Permission;
import java.security.Policy;
import java.security.ProtectionDomain;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;

Expand All @@ -48,6 +53,11 @@
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.inject.Singleton;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;

/**
* Loads the Default Policy File into the system.
Expand All @@ -73,6 +83,7 @@ public class PolicyLoader {
private static final String POLICY_PROVIDER = "jakarta.security.jacc.policy.provider";
private static final String POLICY_CONF_FACTORY = "jakarta.security.jacc.PolicyConfigurationFactory.provider";
private static final String POLICY_PROP_PREFIX = "com.sun.enterprise.jaccprovider.property.";
private static final String POLICY_PROXY = "com.sun.enterprise.jaccprovider.proxy";
private boolean isPolicyInstalled;

/**
Expand Down Expand Up @@ -104,8 +115,6 @@ public void loadPolicy() {
javaPolicyClassName = authorizationModule.getPolicyProvider();
}

// TEMP TEMP TEMP

if (System.getProperty("simple.jacc.provider.JACCRoleMapper.class") == null) {
System.setProperty("simple.jacc.provider.JACCRoleMapper.class",
"com.sun.enterprise.security.web.integration.GlassfishRoleMapper");
Expand All @@ -116,8 +125,16 @@ public void loadPolicy() {

try {
LOGGER.log(INFO, policyLoading, javaPolicyClassName);

boolean usePolicyProxy = Boolean.parseBoolean(System.getProperty(POLICY_PROXY, "true"));

Policy policy = null;
if (usePolicyProxy && System.getSecurityManager() != null) {
policy = loadPolicyAsProxy(javaPolicyClassName);
} else {
policy = loadPolicy(javaPolicyClassName);
}

Policy policy = loadPolicy(javaPolicyClassName);
Policy.setPolicy(policy);

// TODO: causing ClassCircularity error when SM ON and
Expand All @@ -143,14 +160,91 @@ public void loadPolicy() {
}
}

private Policy loadPolicy(String javaPolicyClassName) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
Object javaPolicyInstance = Thread.currentThread().getContextClassLoader().loadClass(javaPolicyClassName).getDeclaredConstructor()
.newInstance();
@SuppressWarnings("unchecked")
public static <T> T createPolicyProxy(Class<T> targetClass) throws Exception {
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(targetClass);

ProxyObject instance = (ProxyObject) factory.createClass().getDeclaredConstructor().newInstance();
instance.setHandler(new JakartaAuthenticationGuardHandler(Policy.getPolicy()));

return (T) instance;
}

private static class JakartaAuthenticationGuardHandler implements MethodHandler {

public final static Method impliesMethod = getMethod(
Policy.class, "implies", ProtectionDomain.class, Permission.class);

private final Policy javaSePolicy;

public JakartaAuthenticationGuardHandler(Policy javaSePolicy) {
this.javaSePolicy = javaSePolicy;
}

@Override
public Object invoke(Object self, Method overridden, Method forwarder, Object[] args) throws Throwable {
if (isImplementationOf(overridden, impliesMethod)) {
Permission permission = (Permission) args[1];
if (!permission.getClass().getName().startsWith("jakarta.")) {
return javaSePolicy.implies((ProtectionDomain)args[0], permission);
}
}

return forwarder.invoke(self, args);
}

public static boolean isImplementationOf(Method implementationMethod, Method interfaceMethod) {
return
interfaceMethod.getDeclaringClass().isAssignableFrom(implementationMethod.getDeclaringClass()) &&
interfaceMethod.getName().equals(implementationMethod.getName()) &&
Arrays.equals(interfaceMethod.getParameterTypes(), implementationMethod.getParameterTypes());
}

public static Method getMethod(Class<?> base, String name, Class<?>... parameterTypes) {
try {
// Method literals in Java would be nice
return base.getMethod(name, parameterTypes);
} catch (NoSuchMethodException | SecurityException e) {
throw new IllegalStateException(e);
}
}

}

private Policy loadPolicy(String javaPolicyClassName) throws ReflectiveOperationException, SecurityException {
Object javaPolicyInstance =
Thread.currentThread()
.getContextClassLoader()
.loadClass(javaPolicyClassName)
.getDeclaredConstructor()
.newInstance();

if (!(javaPolicyInstance instanceof Policy)) {
throw new RuntimeException(SM.getString("enterprise.security.plcyload.not14"));
}

return (Policy) javaPolicyInstance;
}

private Policy loadPolicyAsProxy(String javaPolicyClassName) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.get(javaPolicyClassName);
clazz.defrost();
clazz.setModifiers(PUBLIC);

Object javaPolicyInstance =
createPolicyProxy(
clazz.toClass(
Thread.currentThread()
.getContextClassLoader()
.loadClass(System.getProperty(POLICY_CONF_FACTORY))));

if (!(javaPolicyInstance instanceof Policy)) {
throw new RuntimeException(SM.getString("enterprise.security.plcyload.not14"));
}

javaPolicyInstance.toString();

return (Policy) javaPolicyInstance;
}
Expand Down

0 comments on commit 26eba02

Please sign in to comment.