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