1 /*
2 * Copyright (c) 1999, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javax.security.auth;
27
28 import java.security.AccessController;
29 import java.security.Permission;
30 import java.security.Permissions;
31 import java.security.PermissionCollection;
32 import java.security.Principal;
33 import java.security.PrivilegedAction;
34 import java.security.ProtectionDomain;
35 import java.security.Security;
36 import java.util.Set;
37 import java.util.WeakHashMap;
38 import java.lang.ref.WeakReference;
39
40 /**
41 * A {@code SubjectDomainCombiner} updates ProtectionDomains
42 * with Principals from the {@code Subject} associated with this
43 * {@code SubjectDomainCombiner}.
44 *
45 * @since 1.4
46 */
47 public class SubjectDomainCombiner implements java.security.DomainCombiner {
48
49 private Subject subject;
50 private WeakKeyValueMap<ProtectionDomain, ProtectionDomain> cachedPDs =
51 new WeakKeyValueMap<>();
52 private Set<Principal> principalSet;
53 private Principal[] principals;
54
55 private static final sun.security.util.Debug debug =
56 sun.security.util.Debug.getInstance("combiner",
57 "\t[SubjectDomainCombiner]");
58
59 @SuppressWarnings({"deprecation", "removal"})
60 // Note: check only at classloading time, not dynamically during combine()
61 private static final boolean useJavaxPolicy =
62 javax.security.auth.Policy.isCustomPolicySet(debug);
63
64 // Relevant only when useJavaxPolicy is true
65 private static final boolean allowCaching =
66 (useJavaxPolicy && cachePolicy());
67
68 /**
69 * Associate the provided {@code Subject} with this
70 * {@code SubjectDomainCombiner}.
71 *
72 * @param subject the {@code Subject} to be associated with
73 * with this {@code SubjectDomainCombiner}.
74 */
75 public SubjectDomainCombiner(Subject subject) {
76 this.subject = subject;
77
78 if (subject.isReadOnly()) {
79 principalSet = subject.getPrincipals();
80 principals = principalSet.toArray
81 (new Principal[principalSet.size()]);
82 }
83 }
84
85 /**
86 * Get the {@code Subject} associated with this
87 * {@code SubjectDomainCombiner}.
179 // array instance in this case
180
181 return assignedDomains;
182 }
183
184 // optimize currentDomains
185 //
186 // No need to optimize assignedDomains because it should
187 // have been previously optimized (when it was set).
188
189 currentDomains = optimize(currentDomains);
190 if (debug != null) {
191 debug.println("after optimize");
192 printInputDomains(currentDomains, assignedDomains);
193 }
194
195 if (currentDomains == null && assignedDomains == null) {
196 return null;
197 }
198
199 // maintain backwards compatibility for developers who provide
200 // their own custom javax.security.auth.Policy implementations
201 if (useJavaxPolicy) {
202 return combineJavaxPolicy(currentDomains, assignedDomains);
203 }
204
205 int cLen = (currentDomains == null ? 0 : currentDomains.length);
206 int aLen = (assignedDomains == null ? 0 : assignedDomains.length);
207
208 // the ProtectionDomains for the new AccessControlContext
209 // that we will return
210 ProtectionDomain[] newDomains = new ProtectionDomain[cLen + aLen];
211
212 boolean allNew = true;
213 synchronized(cachedPDs) {
214 if (!subject.isReadOnly() &&
215 !subject.getPrincipals().equals(principalSet)) {
216
217 // if the Subject was mutated, clear the PD cache
218 Set<Principal> newSet = subject.getPrincipals();
219 synchronized(newSet) {
220 principalSet = new java.util.HashSet<Principal>(newSet);
221 }
222 principals = principalSet.toArray
223 (new Principal[principalSet.size()]);
224 cachedPDs.clear();
275 if (debug != null) {
276 if (newDomains == null || newDomains.length == 0) {
277 debug.println("returning null");
278 } else {
279 debug.println("combinedDomains: ");
280 for (int i = 0; i < newDomains.length; i++) {
281 debug.println("newDomain " + i + ": " +
282 printDomain(newDomains[i]));
283 }
284 }
285 }
286
287 // return the new ProtectionDomains
288 if (newDomains == null || newDomains.length == 0) {
289 return null;
290 } else {
291 return newDomains;
292 }
293 }
294
295 /**
296 * Use the javax.security.auth.Policy implementation
297 */
298 private ProtectionDomain[] combineJavaxPolicy(
299 ProtectionDomain[] currentDomains,
300 ProtectionDomain[] assignedDomains) {
301
302 if (!allowCaching) {
303 java.security.AccessController.doPrivileged
304 (new PrivilegedAction<Void>() {
305 @SuppressWarnings({"deprecation", "removal"})
306 public Void run() {
307 // Call refresh only caching is disallowed
308 javax.security.auth.Policy.getPolicy().refresh();
309 return null;
310 }
311 });
312 }
313
314
315 int cLen = (currentDomains == null ? 0 : currentDomains.length);
316 int aLen = (assignedDomains == null ? 0 : assignedDomains.length);
317
318 // the ProtectionDomains for the new AccessControlContext
319 // that we will return
320 ProtectionDomain[] newDomains = new ProtectionDomain[cLen + aLen];
321
322 synchronized(cachedPDs) {
323 if (!subject.isReadOnly() &&
324 !subject.getPrincipals().equals(principalSet)) {
325
326 // if the Subject was mutated, clear the PD cache
327 Set<Principal> newSet = subject.getPrincipals();
328 synchronized(newSet) {
329 principalSet = new java.util.HashSet<Principal>(newSet);
330 }
331 principals = principalSet.toArray
332 (new Principal[principalSet.size()]);
333 cachedPDs.clear();
334
335 if (debug != null) {
336 debug.println("Subject mutated - clearing cache");
337 }
338 }
339
340 for (int i = 0; i < cLen; i++) {
341 ProtectionDomain pd = currentDomains[i];
342 ProtectionDomain subjectPd = cachedPDs.getValue(pd);
343
344 if (subjectPd == null) {
345 if (pd.staticPermissionsOnly()) {
346 // keep static ProtectionDomain objects static
347 subjectPd = pd;
348 } else {
349 // XXX
350 // we must first add the original permissions.
351 // that way when we later add the new JAAS permissions,
352 // any unresolved JAAS-related permissions will
353 // automatically get resolved.
354
355 // get the original perms
356 Permissions perms = new Permissions();
357 PermissionCollection coll = pd.getPermissions();
358 java.util.Enumeration<Permission> e;
359 if (coll != null) {
360 synchronized (coll) {
361 e = coll.elements();
362 while (e.hasMoreElements()) {
363 Permission newPerm =
364 e.nextElement();
365 perms.add(newPerm);
366 }
367 }
368 }
369
370 // get perms from the policy
371 final java.security.CodeSource finalCs = pd.getCodeSource();
372 final Subject finalS = subject;
373 PermissionCollection newPerms =
374 java.security.AccessController.doPrivileged
375 (new PrivilegedAction<PermissionCollection>() {
376 @SuppressWarnings({"deprecation", "removal"})
377 public PermissionCollection run() {
378 return
379 javax.security.auth.Policy.getPolicy().getPermissions
380 (finalS, finalCs);
381 }
382 });
383
384 // add the newly granted perms,
385 // avoiding duplicates
386 synchronized (newPerms) {
387 e = newPerms.elements();
388 while (e.hasMoreElements()) {
389 Permission newPerm = e.nextElement();
390 if (!perms.implies(newPerm)) {
391 perms.add(newPerm);
392 if (debug != null)
393 debug.println (
394 "Adding perm " + newPerm + "\n");
395 }
396 }
397 }
398 subjectPd = new ProtectionDomain
399 (finalCs, perms, pd.getClassLoader(), principals);
400 }
401 if (allowCaching)
402 cachedPDs.putValue(pd, subjectPd);
403 }
404 newDomains[i] = subjectPd;
405 }
406 }
407
408 if (debug != null) {
409 debug.println("updated current: ");
410 for (int i = 0; i < cLen; i++) {
411 debug.println("\tupdated[" + i + "] = " + newDomains[i]);
412 }
413 }
414
415 // now add on the assigned domains
416 if (aLen > 0) {
417 System.arraycopy(assignedDomains, 0, newDomains, cLen, aLen);
418 }
419
420 if (debug != null) {
421 if (newDomains == null || newDomains.length == 0) {
422 debug.println("returning null");
423 } else {
424 debug.println("combinedDomains: ");
425 for (int i = 0; i < newDomains.length; i++) {
426 debug.println("newDomain " + i + ": " +
427 newDomains[i].toString());
428 }
429 }
430 }
431
432 // return the new ProtectionDomains
433 if (newDomains == null || newDomains.length == 0) {
434 return null;
435 } else {
436 return newDomains;
437 }
438 }
439
440 private static ProtectionDomain[] optimize(ProtectionDomain[] domains) {
441 if (domains == null || domains.length == 0)
442 return null;
443
444 ProtectionDomain[] optimized = new ProtectionDomain[domains.length];
445 ProtectionDomain pd;
446 int num = 0;
447 for (int i = 0; i < domains.length; i++) {
448
449 // skip domains with AllPermission
450 // XXX
451 //
452 // if (domains[i].implies(ALL_PERMISSION))
453 // continue;
454
455 // skip System Domains
456 if ((pd = domains[i]) != null) {
457
458 // remove duplicates
459 boolean found = false;
460 for (int j = 0; j < num && !found; j++) {
461 found = (optimized[j] == pd);
462 }
463 if (!found) {
464 optimized[num++] = pd;
465 }
466 }
467 }
468
469 // resize the array if necessary
470 if (num > 0 && num < domains.length) {
471 ProtectionDomain[] downSize = new ProtectionDomain[num];
472 System.arraycopy(optimized, 0, downSize, 0, downSize.length);
473 optimized = downSize;
474 }
475
476 return ((num == 0 || optimized.length == 0) ? null : optimized);
477 }
478
479 private static boolean cachePolicy() {
480 String s = AccessController.doPrivileged
481 (new PrivilegedAction<String>() {
482 public String run() {
483 return Security.getProperty("cache.auth.policy");
484 }
485 });
486 if (s != null) {
487 return Boolean.parseBoolean(s);
488 }
489
490 // cache by default
491 return true;
492 }
493
494 private static void printInputDomains(ProtectionDomain[] currentDomains,
495 ProtectionDomain[] assignedDomains) {
496 if (currentDomains == null || currentDomains.length == 0) {
497 debug.println("currentDomains null or 0 length");
498 } else {
499 for (int i = 0; currentDomains != null &&
500 i < currentDomains.length; i++) {
501 if (currentDomains[i] == null) {
502 debug.println("currentDomain " + i + ": SystemDomain");
503 } else {
504 debug.println("currentDomain " + i + ": " +
505 printDomain(currentDomains[i]));
506 }
507 }
508 }
509
510 if (assignedDomains == null || assignedDomains.length == 0) {
511 debug.println("assignedDomains null or 0 length");
512 } else {
513 debug.println("assignedDomains = ");
|
1 /*
2 * Copyright (c) 1999, 2018, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javax.security.auth;
27
28 import java.security.AccessController;
29 import java.security.Principal;
30 import java.security.PrivilegedAction;
31 import java.security.ProtectionDomain;
32 import java.util.Set;
33 import java.util.WeakHashMap;
34 import java.lang.ref.WeakReference;
35
36 /**
37 * A {@code SubjectDomainCombiner} updates ProtectionDomains
38 * with Principals from the {@code Subject} associated with this
39 * {@code SubjectDomainCombiner}.
40 *
41 * @since 1.4
42 */
43 public class SubjectDomainCombiner implements java.security.DomainCombiner {
44
45 private Subject subject;
46 private WeakKeyValueMap<ProtectionDomain, ProtectionDomain> cachedPDs =
47 new WeakKeyValueMap<>();
48 private Set<Principal> principalSet;
49 private Principal[] principals;
50
51 private static final sun.security.util.Debug debug =
52 sun.security.util.Debug.getInstance("combiner",
53 "\t[SubjectDomainCombiner]");
54
55 /**
56 * Associate the provided {@code Subject} with this
57 * {@code SubjectDomainCombiner}.
58 *
59 * @param subject the {@code Subject} to be associated with
60 * with this {@code SubjectDomainCombiner}.
61 */
62 public SubjectDomainCombiner(Subject subject) {
63 this.subject = subject;
64
65 if (subject.isReadOnly()) {
66 principalSet = subject.getPrincipals();
67 principals = principalSet.toArray
68 (new Principal[principalSet.size()]);
69 }
70 }
71
72 /**
73 * Get the {@code Subject} associated with this
74 * {@code SubjectDomainCombiner}.
166 // array instance in this case
167
168 return assignedDomains;
169 }
170
171 // optimize currentDomains
172 //
173 // No need to optimize assignedDomains because it should
174 // have been previously optimized (when it was set).
175
176 currentDomains = optimize(currentDomains);
177 if (debug != null) {
178 debug.println("after optimize");
179 printInputDomains(currentDomains, assignedDomains);
180 }
181
182 if (currentDomains == null && assignedDomains == null) {
183 return null;
184 }
185
186 int cLen = (currentDomains == null ? 0 : currentDomains.length);
187 int aLen = (assignedDomains == null ? 0 : assignedDomains.length);
188
189 // the ProtectionDomains for the new AccessControlContext
190 // that we will return
191 ProtectionDomain[] newDomains = new ProtectionDomain[cLen + aLen];
192
193 boolean allNew = true;
194 synchronized(cachedPDs) {
195 if (!subject.isReadOnly() &&
196 !subject.getPrincipals().equals(principalSet)) {
197
198 // if the Subject was mutated, clear the PD cache
199 Set<Principal> newSet = subject.getPrincipals();
200 synchronized(newSet) {
201 principalSet = new java.util.HashSet<Principal>(newSet);
202 }
203 principals = principalSet.toArray
204 (new Principal[principalSet.size()]);
205 cachedPDs.clear();
256 if (debug != null) {
257 if (newDomains == null || newDomains.length == 0) {
258 debug.println("returning null");
259 } else {
260 debug.println("combinedDomains: ");
261 for (int i = 0; i < newDomains.length; i++) {
262 debug.println("newDomain " + i + ": " +
263 printDomain(newDomains[i]));
264 }
265 }
266 }
267
268 // return the new ProtectionDomains
269 if (newDomains == null || newDomains.length == 0) {
270 return null;
271 } else {
272 return newDomains;
273 }
274 }
275
276 private static ProtectionDomain[] optimize(ProtectionDomain[] domains) {
277 if (domains == null || domains.length == 0)
278 return null;
279
280 ProtectionDomain[] optimized = new ProtectionDomain[domains.length];
281 ProtectionDomain pd;
282 int num = 0;
283 for (int i = 0; i < domains.length; i++) {
284
285 // skip domains with AllPermission
286 // XXX
287 //
288 // if (domains[i].implies(ALL_PERMISSION))
289 // continue;
290
291 // skip System Domains
292 if ((pd = domains[i]) != null) {
293
294 // remove duplicates
295 boolean found = false;
296 for (int j = 0; j < num && !found; j++) {
297 found = (optimized[j] == pd);
298 }
299 if (!found) {
300 optimized[num++] = pd;
301 }
302 }
303 }
304
305 // resize the array if necessary
306 if (num > 0 && num < domains.length) {
307 ProtectionDomain[] downSize = new ProtectionDomain[num];
308 System.arraycopy(optimized, 0, downSize, 0, downSize.length);
309 optimized = downSize;
310 }
311
312 return ((num == 0 || optimized.length == 0) ? null : optimized);
313 }
314
315 private static void printInputDomains(ProtectionDomain[] currentDomains,
316 ProtectionDomain[] assignedDomains) {
317 if (currentDomains == null || currentDomains.length == 0) {
318 debug.println("currentDomains null or 0 length");
319 } else {
320 for (int i = 0; currentDomains != null &&
321 i < currentDomains.length; i++) {
322 if (currentDomains[i] == null) {
323 debug.println("currentDomain " + i + ": SystemDomain");
324 } else {
325 debug.println("currentDomain " + i + ": " +
326 printDomain(currentDomains[i]));
327 }
328 }
329 }
330
331 if (assignedDomains == null || assignedDomains.length == 0) {
332 debug.println("assignedDomains null or 0 length");
333 } else {
334 debug.println("assignedDomains = ");
|