Example #1
0
    public CommandResult authenticate() {
      SaslClient saslClient = createSaslClient();
      try {
        byte[] response =
            (saslClient.hasInitialResponse() ? saslClient.evaluateChallenge(new byte[0]) : null);
        CommandResult res = sendSaslStart(response);
        res.throwOnError();

        int conversationId = (Integer) res.get("conversationId");

        while (!(Boolean) res.get("done")) {
          response = saslClient.evaluateChallenge((byte[]) res.get("payload"));

          if (response == null) {
            throw new MongoException("SASL protocol error: no client response to challenge");
          }

          res = sendSaslContinue(conversationId, response);
          res.throwOnError();
        }
        return res;
      } catch (IOException e) {
        throw new MongoException.Network("IOException authenticating the connection", e);
      } finally {
        try {
          saslClient.dispose();
        } catch (SaslException e) {
          // ignore
        }
      }
    }
  @Test
  public void testServerNotTrustedByClient() throws Exception {
    final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
    assertNotNull(clientFactory);

    final SaslServer saslServer =
        createSaslServer(
            SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC,
            "testserver1.example.com",
            getX509KeyManager(serverKeyStore, KEYSTORE_PASSWORD),
            getX509TrustManager(serverTrustStore));

    final String[] mechanisms =
        new String[] {SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC};
    CallbackHandler cbh =
        createClientCallbackHandler(
            mechanisms, clientKeyStore, CLIENT_KEYSTORE_ALIAS, KEYSTORE_PASSWORD, null);
    final SaslClient saslClient =
        clientFactory.createSaslClient(
            mechanisms,
            null,
            "test",
            "testserver1.example.com",
            Collections.<String, Object>emptyMap(),
            cbh);

    byte[] message = saslServer.evaluateResponse(new byte[0]);
    message = saslClient.evaluateChallenge(message);
    message = saslServer.evaluateResponse(message);
    try {
      saslClient.evaluateChallenge(message);
      fail("Expected SaslException not thrown");
    } catch (SaslException expected) {
    }
  }
  @Test
  public void testServerAuthIndirect_Client() throws Exception {
    Map<String, Object> props = new HashMap<String, Object>();

    // No properties are set, an appropriate EntitySaslClient should be returned
    SaslClient client =
        Sasl.createSaslClient(
            new String[] {SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC},
            "TestUser",
            "TestProtocol",
            "TestServer",
            props,
            null);
    assertEquals(EntitySaslClient.class, client.getClass());
    assertEquals(
        SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, client.getMechanismName());

    // If we set SERVER_AUTH to true even though only unilateral mechanisms are specified, no client
    // should be returned
    props.put(Sasl.SERVER_AUTH, Boolean.toString(true));
    client =
        Sasl.createSaslClient(
            new String[] {
              SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC,
              SaslMechanismInformation.Names.IEC_ISO_9798_U_DSA_SHA1,
              SaslMechanismInformation.Names.IEC_ISO_9798_U_ECDSA_SHA1
            },
            "TestUser",
            "TestProtocol",
            "TestServer",
            props,
            null);
    assertNull(client);

    // If we set SERVER_AUTH to true, an appropriate EntitySaslClient should be returned
    props.put(Sasl.SERVER_AUTH, Boolean.toString(true));
    client =
        Sasl.createSaslClient(
            new String[] {
              SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC,
              SaslMechanismInformation.Names.IEC_ISO_9798_U_DSA_SHA1,
              SaslMechanismInformation.Names.IEC_ISO_9798_U_ECDSA_SHA1,
              SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC,
              SaslMechanismInformation.Names.IEC_ISO_9798_M_DSA_SHA1,
              SaslMechanismInformation.Names.IEC_ISO_9798_M_ECDSA_SHA1
            },
            "TestUser",
            "TestProtocol",
            "TestServer",
            props,
            null);
    assertEquals(EntitySaslClient.class, client.getClass());
    assertEquals(
        SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC, client.getMechanismName());
  }
Example #4
0
  protected void authenticate() throws IOException, XMPPException {
    String authenticationText = null;
    try {
      if (sc.hasInitialResponse()) {
        byte[] response = sc.evaluateChallenge(new byte[0]);
        authenticationText = Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
      }
    } catch (SaslException e) {
      throw new XMPPException("SASL authentication failed", e);
    }

    // Send the authentication to the server
    getSASLAuthentication().send(new AuthMechanism(getName(), authenticationText));
  }
  public SaslOutputStream(SaslClient client, OutputStream dest) throws IOException {
    super();

    this.client = client;
    maxRawSendSize = Integer.parseInt((String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE));
    server = null;
    this.dest = dest;
  }
Example #6
0
  /**
   * The server is challenging the SASL mechanism for the stanza he just sent. Send a response to
   * the server's challenge.
   *
   * @param challenge a base64 encoded string representing the challenge.
   * @throws IOException if an exception sending the response occurs.
   */
  public void challengeReceived(String challenge) throws IOException {
    byte response[];
    if (challenge != null) {
      response = sc.evaluateChallenge(Base64.decode(challenge));
    } else {
      response = sc.evaluateChallenge(new byte[0]);
    }

    Packet responseStanza;
    if (response == null) {
      responseStanza = new Response();
    } else {
      responseStanza = new Response(Base64.encodeBytes(response, Base64.DONT_BREAK_LINES));
    }

    // Send the authentication to the server
    getSASLAuthentication().send(responseStanza);
  }
 private void saslDispose(final SaslClient saslClient) {
   if (saslClient != null) {
     try {
       saslClient.dispose();
     } catch (SaslException e) {
       client.trace("Failure disposing of SaslClient", e);
     }
   }
 }
  @Test
  public void testMutualAuthenticationWithDNSInCNField() throws Exception {
    // Although specifying a DNS name using the Common Name field has been deprecated, it is
    // still used in practice (e.g., see http://tools.ietf.org/html/rfc2818). This test makes
    // sure that general name matching during authentication still works in this case.
    final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
    assertNotNull(clientFactory);

    final KeyStore keyStore = loadKeyStore(serverKeyStore);
    final Certificate[] certificateChain = keyStore.getCertificateChain("dnsInCNServer");
    final SaslServer saslServer =
        createSaslServer(
            SaslMechanismInformation.Names.IEC_ISO_9798_M_DSA_SHA1,
            "testserver2.example.com",
            getX509TrustManager(serverTrustStore),
            (PrivateKey) keyStore.getKey("dnsInCNServer", KEYSTORE_PASSWORD),
            Arrays.copyOf(certificateChain, certificateChain.length, X509Certificate[].class));

    final String[] mechanisms =
        new String[] {SaslMechanismInformation.Names.IEC_ISO_9798_M_DSA_SHA1};
    CallbackHandler cbh =
        createClientCallbackHandler(
            mechanisms,
            clientKeyStore,
            "dnsInCNClient",
            KEYSTORE_PASSWORD,
            getX509TrustManager(clientTrustStore));
    final SaslClient saslClient =
        clientFactory.createSaslClient(
            mechanisms,
            null,
            "test",
            "testserver2.example.com",
            Collections.<String, Object>emptyMap(),
            cbh);
    assertFalse(saslServer.isComplete());
    assertFalse(saslClient.isComplete());

    byte[] message = saslServer.evaluateResponse(new byte[0]);
    assertFalse(saslServer.isComplete());
    assertFalse(saslClient.isComplete());

    message = saslClient.evaluateChallenge(message);
    assertFalse(saslServer.isComplete());
    assertFalse(saslClient.isComplete());

    message = saslServer.evaluateResponse(message);
    assertNotNull(message);

    message = saslClient.evaluateChallenge(message);
    assertNull(message);
    assertTrue(saslClient.isComplete());
    assertTrue(saslServer.isComplete());
    assertEquals(
        "cn=testclient2.example.com,ou=jboss,o=red hat,l=raleigh,st=north carolina,c=us",
        saslServer.getAuthorizationID());
  }
 public OcsConnection(final String domain, final OcsAccount account, int key) {
   this.domain = domain;
   this.addr = Util.cast2SocketAddress(domain);
   this.account = account;
   this.setKey(key);
   if (account.isExemptPassword() == false) {
     this.plainHandler = new OcsPlainHandler(account.getUsername(), account.getPassword());
     mech = new String[] {"PLAIN"};
     try {
       SaslClient sc =
           Sasl.createSaslClient(mech, null, "memcached", addr.toString(), null, plainHandler);
       evaluate = sc.evaluateChallenge(/* empty bytes */ new byte[0]);
       mechanism = sc.getMechanismName();
     } catch (SaslException e) {
       logger.error("SaslClient exception", e);
       throw new RuntimeException("SaslClient exception", e);
     }
   }
   channel = null;
 }
  @Ignore // todo: this test could be modified to use the wrong key of the write algorithm, or it
          // could be removed
  @Test
  public void testServerPrivateKeyPublicKeyMismatch() throws Exception {
    final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
    assertNotNull(clientFactory);

    // A certificate that does not correspond to the server's private key will be used
    final KeyStore keyStore = loadKeyStore(serverKeyStore);
    final Certificate[] certificateChain = keyStore.getCertificateChain(WRONG_KEYSTORE_ALIAS);
    final SaslServer saslServer =
        createSaslServer(
            SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC,
            "testserver1.example.com",
            getX509TrustManager(serverTrustStore),
            (PrivateKey) keyStore.getKey(SERVER_KEYSTORE_ALIAS, KEYSTORE_PASSWORD),
            Arrays.copyOf(certificateChain, certificateChain.length, X509Certificate[].class));

    final String[] mechanisms =
        new String[] {SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC};
    CallbackHandler cbh =
        createClientCallbackHandler(
            mechanisms,
            clientKeyStore,
            CLIENT_KEYSTORE_ALIAS,
            KEYSTORE_PASSWORD,
            getX509TrustManager(clientTrustStore));
    final SaslClient saslClient =
        clientFactory.createSaslClient(
            mechanisms, null, "test", "", Collections.<String, Object>emptyMap(), cbh);

    byte[] message = saslServer.evaluateResponse(new byte[0]);
    message = saslClient.evaluateChallenge(message);
    message = saslServer.evaluateResponse(message);
    try {
      saslClient.evaluateChallenge(message);
      fail("Expected SaslException not thrown");
    } catch (SaslException expected) {
    }
  }
  @Test
  public void testUnilateralSha1WithRsaAuthenticationWithTrustedAuthorities() throws Exception {
    final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
    assertNotNull(clientFactory);

    final SaslServer saslServer =
        createSaslServer(
            SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC,
            "testserver1.example.com",
            getX509KeyManager(serverKeyStore, KEYSTORE_PASSWORD),
            getX509TrustManager(serverTrustStore));
    assertNotNull(saslServer);
    assertFalse(saslServer.isComplete());

    final String[] mechanisms =
        new String[] {SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC};
    CallbackHandler cbh =
        createClientCallbackHandler(
            mechanisms, getX509KeyManager(clientKeyStore, KEYSTORE_PASSWORD), null);
    final SaslClient saslClient =
        clientFactory.createSaslClient(
            mechanisms,
            null,
            "test",
            "testserver1.example.com",
            Collections.<String, Object>emptyMap(),
            cbh);
    assertNotNull(saslClient);
    assertTrue(saslClient instanceof EntitySaslClient);
    assertFalse(saslClient.hasInitialResponse());
    assertFalse(saslClient.isComplete());

    byte[] message = saslServer.evaluateResponse(new byte[0]);
    assertFalse(saslServer.isComplete());
    assertFalse(saslClient.isComplete());

    message = saslClient.evaluateChallenge(message);
    assertFalse(saslServer.isComplete());
    assertFalse(saslClient.isComplete());

    message = saslServer.evaluateResponse(message);
    assertTrue(saslServer.isComplete());
    assertNull(message);
    assertNull(saslClient.evaluateChallenge(message));
    assertTrue(saslClient.isComplete());
    assertEquals(
        "cn=test client 1,ou=jboss,o=red hat,st=north carolina,c=us",
        saslServer.getAuthorizationID());
  }
  public static void main(String[] args) throws Exception {
    if (args.length == 0) {
      namesfile = null;
      auto = true;
    } else {
      int i = 0;
      if (args[i].equals("-m")) {
        i++;
        auto = false;
      }
      if (args.length > i) {
        namesfile = args[i++];
        if (args.length > i) {
          proxyfile = args[i];
        }
      } else {
        namesfile = null;
      }
    }

    CallbackHandler clntCbh = null;
    final CallbackHandler srvCbh = new PropertiesFileCallbackHandler(null, namesfile, proxyfile);

    Subject clntSubj = doLogin("client");
    Subject srvSubj = doLogin("server");
    final HashMap clntprops = new HashMap();
    final HashMap srvprops = new HashMap();

    clntprops.put(Sasl.QOP, "auth");
    srvprops.put(Sasl.QOP, "auth,auth-int,auth-conf");

    final SaslClient clnt =
        (SaslClient)
            Subject.doAs(
                clntSubj,
                new PrivilegedExceptionAction() {
                  public Object run() throws Exception {
                    return Sasl.createSaslClient(
                        new String[] {MECH}, null, PROTOCOL, SERVER_FQDN, clntprops, null);
                  }
                });

    if (verbose) {
      System.out.println(clntSubj);
      System.out.println(srvSubj);
    }
    final SaslServer srv =
        (SaslServer)
            Subject.doAs(
                srvSubj,
                new PrivilegedExceptionAction() {
                  public Object run() throws Exception {
                    return Sasl.createSaslServer(MECH, PROTOCOL, SERVER_FQDN, srvprops, srvCbh);
                  }
                });

    if (clnt == null) {
      throw new IllegalStateException("Unable to find client impl for " + MECH);
    }
    if (srv == null) {
      throw new IllegalStateException("Unable to find server impl for " + MECH);
    }

    byte[] response;
    byte[] challenge;

    response =
        (byte[])
            Subject.doAs(
                clntSubj,
                new PrivilegedExceptionAction() {
                  public Object run() throws Exception {
                    return (clnt.hasInitialResponse() ? clnt.evaluateChallenge(EMPTY) : EMPTY);
                  }
                });

    while (!clnt.isComplete() || !srv.isComplete()) {
      final byte[] responseCopy = response;
      challenge =
          (byte[])
              Subject.doAs(
                  srvSubj,
                  new PrivilegedExceptionAction() {
                    public Object run() throws Exception {
                      return srv.evaluateResponse(responseCopy);
                    }
                  });

      if (challenge != null) {
        final byte[] challengeCopy = challenge;
        response =
            (byte[])
                Subject.doAs(
                    clntSubj,
                    new PrivilegedExceptionAction() {
                      public Object run() throws Exception {
                        return clnt.evaluateChallenge(challengeCopy);
                      }
                    });
      }
    }

    if (clnt.isComplete() && srv.isComplete()) {
      if (verbose) {
        System.out.println("SUCCESS");
        System.out.println("authzid is " + srv.getAuthorizationID());
      }
    } else {
      throw new IllegalStateException(
          "FAILURE: mismatched state:"
              + " client complete? "
              + clnt.isComplete()
              + " server complete? "
              + srv.isComplete());
    }

    if (verbose) {
      System.out.println(clnt.getNegotiatedProperty(Sasl.QOP));
    }

    // Now try to use security layer

    byte[] clntBuf = new byte[] {0, 1, 2, 3};
    try {
      byte[] wrapped = clnt.wrap(clntBuf, 0, clntBuf.length);
      throw new Exception("clnt wrap should not be allowed w/no security layer");
    } catch (IllegalStateException e) {
      // expected
    }

    byte[] srvBuf = new byte[] {10, 11, 12, 13};
    try {
      byte[] wrapped = srv.wrap(srvBuf, 0, srvBuf.length);
      throw new Exception("srv wrap should not be allowed w/no security layer");
    } catch (IllegalStateException e) {
      // expected
    }

    try {
      byte[] unwrapped = clnt.unwrap(clntBuf, 0, clntBuf.length);
      throw new Exception("clnt wrap should not be allowed w/no security layer");
    } catch (IllegalStateException e) {
      // expected
    }

    try {
      byte[] unwrapped = srv.unwrap(srvBuf, 0, srvBuf.length);
      throw new Exception("srv wrap should not be allowed w/no security layer");
    } catch (IllegalStateException e) {
      // expected
    }
  }
  public boolean authenticate(
      String[] mechs, final String realm, final String authzid, final String u, final String p)
      throws ProtocolException {

    synchronized (pr) { // authenticate method should be synchronized
      List<Response> v = new ArrayList<Response>();
      String tag = null;
      Response r = null;
      boolean done = false;
      if (logger.isLoggable(Level.FINE)) {
        logger.fine("SASL Mechanisms:");
        for (int i = 0; i < mechs.length; i++) logger.fine(" " + mechs[i]);
        logger.fine("");
      }

      SaslClient sc;
      CallbackHandler cbh =
          new CallbackHandler() {
            public void handle(Callback[] callbacks) {
              if (logger.isLoggable(Level.FINE))
                logger.fine("SASL callback length: " + callbacks.length);
              for (int i = 0; i < callbacks.length; i++) {
                if (logger.isLoggable(Level.FINE))
                  logger.fine("SASL callback " + i + ": " + callbacks[i]);
                if (callbacks[i] instanceof NameCallback) {
                  NameCallback ncb = (NameCallback) callbacks[i];
                  ncb.setName(u);
                } else if (callbacks[i] instanceof PasswordCallback) {
                  PasswordCallback pcb = (PasswordCallback) callbacks[i];
                  pcb.setPassword(p.toCharArray());
                } else if (callbacks[i] instanceof RealmCallback) {
                  RealmCallback rcb = (RealmCallback) callbacks[i];
                  rcb.setText(realm != null ? realm : rcb.getDefaultText());
                } else if (callbacks[i] instanceof RealmChoiceCallback) {
                  RealmChoiceCallback rcb = (RealmChoiceCallback) callbacks[i];
                  if (realm == null) rcb.setSelectedIndex(rcb.getDefaultChoice());
                  else {
                    // need to find specified realm in list
                    String[] choices = rcb.getChoices();
                    for (int k = 0; k < choices.length; k++) {
                      if (choices[k].equals(realm)) {
                        rcb.setSelectedIndex(k);
                        break;
                      }
                    }
                  }
                }
              }
            }
          };

      try {
        sc = Sasl.createSaslClient(mechs, authzid, name, host, (Map) props, cbh);
      } catch (SaslException sex) {
        logger.log(Level.FINE, "Failed to create SASL client", sex);
        throw new UnsupportedOperationException(sex.getMessage(), sex);
      }
      if (sc == null) {
        logger.fine("No SASL support");
        throw new UnsupportedOperationException("No SASL support");
      }
      if (logger.isLoggable(Level.FINE)) logger.fine("SASL client " + sc.getMechanismName());

      try {
        Argument args = new Argument();
        args.writeAtom(sc.getMechanismName());
        if (pr.hasCapability("SASL-IR") && sc.hasInitialResponse()) {
          String irs;
          byte[] ba = sc.evaluateChallenge(new byte[0]);
          if (ba.length > 0) {
            ba = BASE64EncoderStream.encode(ba);
            irs = ASCIIUtility.toString(ba, 0, ba.length);
          } else irs = "=";
          args.writeAtom(irs);
        }
        tag = pr.writeCommand("AUTHENTICATE", args);
      } catch (Exception ex) {
        logger.log(Level.FINE, "SASL AUTHENTICATE Exception", ex);
        return false;
      }

      OutputStream os = pr.getIMAPOutputStream(); // stream to IMAP server

      /*
       * Wrap a BASE64Encoder around a ByteArrayOutputstream
       * to craft b64 encoded username and password strings
       *
       * Note that the encoded bytes should be sent "as-is" to the
       * server, *not* as literals or quoted-strings.
       *
       * Also note that unlike the B64 definition in MIME, CRLFs
       * should *not* be inserted during the encoding process. So, I
       * use Integer.MAX_VALUE (0x7fffffff (> 1G)) as the bytesPerLine,
       * which should be sufficiently large !
       */

      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      byte[] CRLF = {(byte) '\r', (byte) '\n'};

      // Hack for Novell GroupWise XGWTRUSTEDAPP authentication mechanism
      // http://www.novell.com/developer/documentation/gwimap/?
      //   page=/developer/documentation/gwimap/gwimpenu/data/al7te9j.html
      boolean isXGWTRUSTEDAPP =
          sc.getMechanismName().equals("XGWTRUSTEDAPP")
              && PropUtil.getBooleanProperty(
                  props, "mail." + name + ".sasl.xgwtrustedapphack.enable", true);
      while (!done) { // loop till we are done
        try {
          r = pr.readResponse();
          if (r.isContinuation()) {
            byte[] ba = null;
            if (!sc.isComplete()) {
              ba = r.readByteArray().getNewBytes();
              if (ba.length > 0) ba = BASE64DecoderStream.decode(ba);
              if (logger.isLoggable(Level.FINE))
                logger.fine("SASL challenge: " + ASCIIUtility.toString(ba, 0, ba.length) + " :");
              ba = sc.evaluateChallenge(ba);
            }
            if (ba == null) {
              logger.fine("SASL no response");
              os.write(CRLF); // write out empty line
              os.flush(); // flush the stream
              bos.reset(); // reset buffer
            } else {
              if (logger.isLoggable(Level.FINE))
                logger.fine("SASL response: " + ASCIIUtility.toString(ba, 0, ba.length) + " :");
              ba = BASE64EncoderStream.encode(ba);
              if (isXGWTRUSTEDAPP) bos.write(ASCIIUtility.getBytes("XGWTRUSTEDAPP "));
              bos.write(ba);

              bos.write(CRLF); // CRLF termination
              os.write(bos.toByteArray()); // write out line
              os.flush(); // flush the stream
              bos.reset(); // reset buffer
            }
          } else if (r.isTagged() && r.getTag().equals(tag))
            // Ah, our tagged response
            done = true;
          else if (r.isBYE()) // outta here
          done = true;
          else // hmm .. unsolicited response here ?!
          v.add(r);
        } catch (Exception ioex) {
          logger.log(Level.FINE, "SASL Exception", ioex);
          // convert this into a BYE response
          r = Response.byeResponse(ioex);
          done = true;
          // XXX - ultimately return true???
        }
      }

      if (sc.isComplete() /*&& res.status == SUCCESS*/) {
        String qop = (String) sc.getNegotiatedProperty(Sasl.QOP);
        if (qop != null
            && (qop.equalsIgnoreCase("auth-int") || qop.equalsIgnoreCase("auth-conf"))) {
          // XXX - NOT SUPPORTED!!!
          logger.fine("SASL Mechanism requires integrity or confidentiality");
          return false;
        }
      }

      /* Dispatch untagged responses.
       * NOTE: in our current upper level IMAP classes, we add the
       * responseHandler to the Protocol object only *after* the
       * connection has been authenticated. So, for now, the below
       * code really ends up being just a no-op.
       */
      Response[] responses = v.toArray(new Response[v.size()]);
      pr.notifyResponseHandlers(responses);

      // Handle the final OK, NO, BAD or BYE response
      pr.handleResult(r);
      pr.setCapabilities(r);

      /*
       * If we're using the Novell Groupwise XGWTRUSTEDAPP mechanism
       * to run as a specified authorization ID, we have to issue a
       * LOGIN command to select the user we want to operate as.
       */
      if (isXGWTRUSTEDAPP && authzid != null) {
        Argument args = new Argument();
        args.writeString(authzid);

        responses = pr.command("LOGIN", args);

        // dispatch untagged responses
        pr.notifyResponseHandlers(responses);

        // Handle result of this command
        pr.handleResult(responses[responses.length - 1]);
        // If the response includes a CAPABILITY response code, process it
        pr.setCapabilities(responses[responses.length - 1]);
      }
      return true;
    }
  }
 public void handleEvent(final ConnectedMessageChannel channel) {
   final Pooled<ByteBuffer> pooledBuffer = connection.allocate();
   try {
     final ByteBuffer buffer = pooledBuffer.getResource();
     final int res;
     try {
       res = channel.receive(buffer);
     } catch (IOException e) {
       connection.handleException(e);
       return;
     }
     if (res == 0) {
       return;
     }
     if (res == -1) {
       connection.handleException(client.abruptClose(connection));
       return;
     }
     buffer.flip();
     final byte msgType = buffer.get();
     switch (msgType) {
       case Protocol.CONNECTION_ALIVE:
         {
           client.trace("Client received connection alive");
           return;
         }
       case Protocol.CONNECTION_CLOSE:
         {
           client.trace("Client received connection close request");
           connection.handleIncomingCloseRequest();
           return;
         }
       case Protocol.AUTH_CHALLENGE:
         {
           client.trace("Client received authentication challenge");
           connection
               .getExecutor()
               .execute(
                   new Runnable() {
                     public void run() {
                       final boolean clientComplete = saslClient.isComplete();
                       if (clientComplete) {
                         connection.handleException(
                             new SaslException("Received extra auth message after completion"));
                         return;
                       }
                       final byte[] response;
                       final byte[] challenge = Buffers.take(buffer, buffer.remaining());
                       try {
                         response = saslClient.evaluateChallenge(challenge);
                         if (msgType == Protocol.AUTH_COMPLETE
                             && response != null
                             && response.length > 0) {
                           connection.handleException(
                               new SaslException(
                                   "Received extra auth message after completion"));
                           return;
                         }
                       } catch (Exception e) {
                         client.tracef("Client authentication failed: %s", e);
                         failedMechs.add(saslClient.getMechanismName());
                         sendCapRequest(serverName);
                         return;
                       }
                       client.trace("Client sending authentication response");
                       final Pooled<ByteBuffer> pooled = connection.allocate();
                       final ByteBuffer sendBuffer = pooled.getResource();
                       sendBuffer.put(Protocol.AUTH_RESPONSE);
                       sendBuffer.put(response);
                       sendBuffer.flip();
                       connection.send(pooled);
                       connection.getChannel().resumeReads();
                       return;
                     }
                   });
           connection.getChannel().suspendReads();
           return;
         }
       case Protocol.AUTH_COMPLETE:
         {
           client.trace("Client received authentication complete");
           connection
               .getExecutor()
               .execute(
                   new Runnable() {
                     public void run() {
                       final boolean clientComplete = saslClient.isComplete();
                       final byte[] challenge = Buffers.take(buffer, buffer.remaining());
                       if (!clientComplete)
                         try {
                           final byte[] response = saslClient.evaluateChallenge(challenge);
                           if (response != null && response.length > 0) {
                             connection.handleException(
                                 new SaslException(
                                     "Received extra auth message after completion"));
                             return;
                           }
                           if (!saslClient.isComplete()) {
                             connection.handleException(
                                 new SaslException(
                                     "Client not complete after processing auth complete message"));
                             return;
                           }
                         } catch (SaslException e) {
                           // todo log message
                           failedMechs.add(saslClient.getMechanismName());
                           sendCapRequest(serverName);
                           return;
                         }
                       // auth complete.
                       final ConnectionHandlerFactory connectionHandlerFactory =
                           new ConnectionHandlerFactory() {
                             public ConnectionHandler createInstance(
                                 final ConnectionHandlerContext connectionContext) {
                               // this happens immediately.
                               final RemoteConnectionHandler connectionHandler =
                                   new RemoteConnectionHandler(connectionContext, connection);
                               connection.setReadListener(
                                   new RemoteReadListener(connectionHandler, connection));
                               return connectionHandler;
                             }
                           };
                       connection.getResult().setResult(connectionHandlerFactory);
                       connection.getChannel().resumeReads();
                       return;
                     }
                   });
           connection.getChannel().suspendReads();
           return;
         }
       case Protocol.AUTH_REJECTED:
         {
           client.trace("Client received authentication rejected");
           failedMechs.add(saslClient.getMechanismName());
           sendCapRequest(serverName);
           return;
         }
       default:
         {
           client.unknownProtocolId(msgType);
           connection.handleException(client.invalidMessage(connection));
           return;
         }
     }
   } finally {
     pooledBuffer.free();
   }
 }
    public void handleEvent(final ConnectedMessageChannel channel) {
      final Pooled<ByteBuffer> pooledReceiveBuffer = connection.allocate();
      try {
        final ByteBuffer receiveBuffer = pooledReceiveBuffer.getResource();
        int res = 0;
        try {
          res = channel.receive(receiveBuffer);
        } catch (IOException e) {
          connection.handleException(e);
          return;
        }
        if (res == -1) {
          connection.handleException(client.abruptClose(connection));
          return;
        }
        if (res == 0) {
          return;
        }
        receiveBuffer.flip();
        boolean starttls = false;
        final Set<String> saslMechs = new LinkedHashSet<String>();
        final byte msgType = receiveBuffer.get();
        switch (msgType) {
          case Protocol.CONNECTION_ALIVE:
            {
              client.trace("Client received connection alive");
              return;
            }
          case Protocol.CONNECTION_CLOSE:
            {
              client.trace("Client received connection close request");
              connection.handleIncomingCloseRequest();
              return;
            }
          case Protocol.CAPABILITIES:
            {
              client.trace("Client received capabilities response");
              while (receiveBuffer.hasRemaining()) {
                final byte type = receiveBuffer.get();
                final int len = receiveBuffer.get() & 0xff;
                final ByteBuffer data = Buffers.slice(receiveBuffer, len);
                switch (type) {
                  case Protocol.CAP_VERSION:
                    {
                      final byte version = data.get();
                      client.tracef(
                          "Client received capability: version %d",
                          Integer.valueOf(version & 0xff));
                      // We only support version zero, so knowing the other side's version is not
                      // useful presently
                      break;
                    }
                  case Protocol.CAP_SASL_MECH:
                    {
                      final String mechName = Buffers.getModifiedUtf8(data);
                      client.tracef("Client received capability: SASL mechanism %s", mechName);
                      if (!failedMechs.contains(mechName)
                          && !disallowedMechs.contains(mechName)
                          && (allowedMechs == null || allowedMechs.contains(mechName))) {
                        client.tracef("SASL mechanism %s added to allowed set", mechName);
                        saslMechs.add(mechName);
                      }
                      break;
                    }
                  case Protocol.CAP_STARTTLS:
                    {
                      client.trace("Client received capability: STARTTLS");
                      starttls = true;
                      break;
                    }
                  default:
                    {
                      client.tracef(
                          "Client received unknown capability %02x", Integer.valueOf(type & 0xff));
                      // unknown, skip it for forward compatibility.
                      break;
                    }
                }
              }
              if (starttls) {
                // only initiate starttls if not forbidden by config
                if (optionMap.get(Options.SSL_STARTTLS, true)) {
                  // Prepare the request message body
                  final Pooled<ByteBuffer> pooledSendBuffer = connection.allocate();
                  final ByteBuffer sendBuffer = pooledSendBuffer.getResource();
                  sendBuffer.put(Protocol.STARTTLS);
                  sendBuffer.flip();
                  connection.setReadListener(new StartTls(serverName));
                  connection.send(pooledSendBuffer);
                  // all set
                  return;
                }
              }

              if (saslMechs.isEmpty()) {
                connection.handleException(
                    new SaslException("No more authentication mechanisms to try"));
                return;
              }
              // OK now send our authentication request
              final OptionMap optionMap = connection.getOptionMap();
              final String userName = optionMap.get(RemotingOptions.AUTHORIZE_ID);
              final Map<String, ?> propertyMap =
                  SaslUtils.createPropertyMap(
                      optionMap, Channels.getOption(channel, Options.SECURE, false));
              final SaslClient saslClient;
              try {
                saslClient =
                    AccessController.doPrivileged(
                        new PrivilegedExceptionAction<SaslClient>() {
                          public SaslClient run() throws SaslException {
                            return Sasl.createSaslClient(
                                saslMechs.toArray(new String[saslMechs.size()]),
                                userName,
                                "remote",
                                serverName,
                                propertyMap,
                                callbackHandler);
                          }
                        },
                        accessControlContext);
              } catch (PrivilegedActionException e) {
                final SaslException se = (SaslException) e.getCause();
                connection.handleException(se);
                return;
              }
              final String mechanismName = saslClient.getMechanismName();
              client.tracef("Client initiating authentication using mechanism %s", mechanismName);
              // Prepare the request message body
              final Pooled<ByteBuffer> pooledSendBuffer = connection.allocate();
              final ByteBuffer sendBuffer = pooledSendBuffer.getResource();
              sendBuffer.put(Protocol.AUTH_REQUEST);
              Buffers.putModifiedUtf8(sendBuffer, mechanismName);
              sendBuffer.flip();
              connection.send(pooledSendBuffer);
              connection.setReadListener(new Authentication(saslClient, serverName));
              return;
            }
          default:
            {
              client.unknownProtocolId(msgType);
              connection.handleException(client.invalidMessage(connection));
              return;
            }
        }
      } catch (BufferUnderflowException e) {
        connection.handleException(client.invalidMessage(connection));
        return;
      } catch (BufferOverflowException e) {
        connection.handleException(client.invalidMessage(connection));
        return;
      } finally {
        pooledReceiveBuffer.free();
      }
    }
 public boolean isComplete() {
   return saslClient.isComplete();
 }
Example #17
0
 @After
 public void dispose() throws Exception {
   if (client != null) client.dispose();
   if (server != null) server.dispose();
   if (testKdc != null) testKdc.stopAll();
 }
    public void handleEvent(final ConnectedMessageChannel channel) {
      final Pooled<ByteBuffer> pooledBuffer = connection.allocate();
      boolean free = true;
      try {
        final ByteBuffer buffer = pooledBuffer.getResource();
        synchronized (connection.getLock()) {
          final int res;
          try {
            res = channel.receive(buffer);
          } catch (IOException e) {
            connection.handleException(e);
            saslDispose(saslClient);
            return;
          }
          if (res == 0) {
            return;
          }
          if (res == -1) {
            connection.handleException(client.abruptClose(connection));
            saslDispose(saslClient);
            return;
          }
        }
        buffer.flip();
        final byte msgType = buffer.get();
        switch (msgType) {
          case Protocol.CONNECTION_ALIVE:
            {
              client.trace("Client received connection alive");
              connection.sendAliveResponse();
              return;
            }
          case Protocol.CONNECTION_ALIVE_ACK:
            {
              client.trace("Client received connection alive ack");
              return;
            }
          case Protocol.CONNECTION_CLOSE:
            {
              client.trace("Client received connection close request");
              connection.handlePreAuthCloseRequest();
              saslDispose(saslClient);
              return;
            }
          case Protocol.AUTH_CHALLENGE:
            {
              client.trace("Client received authentication challenge");
              channel.suspendReads();
              connection
                  .getExecutor()
                  .execute(
                      () -> {
                        try {
                          final boolean clientComplete = saslClient.isComplete();
                          if (clientComplete) {
                            connection.handleException(
                                new SaslException("Received extra auth message after completion"));
                            return;
                          }
                          final byte[] response;
                          final byte[] challenge = Buffers.take(buffer, buffer.remaining());
                          try {
                            response = saslClient.evaluateChallenge(challenge);
                          } catch (Throwable e) {
                            final String mechanismName = saslClient.getMechanismName();
                            client.debugf(
                                "Client authentication failed for mechanism %s: %s",
                                mechanismName, e);
                            failedMechs.put(mechanismName, e.toString());
                            saslDispose(saslClient);
                            sendCapRequest(serverName);
                            return;
                          }
                          client.trace("Client sending authentication response");
                          final Pooled<ByteBuffer> pooled = connection.allocate();
                          boolean ok = false;
                          try {
                            final ByteBuffer sendBuffer = pooled.getResource();
                            sendBuffer.put(Protocol.AUTH_RESPONSE);
                            sendBuffer.put(response);
                            sendBuffer.flip();
                            connection.send(pooled);
                            ok = true;
                            channel.resumeReads();
                          } finally {
                            if (!ok) pooled.free();
                          }
                          return;
                        } finally {
                          pooledBuffer.free();
                        }
                      });
              free = false;
              return;
            }
          case Protocol.AUTH_COMPLETE:
            {
              client.trace("Client received authentication complete");
              channel.suspendReads();
              connection
                  .getExecutor()
                  .execute(
                      () -> {
                        try {
                          final boolean clientComplete = saslClient.isComplete();
                          final byte[] challenge = Buffers.take(buffer, buffer.remaining());
                          if (!clientComplete)
                            try {
                              final byte[] response = saslClient.evaluateChallenge(challenge);
                              if (response != null && response.length > 0) {
                                connection.handleException(
                                    new SaslException(
                                        "Received extra auth message after completion"));
                                saslDispose(saslClient);
                                return;
                              }
                              if (!saslClient.isComplete()) {
                                connection.handleException(
                                    new SaslException(
                                        "Client not complete after processing auth complete message"));
                                saslDispose(saslClient);
                                return;
                              }
                            } catch (Throwable e) {
                              final String mechanismName = saslClient.getMechanismName();
                              client.debugf(
                                  "Client authentication failed for mechanism %s: %s",
                                  mechanismName, e);
                              failedMechs.put(mechanismName, e.toString());
                              saslDispose(saslClient);
                              sendCapRequest(serverName);
                              return;
                            }
                          final Object qop = saslClient.getNegotiatedProperty(Sasl.QOP);
                          if ("auth-int".equals(qop) || "auth-conf".equals(qop)) {
                            connection.setSaslWrapper(SaslWrapper.create(saslClient));
                          }
                          // auth complete.
                          final ConnectionHandlerFactory connectionHandlerFactory =
                              connectionContext -> {

                                // this happens immediately.
                                final RemoteConnectionHandler connectionHandler =
                                    new RemoteConnectionHandler(
                                        connectionContext,
                                        connection,
                                        maxInboundChannels,
                                        maxOutboundChannels,
                                        remoteEndpointName,
                                        behavior);
                                connection.setReadListener(
                                    new RemoteReadListener(connectionHandler, connection), false);
                                connection
                                    .getRemoteConnectionProvider()
                                    .addConnectionHandler(connectionHandler);
                                return connectionHandler;
                              };
                          connection.getResult().setResult(connectionHandlerFactory);
                          channel.resumeReads();
                          return;
                        } finally {
                          pooledBuffer.free();
                        }
                      });
              free = false;
              return;
            }
          case Protocol.AUTH_REJECTED:
            {
              final String mechanismName = saslClient.getMechanismName();
              client.debugf(
                  "Client received authentication rejected for mechanism %s", mechanismName);
              failedMechs.put(mechanismName, "Server rejected authentication");
              saslDispose(saslClient);
              sendCapRequest(serverName);
              return;
            }
          default:
            {
              client.unknownProtocolId(msgType);
              connection.handleException(client.invalidMessage(connection));
              saslDispose(saslClient);
              return;
            }
        }
      } finally {
        if (free) pooledBuffer.free();
      }
    }
    public void handleEvent(final ConnectedMessageChannel channel) {
      final Pooled<ByteBuffer> pooledReceiveBuffer = connection.allocate();
      try {
        final ByteBuffer receiveBuffer = pooledReceiveBuffer.getResource();
        synchronized (connection.getLock()) {
          int res;
          try {
            res = channel.receive(receiveBuffer);
          } catch (IOException e) {
            connection.handleException(e);
            return;
          }
          if (res == -1) {
            connection.handleException(client.abruptClose(connection));
            return;
          }
          if (res == 0) {
            return;
          }
        }
        receiveBuffer.flip();
        boolean starttls = false;
        final Set<String> serverSaslMechs = new LinkedHashSet<String>();
        final byte msgType = receiveBuffer.get();
        switch (msgType) {
          case Protocol.CONNECTION_ALIVE:
            {
              client.trace("Client received connection alive");
              connection.sendAliveResponse();
              return;
            }
          case Protocol.CONNECTION_ALIVE_ACK:
            {
              client.trace("Client received connection alive ack");
              return;
            }
          case Protocol.CONNECTION_CLOSE:
            {
              client.trace("Client received connection close request");
              connection.handlePreAuthCloseRequest();
              return;
            }
          case Protocol.CAPABILITIES:
            {
              client.trace("Client received capabilities response");
              String remoteEndpointName = null;
              int version = Protocol.VERSION;
              int behavior = Protocol.BH_FAULTY_MSG_SIZE;
              boolean useDefaultChannels = true;
              int channelsIn = 40;
              int channelsOut = 40;
              while (receiveBuffer.hasRemaining()) {
                final byte type = receiveBuffer.get();
                final int len = receiveBuffer.get() & 0xff;
                final ByteBuffer data = Buffers.slice(receiveBuffer, len);
                switch (type) {
                  case Protocol.CAP_VERSION:
                    {
                      version = data.get() & 0xff;
                      client.tracef(
                          "Client received capability: version %d",
                          Integer.valueOf(version & 0xff));
                      break;
                    }
                  case Protocol.CAP_SASL_MECH:
                    {
                      final String mechName = Buffers.getModifiedUtf8(data);
                      client.tracef("Client received capability: SASL mechanism %s", mechName);
                      if (!failedMechs.containsKey(mechName)
                          && !disallowedMechs.contains(mechName)
                          && (allowedMechs == null || allowedMechs.contains(mechName))) {
                        client.tracef("SASL mechanism %s added to allowed set", mechName);
                        serverSaslMechs.add(mechName);
                      }
                      break;
                    }
                  case Protocol.CAP_STARTTLS:
                    {
                      client.trace("Client received capability: STARTTLS");
                      starttls = true;
                      break;
                    }
                  case Protocol.CAP_ENDPOINT_NAME:
                    {
                      remoteEndpointName = Buffers.getModifiedUtf8(data);
                      client.tracef(
                          "Client received capability: remote endpoint name \"%s\"",
                          remoteEndpointName);
                      break;
                    }
                  case Protocol.CAP_MESSAGE_CLOSE:
                    {
                      behavior |= Protocol.BH_MESSAGE_CLOSE;
                      // remote side must be >= 3.2.11.GA
                      // but, we'll assume it's >= 3.2.14.GA because no AS or EAP release included
                      // 3.2.8.SP1 < x < 3.2.14.GA
                      behavior &= ~Protocol.BH_FAULTY_MSG_SIZE;
                      client.tracef("Client received capability: message close protocol supported");
                      break;
                    }
                  case Protocol.CAP_VERSION_STRING:
                    {
                      // remote side must be >= 3.2.16.GA
                      behavior &= ~Protocol.BH_FAULTY_MSG_SIZE;
                      final String remoteVersionString = Buffers.getModifiedUtf8(data);
                      client.tracef(
                          "Client received capability: remote version is \"%s\"",
                          remoteVersionString);
                      break;
                    }
                  case Protocol.CAP_CHANNELS_IN:
                    {
                      useDefaultChannels = false;
                      // their channels in is our channels out
                      channelsOut = ProtocolUtils.readIntData(data, len);
                      client.tracef(
                          "Client received capability: remote channels in is \"%d\"", channelsOut);
                      break;
                    }
                  case Protocol.CAP_CHANNELS_OUT:
                    {
                      useDefaultChannels = false;
                      // their channels out is our channels in
                      channelsIn = ProtocolUtils.readIntData(data, len);
                      client.tracef(
                          "Client received capability: remote channels out is \"%d\"", channelsIn);
                      break;
                    }
                  default:
                    {
                      client.tracef(
                          "Client received unknown capability %02x", Integer.valueOf(type & 0xff));
                      // unknown, skip it for forward compatibility.
                      break;
                    }
                }
              }
              if (useDefaultChannels) {
                channelsIn = 40;
                channelsOut = 40;
              }
              if (starttls) {
                // only initiate starttls if not forbidden by config
                if (optionMap.get(Options.SSL_STARTTLS, true)) {
                  // Prepare the request message body
                  final Pooled<ByteBuffer> pooledSendBuffer = connection.allocate();
                  boolean ok = false;
                  try {
                    final ByteBuffer sendBuffer = pooledSendBuffer.getResource();
                    sendBuffer.put(Protocol.STARTTLS);
                    sendBuffer.flip();
                    connection.setReadListener(new StartTls(remoteServerName), true);
                    connection.send(pooledSendBuffer);
                    ok = true;
                    // all set
                    return;
                  } finally {
                    if (!ok) pooledSendBuffer.free();
                  }
                }
              }

              if (serverSaslMechs.isEmpty()) {
                if (failedMechs.isEmpty()) {
                  connection.handleException(
                      new SaslException(
                          "Authentication failed: the server presented no authentication mechanisms"));
                } else {
                  // At this point we have been attempting to use mechanisms as they have been
                  // presented to us but we have now exhausted the list.
                  connection.handleException(allMechanismsFailed());
                }
                return;
              }

              // OK now send our authentication request
              final AuthenticationContextConfigurationClient configurationClient =
                  AUTH_CONFIGURATION_CLIENT;
              AuthenticationConfiguration configuration =
                  configurationClient.getAuthenticationConfiguration(uri, authenticationContext);
              final SaslClient saslClient;
              try {
                saslClient =
                    configurationClient.createSaslClient(
                        uri, configuration, saslClientFactory, serverSaslMechs);
              } catch (SaslException e) {
                // apparently no more mechanisms can succeed
                connection.handleException(e);
                return;
              }
              if (saslClient == null) {
                connection.handleException(allMechanismsFailed());
                return;
              }
              final String mechanismName = saslClient.getMechanismName();
              client.tracef("Client initiating authentication using mechanism %s", mechanismName);

              connection.getChannel().suspendReads();
              final int negotiatedVersion = version;
              final SaslClient usedSaslClient = saslClient;
              final Authentication authentication =
                  new Authentication(
                      usedSaslClient,
                      remoteServerName,
                      remoteEndpointName,
                      behavior,
                      channelsIn,
                      channelsOut);
              connection
                  .getExecutor()
                  .execute(
                      () -> {
                        final byte[] response;
                        try {
                          response =
                              usedSaslClient.hasInitialResponse()
                                  ? usedSaslClient.evaluateChallenge(EMPTY_BYTES)
                                  : null;
                        } catch (SaslException e) {
                          client.tracef("Client authentication failed: %s", e);
                          saslDispose(usedSaslClient);
                          failedMechs.put(mechanismName, e.toString());
                          sendCapRequest(remoteServerName);
                          return;
                        }
                        // Prepare the request message body
                        final Pooled<ByteBuffer> pooledSendBuffer = connection.allocate();
                        boolean ok = false;
                        try {
                          final ByteBuffer sendBuffer = pooledSendBuffer.getResource();
                          sendBuffer.put(Protocol.AUTH_REQUEST);
                          if (negotiatedVersion < 1) {
                            sendBuffer.put(mechanismName.getBytes(Protocol.UTF_8));
                          } else {
                            ProtocolUtils.writeString(sendBuffer, mechanismName);
                            if (response != null) {
                              sendBuffer.put(response);
                            }
                          }

                          sendBuffer.flip();
                          connection.send(pooledSendBuffer);
                          ok = true;
                          connection.setReadListener(authentication, true);
                          return;
                        } finally {
                          if (!ok) pooledSendBuffer.free();
                        }
                      });
              return;
            }
          default:
            {
              client.unknownProtocolId(msgType);
              connection.handleException(client.invalidMessage(connection));
              return;
            }
        }
      } catch (BufferUnderflowException | BufferOverflowException e) {
        connection.handleException(client.invalidMessage(connection));
        return;
      } finally {
        pooledReceiveBuffer.free();
      }
    }
Example #20
0
  private void doAuth() {
    SaslClient saslClient = null;
    try {
      saslClient =
          Sasl.createSaslClient(
              authInfo.getMechanisms(),
              null,
              "memcached",
              memcachedTCPSession.getRemoteSocketAddress().toString(),
              null,
              this.authInfo.getCallbackHandler());

      final AtomicBoolean done = new AtomicBoolean(false);
      byte[] response =
          saslClient.hasInitialResponse() ? saslClient.evaluateChallenge(EMPTY_BYTES) : EMPTY_BYTES;
      CountDownLatch latch = new CountDownLatch(1);
      Command command =
          this.commandFactory.createAuthStartCommand(
              saslClient.getMechanismName(), latch, response);
      if (!this.memcachedTCPSession.isClosed()) this.memcachedTCPSession.write(command);
      else {
        log.error("Authentication fail,because the connection has been closed");
        throw new RuntimeException("Authentication fai,connection has been close");
      }

      while (!done.get()) {
        try {
          latch.await();
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
          done.set(true);
        }
        ResponseStatus responseStatus = ((BaseBinaryCommand) command).getResponseStatus();
        switch (responseStatus) {
          case NO_ERROR:
            done.set(true);
            log.info(
                "Authentication to "
                    + this.memcachedTCPSession.getRemoteSocketAddress()
                    + " successfully");
            break;
          case AUTH_REQUIRED:
            log.error(
                "Authentication failed to " + this.memcachedTCPSession.getRemoteSocketAddress());
            log.warn(
                "Reopen connection to "
                    + this.memcachedTCPSession.getRemoteSocketAddress()
                    + ",beacause auth fail");
            this.memcachedTCPSession.setAuthFailed(true);

            // It it is not first time,try to sleep 1 second
            if (!this.authInfo.isFirstTime()) {
              Thread.sleep(1000);
            }
            this.memcachedTCPSession.close();
            done.set(true);
            break;
          case FUTHER_AUTH_REQUIRED:
            String result = (String) command.getResult();
            response = saslClient.evaluateChallenge(ByteUtils.getBytes(result));
            latch = new CountDownLatch(1);
            command =
                commandFactory.createAuthStepCommand(
                    saslClient.getMechanismName(), latch, response);
            if (!this.memcachedTCPSession.isClosed()) this.memcachedTCPSession.write(command);
            else {
              log.error("Authentication fail,because the connection has been closed");
              throw new RuntimeException("Authentication fai,connection has been close");
            }

            break;
          default:
            done.set(true);
            log.error(
                "Authentication failed to "
                    + this.memcachedTCPSession.getRemoteSocketAddress()
                    + ",response status="
                    + responseStatus);
            break;
        }
      }
    } catch (Exception e) {
      log.error("Create saslClient error", e);
    } finally {
      if (saslClient != null) {
        try {
          saslClient.dispose();
        } catch (SaslException e) {
          log.error("Dispose saslClient error", e);
        }
      }
    }
  }
  /**
   * When writing octets to the resulting stream, if a security layer has been negotiated, each
   * piece of data written (by a single invocation of <code>write()</code>) will be encapsulated as
   * a SASL buffer, as defined in RFC 2222, and then written to the underlying <i>dest</i> output
   * stream.
   */
  public void write(byte[] b, int off, int len) throws IOException {
    if (b == null) {
      throw new NullPointerException("b");
    }
    if ((off < 0)
        || (off > b.length)
        || (len < 0)
        || ((off + len) > b.length)
        || ((off + len) < 0)) {
      throw new IndexOutOfBoundsException(
          "off="
              + String.valueOf(off)
              + ", len="
              + String.valueOf(len)
              + ", b.length="
              + String.valueOf(b.length));
    }
    if (len == 0) {
      return;
    }
    if (DEBUG && debuglevel > 8) debug(TRACE, "==> write()");

    int chunckSize, length, chunck = 1;
    byte[] output = null, result;
    if (DEBUG && debuglevel > 6)
      debug(TRACE, "About to wrap " + String.valueOf(len) + " byte(s)...");
    while (len > 0) {
      chunckSize = (len > maxRawSendSize ? maxRawSendSize : len);

      if (DEBUG && debuglevel > 6)
        debug(
            TRACE,
            "Outgoing buffer (before security) (hex): " + Util.dumpString(b, off, chunckSize));
      if (DEBUG && debuglevel > 6)
        debug(
            TRACE,
            "Outgoing buffer (before security) (str): \"" + new String(b, off, chunckSize) + "\"");

      if (client != null) output = client.wrap(b, off, chunckSize);
      else output = server.wrap(b, off, chunckSize);

      if (DEBUG && debuglevel > 6)
        debug(TRACE, "Outgoing buffer (after security) (hex): " + Util.dumpString(output));
      if (DEBUG && debuglevel > 6)
        debug(TRACE, "Outgoing buffer (after security) (str): \"" + new String(output) + "\"");

      length = output.length;
      result = new byte[length + 4];
      result[0] = (byte) (length >>> 24);
      result[1] = (byte) (length >>> 16);
      result[2] = (byte) (length >>> 8);
      result[3] = (byte) length;
      System.arraycopy(output, 0, result, 4, length);

      dest.write(result);

      off += chunckSize;
      len -= chunckSize;
      if (DEBUG && debuglevel > 6) debug(TRACE, "Wrapped chunck #" + String.valueOf(chunck));
      chunck++;
    }

    dest.flush();
    if (DEBUG && debuglevel > 8) debug(TRACE, "<== write()");
  }