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