Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java
41161 views
1
/*
2
* Copyright (c) 1999, 2020, 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 com.sun.jndi.ldap;
27
28
import javax.naming.*;
29
import javax.naming.directory.*;
30
import javax.naming.spi.DirectoryManager;
31
import javax.naming.spi.DirStateFactory;
32
33
import java.io.IOException;
34
import java.io.ByteArrayInputStream;
35
import java.io.ByteArrayOutputStream;
36
import java.io.ObjectInputStream;
37
import java.io.ObjectOutputStream;
38
import java.io.ObjectStreamClass;
39
import java.io.InputStream;
40
41
import java.util.Base64;
42
import java.util.Hashtable;
43
import java.util.Vector;
44
import java.util.StringTokenizer;
45
46
import java.lang.reflect.Proxy;
47
import java.lang.reflect.Modifier;
48
49
/**
50
* Class containing static methods and constants for dealing with
51
* encoding/decoding JNDI References and Serialized Objects
52
* in LDAP.
53
* @author Vincent Ryan
54
* @author Rosanna Lee
55
*/
56
final class Obj {
57
58
private Obj () {}; // Make sure no one can create one
59
60
// package private; used by Connection
61
static VersionHelper helper = VersionHelper.getVersionHelper();
62
63
// LDAP attributes used to support Java objects.
64
static final String[] JAVA_ATTRIBUTES = {
65
"objectClass",
66
"javaSerializedData",
67
"javaClassName",
68
"javaFactory",
69
"javaCodeBase",
70
"javaReferenceAddress",
71
"javaClassNames",
72
"javaRemoteLocation" // Deprecated
73
};
74
75
static final int OBJECT_CLASS = 0;
76
static final int SERIALIZED_DATA = 1;
77
static final int CLASSNAME = 2;
78
static final int FACTORY = 3;
79
static final int CODEBASE = 4;
80
static final int REF_ADDR = 5;
81
static final int TYPENAME = 6;
82
/**
83
* @deprecated
84
*/
85
@Deprecated
86
private static final int REMOTE_LOC = 7;
87
88
// LDAP object classes to support Java objects
89
static final String[] JAVA_OBJECT_CLASSES = {
90
"javaContainer",
91
"javaObject",
92
"javaNamingReference",
93
"javaSerializedObject",
94
"javaMarshalledObject",
95
};
96
97
static final String[] JAVA_OBJECT_CLASSES_LOWER = {
98
"javacontainer",
99
"javaobject",
100
"javanamingreference",
101
"javaserializedobject",
102
"javamarshalledobject",
103
};
104
105
static final int STRUCTURAL = 0; // structural object class
106
static final int BASE_OBJECT = 1; // auxiliary java object class
107
static final int REF_OBJECT = 2; // auxiliary reference object class
108
static final int SER_OBJECT = 3; // auxiliary serialized object class
109
static final int MAR_OBJECT = 4; // auxiliary marshalled object class
110
111
/**
112
* Encode an object in LDAP attributes.
113
* Supports binding Referenceable or Reference, Serializable,
114
* and DirContext.
115
*
116
* If the object supports the Referenceable interface then encode
117
* the reference to the object. See encodeReference() for details.
118
*<p>
119
* If the object is serializable, it is stored as follows:
120
* javaClassName
121
* value: Object.getClass();
122
* javaSerializedData
123
* value: serialized form of Object (in binary form).
124
* javaTypeName
125
* value: getTypeNames(Object.getClass());
126
*/
127
private static Attributes encodeObject(char separator,
128
Object obj, Attributes attrs,
129
Attribute objectClass, boolean cloned)
130
throws NamingException {
131
boolean structural =
132
(objectClass.size() == 0 ||
133
(objectClass.size() == 1 && objectClass.contains("top")));
134
135
if (structural) {
136
objectClass.add(JAVA_OBJECT_CLASSES[STRUCTURAL]);
137
}
138
139
// References
140
if (obj instanceof Referenceable) {
141
objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
142
objectClass.add(JAVA_OBJECT_CLASSES[REF_OBJECT]);
143
if (!cloned) {
144
attrs = (Attributes)attrs.clone();
145
}
146
attrs.put(objectClass);
147
return (encodeReference(separator,
148
((Referenceable)obj).getReference(),
149
attrs, obj));
150
151
} else if (obj instanceof Reference) {
152
objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
153
objectClass.add(JAVA_OBJECT_CLASSES[REF_OBJECT]);
154
if (!cloned) {
155
attrs = (Attributes)attrs.clone();
156
}
157
attrs.put(objectClass);
158
return (encodeReference(separator, (Reference)obj, attrs, null));
159
160
// Serializable Object
161
} else if (obj instanceof java.io.Serializable) {
162
objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
163
if (!(objectClass.contains(JAVA_OBJECT_CLASSES[MAR_OBJECT]) ||
164
objectClass.contains(JAVA_OBJECT_CLASSES_LOWER[MAR_OBJECT]))) {
165
objectClass.add(JAVA_OBJECT_CLASSES[SER_OBJECT]);
166
}
167
if (!cloned) {
168
attrs = (Attributes)attrs.clone();
169
}
170
attrs.put(objectClass);
171
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[SERIALIZED_DATA],
172
serializeObject(obj)));
173
if (attrs.get(JAVA_ATTRIBUTES[CLASSNAME]) == null) {
174
attrs.put(JAVA_ATTRIBUTES[CLASSNAME],
175
obj.getClass().getName());
176
}
177
if (attrs.get(JAVA_ATTRIBUTES[TYPENAME]) == null) {
178
Attribute tAttr =
179
LdapCtxFactory.createTypeNameAttr(obj.getClass());
180
if (tAttr != null) {
181
attrs.put(tAttr);
182
}
183
}
184
// DirContext Object
185
} else if (obj instanceof DirContext) {
186
// do nothing
187
} else {
188
throw new IllegalArgumentException(
189
"can only bind Referenceable, Serializable, DirContext");
190
}
191
// System.err.println(attrs);
192
return attrs;
193
}
194
195
/**
196
* Each value in javaCodebase contains a list of space-separated
197
* URLs. Each value is independent; we can pick any of the values
198
* so we just use the first one.
199
* @return an array of URL strings for the codebase
200
*/
201
private static String[] getCodebases(Attribute codebaseAttr) throws
202
NamingException {
203
if (codebaseAttr == null) {
204
return null;
205
} else {
206
StringTokenizer parser =
207
new StringTokenizer((String)codebaseAttr.get());
208
Vector<String> vec = new Vector<>(10);
209
while (parser.hasMoreTokens()) {
210
vec.addElement(parser.nextToken());
211
}
212
String[] answer = new String[vec.size()];
213
for (int i = 0; i < answer.length; i++) {
214
answer[i] = vec.elementAt(i);
215
}
216
return answer;
217
}
218
}
219
220
/*
221
* Decode an object from LDAP attribute(s).
222
* The object may be a Reference, or a Serialized object.
223
*
224
* See encodeObject() and encodeReference() for details on formats
225
* expected.
226
*/
227
static Object decodeObject(Attributes attrs)
228
throws NamingException {
229
230
Attribute attr;
231
232
// Get codebase, which is used in all 3 cases.
233
String[] codebases = getCodebases(attrs.get(JAVA_ATTRIBUTES[CODEBASE]));
234
try {
235
if ((attr = attrs.get(JAVA_ATTRIBUTES[SERIALIZED_DATA])) != null) {
236
if (!VersionHelper.isSerialDataAllowed()) {
237
throw new NamingException("Object deserialization is not allowed");
238
}
239
ClassLoader cl = helper.getURLClassLoader(codebases);
240
return deserializeObject((byte[])attr.get(), cl);
241
} else if ((attr = attrs.get(JAVA_ATTRIBUTES[REMOTE_LOC])) != null) {
242
// For backward compatibility only
243
return decodeRmiObject(
244
(String)attrs.get(JAVA_ATTRIBUTES[CLASSNAME]).get(),
245
(String)attr.get(), codebases);
246
}
247
248
attr = attrs.get(JAVA_ATTRIBUTES[OBJECT_CLASS]);
249
if (attr != null &&
250
(attr.contains(JAVA_OBJECT_CLASSES[REF_OBJECT]) ||
251
attr.contains(JAVA_OBJECT_CLASSES_LOWER[REF_OBJECT]))) {
252
return decodeReference(attrs, codebases);
253
}
254
return null;
255
} catch (IOException e) {
256
NamingException ne = new NamingException();
257
ne.setRootCause(e);
258
throw ne;
259
}
260
}
261
262
/**
263
* Convert a Reference object into several LDAP attributes.
264
*
265
* A Reference is stored as into the following attributes:
266
* javaClassName
267
* value: Reference.getClassName();
268
* javaFactory
269
* value: Reference.getFactoryClassName();
270
* javaCodeBase
271
* value: Reference.getFactoryClassLocation();
272
* javaReferenceAddress
273
* value: #0#typeA#valA
274
* value: #1#typeB#valB
275
* value: #2#typeC##[serialized RefAddr C]
276
* value: #3#typeD#valD
277
*
278
* where
279
* - the first character denotes the separator
280
* - the number following the first separator denotes the position
281
* of the RefAddr within the Reference
282
* - "typeA" is RefAddr.getType()
283
* - ## denotes that the Base64-encoded form of the non-StringRefAddr
284
* is to follow; otherwise the value that follows is
285
* StringRefAddr.getContents()
286
*
287
* The default separator is the hash character (#).
288
* May provide property for this in future.
289
*/
290
291
private static Attributes encodeReference(char separator,
292
Reference ref, Attributes attrs, Object orig)
293
throws NamingException {
294
295
if (ref == null)
296
return attrs;
297
298
String s;
299
300
if ((s = ref.getClassName()) != null) {
301
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[CLASSNAME], s));
302
}
303
304
if ((s = ref.getFactoryClassName()) != null) {
305
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[FACTORY], s));
306
}
307
308
if ((s = ref.getFactoryClassLocation()) != null) {
309
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[CODEBASE], s));
310
}
311
312
// Get original object's types if caller has not explicitly
313
// specified other type names
314
if (orig != null && attrs.get(JAVA_ATTRIBUTES[TYPENAME]) != null) {
315
Attribute tAttr =
316
LdapCtxFactory.createTypeNameAttr(orig.getClass());
317
if (tAttr != null) {
318
attrs.put(tAttr);
319
}
320
}
321
322
int count = ref.size();
323
324
if (count > 0) {
325
326
Attribute refAttr = new BasicAttribute(JAVA_ATTRIBUTES[REF_ADDR]);
327
RefAddr refAddr;
328
Base64.Encoder encoder = null;
329
330
for (int i = 0; i < count; i++) {
331
refAddr = ref.get(i);
332
333
if (refAddr instanceof StringRefAddr) {
334
refAttr.add(""+ separator + i +
335
separator + refAddr.getType() +
336
separator + refAddr.getContent());
337
} else {
338
if (encoder == null)
339
encoder = Base64.getMimeEncoder();
340
341
refAttr.add(""+ separator + i +
342
separator + refAddr.getType() +
343
separator + separator +
344
encoder.encodeToString(serializeObject(refAddr)));
345
}
346
}
347
attrs.put(refAttr);
348
}
349
return attrs;
350
}
351
352
/*
353
* A RMI object is stored in the directory as
354
* javaClassName
355
* value: Object.getClass();
356
* javaRemoteLocation
357
* value: URL of RMI object (accessed through the RMI Registry)
358
* javaCodebase:
359
* value: URL of codebase of where to find classes for object
360
*
361
* Return the RMI Location URL itself. This will be turned into
362
* an RMI object when getObjectInstance() is called on it.
363
* %%% Ignore codebase for now. Depend on RMI registry to send code.-RL
364
* @deprecated For backward compatibility only
365
*/
366
private static Object decodeRmiObject(String className,
367
String rmiName, String[] codebases) throws NamingException {
368
return new Reference(className, new StringRefAddr("URL", rmiName));
369
}
370
371
/*
372
* Restore a Reference object from several LDAP attributes
373
*/
374
private static Reference decodeReference(Attributes attrs,
375
String[] codebases) throws NamingException, IOException {
376
377
Attribute attr;
378
String className;
379
String factory = null;
380
381
if ((attr = attrs.get(JAVA_ATTRIBUTES[CLASSNAME])) != null) {
382
className = (String)attr.get();
383
} else {
384
throw new InvalidAttributesException(JAVA_ATTRIBUTES[CLASSNAME] +
385
" attribute is required");
386
}
387
388
if ((attr = attrs.get(JAVA_ATTRIBUTES[FACTORY])) != null) {
389
factory = (String)attr.get();
390
}
391
392
Reference ref = new Reference(className, factory,
393
(codebases != null? codebases[0] : null));
394
395
/*
396
* string encoding of a RefAddr is either:
397
*
398
* #posn#<type>#<address>
399
* or
400
* #posn#<type>##<base64-encoded address>
401
*/
402
if ((attr = attrs.get(JAVA_ATTRIBUTES[REF_ADDR])) != null) {
403
404
String val, posnStr, type;
405
char separator;
406
int start, sep, posn;
407
Base64.Decoder decoder = null;
408
409
ClassLoader cl = helper.getURLClassLoader(codebases);
410
411
/*
412
* Temporary Vector for decoded RefAddr addresses - used to ensure
413
* unordered addresses are correctly re-ordered.
414
*/
415
Vector<RefAddr> refAddrList = new Vector<>();
416
refAddrList.setSize(attr.size());
417
418
for (NamingEnumeration<?> vals = attr.getAll(); vals.hasMore(); ) {
419
420
val = (String)vals.next();
421
422
if (val.length() == 0) {
423
throw new InvalidAttributeValueException(
424
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - "+
425
"empty attribute value");
426
}
427
// first character denotes encoding separator
428
separator = val.charAt(0);
429
start = 1; // skip over separator
430
431
// extract position within Reference
432
if ((sep = val.indexOf(separator, start)) < 0) {
433
throw new InvalidAttributeValueException(
434
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
435
"separator '" + separator + "'" + "not found");
436
}
437
if ((posnStr = val.substring(start, sep)) == null) {
438
throw new InvalidAttributeValueException(
439
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
440
"empty RefAddr position");
441
}
442
try {
443
posn = Integer.parseInt(posnStr);
444
} catch (NumberFormatException nfe) {
445
throw new InvalidAttributeValueException(
446
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
447
"RefAddr position not an integer");
448
}
449
start = sep + 1; // skip over position and trailing separator
450
451
// extract type
452
if ((sep = val.indexOf(separator, start)) < 0) {
453
throw new InvalidAttributeValueException(
454
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
455
"RefAddr type not found");
456
}
457
if ((type = val.substring(start, sep)) == null) {
458
throw new InvalidAttributeValueException(
459
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
460
"empty RefAddr type");
461
}
462
start = sep + 1; // skip over type and trailing separator
463
464
// extract content
465
if (start == val.length()) {
466
// Empty content
467
refAddrList.setElementAt(new StringRefAddr(type, null), posn);
468
} else if (val.charAt(start) == separator) {
469
// Double separators indicate a non-StringRefAddr
470
// Content is a Base64-encoded serialized RefAddr
471
472
++start; // skip over consecutive separator
473
// %%% RL: exception if empty after double separator
474
475
if (decoder == null)
476
decoder = Base64.getMimeDecoder();
477
478
RefAddr ra = (RefAddr)
479
deserializeObject(
480
decoder.decode(val.substring(start).getBytes()),
481
cl);
482
483
refAddrList.setElementAt(ra, posn);
484
} else {
485
// Single separator indicates a StringRefAddr
486
refAddrList.setElementAt(new StringRefAddr(type,
487
val.substring(start)), posn);
488
}
489
}
490
491
// Copy to real reference
492
for (int i = 0; i < refAddrList.size(); i++) {
493
ref.add(refAddrList.elementAt(i));
494
}
495
}
496
497
return (ref);
498
}
499
500
/*
501
* Serialize an object into a byte array
502
*/
503
private static byte[] serializeObject(Object obj) throws NamingException {
504
505
try {
506
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
507
try (ObjectOutputStream serial = new ObjectOutputStream(bytes)) {
508
serial.writeObject(obj);
509
}
510
511
return (bytes.toByteArray());
512
513
} catch (IOException e) {
514
NamingException ne = new NamingException();
515
ne.setRootCause(e);
516
throw ne;
517
}
518
}
519
520
/*
521
* Deserializes a byte array into an object.
522
*/
523
private static Object deserializeObject(byte[] obj, ClassLoader cl)
524
throws NamingException {
525
526
try {
527
// Create ObjectInputStream for deserialization
528
ByteArrayInputStream bytes = new ByteArrayInputStream(obj);
529
try (ObjectInputStream deserial = cl == null ?
530
new ObjectInputStream(bytes) :
531
new LoaderInputStream(bytes, cl)) {
532
return deserial.readObject();
533
} catch (ClassNotFoundException e) {
534
NamingException ne = new NamingException();
535
ne.setRootCause(e);
536
throw ne;
537
}
538
} catch (IOException e) {
539
NamingException ne = new NamingException();
540
ne.setRootCause(e);
541
throw ne;
542
}
543
}
544
545
/**
546
* Returns the attributes to bind given an object and its attributes.
547
*/
548
static Attributes determineBindAttrs(
549
char separator, Object obj, Attributes attrs, boolean cloned,
550
Name name, Context ctx, Hashtable<?,?> env)
551
throws NamingException {
552
553
// Call state factories to convert object and attrs
554
DirStateFactory.Result res =
555
DirectoryManager.getStateToBind(obj, name, ctx, env, attrs);
556
obj = res.getObject();
557
attrs = res.getAttributes();
558
559
// We're only storing attributes; no further processing required
560
if (obj == null) {
561
return attrs;
562
}
563
564
//if object to be bound is a DirContext extract its attributes
565
if ((attrs == null) && (obj instanceof DirContext)) {
566
cloned = true;
567
attrs = ((DirContext)obj).getAttributes("");
568
}
569
570
boolean ocNeedsCloning = false;
571
572
// Create "objectClass" attribute
573
Attribute objectClass;
574
if (attrs == null || attrs.size() == 0) {
575
attrs = new BasicAttributes(LdapClient.caseIgnore);
576
cloned = true;
577
578
// No objectclasses supplied, use "top" to start
579
objectClass = new BasicAttribute("objectClass", "top");
580
581
} else {
582
// Get existing objectclass attribute
583
objectClass = attrs.get("objectClass");
584
if (objectClass == null && !attrs.isCaseIgnored()) {
585
// %%% workaround
586
objectClass = attrs.get("objectclass");
587
}
588
589
// No objectclasses supplied, use "top" to start
590
if (objectClass == null) {
591
objectClass = new BasicAttribute("objectClass", "top");
592
} else if (ocNeedsCloning || !cloned) {
593
objectClass = (Attribute)objectClass.clone();
594
}
595
}
596
597
// convert the supplied object into LDAP attributes
598
attrs = encodeObject(separator, obj, attrs, objectClass, cloned);
599
600
// System.err.println("Determined: " + attrs);
601
return attrs;
602
}
603
604
/**
605
* An ObjectInputStream that uses a class loader to find classes.
606
*/
607
private static final class LoaderInputStream extends ObjectInputStream {
608
private ClassLoader classLoader;
609
610
LoaderInputStream(InputStream in, ClassLoader cl) throws IOException {
611
super(in);
612
classLoader = cl;
613
}
614
615
protected Class<?> resolveClass(ObjectStreamClass desc) throws
616
IOException, ClassNotFoundException {
617
try {
618
// %%% Should use Class.forName(desc.getName(), false, classLoader);
619
// except we can't because that is only available on JDK1.2
620
return classLoader.loadClass(desc.getName());
621
} catch (ClassNotFoundException e) {
622
return super.resolveClass(desc);
623
}
624
}
625
626
protected Class<?> resolveProxyClass(String[] interfaces) throws
627
IOException, ClassNotFoundException {
628
ClassLoader nonPublicLoader = null;
629
boolean hasNonPublicInterface = false;
630
631
// define proxy in class loader of non-public interface(s), if any
632
Class<?>[] classObjs = new Class<?>[interfaces.length];
633
for (int i = 0; i < interfaces.length; i++) {
634
Class<?> cl = Class.forName(interfaces[i], false, classLoader);
635
if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
636
if (hasNonPublicInterface) {
637
if (nonPublicLoader != cl.getClassLoader()) {
638
throw new IllegalAccessError(
639
"conflicting non-public interface class loaders");
640
}
641
} else {
642
nonPublicLoader = cl.getClassLoader();
643
hasNonPublicInterface = true;
644
}
645
}
646
classObjs[i] = cl;
647
}
648
try {
649
@SuppressWarnings("deprecation")
650
Class<?> proxyClass = Proxy.getProxyClass(hasNonPublicInterface ?
651
nonPublicLoader : classLoader, classObjs);
652
return proxyClass;
653
} catch (IllegalArgumentException e) {
654
throw new ClassNotFoundException(null, e);
655
}
656
}
657
658
}
659
}
660
661