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 2007-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.core;
028    import org.opends.messages.Message;
029    import org.opends.messages.MessageBuilder;
030    
031    
032    import static org.opends.server.core.CoreConstants.LOG_ELEMENT_AUTH_TYPE;
033    import static org.opends.server.core.CoreConstants.LOG_ELEMENT_BIND_DN;
034    import static org.opends.server.core.CoreConstants.LOG_ELEMENT_ERROR_MESSAGE;
035    import static org.opends.server.core.CoreConstants.LOG_ELEMENT_MATCHED_DN;
036    import static org.opends.server.core.CoreConstants.LOG_ELEMENT_PROCESSING_TIME;
037    import static org.opends.server.core.CoreConstants.LOG_ELEMENT_REFERRAL_URLS;
038    import static org.opends.server.core.CoreConstants.LOG_ELEMENT_RESULT_CODE;
039    import static org.opends.server.core.CoreConstants.LOG_ELEMENT_SASL_MECHANISM;
040    import static org.opends.server.loggers.AccessLogger.logBindRequest;
041    import static org.opends.server.loggers.AccessLogger.logBindResponse;
042    import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
043    import static org.opends.messages.CoreMessages.*;
044    
045    import java.util.ArrayList;
046    import java.util.Iterator;
047    import java.util.List;
048    
049    import org.opends.server.api.ClientConnection;
050    import org.opends.server.api.plugin.PluginResult;
051    import org.opends.server.loggers.debug.DebugLogger;
052    import org.opends.server.loggers.debug.DebugTracer;
053    import org.opends.server.protocols.asn1.ASN1OctetString;
054    import org.opends.server.types.*;
055    import org.opends.server.types.operation.PreParseBindOperation;
056    import org.opends.server.workflowelement.localbackend.*;
057    
058    
059    
060    
061    /**
062     * This class defines an operation that may be used to authenticate a user to
063     * the Directory Server.  Note that for security restrictions, response messages
064     * that may be returned to the client must be carefully cleaned to ensure that
065     * they do not provide a malicious client with information that may be useful in
066     * an attack.  This does impact the debugability of the server, but that can
067     * be addressed by calling the <CODE>setAuthFailureReason</CODE> method, which
068     * can provide a reason for a failure in a form that will not be returned to the
069     * client but may be written to a log file.
070     */
071    public class BindOperationBasis
072                 extends AbstractOperation
073                 implements BindOperation, PreParseBindOperation
074    {
075      /**
076       * The tracer object for the debug logger.
077       */
078      private static final DebugTracer TRACER = DebugLogger.getTracer();
079    
080      // The credentials used for SASL authentication.
081      private ASN1OctetString saslCredentials;
082    
083      // The server SASL credentials provided to the client in the response.
084      private ASN1OctetString serverSASLCredentials;
085    
086      // The authentication info for this bind operation.
087      private AuthenticationInfo authInfo = null;
088    
089      // The authentication type used for this bind operation.
090      private AuthenticationType authType;
091    
092      // The raw, unprocessed bind DN as contained in the client request.
093      private ByteString rawBindDN;
094    
095      // The password used for simple authentication.
096      private ByteString simplePassword;
097    
098      // The bind DN used for this bind operation.
099      private DN bindDN;
100    
101      // The DN of the user entry that is attempting to authenticate.
102      private DN userEntryDN;
103    
104      // The DN of the user as whom a SASL authentication was attempted (regardless
105      // of whether the authentication was successful) for the purpose of updating
106      // password policy state information.
107      private Entry saslAuthUserEntry;
108    
109      // The set of response controls for this bind operation.
110      private List<Control> responseControls;
111    
112      // A message explaining the reason for the authentication failure.
113      private Message authFailureReason;
114    
115      // The SASL mechanism used for SASL authentication.
116      private String saslMechanism;
117    
118      // A string representation of the protocol version for this bind operation.
119      private String protocolVersion;
120    
121      /**
122       * Creates a new simple bind operation with the provided information.
123       *
124       * @param  clientConnection  The client connection with which this operation
125       *                           is associated.
126       * @param  operationID       The operation ID for this operation.
127       * @param  messageID         The message ID of the request with which this
128       *                           operation is associated.
129       * @param  requestControls   The set of controls included in the request.
130       * @param  protocolVersion   The string representation of the protocol version
131       *                           associated with this bind request.
132       * @param  rawBindDN         The raw, unprocessed bind DN as provided in the
133       *                           request from the client.
134       * @param  simplePassword    The password to use for the simple
135       *                           authentication.
136       */
137      public BindOperationBasis(ClientConnection clientConnection, long operationID,
138                           int messageID, List<Control> requestControls,
139                           String protocolVersion, ByteString rawBindDN,
140                           ByteString simplePassword)
141      {
142        super(clientConnection, operationID, messageID, requestControls);
143    
144    
145        this.protocolVersion = protocolVersion;
146        this.authType        = AuthenticationType.SIMPLE;
147        this.saslMechanism   = null;
148        this.saslCredentials = null;
149    
150        if (rawBindDN == null)
151        {
152          this.rawBindDN = new ASN1OctetString();
153        }
154        else
155        {
156          this.rawBindDN = rawBindDN;
157        }
158    
159        if (simplePassword == null)
160        {
161          this.simplePassword = new ASN1OctetString();
162        }
163        else
164        {
165          this.simplePassword = simplePassword;
166        }
167    
168        bindDN                   = null;
169        userEntryDN              = null;
170        responseControls         = new ArrayList<Control>(0);
171        authFailureReason        = null;
172        saslAuthUserEntry        = null;
173    
174        cancelResult = new CancelResult(ResultCode.CANNOT_CANCEL,
175            ERR_CANNOT_CANCEL_BIND.get());
176      }
177    
178    
179    
180      /**
181       * Creates a new SASL bind operation with the provided information.
182       *
183       * @param  clientConnection  The client connection with which this operation
184       *                           is associated.
185       * @param  operationID       The operation ID for this operation.
186       * @param  messageID         The message ID of the request with which this
187       *                           operation is associated.
188       * @param  requestControls   The set of controls included in the request.
189       * @param  protocolVersion   The string representation of the protocol version
190       *                           associated with this bind request.
191       * @param  rawBindDN         The raw, unprocessed bind DN as provided in the
192       *                           request from the client.
193       * @param  saslMechanism     The SASL mechanism included in the request.
194       * @param  saslCredentials   The optional SASL credentials included in the
195       *                           request.
196       */
197      public BindOperationBasis(ClientConnection clientConnection, long operationID,
198                           int messageID, List<Control> requestControls,
199                           String protocolVersion, ByteString rawBindDN,
200                           String saslMechanism, ASN1OctetString saslCredentials)
201      {
202        super(clientConnection, operationID, messageID, requestControls);
203    
204    
205        this.protocolVersion = protocolVersion;
206        this.authType        = AuthenticationType.SASL;
207        this.saslMechanism   = saslMechanism;
208        this.saslCredentials = saslCredentials;
209        this.simplePassword  = null;
210    
211        if (rawBindDN == null)
212        {
213          this.rawBindDN = new ASN1OctetString();
214        }
215        else
216        {
217          this.rawBindDN = rawBindDN;
218        }
219    
220        bindDN                 = null;
221        userEntryDN            = null;
222        responseControls       = new ArrayList<Control>(0);
223        authFailureReason      = null;
224        saslAuthUserEntry      = null;
225    
226        cancelResult = new CancelResult(ResultCode.CANNOT_CANCEL,
227            ERR_CANNOT_CANCEL_BIND.get());
228      }
229    
230    
231    
232      /**
233       * Creates a new simple bind operation with the provided information.
234       *
235       * @param  clientConnection  The client connection with which this operation
236       *                           is associated.
237       * @param  operationID       The operation ID for this operation.
238       * @param  messageID         The message ID of the request with which this
239       *                           operation is associated.
240       * @param  requestControls   The set of controls included in the request.
241       * @param  protocolVersion   The string representation of the protocol version
242       *                           associated with this bind request.
243       * @param  bindDN            The bind DN for this bind operation.
244       * @param  simplePassword    The password to use for the simple
245       *                           authentication.
246       */
247      public BindOperationBasis(ClientConnection clientConnection, long operationID,
248                           int messageID, List<Control> requestControls,
249                           String protocolVersion, DN bindDN,
250                           ByteString simplePassword)
251      {
252        super(clientConnection, operationID, messageID, requestControls);
253    
254    
255        this.protocolVersion = protocolVersion;
256        this.authType        = AuthenticationType.SIMPLE;
257        this.bindDN          = bindDN;
258        this.saslMechanism   = null;
259        this.saslCredentials = null;
260    
261        if (bindDN == null)
262        {
263          rawBindDN = new ASN1OctetString();
264        }
265        else
266        {
267          rawBindDN = new ASN1OctetString(bindDN.toString());
268        }
269    
270        if (simplePassword == null)
271        {
272          this.simplePassword = new ASN1OctetString();
273        }
274        else
275        {
276          this.simplePassword = simplePassword;
277        }
278    
279        responseControls         = new ArrayList<Control>(0);
280        authFailureReason        = null;
281        saslAuthUserEntry        = null;
282        userEntryDN              = null;
283    
284        cancelResult = new CancelResult(ResultCode.CANNOT_CANCEL,
285            ERR_CANNOT_CANCEL_BIND.get());
286      }
287    
288    
289    
290      /**
291       * Creates a new SASL bind operation with the provided information.
292       *
293       * @param  clientConnection  The client connection with which this operation
294       *                           is associated.
295       * @param  operationID       The operation ID for this operation.
296       * @param  messageID         The message ID of the request with which this
297       *                           operation is associated.
298       * @param  requestControls   The set of controls included in the request.
299       * @param  protocolVersion   The string representation of the protocol version
300       *                           associated with this bind request.
301       * @param  bindDN            The bind DN for this bind operation.
302       * @param  saslMechanism     The SASL mechanism included in the request.
303       * @param  saslCredentials   The optional SASL credentials included in the
304       *                           request.
305       */
306      public BindOperationBasis(ClientConnection clientConnection, long operationID,
307                           int messageID, List<Control> requestControls,
308                           String protocolVersion, DN bindDN,
309                           String saslMechanism, ASN1OctetString saslCredentials)
310      {
311        super(clientConnection, operationID, messageID, requestControls);
312    
313    
314        this.protocolVersion = protocolVersion;
315        this.authType        = AuthenticationType.SASL;
316        this.bindDN          = bindDN;
317        this.saslMechanism   = saslMechanism;
318        this.saslCredentials = saslCredentials;
319        this.simplePassword  = null;
320    
321        if (bindDN == null)
322        {
323          rawBindDN = new ASN1OctetString();
324        }
325        else
326        {
327          rawBindDN = new ASN1OctetString(bindDN.toString());
328        }
329    
330        responseControls       = new ArrayList<Control>(0);
331        authFailureReason      = null;
332        saslAuthUserEntry      = null;
333        userEntryDN            = null;
334    
335        cancelResult = new CancelResult(ResultCode.CANNOT_CANCEL,
336            ERR_CANNOT_CANCEL_BIND.get());
337      }
338    
339    
340      /**
341       * {@inheritDoc}
342       */
343      public final AuthenticationType getAuthenticationType()
344      {
345        return authType;
346      }
347    
348    
349      /**
350       * {@inheritDoc}
351       */
352      public final ByteString getRawBindDN()
353      {
354        return rawBindDN;
355      }
356    
357      /**
358       * {@inheritDoc}
359       */
360      public final void setRawBindDN(ByteString rawBindDN)
361      {
362        if (rawBindDN == null)
363        {
364          this.rawBindDN = new ASN1OctetString();
365        }
366        else
367        {
368          this.rawBindDN = rawBindDN;
369        }
370    
371        bindDN = null;
372      }
373    
374    
375      /**
376       * {@inheritDoc}
377       */
378      public final DN getBindDN()
379      {
380        try
381        {
382          if (bindDN == null)
383          {
384            bindDN = DN.decode(rawBindDN);
385          }
386        }
387        catch (DirectoryException de)
388        {
389          if (debugEnabled())
390          {
391            TRACER.debugCaught(DebugLogLevel.ERROR, de);
392          }
393    
394          setResultCode(ResultCode.INVALID_CREDENTIALS);
395          setAuthFailureReason(de.getMessageObject());
396        }
397        return bindDN;
398      }
399    
400      /**
401       * {@inheritDoc}
402       */
403      public final ByteString getSimplePassword()
404      {
405        return simplePassword;
406      }
407    
408      /**
409       * {@inheritDoc}
410       */
411      public final void setSimplePassword(ByteString simplePassword)
412      {
413        if (simplePassword == null)
414        {
415          this.simplePassword = new ASN1OctetString();
416        }
417        else
418        {
419          this.simplePassword = simplePassword;
420        }
421    
422        authType        = AuthenticationType.SIMPLE;
423        saslMechanism   = null;
424        saslCredentials = null;
425      }
426    
427      /**
428       * {@inheritDoc}
429       */
430      public final String getSASLMechanism()
431      {
432        return  saslMechanism;
433      }
434    
435      /**
436       * {@inheritDoc}
437       */
438      public final ASN1OctetString getSASLCredentials()
439      {
440        return saslCredentials;
441      }
442    
443      /**
444       * {@inheritDoc}
445       */
446      public final void setSASLCredentials(String saslMechanism,
447                                           ASN1OctetString saslCredentials)
448      {
449        this.saslMechanism   = saslMechanism;
450        this.saslCredentials = saslCredentials;
451    
452        authType       = AuthenticationType.SASL;
453        simplePassword = null;
454      }
455    
456      /**
457       * {@inheritDoc}
458       */
459      public final ASN1OctetString getServerSASLCredentials()
460      {
461        return serverSASLCredentials;
462      }
463    
464      /**
465       * {@inheritDoc}
466       */
467      public final void setServerSASLCredentials(ASN1OctetString
468                                                      serverSASLCredentials)
469      {
470        this.serverSASLCredentials = serverSASLCredentials;
471      }
472    
473      /**
474       * {@inheritDoc}
475       */
476      public final Entry getSASLAuthUserEntry()
477      {
478        return saslAuthUserEntry;
479      }
480    
481      /**
482       * {@inheritDoc}
483       */
484      public final void setSASLAuthUserEntry(Entry saslAuthUserEntry)
485      {
486        this.saslAuthUserEntry = saslAuthUserEntry;
487      }
488    
489      /**
490       * {@inheritDoc}
491       */
492      public final Message getAuthFailureReason()
493      {
494        return authFailureReason;
495      }
496    
497      /**
498       * {@inheritDoc}
499       */
500      public final void setAuthFailureReason(Message message)
501      {
502        if (DirectoryServer.returnBindErrorMessages())
503        {
504          appendErrorMessage(message);
505        }
506        else
507        {
508          authFailureReason = message;
509        }
510      }
511    
512      /**
513       * {@inheritDoc}
514       */
515      public final DN getUserEntryDN()
516      {
517        return userEntryDN;
518      }
519    
520      /**
521       * {@inheritDoc}
522       */
523      public final AuthenticationInfo getAuthenticationInfo()
524      {
525        return authInfo;
526      }
527    
528      /**
529       * {@inheritDoc}
530       */
531      public final void setAuthenticationInfo(AuthenticationInfo authInfo)
532      {
533        this.authInfo = authInfo;
534      }
535    
536      /**
537       * {@inheritDoc}
538       */
539      @Override()
540      public final OperationType getOperationType()
541      {
542        // Note that no debugging will be done in this method because it is a likely
543        // candidate for being called by the logging subsystem.
544    
545        return OperationType.BIND;
546      }
547    
548      /**
549       * {@inheritDoc}
550       */
551      @Override()
552      public final String[][] getRequestLogElements()
553      {
554        // Note that no debugging will be done in this method because it is a likely
555        // candidate for being called by the logging subsystem.
556    
557        if (authType == AuthenticationType.SASL)
558        {
559          return new String[][]
560          {
561            new String[] { LOG_ELEMENT_BIND_DN, String.valueOf(rawBindDN) },
562            new String[] { LOG_ELEMENT_AUTH_TYPE, authType.toString() },
563            new String[] { LOG_ELEMENT_SASL_MECHANISM, saslMechanism }
564          };
565        }
566        else
567        {
568          return new String[][]
569          {
570            new String[] { LOG_ELEMENT_BIND_DN, String.valueOf(rawBindDN) },
571            new String[] { LOG_ELEMENT_AUTH_TYPE, authType.toString() }
572          };
573        }
574      }
575    
576      /**
577       * {@inheritDoc}
578       */
579      @Override()
580      public final String[][] getResponseLogElements()
581      {
582        // Note that no debugging will be done in this method because it is a likely
583        // candidate for being called by the logging subsystem.
584    
585        String resultCode = String.valueOf(getResultCode().getIntValue());
586    
587        String errorMessage;
588        MessageBuilder errorMessageBuffer = getErrorMessage();
589        if (errorMessageBuffer == null)
590        {
591          errorMessage = null;
592        }
593        else
594        {
595          errorMessage = errorMessageBuffer.toString();
596        }
597    
598        String matchedDNStr;
599        DN matchedDN = getMatchedDN();
600        if (matchedDN == null)
601        {
602          matchedDNStr = null;
603        }
604        else
605        {
606          matchedDNStr = matchedDN.toString();
607        }
608    
609        String referrals;
610        List<String> referralURLs = getReferralURLs();
611        if ((referralURLs == null) || referralURLs.isEmpty())
612        {
613          referrals = null;
614        }
615        else
616        {
617          StringBuilder buffer = new StringBuilder();
618          Iterator<String> iterator = referralURLs.iterator();
619          buffer.append(iterator.next());
620    
621          while (iterator.hasNext())
622          {
623            buffer.append(", ");
624            buffer.append(iterator.next());
625          }
626    
627          referrals = buffer.toString();
628        }
629    
630        String processingTime =
631             String.valueOf(getProcessingTime());
632    
633        return new String[][]
634        {
635          new String[] { LOG_ELEMENT_RESULT_CODE, resultCode },
636          new String[] { LOG_ELEMENT_ERROR_MESSAGE, errorMessage },
637          new String[] { LOG_ELEMENT_MATCHED_DN, matchedDNStr },
638          new String[] { LOG_ELEMENT_REFERRAL_URLS, referrals },
639          new String[] { LOG_ELEMENT_PROCESSING_TIME, processingTime }
640        };
641      }
642    
643      /**
644       * {@inheritDoc}
645       */
646      @Override()
647      public final List<Control> getResponseControls()
648      {
649        return responseControls;
650      }
651    
652      /**
653       * {@inheritDoc}
654       */
655      @Override()
656      public final void addResponseControl(Control control)
657      {
658        responseControls.add(control);
659      }
660    
661      /**
662       * {@inheritDoc}
663       */
664      @Override()
665      public final void removeResponseControl(Control control)
666      {
667        responseControls.remove(control);
668      }
669    
670    
671      /**
672       * {@inheritDoc}
673       */
674      @Override()
675      public final void toString(StringBuilder buffer)
676      {
677        buffer.append("BindOperation(connID=");
678        buffer.append(clientConnection.getConnectionID());
679        buffer.append(", opID=");
680        buffer.append(operationID);
681        buffer.append(", protocol=\"");
682        buffer.append(clientConnection.getProtocol());
683        buffer.append(" ");
684        buffer.append(protocolVersion);
685        buffer.append(", dn=");
686        buffer.append(rawBindDN);
687        buffer.append(", authType=");
688        buffer.append(authType);
689        buffer.append(")");
690      }
691    
692      /**
693       * {@inheritDoc}
694       */
695      public void setUserEntryDN(DN userEntryDN)
696      {
697        this.userEntryDN = userEntryDN;
698      }
699    
700      /**
701       * {@inheritDoc}
702       */
703      public String getProtocolVersion()
704      {
705        return protocolVersion;
706      }
707    
708      /**
709       * {@inheritDoc}
710       */
711      public void setProtocolVersion(String protocolVersion)
712      {
713        this.protocolVersion = protocolVersion;
714      }
715    
716      /**
717       * {@inheritDoc}
718       */
719      public final void run()
720      {
721        setResultCode(ResultCode.UNDEFINED);
722    
723        // Start the processing timer and initially set the result to indicate that
724        // the result is unknown.
725        setProcessingStartTime();
726    
727        // Log the bind request message.
728        logBindRequest(this);
729    
730        ClientConnection clientConnection = getClientConnection();
731    
732        // Set a flag to indicate that a bind operation is in progress.  This should
733        // ensure that no new operations will be accepted for this client until the
734        // bind is complete.
735        clientConnection.setBindInProgress(true);
736    
737        // Wipe out any existing authentication for the client connection and create
738        // a placeholder that will be used if the bind is successful.
739        clientConnection.setUnauthenticated();
740    
741        // Abandon any operations that may be in progress for the client.
742        Message cancelReason = INFO_CANCELED_BY_BIND_REQUEST.get();
743        CancelRequest cancelRequest = new CancelRequest(true, cancelReason);
744        clientConnection.cancelAllOperationsExcept(cancelRequest, getMessageID());
745    
746    
747        // Get the plugin config manager that will be used for invoking plugins.
748        PluginConfigManager pluginConfigManager =
749            DirectoryServer.getPluginConfigManager();
750    
751    
752        // This flag is set to true as soon as a workflow has been executed.
753        boolean workflowExecuted = false;
754    
755    
756        try
757        {
758          // Invoke the pre-parse bind plugins.
759          PluginResult.PreParse preParseResult =
760              pluginConfigManager.invokePreParseBindPlugins(this);
761          if (!preParseResult.continueProcessing())
762          {
763            setResultCode(preParseResult.getResultCode());
764            appendErrorMessage(preParseResult.getErrorMessage());
765            setMatchedDN(preParseResult.getMatchedDN());
766            setReferralURLs(preParseResult.getReferralURLs());
767            return;
768          }
769    
770    
771          // Process the bind DN to convert it from the raw form as provided by the
772          // client into the form required for the rest of the bind processing.
773          DN bindDN = getBindDN();
774          if (bindDN == null){
775            return;
776          }
777    
778          // If this is a simple bind
779          // Then check wether the bind DN is actually one of the alternate root DNs
780          // defined in the server.  If so, then replace it with the actual DN
781          // for that user.
782          switch (getAuthenticationType())
783          {
784            case SIMPLE:
785              DN actualRootDN = DirectoryServer.getActualRootBindDN(bindDN);
786              if (actualRootDN != null)
787              {
788                bindDN = actualRootDN;
789              }
790          }
791    
792    
793          // Retrieve the network group attached to the client connection
794          // and get a workflow to process the operation.
795          NetworkGroup ng = getClientConnection().getNetworkGroup();
796          Workflow workflow = ng.getWorkflowCandidate(bindDN);
797          if (workflow == null)
798          {
799            // We have found no workflow for the requested base DN, just return
800            // a no such entry result code and stop the processing.
801            updateOperationErrMsgAndResCode();
802            return;
803          }
804          workflow.execute(this);
805          workflowExecuted = true;
806    
807        }
808        catch(CanceledOperationException coe)
809        {
810          // This shouldn't happen for bind operations. Just cancel anyways
811          if (debugEnabled())
812          {
813            TRACER.debugCaught(DebugLogLevel.ERROR, coe);
814          }
815    
816          setResultCode(ResultCode.CANCELED);
817    
818          appendErrorMessage(cancelRequest.getCancelReason());
819        }
820        finally
821        {
822          // If the bind processing is finished, then unset the "bind in progress"
823          // flag to allow other operations to be processed on the connection.
824          if (getResultCode() != ResultCode.SASL_BIND_IN_PROGRESS)
825          {
826            clientConnection.setBindInProgress(false);
827          }
828    
829          // Stop the processing timer.
830          setProcessingStopTime();
831    
832          // Send the bind response to the client.
833          clientConnection.sendResponse(this);
834    
835          // Log the bind response.
836          logBindResponse(this);
837    
838          // Invoke the post-response bind plugins.
839          invokePostResponsePlugins(workflowExecuted);
840        }
841      }
842    
843    
844      /**
845       * Invokes the post response plugins. If a workflow has been executed
846       * then invoke the post response plugins provided by the workflow
847       * elements of the worklfow, otherwise invoke the post reponse plugins
848       * that have been registered with the current operation.
849       *
850       * @param workflowExecuted <code>true</code> if a workflow has been
851       *                         executed
852       */
853      private void invokePostResponsePlugins(boolean workflowExecuted)
854      {
855        // Get the plugin config manager that will be used for invoking plugins.
856        PluginConfigManager pluginConfigManager =
857          DirectoryServer.getPluginConfigManager();
858    
859        // Invoke the post response plugins
860        if (workflowExecuted)
861        {
862          // The post responses are provided by the workflow elements of the
863          // workflow.
864          List localOperations =
865            (List)getAttachment(Operation.LOCALBACKENDOPERATIONS);
866          if (localOperations != null)
867          {
868            for (Object localOp : localOperations)
869            {
870              LocalBackendBindOperation localOperation =
871                (LocalBackendBindOperation)localOp;
872              // Invoke the post-response bind plugins.
873              pluginConfigManager.invokePostResponseBindPlugins(localOperation);
874            }
875          }
876          else
877          {
878            // The current operation does not implement any bind post response
879            // interface so we cannot invoke any post-response plugin.
880          }
881        }
882      }
883    
884    
885      /**
886       * Updates the error message and the result code of the operation.
887       *
888       * This method is called because no workflows were found to process
889       * the operation.
890       */
891      private void updateOperationErrMsgAndResCode()
892      {
893        Message message = ERR_BIND_OPERATION_UNKNOWN_USER.get(
894                String.valueOf(getBindDN()));
895        setResultCode(ResultCode.INVALID_CREDENTIALS);
896        setAuthFailureReason(message);
897      }
898    
899    }
900