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/sun/security/krb5/PrincipalName.java
38830 views
1
/*
2
* Copyright (c) 2000, 2019, 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
/*
27
*
28
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
29
* Copyright 1997 The Open Group Research Institute. All rights reserved.
30
*/
31
32
package sun.security.krb5;
33
34
import sun.security.krb5.internal.*;
35
import sun.security.util.*;
36
import java.net.*;
37
import java.util.Vector;
38
import java.util.Locale;
39
import java.io.IOException;
40
import java.math.BigInteger;
41
import java.util.Arrays;
42
import sun.security.krb5.internal.ccache.CCacheOutputStream;
43
import sun.security.krb5.internal.util.KerberosString;
44
45
46
/**
47
* Implements the ASN.1 PrincipalName type and its realm in a single class.
48
* <pre>{@code
49
* Realm ::= KerberosString
50
*
51
* PrincipalName ::= SEQUENCE {
52
* name-type [0] Int32,
53
* name-string [1] SEQUENCE OF KerberosString
54
* }
55
* }</pre>
56
* This class is immutable.
57
* @see Realm
58
*/
59
public class PrincipalName implements Cloneable {
60
61
//name types
62
63
/**
64
* Name type not known
65
*/
66
public static final int KRB_NT_UNKNOWN = 0;
67
68
/**
69
* Just the name of the principal as in DCE, or for users
70
*/
71
public static final int KRB_NT_PRINCIPAL = 1;
72
73
/**
74
* Service and other unique instance (krbtgt)
75
*/
76
public static final int KRB_NT_SRV_INST = 2;
77
78
/**
79
* Service with host name as instance (telnet, rcommands)
80
*/
81
public static final int KRB_NT_SRV_HST = 3;
82
83
/**
84
* Service with host as remaining components
85
*/
86
public static final int KRB_NT_SRV_XHST = 4;
87
88
/**
89
* Unique ID
90
*/
91
public static final int KRB_NT_UID = 5;
92
93
/**
94
* Enterprise name (alias)
95
*/
96
public static final int KRB_NT_ENTERPRISE = 10;
97
98
/**
99
* TGS Name
100
*/
101
public static final String TGS_DEFAULT_SRV_NAME = "krbtgt";
102
public static final int TGS_DEFAULT_NT = KRB_NT_SRV_INST;
103
104
public static final char NAME_COMPONENT_SEPARATOR = '/';
105
public static final char NAME_REALM_SEPARATOR = '@';
106
public static final char REALM_COMPONENT_SEPARATOR = '.';
107
108
public static final String NAME_COMPONENT_SEPARATOR_STR = "/";
109
public static final String NAME_REALM_SEPARATOR_STR = "@";
110
public static final String REALM_COMPONENT_SEPARATOR_STR = ".";
111
112
// Instance fields.
113
114
/**
115
* The name type, from PrincipalName's name-type field.
116
*/
117
private final int nameType;
118
119
/**
120
* The name strings, from PrincipalName's name-strings field. This field
121
* must be neither null nor empty. Each entry of it must also be neither
122
* null nor empty. Make sure to clone the field when it's passed in or out.
123
*/
124
private final String[] nameStrings;
125
126
/**
127
* The realm this principal belongs to.
128
*/
129
private final Realm nameRealm; // not null
130
131
132
/**
133
* When constructing a PrincipalName, whether the realm is included in
134
* the input, or deduced from default realm or domain-realm mapping.
135
*/
136
private final boolean realmDeduced;
137
138
// cached default salt, not used in clone
139
private transient String salt = null;
140
141
// There are 3 basic constructors. All other constructors must call them.
142
// All basic constructors must call validateNameStrings.
143
// 1. From name components
144
// 2. From name
145
// 3. From DER encoding
146
147
/**
148
* Creates a PrincipalName.
149
*/
150
public PrincipalName(int nameType, String[] nameStrings, Realm nameRealm) {
151
if (nameRealm == null) {
152
throw new IllegalArgumentException("Null realm not allowed");
153
}
154
validateNameStrings(nameStrings);
155
this.nameType = nameType;
156
this.nameStrings = nameStrings.clone();
157
this.nameRealm = nameRealm;
158
this.realmDeduced = false;
159
}
160
161
// This method is called by Windows NativeCred.c
162
public PrincipalName(String[] nameParts, String realm) throws RealmException {
163
this(KRB_NT_UNKNOWN, nameParts, new Realm(realm));
164
}
165
166
// Validate a nameStrings argument
167
private static void validateNameStrings(String[] ns) {
168
if (ns == null) {
169
throw new IllegalArgumentException("Null nameStrings not allowed");
170
}
171
if (ns.length == 0) {
172
throw new IllegalArgumentException("Empty nameStrings not allowed");
173
}
174
for (String s: ns) {
175
if (s == null) {
176
throw new IllegalArgumentException("Null nameString not allowed");
177
}
178
if (s.isEmpty()) {
179
throw new IllegalArgumentException("Empty nameString not allowed");
180
}
181
}
182
}
183
184
public Object clone() {
185
try {
186
PrincipalName pName = (PrincipalName) super.clone();
187
UNSAFE.putObject(this, NAME_STRINGS_OFFSET, nameStrings.clone());
188
return pName;
189
} catch (CloneNotSupportedException ex) {
190
throw new AssertionError("Should never happen");
191
}
192
}
193
194
private static final long NAME_STRINGS_OFFSET;
195
private static final sun.misc.Unsafe UNSAFE;
196
static {
197
try {
198
sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
199
NAME_STRINGS_OFFSET = unsafe.objectFieldOffset(
200
PrincipalName.class.getDeclaredField("nameStrings"));
201
UNSAFE = unsafe;
202
} catch (ReflectiveOperationException e) {
203
throw new Error(e);
204
}
205
}
206
207
@Override
208
public boolean equals(Object o) {
209
if (this == o) {
210
return true;
211
}
212
if (o instanceof PrincipalName) {
213
PrincipalName other = (PrincipalName)o;
214
return nameRealm.equals(other.nameRealm) &&
215
Arrays.equals(nameStrings, other.nameStrings);
216
}
217
return false;
218
}
219
220
/**
221
* Returns the ASN.1 encoding of the
222
* <pre>{@code
223
* PrincipalName ::= SEQUENCE {
224
* name-type [0] Int32,
225
* name-string [1] SEQUENCE OF KerberosString
226
* }
227
*
228
* KerberosString ::= GeneralString (IA5String)
229
* }</pre>
230
*
231
* <p>
232
* This definition reflects the Network Working Group RFC 4120
233
* specification available at
234
* <a href="http://www.ietf.org/rfc/rfc4120.txt">
235
* http://www.ietf.org/rfc/rfc4120.txt</a>.
236
*
237
* @param encoding DER-encoded PrincipalName (without Realm)
238
* @param realm the realm for this name
239
* @exception Asn1Exception if an error occurs while decoding
240
* an ASN1 encoded data.
241
* @exception Asn1Exception if there is an ASN1 encoding error
242
* @exception IOException if an I/O error occurs
243
* @exception IllegalArgumentException if encoding is null
244
* reading encoded data.
245
*/
246
public PrincipalName(DerValue encoding, Realm realm)
247
throws Asn1Exception, IOException {
248
if (realm == null) {
249
throw new IllegalArgumentException("Null realm not allowed");
250
}
251
realmDeduced = false;
252
nameRealm = realm;
253
DerValue der;
254
if (encoding == null) {
255
throw new IllegalArgumentException("Null encoding not allowed");
256
}
257
if (encoding.getTag() != DerValue.tag_Sequence) {
258
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
259
}
260
der = encoding.getData().getDerValue();
261
if ((der.getTag() & 0x1F) == 0x00) {
262
BigInteger bint = der.getData().getBigInteger();
263
nameType = bint.intValue();
264
} else {
265
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
266
}
267
der = encoding.getData().getDerValue();
268
if ((der.getTag() & 0x01F) == 0x01) {
269
DerValue subDer = der.getData().getDerValue();
270
if (subDer.getTag() != DerValue.tag_SequenceOf) {
271
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
272
}
273
Vector<String> v = new Vector<>();
274
DerValue subSubDer;
275
while(subDer.getData().available() > 0) {
276
subSubDer = subDer.getData().getDerValue();
277
String namePart = new KerberosString(subSubDer).toString();
278
v.addElement(namePart);
279
}
280
nameStrings = new String[v.size()];
281
v.copyInto(nameStrings);
282
validateNameStrings(nameStrings);
283
} else {
284
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
285
}
286
}
287
288
/**
289
* Parse (unmarshal) a <code>PrincipalName</code> from a DER
290
* input stream. This form
291
* parsing might be used when expanding a value which is part of
292
* a constructed sequence and uses explicitly tagged type.
293
*
294
* @exception Asn1Exception on error.
295
* @param data the Der input stream value, which contains one or
296
* more marshaled value.
297
* @param explicitTag tag number.
298
* @param optional indicate if this data field is optional
299
* @param realm the realm for the name
300
* @return an instance of <code>PrincipalName</code>, or null if the
301
* field is optional and missing.
302
*/
303
public static PrincipalName parse(DerInputStream data,
304
byte explicitTag, boolean
305
optional,
306
Realm realm)
307
throws Asn1Exception, IOException, RealmException {
308
309
if ((optional) && (((byte)data.peekByte() & (byte)0x1F) !=
310
explicitTag))
311
return null;
312
DerValue der = data.getDerValue();
313
if (explicitTag != (der.getTag() & (byte)0x1F)) {
314
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
315
} else {
316
DerValue subDer = der.getData().getDerValue();
317
if (realm == null) {
318
realm = Realm.getDefault();
319
}
320
return new PrincipalName(subDer, realm);
321
}
322
}
323
324
325
// XXX Error checkin consistent with MIT krb5_parse_name
326
// Code repetition, realm parsed again by class Realm
327
private static String[] parseName(String name) {
328
329
Vector<String> tempStrings = new Vector<>();
330
String temp = name;
331
int i = 0;
332
int componentStart = 0;
333
String component;
334
335
while (i < temp.length()) {
336
if (temp.charAt(i) == NAME_COMPONENT_SEPARATOR) {
337
/*
338
* If this separator is escaped then don't treat it
339
* as a separator
340
*/
341
if (i > 0 && temp.charAt(i - 1) == '\\') {
342
temp = temp.substring(0, i - 1) +
343
temp.substring(i, temp.length());
344
continue;
345
}
346
else {
347
if (componentStart <= i) {
348
component = temp.substring(componentStart, i);
349
tempStrings.addElement(component);
350
}
351
componentStart = i + 1;
352
}
353
} else {
354
if (temp.charAt(i) == NAME_REALM_SEPARATOR) {
355
/*
356
* If this separator is escaped then don't treat it
357
* as a separator
358
*/
359
if (i > 0 && temp.charAt(i - 1) == '\\') {
360
temp = temp.substring(0, i - 1) +
361
temp.substring(i, temp.length());
362
continue;
363
} else {
364
if (componentStart < i) {
365
component = temp.substring(componentStart, i);
366
tempStrings.addElement(component);
367
}
368
componentStart = i + 1;
369
break;
370
}
371
}
372
}
373
i++;
374
}
375
376
if (i == temp.length()) {
377
component = temp.substring(componentStart, i);
378
tempStrings.addElement(component);
379
}
380
381
String[] result = new String[tempStrings.size()];
382
tempStrings.copyInto(result);
383
return result;
384
}
385
386
/**
387
* Constructs a PrincipalName from a string.
388
* @param name the name
389
* @param type the type
390
* @param realm the realm, null if not known. Note that when realm is not
391
* null, it will be always used even if there is a realm part in name. When
392
* realm is null, will read realm part from name, or try to map a realm
393
* (for KRB_NT_SRV_HST), or use the default realm, or fail
394
* @throws RealmException
395
*/
396
public PrincipalName(String name, int type, String realm)
397
throws RealmException {
398
if (name == null) {
399
throw new IllegalArgumentException("Null name not allowed");
400
}
401
String[] nameParts = parseName(name);
402
validateNameStrings(nameParts);
403
if (realm == null) {
404
realm = Realm.parseRealmAtSeparator(name);
405
}
406
407
// No realm info from parameter and string, must deduce later
408
realmDeduced = realm == null;
409
410
switch (type) {
411
case KRB_NT_SRV_HST:
412
if (nameParts.length >= 2) {
413
String hostName = nameParts[1];
414
try {
415
// RFC4120 does not recommend canonicalizing a hostname.
416
// However, for compatibility reason, we will try
417
// canonicalize it and see if the output looks better.
418
419
String canonicalized = (InetAddress.getByName(hostName)).
420
getCanonicalHostName();
421
422
// Looks if canonicalized is a longer format of hostName,
423
// we accept cases like
424
// bunny -> bunny.rabbit.hole
425
if (canonicalized.toLowerCase(Locale.ENGLISH).startsWith(
426
hostName.toLowerCase(Locale.ENGLISH)+".")) {
427
hostName = canonicalized;
428
}
429
} catch (UnknownHostException | SecurityException e) {
430
// not canonicalized or no permission to do so, use old
431
}
432
if (hostName.endsWith(".")) {
433
hostName = hostName.substring(0, hostName.length() - 1);
434
}
435
nameParts[1] = hostName.toLowerCase(Locale.ENGLISH);
436
}
437
nameStrings = nameParts;
438
nameType = type;
439
440
if (realm != null) {
441
nameRealm = new Realm(realm);
442
} else {
443
// We will try to get realm name from the mapping in
444
// the configuration. If it is not specified
445
// we will use the default realm. This nametype does
446
// not allow a realm to be specified. The name string must of
447
// the form service@host and this is internally changed into
448
// service/host by Kerberos
449
String mapRealm = mapHostToRealm(nameParts[1]);
450
if (mapRealm != null) {
451
nameRealm = new Realm(mapRealm);
452
} else {
453
nameRealm = Realm.getDefault();
454
}
455
}
456
break;
457
case KRB_NT_UNKNOWN:
458
case KRB_NT_PRINCIPAL:
459
case KRB_NT_SRV_INST:
460
case KRB_NT_SRV_XHST:
461
case KRB_NT_UID:
462
case KRB_NT_ENTERPRISE:
463
nameStrings = nameParts;
464
nameType = type;
465
if (realm != null) {
466
nameRealm = new Realm(realm);
467
} else {
468
nameRealm = Realm.getDefault();
469
}
470
break;
471
default:
472
throw new IllegalArgumentException("Illegal name type");
473
}
474
}
475
476
public PrincipalName(String name, int type) throws RealmException {
477
this(name, type, (String)null);
478
}
479
480
public PrincipalName(String name) throws RealmException {
481
this(name, KRB_NT_UNKNOWN);
482
}
483
484
public PrincipalName(String name, String realm) throws RealmException {
485
this(name, KRB_NT_UNKNOWN, realm);
486
}
487
488
public static PrincipalName tgsService(String r1, String r2)
489
throws KrbException {
490
return new PrincipalName(PrincipalName.KRB_NT_SRV_INST,
491
new String[] {PrincipalName.TGS_DEFAULT_SRV_NAME, r1},
492
new Realm(r2));
493
}
494
495
public String getRealmAsString() {
496
return getRealmString();
497
}
498
499
public String getPrincipalNameAsString() {
500
StringBuffer temp = new StringBuffer(nameStrings[0]);
501
for (int i = 1; i < nameStrings.length; i++)
502
temp.append(nameStrings[i]);
503
return temp.toString();
504
}
505
506
public int hashCode() {
507
return toString().hashCode();
508
}
509
510
public String getName() {
511
return toString();
512
}
513
514
public int getNameType() {
515
return nameType;
516
}
517
518
public String[] getNameStrings() {
519
return nameStrings.clone();
520
}
521
522
public byte[][] toByteArray() {
523
byte[][] result = new byte[nameStrings.length][];
524
for (int i = 0; i < nameStrings.length; i++) {
525
result[i] = new byte[nameStrings[i].length()];
526
result[i] = nameStrings[i].getBytes();
527
}
528
return result;
529
}
530
531
public String getRealmString() {
532
return nameRealm.toString();
533
}
534
535
public Realm getRealm() {
536
return nameRealm;
537
}
538
539
public String getSalt() {
540
if (salt == null) {
541
StringBuffer salt = new StringBuffer();
542
salt.append(nameRealm.toString());
543
for (int i = 0; i < nameStrings.length; i++) {
544
salt.append(nameStrings[i]);
545
}
546
return salt.toString();
547
}
548
return salt;
549
}
550
551
public String toString() {
552
StringBuffer str = new StringBuffer();
553
for (int i = 0; i < nameStrings.length; i++) {
554
if (i > 0)
555
str.append("/");
556
String n = nameStrings[i];
557
n = n.replace("@", "\\@");
558
str.append(n);
559
}
560
str.append("@");
561
str.append(nameRealm.toString());
562
return str.toString();
563
}
564
565
public String getNameString() {
566
StringBuffer str = new StringBuffer();
567
for (int i = 0; i < nameStrings.length; i++) {
568
if (i > 0)
569
str.append("/");
570
str.append(nameStrings[i]);
571
}
572
return str.toString();
573
}
574
575
/**
576
* Encodes a <code>PrincipalName</code> object. Note that only the type and
577
* names are encoded. To encode the realm, call getRealm().asn1Encode().
578
* @return the byte array of the encoded PrncipalName object.
579
* @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
580
* @exception IOException if an I/O error occurs while reading encoded data.
581
*
582
*/
583
public byte[] asn1Encode() throws Asn1Exception, IOException {
584
DerOutputStream bytes = new DerOutputStream();
585
DerOutputStream temp = new DerOutputStream();
586
BigInteger bint = BigInteger.valueOf(this.nameType);
587
temp.putInteger(bint);
588
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp);
589
temp = new DerOutputStream();
590
DerValue der[] = new DerValue[nameStrings.length];
591
for (int i = 0; i < nameStrings.length; i++) {
592
der[i] = new KerberosString(nameStrings[i]).toDerValue();
593
}
594
temp.putSequence(der);
595
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), temp);
596
temp = new DerOutputStream();
597
temp.write(DerValue.tag_Sequence, bytes);
598
return temp.toByteArray();
599
}
600
601
602
/**
603
* Checks if two <code>PrincipalName</code> objects have identical values in their corresponding data fields.
604
*
605
* @param pname the other <code>PrincipalName</code> object.
606
* @return true if two have identical values, otherwise, return false.
607
*/
608
// It is used in <code>sun.security.krb5.internal.ccache</code> package.
609
public boolean match(PrincipalName pname) {
610
boolean matched = true;
611
//name type is just a hint, no two names can be the same ignoring name type.
612
// if (this.nameType != pname.nameType) {
613
// matched = false;
614
// }
615
if ((this.nameRealm != null) && (pname.nameRealm != null)) {
616
if (!(this.nameRealm.toString().equalsIgnoreCase(pname.nameRealm.toString()))) {
617
matched = false;
618
}
619
}
620
if (this.nameStrings.length != pname.nameStrings.length) {
621
matched = false;
622
} else {
623
for (int i = 0; i < this.nameStrings.length; i++) {
624
if (!(this.nameStrings[i].equalsIgnoreCase(pname.nameStrings[i]))) {
625
matched = false;
626
}
627
}
628
}
629
return matched;
630
}
631
632
/**
633
* Writes data field values of <code>PrincipalName</code> in FCC format to an output stream.
634
*
635
* @param cos a <code>CCacheOutputStream</code> for writing data.
636
* @exception IOException if an I/O exception occurs.
637
* @see sun.security.krb5.internal.ccache.CCacheOutputStream
638
*/
639
public void writePrincipal(CCacheOutputStream cos) throws IOException {
640
cos.write32(nameType);
641
cos.write32(nameStrings.length);
642
byte[] realmBytes = null;
643
realmBytes = nameRealm.toString().getBytes();
644
cos.write32(realmBytes.length);
645
cos.write(realmBytes, 0, realmBytes.length);
646
byte[] bytes = null;
647
for (int i = 0; i < nameStrings.length; i++) {
648
bytes = nameStrings[i].getBytes();
649
cos.write32(bytes.length);
650
cos.write(bytes, 0, bytes.length);
651
}
652
}
653
654
/**
655
* Returns the instance component of a name.
656
* In a multi-component name such as a KRB_NT_SRV_INST
657
* name, the second component is returned.
658
* Null is returned if there are not two or more
659
* components in the name.
660
*
661
* @return instance component of a multi-component name.
662
*/
663
public String getInstanceComponent()
664
{
665
if (nameStrings != null && nameStrings.length >= 2)
666
{
667
return new String(nameStrings[1]);
668
}
669
670
return null;
671
}
672
673
static String mapHostToRealm(String name) {
674
String result = null;
675
try {
676
String subname = null;
677
Config c = Config.getInstance();
678
if ((result = c.get("domain_realm", name)) != null)
679
return result;
680
else {
681
for (int i = 1; i < name.length(); i++) {
682
if ((name.charAt(i) == '.') && (i != name.length() - 1)) { //mapping could be .ibm.com = AUSTIN.IBM.COM
683
subname = name.substring(i);
684
result = c.get("domain_realm", subname);
685
if (result != null) {
686
break;
687
}
688
else {
689
subname = name.substring(i + 1); //or mapping could be ibm.com = AUSTIN.IBM.COM
690
result = c.get("domain_realm", subname);
691
if (result != null) {
692
break;
693
}
694
}
695
}
696
}
697
}
698
} catch (KrbException e) {
699
}
700
return result;
701
}
702
703
public boolean isRealmDeduced() {
704
return realmDeduced;
705
}
706
}
707
708