001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2006-2008 Sun Microsystems, Inc.
015 * Portions Copyright 2011-2016 ForgeRock AS.
016 */
017package org.opends.server.controls;
018
019import java.io.IOException;
020import org.forgerock.i18n.LocalizableMessage;
021import org.opends.server.api.AuthenticationPolicyState;
022import org.opends.server.core.DirectoryServer;
023import org.opends.server.core.PasswordPolicyState;
024import org.forgerock.i18n.slf4j.LocalizedLogger;
025import org.forgerock.opendj.io.ASN1;
026import org.forgerock.opendj.io.ASN1Reader;
027import org.forgerock.opendj.io.ASN1Writer;
028import org.opends.server.types.*;
029import org.forgerock.opendj.ldap.DN;
030import org.forgerock.opendj.ldap.ResultCode;
031import org.forgerock.opendj.ldap.ByteString;
032import static org.opends.messages.ProtocolMessages.*;
033import static org.opends.server.util.ServerConstants.*;
034import static org.opends.server.util.StaticUtils.*;
035
036/**
037 * This class implements version 1 of the proxied authorization control as
038 * defined in early versions of draft-weltman-ldapv3-proxy (this implementation
039 * is based on the "-04" revision).  It makes it possible for one user to
040 * request that an operation be performed under the authorization of another.
041 * The target user is specified as a DN in the control value, which
042 * distinguishes it from later versions of the control (which used a different
043 * OID) in which the target user was specified using an authorization ID.
044 */
045public class ProxiedAuthV1Control
046       extends Control
047{
048  /** ControlDecoder implementation to decode this control from a ByteString. */
049  private static final class Decoder
050      implements ControlDecoder<ProxiedAuthV1Control>
051  {
052    @Override
053    public ProxiedAuthV1Control decode(boolean isCritical, ByteString value)
054        throws DirectoryException
055    {
056      if (!isCritical)
057      {
058        LocalizableMessage message = ERR_PROXYAUTH1_CONTROL_NOT_CRITICAL.get();
059        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
060      }
061
062      if (value == null)
063      {
064        LocalizableMessage message = ERR_PROXYAUTH1_NO_CONTROL_VALUE.get();
065        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
066      }
067
068      ASN1Reader reader = ASN1.getReader(value);
069      DN authorizationDN;
070      try
071      {
072        reader.readStartSequence();
073        authorizationDN = DN.valueOf(reader.readOctetString());
074        reader.readEndSequence();
075      }
076      catch (Exception e)
077      {
078        logger.traceException(e);
079
080        LocalizableMessage message =
081            ERR_PROXYAUTH1_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
082        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
083      }
084
085      return new ProxiedAuthV1Control(isCritical, authorizationDN);
086    }
087
088    @Override
089    public String getOID()
090    {
091      return OID_PROXIED_AUTH_V1;
092    }
093
094  }
095
096  /** The Control Decoder that can be used to decode this control. */
097  public static final ControlDecoder<ProxiedAuthV1Control> DECODER =
098    new Decoder();
099  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
100
101
102
103
104  /** The raw, unprocessed authorization DN from the control value. */
105  private ByteString rawAuthorizationDN;
106
107  /** The processed authorization DN from the control value. */
108  private DN authorizationDN;
109
110
111
112  /**
113   * Creates a new instance of the proxied authorization v1 control with the
114   * provided information.
115   *
116   * @param  rawAuthorizationDN  The raw, unprocessed authorization DN from the
117   *                             control value.  It must not be {@code null}.
118   */
119  public ProxiedAuthV1Control(ByteString rawAuthorizationDN)
120  {
121    this(true, rawAuthorizationDN);
122  }
123
124
125
126  /**
127   * Creates a new instance of the proxied authorization v1 control with the
128   * provided information.
129   *
130   * @param  authorizationDN  The authorization DN from the control value.  It
131   *                          must not be {@code null}.
132   */
133  public ProxiedAuthV1Control(DN authorizationDN)
134  {
135    this(true, authorizationDN);
136  }
137
138
139
140  /**
141   * Creates a new instance of the proxied authorization v1 control with the
142   * provided information.
143   *
144   * @param  isCritical          Indicates whether support for this control
145   *                             should be considered a critical part of the
146   *                             server processing.
147   * @param  rawAuthorizationDN  The raw, unprocessed authorization DN from the
148   *                             control value.
149   */
150  public ProxiedAuthV1Control(boolean isCritical, ByteString rawAuthorizationDN)
151  {
152    super(OID_PROXIED_AUTH_V1, isCritical);
153
154
155    this.rawAuthorizationDN = rawAuthorizationDN;
156
157    authorizationDN = null;
158  }
159
160
161
162  /**
163   * Creates a new instance of the proxied authorization v1 control with the
164   * provided information.
165   *
166   * @param  isCritical          Indicates whether support for this control
167   *                             should be considered a critical part of the
168   *                             server processing.
169   * @param  authorizationDN     The authorization DN from the control value.
170   *                             It must not be {@code null}.
171   */
172  public ProxiedAuthV1Control(boolean isCritical, DN authorizationDN)
173  {
174    super(OID_PROXIED_AUTH_V1, isCritical);
175
176
177    this.authorizationDN = authorizationDN;
178
179    rawAuthorizationDN = ByteString.valueOfUtf8(authorizationDN.toString());
180  }
181
182
183
184  /**
185   * Writes this control's value to an ASN.1 writer. The value (if any) must be
186   * written as an ASN1OctetString.
187   *
188   * @param writer The ASN.1 writer to use.
189   * @throws IOException If a problem occurs while writing to the stream.
190   */
191  @Override
192  protected void writeValue(ASN1Writer writer) throws IOException {
193    writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE);
194
195    writer.writeStartSequence();
196    writer.writeOctetString(rawAuthorizationDN);
197    writer.writeEndSequence();
198
199    writer.writeEndSequence();
200  }
201
202
203
204  /**
205   * Retrieves the raw, unprocessed authorization DN from the control value.
206   *
207   * @return  The raw, unprocessed authorization DN from the control value.
208   */
209  public ByteString getRawAuthorizationDN()
210  {
211    return rawAuthorizationDN;
212  }
213
214
215
216  /**
217   * Retrieves the authorization DN from the control value.
218   *
219   * @return  The authorization DN from the control value.
220   *
221   * @throws  DirectoryException  If a problem occurs while attempting to decode
222   *                              the raw authorization DN as a DN.
223   */
224  public DN getAuthorizationDN()
225         throws DirectoryException
226  {
227    if (authorizationDN == null)
228    {
229      authorizationDN = DN.valueOf(rawAuthorizationDN);
230    }
231
232    return authorizationDN;
233  }
234
235
236
237  /**
238   * Retrieves the authorization entry for this proxied authorization V1
239   * control.  It will also perform any necessary password policy checks to
240   * ensure that the associated user account is suitable for use in performing
241   * this processing.
242   *
243   * @return  The entry for user specified as the authorization identity in this
244   *          proxied authorization V1 control, or {@code null} if the
245   *          authorization DN is the null DN.
246   *
247   * @throws  DirectoryException  If the target user does not exist or is not
248   *                              available for use, or if a problem occurs
249   *                              while making the determination.
250   */
251  public Entry getAuthorizationEntry()
252         throws DirectoryException
253  {
254    DN authzDN = getAuthorizationDN();
255    if (authzDN.isRootDN())
256    {
257      return null;
258    }
259
260
261    // See if the authorization DN is one of the alternate bind DNs for one of
262    // the root users and if so then map it accordingly.
263    DN actualDN = DirectoryServer.getActualRootBindDN(authzDN);
264    if (actualDN != null)
265    {
266      authzDN = actualDN;
267    }
268
269
270    Entry userEntry = DirectoryServer.getEntry(authzDN);
271    if (userEntry == null)
272    {
273      // The requested user does not exist.
274      LocalizableMessage message = ERR_PROXYAUTH1_NO_SUCH_USER.get(authzDN);
275      throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message);
276    }
277
278
279    // FIXME -- We should provide some mechanism for enabling debug
280    // processing.
281    AuthenticationPolicyState state = AuthenticationPolicyState.forUser(
282        userEntry, false);
283
284    if (state.isDisabled())
285    {
286      LocalizableMessage message = ERR_PROXYAUTH1_UNUSABLE_ACCOUNT.get(userEntry.getName());
287      throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message);
288    }
289
290    if (state.isPasswordPolicy())
291    {
292      PasswordPolicyState pwpState = (PasswordPolicyState) state;
293      if (pwpState.isAccountExpired() || pwpState.isLocked() || pwpState.isPasswordExpired())
294      {
295        LocalizableMessage message = ERR_PROXYAUTH1_UNUSABLE_ACCOUNT.get(authzDN);
296        throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message);
297      }
298    }
299
300    // If we've made it here, then the user is acceptable.
301    return userEntry;
302  }
303
304
305
306  /**
307   * Appends a string representation of this proxied auth v1 control to the
308   * provided buffer.
309   *
310   * @param  buffer  The buffer to which the information should be appended.
311   */
312  @Override
313  public void toString(StringBuilder buffer)
314  {
315    buffer.append("ProxiedAuthorizationV1Control(authorizationDN=\"");
316    buffer.append(rawAuthorizationDN);
317    buffer.append("\")");
318  }
319}
320