001    /*
002     * Copyright 2007-2013 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2013 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.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.DN;
030    import com.unboundid.ldap.sdk.LDAPException;
031    import com.unboundid.ldap.sdk.ResultCode;
032    import com.unboundid.util.NotMutable;
033    import com.unboundid.util.ThreadSafety;
034    import com.unboundid.util.ThreadSafetyLevel;
035    
036    import static com.unboundid.ldap.sdk.controls.ControlMessages.*;
037    import static com.unboundid.util.Debug.*;
038    import static com.unboundid.util.Validator.*;
039    
040    
041    
042    /**
043     * This class provides an implementation of the proxied authorization V1
044     * request control, which may be used to request that the associated operation
045     * be performed as if it had been requested by some other user.  It is based on
046     * the specification provided in early versions of the
047     * draft-weltman-ldapv3-proxy Internet Draft (this implementation is based on
048     * the "-04" revision).  Later versions of the draft, and subsequently
049     * <A HREF="http://www.ietf.org/rfc/rfc4370.txt">RFC 4370</A>, define a second
050     * version of the proxied authorization control with a different OID and
051     * different value format.  This control is supported primarily for legacy
052     * purposes, and it is recommended that new applications use the
053     * {@link ProxiedAuthorizationV2RequestControl} instead if this version.
054     * <BR><BR>
055     * The value of this control includes the DN of the user as whom the operation
056     * should be performed.  Note that it should be a distinguished name, and not an
057     * authzId value as is used in the proxied authorization V2 control.
058     * <BR><BR>
059     * This control may be used in conjunction with add, delete, compare, delete,
060     * extended, modify, modify DN, and search requests.  In that case, the
061     * associated operation will be processed under the authority of the specified
062     * authorization identity rather than the identity associated with the client
063     * connection (i.e., the user as whom that connection is bound).  Note that
064     * because of the inherent security risks associated with the use of the proxied
065     * authorization control, most directory servers which support its use enforce
066     * strict restrictions on the users that are allowed to request this control.
067     * Note that while the directory server should return a
068     * {@link ResultCode#AUTHORIZATION_DENIED} result for a proxied authorization V2
069     * control if the requester does not have the appropriate permission to use that
070     * control, this result will not necessarily be used for the same condition with
071     * the proxied authorization V1 control because this result code was not defined
072     * until the release of the proxied authorization V2 specification.
073     * code.
074     * <BR><BR>
075     * There is no corresponding response control for this request control.
076     * <BR><BR>
077     * <H2>Example</H2>
078     * The following example demonstrates the use of the proxied authorization V1
079     * control to delete an entry under the authority of the user with DN
080     * "uid=john.doe,ou=People,dc=example,dc=com":
081     * <PRE>
082     *   DeleteRequest deleteRequest =
083     *        new DeleteRequest("cn=no longer needed,dc=example,dc=com");
084     *   deleteRequest.addControl(new ProxiedAuthorizationV1RequestControl(
085     *        "uid=john.doe,ou=People,dc=example,dc=com"));
086     *
087     *   try
088     *   {
089     *     LDAPResult deleteResult = connection.delete(deleteRequest);
090     *     // If we got here, then the delete was successful.
091     *   }
092     *   catch (LDAPException le)
093     *   {
094     *     // The delete failed for some reason.  It may or may not have been
095     *     // because the authenticated user does not have permission to use the
096     *     // proxied authorization V1 control.
097     *   }
098     * </PRE>
099     */
100    @NotMutable()
101    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
102    public final class ProxiedAuthorizationV1RequestControl
103           extends Control
104    {
105      /**
106       * The OID (2.16.840.1.113730.3.4.12) for the proxied authorization v1 request
107       * control.
108       */
109      public static final String PROXIED_AUTHORIZATION_V1_REQUEST_OID =
110           "2.16.840.1.113730.3.4.12";
111    
112    
113    
114      /**
115       * The serial version UID for this serializable class.
116       */
117      private static final long serialVersionUID = 7312632337431962774L;
118    
119    
120    
121      // The DN of the target user under whose authorization the associated
122      // operation should be performed.
123      private final String proxyDN;
124    
125    
126    
127      /**
128       * Creates a new proxied authorization V1 request control that will proxy as
129       * the specified user.
130       *
131       * @param  proxyDN  The DN of the target user under whose authorization the
132       *                  associated request should be performed.  It must not be
133       *                  {@code null}, although it may be an empty string to
134       *                  request an anonymous authorization.
135       */
136      public ProxiedAuthorizationV1RequestControl(final String proxyDN)
137      {
138        super(PROXIED_AUTHORIZATION_V1_REQUEST_OID, true, encodeValue(proxyDN));
139    
140        ensureNotNull(proxyDN);
141    
142        this.proxyDN = proxyDN;
143      }
144    
145    
146    
147      /**
148       * Creates a new proxied authorization V1 request control that will proxy as
149       * the specified user.
150       *
151       * @param  proxyDN  The DN of the target user under whose authorization the
152       *                  associated request should be performed.  It must not be
153       *                  {@code null}.
154       */
155      public ProxiedAuthorizationV1RequestControl(final DN proxyDN)
156      {
157        super(PROXIED_AUTHORIZATION_V1_REQUEST_OID, true,
158              encodeValue(proxyDN.toString()));
159    
160        this.proxyDN = proxyDN.toString();
161      }
162    
163    
164    
165      /**
166       * Creates a new proxied authorization v1 request control which is decoded
167       * from the provided generic control.
168       *
169       * @param  control  The generic control to be decoded as a proxied
170       *                  authorization v1 request control.
171       *
172       * @throws  LDAPException  If the provided control cannot be decoded as a
173       *                         proxied authorization v1 request control.
174       */
175      public ProxiedAuthorizationV1RequestControl(final Control control)
176             throws LDAPException
177      {
178        super(control);
179    
180        final ASN1OctetString value = control.getValue();
181        if (value == null)
182        {
183          throw new LDAPException(ResultCode.DECODING_ERROR,
184                                  ERR_PROXY_V1_NO_VALUE.get());
185        }
186    
187        try
188        {
189          final ASN1Element valueElement = ASN1Element.decode(value.getValue());
190          final ASN1Element[] elements =
191               ASN1Sequence.decodeAsSequence(valueElement).elements();
192          proxyDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
193        }
194        catch (Exception e)
195        {
196          debugException(e);
197          throw new LDAPException(ResultCode.DECODING_ERROR,
198                                  ERR_PROXYV1_DECODE_ERROR.get(e), e);
199        }
200      }
201    
202    
203    
204      /**
205       * Encodes the provided information into an octet string that can be used as
206       * the value for this control.
207       *
208       * @param  proxyDN  The DN of the target user under whose authorization the
209       *                  associated request should be performed.  It must not be
210       *                  {@code null}, although it may be an empty string to
211       *                  request an anonymous authorization.
212       *
213       * @return  An ASN.1 octet string that can be used as the value for this
214       *          control.
215       */
216      private static ASN1OctetString encodeValue(final String proxyDN)
217      {
218        final ASN1Element[] valueElements =
219        {
220          new ASN1OctetString(proxyDN)
221        };
222    
223        return new ASN1OctetString(new ASN1Sequence(valueElements).encode());
224      }
225    
226    
227    
228      /**
229       * Retrieves the DN of the target user under whose authorization the
230       * associated request should be performed.
231       *
232       * @return  The DN of the target user under whose authorization the associated
233       *          request should be performed.
234       */
235      public String getProxyDN()
236      {
237        return proxyDN;
238      }
239    
240    
241    
242      /**
243       * {@inheritDoc}
244       */
245      @Override()
246      public String getControlName()
247      {
248        return INFO_CONTROL_NAME_PROXIED_AUTHZ_V1_REQUEST.get();
249      }
250    
251    
252    
253      /**
254       * {@inheritDoc}
255       */
256      @Override()
257      public void toString(final StringBuilder buffer)
258      {
259        buffer.append("ProxiedAuthorizationV1RequestControl(proxyDN='");
260        buffer.append(proxyDN);
261        buffer.append("')");
262      }
263    }