/* * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jaxp.library; import java.lang.reflect.ReflectPermission; import java.security.CodeSource; import java.security.Permission; import java.security.PermissionCollection; import java.security.Permissions; import java.security.Policy; import java.security.ProtectionDomain; import java.security.SecurityPermission; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.PropertyPermission; import java.util.StringJoiner; /* * This is a base class that every test class must extend if it needs to be run * with security mode. */ public class JAXPPolicyManager { /* * Backing up policy. */ private Policy policyBackup; /* * Backing up security manager. */ private SecurityManager smBackup; /* * Current policy. */ private TestPolicy policy = new TestPolicy(); /* * JAXPPolicyManager singleton. */ private static JAXPPolicyManager policyManager = null; /* * Install a SecurityManager along with a default Policy to allow testNG to * run when there is a security manager. */ private JAXPPolicyManager() { // Backing up policy and security manager for restore policyBackup = Policy.getPolicy(); smBackup = System.getSecurityManager(); // Set customized policy setDefaultPermissions(); Policy.setPolicy(policy); System.setSecurityManager(new SecurityManager()); } static synchronized JAXPPolicyManager getJAXPPolicyManager(boolean createIfNone) { if (policyManager == null & createIfNone) policyManager = new JAXPPolicyManager(); return policyManager; } private void teardown() throws Exception { System.setSecurityManager(smBackup); Policy.setPolicy(policyBackup); } /* * Restore the original Policy and SecurityManager. */ static synchronized void teardownPolicyManager() throws Exception { if (policyManager != null) { policyManager.teardown(); policyManager = null; } } /* * Set default permissions, sub-class of JAXPBaseTest should override this * method. */ private void setDefaultPermissions() { addPermission(new SecurityPermission("getPolicy")); addPermission(new SecurityPermission("setPolicy")); addPermission(new RuntimePermission("getClassLoader")); addPermission(new RuntimePermission("createClassLoader")); addPermission(new RuntimePermission("setSecurityManager")); addPermission(new RuntimePermission("createSecurityManager")); addPermission(new RuntimePermission("modifyThread")); addPermission(new PropertyPermission("*", "read, write")); addPermission(new ReflectPermission("suppressAccessChecks")); addPermission(new RuntimePermission("setIO")); addPermission(new RuntimePermission("setContextClassLoader")); addPermission(new RuntimePermission("accessDeclaredMembers")); } /* * Add permission to the TestPolicy. * * @param permission to be added. */ void addPermission(Permission p) { policy.addPermission(p); } /* * Add a temporary permission in current thread context. This won't impact * global policy and doesn't support permission combination. * * @param permission * to add. * @return index of the added permission. */ int addTmpPermission(Permission p) { return policy.addTmpPermission(p); } /* * Remove a temporary permission from current thread context. * * @param index to remove. * * @throws RuntimeException if no temporary permission list in current * thread context or no permission correlated to the index. */ void removeTmpPermission(int index) { policy.removeTmpPermission(index); } } /* * Simple Policy class that supports the required Permissions to validate the * JAXP concrete classes. */ class TestPolicy extends Policy { private final PermissionCollection permissions = new Permissions(); private ThreadLocal> transientPermissions = new ThreadLocal<>(); private static Policy defaultPolicy = Policy.getPolicy(); /* * Add permission to this policy. * * @param permission to be added. */ void addPermission(Permission p) { permissions.add(p); } /* * Set all permissions. Caution: this should not called carefully unless * it's really needed. * * private void setAllPermissions() { permissions.add(new AllPermission()); * } */ /* * Overloaded methods from the Policy class. */ @Override public String toString() { StringJoiner sj = new StringJoiner("\n", "policy: ", ""); Enumeration perms = permissions.elements(); while (perms.hasMoreElements()) { sj.add(perms.nextElement().toString()); } return sj.toString(); } @Override public PermissionCollection getPermissions(ProtectionDomain domain) { return permissions; } @Override public PermissionCollection getPermissions(CodeSource codesource) { return permissions; } @Override public boolean implies(ProtectionDomain domain, Permission perm) { if (defaultPolicy.implies(domain, perm)) return true; if (permissions.implies(perm)) return true; else return tmpImplies(perm); } /* * Add a temporary permission in current thread context. This won't impact * global policy and doesn't support permission combination. * * @param permission to add. * @return index of the added permission. */ int addTmpPermission(Permission p) { List tmpPermissions = transientPermissions.get(); if (tmpPermissions == null) tmpPermissions = new ArrayList<>(); tmpPermissions.add(p); transientPermissions.set(tmpPermissions); return tmpPermissions.size() - 1; } /* * Remove a temporary permission from current thread context. * * @param index to remove. * * @throws RuntimeException if no temporary permission list in current * thread context or no permission correlated to the index. */ void removeTmpPermission(int index) { try { List tmpPermissions = transientPermissions.get(); tmpPermissions.remove(index); } catch (NullPointerException | IndexOutOfBoundsException e) { throw new RuntimeException("Tried to delete a non-existent temporary permission", e); } } /* * Checks to see if the specified permission is implied by temporary * permission list in current thread context. * * @param permission the Permission object to compare. * * @return true if "permission" is implied by any permission in the * temporary permission list, false if not. */ private boolean tmpImplies(Permission perm) { List tmpPermissions = transientPermissions.get(); if (tmpPermissions != null) { for (Permission p : tmpPermissions) { if (p.implies(perm)) return true; } } return false; } }