001/* 002 * Copyright 2008-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-2018 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 com.unboundid.asn1.ASN1Element; 026import com.unboundid.asn1.ASN1OctetString; 027import com.unboundid.asn1.ASN1Sequence; 028import com.unboundid.ldap.sdk.Control; 029import com.unboundid.ldap.sdk.LDAPException; 030import com.unboundid.ldap.sdk.ResultCode; 031import com.unboundid.util.Debug; 032import com.unboundid.util.NotMutable; 033import com.unboundid.util.StaticUtils; 034import com.unboundid.util.ThreadSafety; 035import com.unboundid.util.ThreadSafetyLevel; 036import com.unboundid.util.Validator; 037 038import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 039 040 041 042/** 043 * This class provides an implementation of the get effective rights request 044 * control, which may be included in a search request to indicate that matching 045 * entries should include information about the rights a given user may have 046 * when interacting with that entry. 047 * <BR> 048 * <BLOCKQUOTE> 049 * <B>NOTE:</B> This class, and other classes within the 050 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 051 * supported for use against Ping Identity, UnboundID, and 052 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 053 * for proprietary functionality or for external specifications that are not 054 * considered stable or mature enough to be guaranteed to work in an 055 * interoperable way with other types of LDAP servers. 056 * </BLOCKQUOTE> 057 * <BR> 058 * When the get effective rights control is included in a search request, then 059 * each entry returned may include information about the rights that the 060 * specified user has for that entry in the {@code aclRights} operational 061 * attribute. Note that because this is an operational attribute, it must be 062 * explicitly included in the set of attributes to return. 063 * <BR><BR> 064 * If the {@code aclRights} attribute is included in the entry, then it will be 065 * present with multiple sets of options. In one case, it will have an option 066 * of "entryLevel", which provides information about the rights that the user 067 * has for the entry in general (see the {@link EntryRight} enum for a list of 068 * the entry-level rights that can be held). In all other cases, it will have 069 * one option of "attributeLevel" and another option that is the name of the 070 * attribute for which the set of rights is granted (see the 071 * {@link AttributeRight} enum for a list of the attribute-level rights that can 072 * be held). In either case, the value will be a comma-delimited list of 073 * right strings, where each right string is the name of the right followed by 074 * a colon and a one to indicate that the right is granted or zero to indicate 075 * that it is not granted. The {@link EffectiveRightsEntry} class provides a 076 * simple means of accessing the information encoded in the values of the 077 * {@code aclRights} attribute. 078 * <BR><BR> 079 * This control was designed by Sun Microsystems, and it is not the same as the 080 * get effective rights control referenced in the draft-ietf-ldapext-acl-model 081 * Internet draft. The value for this control should be encoded as follows: 082 * <BR><BR> 083 * <PRE> 084 * GET_EFFECTIVE_RIGHTS := SEQUENCE { 085 * authzID authzID, 086 * attributes SEQUENCE OF AttributeType OPTIONAL } 087 * </PRE> 088 * <H2>Example</H2> 089 * The following example demonstrates the use of the get effective rights 090 * control to determine whether user "uid=admin,dc=example,dc=com" has the 091 * ability to change the password for the user with uid "john.doe": 092 * <PRE> 093 * SearchRequest searchRequest = new SearchRequest("dc=example,dc=com", 094 * SearchScope.SUB, Filter.createEqualityFilter("uid", "john.doe"), 095 * "userPassword", "aclRights"); 096 * searchRequest.addControl(new GetEffectiveRightsRequestControl( 097 * "dn:uid=admin,dc=example,dc=com")); 098 * SearchResult searchResult = connection.search(searchRequest); 099 * 100 * for (SearchResultEntry entry : searchResult.getSearchEntries()) 101 * { 102 * EffectiveRightsEntry effectiveRightsEntry = 103 * new EffectiveRightsEntry(entry); 104 * if (effectiveRightsEntry.rightsInformationAvailable()) 105 * { 106 * if (effectiveRightsEntry.hasAttributeRight(AttributeRight.WRITE, 107 * "userPassword")) 108 * { 109 * // The admin user has permission to change the target user's password. 110 * } 111 * else 112 * { 113 * // The admin user does not have permission to change the target user's 114 * // password. 115 * } 116 * } 117 * else 118 * { 119 * // No effective rights information was returned. 120 * } 121 * } 122 * </PRE> 123 */ 124@NotMutable() 125@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 126public final class GetEffectiveRightsRequestControl 127 extends Control 128{ 129 /** 130 * The OID (1.3.6.1.4.1.42.2.27.9.5.2) for the get effective rights request 131 * control. 132 */ 133 public static final String GET_EFFECTIVE_RIGHTS_REQUEST_OID = 134 "1.3.6.1.4.1.42.2.27.9.5.2"; 135 136 137 138 /** 139 * The serial version UID for this serializable class. 140 */ 141 private static final long serialVersionUID = 354733122036206073L; 142 143 144 145 // The authorization ID of the user for which to calculate the effective 146 // rights. 147 private final String authzID; 148 149 // The names of the attribute types for which to calculate the effective 150 // rights. 151 private final String[] attributes; 152 153 154 155 /** 156 * Creates a new get effective rights request control with the provided 157 * information. It will not be marked critical. 158 * 159 * @param authzID The authorization ID of the user for whom the effective 160 * rights should be calculated. It must not be 161 * {@code null}. 162 * @param attributes The set of attributes for which to calculate the 163 * effective rights. 164 */ 165 public GetEffectiveRightsRequestControl(final String authzID, 166 final String... attributes) 167 { 168 this(false, authzID, attributes); 169 } 170 171 172 173 /** 174 * Creates a new get effective rights request control with the provided 175 * information. It will not be marked critical. 176 * 177 * @param isCritical Indicates whether this control should be marked 178 * critical. 179 * @param authzID The authorization ID of the user for whom the effective 180 * rights should be calculated. It must not be 181 * {@code null}. 182 * @param attributes The set of attributes for which to calculate the 183 * effective rights. 184 */ 185 public GetEffectiveRightsRequestControl(final boolean isCritical, 186 final String authzID, 187 final String... attributes) 188 { 189 super(GET_EFFECTIVE_RIGHTS_REQUEST_OID, isCritical, 190 encodeValue(authzID, attributes)); 191 192 this.authzID = authzID; 193 this.attributes = attributes; 194 } 195 196 197 198 /** 199 * Creates a new get effective rights request control which is decoded from 200 * the provided generic control. 201 * 202 * @param control The generic control to be decoded as a get effective 203 * rights request control. 204 * 205 * @throws LDAPException If the provided control cannot be decoded as a get 206 * effective rights request control. 207 */ 208 public GetEffectiveRightsRequestControl(final Control control) 209 throws LDAPException 210 { 211 super(control); 212 213 final ASN1OctetString value = control.getValue(); 214 if (value == null) 215 { 216 throw new LDAPException(ResultCode.DECODING_ERROR, 217 ERR_GER_REQUEST_NO_VALUE.get()); 218 } 219 220 final ASN1Element[] elements; 221 try 222 { 223 final ASN1Element valueElement = ASN1Element.decode(value.getValue()); 224 elements = ASN1Sequence.decodeAsSequence(valueElement).elements(); 225 } 226 catch (final Exception e) 227 { 228 Debug.debugException(e); 229 throw new LDAPException(ResultCode.DECODING_ERROR, 230 ERR_GER_REQUEST_VALUE_NOT_SEQUENCE.get(e), e); 231 } 232 233 if ((elements.length < 1) || (elements.length > 2)) 234 { 235 throw new LDAPException(ResultCode.DECODING_ERROR, 236 ERR_GER_REQUEST_INVALID_ELEMENT_COUNT.get( 237 elements.length)); 238 } 239 240 authzID = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue(); 241 242 if (elements.length == 2) 243 { 244 try 245 { 246 final ASN1Element[] attrElements = 247 ASN1Sequence.decodeAsSequence(elements[1]).elements(); 248 attributes = new String[attrElements.length]; 249 for (int i=0; i < attrElements.length; i++) 250 { 251 attributes[i] = ASN1OctetString.decodeAsOctetString( 252 attrElements[i]).stringValue(); 253 } 254 } 255 catch (final Exception e) 256 { 257 Debug.debugException(e); 258 throw new LDAPException(ResultCode.DECODING_ERROR, 259 ERR_GER_REQUEST_CANNOT_DECODE.get(e), e); 260 } 261 } 262 else 263 { 264 attributes = StaticUtils.NO_STRINGS; 265 } 266 } 267 268 269 270 /** 271 * Encodes the provided information into an ASN.1 octet string suitable for 272 * use as the value of this control. 273 * 274 * @param authzID The authorization ID of the user for whom the effective 275 * rights should be calculated. It must not be 276 * {@code null}. 277 * @param attributes The set of attributes for which to calculate the 278 * effective rights. 279 * 280 * @return An ASN.1 octet string containing the encoded control value. 281 */ 282 private static ASN1OctetString encodeValue(final String authzID, 283 final String[] attributes) 284 { 285 Validator.ensureNotNull(authzID); 286 287 final ASN1Element[] elements; 288 if ((attributes == null) || (attributes.length == 0)) 289 { 290 elements = new ASN1Element[] 291 { 292 new ASN1OctetString(authzID), 293 new ASN1Sequence() 294 }; 295 } 296 else 297 { 298 final ASN1Element[] attrElements = new ASN1Element[attributes.length]; 299 for (int i=0; i < attributes.length; i++) 300 { 301 attrElements[i] = new ASN1OctetString(attributes[i]); 302 } 303 304 elements = new ASN1Element[] 305 { 306 new ASN1OctetString(authzID), 307 new ASN1Sequence(attrElements) 308 }; 309 } 310 311 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 312 } 313 314 315 316 /** 317 * Retrieves the authorization ID of the user for whom to calculate the 318 * effective rights. 319 * 320 * @return The authorization ID of the user for whom to calculate the 321 * effective rights. 322 */ 323 public String getAuthzID() 324 { 325 return authzID; 326 } 327 328 329 330 /** 331 * Retrieves the names of the attributes for which to calculate the effective 332 * rights information. 333 * 334 * @return The names of the attributes for which to calculate the effective 335 * rights information, or an empty array if no attribute names were 336 * specified. 337 */ 338 public String[] getAttributes() 339 { 340 return attributes; 341 } 342 343 344 345 /** 346 * {@inheritDoc} 347 */ 348 @Override() 349 public String getControlName() 350 { 351 return INFO_CONTROL_NAME_GET_EFFECTIVE_RIGHTS_REQUEST.get(); 352 } 353 354 355 356 /** 357 * {@inheritDoc} 358 */ 359 @Override() 360 public void toString(final StringBuilder buffer) 361 { 362 buffer.append("GetEffectiveRightsRequestControl(authzId='"); 363 buffer.append(authzID); 364 buffer.append('\''); 365 366 if (attributes.length > 0) 367 { 368 buffer.append(", attributes={"); 369 for (int i=0; i < attributes.length; i++) 370 { 371 if (i > 0) 372 { 373 buffer.append(", "); 374 } 375 376 buffer.append(attributes[i]); 377 } 378 buffer.append('}'); 379 } 380 381 buffer.append(", isCritical="); 382 buffer.append(isCritical()); 383 buffer.append(')'); 384 } 385}