mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

matthew_swift
28.47.2010 f2160f4bd1c8ac67e5a86a6710d431e8932877f9
sdk/src/org/opends/sdk/controls/GetEffectiveRightsRequestControl.java
@@ -1,8 +1,35 @@
/*
 * 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.*;
@@ -13,221 +40,343 @@
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);
@@ -236,32 +385,43 @@
  /**
   * {@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();
  }
}