001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    
028    package org.opends.server.controls;
029    import org.opends.messages.Message;
030    
031    import org.opends.server.types.*;
032    import org.opends.server.protocols.asn1.ASN1OctetString;
033    import org.opends.server.protocols.asn1.ASN1Element;
034    import org.opends.server.protocols.asn1.ASN1Exception;
035    import org.opends.server.protocols.ldap.LDAPResultCode;
036    import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
037    import static org.opends.server.util.Validator.ensureNotNull;
038    import static org.opends.server.util.StaticUtils.toLowerCase;
039    import org.opends.server.core.DirectoryServer;
040    import static org.opends.messages.ProtocolMessages.*;
041    import static org.opends.server.loggers.debug.DebugLogger.*;
042    import org.opends.server.loggers.debug.DebugTracer;
043    
044    import java.util.List;
045    import java.util.ArrayList;
046    import java.util.LinkedList;
047    
048    /**
049     * This class partially implements the geteffectiverights control as defined
050     * in draft-ietf-ldapext-acl-model-08.txt. The main differences are:
051     *
052     *  - The response control is not supported. Instead the dseecompat
053     *    geteffectiverights control implementation creates attributes containing
054     *    right information strings and adds those attributes to the
055     *    entry being returned. The attribute type names are dynamically created;
056     *    see the dseecompat's AciGetEffectiveRights class for details.
057     *
058     *  - The dseecompat implementation allows additional attribute types
059     *    in the request control for which rights information can be returned.
060     *    These are known as the specified attribute types.
061     *
062     * The dseecompat request control value is the following:
063     *
064     * <BR>
065     * <PRE>
066     *  GetRightsControl ::= SEQUENCE {
067     *    authzId    authzId
068     *    attributes  SEQUENCE OF AttributeType
069     *  }
070     *
071     *   -- Only the "dn:DN form is supported.
072     *
073     * </PRE>
074     *
075     **/
076    public class GetEffectiveRights extends Control {
077      /**
078       * The tracer object for the debug logger.
079       */
080      private static final DebugTracer TRACER = getTracer();
081    
082    
083      //The DN representing the authzId. May be null.
084      private DN authzDN=null;
085    
086      //The list of additional attribute types to return rights for. May be null.
087      private List<AttributeType> attrs=null;
088    
089      /**
090       *  Create a new geteffectiverights control with null authzDN and null
091       *  attribute list.
092       */
093      public GetEffectiveRights() {
094        super(OID_GET_EFFECTIVE_RIGHTS, true, null);
095      }
096    
097      /**
098       * Create a new geteffectiverights control with the specified raw octet
099       * string, an authzDN and an attribute list.
100       *
101       * @param val  The octet string repsentation of the control value.
102       *
103       * @param authzDN  The authzDN.
104       *
105       * @param attrs  The list of additional attributes to be returned.
106       */
107      public GetEffectiveRights(ASN1OctetString val, DN authzDN,
108                                List<AttributeType> attrs) {
109        super(OID_GET_EFFECTIVE_RIGHTS, true, val);
110        this.authzDN=authzDN;
111        this.attrs=attrs;
112      }
113    
114      /**
115       * Return the authzDN parsed from the control.
116       *
117       * @return The DN representing the authzId.
118       */
119      public DN getAuthzDN () {
120        return authzDN;
121      }
122    
123      /**
124       * Return the requested additional attributes parsed from the control. Known
125       * as the specified attributes.
126       *
127       * @return  The list containing any additional attributes to return rights
128       *          about.
129       */
130      public List<AttributeType> getAttributes() {
131        return attrs;
132      }
133    
134    
135      /**
136       * Decodes the provided ASN1 element.  Assume that it is a ASN1 sequence
137       * of attributetypes.
138       *
139       * @param attributeElement   The ASN1 element to be decoded.
140       *
141       * @return  A list of attribute types to process rights of.
142       *
143       * @throws ASN1Exception If the attribute element cannot be decoded as a
144       *                       sequence.
145       */
146      private static
147      List<AttributeType> decodeAttributeSequence(ASN1Element attributeElement)
148              throws ASN1Exception {
149        List<AttributeType>  attributeList = new LinkedList<AttributeType>();
150        //Decode the sequence element and put the individual elements in array.
151        ArrayList<ASN1Element> attrElems =
152                attributeElement.decodeAsSequence().elements();
153        int numAttrElements = attrElems.size();
154        for(int i=0; i < numAttrElements; i++) {
155          //Decode as an octet string.
156          ASN1OctetString tmp=attrElems.get(i).decodeAsOctetString();
157          //Get an attribute type for it and add to the list.
158          AttributeType attributeType;
159          if((attributeType =
160                  DirectoryServer.getAttributeType(tmp.toString())) == null)
161            attributeType =
162                    DirectoryServer.getDefaultAttributeType(tmp.toString());
163          attributeList.add(attributeType);
164        }
165        return attributeList;
166      }
167    
168      /**
169       * Decodes the request control's value octet string into a GetEffectiveRights
170       * class. It assumes that it is an ASN1 sequence as described in class
171       * description.
172       *
173       * @param val The octet string repsentation of the control value.
174       *
175       * @return  A decoded GetEffectiveRights class representing the request
176       *          control.
177       *
178       * @throws LDAPException   If the request control's value contains errors
179       *                         causing a valid GetEffectiveRights class to not
180       *                         be created.
181       */
182      private static
183      GetEffectiveRights decodeValueSequence(ASN1OctetString val )
184              throws LDAPException {
185        DN authzDN;
186        List<AttributeType> attrs=null;
187        String authzIDString="";
188        try {
189          ASN1Element sequence = ASN1Element.decode(val.value());
190          ArrayList<ASN1Element> elements =
191                  sequence.decodeAsSequence().elements();
192          ASN1OctetString authzID = elements.get(0).decodeAsOctetString();
193          //There is an sequence containing an attribute list, try to decode it.
194          if(elements.size() == 2)
195            attrs=decodeAttributeSequence(elements.get(1));
196          authzIDString = authzID.stringValue();
197          String lowerAuthzIDString = toLowerCase(authzIDString);
198          //Make sure authzId starts with "dn:" and is a valid DN.
199          if (lowerAuthzIDString.startsWith("dn:"))
200             authzDN = DN.decode(authzIDString.substring(3));
201          else {
202             Message message = INFO_GETEFFECTIVERIGHTS_INVALID_AUTHZID.get(
203                     String.valueOf(authzID));
204             throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
205          }
206        } catch (ASN1Exception e) {
207             if (debugEnabled()) {
208                TRACER.debugCaught(DebugLogLevel.ERROR, e);
209             }
210    
211             Message message =
212                 INFO_GETEFFECTIVERIGHTS_DECODE_ERROR.get(e.getMessage());
213             throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
214        } catch (DirectoryException de) {
215            if (debugEnabled()) {
216              TRACER.debugCaught(DebugLogLevel.ERROR, de);
217            }
218    
219            Message message = INFO_CANNOT_DECODE_GETEFFECTIVERIGHTS_AUTHZID_DN.get(
220                authzIDString.substring(3), de.getMessageObject());
221            throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
222        }
223        return new GetEffectiveRights(val, authzDN, attrs);
224      }
225    
226      /**
227       * Decodes the request control's value into a GetEffectiveRights class.
228       *
229       * @param control  The control class representing the request control.
230       *
231       * @return  A decoded GetEffectiveRights class representing the request
232       *          control.
233       *
234       * @throws LDAPException   If the request control's value contains errors
235       *                         causing a valid GetEffectiveRights class to not
236       *                         be created.
237       */
238      public static
239      GetEffectiveRights decodeControl(Control control) throws LDAPException {
240        ensureNotNull(control);
241        ASN1OctetString value=control.getValue();
242        //If the value is null create a GetEffectiveRights class with null
243        //authzDN and attribute list, else try to decode the value.
244        if(value == null)
245          return new GetEffectiveRights();
246        else
247          return GetEffectiveRights.decodeValueSequence(value);
248      }
249    }