001/* 002 * Copyright 2008-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-2019 Ping Identity Corporation 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 */ 021package com.unboundid.ldap.sdk.unboundidds.controls; 022 023 024 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.Collections; 028import java.util.Iterator; 029import java.util.List; 030 031import com.unboundid.asn1.ASN1Boolean; 032import com.unboundid.asn1.ASN1Element; 033import com.unboundid.asn1.ASN1OctetString; 034import com.unboundid.asn1.ASN1Sequence; 035import com.unboundid.ldap.sdk.Control; 036import com.unboundid.ldap.sdk.LDAPException; 037import com.unboundid.ldap.sdk.ResultCode; 038import com.unboundid.util.Debug; 039import com.unboundid.util.NotMutable; 040import com.unboundid.util.StaticUtils; 041import com.unboundid.util.ThreadSafety; 042import com.unboundid.util.ThreadSafetyLevel; 043 044import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 045 046 047 048/** 049 * This class provides an implementation of an LDAP control that can be included 050 * in a bind request to request that the Directory Server return the 051 * authentication and authorization entries for the user that authenticated. 052 * <BR> 053 * <BLOCKQUOTE> 054 * <B>NOTE:</B> This class, and other classes within the 055 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 056 * supported for use against Ping Identity, UnboundID, and 057 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 058 * for proprietary functionality or for external specifications that are not 059 * considered stable or mature enough to be guaranteed to work in an 060 * interoperable way with other types of LDAP servers. 061 * </BLOCKQUOTE> 062 * <BR> 063 * The value of this control may be absent, but if it is present then will be 064 * encoded as follows: 065 * <PRE> 066 * GetAuthorizationEntryRequest ::= SEQUENCE { 067 * includeAuthNEntry [0] BOOLEAN DEFAULT TRUE, 068 * includeAuthZEntry [1] BOOLEAN DEFAULT TRUE, 069 * attributes [2] AttributeSelection OPTIONAL } 070 * </PRE> 071 * <BR><BR> 072 * <H2>Example</H2> 073 * The following example demonstrates the process for processing a bind 074 * operation using the get authorization entry request control to return all 075 * user attributes in both the authentication and authorization entries: 076 * <PRE> 077 * ReadOnlyEntry authNEntry = null; 078 * ReadOnlyEntry authZEntry = null; 079 * 080 * BindRequest bindRequest = new SimpleBindRequest( 081 * "uid=john.doe,ou=People,dc=example,dc=com", "password", 082 * new GetAuthorizationEntryRequestControl()); 083 * 084 * BindResult bindResult = connection.bind(bindRequest); 085 * GetAuthorizationEntryResponseControl c = 086 * GetAuthorizationEntryResponseControl.get(bindResult); 087 * if (c != null) 088 * { 089 * authNEntry = c.getAuthNEntry(); 090 * authZEntry = c.getAuthZEntry(); 091 * } 092 * </PRE> 093 */ 094@NotMutable() 095@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 096public final class GetAuthorizationEntryRequestControl 097 extends Control 098{ 099 /** 100 * The OID (1.3.6.1.4.1.30221.2.5.6) for the get authorization entry request 101 * control. 102 */ 103 public static final String GET_AUTHORIZATION_ENTRY_REQUEST_OID = 104 "1.3.6.1.4.1.30221.2.5.6"; 105 106 107 108 /** 109 * The BER type for the {@code includeAuthNEntry} element. 110 */ 111 private static final byte TYPE_INCLUDE_AUTHN_ENTRY = (byte) 0x80; 112 113 114 115 /** 116 * The BER type for the {@code includeAuthZEntry} element. 117 */ 118 private static final byte TYPE_INCLUDE_AUTHZ_ENTRY = (byte) 0x81; 119 120 121 122 /** 123 * The BER type for the {@code attributes} element. 124 */ 125 private static final byte TYPE_ATTRIBUTES = (byte) 0xA2; 126 127 128 129 /** 130 * The serial version UID for this serializable class. 131 */ 132 private static final long serialVersionUID = -5540345171260624216L; 133 134 135 136 // Indicates whether to include the authentication entry in the response. 137 private final boolean includeAuthNEntry; 138 139 // Indicates whether to include the authorization entry in the response. 140 private final boolean includeAuthZEntry; 141 142 // The list of attributes to include in entries that are returned. 143 private final List<String> attributes; 144 145 146 147 /** 148 * Creates a new get authorization entry request control that will request all 149 * user attributes in both the authentication and authorization entries. It 150 * will not be marked critical. 151 */ 152 public GetAuthorizationEntryRequestControl() 153 { 154 this(false, true, true, (List<String>) null); 155 } 156 157 158 159 /** 160 * Creates a new get authorization entry request control with the provided 161 * information. 162 * 163 * @param includeAuthNEntry Indicates whether to include the authentication 164 * entry in the response. 165 * @param includeAuthZEntry Indicates whether to include the authorization 166 * entry in the response. 167 * @param attributes The attributes to include in the entries in the 168 * response. It may be empty or {@code null} to 169 * request all user attributes. 170 */ 171 public GetAuthorizationEntryRequestControl(final boolean includeAuthNEntry, 172 final boolean includeAuthZEntry, 173 final String... attributes) 174 { 175 this(false, includeAuthNEntry, includeAuthZEntry, 176 (attributes == null) ? null : Arrays.asList(attributes)); 177 } 178 179 180 181 /** 182 * Creates a new get authorization entry request control with the provided 183 * information. 184 * 185 * @param includeAuthNEntry Indicates whether to include the authentication 186 * entry in the response. 187 * @param includeAuthZEntry Indicates whether to include the authorization 188 * entry in the response. 189 * @param attributes The attributes to include in the entries in the 190 * response. It may be empty or {@code null} to 191 * request all user attributes. 192 */ 193 public GetAuthorizationEntryRequestControl(final boolean includeAuthNEntry, 194 final boolean includeAuthZEntry, 195 final List<String> attributes) 196 { 197 this(false, includeAuthNEntry, includeAuthZEntry, attributes); 198 } 199 200 201 202 /** 203 * Creates a new get authorization entry request control with the provided 204 * information. 205 * 206 * @param isCritical Indicates whether the control should be marked 207 * critical. 208 * @param includeAuthNEntry Indicates whether to include the authentication 209 * entry in the response. 210 * @param includeAuthZEntry Indicates whether to include the authorization 211 * entry in the response. 212 * @param attributes The attributes to include in the entries in the 213 * response. It may be empty or {@code null} to 214 * request all user attributes. 215 */ 216 public GetAuthorizationEntryRequestControl(final boolean isCritical, 217 final boolean includeAuthNEntry, 218 final boolean includeAuthZEntry, 219 final String... attributes) 220 { 221 this(isCritical, includeAuthNEntry, includeAuthZEntry, 222 (attributes == null) ? null : Arrays.asList(attributes)); 223 } 224 225 226 227 /** 228 * Creates a new get authorization entry request control with the provided 229 * information. 230 * 231 * @param isCritical Indicates whether the control should be marked 232 * critical. 233 * @param includeAuthNEntry Indicates whether to include the authentication 234 * entry in the response. 235 * @param includeAuthZEntry Indicates whether to include the authorization 236 * entry in the response. 237 * @param attributes The attributes to include in the entries in the 238 * response. It may be empty or {@code null} to 239 * request all user attributes. 240 */ 241 public GetAuthorizationEntryRequestControl(final boolean isCritical, 242 final boolean includeAuthNEntry, 243 final boolean includeAuthZEntry, 244 final List<String> attributes) 245 { 246 super(GET_AUTHORIZATION_ENTRY_REQUEST_OID, isCritical, 247 encodeValue(includeAuthNEntry, includeAuthZEntry, attributes)); 248 249 this.includeAuthNEntry = includeAuthNEntry; 250 this.includeAuthZEntry = includeAuthZEntry; 251 252 if ((attributes == null) || attributes.isEmpty()) 253 { 254 this.attributes = Collections.emptyList(); 255 } 256 else 257 { 258 this.attributes = 259 Collections.unmodifiableList(new ArrayList<>(attributes)); 260 } 261 } 262 263 264 265 /** 266 * Creates a new get authorization entry request control which is decoded from 267 * the provided generic control. 268 * 269 * @param control The generic control to decode as a get authorization entry 270 * request control. 271 * 272 * @throws LDAPException If the provided control cannot be decoded as a get 273 * authorization entry request control. 274 */ 275 public GetAuthorizationEntryRequestControl(final Control control) 276 throws LDAPException 277 { 278 super(control); 279 280 final ASN1OctetString value = control.getValue(); 281 if (value == null) 282 { 283 includeAuthNEntry = true; 284 includeAuthZEntry = true; 285 attributes = Collections.emptyList(); 286 return; 287 } 288 289 try 290 { 291 final ArrayList<String> attrs = new ArrayList<>(20); 292 boolean includeAuthN = true; 293 boolean includeAuthZ = true; 294 295 final ASN1Element element = ASN1Element.decode(value.getValue()); 296 for (final ASN1Element e : 297 ASN1Sequence.decodeAsSequence(element).elements()) 298 { 299 switch (e.getType()) 300 { 301 case TYPE_INCLUDE_AUTHN_ENTRY: 302 includeAuthN = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 303 break; 304 case TYPE_INCLUDE_AUTHZ_ENTRY: 305 includeAuthZ = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 306 break; 307 case TYPE_ATTRIBUTES: 308 for (final ASN1Element ae : 309 ASN1Sequence.decodeAsSequence(e).elements()) 310 { 311 attrs.add(ASN1OctetString.decodeAsOctetString(ae).stringValue()); 312 } 313 break; 314 default: 315 throw new LDAPException(ResultCode.DECODING_ERROR, 316 ERR_GET_AUTHORIZATION_ENTRY_REQUEST_INVALID_SEQUENCE_ELEMENT. 317 get(StaticUtils.toHex(e.getType()))); 318 } 319 } 320 321 includeAuthNEntry = includeAuthN; 322 includeAuthZEntry = includeAuthZ; 323 attributes = attrs; 324 } 325 catch (final LDAPException le) 326 { 327 throw le; 328 } 329 catch (final Exception e) 330 { 331 Debug.debugException(e); 332 throw new LDAPException(ResultCode.DECODING_ERROR, 333 ERR_GET_AUTHORIZATION_ENTRY_REQUEST_CANNOT_DECODE_VALUE.get( 334 StaticUtils.getExceptionMessage(e)), 335 e); 336 } 337 } 338 339 340 341 /** 342 * Encodes the provided information as appropriate for use as the value of 343 * this control. 344 * 345 * @param includeAuthNEntry Indicates whether to include the authentication 346 * entry in the response. 347 * @param includeAuthZEntry Indicates whether to include the authorization 348 * entry in the response. 349 * @param attributes The attributes to include in the entries in the 350 * response. It may be empty or {@code null} to 351 * request all user attributes. 352 * 353 * @return An ASN.1 octet string appropriately encoded for use as the control 354 * value, or {@code null} if no value is needed. 355 */ 356 private static ASN1OctetString encodeValue(final boolean includeAuthNEntry, 357 final boolean includeAuthZEntry, 358 final List<String> attributes) 359 { 360 if (includeAuthNEntry && includeAuthZEntry && 361 ((attributes == null) || attributes.isEmpty())) 362 { 363 return null; 364 } 365 366 final ArrayList<ASN1Element> elements = new ArrayList<>(3); 367 368 if (! includeAuthNEntry) 369 { 370 elements.add(new ASN1Boolean(TYPE_INCLUDE_AUTHN_ENTRY, false)); 371 } 372 373 if (! includeAuthZEntry) 374 { 375 elements.add(new ASN1Boolean(TYPE_INCLUDE_AUTHZ_ENTRY, false)); 376 } 377 378 if ((attributes != null) && (! attributes.isEmpty())) 379 { 380 final ArrayList<ASN1Element> attrElements = 381 new ArrayList<>(attributes.size()); 382 for (final String s : attributes) 383 { 384 attrElements.add(new ASN1OctetString(s)); 385 } 386 387 elements.add(new ASN1Sequence(TYPE_ATTRIBUTES, attrElements)); 388 } 389 390 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 391 } 392 393 394 395 /** 396 * Indicates whether the entry for the authenticated user should be included 397 * in the response control. 398 * 399 * @return {@code true} if the entry for the authenticated user should be 400 * included in the response control, or {@code false} if not. 401 */ 402 public boolean includeAuthNEntry() 403 { 404 return includeAuthNEntry; 405 } 406 407 408 409 /** 410 * Indicates whether the entry for the authorized user should be included 411 * in the response control. 412 * 413 * @return {@code true} if the entry for the authorized user should be 414 * included in the response control, or {@code false} if not. 415 */ 416 public boolean includeAuthZEntry() 417 { 418 return includeAuthZEntry; 419 } 420 421 422 423 /** 424 * Retrieves the attributes that will be requested for the authentication 425 * and/or authorization entries. 426 * 427 * @return The attributes that will be requested for the authentication 428 * and/or authorization entries, or an empty list if all user 429 * attributes should be included. 430 */ 431 public List<String> getAttributes() 432 { 433 return attributes; 434 } 435 436 437 438 /** 439 * {@inheritDoc} 440 */ 441 @Override() 442 public String getControlName() 443 { 444 return INFO_CONTROL_NAME_GET_AUTHORIZATION_ENTRY_REQUEST.get(); 445 } 446 447 448 449 /** 450 * {@inheritDoc} 451 */ 452 @Override() 453 public void toString(final StringBuilder buffer) 454 { 455 buffer.append("GetAuthorizationEntryRequestControl(isCritical="); 456 buffer.append(isCritical()); 457 buffer.append(", includeAuthNEntry="); 458 buffer.append(includeAuthNEntry); 459 buffer.append(", includeAuthZEntry="); 460 buffer.append(includeAuthZEntry); 461 buffer.append(", attributes={"); 462 463 final Iterator<String> iterator = attributes.iterator(); 464 while (iterator.hasNext()) 465 { 466 buffer.append(iterator.next()); 467 if (iterator.hasNext()) 468 { 469 buffer.append(", "); 470 } 471 } 472 473 buffer.append("})"); 474 } 475}