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 2007-2010 Sun Microsystems, Inc.
015 * Portions Copyright 2013-2016 ForgeRock AS.
016 */
017package org.opends.server.core;
018
019import java.util.ArrayList;
020import java.util.List;
021
022import org.forgerock.i18n.LocalizableMessage;
023import org.forgerock.i18n.LocalizedIllegalArgumentException;
024import org.forgerock.i18n.slf4j.LocalizedLogger;
025import org.forgerock.opendj.ldap.ByteString;
026import org.forgerock.opendj.ldap.DN;
027import org.forgerock.opendj.ldap.ResultCode;
028import org.opends.server.api.ClientConnection;
029import org.opends.server.types.*;
030import org.opends.server.types.operation.PreParseBindOperation;
031import org.opends.server.workflowelement.localbackend.LocalBackendBindOperation;
032
033import static org.forgerock.opendj.ldap.ResultCode.*;
034import static org.opends.messages.CoreMessages.*;
035import static org.opends.server.core.DirectoryServer.*;
036import static org.opends.server.loggers.AccessLogger.*;
037import static org.opends.server.workflowelement.localbackend.LocalBackendWorkflowElement.*;
038
039/**
040 * This class defines an operation that may be used to authenticate a user to
041 * the Directory Server.  Note that for security restrictions, response messages
042 * that may be returned to the client must be carefully cleaned to ensure that
043 * they do not provide a malicious client with information that may be useful in
044 * an attack.  This does impact the debuggability of the server, but that can
045 * be addressed by calling the <CODE>setAuthFailureReason</CODE> method, which
046 * can provide a reason for a failure in a form that will not be returned to the
047 * client but may be written to a log file.
048 */
049public class BindOperationBasis
050             extends AbstractOperation
051             implements BindOperation, PreParseBindOperation
052{
053  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
054
055  /** The credentials used for SASL authentication. */
056  private ByteString saslCredentials;
057
058  /** The server SASL credentials provided to the client in the response. */
059  private ByteString serverSASLCredentials;
060
061  /** The authentication info for this bind operation. */
062  private AuthenticationInfo authInfo;
063
064  /** The authentication type used for this bind operation. */
065  private AuthenticationType authType;
066
067  /** The raw, unprocessed bind DN as contained in the client request. */
068  private ByteString rawBindDN;
069
070  /** The password used for simple authentication. */
071  private ByteString simplePassword;
072
073  /** The bind DN used for this bind operation. */
074  private DN bindDN;
075
076  /** The DN of the user entry that is attempting to authenticate. */
077  private DN userEntryDN;
078
079  /**
080   * The DN of the user as whom a SASL authentication was attempted (regardless
081   * of whether the authentication was successful) for the purpose of updating
082   * password policy state information.
083   */
084  private Entry saslAuthUserEntry;
085
086  /** The set of response controls for this bind operation. */
087  private final List<Control> responseControls = new ArrayList<>(0);
088
089  /** A message explaining the reason for the authentication failure. */
090  private LocalizableMessage authFailureReason;
091
092  /** The SASL mechanism used for SASL authentication. */
093  private String saslMechanism;
094
095  /**
096   * A string representation of the protocol version for this bind operation.
097   */
098  private String protocolVersion;
099
100  /**
101   * Creates a new simple bind operation with the provided information.
102   *
103   * @param  clientConnection  The client connection with which this operation
104   *                           is associated.
105   * @param  operationID       The operation ID for this operation.
106   * @param  messageID         The message ID of the request with which this
107   *                           operation is associated.
108   * @param  requestControls   The set of controls included in the request.
109   * @param  protocolVersion   The string representation of the protocol version
110   *                           associated with this bind request.
111   * @param  rawBindDN         The raw, unprocessed bind DN as provided in the
112   *                           request from the client.
113   * @param  simplePassword    The password to use for the simple
114   *                           authentication.
115   */
116  public BindOperationBasis(ClientConnection clientConnection, long operationID,
117                       int messageID, List<Control> requestControls,
118                       String protocolVersion, ByteString rawBindDN,
119                       ByteString simplePassword)
120  {
121    super(clientConnection, operationID, messageID, requestControls);
122
123    this.protocolVersion = protocolVersion;
124
125    setRawBindDN(rawBindDN);
126    setSimplePassword(simplePassword);
127
128    cancelResult = getBindCancelResult();
129  }
130
131
132
133  /**
134   * Creates a new SASL bind operation with the provided information.
135   *
136   * @param  clientConnection  The client connection with which this operation
137   *                           is associated.
138   * @param  operationID       The operation ID for this operation.
139   * @param  messageID         The message ID of the request with which this
140   *                           operation is associated.
141   * @param  requestControls   The set of controls included in the request.
142   * @param  protocolVersion   The string representation of the protocol version
143   *                           associated with this bind request.
144   * @param  rawBindDN         The raw, unprocessed bind DN as provided in the
145   *                           request from the client.
146   * @param  saslMechanism     The SASL mechanism included in the request.
147   * @param  saslCredentials   The optional SASL credentials included in the
148   *                           request.
149   */
150  public BindOperationBasis(ClientConnection clientConnection, long operationID,
151                       int messageID, List<Control> requestControls,
152                       String protocolVersion, ByteString rawBindDN,
153                       String saslMechanism, ByteString saslCredentials)
154  {
155    super(clientConnection, operationID, messageID, requestControls);
156
157    this.protocolVersion = protocolVersion;
158    this.authType        = AuthenticationType.SASL;
159    this.saslMechanism   = saslMechanism;
160    this.saslCredentials = saslCredentials;
161
162    setRawBindDN(rawBindDN);
163
164    cancelResult = getBindCancelResult();
165  }
166
167  /**
168   * Creates a new simple bind operation with the provided information.
169   *
170   * @param  clientConnection  The client connection with which this operation
171   *                           is associated.
172   * @param  operationID       The operation ID for this operation.
173   * @param  messageID         The message ID of the request with which this
174   *                           operation is associated.
175   * @param  requestControls   The set of controls included in the request.
176   * @param  protocolVersion   The string representation of the protocol version
177   *                           associated with this bind request.
178   * @param  bindDN            The bind DN for this bind operation.
179   * @param  simplePassword    The password to use for the simple
180   *                           authentication.
181   */
182  public BindOperationBasis(ClientConnection clientConnection, long operationID,
183                       int messageID, List<Control> requestControls,
184                       String protocolVersion, DN bindDN,
185                       ByteString simplePassword)
186  {
187    super(clientConnection, operationID, messageID, requestControls);
188
189    this.protocolVersion = protocolVersion;
190    this.bindDN          = bindDN;
191
192    rawBindDN = computeRawBindDN(bindDN);
193
194    setSimplePassword(simplePassword);
195
196    cancelResult = getBindCancelResult();
197  }
198
199
200
201  /**
202   * Creates a new SASL bind operation with the provided information.
203   *
204   * @param  clientConnection  The client connection with which this operation
205   *                           is associated.
206   * @param  operationID       The operation ID for this operation.
207   * @param  messageID         The message ID of the request with which this
208   *                           operation is associated.
209   * @param  requestControls   The set of controls included in the request.
210   * @param  protocolVersion   The string representation of the protocol version
211   *                           associated with this bind request.
212   * @param  bindDN            The bind DN for this bind operation.
213   * @param  saslMechanism     The SASL mechanism included in the request.
214   * @param  saslCredentials   The optional SASL credentials included in the
215   *                           request.
216   */
217  public BindOperationBasis(ClientConnection clientConnection, long operationID,
218                       int messageID, List<Control> requestControls,
219                       String protocolVersion, DN bindDN,
220                       String saslMechanism, ByteString saslCredentials)
221  {
222    super(clientConnection, operationID, messageID, requestControls);
223
224    this.protocolVersion = protocolVersion;
225    this.authType        = AuthenticationType.SASL;
226    this.bindDN          = bindDN;
227    this.saslMechanism   = saslMechanism;
228    this.saslCredentials = saslCredentials;
229
230    rawBindDN = computeRawBindDN(bindDN);
231
232    cancelResult = getBindCancelResult();
233  }
234
235  private ByteString computeRawBindDN(DN bindDN)
236  {
237    if (bindDN != null)
238    {
239      return ByteString.valueOfUtf8(bindDN.toString());
240    }
241    return ByteString.empty();
242  }
243
244  private CancelResult getBindCancelResult()
245  {
246    return new CancelResult(CANNOT_CANCEL, ERR_CANNOT_CANCEL_BIND.get());
247  }
248
249  /** {@inheritDoc} */
250  @Override
251  public DN getProxiedAuthorizationDN()
252  {
253    return null;
254  }
255
256  /** {@inheritDoc} */
257  @Override
258  public void setProxiedAuthorizationDN(DN proxiedAuthorizationDN)
259  {
260  }
261
262  /** {@inheritDoc} */
263  @Override
264  public final AuthenticationType getAuthenticationType()
265  {
266    return authType;
267  }
268
269  /** {@inheritDoc} */
270  @Override
271  public final ByteString getRawBindDN()
272  {
273    return rawBindDN;
274  }
275
276  /** {@inheritDoc} */
277  @Override
278  public final void setRawBindDN(ByteString rawBindDN)
279  {
280    if (rawBindDN != null)
281    {
282      this.rawBindDN = rawBindDN;
283    }
284    else
285    {
286      this.rawBindDN = ByteString.empty();
287    }
288
289    bindDN = null;
290  }
291
292  @Override
293  public final DN getBindDN()
294  {
295    try
296    {
297      if (bindDN == null)
298      {
299        bindDN = DN.valueOf(rawBindDN);
300      }
301    }
302    catch (LocalizedIllegalArgumentException e)
303    {
304      logger.traceException(e);
305
306      setResultCode(ResultCode.INVALID_CREDENTIALS);
307      setAuthFailureReason(e.getMessageObject());
308    }
309    return bindDN;
310  }
311
312  @Override
313  public final ByteString getSimplePassword()
314  {
315    return simplePassword;
316  }
317
318  /** {@inheritDoc} */
319  @Override
320  public final void setSimplePassword(ByteString simplePassword)
321  {
322    if (simplePassword != null)
323    {
324      this.simplePassword = simplePassword;
325    }
326    else
327    {
328      this.simplePassword = ByteString.empty();
329    }
330
331    authType        = AuthenticationType.SIMPLE;
332    saslMechanism   = null;
333    saslCredentials = null;
334  }
335
336  /** {@inheritDoc} */
337  @Override
338  public final String getSASLMechanism()
339  {
340    return saslMechanism;
341  }
342
343  /** {@inheritDoc} */
344  @Override
345  public final ByteString getSASLCredentials()
346  {
347    return saslCredentials;
348  }
349
350  /** {@inheritDoc} */
351  @Override
352  public final void setSASLCredentials(String saslMechanism,
353                                       ByteString saslCredentials)
354  {
355    this.saslMechanism   = saslMechanism;
356    this.saslCredentials = saslCredentials;
357
358    authType       = AuthenticationType.SASL;
359    simplePassword = null;
360  }
361
362  /** {@inheritDoc} */
363  @Override
364  public final ByteString getServerSASLCredentials()
365  {
366    return serverSASLCredentials;
367  }
368
369  /** {@inheritDoc} */
370  @Override
371  public final void setServerSASLCredentials(ByteString serverSASLCredentials)
372  {
373    this.serverSASLCredentials = serverSASLCredentials;
374  }
375
376  /** {@inheritDoc} */
377  @Override
378  public final Entry getSASLAuthUserEntry()
379  {
380    return saslAuthUserEntry;
381  }
382
383  /** {@inheritDoc} */
384  @Override
385  public final void setSASLAuthUserEntry(Entry saslAuthUserEntry)
386  {
387    this.saslAuthUserEntry = saslAuthUserEntry;
388  }
389
390  /** {@inheritDoc} */
391  @Override
392  public final LocalizableMessage getAuthFailureReason()
393  {
394    return authFailureReason;
395  }
396
397  /** {@inheritDoc} */
398  @Override
399  public final void setAuthFailureReason(LocalizableMessage message)
400  {
401    if (DirectoryServer.returnBindErrorMessages())
402    {
403      appendErrorMessage(message);
404    }
405    else
406    {
407      authFailureReason = message;
408    }
409  }
410
411  /** {@inheritDoc} */
412  @Override
413  public final DN getUserEntryDN()
414  {
415    return userEntryDN;
416  }
417
418  /** {@inheritDoc} */
419  @Override
420  public final AuthenticationInfo getAuthenticationInfo()
421  {
422    return authInfo;
423  }
424
425  /** {@inheritDoc} */
426  @Override
427  public final void setAuthenticationInfo(AuthenticationInfo authInfo)
428  {
429    this.authInfo = authInfo;
430  }
431
432  /** {@inheritDoc} */
433  @Override
434  public final OperationType getOperationType()
435  {
436    // Note that no debugging will be done in this method because it is a likely
437    // candidate for being called by the logging subsystem.
438    return OperationType.BIND;
439  }
440
441  /** {@inheritDoc} */
442  @Override
443  public final List<Control> getResponseControls()
444  {
445    return responseControls;
446  }
447
448  /** {@inheritDoc} */
449  @Override
450  public final void addResponseControl(Control control)
451  {
452    responseControls.add(control);
453  }
454
455  /** {@inheritDoc} */
456  @Override
457  public final void removeResponseControl(Control control)
458  {
459    responseControls.remove(control);
460  }
461
462  /** {@inheritDoc} */
463  @Override
464  public final void toString(StringBuilder buffer)
465  {
466    buffer.append("BindOperation(connID=");
467    buffer.append(clientConnection.getConnectionID());
468    buffer.append(", opID=");
469    buffer.append(operationID);
470    buffer.append(", protocol=\"");
471    buffer.append(clientConnection.getProtocol());
472    buffer.append(" ");
473    buffer.append(protocolVersion);
474    buffer.append(", dn=");
475    buffer.append(rawBindDN);
476    buffer.append(", authType=");
477    buffer.append(authType);
478    buffer.append(")");
479  }
480
481  /** {@inheritDoc} */
482  @Override
483  public void setUserEntryDN(DN userEntryDN)
484  {
485    this.userEntryDN = userEntryDN;
486  }
487
488  /** {@inheritDoc} */
489  @Override
490  public String getProtocolVersion()
491  {
492    return protocolVersion;
493  }
494
495  /** {@inheritDoc} */
496  @Override
497  public void setProtocolVersion(String protocolVersion)
498  {
499    this.protocolVersion = protocolVersion;
500  }
501
502  /** {@inheritDoc} */
503  @Override
504  public final void run()
505  {
506    // Start the processing timer and initially set the result to indicate that
507    // the result is unknown.
508    setResultCode(ResultCode.UNDEFINED);
509    setProcessingStartTime();
510
511    logBindRequest(this);
512
513    // Wipe out any existing authentication for the client connection and create
514    // a placeholder that will be used if the bind is successful.
515    ClientConnection clientConnection = getClientConnection();
516    clientConnection.setUnauthenticated();
517
518    // Abandon any operations that may be in progress for the client.
519    LocalizableMessage cancelReason = INFO_CANCELED_BY_BIND_REQUEST.get();
520    CancelRequest cancelRequest = new CancelRequest(true, cancelReason);
521    clientConnection.cancelAllOperationsExcept(cancelRequest, getMessageID());
522
523
524    // This flag is set to true as soon as a workflow has been executed.
525    boolean workflowExecuted = false;
526    try
527    {
528      // Invoke the pre-parse bind plugins.
529      if (!processOperationResult(getPluginConfigManager().invokePreParseBindPlugins(this)))
530      {
531        return;
532      }
533
534
535      // Process the bind DN to convert it from the raw form as provided by the
536      // client into the form required for the rest of the bind processing.
537      DN bindDN = getBindDN();
538      if (bindDN == null){
539        return;
540      }
541
542      // If this is a simple bind
543      // Then check whether the bind DN is actually one of the alternate root DNs
544      // defined in the server.  If so, then replace it with the actual DN
545      // for that user.
546      switch (getAuthenticationType())
547      {
548        case SIMPLE:
549          DN actualRootDN = DirectoryServer.getActualRootBindDN(bindDN);
550          if (actualRootDN != null)
551          {
552            bindDN = actualRootDN;
553          }
554      }
555
556      workflowExecuted = execute(this, bindDN);
557    }
558    catch(CanceledOperationException coe)
559    {
560      // This shouldn't happen for bind operations. Just cancel anyways
561      logger.traceException(coe);
562
563      setResultCode(ResultCode.CANCELLED);
564
565      appendErrorMessage(cancelRequest.getCancelReason());
566    }
567    finally
568    {
569      setProcessingStopTime();
570      logBindResponse(this);
571
572      // Send the bind response to the client.
573      clientConnection.sendResponse(this);
574
575      // If the bind processing is finished, then unset the "bind in progress"
576      // flag to allow other operations to be processed on the connection.
577      if (getResultCode() != ResultCode.SASL_BIND_IN_PROGRESS)
578      {
579        clientConnection.finishSaslBind();
580      }
581      clientConnection.finishBind();
582
583      invokePostResponsePlugins(workflowExecuted);
584    }
585  }
586
587  /**
588   * Invokes the post response plugins. If a workflow has been executed
589   * then invoke the post response plugins provided by the workflow
590   * elements of the workflow, otherwise invoke the post response plugins
591   * that have been registered with the current operation.
592   *
593   * @param workflowExecuted <code>true</code> if a workflow has been executed
594   */
595  private void invokePostResponsePlugins(boolean workflowExecuted)
596  {
597    // Invoke the post response plugins
598    if (workflowExecuted)
599    {
600      // The post responses are provided by the workflow elements of the workflow.
601      List localOperations = (List) getAttachment(Operation.LOCALBACKENDOPERATIONS);
602      if (localOperations != null)
603      {
604        for (Object localOp : localOperations)
605        {
606          LocalBackendBindOperation localOperation = (LocalBackendBindOperation) localOp;
607          // Invoke the post-response bind plugins.
608          getPluginConfigManager().invokePostResponseBindPlugins(localOperation);
609        }
610      }
611      else
612      {
613        // The current operation does not implement any bind post response
614        // interface so we cannot invoke any post-response plugin.
615      }
616    }
617  }
618
619  /** {@inheritDoc} */
620  @Override
621  public void updateOperationErrMsgAndResCode()
622  {
623    LocalizableMessage message = ERR_BIND_OPERATION_UNKNOWN_USER.get();
624    setResultCode(ResultCode.INVALID_CREDENTIALS);
625    setAuthFailureReason(message);
626  }
627}