001/* 002 * Copyright 2012-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2012-2024 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) 2012-2024 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.List; 041 042import com.unboundid.asn1.ASN1Boolean; 043import com.unboundid.asn1.ASN1Element; 044import com.unboundid.asn1.ASN1OctetString; 045import com.unboundid.asn1.ASN1Sequence; 046import com.unboundid.ldap.sdk.Control; 047import com.unboundid.ldap.sdk.JSONControlDecodeHelper; 048import com.unboundid.ldap.sdk.LDAPException; 049import com.unboundid.ldap.sdk.ResultCode; 050import com.unboundid.ldap.sdk.RootDSE; 051import com.unboundid.util.Debug; 052import com.unboundid.util.NotMutable; 053import com.unboundid.util.NotNull; 054import com.unboundid.util.Nullable; 055import com.unboundid.util.StaticUtils; 056import com.unboundid.util.ThreadSafety; 057import com.unboundid.util.ThreadSafetyLevel; 058import com.unboundid.util.json.JSONField; 059import com.unboundid.util.json.JSONObject; 060 061import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 062 063 064 065/** 066 * This class provides a request control which may be used to request that the 067 * server return resource limit information for the authenticated user in the 068 * response to a successful bind operation. Resource limits that may be 069 * returned include custom size limit, time limit, idle time limit, lookthrough 070 * limit, equivalent authorization user DN, client connection policy name, and 071 * privilege names. 072 * <BR> 073 * <BLOCKQUOTE> 074 * <B>NOTE:</B> This class, and other classes within the 075 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 076 * supported for use against Ping Identity, UnboundID, and 077 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 078 * for proprietary functionality or for external specifications that are not 079 * considered stable or mature enough to be guaranteed to work in an 080 * interoperable way with other types of LDAP servers. 081 * </BLOCKQUOTE> 082 * <BR> 083 * The criticality for this control may be either {@code true} or {@code false}. 084 * It may optionally have a value, although it should only have a value if the 085 * server advertises OID "1.3.6.1.4.1.30221.2.12.6" 086 * ({@link #EXCLUDE_GROUPS_FEATURE_OID}) in the supportedFeatures attribute of 087 * its root DSE. The {@link #serverAdvertisesExcludeGroupsFeature} method can 088 * help clients make that determination. 089 * <BR><BR> 090 * If the control does have a value, then it should use the following encoding: 091 * <PRE> 092 * GetUserResourceLimitsRequest ::= SEQUENCE { 093 * excludeGroups [0] BOOLEAN DEFAULT FALSE, 094 * ... } 095 * </PRE> 096 * <BR><BR> 097 * If the control does not have a value, then the server will assume the default 098 * behavior for all elements that would be in the value. 099 * 100 * @see GetUserResourceLimitsResponseControl 101 */ 102@NotMutable() 103@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 104public final class GetUserResourceLimitsRequestControl 105 extends Control 106{ 107 /** 108 * The OID (1.3.6.1.4.1.30221.2.5.25) for the get user resource limits request 109 * control. 110 */ 111 @NotNull public static final String GET_USER_RESOURCE_LIMITS_REQUEST_OID = 112 "1.3.6.1.4.1.30221.2.5.25"; 113 114 115 116 /** 117 * The OID (1.3.6.1.4.1.30221.2.12.6) for the supportedFeature value that a 118 * server should advertise in its root DSE if it supports a value indicating 119 * that the server allows the control to include a value that indicates it 120 * should omit group membership information from the response control. 121 */ 122 @NotNull public static final String EXCLUDE_GROUPS_FEATURE_OID = 123 "1.3.6.1.4.1.30221.2.12.6"; 124 125 126 127 /** 128 * The BER type for the request value element that indicates whether groups 129 * should be excluded from the response control. 130 */ 131 private static final byte TYPE_EXCLUDE_GROUPS = (byte) 0x80; 132 133 134 135 /** 136 * The name of the field used to indicate whether to exclude group information 137 * in the JSON representation of this control. 138 */ 139 @NotNull private static final String JSON_FIELD_EXCLUDE_GROUPS = 140 "exclude-groups"; 141 142 143 144 /** 145 * The serial version UID for this serializable class. 146 */ 147 private static final long serialVersionUID = -4349321415426346390L; 148 149 150 151 // Indicates whether the server should exclude information about group 152 // membership from the response control. 153 private final boolean excludeGroups; 154 155 156 157 /** 158 * Creates a new get user resource limits request control. It will not be 159 * marked critical. 160 */ 161 public GetUserResourceLimitsRequestControl() 162 { 163 this(false); 164 } 165 166 167 168 /** 169 * Creates a new get user resource limits request control with the specified 170 * criticality. 171 * 172 * @param isCritical Indicates whether this control should be marked 173 * critical. 174 */ 175 public GetUserResourceLimitsRequestControl(final boolean isCritical) 176 { 177 this(false, false); 178 } 179 180 181 182 /** 183 * Creates a new get user resource limits request control with the specified 184 * criticality. 185 * 186 * @param isCritical Indicates whether this control should be marked 187 * critical. 188 * @param excludeGroups Indicates whether the server should exclude 189 * information about group membership from the response 190 * control. This should generally only be {@code true} 191 * if the client has confirmed that the server supports 192 * this ability, which may be determined using the 193 * {@link #serverAdvertisesExcludeGroupsFeature} 194 * method. 195 */ 196 public GetUserResourceLimitsRequestControl(final boolean isCritical, 197 final boolean excludeGroups) 198 { 199 super(GET_USER_RESOURCE_LIMITS_REQUEST_OID, isCritical, 200 encodeValue(excludeGroups)); 201 202 this.excludeGroups = excludeGroups; 203 } 204 205 206 207 /** 208 * Encodes a value for this control, if appropriate. 209 * 210 * @param excludeGroups Indicates whether the server should exclude 211 * information about group membership from the response 212 * control. This should generally only be {@code true} 213 * if the client has confirmed that the server supports 214 * this ability, which may be determined using the 215 * {@link #serverAdvertisesExcludeGroupsFeature} 216 * method. 217 * 218 * @return A value for this control, or {@code null} if no value is needed. 219 */ 220 @Nullable() 221 private static ASN1OctetString encodeValue(final boolean excludeGroups) 222 { 223 if (excludeGroups) 224 { 225 return new ASN1OctetString( 226 new ASN1Sequence( 227 new ASN1Boolean(TYPE_EXCLUDE_GROUPS, true)).encode()); 228 } 229 230 return null; 231 } 232 233 234 235 /** 236 * Creates a new get user resource limits request control which is decoded 237 * from the provided generic control. 238 * 239 * @param control The generic control to be decoded as a get user resource 240 * limits request control. 241 * 242 * @throws LDAPException If the provided control cannot be decoded as a get 243 * user resource limits request control. 244 */ 245 public GetUserResourceLimitsRequestControl(@NotNull final Control control) 246 throws LDAPException 247 { 248 super(control); 249 250 final ASN1OctetString value = control.getValue(); 251 if (value == null) 252 { 253 excludeGroups = false; 254 return; 255 } 256 257 try 258 { 259 boolean excludeGroupsMutable = false; 260 final ASN1Sequence valueSequence = 261 ASN1Sequence.decodeAsSequence(value.getValue()); 262 for (final ASN1Element e : valueSequence.elements()) 263 { 264 switch (e.getType()) 265 { 266 case TYPE_EXCLUDE_GROUPS: 267 excludeGroupsMutable = 268 ASN1Boolean.decodeAsBoolean(e).booleanValue(); 269 break; 270 } 271 } 272 273 excludeGroups = excludeGroupsMutable; 274 } 275 catch (final Exception e) 276 { 277 Debug.debugException(e); 278 throw new LDAPException(ResultCode.DECODING_ERROR, 279 ERR_GET_USER_RESOURCE_LIMITS_REQUEST_CANNOT_DECODE.get( 280 StaticUtils.getExceptionMessage(e)), 281 e); 282 } 283 } 284 285 286 287 /** 288 * Indicates whether the control requests that the server exclude information 289 * about group membership from the corresponding response control. 290 * 291 * @return {@code true} if the server should exclude information about group 292 * membership from the response control, or {@code false} if not. 293 */ 294 public boolean excludeGroups() 295 { 296 return excludeGroups; 297 } 298 299 300 301 /** 302 * Indicates whether the provided root DSE advertises support for a feature 303 * that indicates it is acceptable for the client to request that the server 304 * omit group membership information from the corresponding response 305 * control. 306 * 307 * @param rootDSE An object with information from the root DSE of the server 308 * for which to make the determination. It must not be 309 * {@code null}. 310 * 311 * @return {@code true} if the provided root DSE object indicates that the 312 * server supports clients requesting to exclude group membership 313 * information from the response control, or {@code false} if not. 314 */ 315 public static boolean serverAdvertisesExcludeGroupsFeature( 316 @NotNull final RootDSE rootDSE) 317 { 318 return rootDSE.supportsFeature(EXCLUDE_GROUPS_FEATURE_OID); 319 } 320 321 322 323 /** 324 * {@inheritDoc} 325 */ 326 @Override() 327 @NotNull() 328 public String getControlName() 329 { 330 return INFO_CONTROL_NAME_GET_USER_RESOURCE_LIMITS_REQUEST.get(); 331 } 332 333 334 335 /** 336 * Retrieves a representation of this get user resource limits request control 337 * as a JSON object. The JSON object uses the following fields: 338 * <UL> 339 * <LI> 340 * {@code oid} -- A mandatory string field whose value is the object 341 * identifier for this control. For the get user resource limits request 342 * control, the OID is "1.3.6.1.4.1.30221.2.5.15". 343 * </LI> 344 * <LI> 345 * {@code control-name} -- An optional string field whose value is a 346 * human-readable name for this control. This field is only intended for 347 * descriptive purposes, and when decoding a control, the {@code oid} 348 * field should be used to identify the type of control. 349 * </LI> 350 * <LI> 351 * {@code criticality} -- A mandatory Boolean field used to indicate 352 * whether this control is considered critical. 353 * </LI> 354 * <LI> 355 * {@code value-base64} -- An optional string field whose value is a 356 * base64-encoded representation of the raw value for this get user 357 * resource limits request control. Exactly one of the 358 * {@code value-base64} and {@code value-json} fields must be present. 359 * </LI> 360 * <LI> 361 * {@code value-json} -- An optional JSON object field whose value is a 362 * user-friendly representation of the value for this get user resource 363 * limits request control. Exactly one of the {@code value-base64} and 364 * {@code value-json} fields must be present, and if the 365 * {@code value-json} field is used, then it will use the following 366 * fields: 367 * <UL> 368 * <LI> 369 * {@code exclude-groups} -- A mandatory Boolean field that indicates 370 * whether to exclude information about the user's group membership 371 * from the response control. 372 * </LI> 373 * </UL> 374 * </LI> 375 * </UL> 376 * 377 * @return A JSON object that contains a representation of this control. 378 */ 379 @Override() 380 @NotNull() 381 public JSONObject toJSONControl() 382 { 383 return new JSONObject( 384 new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID, 385 GET_USER_RESOURCE_LIMITS_REQUEST_OID), 386 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME, 387 INFO_CONTROL_NAME_GET_USER_RESOURCE_LIMITS_REQUEST.get()), 388 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY, 389 isCritical()), 390 new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON, 391 new JSONObject( 392 new JSONField(JSON_FIELD_EXCLUDE_GROUPS, excludeGroups)))); 393 } 394 395 396 397 /** 398 * Attempts to decode the provided object as a JSON representation of a get 399 * user resource limits request control. 400 * 401 * @param controlObject The JSON object to be decoded. It must not be 402 * {@code null}. 403 * @param strict Indicates whether to use strict mode when decoding 404 * the provided JSON object. If this is {@code true}, 405 * then this method will throw an exception if the 406 * provided JSON object contains any unrecognized 407 * fields. If this is {@code false}, then unrecognized 408 * fields will be ignored. 409 * 410 * @return The authorization identity request control that was decoded from 411 * the provided JSON object. 412 * 413 * @throws LDAPException If the provided JSON object cannot be parsed as a 414 * valid authorization identity request control. 415 */ 416 @NotNull() 417 public static GetUserResourceLimitsRequestControl decodeJSONControl( 418 @NotNull final JSONObject controlObject, 419 final boolean strict) 420 throws LDAPException 421 { 422 final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper( 423 controlObject, strict, true, true); 424 425 final ASN1OctetString rawValue = jsonControl.getRawValue(); 426 if (rawValue != null) 427 { 428 return new GetUserResourceLimitsRequestControl(new Control( 429 jsonControl.getOID(), jsonControl.getCriticality(), rawValue)); 430 } 431 432 433 final JSONObject valueObject = jsonControl.getValueObject(); 434 435 final Boolean excludeGroups = 436 valueObject.getFieldAsBoolean(JSON_FIELD_EXCLUDE_GROUPS); 437 if (excludeGroups == null) 438 { 439 throw new LDAPException(ResultCode.DECODING_ERROR, 440 ERR_GET_USER_RESOURCE_LIMITS_REQUEST_JSON_MISSING_EXCLUDE_GROUPS.get( 441 controlObject.toSingleLineString(), 442 JSON_FIELD_EXCLUDE_GROUPS)); 443 } 444 445 446 if (strict) 447 { 448 final List<String> unrecognizedFields = 449 JSONControlDecodeHelper.getControlObjectUnexpectedFields( 450 valueObject, JSON_FIELD_EXCLUDE_GROUPS); 451 if (! unrecognizedFields.isEmpty()) 452 { 453 throw new LDAPException(ResultCode.DECODING_ERROR, 454 ERR_GET_USER_RESOURCE_LIMITS_REQUEST_JSON_UNRECOGNIZED_FIELD.get( 455 controlObject.toSingleLineString(), 456 unrecognizedFields.get(0))); 457 } 458 } 459 460 461 return new GetUserResourceLimitsRequestControl( 462 jsonControl.getCriticality(), excludeGroups); 463 } 464 465 466 467 /** 468 * {@inheritDoc} 469 */ 470 @Override() 471 public void toString(@NotNull final StringBuilder buffer) 472 { 473 buffer.append("GetUserResourceLimitsRequestControl(isCritical="); 474 buffer.append(isCritical()); 475 buffer.append(", excludeGroups="); 476 buffer.append(excludeGroups); 477 buffer.append(')'); 478 } 479}