001    /*
002     * Copyright 2007-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2015 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=alternate.user,ou=People,dc=example,dc=com":
081     * <PRE>
082     * // Create a delete request to delete an entry.  Include the proxied
083     * // authorization v1 request control in the delete request so that the
084     * // delete will be processed as user
085     * // "uid=alternate.user,ou=People,dc=example,dc=com" instead of the user
086     * // that's actually authenticated on the connection.
087     * DeleteRequest deleteRequest =
088     *      new DeleteRequest("uid=test.user,ou=People,dc=example,dc=com");
089     * deleteRequest.addControl(new ProxiedAuthorizationV1RequestControl(
090     *      "uid=alternate.user,ou=People,dc=example,dc=com"));
091     *
092     * LDAPResult deleteResult;
093     * try
094     * {
095     *   deleteResult = connection.delete(deleteRequest);
096     *   // If we got here, then the delete was successful.
097     * }
098     * catch (LDAPException le)
099     * {
100     *   // The delete failed for some reason.  In addition to all of the normal
101     *   // reasons a delete could fail (e.g., the entry doesn't exist, or has one
102     *   // or more subordinates), proxied-authorization specific failures may
103     *   // include that the authenticated user doesn't have permission to use the
104     *   // proxied authorization control to impersonate the alternate user, that
105     *   // the alternate user doesn't exist, or that the alternate user doesn't
106     *   // have permission to perform the requested operation.
107     *   deleteResult = le.toLDAPResult();
108     *   ResultCode resultCode = le.getResultCode();
109     *   String errorMessageFromServer = le.getDiagnosticMessage();
110     * }
111     * </PRE>
112     */
113    @NotMutable()
114    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
115    public final class ProxiedAuthorizationV1RequestControl
116           extends Control
117    {
118      /**
119       * The OID (2.16.840.1.113730.3.4.12) for the proxied authorization v1 request
120       * control.
121       */
122      public static final String PROXIED_AUTHORIZATION_V1_REQUEST_OID =
123           "2.16.840.1.113730.3.4.12";
124    
125    
126    
127      /**
128       * The serial version UID for this serializable class.
129       */
130      private static final long serialVersionUID = 7312632337431962774L;
131    
132    
133    
134      // The DN of the target user under whose authorization the associated
135      // operation should be performed.
136      private final String proxyDN;
137    
138    
139    
140      /**
141       * Creates a new proxied authorization V1 request control that will proxy as
142       * the specified user.
143       *
144       * @param  proxyDN  The DN of the target user under whose authorization the
145       *                  associated request should be performed.  It must not be
146       *                  {@code null}, although it may be an empty string to
147       *                  request an anonymous authorization.
148       */
149      public ProxiedAuthorizationV1RequestControl(final String proxyDN)
150      {
151        super(PROXIED_AUTHORIZATION_V1_REQUEST_OID, true, encodeValue(proxyDN));
152    
153        ensureNotNull(proxyDN);
154    
155        this.proxyDN = proxyDN;
156      }
157    
158    
159    
160      /**
161       * Creates a new proxied authorization V1 request control that will proxy as
162       * the specified user.
163       *
164       * @param  proxyDN  The DN of the target user under whose authorization the
165       *                  associated request should be performed.  It must not be
166       *                  {@code null}.
167       */
168      public ProxiedAuthorizationV1RequestControl(final DN proxyDN)
169      {
170        super(PROXIED_AUTHORIZATION_V1_REQUEST_OID, true,
171              encodeValue(proxyDN.toString()));
172    
173        this.proxyDN = proxyDN.toString();
174      }
175    
176    
177    
178      /**
179       * Creates a new proxied authorization v1 request control which is decoded
180       * from the provided generic control.
181       *
182       * @param  control  The generic control to be decoded as a proxied
183       *                  authorization v1 request control.
184       *
185       * @throws  LDAPException  If the provided control cannot be decoded as a
186       *                         proxied authorization v1 request control.
187       */
188      public ProxiedAuthorizationV1RequestControl(final Control control)
189             throws LDAPException
190      {
191        super(control);
192    
193        final ASN1OctetString value = control.getValue();
194        if (value == null)
195        {
196          throw new LDAPException(ResultCode.DECODING_ERROR,
197                                  ERR_PROXY_V1_NO_VALUE.get());
198        }
199    
200        try
201        {
202          final ASN1Element valueElement = ASN1Element.decode(value.getValue());
203          final ASN1Element[] elements =
204               ASN1Sequence.decodeAsSequence(valueElement).elements();
205          proxyDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
206        }
207        catch (Exception e)
208        {
209          debugException(e);
210          throw new LDAPException(ResultCode.DECODING_ERROR,
211                                  ERR_PROXYV1_DECODE_ERROR.get(e), e);
212        }
213      }
214    
215    
216    
217      /**
218       * Encodes the provided information into an octet string that can be used as
219       * the value for this control.
220       *
221       * @param  proxyDN  The DN of the target user under whose authorization the
222       *                  associated request should be performed.  It must not be
223       *                  {@code null}, although it may be an empty string to
224       *                  request an anonymous authorization.
225       *
226       * @return  An ASN.1 octet string that can be used as the value for this
227       *          control.
228       */
229      private static ASN1OctetString encodeValue(final String proxyDN)
230      {
231        final ASN1Element[] valueElements =
232        {
233          new ASN1OctetString(proxyDN)
234        };
235    
236        return new ASN1OctetString(new ASN1Sequence(valueElements).encode());
237      }
238    
239    
240    
241      /**
242       * Retrieves the DN of the target user under whose authorization the
243       * associated request should be performed.
244       *
245       * @return  The DN of the target user under whose authorization the associated
246       *          request should be performed.
247       */
248      public String getProxyDN()
249      {
250        return proxyDN;
251      }
252    
253    
254    
255      /**
256       * {@inheritDoc}
257       */
258      @Override()
259      public String getControlName()
260      {
261        return INFO_CONTROL_NAME_PROXIED_AUTHZ_V1_REQUEST.get();
262      }
263    
264    
265    
266      /**
267       * {@inheritDoc}
268       */
269      @Override()
270      public void toString(final StringBuilder buffer)
271      {
272        buffer.append("ProxiedAuthorizationV1RequestControl(proxyDN='");
273        buffer.append(proxyDN);
274        buffer.append("')");
275      }
276    }