001 /*
002 * Copyright 2008-2015 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2015 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk.unboundidds.controls;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Collection;
027
028 import com.unboundid.asn1.ASN1Boolean;
029 import com.unboundid.asn1.ASN1Element;
030 import com.unboundid.asn1.ASN1Exception;
031 import com.unboundid.asn1.ASN1OctetString;
032 import com.unboundid.asn1.ASN1Sequence;
033 import com.unboundid.ldap.sdk.Attribute;
034 import com.unboundid.ldap.sdk.BindResult;
035 import com.unboundid.ldap.sdk.Control;
036 import com.unboundid.ldap.sdk.DecodeableControl;
037 import com.unboundid.ldap.sdk.LDAPException;
038 import com.unboundid.ldap.sdk.ReadOnlyEntry;
039 import com.unboundid.ldap.sdk.ResultCode;
040 import com.unboundid.util.NotMutable;
041 import com.unboundid.util.ThreadSafety;
042 import com.unboundid.util.ThreadSafetyLevel;
043
044 import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
045 import static com.unboundid.util.Debug.*;
046 import static com.unboundid.util.StaticUtils.*;
047
048
049
050 /**
051 * <BLOCKQUOTE>
052 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID
053 * LDAP SDK for Java. It is not available for use in applications that
054 * include only the Standard Edition of the LDAP SDK, and is not supported for
055 * use in conjunction with non-UnboundID products.
056 * </BLOCKQUOTE>
057 * This class provides an implementation of an LDAP control that may be included
058 * in a bind response to provide information about the authenticated and/or
059 * authorized user. The value of this control will be encoded as follows:
060 * <PRE>
061 * GetAuthorizationEntryResponse ::= SEQUENCE {
062 * isAuthenticated [0] BOOLEAN,
063 * identitiesMatch [1] BOOLEAN,
064 * authNEntry [2] AuthEntry OPTIONAL,
065 * authZEntry [3] AuthEntry OPTIONAL }
066 *
067 * AuthEntry ::= SEQUENCE {
068 * authID [0] AuthzId OPTIONAL,
069 * authDN [1] LDAPDN,
070 * attributes [2] PartialAttributeList }
071 * </PRE>
072 * <BR><BR>
073 * See the documentation for the {@link GetAuthorizationEntryRequestControl}
074 * class for more information and an example demonstrating the use of these
075 * controls.
076 */
077 @NotMutable()
078 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
079 public final class GetAuthorizationEntryResponseControl
080 extends Control
081 implements DecodeableControl
082 {
083 /**
084 * The OID (1.3.6.1.4.1.30221.2.5.6) for the get authorization entry response
085 * control.
086 */
087 public static final String GET_AUTHORIZATION_ENTRY_RESPONSE_OID =
088 "1.3.6.1.4.1.30221.2.5.6";
089
090
091
092 /**
093 * The BER type for the {@code isAuthenticated} element.
094 */
095 private static final byte TYPE_IS_AUTHENTICATED = (byte) 0x80;
096
097
098
099 /**
100 * The BER type for the {@code identitiesMatch} element.
101 */
102 private static final byte TYPE_IDENTITIES_MATCH = (byte) 0x81;
103
104
105
106 /**
107 * The BER type for the {@code authNEntry} element.
108 */
109 private static final byte TYPE_AUTHN_ENTRY = (byte) 0xA2;
110
111
112
113 /**
114 * The BER type for the {@code authZEntry} element.
115 */
116 private static final byte TYPE_AUTHZ_ENTRY = (byte) 0xA3;
117
118
119
120 /**
121 * The BER type for the {@code authID} element.
122 */
123 private static final byte TYPE_AUTHID = (byte) 0x80;
124
125
126
127 /**
128 * The BER type for the {@code authDN} element.
129 */
130 private static final byte TYPE_AUTHDN = (byte) 0x81;
131
132
133
134 /**
135 * The BER type for the {@code attributesDN} element.
136 */
137 private static final byte TYPE_ATTRIBUTES= (byte) 0xA2;
138
139
140
141 /**
142 * The serial version UID for this serializable class.
143 */
144 private static final long serialVersionUID = -5443107150740697226L;
145
146
147
148 // Indicates whether the authentication and authorization identities are the
149 // same.
150 private final boolean identitiesMatch;
151
152 // Indicates whether the client is authenticated.
153 private final boolean isAuthenticated;
154
155 // The entry for the authentication identity, if available.
156 private final ReadOnlyEntry authNEntry;
157
158 // The entry for the authorization identity, if available.
159 private final ReadOnlyEntry authZEntry;
160
161 // The authID for the authentication identity, if available.
162 private final String authNID;
163
164 // The authID for the authorization identity, if available.
165 private final String authZID;
166
167
168
169 /**
170 * Creates a new empty control instance that is intended to be used only for
171 * decoding controls via the {@code DecodeableControl} interface.
172 */
173 GetAuthorizationEntryResponseControl()
174 {
175 isAuthenticated = false;
176 identitiesMatch = true;
177 authNEntry = null;
178 authNID = null;
179 authZEntry = null;
180 authZID = null;
181 }
182
183
184
185 /**
186 * Creates a new get authorization entry response control with the provided
187 * information.
188 *
189 * @param isAuthenticated Indicates whether the client is authenticated.
190 * @param identitiesMatch Indicates whether the authentication identity is
191 * the same as the authorization identity.
192 * @param authNID The string that may be used to reference the
193 * authentication identity. It may be {@code null}
194 * if information about the authentication identity
195 * is not to be included, or if the identifier should
196 * be derived from the DN.
197 * @param authNEntry The entry for the authentication identity. It may
198 * be {@code null} if the information about the
199 * authentication identity is not to be included.
200 * @param authZID The string that may be used to reference the
201 * authorization identity. It may be {@code null}
202 * if information about the authentication identity
203 * is not to be included, if the identifier should
204 * be derived from the DN, or if the authentication
205 * and authorization identities are the same.
206 * @param authZEntry The entry for the authentication identity. It may
207 * be {@code null} if the information about the
208 * authentication identity is not to be included, or
209 * if the authentication and authorization identities
210 * are the same.
211 */
212 public GetAuthorizationEntryResponseControl(final boolean isAuthenticated,
213 final boolean identitiesMatch, final String authNID,
214 final ReadOnlyEntry authNEntry, final String authZID,
215 final ReadOnlyEntry authZEntry)
216 {
217 super(GET_AUTHORIZATION_ENTRY_RESPONSE_OID, false,
218 encodeValue(isAuthenticated, identitiesMatch, authNID, authNEntry,
219 authZID, authZEntry));
220
221 this.isAuthenticated = isAuthenticated;
222 this.identitiesMatch = identitiesMatch;
223 this.authNID = authNID;
224 this.authNEntry = authNEntry;
225 this.authZID = authZID;
226 this.authZEntry = authZEntry;
227 }
228
229
230
231 /**
232 * Creates a new get authorization entry response control with the provided
233 * information.
234 *
235 * @param oid The OID for the control.
236 * @param isCritical Indicates whether the control should be marked
237 * critical.
238 * @param value The encoded value for the control. This may be
239 * {@code null} if no value was provided.
240 *
241 * @throws LDAPException If the provided control cannot be decoded as a get
242 * authorization entry response control.
243 */
244 public GetAuthorizationEntryResponseControl(final String oid,
245 final boolean isCritical,
246 final ASN1OctetString value)
247 throws LDAPException
248 {
249 super(oid, isCritical, value);
250
251 if (value == null)
252 {
253 throw new LDAPException(ResultCode.DECODING_ERROR,
254 ERR_GET_AUTHORIZATION_ENTRY_RESPONSE_NO_VALUE.get());
255 }
256
257 try
258 {
259 boolean isAuth = false;
260 boolean idsMatch = false;
261 String nID = null;
262 String zID = null;
263 ReadOnlyEntry nEntry = null;
264 ReadOnlyEntry zEntry = null;
265
266 final ASN1Element valElement = ASN1Element.decode(value.getValue());
267 for (final ASN1Element e :
268 ASN1Sequence.decodeAsSequence(valElement).elements())
269 {
270 switch (e.getType())
271 {
272 case TYPE_IS_AUTHENTICATED:
273 isAuth = ASN1Boolean.decodeAsBoolean(e).booleanValue();
274 break;
275 case TYPE_IDENTITIES_MATCH:
276 idsMatch = ASN1Boolean.decodeAsBoolean(e).booleanValue();
277 break;
278 case TYPE_AUTHN_ENTRY:
279 final Object[] nObjects = decodeAuthEntry(e);
280 nID = (String) nObjects[0];
281 nEntry = (ReadOnlyEntry) nObjects[1];
282 break;
283 case TYPE_AUTHZ_ENTRY:
284 final Object[] zObjects = decodeAuthEntry(e);
285 zID = (String) zObjects[0];
286 zEntry = (ReadOnlyEntry) zObjects[1];
287 break;
288 default:
289 throw new LDAPException(ResultCode.DECODING_ERROR,
290 ERR_GET_AUTHORIZATION_ENTRY_RESPONSE_INVALID_VALUE_TYPE.get(
291 toHex(e.getType())));
292 }
293 }
294
295 isAuthenticated = isAuth;
296 identitiesMatch = idsMatch;
297 authNID = nID;
298 authNEntry = nEntry;
299 authZID = zID;
300 authZEntry = zEntry;
301 }
302 catch (Exception e)
303 {
304 debugException(e);
305 throw new LDAPException(ResultCode.DECODING_ERROR,
306 ERR_GET_AUTHORIZATION_ENTRY_RESPONSE_CANNOT_DECODE_VALUE.get(
307 getExceptionMessage(e)), e);
308 }
309 }
310
311
312
313 /**
314 * {@inheritDoc}
315 */
316 public GetAuthorizationEntryResponseControl decodeControl(final String oid,
317 final boolean isCritical,
318 final ASN1OctetString value)
319 throws LDAPException
320 {
321 return new GetAuthorizationEntryResponseControl(oid, isCritical, value);
322 }
323
324
325
326 /**
327 * Extracts a get authorization entry response control from the provided
328 * result.
329 *
330 * @param result The result from which to retrieve the get authorization
331 * entry response control.
332 *
333 * @return The get authorization entry response control contained in the
334 * provided result, or {@code null} if the result did not contain a
335 * get authorization entry response control.
336 *
337 * @throws LDAPException If a problem is encountered while attempting to
338 * decode the get authorization entry response control
339 * contained in the provided result.
340 */
341 public static GetAuthorizationEntryResponseControl
342 get(final BindResult result)
343 throws LDAPException
344 {
345 final Control c =
346 result.getResponseControl(GET_AUTHORIZATION_ENTRY_RESPONSE_OID);
347 if (c == null)
348 {
349 return null;
350 }
351
352 if (c instanceof GetAuthorizationEntryResponseControl)
353 {
354 return (GetAuthorizationEntryResponseControl) c;
355 }
356 else
357 {
358 return new GetAuthorizationEntryResponseControl(c.getOID(),
359 c.isCritical(), c.getValue());
360 }
361 }
362
363
364
365 /**
366 * Encodes the provided information appropriately for use as the value of this
367 * control.
368 *
369 * @param isAuthenticated Indicates whether the client is authenticated.
370 * @param identitiesMatch Indicates whether the authentication identity is
371 * the same as the authorization identity.
372 * @param authNID The string that may be used to reference the
373 * authentication identity. It may be {@code null}
374 * if information about the authentication identity
375 * is not to be included, or if the identifier should
376 * be derived from the DN.
377 * @param authNEntry The entry for the authentication identity. It may
378 * be {@code null} if the information about the
379 * authentication identity is not to be included.
380 * @param authZID The string that may be used to reference the
381 * authorization identity. It may be {@code null}
382 * if information about the authentication identity
383 * is not to be included, if the identifier should
384 * be derived from the DN, or if the authentication
385 * and authorization identities are the same.
386 * @param authZEntry The entry for the authentication identity. It may
387 * be {@code null} if the information about the
388 * authentication identity is not to be included, or
389 * if the authentication and authorization identities
390 * are the same.
391 *
392 * @return The ASN.1 octet string suitable for use as the control value.
393 */
394 private static ASN1OctetString encodeValue(final boolean isAuthenticated,
395 final boolean identitiesMatch,
396 final String authNID,
397 final ReadOnlyEntry authNEntry,
398 final String authZID,
399 final ReadOnlyEntry authZEntry)
400 {
401 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(4);
402 elements.add(new ASN1Boolean(TYPE_IS_AUTHENTICATED, isAuthenticated));
403 elements.add(new ASN1Boolean(TYPE_IDENTITIES_MATCH, identitiesMatch));
404
405 if (authNEntry != null)
406 {
407 elements.add(encodeAuthEntry(TYPE_AUTHN_ENTRY, authNID, authNEntry));
408 }
409
410 if (authZEntry != null)
411 {
412 elements.add(encodeAuthEntry(TYPE_AUTHZ_ENTRY, authZID, authZEntry));
413 }
414
415 return new ASN1OctetString(new ASN1Sequence(elements).encode());
416 }
417
418
419
420 /**
421 * Encodes the provided information as appropriate for an auth entry.
422 *
423 * @param type The BER type to use for the element.
424 * @param authID The authID to be encoded, if available.
425 * @param authEntry The entry to be encoded.
426 *
427 * @return The ASN.1 sequence containing the encoded auth entry.
428 */
429 private static ASN1Sequence encodeAuthEntry(final byte type,
430 final String authID,
431 final ReadOnlyEntry authEntry)
432 {
433 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3);
434
435 if (authID != null)
436 {
437 elements.add(new ASN1OctetString(TYPE_AUTHID, authID));
438 }
439
440 elements.add(new ASN1OctetString(TYPE_AUTHDN, authEntry.getDN()));
441
442 final Collection<Attribute> attributes = authEntry.getAttributes();
443 final ArrayList<ASN1Element> attrElements =
444 new ArrayList<ASN1Element>(attributes.size());
445 for (final Attribute a : attributes)
446 {
447 attrElements.add(a.encode());
448 }
449 elements.add(new ASN1Sequence(TYPE_ATTRIBUTES, attrElements));
450
451 return new ASN1Sequence(type, elements);
452 }
453
454
455
456 /**
457 * Decodes the provided ASN.1 element into an array of auth entry elements.
458 * The first element of the array will be the auth ID, and the second element
459 * will be the read-only entry.
460 *
461 * @param element The element to decode.
462 *
463 * @return The decoded array of elements.
464 *
465 * @throws ASN1Exception If a problem occurs while performing ASN.1 parsing.
466 *
467 * @throws LDAPException If a problem occurs while performing LDAP parsing.
468 */
469 private static Object[] decodeAuthEntry(final ASN1Element element)
470 throws ASN1Exception, LDAPException
471 {
472 String authID = null;
473 String authDN = null;
474 final ArrayList<Attribute> attrs = new ArrayList<Attribute>();
475
476 for (final ASN1Element e :
477 ASN1Sequence.decodeAsSequence(element).elements())
478 {
479 switch (e.getType())
480 {
481 case TYPE_AUTHID:
482 authID = ASN1OctetString.decodeAsOctetString(e).stringValue();
483 break;
484 case TYPE_AUTHDN:
485 authDN = ASN1OctetString.decodeAsOctetString(e).stringValue();
486 break;
487 case TYPE_ATTRIBUTES:
488 for (final ASN1Element ae :
489 ASN1Sequence.decodeAsSequence(e).elements())
490 {
491 attrs.add(Attribute.decode(ASN1Sequence.decodeAsSequence(ae)));
492 }
493 break;
494 default:
495 throw new LDAPException(ResultCode.DECODING_ERROR,
496 ERR_GET_AUTHORIZATION_ENTRY_RESPONSE_INVALID_ENTRY_TYPE.get(
497 toHex(e.getType())));
498 }
499 }
500
501 return new Object[] { authID, new ReadOnlyEntry(authDN, attrs) };
502 }
503
504
505
506 /**
507 * Indicates whether the client is authenticated.
508 *
509 * @return {@code true} if the client is authenticated, or {@code false} if
510 * not.
511 */
512 public boolean isAuthenticated()
513 {
514 return isAuthenticated;
515 }
516
517
518
519 /**
520 * Indicates whether the authentication identity and the authorization
521 * identity reference the same user.
522 *
523 * @return {@code true} if both the authentication identity and the
524 * authorization identity reference the same user, or {@code false}
525 * if not.
526 */
527 public boolean identitiesMatch()
528 {
529 return identitiesMatch;
530 }
531
532
533
534 /**
535 * Retrieves the identifier that may be used to reference the authentication
536 * identity in the directory server, if it is available.
537 *
538 * @return The identifier that may be used to reference the authentication
539 * identity in the directory server, or {@code null} if it is not
540 * available.
541 */
542 public String getAuthNID()
543 {
544 if ((authNID == null) && identitiesMatch)
545 {
546 return authZID;
547 }
548
549 return authNID;
550 }
551
552
553
554 /**
555 * Retrieves the entry for the user specified as the authentication identity,
556 * if it is available.
557 *
558 * @return The entry for the user specified as the authentication identity,
559 * or {@code null} if it is not available.
560 */
561 public ReadOnlyEntry getAuthNEntry()
562 {
563 if ((authNEntry == null) && identitiesMatch)
564 {
565 return authZEntry;
566 }
567
568 return authNEntry;
569 }
570
571
572
573 /**
574 * Retrieves the identifier that may be used to reference the authorization
575 * identity in the directory server, if it is available.
576 *
577 * @return The identifier that may be used to reference the authorization
578 * identity in the directory server, or {@code null} if it is not
579 * available.
580 */
581 public String getAuthZID()
582 {
583 if ((authZID == null) && identitiesMatch)
584 {
585 return authNID;
586 }
587
588 return authZID;
589 }
590
591
592
593 /**
594 * Retrieves the entry for the user specified as the authorization identity,
595 * if it is available.
596 *
597 * @return The entry for the user specified as the authorization identity,
598 * or {@code null} if it is not available.
599 */
600 public ReadOnlyEntry getAuthZEntry()
601 {
602 if ((authZEntry == null) && identitiesMatch)
603 {
604 return authNEntry;
605 }
606
607 return authZEntry;
608 }
609
610
611
612 /**
613 * {@inheritDoc}
614 */
615 @Override()
616 public String getControlName()
617 {
618 return INFO_CONTROL_NAME_GET_AUTHORIZATION_ENTRY_RESPONSE.get();
619 }
620
621
622
623 /**
624 * {@inheritDoc}
625 */
626 @Override()
627 public void toString(final StringBuilder buffer)
628 {
629 buffer.append("GetAuthorizationEntryResponseControl(identitiesMatch=");
630 buffer.append(identitiesMatch);
631
632 if (authNID != null)
633 {
634 buffer.append(", authNID='");
635 buffer.append(authNID);
636 buffer.append('\'');
637 }
638
639 if (authNEntry != null)
640 {
641 buffer.append(", authNEntry=");
642 authNEntry.toString(buffer);
643 }
644
645 if (authZID != null)
646 {
647 buffer.append(", authZID='");
648 buffer.append(authZID);
649 buffer.append('\'');
650 }
651
652 if (authZEntry != null)
653 {
654 buffer.append(", authZEntry=");
655 authZEntry.toString(buffer);
656 }
657
658 buffer.append(')');
659 }
660 }