/*
|
* 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.*;
|
import org.opends.sdk.asn1.ASN1;
|
import org.opends.sdk.asn1.ASN1Reader;
|
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;
|
|
|
|
/**
|
* 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 -- Only the "dn:DN" form is supported.
|
* attributes SEQUENCE OF AttributeType
|
* }
|
* </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 final class GetEffectiveRightsRequestControl implements Control
|
{
|
/**
|
* The OID for the get effective rights request control.
|
*/
|
public static final String OID = "1.3.6.1.4.1.42.2.27.9.5.2";
|
|
/**
|
* A decoder which can be used for decoding the get effective rights request
|
* control.
|
*/
|
public static final ControlDecoder<GetEffectiveRightsRequestControl> DECODER =
|
new ControlDecoder<GetEffectiveRightsRequestControl>()
|
{
|
|
public GetEffectiveRightsRequestControl decodeControl(
|
final Control control, final DecodeOptions options)
|
throws DecodeException
|
{
|
Validator.ensureNotNull(control);
|
|
if (control instanceof GetEffectiveRightsRequestControl)
|
{
|
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();
|
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:"))
|
{
|
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
|
{
|
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())
|
{
|
attributes = new LinkedList<AttributeType>();
|
reader.readStartSequence();
|
while (reader.hasNextElement())
|
{
|
// 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 (final IOException e)
|
{
|
final LocalizableMessage message = INFO_GETEFFECTIVERIGHTS_DECODE_ERROR
|
.get(e.getMessage());
|
throw DecodeException.error(message);
|
}
|
}
|
|
return new GetEffectiveRightsRequestControl(control.isCritical(),
|
authorizationDN, attributes);
|
|
}
|
|
|
|
public String getOID()
|
{
|
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);
|
}
|
|
|
|
/**
|
* 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 GetEffectiveRightsRequestControl newControl(
|
final boolean isCritical, final String authorizationName,
|
final String... attributes) throws UnknownSchemaElementException,
|
LocalizedIllegalArgumentException, NullPointerException
|
{
|
Validator.ensureNotNull((Object) attributes);
|
|
final DN dn = authorizationName == null ? null : DN
|
.valueOf(authorizationName);
|
|
List<AttributeType> copyOfAttributes;
|
if (attributes != null && attributes.length > 0)
|
{
|
copyOfAttributes = new ArrayList<AttributeType>(attributes.length);
|
for (final String attribute : attributes)
|
{
|
copyOfAttributes.add(Schema.getDefaultSchema().getAttributeType(
|
attribute));
|
}
|
copyOfAttributes = Collections.unmodifiableList(copyOfAttributes);
|
}
|
else
|
{
|
copyOfAttributes = Collections.emptyList();
|
}
|
|
return new GetEffectiveRightsRequestControl(isCritical, dn,
|
copyOfAttributes);
|
}
|
|
|
|
// 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)
|
{
|
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()
|
{
|
final ByteStringBuilder buffer = new ByteStringBuilder();
|
final ASN1Writer writer = ASN1.getWriter(buffer);
|
try
|
{
|
writer.writeStartSequence();
|
if (authorizationName != null)
|
{
|
writer.writeOctetString("dn:" + authorizationName);
|
}
|
|
if (!attributes.isEmpty())
|
{
|
writer.writeStartSequence();
|
for (final AttributeType attribute : attributes)
|
{
|
writer.writeOctetString(attribute.getNameOrOID());
|
}
|
writer.writeEndSequence();
|
}
|
writer.writeEndSequence();
|
return buffer.toByteString();
|
}
|
catch (final IOException ioe)
|
{
|
// This should never happen unless there is a bug somewhere.
|
throw new RuntimeException(ioe);
|
}
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public boolean hasValue()
|
{
|
return authorizationName != null || !attributes.isEmpty();
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public boolean isCritical()
|
{
|
return isCritical;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public String toString()
|
{
|
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();
|
}
|
}
|