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