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