Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.security.jgss/share/classes/sun/security/krb5/Realm.java
41159 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.action.GetBooleanAction;
35
import sun.security.krb5.internal.Krb5;
36
import sun.security.util.*;
37
import java.io.IOException;
38
import java.util.*;
39
40
import sun.security.krb5.internal.util.KerberosString;
41
42
/**
43
* Implements the ASN.1 Realm type.
44
*
45
* {@code Realm ::= GeneralString}
46
*
47
* This class is immutable.
48
*/
49
public class Realm implements Cloneable {
50
51
public static final boolean AUTODEDUCEREALM = GetBooleanAction
52
.privilegedGetProperty("sun.security.krb5.autodeducerealm");
53
54
private final String realm; // not null nor empty
55
56
public Realm(String name) throws RealmException {
57
realm = parseRealm(name);
58
}
59
60
public static Realm getDefault() throws RealmException {
61
try {
62
return new Realm(Config.getInstance().getDefaultRealm());
63
} catch (RealmException re) {
64
throw re;
65
} catch (KrbException ke) {
66
throw new RealmException(ke);
67
}
68
}
69
70
// Immutable class, no need to clone
71
public Object clone() {
72
return this;
73
}
74
75
public boolean equals(Object obj) {
76
if (this == obj) {
77
return true;
78
}
79
80
if (!(obj instanceof Realm)) {
81
return false;
82
}
83
84
Realm that = (Realm)obj;
85
return this.realm.equals(that.realm);
86
}
87
88
public int hashCode() {
89
return realm.hashCode();
90
}
91
92
/**
93
* Constructs a Realm object.
94
* @param encoding a Der-encoded data.
95
* @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
96
* @exception IOException if an I/O error occurs while reading encoded data.
97
* @exception RealmException if an error occurs while parsing a Realm object.
98
*/
99
public Realm(DerValue encoding)
100
throws Asn1Exception, RealmException, IOException {
101
if (encoding == null) {
102
throw new IllegalArgumentException("encoding can not be null");
103
}
104
realm = new KerberosString(encoding).toString();
105
if (realm == null || realm.length() == 0)
106
throw new RealmException(Krb5.REALM_NULL);
107
if (!isValidRealmString(realm))
108
throw new RealmException(Krb5.REALM_ILLCHAR);
109
}
110
111
public String toString() {
112
return realm;
113
}
114
115
// Extract realm from a string like dummy@REALM
116
public static String parseRealmAtSeparator(String name)
117
throws RealmException {
118
if (name == null) {
119
throw new IllegalArgumentException
120
("null input name is not allowed");
121
}
122
String temp = new String(name);
123
String result = null;
124
int i = 0;
125
while (i < temp.length()) {
126
if (temp.charAt(i) == PrincipalName.NAME_REALM_SEPARATOR) {
127
if (i == 0 || temp.charAt(i - 1) != '\\') {
128
if (i + 1 < temp.length()) {
129
result = temp.substring(i + 1, temp.length());
130
} else {
131
throw new IllegalArgumentException
132
("empty realm part not allowed");
133
}
134
break;
135
}
136
}
137
i++;
138
}
139
if (result != null) {
140
if (result.length() == 0)
141
throw new RealmException(Krb5.REALM_NULL);
142
if (!isValidRealmString(result))
143
throw new RealmException(Krb5.REALM_ILLCHAR);
144
}
145
return result;
146
}
147
148
public static String parseRealmComponent(String name) {
149
if (name == null) {
150
throw new IllegalArgumentException
151
("null input name is not allowed");
152
}
153
String temp = new String(name);
154
String result = null;
155
int i = 0;
156
while (i < temp.length()) {
157
if (temp.charAt(i) == PrincipalName.REALM_COMPONENT_SEPARATOR) {
158
if (i == 0 || temp.charAt(i - 1) != '\\') {
159
if (i + 1 < temp.length())
160
result = temp.substring(i + 1, temp.length());
161
break;
162
}
163
}
164
i++;
165
}
166
return result;
167
}
168
169
protected static String parseRealm(String name) throws RealmException {
170
String result = parseRealmAtSeparator(name);
171
if (result == null)
172
result = name;
173
if (result == null || result.length() == 0)
174
throw new RealmException(Krb5.REALM_NULL);
175
if (!isValidRealmString(result))
176
throw new RealmException(Krb5.REALM_ILLCHAR);
177
return result;
178
}
179
180
// This is protected because the definition of a realm
181
// string is fixed
182
protected static boolean isValidRealmString(String name) {
183
if (name == null)
184
return false;
185
if (name.length() == 0)
186
return false;
187
for (int i = 0; i < name.length(); i++) {
188
if (name.charAt(i) == '/' ||
189
name.charAt(i) == '\0') {
190
return false;
191
}
192
}
193
return true;
194
}
195
196
/**
197
* Encodes a Realm object.
198
* @return the byte array of encoded KrbCredInfo object.
199
* @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
200
* @exception IOException if an I/O error occurs while reading encoded data.
201
*
202
*/
203
public byte[] asn1Encode() throws Asn1Exception, IOException {
204
DerOutputStream out = new DerOutputStream();
205
out.putDerValue(new KerberosString(this.realm).toDerValue());
206
return out.toByteArray();
207
}
208
209
210
/**
211
* Parse (unmarshal) a realm from a DER input stream. This form
212
* parsing might be used when expanding a value which is part of
213
* a constructed sequence and uses explicitly tagged type.
214
*
215
* @exception Asn1Exception on error.
216
* @param data the Der input stream value, which contains one or more marshaled value.
217
* @param explicitTag tag number.
218
* @param optional indicate if this data field is optional
219
* @return an instance of Realm.
220
*
221
*/
222
public static Realm parse(DerInputStream data, byte explicitTag, boolean optional)
223
throws Asn1Exception, IOException, RealmException {
224
if ((optional) && (((byte)data.peekByte() & (byte)0x1F) != explicitTag)) {
225
return null;
226
}
227
DerValue der = data.getDerValue();
228
if (explicitTag != (der.getTag() & (byte)0x1F)) {
229
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
230
} else {
231
DerValue subDer = der.getData().getDerValue();
232
return new Realm(subDer);
233
}
234
}
235
236
/**
237
* Returns an array of realms that may be traversed to obtain
238
* a TGT from the initiating realm cRealm to the target realm
239
* sRealm.
240
* <br>
241
* This method would read [capaths] to create a path, or generate a
242
* hierarchical path if [capaths] does not contain a sub-stanza for cRealm
243
* or the sub-stanza does not contain a tag for sRealm.
244
* <br>
245
* The returned list would never be null, and it always contains
246
* cRealm as the head entry. sRealm is not included as the tail.
247
*
248
* @param cRealm the initiating realm, not null
249
* @param sRealm the target realm, not null, not equals to cRealm
250
* @return array of realms including at least cRealm as the first
251
* element
252
*/
253
public static String[] getRealmsList(String cRealm, String sRealm) {
254
try {
255
// Try [capaths]
256
return parseCapaths(cRealm, sRealm);
257
} catch (KrbException ke) {
258
// Now assume the realms are organized hierarchically.
259
return parseHierarchy(cRealm, sRealm);
260
}
261
}
262
263
/**
264
* Parses the [capaths] stanza of the configuration file for a
265
* list of realms to traverse to obtain credentials from the
266
* initiating realm cRealm to the target realm sRealm.
267
*
268
* For a given client realm C there is a tag C in [capaths] whose
269
* subtag S has a value which is a (possibly partial) path from C
270
* to S. When the path is partial, it contains only the tail of the
271
* full path. Values of other subtags will be used to build the full
272
* path. The value "." means a direct path from C to S. If realm S
273
* does not appear as a subtag, there is no path defined here.
274
*
275
* The implementation ignores all values which equals to C or S, or
276
* a "." in multiple values, or any duplicated realm names.
277
*
278
* When a path value has more than two realms, they can be specified
279
* with multiple key-value pairs each having a single value, but the
280
* order must not change.
281
*
282
* For example:
283
*
284
* [capaths]
285
* TIVOLI.COM = {
286
* IBM.COM = IBM_LDAPCENTRAL.COM MOONLITE.ORG
287
* IBM_LDAPCENTRAL.COM = LDAPCENTRAL.NET
288
* LDAPCENTRAL.NET = .
289
* }
290
*
291
* TIVOLI.COM has a direct path to LDAPCENTRAL.NET, which has a direct
292
* path to IBM_LDAPCENTRAL.COM. It also has a partial path to IBM.COM
293
* being "IBM_LDAPCENTRAL.COM MOONLITE.ORG". Merging these info together,
294
* a full path from TIVOLI.COM to IBM.COM will be
295
*
296
* TIVOLI.COM -> LDAPCENTRAL.NET -> IBM_LDAPCENTRAL.COM
297
* -> IBM_LDAPCENTRAL.COM -> MOONLITE.ORG
298
*
299
* Please note the sRealm IBM.COM does not appear in the path.
300
*
301
* @param cRealm the initiating realm
302
* @param sRealm the target realm, not the same as cRealm
303
* @return array of realms including at least cRealm as the first
304
* element
305
* @throws KrbException if the config does not contain a sub-stanza
306
* for cRealm in [capaths] or the sub-stanza does not contain
307
* sRealm as a tag
308
*/
309
private static String[] parseCapaths(String cRealm, String sRealm)
310
throws KrbException {
311
312
// This line could throw a KrbException
313
Config cfg = Config.getInstance();
314
315
if (!cfg.exists("capaths", cRealm, sRealm)) {
316
throw new KrbException("No conf");
317
}
318
319
LinkedList<String> path = new LinkedList<>();
320
321
String head = sRealm;
322
while (true) {
323
String value = cfg.getAll("capaths", cRealm, head);
324
if (value == null) {
325
break;
326
}
327
String[] more = value.split("\\s+");
328
boolean changed = false;
329
for (int i=more.length-1; i>=0; i--) {
330
if (path.contains(more[i])
331
|| more[i].equals(".")
332
|| more[i].equals(cRealm)
333
|| more[i].equals(sRealm)
334
|| more[i].equals(head)) {
335
// Ignore invalid values
336
continue;
337
}
338
changed = true;
339
path.addFirst(more[i]);
340
}
341
if (!changed) break;
342
head = path.getFirst();
343
}
344
path.addFirst(cRealm);
345
return path.toArray(new String[path.size()]);
346
}
347
348
/**
349
* Build a list of realm that can be traversed
350
* to obtain credentials from the initiating realm cRealm
351
* for a service in the target realm sRealm.
352
* @param cRealm the initiating realm
353
* @param sRealm the target realm, not the same as cRealm
354
* @return array of realms including cRealm as the first element
355
*/
356
private static String[] parseHierarchy(String cRealm, String sRealm) {
357
358
String[] cComponents = cRealm.split("\\.");
359
String[] sComponents = sRealm.split("\\.");
360
361
int cPos = cComponents.length;
362
int sPos = sComponents.length;
363
364
boolean hasCommon = false;
365
for (sPos--, cPos--; sPos >=0 && cPos >= 0 &&
366
sComponents[sPos].equals(cComponents[cPos]);
367
sPos--, cPos--) {
368
hasCommon = true;
369
}
370
371
// For those with common components:
372
// length pos
373
// SITES1.SALES.EXAMPLE.COM 4 1
374
// EVERYWHERE.EXAMPLE.COM 3 0
375
376
// For those without common components:
377
// length pos
378
// DEVEL.EXAMPLE.COM 3 2
379
// PROD.EXAMPLE.ORG 3 2
380
381
LinkedList<String> path = new LinkedList<>();
382
383
// Un-common ones for client side
384
for (int i=0; i<=cPos; i++) {
385
path.addLast(subStringFrom(cComponents, i));
386
}
387
388
// Common one
389
if (hasCommon) {
390
path.addLast(subStringFrom(cComponents, cPos+1));
391
}
392
393
// Un-common ones for server side
394
for (int i=sPos; i>=0; i--) {
395
path.addLast(subStringFrom(sComponents, i));
396
}
397
398
// Remove sRealm from path. Note that it might be added at last loop
399
// or as a common component, if sRealm is a parent of cRealm
400
path.removeLast();
401
402
return path.toArray(new String[path.size()]);
403
}
404
405
/**
406
* Creates a realm name using components from the given position.
407
* For example, subStringFrom({"A", "B", "C"}, 1) is "B.C".
408
*/
409
private static String subStringFrom(String[] components, int from) {
410
StringBuilder sb = new StringBuilder();
411
for (int i=from; i<components.length; i++) {
412
if (sb.length() != 0) sb.append('.');
413
sb.append(components[i]);
414
}
415
return sb.toString();
416
}
417
}
418
419