Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/security/auth/SubjectDomainCombiner.java
38918 views
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.Policy;
33
import java.security.Principal;
34
import java.security.PrivilegedAction;
35
import java.security.ProtectionDomain;
36
import java.security.Security;
37
import java.util.Set;
38
import java.util.WeakHashMap;
39
import java.lang.ref.WeakReference;
40
import sun.misc.SharedSecrets;
41
import sun.misc.JavaSecurityProtectionDomainAccess;
42
43
/**
44
* A {@code SubjectDomainCombiner} updates ProtectionDomains
45
* with Principals from the {@code Subject} associated with this
46
* {@code SubjectDomainCombiner}.
47
*
48
*/
49
public class SubjectDomainCombiner implements java.security.DomainCombiner {
50
51
private Subject subject;
52
private WeakKeyValueMap<ProtectionDomain, ProtectionDomain> cachedPDs =
53
new WeakKeyValueMap<>();
54
private Set<Principal> principalSet;
55
private Principal[] principals;
56
57
private static final sun.security.util.Debug debug =
58
sun.security.util.Debug.getInstance("combiner",
59
"\t[SubjectDomainCombiner]");
60
61
@SuppressWarnings("deprecation")
62
// Note: check only at classloading time, not dynamically during combine()
63
private static final boolean useJavaxPolicy =
64
javax.security.auth.Policy.isCustomPolicySet(debug);
65
66
// Relevant only when useJavaxPolicy is true
67
private static final boolean allowCaching =
68
(useJavaxPolicy && cachePolicy());
69
70
private static final JavaSecurityProtectionDomainAccess pdAccess =
71
SharedSecrets.getJavaSecurityProtectionDomainAccess();
72
73
/**
74
* Associate the provided {@code Subject} with this
75
* {@code SubjectDomainCombiner}.
76
*
77
* <p>
78
*
79
* @param subject the {@code Subject} to be associated with
80
* with this {@code SubjectDomainCombiner}.
81
*/
82
public SubjectDomainCombiner(Subject subject) {
83
this.subject = subject;
84
85
if (subject.isReadOnly()) {
86
principalSet = subject.getPrincipals();
87
principals = principalSet.toArray
88
(new Principal[principalSet.size()]);
89
}
90
}
91
92
/**
93
* Get the {@code Subject} associated with this
94
* {@code SubjectDomainCombiner}.
95
*
96
* <p>
97
*
98
* @return the {@code Subject} associated with this
99
* {@code SubjectDomainCombiner}, or {@code null}
100
* if no {@code Subject} is associated with this
101
* {@code SubjectDomainCombiner}.
102
*
103
* @exception SecurityException if the caller does not have permission
104
* to get the {@code Subject} associated with this
105
* {@code SubjectDomainCombiner}.
106
*/
107
public Subject getSubject() {
108
java.lang.SecurityManager sm = System.getSecurityManager();
109
if (sm != null) {
110
sm.checkPermission(new AuthPermission
111
("getSubjectFromDomainCombiner"));
112
}
113
return subject;
114
}
115
116
/**
117
* Update the relevant ProtectionDomains with the Principals
118
* from the {@code Subject} associated with this
119
* {@code SubjectDomainCombiner}.
120
*
121
* <p> A new {@code ProtectionDomain} instance is created
122
* for each {@code ProtectionDomain} in the
123
* <i>currentDomains</i> array. Each new {@code ProtectionDomain}
124
* instance is created using the {@code CodeSource},
125
* {@code Permission}s and {@code ClassLoader}
126
* from the corresponding {@code ProtectionDomain} in
127
* <i>currentDomains</i>, as well as with the Principals from
128
* the {@code Subject} associated with this
129
* {@code SubjectDomainCombiner}.
130
*
131
* <p> All of the newly instantiated ProtectionDomains are
132
* combined into a new array. The ProtectionDomains from the
133
* <i>assignedDomains</i> array are appended to this new array,
134
* and the result is returned.
135
*
136
* <p> Note that optimizations such as the removal of duplicate
137
* ProtectionDomains may have occurred.
138
* In addition, caching of ProtectionDomains may be permitted.
139
*
140
* <p>
141
*
142
* @param currentDomains the ProtectionDomains associated with the
143
* current execution Thread, up to the most recent
144
* privileged {@code ProtectionDomain}.
145
* The ProtectionDomains are are listed in order of execution,
146
* with the most recently executing {@code ProtectionDomain}
147
* residing at the beginning of the array. This parameter may
148
* be {@code null} if the current execution Thread
149
* has no associated ProtectionDomains.<p>
150
*
151
* @param assignedDomains the ProtectionDomains inherited from the
152
* parent Thread, or the ProtectionDomains from the
153
* privileged <i>context</i>, if a call to
154
* AccessController.doPrivileged(..., <i>context</i>)
155
* had occurred This parameter may be {@code null}
156
* if there were no ProtectionDomains inherited from the
157
* parent Thread, or from the privileged <i>context</i>.
158
*
159
* @return a new array consisting of the updated ProtectionDomains,
160
* or {@code null}.
161
*/
162
public ProtectionDomain[] combine(ProtectionDomain[] currentDomains,
163
ProtectionDomain[] assignedDomains) {
164
if (debug != null) {
165
if (subject == null) {
166
debug.println("null subject");
167
} else {
168
final Subject s = subject;
169
AccessController.doPrivileged
170
(new java.security.PrivilegedAction<Void>() {
171
public Void run() {
172
debug.println(s.toString());
173
return null;
174
}
175
});
176
}
177
printInputDomains(currentDomains, assignedDomains);
178
}
179
180
if (currentDomains == null || currentDomains.length == 0) {
181
// No need to optimize assignedDomains because it should
182
// have been previously optimized (when it was set).
183
184
// Note that we are returning a direct reference
185
// to the input array - since ACC does not clone
186
// the arrays when it calls combiner.combine,
187
// multiple ACC instances may share the same
188
// array instance in this case
189
190
return assignedDomains;
191
}
192
193
// optimize currentDomains
194
//
195
// No need to optimize assignedDomains because it should
196
// have been previously optimized (when it was set).
197
198
currentDomains = optimize(currentDomains);
199
if (debug != null) {
200
debug.println("after optimize");
201
printInputDomains(currentDomains, assignedDomains);
202
}
203
204
if (currentDomains == null && assignedDomains == null) {
205
return null;
206
}
207
208
// maintain backwards compatibility for developers who provide
209
// their own custom javax.security.auth.Policy implementations
210
if (useJavaxPolicy) {
211
return combineJavaxPolicy(currentDomains, assignedDomains);
212
}
213
214
int cLen = (currentDomains == null ? 0 : currentDomains.length);
215
int aLen = (assignedDomains == null ? 0 : assignedDomains.length);
216
217
// the ProtectionDomains for the new AccessControlContext
218
// that we will return
219
ProtectionDomain[] newDomains = new ProtectionDomain[cLen + aLen];
220
221
boolean allNew = true;
222
synchronized(cachedPDs) {
223
if (!subject.isReadOnly() &&
224
!subject.getPrincipals().equals(principalSet)) {
225
226
// if the Subject was mutated, clear the PD cache
227
Set<Principal> newSet = subject.getPrincipals();
228
synchronized(newSet) {
229
principalSet = new java.util.HashSet<Principal>(newSet);
230
}
231
principals = principalSet.toArray
232
(new Principal[principalSet.size()]);
233
cachedPDs.clear();
234
235
if (debug != null) {
236
debug.println("Subject mutated - clearing cache");
237
}
238
}
239
240
ProtectionDomain subjectPd;
241
for (int i = 0; i < cLen; i++) {
242
ProtectionDomain pd = currentDomains[i];
243
244
subjectPd = cachedPDs.getValue(pd);
245
246
if (subjectPd == null) {
247
if (pdAccess.getStaticPermissionsField(pd)) {
248
// Need to keep static ProtectionDomain objects static
249
subjectPd = new ProtectionDomain(pd.getCodeSource(),
250
pd.getPermissions());
251
} else {
252
subjectPd = new ProtectionDomain(pd.getCodeSource(),
253
pd.getPermissions(),
254
pd.getClassLoader(),
255
principals);
256
}
257
cachedPDs.putValue(pd, subjectPd);
258
} else {
259
allNew = false;
260
}
261
newDomains[i] = subjectPd;
262
}
263
}
264
265
if (debug != null) {
266
debug.println("updated current: ");
267
for (int i = 0; i < cLen; i++) {
268
debug.println("\tupdated[" + i + "] = " +
269
printDomain(newDomains[i]));
270
}
271
}
272
273
// now add on the assigned domains
274
if (aLen > 0) {
275
System.arraycopy(assignedDomains, 0, newDomains, cLen, aLen);
276
277
// optimize the result (cached PDs might exist in assignedDomains)
278
if (!allNew) {
279
newDomains = optimize(newDomains);
280
}
281
}
282
283
// if aLen == 0 || allNew, no need to further optimize newDomains
284
285
if (debug != null) {
286
if (newDomains == null || newDomains.length == 0) {
287
debug.println("returning null");
288
} else {
289
debug.println("combinedDomains: ");
290
for (int i = 0; i < newDomains.length; i++) {
291
debug.println("newDomain " + i + ": " +
292
printDomain(newDomains[i]));
293
}
294
}
295
}
296
297
// return the new ProtectionDomains
298
if (newDomains == null || newDomains.length == 0) {
299
return null;
300
} else {
301
return newDomains;
302
}
303
}
304
305
/**
306
* Use the javax.security.auth.Policy implementation
307
*/
308
private ProtectionDomain[] combineJavaxPolicy(
309
ProtectionDomain[] currentDomains,
310
ProtectionDomain[] assignedDomains) {
311
312
if (!allowCaching) {
313
java.security.AccessController.doPrivileged
314
(new PrivilegedAction<Void>() {
315
@SuppressWarnings("deprecation")
316
public Void run() {
317
// Call refresh only caching is disallowed
318
javax.security.auth.Policy.getPolicy().refresh();
319
return null;
320
}
321
});
322
}
323
324
325
int cLen = (currentDomains == null ? 0 : currentDomains.length);
326
int aLen = (assignedDomains == null ? 0 : assignedDomains.length);
327
328
// the ProtectionDomains for the new AccessControlContext
329
// that we will return
330
ProtectionDomain[] newDomains = new ProtectionDomain[cLen + aLen];
331
332
synchronized(cachedPDs) {
333
if (!subject.isReadOnly() &&
334
!subject.getPrincipals().equals(principalSet)) {
335
336
// if the Subject was mutated, clear the PD cache
337
Set<Principal> newSet = subject.getPrincipals();
338
synchronized(newSet) {
339
principalSet = new java.util.HashSet<Principal>(newSet);
340
}
341
principals = principalSet.toArray
342
(new Principal[principalSet.size()]);
343
cachedPDs.clear();
344
345
if (debug != null) {
346
debug.println("Subject mutated - clearing cache");
347
}
348
}
349
350
for (int i = 0; i < cLen; i++) {
351
ProtectionDomain pd = currentDomains[i];
352
ProtectionDomain subjectPd = cachedPDs.getValue(pd);
353
354
if (subjectPd == null) {
355
if (pdAccess.getStaticPermissionsField(pd)) {
356
// keep static ProtectionDomain objects static
357
subjectPd = new ProtectionDomain(pd.getCodeSource(),
358
pd.getPermissions());
359
} else {
360
// XXX
361
// we must first add the original permissions.
362
// that way when we later add the new JAAS permissions,
363
// any unresolved JAAS-related permissions will
364
// automatically get resolved.
365
366
// get the original perms
367
Permissions perms = new Permissions();
368
PermissionCollection coll = pd.getPermissions();
369
java.util.Enumeration<Permission> e;
370
if (coll != null) {
371
synchronized (coll) {
372
e = coll.elements();
373
while (e.hasMoreElements()) {
374
Permission newPerm =
375
e.nextElement();
376
perms.add(newPerm);
377
}
378
}
379
}
380
381
// get perms from the policy
382
final java.security.CodeSource finalCs = pd.getCodeSource();
383
final Subject finalS = subject;
384
PermissionCollection newPerms =
385
java.security.AccessController.doPrivileged
386
(new PrivilegedAction<PermissionCollection>() {
387
@SuppressWarnings("deprecation")
388
public PermissionCollection run() {
389
return
390
javax.security.auth.Policy.getPolicy().getPermissions
391
(finalS, finalCs);
392
}
393
});
394
395
// add the newly granted perms,
396
// avoiding duplicates
397
synchronized (newPerms) {
398
e = newPerms.elements();
399
while (e.hasMoreElements()) {
400
Permission newPerm = e.nextElement();
401
if (!perms.implies(newPerm)) {
402
perms.add(newPerm);
403
if (debug != null)
404
debug.println (
405
"Adding perm " + newPerm + "\n");
406
}
407
}
408
}
409
subjectPd = new ProtectionDomain
410
(finalCs, perms, pd.getClassLoader(), principals);
411
}
412
if (allowCaching)
413
cachedPDs.putValue(pd, subjectPd);
414
}
415
newDomains[i] = subjectPd;
416
}
417
}
418
419
if (debug != null) {
420
debug.println("updated current: ");
421
for (int i = 0; i < cLen; i++) {
422
debug.println("\tupdated[" + i + "] = " + newDomains[i]);
423
}
424
}
425
426
// now add on the assigned domains
427
if (aLen > 0) {
428
System.arraycopy(assignedDomains, 0, newDomains, cLen, aLen);
429
}
430
431
if (debug != null) {
432
if (newDomains == null || newDomains.length == 0) {
433
debug.println("returning null");
434
} else {
435
debug.println("combinedDomains: ");
436
for (int i = 0; i < newDomains.length; i++) {
437
debug.println("newDomain " + i + ": " +
438
newDomains[i].toString());
439
}
440
}
441
}
442
443
// return the new ProtectionDomains
444
if (newDomains == null || newDomains.length == 0) {
445
return null;
446
} else {
447
return newDomains;
448
}
449
}
450
451
private static ProtectionDomain[] optimize(ProtectionDomain[] domains) {
452
if (domains == null || domains.length == 0)
453
return null;
454
455
ProtectionDomain[] optimized = new ProtectionDomain[domains.length];
456
ProtectionDomain pd;
457
int num = 0;
458
for (int i = 0; i < domains.length; i++) {
459
460
// skip domains with AllPermission
461
// XXX
462
//
463
// if (domains[i].implies(ALL_PERMISSION))
464
// continue;
465
466
// skip System Domains
467
if ((pd = domains[i]) != null) {
468
469
// remove duplicates
470
boolean found = false;
471
for (int j = 0; j < num && !found; j++) {
472
found = (optimized[j] == pd);
473
}
474
if (!found) {
475
optimized[num++] = pd;
476
}
477
}
478
}
479
480
// resize the array if necessary
481
if (num > 0 && num < domains.length) {
482
ProtectionDomain[] downSize = new ProtectionDomain[num];
483
System.arraycopy(optimized, 0, downSize, 0, downSize.length);
484
optimized = downSize;
485
}
486
487
return ((num == 0 || optimized.length == 0) ? null : optimized);
488
}
489
490
private static boolean cachePolicy() {
491
String s = AccessController.doPrivileged
492
(new PrivilegedAction<String>() {
493
public String run() {
494
return Security.getProperty("cache.auth.policy");
495
}
496
});
497
if (s != null) {
498
return Boolean.parseBoolean(s);
499
}
500
501
// cache by default
502
return true;
503
}
504
505
private static void printInputDomains(ProtectionDomain[] currentDomains,
506
ProtectionDomain[] assignedDomains) {
507
if (currentDomains == null || currentDomains.length == 0) {
508
debug.println("currentDomains null or 0 length");
509
} else {
510
for (int i = 0; currentDomains != null &&
511
i < currentDomains.length; i++) {
512
if (currentDomains[i] == null) {
513
debug.println("currentDomain " + i + ": SystemDomain");
514
} else {
515
debug.println("currentDomain " + i + ": " +
516
printDomain(currentDomains[i]));
517
}
518
}
519
}
520
521
if (assignedDomains == null || assignedDomains.length == 0) {
522
debug.println("assignedDomains null or 0 length");
523
} else {
524
debug.println("assignedDomains = ");
525
for (int i = 0; assignedDomains != null &&
526
i < assignedDomains.length; i++) {
527
if (assignedDomains[i] == null) {
528
debug.println("assignedDomain " + i + ": SystemDomain");
529
} else {
530
debug.println("assignedDomain " + i + ": " +
531
printDomain(assignedDomains[i]));
532
}
533
}
534
}
535
}
536
537
private static String printDomain(final ProtectionDomain pd) {
538
if (pd == null) {
539
return "null";
540
}
541
return AccessController.doPrivileged(new PrivilegedAction<String>() {
542
public String run() {
543
return pd.toString();
544
}
545
});
546
}
547
548
/**
549
* A HashMap that has weak keys and values.
550
*
551
* Key objects in this map are the "current" ProtectionDomain instances
552
* received via the combine method. Each "current" PD is mapped to a
553
* new PD instance that holds both the contents of the "current" PD,
554
* as well as the principals from the Subject associated with this combiner.
555
*
556
* The newly created "principal-based" PD values must be stored as
557
* WeakReferences since they contain strong references to the
558
* corresponding key object (the "current" non-principal-based PD),
559
* which will prevent the key from being GC'd. Specifically,
560
* a "principal-based" PD contains strong references to the CodeSource,
561
* signer certs, PermissionCollection and ClassLoader objects
562
* in the "current PD".
563
*/
564
private static class WeakKeyValueMap<K,V> extends
565
WeakHashMap<K,WeakReference<V>> {
566
567
public V getValue(K key) {
568
WeakReference<V> wr = super.get(key);
569
if (wr != null) {
570
return wr.get();
571
}
572
return null;
573
}
574
575
public V putValue(K key, V value) {
576
WeakReference<V> wr = super.put(key, new WeakReference<V>(value));
577
if (wr != null) {
578
return wr.get();
579
}
580
return null;
581
}
582
}
583
}
584
585