mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

matthew_swift
15.58.2009 388f25a9dc58704ea19a333ba9a28054d48590b1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
 
package org.opends.sdk;
 
 
 
import java.util.Collection;
import java.util.Collections;
 
import org.opends.sdk.requests.Requests;
import org.opends.sdk.requests.SearchRequest;
import org.opends.sdk.responses.SearchResultEntry;
import org.opends.sdk.schema.CoreSchema;
 
import com.sun.opends.sdk.util.*;
 
 
 
/**
 * The root DSE is a DSA-specific Entry (DSE) and not part of any naming
 * context (or any subtree), and which is uniquely identified by the
 * empty DN.
 * <p>
 * A Directory Server uses the root DSE to provide information about
 * itself using the following set of attributes:
 * <ul>
 * <li>{@code altServer}: alternative Directory Servers
 * <li>{@code namingContexts}: naming contexts
 * <li>{@code supportedControl}: recognized LDAP controls
 * <li>{@code supportedExtension}: recognized LDAP extended operations
 * <li>{@code supportedFeatures}: recognized LDAP features
 * <li>{@code supportedLDAPVersion}: LDAP versions supported
 * <li>{@code supportedSASLMechanisms}: recognized SASL authentication
 * mechanisms
 * <li>{@code supportedAuthPasswordSchemes}: recognized authentication
 * password schemes
 * <li>{@code subschemaSubentry}: the name of the subschema subentry
 * holding the schema controlling the Root DSE
 * <li>{@code vendorName}: the name of the Directory Server implementer
 * <li>{@code vendorVersion}: the version of the Directory Server
 * implementation.
 * </ul>
 * The values provided for these attributes may depend on session-
 * specific and other factors. For example, a server supporting the SASL
 * EXTERNAL mechanism might only list "EXTERNAL" when the client's
 * identity has been established by a lower level.
 * <p>
 * The root DSE may also include a {@code subschemaSubentry} attribute.
 * If it does, the attribute refers to the subschema (sub)entry holding
 * the schema controlling the root DSE. Clients SHOULD NOT assume that
 * this subschema (sub)entry controls other entries held by the server.
 *
 * @see <a href="http://tools.ietf.org/html/rfc4512">RFC 4512 -
 *      Lightweight Directory Access Protocol (LDAP): Directory
 *      Information Models </a>
 * @see <a href="http://tools.ietf.org/html/rfc3045">RFC 3045 - Storing
 *      Vendor Information in the LDAP Root DSE </a>
 * @see <a href="http://tools.ietf.org/html/rfc3112">RFC 3112 - LDAP
 *      Authentication Password Schema </a>
 */
public final class RootDSE
{
  private static final AttributeDescription ATTR_ALT_SERVER = AttributeDescription
      .create(CoreSchema.getAltServerAttributeType());
 
  private static final AttributeDescription ATTR_NAMING_CONTEXTS = AttributeDescription
      .create(CoreSchema.getNamingContextsAttributeType());
 
  private static final AttributeDescription ATTR_SUPPORTED_CONTROL = AttributeDescription
      .create(CoreSchema.getSupportedControlAttributeType());
 
  private static final AttributeDescription ATTR_SUPPORTED_EXTENSION = AttributeDescription
      .create(CoreSchema.getSupportedExtensionAttributeType());
 
  private static final AttributeDescription ATTR_SUPPORTED_FEATURE = AttributeDescription
      .create(CoreSchema.getSupportedFeaturesAttributeType());
 
  private static final AttributeDescription ATTR_SUPPORTED_LDAP_VERSION = AttributeDescription
      .create(CoreSchema.getSupportedLDAPVersionAttributeType());
 
  private static final AttributeDescription ATTR_SUPPORTED_SASL_MECHANISMS = AttributeDescription
      .create(CoreSchema.getSupportedSASLMechanismsAttributeType());
 
  private static final AttributeDescription ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES = AttributeDescription
      .create(CoreSchema.getSupportedAuthPasswordSchemesAttributeType());
 
  private static final AttributeDescription ATTR_SUBSCHEMA_SUBENTRY = AttributeDescription
      .create(CoreSchema.getSubschemaSubentryAttributeType());
 
  private static final AttributeDescription ATTR_VENDOR_NAME = AttributeDescription
      .create(CoreSchema.getVendorNameAttributeType());
 
  private static final AttributeDescription ATTR_VENDOR_VERSION = AttributeDescription
      .create(CoreSchema.getVendorNameAttributeType());
 
  private static final SearchRequest SEARCH_REQUEST = Requests
      .newSearchRequest(DN.rootDN(), SearchScope.BASE_OBJECT, Filter
          .getObjectClassPresentFilter(), ATTR_ALT_SERVER.toString(),
          ATTR_NAMING_CONTEXTS.toString(), ATTR_SUPPORTED_CONTROL
              .toString(), ATTR_SUPPORTED_EXTENSION.toString(),
          ATTR_SUPPORTED_FEATURE.toString(),
          ATTR_SUPPORTED_LDAP_VERSION.toString(),
          ATTR_SUPPORTED_SASL_MECHANISMS.toString(), ATTR_VENDOR_NAME
              .toString(), ATTR_VENDOR_VERSION.toString(),
          ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES.toString(),
          ATTR_SUBSCHEMA_SUBENTRY.toString(), "*");
 
 
 
  /**
   * Reads the Root DSE from the Directory Server using the provided
   * connection.
   * <p>
   * If the Root DSE is not returned by the Directory Server then the
   * request will fail with an {@link EntryNotFoundException}. More
   * specifically, the returned future will never return {@code null}.
   *
   * @param connection
   *          A connection to the Directory Server whose Root DSE is to
   *          be read.
   * @param handler
   *          A result handler which can be used to asynchronously
   *          process the operation result when it is received, may be
   *          {@code null}.
   * @return A future representing the result of the operation.
   * @throws UnsupportedOperationException
   *           If the connection does not support search operations.
   * @throws IllegalStateException
   *           If the connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code connection} was {@code null}.
   */
  public static FutureResult<RootDSE> readRootDSE(
      AsynchronousConnection connection,
      ResultHandler<RootDSE> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    final FutureResultTransformer<SearchResultEntry, RootDSE> future =
      new FutureResultTransformer<SearchResultEntry, RootDSE>(handler)
    {
 
      protected RootDSE transformResult(SearchResultEntry result)
          throws ErrorResultException
      {
        return new RootDSE(result);
      }
 
    };
 
    FutureResult<SearchResultEntry> innerFuture = connection
        .searchSingleEntry(SEARCH_REQUEST, future);
    future.setFutureResult(innerFuture);
    return future;
  }
 
 
 
  /**
   * Reads the Root DSE from the Directory Server using the provided
   * connection.
   * <p>
   * If the Root DSE is not returned by the Directory Server then the
   * request will fail with an {@link EntryNotFoundException}. More
   * specifically, this method will never return {@code null}.
   *
   * @param connection
   *          A connection to the Directory Server whose Root DSE is to
   *          be read.
   * @return The Directory Server's Root DSE.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If the connection does not support search operations.
   * @throws IllegalStateException
   *           If the connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code connection} was {@code null}.
   */
  public static RootDSE readRootDSE(Connection connection)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    final Entry entry = connection.searchSingleEntry(SEARCH_REQUEST);
    return new RootDSE(entry);
  }
 
 
 
  private final Entry entry;
 
 
 
  /**
   * Creates a new Root DSE instance backed by the provided entry.
   * Modifications made to {@code entry} will be reflected in the
   * returned Root DSE. The returned Root DSE instance is unmodifiable
   * and attempts to use modify any of the returned collections will
   * result in a {@code UnsupportedOperationException}.
   *
   * @param entry
   *          The Root DSE entry.
   * @throws NullPointerException
   *           If {@code entry} was {@code null} .
   */
  public RootDSE(Entry entry) throws NullPointerException
  {
    Validator.ensureNotNull(entry);
    this.entry = entry;
  }
 
 
 
  /**
   * Returns an unmodifiable list of URIs referring to alternative
   * Directory Servers that may be contacted when the Directory Server
   * becomes unavailable.
   * <p>
   * URIs for Directory Servers implementing the LDAP protocol are
   * written according to RFC 4516. Other kinds of URIs may be provided.
   * <p>
   * If the Directory Server does not know of any other Directory
   * Servers that could be used, the returned list will be empty.
   *
   * @return An unmodifiable list of URIs referring to alternative
   *         Directory Servers, which may be empty.
   * @see <a href="http://tools.ietf.org/html/rfc4516">RFC 4516 -
   *      Lightweight Directory Access Protocol (LDAP): Uniform Resource
   *      Locator </a>
   */
  public Collection<String> getAlternativeServers()
  {
    return getMultiValuedAttribute(ATTR_ALT_SERVER, Functions
        .valueToString());
  }
 
 
 
  /**
   * Returns an unmodifiable list of DNs identifying the context
   * prefixes of the naming contexts that the Directory Server masters
   * or shadows (in part or in whole).
   * <p>
   * If the Directory Server does not master or shadow any naming
   * contexts, the returned list will be empty.
   *
   * @return An unmodifiable list of DNs identifying the context
   *         prefixes of the naming contexts, which may be empty.
   */
  public Collection<String> getNamingContexts()
  {
    return getMultiValuedAttribute(
        ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES, Functions.valueToString());
  }
 
 
 
  /**
   * Returns a string which represents the DN of the subschema subentry
   * holding the schema controlling the Root DSE.
   * <p>
   * Clients SHOULD NOT assume that this subschema (sub)entry controls
   * other entries held by the Directory Server.
   *
   * @return The DN of the subschema subentry holding the schema
   *         controlling the Root DSE, or {@code null} if the DN is not
   *         provided.
   */
  public String getSubschemaSubentry()
  {
    return getSingleValuedAttribute(ATTR_SUBSCHEMA_SUBENTRY);
  }
 
 
 
  /**
   * Returns an unmodifiable list of supported authentication password
   * schemes which the Directory Server supports.
   * <p>
   * If the Directory Server does not support any authentication
   * password schemes, the returned list will be empty.
   *
   * @return An unmodifiable list of supported authentication password
   *         schemes, which may be empty.
   * @see <a href="http://tools.ietf.org/html/rfc3112">RFC 3112 - LDAP
   *      Authentication Password Schema </a>
   */
  public Collection<String> getSupportedAuthenticationPasswordSchemes()
  {
    return getMultiValuedAttribute(
        ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES, Functions.valueToString());
  }
 
 
 
  /**
   * Returns an unmodifiable list of object identifiers identifying the
   * request controls that the Directory Server supports.
   * <p>
   * If the Directory Server does not support any request controls, the
   * returned list will be empty. Object identifiers identifying
   * response controls may not be listed.
   *
   * @return An unmodifiable list of object identifiers identifying the
   *         request controls, which may be empty.
   */
  public Collection<String> getSupportedControls()
  {
    return getMultiValuedAttribute(ATTR_SUPPORTED_CONTROL, Functions
        .valueToString());
  }
 
 
 
  /**
   * Returns an unmodifiable list of object identifiers identifying the
   * extended operations that the Directory Server supports.
   * <p>
   * If the Directory Server does not support any extended operations,
   * the returned list will be empty.
   * <p>
   * An extended operation generally consists of an extended request and
   * an extended response but may also include other protocol data units
   * (such as intermediate responses). The object identifier assigned to
   * the extended request is used to identify the extended operation.
   * Other object identifiers used in the extended operation may not be
   * listed as values of this attribute.
   *
   * @return An unmodifiable list of object identifiers identifying the
   *         extended operations, which may be empty.
   */
  public Collection<String> getSupportedExtendedOperations()
  {
    return getMultiValuedAttribute(ATTR_SUPPORTED_EXTENSION, Functions
        .valueToString());
  }
 
 
 
  /**
   * Returns an unmodifiable list of object identifiers identifying
   * elective features that the Directory Server supports.
   * <p>
   * If the server does not support any discoverable elective features,
   * the returned list will be empty.
   *
   * @return An unmodifiable list of object identifiers identifying the
   *         elective features, which may be empty.
   */
  public Collection<String> getSupportedFeatures()
  {
    return getMultiValuedAttribute(ATTR_SUPPORTED_FEATURE, Functions
        .valueToString());
  }
 
 
 
  /**
   * Returns an unmodifiable list of the versions of LDAP that the
   * Directory Server supports.
   *
   * @return An unmodifiable list of the versions.
   */
  public Collection<Integer> getSupportedLDAPVersions()
  {
    return getMultiValuedAttribute(ATTR_SUPPORTED_LDAP_VERSION,
        Functions.valueToInteger());
  }
 
 
 
  /**
   * Returns an unmodifiable list of the SASL mechanisms that the
   * Directory Server recognizes and/or supports.
   * <p>
   * The contents of the returned list may depend on the current session
   * state and may be empty if the Directory Server does not support any
   * SASL mechanisms.
   *
   * @return An unmodifiable list of the SASL mechanisms, which may be
   *         empty.
   * @see <a href="http://tools.ietf.org/html/rfc4513">RFC 4513 -
   *      Lightweight Directory Access Protocol (LDAP): Authentication
   *      Methods and Security Mechanisms </a>
   * @see <a href="http://tools.ietf.org/html/rfc4422">RFC 4422 - Simple
   *      Authentication and Security Layer (SASL) </a>
   */
  public Collection<String> getSupportedSASLMechanisms()
  {
    return getMultiValuedAttribute(ATTR_SUPPORTED_SASL_MECHANISMS,
        Functions.valueToString());
  }
 
 
 
  /**
   * Returns a string which represents the name of the Directory Server
   * implementer.
   *
   * @return The name of the Directory Server implementer, or {@code
   *         null} if the vendor name is not provided.
   * @see <a href="http://tools.ietf.org/html/rfc3045">RFC 3045 -
   *      Storing Vendor Information in the LDAP Root DSE </a>
   */
  public String getVendorName()
  {
    return getSingleValuedAttribute(ATTR_VENDOR_NAME);
  }
 
 
 
  /**
   * Returns a string which represents the version of the Directory
   * Server implementation.
   * <p>
   * Note that this value is typically a release value comprised of a
   * string and/or a string of numbers used by the developer of the LDAP
   * server product. The returned string will be unique between two
   * versions of the Directory Server, but there are no other syntactic
   * restrictions on the value or the way it is formatted.
   *
   * @return The version of the Directory Server implementation, or
   *         {@code null} if the vendor version is not provided.
   * @see <a href="http://tools.ietf.org/html/rfc3045">RFC 3045 -
   *      Storing Vendor Information in the LDAP Root DSE </a>
   */
  public String getVendorVersion()
  {
    return getSingleValuedAttribute(ATTR_VENDOR_VERSION);
  }
 
 
 
  private <N> Collection<N> getMultiValuedAttribute(
      AttributeDescription attributeDescription,
      Function<ByteString, N, Void> function)
  {
    // The returned collection is unmodifiable because we may need to
    // return an empty collection if the attribute does not exist in the
    // underlying entry. If a value is then added to the returned empty
    // collection it would require that an attribute is created in the
    // underlying entry in order to maintain consistency.
    final Attribute attr = entry.getAttribute(attributeDescription);
    if (attr != null)
    {
      return Collections.unmodifiableCollection(Collections2.transform(
          attr, function, Functions.objectToByteString()));
    }
    else
    {
      return Collections.emptySet();
    }
  }
 
 
 
  private String getSingleValuedAttribute(
      AttributeDescription attributeDescription)
  {
    final Attribute attr = entry.getAttribute(attributeDescription);
    if (attr == null || attr.isEmpty())
    {
      return null;
    }
    else
    {
      return attr.firstValueAsString();
    }
  }
 
}