| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.sdk.controls; |
| | | |
| | | |
| | | |
| | | import static com.sun.opends.sdk.messages.Messages.*; |
| | | import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.*; |
| | |
| | | import org.opends.sdk.asn1.ASN1Writer; |
| | | import org.opends.sdk.schema.AttributeType; |
| | | import org.opends.sdk.schema.Schema; |
| | | import org.opends.sdk.schema.UnknownSchemaElementException; |
| | | |
| | | import com.sun.opends.sdk.util.Validator; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class partially implements the geteffectiverights control as |
| | | * defined |
| | | * in draft-ietf-ldapext-acl-model-08.txt. The main differences are: |
| | | * - The response control is not supported. Instead the dseecompat |
| | | * geteffectiverights control implementation creates attributes |
| | | * containing |
| | | * right information strings and adds those attributes to the |
| | | * entry being returned. The attribute type names are dynamically |
| | | * created; |
| | | * see the dseecompat's AciGetEffectiveRights class for details. |
| | | * - The dseecompat implementation allows additional attribute types |
| | | * in the request control for which rights information can be returned. |
| | | * These are known as the specified attribute types. |
| | | * The dseecompat request control value is the following: <BR> |
| | | * |
| | | * <PRE> |
| | | * A partial implementation of the get effective rights request control as |
| | | * defined in draft-ietf-ldapext-acl-model. The main differences are: |
| | | * <ul> |
| | | * <li>The response control is not supported. Instead the OpenDS implementation |
| | | * creates attributes containing effective rights information with the entry |
| | | * being returned. |
| | | * <li>The attribute type names are dynamically created. |
| | | * <li>The set of attributes for which effective rights information is to be |
| | | * requested can be included in the control. |
| | | * </ul> |
| | | * The get effective rights request control value has the following BER |
| | | * encoding: |
| | | * |
| | | * <pre> |
| | | * GetRightsControl ::= SEQUENCE { |
| | | * authzId authzId |
| | | * authzId authzId -- Only the "dn:DN" form is supported. |
| | | * attributes SEQUENCE OF AttributeType |
| | | * } |
| | | * -- Only the "dn:DN form is supported. |
| | | * |
| | | * </PRE> |
| | | * </pre> |
| | | * |
| | | * @see <a |
| | | * href="http://tools.ietf.org/html/draft-ietf-ldapext-acl-model">draft-ietf-ldapext-acl-model |
| | | * - Access Control Model for LDAPv3 </a> |
| | | **/ |
| | | public class GetEffectiveRightsRequestControl extends Control |
| | | public final class GetEffectiveRightsRequestControl implements Control |
| | | { |
| | | /** |
| | | * The OID for the get effective rights control. |
| | | * The OID for the get effective rights request control. |
| | | */ |
| | | public static final String OID_GET_EFFECTIVE_RIGHTS = "1.3.6.1.4.1.42.2.27.9.5.2"; |
| | | |
| | | |
| | | public static final String OID = "1.3.6.1.4.1.42.2.27.9.5.2"; |
| | | |
| | | /** |
| | | * ControlDecoder implentation to decode this control from a |
| | | * ByteString. |
| | | * A decoder which can be used for decoding the get effective rights request |
| | | * control. |
| | | */ |
| | | private static final class Decoder implements |
| | | ControlDecoder<GetEffectiveRightsRequestControl> |
| | | public static final ControlDecoder<GetEffectiveRightsRequestControl> DECODER = |
| | | new ControlDecoder<GetEffectiveRightsRequestControl>() |
| | | { |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public GetEffectiveRightsRequestControl decode(boolean isCritical, |
| | | ByteString value, Schema schema) throws DecodeException |
| | | |
| | | public GetEffectiveRightsRequestControl decodeControl( |
| | | final Control control, final DecodeOptions options) |
| | | throws DecodeException |
| | | { |
| | | // If the value is null create a GetEffectiveRightsRequestControl |
| | | // class with null authzDN and attribute list, else try to |
| | | // decode the value. |
| | | if (value == null) |
| | | return new GetEffectiveRightsRequestControl(isCritical, |
| | | (String) null); |
| | | else |
| | | Validator.ensureNotNull(control); |
| | | |
| | | if (control instanceof GetEffectiveRightsRequestControl) |
| | | { |
| | | ASN1Reader reader = ASN1.getReader(value); |
| | | String authzDN; |
| | | List<String> attrs = Collections.emptyList(); |
| | | return (GetEffectiveRightsRequestControl) control; |
| | | } |
| | | |
| | | if (!control.getOID().equals(OID)) |
| | | { |
| | | final LocalizableMessage message = ERR_GETEFFECTIVERIGHTS_CONTROL_BAD_OID |
| | | .get(control.getOID(), OID); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | DN authorizationDN = null; |
| | | List<AttributeType> attributes = Collections.emptyList(); |
| | | |
| | | if (control.hasValue()) |
| | | { |
| | | final ASN1Reader reader = ASN1.getReader(control.getValue()); |
| | | try |
| | | { |
| | | reader.readStartSequence(); |
| | | String authzIDString = reader.readOctetStringAsString(); |
| | | String lowerAuthzIDString = authzIDString.toLowerCase(); |
| | | final String authzIDString = reader.readOctetStringAsString(); |
| | | final String lowerAuthzIDString = authzIDString.toLowerCase(); |
| | | Schema schema; |
| | | |
| | | // Make sure authzId starts with "dn:" and is a valid DN. |
| | | if (lowerAuthzIDString.startsWith("dn:")) |
| | | authzDN = authzIDString.substring(3); |
| | | { |
| | | final String authorizationDNString = authzIDString.substring(3); |
| | | schema = options.getSchemaResolver().resolveSchema( |
| | | authorizationDNString); |
| | | try |
| | | { |
| | | authorizationDN = DN.valueOf(authorizationDNString, schema); |
| | | } |
| | | catch (final LocalizedIllegalArgumentException e) |
| | | { |
| | | final LocalizableMessage message = ERR_GETEFFECTIVERIGHTS_INVALID_AUTHZIDDN |
| | | .get(getExceptionMessage(e)); |
| | | throw DecodeException.error(message, e); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | LocalizableMessage message = INFO_GETEFFECTIVERIGHTS_INVALID_AUTHZID |
| | | final LocalizableMessage message = INFO_GETEFFECTIVERIGHTS_INVALID_AUTHZID |
| | | .get(lowerAuthzIDString); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | // There is an sequence containing an attribute list, try to |
| | | // decode it. |
| | | if (reader.hasNextElement()) |
| | | { |
| | | attrs = new LinkedList<String>(); |
| | | attributes = new LinkedList<AttributeType>(); |
| | | reader.readStartSequence(); |
| | | while (reader.hasNextElement()) |
| | | { |
| | | // Decode as an octet string. |
| | | attrs.add(reader.readOctetStringAsString()); |
| | | // Decode as an attribute type. |
| | | final String attributeName = reader.readOctetStringAsString(); |
| | | AttributeType attributeType; |
| | | try |
| | | { |
| | | // FIXME: we're using the schema associated with the authzid |
| | | // which is not really correct. We should really use the schema |
| | | // associated with the entry. |
| | | attributeType = schema.getAttributeType(attributeName); |
| | | } |
| | | catch (final UnknownSchemaElementException e) |
| | | { |
| | | final LocalizableMessage message = ERR_GETEFFECTIVERIGHTS_UNKNOWN_ATTRIBUTE |
| | | .get(attributeName); |
| | | throw DecodeException.error(message, e); |
| | | } |
| | | attributes.add(attributeType); |
| | | } |
| | | reader.readEndSequence(); |
| | | attributes = Collections.unmodifiableList(attributes); |
| | | } |
| | | reader.readEndSequence(); |
| | | } |
| | | catch (IOException e) |
| | | catch (final IOException e) |
| | | { |
| | | LocalizableMessage message = INFO_GETEFFECTIVERIGHTS_DECODE_ERROR.get(e |
| | | .getMessage()); |
| | | final LocalizableMessage message = INFO_GETEFFECTIVERIGHTS_DECODE_ERROR |
| | | .get(e.getMessage()); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | return new GetEffectiveRightsRequestControl(isCritical, |
| | | authzDN, attrs); |
| | | } |
| | | |
| | | return new GetEffectiveRightsRequestControl(control.isCritical(), |
| | | authorizationDN, attributes); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | public String getOID() |
| | | { |
| | | return OID_GET_EFFECTIVE_RIGHTS; |
| | | return OID; |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new get effective rights request control with the provided |
| | | * criticality, optional authorization name and attribute list. |
| | | * |
| | | * @param isCritical |
| | | * {@code true} if it is unacceptable to perform the operation |
| | | * without applying the semantics of this control, or {@code false} |
| | | * if it can be ignored. |
| | | * @param authorizationName |
| | | * The distinguished name of the user for which effective rights are |
| | | * to be returned, or {@code null} if the client's authentication ID |
| | | * is to be used. |
| | | * @param attributes |
| | | * The list of attributes for which effective rights are to be |
| | | * returned, which may be empty indicating that no attribute rights |
| | | * are to be returned. |
| | | * @return The new control. |
| | | * @throws NullPointerException |
| | | * If {@code attributes} was {@code null}. |
| | | */ |
| | | public static GetEffectiveRightsRequestControl newControl( |
| | | final boolean isCritical, final DN authorizationName, |
| | | final Collection<AttributeType> attributes) throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(attributes); |
| | | |
| | | final Collection<AttributeType> copyOfAttributes = Collections |
| | | .unmodifiableList(new ArrayList<AttributeType>(attributes)); |
| | | return new GetEffectiveRightsRequestControl(isCritical, authorizationName, |
| | | copyOfAttributes); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * The Control Decoder that can be used to decode this control. |
| | | * Creates a new get effective rights request control with the provided |
| | | * criticality, optional authorization name and attribute list. The |
| | | * authorization name and attributes, if provided, will be decoded using the |
| | | * default schema. |
| | | * |
| | | * @param isCritical |
| | | * {@code true} if it is unacceptable to perform the operation |
| | | * without applying the semantics of this control, or {@code false} |
| | | * if it can be ignored. |
| | | * @param authorizationName |
| | | * The distinguished name of the user for which effective rights are |
| | | * to be returned, or {@code null} if the client's authentication ID |
| | | * is to be used. |
| | | * @param attributes |
| | | * The list of attributes for which effective rights are to be |
| | | * returned, which may be empty indicating that no attribute rights |
| | | * are to be returned. |
| | | * @return The new control. |
| | | * @throws UnknownSchemaElementException |
| | | * If the default schema is a strict schema and one or more of the |
| | | * requested attribute types were not recognized. |
| | | * @throws LocalizedIllegalArgumentException |
| | | * If {@code authorizationName} is not a valid LDAP string |
| | | * representation of a DN. |
| | | * @throws NullPointerException |
| | | * If {@code attributes} was {@code null}. |
| | | */ |
| | | public static final ControlDecoder<GetEffectiveRightsRequestControl> DECODER = new Decoder(); |
| | | |
| | | // The raw DN representing the authzId |
| | | private String authorizationDN = null; |
| | | |
| | | // The raw DN representing the authzId |
| | | private List<String> attributes = null; |
| | | |
| | | |
| | | |
| | | public GetEffectiveRightsRequestControl(boolean isCritical, |
| | | String authorizationDN, String... attributes) |
| | | public static GetEffectiveRightsRequestControl newControl( |
| | | final boolean isCritical, final String authorizationName, |
| | | final String... attributes) throws UnknownSchemaElementException, |
| | | LocalizedIllegalArgumentException, NullPointerException |
| | | { |
| | | super(OID_GET_EFFECTIVE_RIGHTS, isCritical); |
| | | Validator.ensureNotNull((Object) attributes); |
| | | |
| | | this.authorizationDN = authorizationDN; |
| | | if (attributes != null) |
| | | final DN dn = authorizationName == null ? null : DN |
| | | .valueOf(authorizationName); |
| | | |
| | | List<AttributeType> copyOfAttributes; |
| | | if (attributes != null && attributes.length > 0) |
| | | { |
| | | this.attributes = new ArrayList<String>(attributes.length); |
| | | this.attributes.addAll(Arrays.asList(attributes)); |
| | | } |
| | | else |
| | | { |
| | | this.attributes = Collections.emptyList(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public GetEffectiveRightsRequestControl(boolean isCritical, |
| | | DN authorizationDN, AttributeType... attributes) |
| | | { |
| | | super(OID_GET_EFFECTIVE_RIGHTS, isCritical); |
| | | |
| | | Validator.ensureNotNull(authorizationDN, attributes); |
| | | |
| | | this.authorizationDN = authorizationDN.toString(); |
| | | |
| | | if (attributes != null) |
| | | { |
| | | for (AttributeType attr : attributes) |
| | | copyOfAttributes = new ArrayList<AttributeType>(attributes.length); |
| | | for (final String attribute : attributes) |
| | | { |
| | | this.attributes = new ArrayList<String>(attributes.length); |
| | | this.attributes.add(attr.getNameOrOID()); |
| | | copyOfAttributes.add(Schema.getDefaultSchema().getAttributeType( |
| | | attribute)); |
| | | } |
| | | copyOfAttributes = Collections.unmodifiableList(copyOfAttributes); |
| | | } |
| | | else |
| | | { |
| | | this.attributes = Collections.emptyList(); |
| | | copyOfAttributes = Collections.emptyList(); |
| | | } |
| | | |
| | | return new GetEffectiveRightsRequestControl(isCritical, dn, |
| | | copyOfAttributes); |
| | | } |
| | | |
| | | |
| | | |
| | | private GetEffectiveRightsRequestControl(boolean isCritical, |
| | | String authorizationDN, List<String> attributes) |
| | | // The DN representing the authzId (may be null meaning use the client's DN). |
| | | private final DN authorizationName; |
| | | |
| | | // The unmodifiable list of attributes to be queried (may be empty). |
| | | private final Collection<AttributeType> attributes; |
| | | |
| | | private final boolean isCritical; |
| | | |
| | | |
| | | |
| | | private GetEffectiveRightsRequestControl(final boolean isCritical, |
| | | final DN authorizationName, final Collection<AttributeType> attributes) |
| | | { |
| | | super(OID_GET_EFFECTIVE_RIGHTS, isCritical); |
| | | |
| | | Validator.ensureNotNull(authorizationDN, attributes); |
| | | |
| | | this.authorizationDN = authorizationDN; |
| | | this.isCritical = isCritical; |
| | | this.authorizationName = authorizationName; |
| | | this.attributes = attributes; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns an unmodifiable list of attributes for which effective rights are |
| | | * to be returned, which may be empty indicating that no attribute rights are |
| | | * to be returned. |
| | | * |
| | | * @return The unmodifiable list of attributes for which effective rights are |
| | | * to be returned. |
| | | */ |
| | | public Collection<AttributeType> getAttributes() |
| | | { |
| | | return attributes; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the distinguished name of the user for which effective rights are |
| | | * to be returned, or {@code null} if the client's authentication ID is to be |
| | | * used. |
| | | * |
| | | * @return The distinguished name of the user for which effective rights are |
| | | * to be returned. |
| | | */ |
| | | public DN getAuthorizationName() |
| | | { |
| | | return authorizationName; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String getOID() |
| | | { |
| | | return OID; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ByteString getValue() |
| | | { |
| | | if (authorizationDN == null && attributes.isEmpty()) |
| | | { |
| | | return ByteString.empty(); |
| | | } |
| | | |
| | | ByteStringBuilder buffer = new ByteStringBuilder(); |
| | | ASN1Writer writer = ASN1.getWriter(buffer); |
| | | final ByteStringBuilder buffer = new ByteStringBuilder(); |
| | | final ASN1Writer writer = ASN1.getWriter(buffer); |
| | | try |
| | | { |
| | | writer.writeStartSequence(); |
| | | if (authorizationDN != null) |
| | | if (authorizationName != null) |
| | | { |
| | | writer.writeOctetString("dn:" + authorizationDN); |
| | | writer.writeOctetString("dn:" + authorizationName); |
| | | } |
| | | |
| | | if (!attributes.isEmpty()) |
| | | { |
| | | writer.writeStartSequence(); |
| | | for (String attr : attributes) |
| | | for (final AttributeType attribute : attributes) |
| | | { |
| | | writer.writeOctetString(attr); |
| | | writer.writeOctetString(attribute.getNameOrOID()); |
| | | } |
| | | writer.writeEndSequence(); |
| | | } |
| | | writer.writeEndSequence(); |
| | | return buffer.toByteString(); |
| | | } |
| | | catch (IOException ioe) |
| | | catch (final IOException ioe) |
| | | { |
| | | // This should never happen unless there is a bug somewhere. |
| | | throw new RuntimeException(ioe); |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean hasValue() |
| | | { |
| | | return authorizationDN != null || !attributes.isEmpty(); |
| | | return authorizationName != null || !attributes.isEmpty(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Appends a string representation of this proxied auth v2 control to |
| | | * the provided buffer. |
| | | * |
| | | * @param buffer |
| | | * The buffer to which the information should be appended. |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isCritical() |
| | | { |
| | | return isCritical; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void toString(StringBuilder buffer) |
| | | public String toString() |
| | | { |
| | | buffer.append("GetEffectiveRightsRequestControl(oid="); |
| | | buffer.append(getOID()); |
| | | buffer.append(", criticality="); |
| | | buffer.append(isCritical()); |
| | | buffer.append(", authorizationDN=\""); |
| | | buffer.append(authorizationDN); |
| | | buffer.append("\""); |
| | | buffer.append(", attributes=("); |
| | | buffer.append(attributes); |
| | | buffer.append("))"); |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("GetEffectiveRightsRequestControl(oid="); |
| | | builder.append(getOID()); |
| | | builder.append(", criticality="); |
| | | builder.append(isCritical()); |
| | | builder.append(", authorizationDN=\""); |
| | | builder.append(authorizationName); |
| | | builder.append("\""); |
| | | builder.append(", attributes=("); |
| | | builder.append(attributes); |
| | | builder.append("))"); |
| | | return builder.toString(); |
| | | } |
| | | } |