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.security.CodeSource; 27 import java.security.Permission; 28 import java.security.PermissionCollection; 29 import java.security.Permissions; 30 import java.security.Policy; 31 import java.security.ProtectionDomain; 32 import java.security.SecurityPermission; 33 import java.util.Enumeration; 34 import java.util.HashMap; 35 import java.util.Map; 36 import java.util.PropertyPermission; 37 import java.util.StringJoiner; 38 39 40 /* 41 * This is a base class that every test class must extend if it needs to be run 42 * with security mode. 43 */ 44 public class JAXPPolicyManager { 45 /* 46 * Backing up policy. 47 */ 48 private Policy policyBackup; 49 50 /* 51 * Backing up security manager. 52 */ 53 private SecurityManager smBackup; 54 55 /* 56 * Current policy. 57 */ 58 private TestPolicy policy = new TestPolicy(); 59 60 /* 61 * JAXPPolicyManager singleton. 62 */ 63 private static JAXPPolicyManager policyManager = null; 64 65 /* 66 * Install a SecurityManager along with a default Policy to allow testNG to 67 * run when there is a security manager. 68 */ 69 private JAXPPolicyManager() { 70 // Backing up policy and security manager for restore 71 policyBackup = Policy.getPolicy(); 72 smBackup = System.getSecurityManager(); 73 74 // Set customized policy 75 setDefaultPermissions(); 76 Policy.setPolicy(policy); 77 System.setSecurityManager(new SecurityManager()); 78 } 79 80 static synchronized JAXPPolicyManager getJAXPPolicyManager(boolean createIfNone) { 81 if (policyManager == null & createIfNone) 82 policyManager = new JAXPPolicyManager(); 83 return policyManager; 84 } 85 86 private void teardown() throws Exception { 87 System.setSecurityManager(smBackup); 88 Policy.setPolicy(policyBackup); 89 } 90 91 /* 92 * Restore the original Policy and SecurityManager. 93 */ 94 static synchronized void teardownPolicyManager() throws Exception { 95 if (policyManager != null) { 96 policyManager.teardown(); 97 policyManager = null; 98 } 99 } 100 101 /* 102 * Set default permissions, sub-class of JAXPBaseTest should override this 103 * method. 104 */ 105 private void setDefaultPermissions() { 106 //Permissions to set security manager and policy 107 addPermission(new SecurityPermission("getPolicy")); 108 addPermission(new SecurityPermission("setPolicy")); 109 addPermission(new RuntimePermission("setSecurityManager")); 110 //Properties that jtreg and TestNG require 111 addPermission(new PropertyPermission("testng.show.stack.frames", "read")); 112 addPermission(new PropertyPermission("test.src", "read")); 113 addPermission(new PropertyPermission("test.classes", "read")); 114 addPermission(new PropertyPermission("dataproviderthreadcount", "read")); 115 addPermission(new PropertyPermission("experimental", "read")); 116 } 117 118 /* 119 * Add permission to the TestPolicy. 120 * 121 * @param permission to be added. 122 */ 123 void addPermission(Permission p) { 124 policy.addPermission(p); 125 } 126 127 /* 128 * Add a temporary permission in current thread context. This won't impact 129 * global policy and doesn't support permission combination. 130 * 131 * @param permission 132 * to add. 133 * @return index of the added permission. 134 */ 135 int addTmpPermission(Permission p) { 136 return policy.addTmpPermission(p); 137 } 138 139 /* 140 * set allowAll in current thread context. 141 */ 142 void setAllowAll(boolean allow) { 143 policy.setAllowAll(allow); 144 } 145 146 /* 147 * Remove a temporary permission from current thread context. 148 * 149 * @param index to remove. 150 * 151 * @throws RuntimeException if no temporary permission list in current 152 * thread context or no permission correlated to the index. 153 */ 154 void removeTmpPermission(int index) { 155 policy.removeTmpPermission(index); 156 } 157 158 159 } 160 161 /* 162 * Simple Policy class that supports the required Permissions to validate the 163 * JAXP concrete classes. 164 */ 165 class TestPolicy extends Policy { 166 private final PermissionCollection permissions = new Permissions(); 167 168 private ThreadLocal<Map<Integer, Permission>> transientPermissions = new ThreadLocal<>(); 169 private ThreadLocal<Boolean> allowAll = new ThreadLocal<>(); 170 171 private static Policy defaultPolicy = Policy.getPolicy(); 172 173 /* 174 * Add permission to this policy. 175 * 176 * @param permission to be added. 177 */ 178 void addPermission(Permission p) { 179 permissions.add(p); 180 } 181 182 /* 183 * Set all permissions. Caution: this should not called carefully unless 184 * it's really needed. 185 * 186 * private void setAllPermissions() { permissions.add(new AllPermission()); 187 * } 188 */ 189 190 /* 191 * Overloaded methods from the Policy class. 192 */ 193 @Override 194 public String toString() { 195 StringJoiner sj = new StringJoiner("\n", "policy: ", ""); 196 Enumeration<Permission> perms = permissions.elements(); 197 while (perms.hasMoreElements()) { 198 sj.add(perms.nextElement().toString()); 199 } 200 return sj.toString(); 201 202 } 203 204 @Override 205 public PermissionCollection getPermissions(ProtectionDomain domain) { 206 return permissions; 207 } 208 209 @Override 210 public PermissionCollection getPermissions(CodeSource codesource) { 211 return permissions; 212 } 213 214 @Override 215 public boolean implies(ProtectionDomain domain, Permission perm) { 216 if (allowAll()) 217 return true; 218 219 if (defaultPolicy.implies(domain, perm)) 220 return true; 221 222 if (permissions.implies(perm)) 223 return true; 224 else 225 return tmpImplies(perm); 226 } 227 228 /* 229 * Add a temporary permission in current thread context. This won't impact 230 * global policy and doesn't support permission combination. 231 * 232 * @param permission to add. 233 * @return index of the added permission. 234 */ 235 int addTmpPermission(Permission p) { 236 Map<Integer, Permission> tmpPermissions = transientPermissions.get(); 237 if (tmpPermissions == null) 238 tmpPermissions = new HashMap<>(); 239 240 int id = tmpPermissions.size(); 241 tmpPermissions.put(id, p); 242 transientPermissions.set(tmpPermissions); 243 return id; 244 } 245 246 /* 247 * Remove a temporary permission from current thread context. 248 * 249 * @param index to remove. 250 * 251 * @throws RuntimeException if no temporary permission list in current 252 * thread context or no permission correlated to the index. 253 */ 254 void removeTmpPermission(int index) { 255 try { 256 Map<Integer, Permission> tmpPermissions = transientPermissions.get(); 257 tmpPermissions.remove(index); 258 } catch (NullPointerException | IndexOutOfBoundsException e) { 259 throw new RuntimeException("Tried to delete a non-existent temporary permission", e); 260 } 261 } 262 263 /* 264 * Checks to see if the specified permission is implied by temporary 265 * permission list in current thread context. 266 * 267 * @param permission the Permission object to compare. 268 * 269 * @return true if "permission" is implied by any permission in the 270 * temporary permission list, false if not. 271 */ 272 private boolean tmpImplies(Permission perm) { 273 Map<Integer, Permission> tmpPermissions = transientPermissions.get(); 274 if (tmpPermissions != null) { 275 for (Permission p : tmpPermissions.values()) { 276 if (p.implies(perm)) 277 return true; 278 } 279 } 280 return false; 281 } 282 283 /* 284 * Checks to see if allow all permission requests in current thread context. 285 */ 286 private boolean allowAll() { 287 Boolean allow = allowAll.get(); 288 if (allow != null) { 289 return allow; 290 } 291 return false; 292 } 293 294 /* 295 * set allowAll in current thread context. 296 */ 297 void setAllowAll(boolean allow) { 298 allowAll.set(allow); 299 } 300 }