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