Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.base/share/classes/sun/security/provider/PolicyFile.java
67848 views
1
/*
2
* Copyright (c) 1997, 2021, 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 sun.security.provider;
27
28
import java.io.*;
29
import java.lang.reflect.*;
30
import java.net.MalformedURLException;
31
import java.net.URL;
32
import java.net.URI;
33
import java.nio.file.Files;
34
import java.nio.file.Path;
35
import java.util.*;
36
import java.security.*;
37
import java.security.cert.Certificate;
38
import java.security.cert.X509Certificate;
39
import javax.security.auth.Subject;
40
import javax.security.auth.x500.X500Principal;
41
import java.net.SocketPermission;
42
import java.net.NetPermission;
43
import java.util.concurrent.ConcurrentHashMap;
44
import jdk.internal.access.JavaSecurityAccess;
45
import jdk.internal.access.SharedSecrets;
46
import jdk.internal.util.StaticProperty;
47
import sun.nio.fs.DefaultFileSystemProvider;
48
import sun.security.util.*;
49
import sun.net.www.ParseUtil;
50
51
import static java.nio.charset.StandardCharsets.UTF_8;
52
import static jdk.internal.access.JavaSecurityAccess.ProtectionDomainCache;
53
54
/**
55
* This class represents a default Policy implementation for the
56
* "JavaPolicy" type.
57
*
58
* <p> This object stores the policy for the entire Java runtime,
59
* and is the amalgamation of multiple static policy
60
* configurations that resides in files.
61
* The algorithm for locating the policy file(s) and reading their
62
* information into this <code>Policy</code> object is:
63
*
64
* <ol>
65
* <li>
66
* Read in and load the default policy file named
67
* &lt;JAVA_HOME&gt;/lib/security/default.policy. &lt;JAVA_HOME&gt; refers
68
* to the value of the java.home system property, and specifies the directory
69
* where the JRE is installed. This policy file grants permissions to the
70
* modules loaded by the platform class loader. If the default policy file
71
* cannot be loaded, a fatal InternalError is thrown as these permissions
72
* are needed in order for the runtime to operate correctly.
73
* <li>
74
* Loop through the <code>java.security.Security</code> properties,
75
* and <i>policy.url.1</i>, <i>policy.url.2</i>, ...,
76
* <i>policy.url.X</i>". These properties are set
77
* in the Java security properties file, which is located in the file named
78
* &lt;JAVA_HOME&gt;/conf/security/java.security.
79
* Each property value specifies a <code>URL</code> pointing to a
80
* policy file to be loaded. Read in and load each policy.
81
*
82
* If none of these could be loaded, use a builtin static policy
83
* equivalent to the conf/security/java.policy file.
84
*
85
* <li>
86
* The <code>java.lang.System</code> property <i>java.security.policy</i>
87
* may also be set to a <code>URL</code> pointing to another policy file
88
* (which is the case when a user uses the -D switch at runtime).
89
* If this property is defined, and its use is allowed by the
90
* security property file (the Security property,
91
* <i>policy.allowSystemProperty</i> is set to <i>true</i>),
92
* also load that policy.
93
*
94
* If the <i>java.security.policy</i> property is defined using
95
* "==" (rather than "="), then load the specified policy file and ignore
96
* all other configured policies. Note, that the default.policy file is
97
* also loaded, as specified in the first step of the algorithm above.
98
* If the specified policy file cannot be loaded, use a builtin static policy
99
* equivalent to the default conf/security/java.policy file.
100
* </ol>
101
*
102
* Each policy file consists of one or more grant entries, each of
103
* which consists of a number of permission entries.
104
*
105
* <pre>
106
* grant signedBy "<b>alias</b>", codeBase "<b>URL</b>",
107
* principal <b>principalClass</b> "<b>principalName</b>",
108
* principal <b>principalClass</b> "<b>principalName</b>",
109
* ... {
110
*
111
* permission <b>Type</b> "<b>name</b> "<b>action</b>",
112
* signedBy "<b>alias</b>";
113
* permission <b>Type</b> "<b>name</b> "<b>action</b>",
114
* signedBy "<b>alias</b>";
115
* ....
116
* };
117
* </pre>
118
*
119
* All non-bold items above must appear as is (although case
120
* doesn't matter and some are optional, as noted below).
121
* principal entries are optional and need not be present.
122
* Italicized items represent variable values.
123
*
124
* <p> A grant entry must begin with the word <code>grant</code>.
125
* The <code>signedBy</code>,<code>codeBase</code> and <code>principal</code>
126
* name/value pairs are optional.
127
* If they are not present, then any signer (including unsigned code)
128
* will match, and any codeBase will match.
129
* Note that the <i>principalClass</i>
130
* may be set to the wildcard value, *, which allows it to match
131
* any <code>Principal</code> class. In addition, the <i>principalName</i>
132
* may also be set to the wildcard value, *, allowing it to match
133
* any <code>Principal</code> name. When setting the <i>principalName</i>
134
* to the *, do not surround the * with quotes.
135
*
136
* <p> A permission entry must begin with the word <code>permission</code>.
137
* The word <code><i>Type</i></code> in the template above is
138
* a specific permission type, such as <code>java.io.FilePermission</code>
139
* or <code>java.lang.RuntimePermission</code>.
140
*
141
* <p> The "<i>action</i>" is required for
142
* many permission types, such as <code>java.io.FilePermission</code>
143
* (where it specifies what type of file access that is permitted).
144
* It is not required for categories such as
145
* <code>java.lang.RuntimePermission</code>
146
* where it is not necessary - you either have the
147
* permission specified by the <code>"<i>name</i>"</code>
148
* value following the type name or you don't.
149
*
150
* <p> The <code>signedBy</code> name/value pair for a permission entry
151
* is optional. If present, it indicates a signed permission. That is,
152
* the permission class itself must be signed by the given alias in
153
* order for it to be granted. For example,
154
* suppose you have the following grant entry:
155
*
156
* <pre>
157
* grant principal foo.com.Principal "Duke" {
158
* permission Foo "foobar", signedBy "FooSoft";
159
* }
160
* </pre>
161
*
162
* <p> Then this permission of type <i>Foo</i> is granted if the
163
* <code>Foo.class</code> permission has been signed by the
164
* "FooSoft" alias, or if XXX <code>Foo.class</code> is a
165
* system class (i.e., is found on the CLASSPATH).
166
*
167
* <p> Items that appear in an entry must appear in the specified order
168
* (<code>permission</code>, <i>Type</i>, "<i>name</i>", and
169
* "<i>action</i>"). An entry is terminated with a semicolon.
170
*
171
* <p> Case is unimportant for the identifiers (<code>permission</code>,
172
* <code>signedBy</code>, <code>codeBase</code>, etc.) but is
173
* significant for the <i>Type</i>
174
* or for any string that is passed in as a value.
175
*
176
* <p> An example of two entries in a policy configuration file is
177
* <pre>
178
* // if the code is comes from "foo.com" and is running as "Duke",
179
* // grant it read/write to all files in /tmp.
180
*
181
* grant codeBase "foo.com", principal foo.com.Principal "Duke" {
182
* permission java.io.FilePermission "/tmp/*", "read,write";
183
* };
184
*
185
* // grant any code running as "Duke" permission to read
186
* // the "java.vendor" Property.
187
*
188
* grant principal foo.com.Principal "Duke" {
189
* permission java.util.PropertyPermission "java.vendor";
190
*
191
*
192
* </pre>
193
* This Policy implementation supports special handling of any
194
* permission that contains the string, "<b>${{self}}</b>", as part of
195
* its target name. When such a permission is evaluated
196
* (such as during a security check), <b>${{self}}</b> is replaced
197
* with one or more Principal class/name pairs. The exact
198
* replacement performed depends upon the contents of the
199
* grant clause to which the permission belongs.
200
* <p>
201
*
202
* If the grant clause does not contain any principal information,
203
* the permission will be ignored (permissions containing
204
* <b>${{self}}</b> in their target names are only valid in the context
205
* of a principal-based grant clause). For example, BarPermission
206
* will always be ignored in the following grant clause:
207
*
208
* <pre>
209
* grant codebase "www.foo.com", signedby "duke" {
210
* permission BarPermission "... ${{self}} ...";
211
* };
212
* </pre>
213
*
214
* If the grant clause contains principal information, <b>${{self}}</b>
215
* will be replaced with that same principal information.
216
* For example, <b>${{self}}</b> in BarPermission will be replaced by
217
* <b>javax.security.auth.x500.X500Principal "cn=Duke"</b>
218
* in the following grant clause:
219
*
220
* <pre>
221
* grant principal javax.security.auth.x500.X500Principal "cn=Duke" {
222
* permission BarPermission "... ${{self}} ...";
223
* };
224
* </pre>
225
*
226
* If there is a comma-separated list of principals in the grant
227
* clause, then <b>${{self}}</b> will be replaced by the same
228
* comma-separated list or principals.
229
* In the case where both the principal class and name are
230
* wildcarded in the grant clause, <b>${{self}}</b> is replaced
231
* with all the principals associated with the <code>Subject</code>
232
* in the current <code>AccessControlContext</code>.
233
*
234
* <p> For PrivateCredentialPermissions, you can also use "<b>self</b>"
235
* instead of "<b>${{self}}</b>". However the use of "<b>self</b>" is
236
* deprecated in favour of "<b>${{self}}</b>".
237
*
238
* @see java.security.CodeSource
239
* @see java.security.Permissions
240
* @see java.security.ProtectionDomain
241
*/
242
@SuppressWarnings("removal")
243
public class PolicyFile extends java.security.Policy {
244
245
private static final Debug debug = Debug.getInstance("policy");
246
247
private static final String SELF = "${{self}}";
248
private static final String X500PRINCIPAL =
249
"javax.security.auth.x500.X500Principal";
250
private static final String POLICY = "java.security.policy";
251
private static final String POLICY_URL = "policy.url.";
252
253
private static final int DEFAULT_CACHE_SIZE = 1;
254
255
// contains the policy grant entries, PD cache, and alias mapping
256
// can be updated if refresh() is called
257
private volatile PolicyInfo policyInfo;
258
259
private boolean expandProperties = true;
260
private boolean allowSystemProperties = true;
261
private boolean notUtf8 = false;
262
private URL url;
263
264
// for use with the reflection API
265
private static final Class<?>[] PARAMS0 = { };
266
private static final Class<?>[] PARAMS1 = { String.class };
267
private static final Class<?>[] PARAMS2 = { String.class, String.class };
268
269
/**
270
* When a policy file has a syntax error, the exception code may generate
271
* another permission check and this can cause the policy file to be parsed
272
* repeatedly, leading to a StackOverflowError or ClassCircularityError.
273
* To avoid this, this set is populated with policy files that have been
274
* previously parsed and have syntax errors, so that they can be
275
* subsequently ignored.
276
*/
277
private static Set<URL> badPolicyURLs =
278
Collections.newSetFromMap(new ConcurrentHashMap<URL,Boolean>());
279
280
/**
281
* Use the platform's default file system to avoid recursive initialization
282
* issues when the VM is configured to use a custom file system provider.
283
*/
284
private static final java.nio.file.FileSystem builtInFS =
285
DefaultFileSystemProvider.theFileSystem();
286
287
/**
288
* Initializes the Policy object and reads the default policy
289
* configuration file(s) into the Policy object.
290
*/
291
public PolicyFile() {
292
init((URL)null);
293
}
294
295
/**
296
* Initializes the Policy object and reads the default policy
297
* from the specified URL only.
298
*/
299
public PolicyFile(URL url) {
300
this.url = url;
301
init(url);
302
}
303
304
/**
305
* Initializes the Policy object and reads the default policy
306
* configuration file(s) into the Policy object.
307
*
308
* See the class description for details on the algorithm used to
309
* initialize the Policy object.
310
*/
311
private void init(URL url) {
312
// Properties are set once for each init(); ignore changes
313
// between diff invocations of initPolicyFile(policy, url, info).
314
String numCacheStr =
315
AccessController.doPrivileged(new PrivilegedAction<>() {
316
@Override
317
public String run() {
318
expandProperties = "true".equalsIgnoreCase
319
(Security.getProperty("policy.expandProperties"));
320
allowSystemProperties = "true".equalsIgnoreCase
321
(Security.getProperty("policy.allowSystemProperty"));
322
notUtf8 = "false".equalsIgnoreCase
323
(System.getProperty("sun.security.policy.utf8"));
324
return System.getProperty("sun.security.policy.numcaches");
325
}});
326
327
int numCaches;
328
if (numCacheStr != null) {
329
try {
330
numCaches = Integer.parseInt(numCacheStr);
331
} catch (NumberFormatException e) {
332
numCaches = DEFAULT_CACHE_SIZE;
333
}
334
} else {
335
numCaches = DEFAULT_CACHE_SIZE;
336
}
337
PolicyInfo newInfo = new PolicyInfo(numCaches);
338
initPolicyFile(newInfo, url);
339
policyInfo = newInfo;
340
}
341
342
private void initPolicyFile(final PolicyInfo newInfo, final URL url) {
343
344
// always load default.policy
345
AccessController.doPrivileged(new PrivilegedAction<>() {
346
@Override
347
public Void run() {
348
initDefaultPolicy(newInfo);
349
return null;
350
}
351
});
352
353
if (url != null) {
354
355
/**
356
* If the caller specified a URL via Policy.getInstance,
357
* we only read from default.policy and that URL.
358
*/
359
360
if (debug != null) {
361
debug.println("reading " + url);
362
}
363
AccessController.doPrivileged(new PrivilegedAction<>() {
364
@Override
365
public Void run() {
366
if (init(url, newInfo) == false) {
367
// use static policy if all else fails
368
initStaticPolicy(newInfo);
369
}
370
return null;
371
}
372
});
373
374
} else {
375
376
/**
377
* Caller did not specify URL via Policy.getInstance.
378
* Read from URLs listed in the java.security properties file.
379
*/
380
381
boolean loaded_one = initPolicyFile(POLICY, POLICY_URL, newInfo);
382
// To maintain strict backward compatibility
383
// we load the static policy only if POLICY load failed
384
if (!loaded_one) {
385
// use static policy if all else fails
386
initStaticPolicy(newInfo);
387
}
388
}
389
}
390
391
private boolean initPolicyFile(final String propname, final String urlname,
392
final PolicyInfo newInfo) {
393
boolean loadedPolicy =
394
AccessController.doPrivileged(new PrivilegedAction<>() {
395
@Override
396
public Boolean run() {
397
boolean loaded_policy = false;
398
399
if (allowSystemProperties) {
400
String extra_policy = System.getProperty(propname);
401
if (extra_policy != null) {
402
boolean overrideAll = false;
403
if (extra_policy.startsWith("=")) {
404
overrideAll = true;
405
extra_policy = extra_policy.substring(1);
406
}
407
try {
408
extra_policy =
409
PropertyExpander.expand(extra_policy);
410
URL policyURL;
411
412
File policyFile = new File(extra_policy);
413
if (policyFile.exists()) {
414
policyURL = ParseUtil.fileToEncodedURL
415
(new File(policyFile.getCanonicalPath()));
416
} else {
417
policyURL = new URL(extra_policy);
418
}
419
if (debug != null) {
420
debug.println("reading "+policyURL);
421
}
422
if (init(policyURL, newInfo)) {
423
loaded_policy = true;
424
}
425
} catch (Exception e) {
426
// ignore.
427
if (debug != null) {
428
debug.println("caught exception: "+e);
429
}
430
}
431
if (overrideAll) {
432
if (debug != null) {
433
debug.println("overriding other policies!");
434
}
435
return Boolean.valueOf(loaded_policy);
436
}
437
}
438
}
439
440
int n = 1;
441
String policy_uri;
442
443
while ((policy_uri = Security.getProperty(urlname+n)) != null) {
444
try {
445
URL policy_url = null;
446
String expanded_uri = PropertyExpander.expand
447
(policy_uri).replace(File.separatorChar, '/');
448
449
if (policy_uri.startsWith("file:${java.home}/") ||
450
policy_uri.startsWith("file:${user.home}/")) {
451
452
// this special case accommodates
453
// the situation java.home/user.home
454
// expand to a single slash, resulting in
455
// a file://foo URI
456
policy_url = new File
457
(expanded_uri.substring(5)).toURI().toURL();
458
} else {
459
policy_url = new URI(expanded_uri).toURL();
460
}
461
462
if (debug != null) {
463
debug.println("reading " + policy_url);
464
}
465
if (init(policy_url, newInfo)) {
466
loaded_policy = true;
467
}
468
} catch (Exception e) {
469
if (debug != null) {
470
debug.println(
471
"Debug info only. Error reading policy " +e);
472
e.printStackTrace();
473
}
474
// ignore that policy
475
}
476
n++;
477
}
478
return Boolean.valueOf(loaded_policy);
479
}
480
});
481
482
return loadedPolicy;
483
}
484
485
private void initDefaultPolicy(PolicyInfo newInfo) {
486
Path defaultPolicy = builtInFS.getPath(StaticProperty.javaHome(),
487
"lib",
488
"security",
489
"default.policy");
490
if (debug != null) {
491
debug.println("reading " + defaultPolicy);
492
}
493
try (BufferedReader br = Files.newBufferedReader(defaultPolicy)) {
494
495
PolicyParser pp = new PolicyParser(expandProperties);
496
pp.read(br);
497
498
Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();
499
while (enum_.hasMoreElements()) {
500
PolicyParser.GrantEntry ge = enum_.nextElement();
501
addGrantEntry(ge, null, newInfo);
502
}
503
} catch (Exception e) {
504
throw new InternalError("Failed to load default.policy", e);
505
}
506
}
507
508
/**
509
* Reads a policy configuration into the Policy object using a
510
* Reader object.
511
*/
512
private boolean init(URL policy, PolicyInfo newInfo) {
513
514
// skip parsing policy file if it has been previously parsed and
515
// has syntax errors
516
if (badPolicyURLs.contains(policy)) {
517
if (debug != null) {
518
debug.println("skipping bad policy file: " + policy);
519
}
520
return false;
521
}
522
523
try (InputStreamReader isr =
524
getInputStreamReader(PolicyUtil.getInputStream(policy))) {
525
526
PolicyParser pp = new PolicyParser(expandProperties);
527
pp.read(isr);
528
529
KeyStore keyStore = null;
530
try {
531
keyStore = PolicyUtil.getKeyStore
532
(policy,
533
pp.getKeyStoreUrl(),
534
pp.getKeyStoreType(),
535
pp.getKeyStoreProvider(),
536
pp.getStorePassURL(),
537
debug);
538
} catch (Exception e) {
539
// ignore, treat it like we have no keystore
540
if (debug != null) {
541
debug.println("Debug info only. Ignoring exception.");
542
e.printStackTrace();
543
}
544
}
545
546
Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();
547
while (enum_.hasMoreElements()) {
548
PolicyParser.GrantEntry ge = enum_.nextElement();
549
addGrantEntry(ge, keyStore, newInfo);
550
}
551
return true;
552
} catch (PolicyParser.ParsingException pe) {
553
// record bad policy file to avoid later reparsing it
554
badPolicyURLs.add(policy);
555
Object[] source = {policy, pe.getNonlocalizedMessage()};
556
System.err.println(LocalizedMessage.getNonlocalized
557
(POLICY + ".error.parsing.policy.message", source));
558
if (debug != null) {
559
pe.printStackTrace();
560
}
561
} catch (Exception e) {
562
if (debug != null) {
563
debug.println("error parsing "+policy);
564
debug.println(e.toString());
565
e.printStackTrace();
566
}
567
}
568
569
return false;
570
}
571
572
private InputStreamReader getInputStreamReader(InputStream is) {
573
/*
574
* Read in policy using UTF-8 by default.
575
*
576
* Check non-standard system property to see if the default encoding
577
* should be used instead.
578
*/
579
return (notUtf8)
580
? new InputStreamReader(is)
581
: new InputStreamReader(is, UTF_8);
582
}
583
584
private void initStaticPolicy(final PolicyInfo newInfo) {
585
if (debug != null) {
586
debug.println("Initializing with static permissions");
587
}
588
AccessController.doPrivileged(new PrivilegedAction<>() {
589
@Override
590
public Void run() {
591
PolicyEntry pe = new PolicyEntry(new CodeSource(null,
592
(Certificate[]) null));
593
pe.add(SecurityConstants.LOCAL_LISTEN_PERMISSION);
594
pe.add(new PropertyPermission("java.version",
595
SecurityConstants.PROPERTY_READ_ACTION));
596
pe.add(new PropertyPermission("java.vendor",
597
SecurityConstants.PROPERTY_READ_ACTION));
598
pe.add(new PropertyPermission("java.vendor.url",
599
SecurityConstants.PROPERTY_READ_ACTION));
600
pe.add(new PropertyPermission("java.class.version",
601
SecurityConstants.PROPERTY_READ_ACTION));
602
pe.add(new PropertyPermission("os.name",
603
SecurityConstants.PROPERTY_READ_ACTION));
604
pe.add(new PropertyPermission("os.version",
605
SecurityConstants.PROPERTY_READ_ACTION));
606
pe.add(new PropertyPermission("os.arch",
607
SecurityConstants.PROPERTY_READ_ACTION));
608
pe.add(new PropertyPermission("file.separator",
609
SecurityConstants.PROPERTY_READ_ACTION));
610
pe.add(new PropertyPermission("path.separator",
611
SecurityConstants.PROPERTY_READ_ACTION));
612
pe.add(new PropertyPermission("line.separator",
613
SecurityConstants.PROPERTY_READ_ACTION));
614
pe.add(new PropertyPermission
615
("java.specification.version",
616
SecurityConstants.PROPERTY_READ_ACTION));
617
pe.add(new PropertyPermission
618
("java.specification.vendor",
619
SecurityConstants.PROPERTY_READ_ACTION));
620
pe.add(new PropertyPermission
621
("java.specification.name",
622
SecurityConstants.PROPERTY_READ_ACTION));
623
pe.add(new PropertyPermission
624
("java.vm.specification.version",
625
SecurityConstants.PROPERTY_READ_ACTION));
626
pe.add(new PropertyPermission
627
("java.vm.specification.vendor",
628
SecurityConstants.PROPERTY_READ_ACTION));
629
pe.add(new PropertyPermission
630
("java.vm.specification.name",
631
SecurityConstants.PROPERTY_READ_ACTION));
632
pe.add(new PropertyPermission("java.vm.version",
633
SecurityConstants.PROPERTY_READ_ACTION));
634
pe.add(new PropertyPermission("java.vm.vendor",
635
SecurityConstants.PROPERTY_READ_ACTION));
636
pe.add(new PropertyPermission("java.vm.name",
637
SecurityConstants.PROPERTY_READ_ACTION));
638
639
// No need to sync because noone has access to newInfo yet
640
newInfo.policyEntries.add(pe);
641
642
return null;
643
}
644
});
645
}
646
647
/**
648
* Given a GrantEntry, create a codeSource.
649
*
650
* @return null if signedBy alias is not recognized
651
*/
652
private CodeSource getCodeSource(PolicyParser.GrantEntry ge, KeyStore keyStore,
653
PolicyInfo newInfo) throws java.net.MalformedURLException
654
{
655
Certificate[] certs = null;
656
if (ge.signedBy != null) {
657
certs = getCertificates(keyStore, ge.signedBy, newInfo);
658
if (certs == null) {
659
// we don't have a key for this alias,
660
// just return
661
if (debug != null) {
662
debug.println(" -- No certs for alias '" +
663
ge.signedBy + "' - ignoring entry");
664
}
665
return null;
666
}
667
}
668
669
URL location;
670
671
if (ge.codeBase != null)
672
location = new URL(ge.codeBase);
673
else
674
location = null;
675
676
return (canonicalizeCodebase(new CodeSource(location, certs),false));
677
}
678
679
/**
680
* Add one policy entry to the list.
681
*/
682
private void addGrantEntry(PolicyParser.GrantEntry ge,
683
KeyStore keyStore, PolicyInfo newInfo) {
684
685
if (debug != null) {
686
debug.println("Adding policy entry: ");
687
debug.println(" signedBy " + ge.signedBy);
688
debug.println(" codeBase " + ge.codeBase);
689
if (ge.principals != null) {
690
for (PolicyParser.PrincipalEntry pppe : ge.principals) {
691
debug.println(" " + pppe.toString());
692
}
693
}
694
}
695
696
try {
697
CodeSource codesource = getCodeSource(ge, keyStore, newInfo);
698
// skip if signedBy alias was unknown...
699
if (codesource == null) return;
700
701
// perform keystore alias principal replacement.
702
// for example, if alias resolves to X509 certificate,
703
// replace principal with: <X500Principal class> <SubjectDN>
704
// -- skip if alias is unknown
705
if (replacePrincipals(ge.principals, keyStore) == false)
706
return;
707
PolicyEntry entry = new PolicyEntry(codesource, ge.principals);
708
Enumeration<PolicyParser.PermissionEntry> enum_ =
709
ge.permissionElements();
710
while (enum_.hasMoreElements()) {
711
PolicyParser.PermissionEntry pe = enum_.nextElement();
712
713
try {
714
// perform ${{ ... }} expansions within permission name
715
expandPermissionName(pe, keyStore);
716
717
// XXX special case PrivateCredentialPermission-SELF
718
Permission perm;
719
if (pe.permission.equals
720
("javax.security.auth.PrivateCredentialPermission") &&
721
pe.name.endsWith(" self")) {
722
pe.name = pe.name.substring(0, pe.name.indexOf("self"))
723
+ SELF;
724
}
725
// check for self
726
if (pe.name != null && pe.name.indexOf(SELF) != -1) {
727
// Create a "SelfPermission" , it could be an
728
// an unresolved permission which will be resolved
729
// when implies is called
730
// Add it to entry
731
Certificate[] certs;
732
if (pe.signedBy != null) {
733
certs = getCertificates(keyStore,
734
pe.signedBy,
735
newInfo);
736
} else {
737
certs = null;
738
}
739
perm = new SelfPermission(pe.permission,
740
pe.name,
741
pe.action,
742
certs);
743
} else {
744
perm = getInstance(pe.permission,
745
pe.name,
746
pe.action);
747
}
748
entry.add(perm);
749
if (debug != null) {
750
debug.println(" "+perm);
751
}
752
} catch (ClassNotFoundException cnfe) {
753
Certificate[] certs;
754
if (pe.signedBy != null) {
755
certs = getCertificates(keyStore,
756
pe.signedBy,
757
newInfo);
758
} else {
759
certs = null;
760
}
761
762
// only add if we had no signer or we had
763
// a signer and found the keys for it.
764
if (certs != null || pe.signedBy == null) {
765
Permission perm = new UnresolvedPermission(
766
pe.permission,
767
pe.name,
768
pe.action,
769
certs);
770
entry.add(perm);
771
if (debug != null) {
772
debug.println(" "+perm);
773
}
774
}
775
} catch (java.lang.reflect.InvocationTargetException ite) {
776
Object[] source = {pe.permission,
777
ite.getCause().toString()};
778
System.err.println(
779
LocalizedMessage.getNonlocalized(
780
POLICY + ".error.adding.Permission.perm.message",
781
source));
782
} catch (Exception e) {
783
Object[] source = {pe.permission,
784
e.toString()};
785
System.err.println(
786
LocalizedMessage.getNonlocalized(
787
POLICY + ".error.adding.Permission.perm.message",
788
source));
789
}
790
}
791
792
// No need to sync because noone has access to newInfo yet
793
newInfo.policyEntries.add(entry);
794
} catch (Exception e) {
795
Object[] source = {e.toString()};
796
System.err.println(
797
LocalizedMessage.getNonlocalized(
798
POLICY + ".error.adding.Entry.message",
799
source));
800
}
801
if (debug != null)
802
debug.println();
803
}
804
805
/**
806
* Returns a new Permission object of the given Type. The Permission is
807
* created by getting the
808
* Class object using the <code>Class.forName</code> method, and using
809
* the reflection API to invoke the (String name, String actions)
810
* constructor on the
811
* object.
812
*
813
* @param type the type of Permission being created.
814
* @param name the name of the Permission being created.
815
* @param actions the actions of the Permission being created.
816
*
817
* @exception ClassNotFoundException if the particular Permission
818
* class could not be found.
819
*
820
* @exception IllegalAccessException if the class or initializer is
821
* not accessible.
822
*
823
* @exception InstantiationException if getInstance tries to
824
* instantiate an abstract class or an interface, or if the
825
* instantiation fails for some other reason.
826
*
827
* @exception NoSuchMethodException if the (String, String) constructor
828
* is not found.
829
*
830
* @exception InvocationTargetException if the underlying Permission
831
* constructor throws an exception.
832
*
833
*/
834
835
private static final Permission getInstance(String type,
836
String name,
837
String actions)
838
throws ClassNotFoundException,
839
InstantiationException,
840
IllegalAccessException,
841
NoSuchMethodException,
842
InvocationTargetException
843
{
844
Class<?> pc = Class.forName(type, false, null);
845
Permission answer = getKnownPermission(pc, name, actions);
846
if (answer != null) {
847
return answer;
848
}
849
if (!Permission.class.isAssignableFrom(pc)) {
850
// not the right subtype
851
throw new ClassCastException(type + " is not a Permission");
852
}
853
854
if (name == null && actions == null) {
855
try {
856
Constructor<?> c = pc.getConstructor(PARAMS0);
857
return (Permission) c.newInstance(new Object[] {});
858
} catch (NoSuchMethodException ne) {
859
try {
860
Constructor<?> c = pc.getConstructor(PARAMS1);
861
return (Permission) c.newInstance(
862
new Object[] { name});
863
} catch (NoSuchMethodException ne1 ) {
864
Constructor<?> c = pc.getConstructor(PARAMS2);
865
return (Permission) c.newInstance(
866
new Object[] { name, actions });
867
}
868
}
869
} else {
870
if (name != null && actions == null) {
871
try {
872
Constructor<?> c = pc.getConstructor(PARAMS1);
873
return (Permission) c.newInstance(new Object[] { name});
874
} catch (NoSuchMethodException ne) {
875
Constructor<?> c = pc.getConstructor(PARAMS2);
876
return (Permission) c.newInstance(
877
new Object[] { name, actions });
878
}
879
} else {
880
Constructor<?> c = pc.getConstructor(PARAMS2);
881
return (Permission) c.newInstance(
882
new Object[] { name, actions });
883
}
884
}
885
}
886
887
/**
888
* Creates one of the well-known permissions in the java.base module
889
* directly instead of via reflection. Keep list short to not penalize
890
* permissions from other modules.
891
*/
892
private static Permission getKnownPermission(Class<?> claz, String name,
893
String actions) {
894
if (claz.equals(FilePermission.class)) {
895
return new FilePermission(name, actions);
896
} else if (claz.equals(SocketPermission.class)) {
897
return new SocketPermission(name, actions);
898
} else if (claz.equals(RuntimePermission.class)) {
899
return new RuntimePermission(name, actions);
900
} else if (claz.equals(PropertyPermission.class)) {
901
return new PropertyPermission(name, actions);
902
} else if (claz.equals(NetPermission.class)) {
903
return new NetPermission(name, actions);
904
} else if (claz.equals(AllPermission.class)) {
905
return SecurityConstants.ALL_PERMISSION;
906
} else if (claz.equals(SecurityPermission.class)) {
907
return new SecurityPermission(name, actions);
908
} else {
909
return null;
910
}
911
}
912
913
/**
914
* Creates one of the well-known principals in the java.base module
915
* directly instead of via reflection. Keep list short to not penalize
916
* principals from other modules.
917
*/
918
private static Principal getKnownPrincipal(Class<?> claz, String name) {
919
if (claz.equals(X500Principal.class)) {
920
return new X500Principal(name);
921
} else {
922
return null;
923
}
924
}
925
926
/**
927
* Fetch all certs associated with this alias.
928
*/
929
private Certificate[] getCertificates
930
(KeyStore keyStore, String aliases, PolicyInfo newInfo) {
931
932
List<Certificate> vcerts = null;
933
934
StringTokenizer st = new StringTokenizer(aliases, ",");
935
int n = 0;
936
937
while (st.hasMoreTokens()) {
938
String alias = st.nextToken().trim();
939
n++;
940
Certificate cert = null;
941
// See if this alias's cert has already been cached
942
synchronized (newInfo.aliasMapping) {
943
cert = (Certificate)newInfo.aliasMapping.get(alias);
944
945
if (cert == null && keyStore != null) {
946
947
try {
948
cert = keyStore.getCertificate(alias);
949
} catch (KeyStoreException kse) {
950
// never happens, because keystore has already been loaded
951
// when we call this
952
}
953
if (cert != null) {
954
newInfo.aliasMapping.put(alias, cert);
955
newInfo.aliasMapping.put(cert, alias);
956
}
957
}
958
}
959
960
if (cert != null) {
961
if (vcerts == null)
962
vcerts = new ArrayList<>();
963
vcerts.add(cert);
964
}
965
}
966
967
// make sure n == vcerts.size, since we are doing a logical *and*
968
if (vcerts != null && n == vcerts.size()) {
969
Certificate[] certs = new Certificate[vcerts.size()];
970
vcerts.toArray(certs);
971
return certs;
972
} else {
973
return null;
974
}
975
}
976
977
/**
978
* Refreshes the policy object by re-reading all the policy files.
979
*/
980
@Override public void refresh() {
981
init(url);
982
}
983
984
/**
985
* Evaluates the global policy for the permissions granted to
986
* the ProtectionDomain and tests whether the permission is
987
* granted.
988
*
989
* @param pd the ProtectionDomain to test
990
* @param p the Permission object to be tested for implication.
991
*
992
* @return true if "permission" is a proper subset of a permission
993
* granted to this ProtectionDomain.
994
*
995
* @see java.security.ProtectionDomain
996
*/
997
@Override
998
public boolean implies(ProtectionDomain pd, Permission p) {
999
ProtectionDomainCache pdMap = policyInfo.getPdMapping();
1000
PermissionCollection pc = pdMap.get(pd);
1001
1002
if (pc != null) {
1003
return pc.implies(p);
1004
}
1005
1006
pc = getPermissions(pd);
1007
if (pc == null) {
1008
return false;
1009
}
1010
1011
// cache mapping of protection domain to its PermissionCollection
1012
pdMap.put(pd, pc);
1013
return pc.implies(p);
1014
}
1015
1016
/**
1017
* Examines this <code>Policy</code> and returns the permissions granted
1018
* to the specified <code>ProtectionDomain</code>. This includes
1019
* the permissions currently associated with the domain as well
1020
* as the policy permissions granted to the domain's
1021
* CodeSource, ClassLoader, and Principals.
1022
*
1023
* <p> Note that this <code>Policy</code> implementation has
1024
* special handling for PrivateCredentialPermissions.
1025
* When this method encounters a <code>PrivateCredentialPermission</code>
1026
* which specifies "self" as the <code>Principal</code> class and name,
1027
* it does not add that <code>Permission</code> to the returned
1028
* <code>PermissionCollection</code>. Instead, it builds
1029
* a new <code>PrivateCredentialPermission</code>
1030
* for each <code>Principal</code> associated with the provided
1031
* <code>Subject</code>. Each new <code>PrivateCredentialPermission</code>
1032
* contains the same Credential class as specified in the
1033
* originally granted permission, as well as the Class and name
1034
* for the respective <code>Principal</code>.
1035
*
1036
* @param domain the Permissions granted to this
1037
* <code>ProtectionDomain</code> are returned.
1038
*
1039
* @return the Permissions granted to the provided
1040
* <code>ProtectionDomain</code>.
1041
*/
1042
@Override
1043
public PermissionCollection getPermissions(ProtectionDomain domain) {
1044
Permissions perms = new Permissions();
1045
1046
if (domain == null)
1047
return perms;
1048
1049
// first get policy perms
1050
getPermissions(perms, domain);
1051
1052
// add static perms
1053
// - adding static perms after policy perms is necessary
1054
// to avoid a regression for 4301064
1055
PermissionCollection pc = domain.getPermissions();
1056
if (pc != null) {
1057
synchronized (pc) {
1058
Enumeration<Permission> e = pc.elements();
1059
while (e.hasMoreElements()) {
1060
perms.add(FilePermCompat.newPermPlusAltPath(e.nextElement()));
1061
}
1062
}
1063
}
1064
1065
return perms;
1066
}
1067
1068
/**
1069
* Examines this Policy and creates a PermissionCollection object with
1070
* the set of permissions for the specified CodeSource.
1071
*
1072
* @param codesource the CodeSource associated with the caller.
1073
* This encapsulates the original location of the code (where the code
1074
* came from) and the public key(s) of its signer.
1075
*
1076
* @return the set of permissions according to the policy.
1077
*/
1078
@Override
1079
public PermissionCollection getPermissions(CodeSource codesource) {
1080
return getPermissions(new Permissions(), codesource);
1081
}
1082
1083
/**
1084
* Examines the global policy and returns the provided Permissions
1085
* object with additional permissions granted to the specified
1086
* ProtectionDomain.
1087
*
1088
* @param perms the Permissions to populate
1089
* @param pd the ProtectionDomain associated with the caller.
1090
*
1091
* @return the set of Permissions according to the policy.
1092
*/
1093
private PermissionCollection getPermissions(Permissions perms,
1094
ProtectionDomain pd ) {
1095
if (debug != null) {
1096
debug.println("getPermissions:\n\t" + printPD(pd));
1097
}
1098
1099
final CodeSource cs = pd.getCodeSource();
1100
if (cs == null)
1101
return perms;
1102
1103
CodeSource canonCodeSource = AccessController.doPrivileged(
1104
new java.security.PrivilegedAction<>(){
1105
@Override
1106
public CodeSource run() {
1107
return canonicalizeCodebase(cs, true);
1108
}
1109
});
1110
return getPermissions(perms, canonCodeSource, pd.getPrincipals());
1111
}
1112
1113
/**
1114
* Examines the global policy and returns the provided Permissions
1115
* object with additional permissions granted to the specified
1116
* CodeSource.
1117
*
1118
* @param perms the permissions to populate
1119
* @param cs the codesource associated with the caller.
1120
* This encapsulates the original location of the code (where the code
1121
* came from) and the public key(s) of its signer.
1122
*
1123
* @return the set of permissions according to the policy.
1124
*/
1125
private PermissionCollection getPermissions(Permissions perms,
1126
final CodeSource cs) {
1127
1128
if (cs == null)
1129
return perms;
1130
1131
CodeSource canonCodeSource = AccessController.doPrivileged(
1132
new PrivilegedAction<>(){
1133
@Override
1134
public CodeSource run() {
1135
return canonicalizeCodebase(cs, true);
1136
}
1137
});
1138
1139
return getPermissions(perms, canonCodeSource, null);
1140
}
1141
1142
private Permissions getPermissions(Permissions perms,
1143
final CodeSource cs,
1144
Principal[] principals) {
1145
for (PolicyEntry entry : policyInfo.policyEntries) {
1146
addPermissions(perms, cs, principals, entry);
1147
}
1148
1149
return perms;
1150
}
1151
1152
private void addPermissions(Permissions perms,
1153
final CodeSource cs,
1154
Principal[] principals,
1155
final PolicyEntry entry) {
1156
1157
if (debug != null) {
1158
debug.println("evaluate codesources:\n" +
1159
"\tPolicy CodeSource: " + entry.getCodeSource() + "\n" +
1160
"\tActive CodeSource: " + cs);
1161
}
1162
1163
// check to see if the CodeSource implies
1164
Boolean imp = AccessController.doPrivileged
1165
(new PrivilegedAction<>() {
1166
@Override
1167
public Boolean run() {
1168
return entry.getCodeSource().implies(cs);
1169
}
1170
});
1171
if (!imp.booleanValue()) {
1172
if (debug != null) {
1173
debug.println("evaluation (codesource) failed");
1174
}
1175
1176
// CodeSource does not imply - return and try next policy entry
1177
return;
1178
}
1179
1180
// check to see if the Principals imply
1181
1182
List<PolicyParser.PrincipalEntry> entryPs = entry.getPrincipals();
1183
if (debug != null) {
1184
List<PolicyParser.PrincipalEntry> accPs = new ArrayList<>();
1185
if (principals != null) {
1186
for (int i = 0; i < principals.length; i++) {
1187
accPs.add(new PolicyParser.PrincipalEntry
1188
(principals[i].getClass().getName(),
1189
principals[i].getName()));
1190
}
1191
}
1192
debug.println("evaluate principals:\n" +
1193
"\tPolicy Principals: " + entryPs + "\n" +
1194
"\tActive Principals: " + accPs);
1195
}
1196
1197
if (entryPs == null || entryPs.isEmpty()) {
1198
1199
// policy entry has no principals -
1200
// add perms regardless of principals in current ACC
1201
1202
addPerms(perms, principals, entry);
1203
if (debug != null) {
1204
debug.println("evaluation (codesource/principals) passed");
1205
}
1206
return;
1207
1208
} else if (principals == null || principals.length == 0) {
1209
1210
// current thread has no principals but this policy entry
1211
// has principals - perms are not added
1212
1213
if (debug != null) {
1214
debug.println("evaluation (principals) failed");
1215
}
1216
return;
1217
}
1218
1219
// current thread has principals and this policy entry
1220
// has principals. see if policy entry principals match
1221
// principals in current ACC
1222
1223
for (PolicyParser.PrincipalEntry pppe : entryPs) {
1224
1225
// Check for wildcards
1226
if (pppe.isWildcardClass()) {
1227
// a wildcard class matches all principals in current ACC
1228
continue;
1229
}
1230
1231
if (pppe.isWildcardName()) {
1232
// a wildcard name matches any principal with the same class
1233
if (wildcardPrincipalNameImplies(pppe.principalClass,
1234
principals)) {
1235
continue;
1236
}
1237
if (debug != null) {
1238
debug.println("evaluation (principal name wildcard) failed");
1239
}
1240
// policy entry principal not in current ACC -
1241
// immediately return and go to next policy entry
1242
return;
1243
}
1244
1245
Set<Principal> pSet = new HashSet<>(Arrays.asList(principals));
1246
Subject subject = new Subject(true, pSet,
1247
Collections.EMPTY_SET,
1248
Collections.EMPTY_SET);
1249
try {
1250
ClassLoader cl = Thread.currentThread().getContextClassLoader();
1251
Class<?> pClass = Class.forName(pppe.principalClass, false, cl);
1252
Principal p = getKnownPrincipal(pClass, pppe.principalName);
1253
if (p == null) {
1254
if (!Principal.class.isAssignableFrom(pClass)) {
1255
// not the right subtype
1256
throw new ClassCastException(pppe.principalClass +
1257
" is not a Principal");
1258
}
1259
1260
Constructor<?> c = pClass.getConstructor(PARAMS1);
1261
p = (Principal)c.newInstance(new Object[] {
1262
pppe.principalName });
1263
1264
}
1265
1266
if (debug != null) {
1267
debug.println("found Principal " + p.getClass().getName());
1268
}
1269
1270
// check if the Principal implies the current
1271
// thread's principals
1272
if (!p.implies(subject)) {
1273
if (debug != null) {
1274
debug.println("evaluation (principal implies) failed");
1275
}
1276
1277
// policy principal does not imply the current Subject -
1278
// immediately return and go to next policy entry
1279
return;
1280
}
1281
} catch (Exception e) {
1282
// fall back to default principal comparison.
1283
// see if policy entry principal is in current ACC
1284
1285
if (debug != null) {
1286
e.printStackTrace();
1287
}
1288
1289
if (!pppe.implies(subject)) {
1290
if (debug != null) {
1291
debug.println("evaluation (default principal implies) failed");
1292
}
1293
1294
// policy entry principal not in current ACC -
1295
// immediately return and go to next policy entry
1296
return;
1297
}
1298
}
1299
1300
// either the principal information matched,
1301
// or the Principal.implies succeeded.
1302
// continue loop and test the next policy principal
1303
}
1304
1305
// all policy entry principals were found in the current ACC -
1306
// grant the policy permissions
1307
1308
if (debug != null) {
1309
debug.println("evaluation (codesource/principals) passed");
1310
}
1311
addPerms(perms, principals, entry);
1312
}
1313
1314
/**
1315
* Returns true if the array of principals contains at least one
1316
* principal of the specified class.
1317
*/
1318
private static boolean wildcardPrincipalNameImplies(String principalClass,
1319
Principal[] principals)
1320
{
1321
for (Principal p : principals) {
1322
if (principalClass.equals(p.getClass().getName())) {
1323
return true;
1324
}
1325
}
1326
return false;
1327
}
1328
1329
private void addPerms(Permissions perms,
1330
Principal[] accPs,
1331
PolicyEntry entry) {
1332
for (int i = 0; i < entry.permissions.size(); i++) {
1333
Permission p = entry.permissions.get(i);
1334
if (debug != null) {
1335
debug.println(" granting " + p);
1336
}
1337
1338
if (p instanceof SelfPermission) {
1339
// handle "SELF" permissions
1340
expandSelf((SelfPermission)p,
1341
entry.getPrincipals(),
1342
accPs,
1343
perms);
1344
} else {
1345
perms.add(FilePermCompat.newPermPlusAltPath(p));
1346
}
1347
}
1348
}
1349
1350
/**
1351
* @param sp the SelfPermission that needs to be expanded.
1352
*
1353
* @param entryPs list of principals for the Policy entry.
1354
*
1355
* @param pdp Principal array from the current ProtectionDomain.
1356
*
1357
* @param perms the PermissionCollection where the individual
1358
* Permissions will be added after expansion.
1359
*/
1360
1361
private void expandSelf(SelfPermission sp,
1362
List<PolicyParser.PrincipalEntry> entryPs,
1363
Principal[] pdp,
1364
Permissions perms) {
1365
1366
if (entryPs == null || entryPs.isEmpty()) {
1367
// No principals in the grant to substitute
1368
if (debug != null) {
1369
debug.println("Ignoring permission "
1370
+ sp.getSelfType()
1371
+ " with target name ("
1372
+ sp.getSelfName() + "). "
1373
+ "No Principal(s) specified "
1374
+ "in the grant clause. "
1375
+ "SELF-based target names are "
1376
+ "only valid in the context "
1377
+ "of a Principal-based grant entry."
1378
);
1379
}
1380
return;
1381
}
1382
int startIndex = 0;
1383
int v;
1384
StringBuilder sb = new StringBuilder();
1385
while ((v = sp.getSelfName().indexOf(SELF, startIndex)) != -1) {
1386
1387
// add non-SELF string
1388
sb.append(sp.getSelfName().substring(startIndex, v));
1389
1390
// expand SELF
1391
Iterator<PolicyParser.PrincipalEntry> pli = entryPs.iterator();
1392
while (pli.hasNext()) {
1393
PolicyParser.PrincipalEntry pppe = pli.next();
1394
String[][] principalInfo = getPrincipalInfo(pppe,pdp);
1395
for (int i = 0; i < principalInfo.length; i++) {
1396
if (i != 0) {
1397
sb.append(", ");
1398
}
1399
sb.append(principalInfo[i][0] + " " +
1400
"\"" + principalInfo[i][1] + "\"");
1401
}
1402
if (pli.hasNext()) {
1403
sb.append(", ");
1404
}
1405
}
1406
startIndex = v + SELF.length();
1407
}
1408
// add remaining string (might be the entire string)
1409
sb.append(sp.getSelfName().substring(startIndex));
1410
1411
if (debug != null) {
1412
debug.println(" expanded:\n\t" + sp.getSelfName()
1413
+ "\n into:\n\t" + sb.toString());
1414
}
1415
try {
1416
// first try to instantiate the permission
1417
perms.add(FilePermCompat.newPermPlusAltPath(getInstance(sp.getSelfType(),
1418
sb.toString(),
1419
sp.getSelfActions())));
1420
} catch (ClassNotFoundException cnfe) {
1421
// ok, the permission is not in the bootclasspath.
1422
// before we add an UnresolvedPermission, check to see
1423
// whether this perm already belongs to the collection.
1424
// if so, use that perm's ClassLoader to create a new
1425
// one.
1426
Class<?> pc = null;
1427
synchronized (perms) {
1428
Enumeration<Permission> e = perms.elements();
1429
while (e.hasMoreElements()) {
1430
Permission pElement = e.nextElement();
1431
if (pElement.getClass().getName().equals(sp.getSelfType())) {
1432
pc = pElement.getClass();
1433
break;
1434
}
1435
}
1436
}
1437
if (pc == null) {
1438
// create an UnresolvedPermission
1439
perms.add(new UnresolvedPermission(sp.getSelfType(),
1440
sb.toString(),
1441
sp.getSelfActions(),
1442
sp.getCerts()));
1443
} else {
1444
try {
1445
// we found an instantiated permission.
1446
// use its class loader to instantiate a new permission.
1447
Constructor<?> c;
1448
// name parameter can not be null
1449
if (sp.getSelfActions() == null) {
1450
try {
1451
c = pc.getConstructor(PARAMS1);
1452
perms.add((Permission)c.newInstance
1453
(new Object[] {sb.toString()}));
1454
} catch (NoSuchMethodException ne) {
1455
c = pc.getConstructor(PARAMS2);
1456
perms.add((Permission)c.newInstance
1457
(new Object[] {sb.toString(),
1458
sp.getSelfActions() }));
1459
}
1460
} else {
1461
c = pc.getConstructor(PARAMS2);
1462
perms.add((Permission)c.newInstance
1463
(new Object[] {sb.toString(),
1464
sp.getSelfActions()}));
1465
}
1466
} catch (Exception nme) {
1467
if (debug != null) {
1468
debug.println("self entry expansion " +
1469
" instantiation failed: "
1470
+ nme.toString());
1471
}
1472
}
1473
}
1474
} catch (Exception e) {
1475
if (debug != null) {
1476
debug.println(e.toString());
1477
}
1478
}
1479
}
1480
1481
/**
1482
* return the principal class/name pair in the 2D array.
1483
* array[x][y]: x corresponds to the array length.
1484
* if (y == 0), it's the principal class.
1485
* if (y == 1), it's the principal name.
1486
*/
1487
private String[][] getPrincipalInfo
1488
(PolicyParser.PrincipalEntry pe, Principal[] pdp) {
1489
1490
// there are 3 possibilities:
1491
// 1) the entry's Principal class and name are not wildcarded
1492
// 2) the entry's Principal name is wildcarded only
1493
// 3) the entry's Principal class and name are wildcarded
1494
1495
if (!pe.isWildcardClass() && !pe.isWildcardName()) {
1496
1497
// build an info array for the principal
1498
// from the Policy entry
1499
String[][] info = new String[1][2];
1500
info[0][0] = pe.principalClass;
1501
info[0][1] = pe.principalName;
1502
return info;
1503
1504
} else if (!pe.isWildcardClass() && pe.isWildcardName()) {
1505
1506
// build an info array for every principal
1507
// in the current domain which has a principal class
1508
// that is equal to policy entry principal class name
1509
List<Principal> plist = new ArrayList<>();
1510
for (int i = 0; i < pdp.length; i++) {
1511
if (pe.principalClass.equals(pdp[i].getClass().getName()))
1512
plist.add(pdp[i]);
1513
}
1514
String[][] info = new String[plist.size()][2];
1515
int i = 0;
1516
for (Principal p : plist) {
1517
info[i][0] = p.getClass().getName();
1518
info[i][1] = p.getName();
1519
i++;
1520
}
1521
return info;
1522
1523
} else {
1524
1525
// build an info array for every
1526
// one of the current Domain's principals
1527
1528
String[][] info = new String[pdp.length][2];
1529
1530
for (int i = 0; i < pdp.length; i++) {
1531
info[i][0] = pdp[i].getClass().getName();
1532
info[i][1] = pdp[i].getName();
1533
}
1534
return info;
1535
}
1536
}
1537
1538
/*
1539
* Returns the signer certificates from the list of certificates
1540
* associated with the given code source.
1541
*
1542
* The signer certificates are those certificates that were used
1543
* to verify signed code originating from the codesource location.
1544
*
1545
* This method assumes that in the given code source, each signer
1546
* certificate is followed by its supporting certificate chain
1547
* (which may be empty), and that the signer certificate and its
1548
* supporting certificate chain are ordered bottom-to-top
1549
* (i.e., with the signer certificate first and the (root) certificate
1550
* authority last).
1551
*/
1552
protected Certificate[] getSignerCertificates(CodeSource cs) {
1553
Certificate[] certs = null;
1554
if ((certs = cs.getCertificates()) == null)
1555
return null;
1556
for (int i=0; i<certs.length; i++) {
1557
if (!(certs[i] instanceof X509Certificate))
1558
return cs.getCertificates();
1559
}
1560
1561
// Do we have to do anything?
1562
int i = 0;
1563
int count = 0;
1564
while (i < certs.length) {
1565
count++;
1566
while (((i+1) < certs.length)
1567
&& ((X509Certificate)certs[i]).getIssuerX500Principal().equals(
1568
((X509Certificate)certs[i+1]).getSubjectX500Principal())) {
1569
i++;
1570
}
1571
i++;
1572
}
1573
if (count == certs.length)
1574
// Done
1575
return certs;
1576
1577
List<Certificate> userCertList = new ArrayList<>();
1578
i = 0;
1579
while (i < certs.length) {
1580
userCertList.add(certs[i]);
1581
while (((i+1) < certs.length)
1582
&& ((X509Certificate)certs[i]).getIssuerX500Principal().equals(
1583
((X509Certificate)certs[i+1]).getSubjectX500Principal())) {
1584
i++;
1585
}
1586
i++;
1587
}
1588
Certificate[] userCerts = new Certificate[userCertList.size()];
1589
userCertList.toArray(userCerts);
1590
return userCerts;
1591
}
1592
1593
private CodeSource canonicalizeCodebase(CodeSource cs,
1594
boolean extractSignerCerts) {
1595
1596
String path = null;
1597
1598
CodeSource canonCs = cs;
1599
URL u = cs.getLocation();
1600
if (u != null) {
1601
if (u.getProtocol().equals("jar")) {
1602
// unwrap url embedded inside jar url
1603
String spec = u.getFile();
1604
int separator = spec.indexOf("!/");
1605
if (separator != -1) {
1606
try {
1607
u = new URL(spec.substring(0, separator));
1608
} catch (MalformedURLException e) {
1609
// Fail silently. In this case, url stays what
1610
// it was above
1611
}
1612
}
1613
}
1614
if (u.getProtocol().equals("file")) {
1615
boolean isLocalFile = false;
1616
String host = u.getHost();
1617
isLocalFile = (host == null || host.isEmpty() ||
1618
host.equals("~") || host.equalsIgnoreCase("localhost"));
1619
1620
if (isLocalFile) {
1621
path = u.getFile().replace('/', File.separatorChar);
1622
path = ParseUtil.decode(path);
1623
}
1624
}
1625
}
1626
1627
if (path != null) {
1628
try {
1629
URL csUrl = null;
1630
path = canonPath(path);
1631
csUrl = ParseUtil.fileToEncodedURL(new File(path));
1632
1633
if (extractSignerCerts) {
1634
canonCs = new CodeSource(csUrl,
1635
getSignerCertificates(cs));
1636
} else {
1637
canonCs = new CodeSource(csUrl,
1638
cs.getCertificates());
1639
}
1640
} catch (IOException ioe) {
1641
// leave codesource as it is, unless we have to extract its
1642
// signer certificates
1643
if (extractSignerCerts) {
1644
canonCs = new CodeSource(cs.getLocation(),
1645
getSignerCertificates(cs));
1646
}
1647
}
1648
} else {
1649
if (extractSignerCerts) {
1650
canonCs = new CodeSource(cs.getLocation(),
1651
getSignerCertificates(cs));
1652
}
1653
}
1654
return canonCs;
1655
}
1656
1657
// Wrapper to return a canonical path that avoids calling getCanonicalPath()
1658
// with paths that are intended to match all entries in the directory
1659
private static String canonPath(String path) throws IOException {
1660
if (path.endsWith("*")) {
1661
path = path.substring(0, path.length()-1) + "-";
1662
path = new File(path).getCanonicalPath();
1663
return path.substring(0, path.length()-1) + "*";
1664
} else {
1665
return new File(path).getCanonicalPath();
1666
}
1667
}
1668
1669
private String printPD(ProtectionDomain pd) {
1670
Principal[] principals = pd.getPrincipals();
1671
String pals = "<no principals>";
1672
if (principals != null && principals.length > 0) {
1673
StringBuilder palBuf = new StringBuilder("(principals ");
1674
for (int i = 0; i < principals.length; i++) {
1675
palBuf.append(principals[i].getClass().getName() +
1676
" \"" + principals[i].getName() +
1677
"\"");
1678
if (i < principals.length-1)
1679
palBuf.append(", ");
1680
else
1681
palBuf.append(")");
1682
}
1683
pals = palBuf.toString();
1684
}
1685
return "PD CodeSource: "
1686
+ pd.getCodeSource()
1687
+"\n\t" + "PD ClassLoader: "
1688
+ pd.getClassLoader()
1689
+"\n\t" + "PD Principals: "
1690
+ pals;
1691
}
1692
1693
/**
1694
* return true if no replacement was performed,
1695
* or if replacement succeeded.
1696
*/
1697
private boolean replacePrincipals(
1698
List<PolicyParser.PrincipalEntry> principals, KeyStore keystore) {
1699
1700
if (principals == null || principals.isEmpty() || keystore == null)
1701
return true;
1702
1703
for (PolicyParser.PrincipalEntry pppe : principals) {
1704
if (pppe.isReplaceName()) {
1705
1706
// perform replacement
1707
// (only X509 replacement is possible now)
1708
String name;
1709
if ((name = getDN(pppe.principalName, keystore)) == null) {
1710
return false;
1711
}
1712
1713
if (debug != null) {
1714
debug.println(" Replacing \"" +
1715
pppe.principalName +
1716
"\" with " +
1717
X500PRINCIPAL + "/\"" +
1718
name +
1719
"\"");
1720
}
1721
1722
pppe.principalClass = X500PRINCIPAL;
1723
pppe.principalName = name;
1724
}
1725
}
1726
// return true if no replacement was performed,
1727
// or if replacement succeeded
1728
return true;
1729
}
1730
1731
private void expandPermissionName(PolicyParser.PermissionEntry pe,
1732
KeyStore keystore) throws Exception {
1733
// short cut the common case
1734
if (pe.name == null || pe.name.indexOf("${{", 0) == -1) {
1735
return;
1736
}
1737
1738
int startIndex = 0;
1739
int b, e;
1740
StringBuilder sb = new StringBuilder();
1741
while ((b = pe.name.indexOf("${{", startIndex)) != -1) {
1742
e = pe.name.indexOf("}}", b);
1743
if (e < 1) {
1744
break;
1745
}
1746
sb.append(pe.name.substring(startIndex, b));
1747
1748
// get the value in ${{...}}
1749
String value = pe.name.substring(b+3, e);
1750
1751
// parse up to the first ':'
1752
int colonIndex;
1753
String prefix = value;
1754
String suffix;
1755
if ((colonIndex = value.indexOf(':')) != -1) {
1756
prefix = value.substring(0, colonIndex);
1757
}
1758
1759
// handle different prefix possibilities
1760
if (prefix.equalsIgnoreCase("self")) {
1761
// do nothing - handled later
1762
sb.append(pe.name.substring(b, e+2));
1763
startIndex = e+2;
1764
continue;
1765
} else if (prefix.equalsIgnoreCase("alias")) {
1766
// get the suffix and perform keystore alias replacement
1767
if (colonIndex == -1) {
1768
Object[] source = {pe.name};
1769
throw new Exception(
1770
LocalizedMessage.getNonlocalized(
1771
"alias.name.not.provided.pe.name.",
1772
source));
1773
}
1774
suffix = value.substring(colonIndex+1);
1775
if ((suffix = getDN(suffix, keystore)) == null) {
1776
Object[] source = {value.substring(colonIndex+1)};
1777
throw new Exception(
1778
LocalizedMessage.getNonlocalized(
1779
"unable.to.perform.substitution.on.alias.suffix",
1780
source));
1781
}
1782
1783
sb.append(X500PRINCIPAL + " \"" + suffix + "\"");
1784
startIndex = e+2;
1785
} else {
1786
Object[] source = {prefix};
1787
throw new Exception(
1788
LocalizedMessage.getNonlocalized(
1789
"substitution.value.prefix.unsupported",
1790
source));
1791
}
1792
}
1793
1794
// copy the rest of the value
1795
sb.append(pe.name.substring(startIndex));
1796
1797
// replace the name with expanded value
1798
if (debug != null) {
1799
debug.println(" Permission name expanded from:\n\t" +
1800
pe.name + "\nto\n\t" + sb.toString());
1801
}
1802
pe.name = sb.toString();
1803
}
1804
1805
private String getDN(String alias, KeyStore keystore) {
1806
Certificate cert = null;
1807
try {
1808
cert = keystore.getCertificate(alias);
1809
} catch (Exception e) {
1810
if (debug != null) {
1811
debug.println(" Error retrieving certificate for '" +
1812
alias +
1813
"': " +
1814
e.toString());
1815
}
1816
return null;
1817
}
1818
1819
if (cert == null || !(cert instanceof X509Certificate)) {
1820
if (debug != null) {
1821
debug.println(" -- No certificate for '" +
1822
alias +
1823
"' - ignoring entry");
1824
}
1825
return null;
1826
} else {
1827
X509Certificate x509Cert = (X509Certificate)cert;
1828
1829
// 4702543: X500 names with an EmailAddress
1830
// were encoded incorrectly. create new
1831
// X500Principal name with correct encoding
1832
1833
X500Principal p = new X500Principal
1834
(x509Cert.getSubjectX500Principal().toString());
1835
return p.getName();
1836
}
1837
}
1838
1839
/**
1840
* Each entry in the policy configuration file is represented by a
1841
* PolicyEntry object. <p>
1842
*
1843
* A PolicyEntry is a (CodeSource,Permission) pair. The
1844
* CodeSource contains the (URL, PublicKey) that together identify
1845
* where the Java bytecodes come from and who (if anyone) signed
1846
* them. The URL could refer to localhost. The URL could also be
1847
* null, meaning that this policy entry is given to all comers, as
1848
* long as they match the signer field. The signer could be null,
1849
* meaning the code is not signed. <p>
1850
*
1851
* The Permission contains the (Type, Name, Action) triplet. <p>
1852
*
1853
* For now, the Policy object retrieves the public key from the
1854
* X.509 certificate on disk that corresponds to the signedBy
1855
* alias specified in the Policy config file. For reasons of
1856
* efficiency, the Policy object keeps a hashtable of certs already
1857
* read in. This could be replaced by a secure internal key
1858
* store.
1859
*
1860
* <p>
1861
* For example, the entry
1862
* <pre>
1863
* permission java.io.File "/tmp", "read,write",
1864
* signedBy "Duke";
1865
* </pre>
1866
* is represented internally
1867
* <pre>
1868
*
1869
* FilePermission f = new FilePermission("/tmp", "read,write");
1870
* PublicKey p = publickeys.get("Duke");
1871
* URL u = InetAddress.getLocalHost();
1872
* CodeBase c = new CodeBase( p, u );
1873
* pe = new PolicyEntry(f, c);
1874
* </pre>
1875
*
1876
* @author Marianne Mueller
1877
* @author Roland Schemers
1878
* @see java.security.CodeSource
1879
* @see java.security.Policy
1880
* @see java.security.Permissions
1881
* @see java.security.ProtectionDomain
1882
*/
1883
private static class PolicyEntry {
1884
1885
private final CodeSource codesource;
1886
final List<Permission> permissions;
1887
private final List<PolicyParser.PrincipalEntry> principals;
1888
1889
/**
1890
* Given a Permission and a CodeSource, create a policy entry.
1891
*
1892
* XXX Decide if/how to add validity fields and "purpose" fields to
1893
* XXX policy entries
1894
*
1895
* @param cs the CodeSource, which encapsulates the URL and the
1896
* public key
1897
* attributes from the policy config file. Validity checks
1898
* are performed on the public key before PolicyEntry is
1899
* called.
1900
*
1901
*/
1902
PolicyEntry(CodeSource cs, List<PolicyParser.PrincipalEntry> principals)
1903
{
1904
this.codesource = cs;
1905
this.permissions = new ArrayList<Permission>();
1906
this.principals = principals; // can be null
1907
}
1908
1909
PolicyEntry(CodeSource cs)
1910
{
1911
this(cs, null);
1912
}
1913
1914
List<PolicyParser.PrincipalEntry> getPrincipals() {
1915
return principals; // can be null
1916
}
1917
1918
/**
1919
* add a Permission object to this entry.
1920
* No need to sync add op because perms are added to entry only
1921
* while entry is being initialized
1922
*/
1923
void add(Permission p) {
1924
permissions.add(p);
1925
}
1926
1927
/**
1928
* Return the CodeSource for this policy entry
1929
*/
1930
CodeSource getCodeSource() {
1931
return codesource;
1932
}
1933
1934
@Override public String toString(){
1935
StringBuilder sb = new StringBuilder();
1936
sb.append(ResourcesMgr.getString("LPARAM"));
1937
sb.append(getCodeSource());
1938
sb.append("\n");
1939
for (int j = 0; j < permissions.size(); j++) {
1940
Permission p = permissions.get(j);
1941
sb.append(ResourcesMgr.getString("SPACE"));
1942
sb.append(ResourcesMgr.getString("SPACE"));
1943
sb.append(p);
1944
sb.append(ResourcesMgr.getString("NEWLINE"));
1945
}
1946
sb.append(ResourcesMgr.getString("RPARAM"));
1947
sb.append(ResourcesMgr.getString("NEWLINE"));
1948
return sb.toString();
1949
}
1950
}
1951
1952
private static class SelfPermission extends Permission {
1953
1954
@java.io.Serial
1955
private static final long serialVersionUID = -8315562579967246806L;
1956
1957
/**
1958
* The class name of the Permission class that will be
1959
* created when this self permission is expanded .
1960
*
1961
* @serial
1962
*/
1963
private String type;
1964
1965
/**
1966
* The permission name.
1967
*
1968
* @serial
1969
*/
1970
private String name;
1971
1972
/**
1973
* The actions of the permission.
1974
*
1975
* @serial
1976
*/
1977
private String actions;
1978
1979
/**
1980
* The certs of the permission.
1981
*
1982
* @serial
1983
*/
1984
private Certificate[] certs;
1985
1986
/**
1987
* Creates a new SelfPermission containing the permission
1988
* information needed later to expand the self
1989
* @param type the class name of the Permission class that will be
1990
* created when this permission is expanded and if necessary resolved.
1991
* @param name the name of the permission.
1992
* @param actions the actions of the permission.
1993
* @param certs the certificates the permission's class was signed with.
1994
* This is a list of certificate chains, where each chain is composed of
1995
* a signer certificate and optionally its supporting certificate chain.
1996
* Each chain is ordered bottom-to-top (i.e., with the signer
1997
* certificate first and the (root) certificate authority last).
1998
*/
1999
public SelfPermission(String type, String name, String actions,
2000
Certificate[] certs)
2001
{
2002
super(type);
2003
if (type == null) {
2004
throw new NullPointerException
2005
(LocalizedMessage.getNonlocalized("type.can.t.be.null"));
2006
}
2007
this.type = type;
2008
this.name = name;
2009
this.actions = actions;
2010
if (certs != null) {
2011
// Extract the signer certs from the list of certificates.
2012
for (int i=0; i<certs.length; i++) {
2013
if (!(certs[i] instanceof X509Certificate)) {
2014
// there is no concept of signer certs, so we store the
2015
// entire cert array
2016
this.certs = certs.clone();
2017
break;
2018
}
2019
}
2020
2021
if (this.certs == null) {
2022
// Go through the list of certs and see if all the certs are
2023
// signer certs.
2024
int i = 0;
2025
int count = 0;
2026
while (i < certs.length) {
2027
count++;
2028
while (((i+1) < certs.length) &&
2029
((X509Certificate)certs[i]).getIssuerX500Principal().equals(
2030
((X509Certificate)certs[i+1]).getSubjectX500Principal())) {
2031
i++;
2032
}
2033
i++;
2034
}
2035
if (count == certs.length) {
2036
// All the certs are signer certs, so we store the
2037
// entire array
2038
this.certs = certs.clone();
2039
}
2040
2041
if (this.certs == null) {
2042
// extract the signer certs
2043
List<Certificate> signerCerts = new ArrayList<>();
2044
i = 0;
2045
while (i < certs.length) {
2046
signerCerts.add(certs[i]);
2047
while (((i+1) < certs.length) &&
2048
((X509Certificate)certs[i]).getIssuerX500Principal().equals(
2049
((X509Certificate)certs[i+1]).getSubjectX500Principal())) {
2050
i++;
2051
}
2052
i++;
2053
}
2054
this.certs = new Certificate[signerCerts.size()];
2055
signerCerts.toArray(this.certs);
2056
}
2057
}
2058
}
2059
}
2060
2061
/**
2062
* This method always returns false for SelfPermission permissions.
2063
* That is, an SelfPermission never considered to
2064
* imply another permission.
2065
*
2066
* @param p the permission to check against.
2067
*
2068
* @return false.
2069
*/
2070
@Override public boolean implies(Permission p) {
2071
return false;
2072
}
2073
2074
/**
2075
* Checks two SelfPermission objects for equality.
2076
*
2077
* Checks that <i>obj</i> is an SelfPermission, and has
2078
* the same type (class) name, permission name, actions, and
2079
* certificates as this object.
2080
*
2081
* @param obj the object we are testing for equality with this object.
2082
*
2083
* @return true if obj is an SelfPermission, and has the same
2084
* type (class) name, permission name, actions, and
2085
* certificates as this object.
2086
*/
2087
@Override public boolean equals(Object obj) {
2088
if (obj == this)
2089
return true;
2090
2091
if (! (obj instanceof SelfPermission))
2092
return false;
2093
SelfPermission that = (SelfPermission) obj;
2094
2095
if (!(this.type.equals(that.type) &&
2096
this.name.equals(that.name) &&
2097
this.actions.equals(that.actions)))
2098
return false;
2099
2100
if (this.certs.length != that.certs.length)
2101
return false;
2102
2103
int i,j;
2104
boolean match;
2105
2106
for (i = 0; i < this.certs.length; i++) {
2107
match = false;
2108
for (j = 0; j < that.certs.length; j++) {
2109
if (this.certs[i].equals(that.certs[j])) {
2110
match = true;
2111
break;
2112
}
2113
}
2114
if (!match) return false;
2115
}
2116
2117
for (i = 0; i < that.certs.length; i++) {
2118
match = false;
2119
for (j = 0; j < this.certs.length; j++) {
2120
if (that.certs[i].equals(this.certs[j])) {
2121
match = true;
2122
break;
2123
}
2124
}
2125
if (!match) return false;
2126
}
2127
return true;
2128
}
2129
2130
/**
2131
* Returns the hash code value for this object.
2132
*
2133
* @return a hash code value for this object.
2134
*/
2135
@Override public int hashCode() {
2136
int hash = type.hashCode();
2137
if (name != null)
2138
hash ^= name.hashCode();
2139
if (actions != null)
2140
hash ^= actions.hashCode();
2141
return hash;
2142
}
2143
2144
/**
2145
* Returns the canonical string representation of the actions,
2146
* which currently is the empty string "", since there are no actions
2147
* for an SelfPermission. That is, the actions for the
2148
* permission that will be created when this SelfPermission
2149
* is resolved may be non-null, but an SelfPermission
2150
* itself is never considered to have any actions.
2151
*
2152
* @return the empty string "".
2153
*/
2154
@Override public String getActions() {
2155
return "";
2156
}
2157
2158
public String getSelfType() {
2159
return type;
2160
}
2161
2162
public String getSelfName() {
2163
return name;
2164
}
2165
2166
public String getSelfActions() {
2167
return actions;
2168
}
2169
2170
public Certificate[] getCerts() {
2171
return certs;
2172
}
2173
2174
/**
2175
* Returns a string describing this SelfPermission. The convention
2176
* is to specify the class name, the permission name, and the actions,
2177
* in the following format: '(unresolved "ClassName" "name" "actions")'.
2178
*
2179
* @return information about this SelfPermission.
2180
*/
2181
@Override public String toString() {
2182
return "(SelfPermission " + type + " " + name + " " + actions + ")";
2183
}
2184
}
2185
2186
/**
2187
* holds policy information that we need to synch on
2188
*/
2189
private static class PolicyInfo {
2190
private static final boolean verbose = false;
2191
2192
// Stores grant entries in the policy
2193
final List<PolicyEntry> policyEntries;
2194
2195
// Maps aliases to certs
2196
final Map<Object, Object> aliasMapping;
2197
2198
// Maps ProtectionDomain to PermissionCollection
2199
private final ProtectionDomainCache[] pdMapping;
2200
private java.util.Random random;
2201
2202
PolicyInfo(int numCaches) {
2203
policyEntries = new ArrayList<>();
2204
aliasMapping = Collections.synchronizedMap(new HashMap<>(11));
2205
2206
pdMapping = new ProtectionDomainCache[numCaches];
2207
JavaSecurityAccess jspda
2208
= SharedSecrets.getJavaSecurityAccess();
2209
for (int i = 0; i < numCaches; i++) {
2210
pdMapping[i] = jspda.getProtectionDomainCache();
2211
}
2212
if (numCaches > 1) {
2213
random = new java.util.Random();
2214
}
2215
}
2216
ProtectionDomainCache getPdMapping() {
2217
if (pdMapping.length == 1) {
2218
return pdMapping[0];
2219
} else {
2220
int i = java.lang.Math.abs(random.nextInt() % pdMapping.length);
2221
return pdMapping[i];
2222
}
2223
}
2224
}
2225
}
2226
2227