1 /*
   2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jaxp.library;
  24 
  25 
  26 import java.lang.reflect.ReflectPermission;
  27 import java.security.CodeSource;
  28 import java.security.Permission;
  29 import java.security.PermissionCollection;
  30 import java.security.Permissions;
  31 import java.security.Policy;
  32 import java.security.ProtectionDomain;
  33 import java.security.SecurityPermission;
  34 import java.util.ArrayList;
  35 import java.util.Enumeration;
  36 import java.util.List;
  37 import java.util.PropertyPermission;
  38 import java.util.StringJoiner;
  39 
  40 
  41 /*
  42  * This is a base class that every test class must extend if it needs to be run
  43  * with security mode.
  44  */
  45 public class JAXPPolicyManager {
  46     /*
  47      * Backing up policy.
  48      */
  49     private Policy policyBackup;
  50 
  51     /*
  52      * Backing up security manager.
  53      */
  54     private SecurityManager smBackup;
  55 
  56     /*
  57      * Current policy.
  58      */
  59     private TestPolicy policy = new TestPolicy();
  60 
  61     /*
  62      * JAXPPolicyManager singleton.
  63      */
  64     private static JAXPPolicyManager policyManager = null;
  65 
  66     /*
  67      * Install a SecurityManager along with a default Policy to allow testNG to
  68      * run when there is a security manager.
  69      */
  70     private JAXPPolicyManager() {
  71         // Backing up policy and security manager for restore
  72         policyBackup = Policy.getPolicy();
  73         smBackup = System.getSecurityManager();
  74 
  75         // Set customized policy
  76         setDefaultPermissions();
  77         Policy.setPolicy(policy);
  78         System.setSecurityManager(new SecurityManager());
  79     }
  80     
  81     static synchronized JAXPPolicyManager getJAXPPolicyManager(boolean createIfNone) {
  82         if (policyManager == null & createIfNone)
  83             policyManager = new JAXPPolicyManager();
  84         return policyManager;
  85     }
  86     
  87     private void teardown() throws Exception {
  88         System.setSecurityManager(smBackup);
  89         Policy.setPolicy(policyBackup);
  90     }
  91 
  92     /*
  93      * Restore the original Policy and SecurityManager.
  94      */
  95     static synchronized void teardownPolicyManager() throws Exception {
  96         if (policyManager != null) {
  97             policyManager.teardown();
  98             policyManager = null;
  99         }
 100     }
 101 
 102     /*
 103      * Set default permissions, sub-class of JAXPBaseTest should override this
 104      * method.
 105      */
 106     private void setDefaultPermissions() {
 107         addPermission(new SecurityPermission("getPolicy"));
 108         addPermission(new SecurityPermission("setPolicy"));
 109         addPermission(new RuntimePermission("getClassLoader"));
 110         addPermission(new RuntimePermission("createClassLoader"));
 111         addPermission(new RuntimePermission("setSecurityManager"));
 112         addPermission(new RuntimePermission("createSecurityManager"));
 113         addPermission(new RuntimePermission("modifyThread"));
 114         addPermission(new PropertyPermission("*", "read, write"));
 115         addPermission(new ReflectPermission("suppressAccessChecks"));
 116         addPermission(new RuntimePermission("setIO"));
 117         addPermission(new RuntimePermission("setContextClassLoader"));
 118         addPermission(new RuntimePermission("accessDeclaredMembers"));
 119     }
 120 
 121     /*
 122      * Add permission to the TestPolicy.
 123      * 
 124      * @param permission to be added.
 125      */
 126     void addPermission(Permission p) {
 127         policy.addPermission(p);
 128     }
 129 
 130     /*
 131      * Add a temporary permission in current thread context. This won't impact
 132      * global policy and doesn't support permission combination.
 133      * 
 134      * @param permission
 135      *            to add.
 136      * @return index of the added permission.
 137      */
 138     int addTmpPermission(Permission p) {
 139         return policy.addTmpPermission(p);
 140     }
 141 
 142     /*
 143      * Remove a temporary permission from current thread context.
 144      * 
 145      * @param index to remove.
 146      *
 147      * @throws RuntimeException if no temporary permission list in current
 148      *             thread context or no permission correlated to the index.
 149      */
 150     void removeTmpPermission(int index) {
 151         policy.removeTmpPermission(index);
 152     }
 153 
 154 
 155 }
 156 
 157 /*
 158  * Simple Policy class that supports the required Permissions to validate the
 159  * JAXP concrete classes.
 160  */
 161 class TestPolicy extends Policy {
 162     private final PermissionCollection permissions = new Permissions();
 163 
 164     private ThreadLocal<List<Permission>> transientPermissions = new ThreadLocal<>();
 165 
 166     private static Policy defaultPolicy = Policy.getPolicy();
 167 
 168     /*
 169      * Add permission to this policy.
 170      * 
 171      * @param permission to be added.
 172      */
 173     void addPermission(Permission p) {
 174         permissions.add(p);
 175     }
 176 
 177     /*
 178      * Set all permissions. Caution: this should not called carefully unless
 179      * it's really needed.
 180      * 
 181      * private void setAllPermissions() { permissions.add(new AllPermission());
 182      * }
 183      */
 184 
 185     /*
 186      * Overloaded methods from the Policy class.
 187      */
 188     @Override
 189     public String toString() {
 190         StringJoiner sj = new StringJoiner("\n", "policy: ", "");
 191         Enumeration<Permission> perms = permissions.elements();
 192         while (perms.hasMoreElements()) {
 193             sj.add(perms.nextElement().toString());
 194         }
 195         return sj.toString();
 196 
 197     }
 198 
 199     @Override
 200     public PermissionCollection getPermissions(ProtectionDomain domain) {
 201         return permissions;
 202     }
 203 
 204     @Override
 205     public PermissionCollection getPermissions(CodeSource codesource) {
 206         return permissions;
 207     }
 208 
 209     @Override
 210     public boolean implies(ProtectionDomain domain, Permission perm) {
 211         if (defaultPolicy.implies(domain, perm))
 212             return true;
 213 
 214         if (permissions.implies(perm))
 215             return true;
 216         else
 217             return tmpImplies(perm);
 218     }
 219 
 220     /*
 221      * Add a temporary permission in current thread context. This won't impact
 222      * global policy and doesn't support permission combination.
 223      * 
 224      * @param permission to add.
 225      * @return index of the added permission.
 226      */
 227     int addTmpPermission(Permission p) {
 228         List<Permission> tmpPermissions = transientPermissions.get();
 229         if (tmpPermissions == null)
 230             tmpPermissions = new ArrayList<>();
 231 
 232         tmpPermissions.add(p);
 233         transientPermissions.set(tmpPermissions);
 234         return tmpPermissions.size() - 1;
 235     }
 236 
 237     /*
 238      * Remove a temporary permission from current thread context.
 239      * 
 240      * @param index to remove.
 241      *
 242      * @throws RuntimeException if no temporary permission list in current
 243      *             thread context or no permission correlated to the index.
 244      */
 245     void removeTmpPermission(int index) {
 246         try {
 247             List<Permission> tmpPermissions = transientPermissions.get();
 248             tmpPermissions.remove(index);
 249         } catch (NullPointerException | IndexOutOfBoundsException e) {
 250             throw new RuntimeException("Tried to delete a non-existent temporary permission", e);
 251         }
 252     }
 253 
 254     /*
 255      * Checks to see if the specified permission is implied by temporary
 256      * permission list in current thread context.
 257      *
 258      * @param permission the Permission object to compare.
 259      *
 260      * @return true if "permission" is implied by any permission in the
 261      *         temporary permission list, false if not.
 262      */
 263     private boolean tmpImplies(Permission perm) {
 264         List<Permission> tmpPermissions = transientPermissions.get();
 265         if (tmpPermissions != null) {
 266             for (Permission p : tmpPermissions) {
 267                 if (p.implies(perm))
 268                     return true;
 269             }
 270         }
 271         return false;
 272     }
 273 }