Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/javax/security/auth/PrivateCredentialPermission.java
41159 views
1
/*
2
* Copyright (c) 1999, 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 javax.security.auth;
27
28
import java.util.*;
29
import java.io.IOException;
30
import java.text.MessageFormat;
31
import java.security.Permission;
32
import java.security.PermissionCollection;
33
import java.security.Principal;
34
import sun.security.util.ResourcesMgr;
35
36
/**
37
* This class is used to protect access to private Credentials
38
* belonging to a particular {@code Subject}. The {@code Subject}
39
* is represented by a Set of Principals.
40
*
41
* <p> The target name of this {@code Permission} specifies
42
* a Credential class name, and a Set of Principals.
43
* The only valid value for this Permission's actions is, "read".
44
* The target name must abide by the following syntax:
45
*
46
* <pre>
47
* CredentialClass {PrincipalClass "PrincipalName"}*
48
* </pre>
49
*
50
* For example, the following permission grants access to the
51
* com.sun.PrivateCredential owned by Subjects which have
52
* a com.sun.Principal with the name, "duke". Note that although
53
* this example, as well as all the examples below, do not contain
54
* Codebase, SignedBy, or Principal information in the grant statement
55
* (for simplicity reasons), actual policy configurations should
56
* specify that information when appropriate.
57
*
58
* <pre>
59
*
60
* grant {
61
* permission javax.security.auth.PrivateCredentialPermission
62
* "com.sun.PrivateCredential com.sun.Principal \"duke\"",
63
* "read";
64
* };
65
* </pre>
66
*
67
* If CredentialClass is "*", then access is granted to
68
* all private Credentials belonging to the specified
69
* {@code Subject}.
70
* If "PrincipalName" is "*", then access is granted to the
71
* specified Credential owned by any {@code Subject} that has the
72
* specified {@code Principal} (the actual PrincipalName doesn't matter).
73
* For example, the following grants access to the
74
* a.b.Credential owned by any {@code Subject} that has
75
* an a.b.Principal.
76
*
77
* <pre>
78
* grant {
79
* permission javax.security.auth.PrivateCredentialPermission
80
* "a.b.Credential a.b.Principal "*"",
81
* "read";
82
* };
83
* </pre>
84
*
85
* If both the PrincipalClass and "PrincipalName" are "*",
86
* then access is granted to the specified Credential owned by
87
* any {@code Subject}.
88
*
89
* <p> In addition, the PrincipalClass/PrincipalName pairing may be repeated:
90
*
91
* <pre>
92
* grant {
93
* permission javax.security.auth.PrivateCredentialPermission
94
* "a.b.Credential a.b.Principal "duke" c.d.Principal "dukette"",
95
* "read";
96
* };
97
* </pre>
98
*
99
* The above grants access to the private Credential, "a.b.Credential",
100
* belonging to a {@code Subject} with at least two associated Principals:
101
* "a.b.Principal" with the name, "duke", and "c.d.Principal", with the name,
102
* "dukette".
103
*
104
* @since 1.4
105
*/
106
public final class PrivateCredentialPermission extends Permission {
107
108
@java.io.Serial
109
private static final long serialVersionUID = 5284372143517237068L;
110
111
private static final CredOwner[] EMPTY_PRINCIPALS = new CredOwner[0];
112
113
/**
114
* @serial
115
*/
116
private String credentialClass;
117
118
/**
119
* @serial The Principals associated with this permission.
120
* The set contains elements of type,
121
* {@code PrivateCredentialPermission.CredOwner}.
122
*/
123
@SuppressWarnings("serial") // Not statically typed as Serializable
124
private Set<Principal> principals; // ignored - kept around for compatibility
125
private transient CredOwner[] credOwners;
126
127
/**
128
* @serial
129
*/
130
private boolean testing = false;
131
132
/**
133
* Create a new {@code PrivateCredentialPermission}
134
* with the specified {@code credentialClass} and Principals.
135
*/
136
PrivateCredentialPermission(String credentialClass,
137
Set<Principal> principals) {
138
139
super(credentialClass);
140
this.credentialClass = credentialClass;
141
142
synchronized(principals) {
143
if (principals.size() == 0) {
144
this.credOwners = EMPTY_PRINCIPALS;
145
} else {
146
this.credOwners = new CredOwner[principals.size()];
147
int index = 0;
148
Iterator<Principal> i = principals.iterator();
149
while (i.hasNext()) {
150
Principal p = i.next();
151
this.credOwners[index++] = new CredOwner
152
(p.getClass().getName(),
153
p.getName());
154
}
155
}
156
}
157
}
158
159
/**
160
* Creates a new {@code PrivateCredentialPermission}
161
* with the specified {@code name}. The {@code name}
162
* specifies both a Credential class and a {@code Principal} Set.
163
*
164
* @param name the name specifying the Credential class and
165
* {@code Principal} Set.
166
*
167
* @param actions the actions specifying that the Credential can be read.
168
*
169
* @throws IllegalArgumentException if {@code name} does not conform
170
* to the correct syntax or if {@code actions} is not "read".
171
*/
172
public PrivateCredentialPermission(String name, String actions) {
173
super(name);
174
175
if (!"read".equalsIgnoreCase(actions))
176
throw new IllegalArgumentException
177
(ResourcesMgr.getString("actions.can.only.be.read."));
178
init(name);
179
}
180
181
/**
182
* Returns the Class name of the Credential associated with this
183
* {@code PrivateCredentialPermission}.
184
*
185
* @return the Class name of the Credential associated with this
186
* {@code PrivateCredentialPermission}.
187
*/
188
public String getCredentialClass() {
189
return credentialClass;
190
}
191
192
/**
193
* Returns the {@code Principal} classes and names
194
* associated with this {@code PrivateCredentialPermission}.
195
* The information is returned as a two-dimensional array (array[x][y]).
196
* The 'x' value corresponds to the number of {@code Principal}
197
* class and name pairs. When (y==0), it corresponds to
198
* the {@code Principal} class value, and when (y==1),
199
* it corresponds to the {@code Principal} name value.
200
* For example, array[0][0] corresponds to the class name of
201
* the first {@code Principal} in the array. array[0][1]
202
* corresponds to the {@code Principal} name of the
203
* first {@code Principal} in the array.
204
*
205
* @return the {@code Principal} class and names associated
206
* with this {@code PrivateCredentialPermission}.
207
*/
208
public String[][] getPrincipals() {
209
210
if (credOwners == null || credOwners.length == 0) {
211
return new String[0][0];
212
}
213
214
String[][] pArray = new String[credOwners.length][2];
215
for (int i = 0; i < credOwners.length; i++) {
216
pArray[i][0] = credOwners[i].principalClass;
217
pArray[i][1] = credOwners[i].principalName;
218
}
219
return pArray;
220
}
221
222
/**
223
* Checks if this {@code PrivateCredentialPermission} implies
224
* the specified {@code Permission}.
225
*
226
* <p>
227
*
228
* This method returns true if:
229
* <ul>
230
* <li> {@code p} is an instanceof PrivateCredentialPermission and
231
* <li> the target name for {@code p} is implied by this object's
232
* target name. For example:
233
* <pre>
234
* [* P1 "duke"] implies [a.b.Credential P1 "duke"].
235
* [C1 P1 "duke"] implies [C1 P1 "duke" P2 "dukette"].
236
* [C1 P2 "dukette"] implies [C1 P1 "duke" P2 "dukette"].
237
* </pre>
238
* </ul>
239
*
240
* @param p the {@code Permission} to check against.
241
*
242
* @return true if this {@code PrivateCredentialPermission} implies
243
* the specified {@code Permission}, false if not.
244
*/
245
public boolean implies(Permission p) {
246
247
if (p == null || !(p instanceof PrivateCredentialPermission))
248
return false;
249
250
PrivateCredentialPermission that = (PrivateCredentialPermission)p;
251
252
if (!impliesCredentialClass(credentialClass, that.credentialClass))
253
return false;
254
255
return impliesPrincipalSet(credOwners, that.credOwners);
256
}
257
258
/**
259
* Checks two {@code PrivateCredentialPermission} objects for
260
* equality. Checks that {@code obj} is a
261
* {@code PrivateCredentialPermission},
262
* and has the same credential class as this object,
263
* as well as the same Principals as this object.
264
* The order of the Principals in the respective Permission's
265
* target names is not relevant.
266
*
267
* @param obj the object we are testing for equality with this object.
268
*
269
* @return true if obj is a {@code PrivateCredentialPermission},
270
* has the same credential class as this object,
271
* and has the same Principals as this object.
272
*/
273
public boolean equals(Object obj) {
274
if (obj == this)
275
return true;
276
277
if (! (obj instanceof PrivateCredentialPermission))
278
return false;
279
280
PrivateCredentialPermission that = (PrivateCredentialPermission)obj;
281
282
return (this.implies(that) && that.implies(this));
283
}
284
285
/**
286
* Returns the hash code value for this object.
287
*
288
* @return a hash code value for this object.
289
*/
290
public int hashCode() {
291
return this.credentialClass.hashCode();
292
}
293
294
/**
295
* Returns the "canonical string representation" of the actions.
296
* This method always returns the String, "read".
297
*
298
* @return the actions (always returns "read").
299
*/
300
public String getActions() {
301
return "read";
302
}
303
304
/**
305
* Return a homogeneous collection of PrivateCredentialPermissions
306
* in a {@code PermissionCollection}.
307
* No such {@code PermissionCollection} is defined,
308
* so this method always returns {@code null}.
309
*
310
* @return null in all cases.
311
*/
312
public PermissionCollection newPermissionCollection() {
313
return null;
314
}
315
316
private void init(String name) {
317
318
if (name == null || name.trim().isEmpty()) {
319
throw new IllegalArgumentException("invalid empty name");
320
}
321
322
ArrayList<CredOwner> pList = new ArrayList<>();
323
StringTokenizer tokenizer = new StringTokenizer(name, " ", true);
324
String principalClass = null;
325
String principalName = null;
326
327
if (testing)
328
System.out.println("whole name = " + name);
329
330
// get the Credential Class
331
credentialClass = tokenizer.nextToken();
332
if (testing)
333
System.out.println("Credential Class = " + credentialClass);
334
335
if (tokenizer.hasMoreTokens() == false) {
336
MessageFormat form = new MessageFormat(ResourcesMgr.getString
337
("permission.name.name.syntax.invalid."));
338
Object[] source = {name};
339
throw new IllegalArgumentException
340
(form.format(source) + ResourcesMgr.getString
341
("Credential.Class.not.followed.by.a.Principal.Class.and.Name"));
342
}
343
344
while (tokenizer.hasMoreTokens()) {
345
346
// skip delimiter
347
tokenizer.nextToken();
348
349
// get the Principal Class
350
principalClass = tokenizer.nextToken();
351
if (testing)
352
System.out.println(" Principal Class = " + principalClass);
353
354
if (tokenizer.hasMoreTokens() == false) {
355
MessageFormat form = new MessageFormat(ResourcesMgr.getString
356
("permission.name.name.syntax.invalid."));
357
Object[] source = {name};
358
throw new IllegalArgumentException
359
(form.format(source) + ResourcesMgr.getString
360
("Principal.Class.not.followed.by.a.Principal.Name"));
361
}
362
363
// skip delimiter
364
tokenizer.nextToken();
365
366
// get the Principal Name
367
principalName = tokenizer.nextToken();
368
369
if (!principalName.startsWith("\"")) {
370
MessageFormat form = new MessageFormat(ResourcesMgr.getString
371
("permission.name.name.syntax.invalid."));
372
Object[] source = {name};
373
throw new IllegalArgumentException
374
(form.format(source) + ResourcesMgr.getString
375
("Principal.Name.must.be.surrounded.by.quotes"));
376
}
377
378
if (!principalName.endsWith("\"")) {
379
380
// we have a name with spaces in it --
381
// keep parsing until we find the end quote,
382
// and keep the spaces in the name
383
384
while (tokenizer.hasMoreTokens()) {
385
principalName = principalName + tokenizer.nextToken();
386
if (principalName.endsWith("\""))
387
break;
388
}
389
390
if (!principalName.endsWith("\"")) {
391
MessageFormat form = new MessageFormat
392
(ResourcesMgr.getString
393
("permission.name.name.syntax.invalid."));
394
Object[] source = {name};
395
throw new IllegalArgumentException
396
(form.format(source) + ResourcesMgr.getString
397
("Principal.Name.missing.end.quote"));
398
}
399
}
400
401
if (testing)
402
System.out.println("\tprincipalName = '" + principalName + "'");
403
404
principalName = principalName.substring
405
(1, principalName.length() - 1);
406
407
if (principalClass.equals("*") &&
408
!principalName.equals("*")) {
409
throw new IllegalArgumentException(ResourcesMgr.getString
410
("PrivateCredentialPermission.Principal.Class.can.not.be.a.wildcard.value.if.Principal.Name.is.not.a.wildcard.value"));
411
}
412
413
if (testing)
414
System.out.println("\tprincipalName = '" + principalName + "'");
415
416
pList.add(new CredOwner(principalClass, principalName));
417
}
418
419
this.credOwners = new CredOwner[pList.size()];
420
pList.toArray(this.credOwners);
421
}
422
423
private boolean impliesCredentialClass(String thisC, String thatC) {
424
425
// this should never happen
426
if (thisC == null || thatC == null)
427
return false;
428
429
if (testing)
430
System.out.println("credential class comparison: " +
431
thisC + "/" + thatC);
432
433
if (thisC.equals("*"))
434
return true;
435
436
/**
437
* XXX let's not enable this for now --
438
* if people want it, we'll enable it later
439
*/
440
/*
441
if (thisC.endsWith("*")) {
442
String cClass = thisC.substring(0, thisC.length() - 2);
443
return thatC.startsWith(cClass);
444
}
445
*/
446
447
return thisC.equals(thatC);
448
}
449
450
private boolean impliesPrincipalSet(CredOwner[] thisP, CredOwner[] thatP) {
451
452
// this should never happen
453
if (thisP == null || thatP == null)
454
return false;
455
456
if (thatP.length == 0)
457
return true;
458
459
if (thisP.length == 0)
460
return false;
461
462
for (int i = 0; i < thisP.length; i++) {
463
boolean foundMatch = false;
464
for (int j = 0; j < thatP.length; j++) {
465
if (thisP[i].implies(thatP[j])) {
466
foundMatch = true;
467
break;
468
}
469
}
470
if (!foundMatch) {
471
return false;
472
}
473
}
474
return true;
475
}
476
477
/**
478
* Reads this object from a stream (i.e., deserializes it)
479
*
480
* @param s the {@code ObjectInputStream} from which data is read
481
* @throws IOException if an I/O error occurs
482
* @throws ClassNotFoundException if a serialized class cannot be loaded
483
*/
484
@java.io.Serial
485
private void readObject(java.io.ObjectInputStream s) throws
486
IOException,
487
ClassNotFoundException {
488
489
s.defaultReadObject();
490
491
// perform new initialization from the permission name
492
493
if (getName().indexOf(' ') == -1 && getName().indexOf('"') == -1) {
494
495
// name only has a credential class specified
496
credentialClass = getName();
497
credOwners = EMPTY_PRINCIPALS;
498
499
} else {
500
501
// perform regular initialization
502
init(getName());
503
}
504
}
505
506
/**
507
* @serial include
508
*/
509
static class CredOwner implements java.io.Serializable {
510
511
@java.io.Serial
512
private static final long serialVersionUID = -5607449830436408266L;
513
514
/**
515
* @serial
516
*/
517
String principalClass;
518
/**
519
* @serial
520
*/
521
String principalName;
522
523
CredOwner(String principalClass, String principalName) {
524
this.principalClass = principalClass;
525
this.principalName = principalName;
526
}
527
528
public boolean implies(Object obj) {
529
if (obj == null || !(obj instanceof CredOwner))
530
return false;
531
532
CredOwner that = (CredOwner)obj;
533
534
if (principalClass.equals("*") ||
535
principalClass.equals(that.principalClass)) {
536
537
if (principalName.equals("*") ||
538
principalName.equals(that.principalName)) {
539
return true;
540
}
541
}
542
543
/**
544
* XXX no code yet to support a.b.*
545
*/
546
547
return false;
548
}
549
550
public String toString() {
551
MessageFormat form = new MessageFormat(ResourcesMgr.getString
552
("CredOwner.Principal.Class.class.Principal.Name.name"));
553
Object[] source = {principalClass, principalName};
554
return (form.format(source));
555
}
556
}
557
}
558
559