Reorganized authentication implementation locations.

For paving the way into further authentication mechanism
implementations, the existing is reorganized.

Move src/sasl to src/authentication/cram_md5.
Rename src/tests/sasl_tests.cpp to src/tests/cram_md5_authentication_tests.cpp.
Adapt depending include paths.
Rename specific test implementations from SASL to CRAMMD5Authentication.
Rename sasl namespace to cram_md5 throughout all uses.
Add missing license blob to auxprop.cpp.

Review: https://reviews.apache.org/r/27122


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/b51f5550
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/b51f5550
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/b51f5550

Branch: refs/heads/master
Commit: b51f55500b809b452123c011012227d821e02c04
Parents: 64dcf8e
Author: Till Toenshoff <[email protected]>
Authored: Mon Nov 3 14:39:42 2014 -0800
Committer: Adam B <[email protected]>
Committed: Mon Nov 3 14:39:42 2014 -0800

----------------------------------------------------------------------
 src/Makefile.am                               |  10 +-
 src/authentication/cram_md5/authenticatee.hpp | 412 +++++++++++++++++
 src/authentication/cram_md5/authenticator.hpp | 494 +++++++++++++++++++++
 src/authentication/cram_md5/auxprop.cpp       | 204 +++++++++
 src/authentication/cram_md5/auxprop.hpp       |  96 ++++
 src/master/master.cpp                         |  11 +-
 src/master/master.hpp                         |   5 +-
 src/sasl/authenticatee.hpp                    | 412 -----------------
 src/sasl/authenticator.hpp                    | 494 ---------------------
 src/sasl/auxprop.cpp                          | 186 --------
 src/sasl/auxprop.hpp                          |  96 ----
 src/sched/sched.cpp                           |   6 +-
 src/scheduler/scheduler.cpp                   |   6 +-
 src/slave/slave.cpp                           |   6 +-
 src/slave/slave.hpp                           |   6 +-
 src/tests/cram_md5_authentication_tests.cpp   | 209 +++++++++
 src/tests/sasl_tests.cpp                      | 209 ---------
 17 files changed, 1441 insertions(+), 1421 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index e6a0715..21e1e20 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -249,6 +249,10 @@ nodist_libmesos_no_3rdparty_la_SOURCES =                   
        \
   $(REGISTRY_PROTOS)
 
 libmesos_no_3rdparty_la_SOURCES =                                      \
+       authentication/cram_md5/authenticatee.hpp                       \
+       authentication/cram_md5/authenticator.hpp                       \
+       authentication/cram_md5/auxprop.hpp                             \
+       authentication/cram_md5/auxprop.cpp                             \
        authorizer/authorizer.cpp                                       \
        common/attributes.cpp                                           \
        common/date_utils.cpp                                           \
@@ -276,10 +280,6 @@ libmesos_no_3rdparty_la_SOURCES =                          
        \
        master/registrar.cpp                                            \
        master/repairer.cpp                                             \
        module/manager.cpp                                              \
-       sasl/authenticatee.hpp                                          \
-       sasl/authenticator.hpp                                          \
-       sasl/auxprop.hpp                                                \
-       sasl/auxprop.cpp                                                \
        sched/sched.cpp                                                 \
        scheduler/scheduler.cpp                                         \
        slave/constants.cpp                                             \
@@ -1183,6 +1183,7 @@ mesos_tests_SOURCES =                             \
   tests/composing_containerizer_tests.cpp       \
   tests/containerizer.cpp                      \
   tests/containerizer_tests.cpp                        \
+  tests/cram_md5_authentication_tests.cpp      \
   tests/credentials_tests.cpp                  \
   tests/docker_containerizer_tests.cpp          \
   tests/docker_tests.cpp                       \
@@ -1217,7 +1218,6 @@ mesos_tests_SOURCES =                             \
   tests/repair_tests.cpp                       \
   tests/resource_offers_tests.cpp              \
   tests/resources_tests.cpp                    \
-  tests/sasl_tests.cpp                         \
   tests/scheduler_tests.cpp                    \
   tests/script.cpp                             \
   tests/shutdown_tests.cpp                     \

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/authentication/cram_md5/authenticatee.hpp
----------------------------------------------------------------------
diff --git a/src/authentication/cram_md5/authenticatee.hpp 
b/src/authentication/cram_md5/authenticatee.hpp
new file mode 100644
index 0000000..3088a77
--- /dev/null
+++ b/src/authentication/cram_md5/authenticatee.hpp
@@ -0,0 +1,412 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AUTHENTICATION_CRAM_MD5_AUTHENTICATEE_HPP__
+#define __AUTHENTICATION_CRAM_MD5_AUTHENTICATEE_HPP__
+
+#include <sasl/sasl.h>
+
+#include <mesos/mesos.hpp>
+
+#include <process/defer.hpp>
+#include <process/future.hpp>
+#include <process/id.hpp>
+#include <process/once.hpp>
+#include <process/process.hpp>
+#include <process/protobuf.hpp>
+
+#include <stout/strings.hpp>
+
+#include "messages/messages.hpp"
+
+namespace mesos {
+namespace internal {
+namespace cram_md5 {
+
+// Forward declaration.
+class AuthenticateeProcess;
+
+
+class Authenticatee
+{
+public:
+  // 'credential' is used to authenticate the 'client'.
+  Authenticatee(const Credential& credential, const process::UPID& client);
+  ~Authenticatee();
+
+  // Returns true if successfully authenticated otherwise false or an
+  // error. Note that we distinguish authentication failure (false)
+  // from a failed future in the event the future failed due to a
+  // transient error and authentication can (should) be
+  // retried. Discarding the future will cause the future to fail if
+  // it hasn't already completed since we have already started the
+  // authentication procedure and can't reliably cancel.
+  process::Future<bool> authenticate(const process::UPID& pid);
+
+private:
+  AuthenticateeProcess* process;
+};
+
+
+class AuthenticateeProcess : public ProtobufProcess<AuthenticateeProcess>
+{
+public:
+  AuthenticateeProcess(const Credential& _credential,
+                       const process::UPID& _client)
+    : ProcessBase(process::ID::generate("authenticatee")),
+      credential(_credential),
+      client(_client),
+      status(READY),
+      connection(NULL)
+  {
+    const char* data = credential.secret().data();
+    size_t length = credential.secret().length();
+
+    // Need to allocate the secret via 'malloc' because SASL is
+    // expecting the data appended to the end of the struct. *sigh*
+    secret = (sasl_secret_t*) malloc(sizeof(sasl_secret_t) + length);
+
+    CHECK(secret != NULL) << "Failed to allocate memory for secret";
+
+    memcpy(secret->data, data, length);
+    secret->len = length;
+  }
+
+  virtual ~AuthenticateeProcess()
+  {
+    if (connection != NULL) {
+      sasl_dispose(&connection);
+    }
+    free(secret);
+  }
+
+  virtual void finalize()
+  {
+    discarded(); // Fail the promise.
+  }
+
+  process::Future<bool> authenticate(const process::UPID& pid)
+  {
+    static process::Once* initialize = new process::Once();
+    static bool initialized = false;
+
+    if (!initialize->once()) {
+      LOG(INFO) << "Initializing client SASL";
+      int result = sasl_client_init(NULL);
+      if (result != SASL_OK) {
+        status = ERROR;
+        std::string error(sasl_errstring(result, NULL, NULL));
+        promise.fail("Failed to initialize SASL: " + error);
+        initialize->done();
+        return promise.future();
+      }
+
+      initialized = true;
+
+      initialize->done();
+    }
+
+    if (!initialized) {
+      promise.fail("Failed to initialize SASL");
+      return promise.future();
+    }
+
+    if (status != READY) {
+      return promise.future();
+    }
+
+    LOG(INFO) << "Creating new client SASL connection";
+
+    callbacks[0].id = SASL_CB_GETREALM;
+    callbacks[0].proc = NULL;
+    callbacks[0].context = NULL;
+
+    callbacks[1].id = SASL_CB_USER;
+    callbacks[1].proc = (int(*)()) &user;
+    callbacks[1].context = (void*) credential.principal().c_str();
+
+    // NOTE: Some SASL mechanisms do not allow/enable "proxying",
+    // i.e., authorization. Therefore, some mechanisms send _only_ the
+    // authoriation name rather than both the user (authentication
+    // name) and authorization name. Thus, for now, we assume
+    // authorization is handled out of band. Consider the
+    // SASL_NEED_PROXY flag if we want to reconsider this in the
+    // future.
+    callbacks[2].id = SASL_CB_AUTHNAME;
+    callbacks[2].proc = (int(*)()) &user;
+    callbacks[2].context = (void*) credential.principal().c_str();
+
+    callbacks[3].id = SASL_CB_PASS;
+    callbacks[3].proc = (int(*)()) &pass;
+    callbacks[3].context = (void*) secret;
+
+    callbacks[4].id = SASL_CB_LIST_END;
+    callbacks[4].proc = NULL;
+    callbacks[4].context = NULL;
+
+    int result = sasl_client_new(
+        "mesos",    // Registered name of service.
+        NULL,       // Server's FQDN.
+        NULL, NULL, // IP Address information strings.
+        callbacks,  // Callbacks supported only for this connection.
+        0,          // Security flags (security layers are enabled
+                    // using security properties, separately).
+        &connection);
+
+    if (result != SASL_OK) {
+      status = ERROR;
+      std::string error(sasl_errstring(result, NULL, NULL));
+      promise.fail("Failed to create client SASL connection: " + error);
+      return promise.future();
+    }
+
+    AuthenticateMessage message;
+    message.set_pid(client);
+    send(pid, message);
+
+    status = STARTING;
+
+    // Stop authenticating if nobody cares.
+    promise.future().onDiscard(defer(self(), &Self::discarded));
+
+    return promise.future();
+  }
+
+protected:
+  virtual void initialize()
+  {
+    // Anticipate mechanisms and steps from the server.
+    install<AuthenticationMechanismsMessage>(
+        &AuthenticateeProcess::mechanisms,
+        &AuthenticationMechanismsMessage::mechanisms);
+
+    install<AuthenticationStepMessage>(
+        &AuthenticateeProcess::step,
+        &AuthenticationStepMessage::data);
+
+    install<AuthenticationCompletedMessage>(
+        &AuthenticateeProcess::completed);
+
+    install<AuthenticationFailedMessage>(
+        &AuthenticateeProcess::failed);
+
+    install<AuthenticationErrorMessage>(
+        &AuthenticateeProcess::error,
+        &AuthenticationErrorMessage::error);
+  }
+
+  void mechanisms(const std::vector<std::string>& mechanisms)
+  {
+    if (status != STARTING) {
+      status = ERROR;
+      promise.fail("Unexpected authentication 'mechanisms' received");
+      return;
+    }
+
+    // TODO(benh): Store 'from' in order to ensure we only communicate
+    // with the same Authenticator.
+
+    LOG(INFO) << "Received SASL authentication mechanisms: "
+              << strings::join(",", mechanisms);
+
+    sasl_interact_t* interact = NULL;
+    const char* output = NULL;
+    unsigned length = 0;
+    const char* mechanism = NULL;
+
+    int result = sasl_client_start(
+        connection,
+        strings::join(" ", mechanisms).c_str(),
+        &interact,     // Set if an interaction is needed.
+        &output,       // The output string (to send to server).
+        &length,       // The length of the output string.
+        &mechanism);   // The chosen mechanism.
+
+    CHECK_NE(SASL_INTERACT, result)
+      << "Not expecting an interaction (ID: " << interact->id << ")";
+
+    if (result != SASL_OK && result != SASL_CONTINUE) {
+      std::string error(sasl_errdetail(connection));
+      status = ERROR;
+      promise.fail("Failed to start the SASL client: " + error);
+      return;
+    }
+
+    LOG(INFO) << "Attempting to authenticate with mechanism '"
+              << mechanism << "'";
+
+    AuthenticationStartMessage message;
+    message.set_mechanism(mechanism);
+    message.set_data(output, length);
+
+    reply(message);
+
+    status = STEPPING;
+  }
+
+  void step(const std::string& data)
+  {
+    if (status != STEPPING) {
+      status = ERROR;
+      promise.fail("Unexpected authentication 'step' received");
+      return;
+    }
+
+    LOG(INFO) << "Received SASL authentication step";
+
+    sasl_interact_t* interact = NULL;
+    const char* output = NULL;
+    unsigned length = 0;
+
+    int result = sasl_client_step(
+        connection,
+        data.length() == 0 ? NULL : data.data(),
+        data.length(),
+        &interact,
+        &output,
+        &length);
+
+    CHECK_NE(SASL_INTERACT, result)
+      << "Not expecting an interaction (ID: " << interact->id << ")";
+
+    if (result == SASL_OK || result == SASL_CONTINUE) {
+      // We don't start the client with SASL_SUCCESS_DATA so we may
+      // need to send one more "empty" message to the server.
+      AuthenticationStepMessage message;
+      if (output != NULL && length > 0) {
+        message.set_data(output, length);
+      }
+      reply(message);
+    } else {
+      status = ERROR;
+      std::string error(sasl_errdetail(connection));
+      promise.fail("Failed to perform authentication step: " + error);
+    }
+  }
+
+  void completed()
+  {
+    if (status != STEPPING) {
+      status = ERROR;
+      promise.fail("Unexpected authentication 'completed' received");
+      return;
+    }
+
+    LOG(INFO) << "Authentication success";
+
+    status = COMPLETED;
+    promise.set(true);
+  }
+
+  void failed()
+  {
+    status = FAILED;
+    promise.set(false);
+  }
+
+  void error(const std::string& error)
+  {
+    status = ERROR;
+    promise.fail("Authentication error: " + error);
+  }
+
+  void discarded()
+  {
+    status = DISCARDED;
+    promise.fail("Authentication discarded");
+  }
+
+private:
+  static int user(
+      void* context,
+      int id,
+      const char** result,
+      unsigned* length)
+  {
+    CHECK(SASL_CB_USER == id || SASL_CB_AUTHNAME == id);
+    *result = static_cast<const char*>(context);
+    if (length != NULL) {
+      *length = strlen(*result);
+    }
+    return SASL_OK;
+  }
+
+  static int pass(
+      sasl_conn_t* connection,
+      void* context,
+      int id,
+      sasl_secret_t** secret)
+  {
+    CHECK_EQ(SASL_CB_PASS, id);
+    *secret = static_cast<sasl_secret_t*>(context);
+    return SASL_OK;
+  }
+
+  const Credential credential;
+
+  // PID of the client that needs to be authenticated.
+  const process::UPID client;
+
+  sasl_secret_t* secret;
+
+  sasl_callback_t callbacks[5];
+
+  enum {
+    READY,
+    STARTING,
+    STEPPING,
+    COMPLETED,
+    FAILED,
+    ERROR,
+    DISCARDED
+  } status;
+
+  sasl_conn_t* connection;
+
+  process::Promise<bool> promise;
+};
+
+
+inline Authenticatee::Authenticatee(
+    const Credential& credential,
+    const process::UPID& client)
+{
+  process = new AuthenticateeProcess(credential, client);
+  process::spawn(process);
+}
+
+
+inline Authenticatee::~Authenticatee()
+{
+  process::terminate(process);
+  process::wait(process);
+  delete process;
+}
+
+
+inline process::Future<bool> Authenticatee::authenticate(
+    const process::UPID& pid)
+{
+  return process::dispatch(process, &AuthenticateeProcess::authenticate, pid);
+}
+
+} // namespace cram_md5 {
+} // namespace internal {
+} // namespace mesos {
+
+#endif //__AUTHENTICATION_CRAM_MD5_AUTHENTICATEE_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/authentication/cram_md5/authenticator.hpp
----------------------------------------------------------------------
diff --git a/src/authentication/cram_md5/authenticator.hpp 
b/src/authentication/cram_md5/authenticator.hpp
new file mode 100644
index 0000000..7953418
--- /dev/null
+++ b/src/authentication/cram_md5/authenticator.hpp
@@ -0,0 +1,494 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AUTHENTICATION_CRAM_MD5_AUTHENTICATOR_HPP__
+#define __AUTHENTICATION_CRAM_MD5_AUTHENTICATOR_HPP__
+
+#include <sasl/sasl.h>
+#include <sasl/saslplug.h>
+
+#include <string>
+#include <vector>
+
+#include <mesos/mesos.hpp>
+
+#include <process/defer.hpp>
+#include <process/future.hpp>
+#include <process/id.hpp>
+#include <process/once.hpp>
+#include <process/process.hpp>
+#include <process/protobuf.hpp>
+
+#include <stout/check.hpp>
+
+#include "authentication/cram_md5/auxprop.hpp"
+
+#include "messages/messages.hpp"
+
+namespace mesos {
+namespace internal {
+namespace cram_md5 {
+
+// Forward declaration.
+class AuthenticatorProcess;
+
+
+class Authenticator
+{
+public:
+  explicit Authenticator(const process::UPID& pid);
+  ~Authenticator();
+
+  // Returns the principal of the Authenticatee if successfully
+  // authenticated otherwise None or an error. Note that we
+  // distinguish authentication failure (None) from a failed future
+  // in the event the future failed due to a transient error and
+  // authentication can (should) be retried. Discarding the future
+  // will cause the future to fail if it hasn't already completed
+  // since we have already started the authentication procedure and
+  // can't reliably cancel.
+  process::Future<Option<std::string> > authenticate();
+
+private:
+  AuthenticatorProcess* process;
+};
+
+
+class AuthenticatorProcess : public ProtobufProcess<AuthenticatorProcess>
+{
+public:
+  explicit AuthenticatorProcess(const process::UPID& _pid)
+    : ProcessBase(process::ID::generate("authenticator")),
+      status(READY),
+      pid(_pid),
+      connection(NULL) {}
+
+  virtual ~AuthenticatorProcess()
+  {
+    if (connection != NULL) {
+      sasl_dispose(&connection);
+    }
+  }
+
+  virtual void finalize()
+  {
+    discarded(); // Fail the promise.
+  }
+
+  process::Future<Option<std::string> > authenticate()
+  {
+    static process::Once* initialize = new process::Once();
+    static bool initialized = false;
+
+    if (!initialize->once()) {
+      LOG(INFO) << "Initializing server SASL";
+
+      int result = sasl_server_init(NULL, "mesos");
+
+      if (result != SASL_OK) {
+        std::string error = "Failed to initialize SASL: ";
+        error += sasl_errstring(result, NULL, NULL);
+        LOG(ERROR) << error;
+        AuthenticationErrorMessage message;
+        message.set_error(error);
+        send(pid, message);
+        status = ERROR;
+        promise.fail(error);
+        initialize->done();
+        return promise.future();
+      }
+
+      result = sasl_auxprop_add_plugin(
+          InMemoryAuxiliaryPropertyPlugin::name(),
+          &InMemoryAuxiliaryPropertyPlugin::initialize);
+
+      if (result != SASL_OK) {
+        std::string error =
+          "Failed to add \"in-memory\" auxiliary property plugin: ";
+        error += sasl_errstring(result, NULL, NULL);
+        LOG(ERROR) << error;
+        AuthenticationErrorMessage message;
+        message.set_error(error);
+        send(pid, message);
+        status = ERROR;
+        promise.fail(error);
+        initialize->done();
+        return promise.future();
+      }
+
+      initialized = true;
+
+      initialize->done();
+    }
+
+    if (!initialized) {
+      promise.fail("Failed to initialize SASL");
+      return promise.future();
+    }
+
+    if (status != READY) {
+      return promise.future();
+    }
+
+    callbacks[0].id = SASL_CB_GETOPT;
+    callbacks[0].proc = (int(*)()) &getopt;
+    callbacks[0].context = NULL;
+
+    callbacks[1].id = SASL_CB_CANON_USER;
+    callbacks[1].proc = (int(*)()) &canonicalize;
+    // Pass in the principal so we can set it in canon_user().
+    callbacks[1].context = &principal;
+
+    callbacks[2].id = SASL_CB_LIST_END;
+    callbacks[2].proc = NULL;
+    callbacks[2].context = NULL;
+
+    LOG(INFO) << "Creating new server SASL connection";
+
+    int result = sasl_server_new(
+        "mesos",    // Registered name of service.
+        NULL,       // Server's FQDN; NULL uses gethostname().
+        NULL,       // The user realm used for password lookups;
+                    // NULL means default to FQDN.
+                    // NOTE: This does not affect Kerberos.
+        NULL, NULL, // IP address information strings.
+        callbacks,  // Callbacks supported only for this connection.
+        0,          // Security flags (security layers are enabled
+                    // using security properties, separately).
+        &connection);
+
+    if (result != SASL_OK) {
+      std::string error = "Failed to create server SASL connection: ";
+      error += sasl_errstring(result, NULL, NULL);
+      LOG(ERROR) << error;
+      AuthenticationErrorMessage message;
+      message.set_error(error);
+      send(pid, message);
+      status = ERROR;
+      promise.fail(error);
+      return promise.future();
+    }
+
+    // Get the list of mechanisms.
+    const char* output = NULL;
+    unsigned length = 0;
+    int count = 0;
+
+    result = sasl_listmech(
+        connection,  // The context for this connection.
+        NULL,        // Not supported.
+        "",          // What to prepend to the output string.
+        ",",         // What to separate mechanisms with.
+        "",          // What to append to the output string.
+        &output,     // The output string.
+        &length,     // The length of the output string.
+        &count);     // The count of the mechanisms in output.
+
+    if (result != SASL_OK) {
+      std::string error = "Failed to get list of mechanisms: ";
+      LOG(WARNING) << error << sasl_errstring(result, NULL, NULL);
+      AuthenticationErrorMessage message;
+      error += sasl_errdetail(connection);
+      message.set_error(error);
+      send(pid, message);
+      status = ERROR;
+      promise.fail(error);
+      return promise.future();
+    }
+
+    std::vector<std::string> mechanisms = strings::tokenize(output, ",");
+
+    // Send authentication mechanisms.
+    AuthenticationMechanismsMessage message;
+    foreach (const std::string& mechanism, mechanisms) {
+      message.add_mechanisms(mechanism);
+    }
+
+    send(pid, message);
+
+    status = STARTING;
+
+    // Stop authenticating if nobody cares.
+    promise.future().onDiscard(defer(self(), &Self::discarded));
+
+    return promise.future();
+  }
+
+protected:
+  virtual void initialize()
+  {
+    link(pid); // Don't bother waiting for a lost authenticatee.
+
+    // Anticipate start and steps messages from the client.
+    install<AuthenticationStartMessage>(
+        &AuthenticatorProcess::start,
+        &AuthenticationStartMessage::mechanism,
+        &AuthenticationStartMessage::data);
+
+    install<AuthenticationStepMessage>(
+        &AuthenticatorProcess::step,
+        &AuthenticationStepMessage::data);
+  }
+
+  virtual void exited(const process::UPID& _pid)
+  {
+    if (pid == _pid) {
+      status = ERROR;
+      promise.fail("Failed to communicate with authenticatee");
+    }
+  }
+
+  void start(const std::string& mechanism, const std::string& data)
+  {
+    if (status != STARTING) {
+      AuthenticationErrorMessage message;
+      message.set_error("Unexpected authentication 'start' received");
+      send(pid, message);
+      status = ERROR;
+      promise.fail(message.error());
+      return;
+    }
+
+    LOG(INFO) << "Received SASL authentication start";
+
+    // Start the server.
+    const char* output = NULL;
+    unsigned length = 0;
+
+    int result = sasl_server_start(
+        connection,
+        mechanism.c_str(),
+        data.length() == 0 ? NULL : data.data(),
+        data.length(),
+        &output,
+        &length);
+
+    handle(result, output, length);
+  }
+
+  void step(const std::string& data)
+  {
+    if (status != STEPPING) {
+      AuthenticationErrorMessage message;
+      message.set_error("Unexpected authentication 'step' received");
+      send(pid, message);
+      status = ERROR;
+      promise.fail(message.error());
+      return;
+    }
+
+    LOG(INFO) << "Received SASL authentication step";
+
+    const char* output = NULL;
+    unsigned length = 0;
+
+    int result = sasl_server_step(
+        connection,
+        data.length() == 0 ? NULL : data.data(),
+        data.length(),
+        &output,
+        &length);
+
+    handle(result, output, length);
+  }
+
+  void discarded()
+  {
+    status = DISCARDED;
+    promise.fail("Authentication discarded");
+  }
+
+private:
+  static int getopt(
+      void* context,
+      const char* plugin,
+      const char* option,
+      const char** result,
+      unsigned* length)
+  {
+    bool found = false;
+    if (std::string(option) == "auxprop_plugin") {
+      *result = "in-memory-auxprop";
+      found = true;
+    } else if (std::string(option) == "mech_list") {
+      *result = "CRAM-MD5";
+      found = true;
+    } else if (std::string(option) == "pwcheck_method") {
+      *result = "auxprop";
+      found = true;
+    }
+
+    if (found && length != NULL) {
+      *length = strlen(*result);
+    }
+
+    return SASL_OK;
+  }
+
+  // Callback for canonicalizing the username (principal). We use it
+  // to record the principal in Authenticator.
+  static int canonicalize(
+      sasl_conn_t* connection,
+      void* context,
+      const char* input,
+      unsigned inputLength,
+      unsigned flags,
+      const char* userRealm,
+      char* output,
+      unsigned outputMaxLength,
+      unsigned* outputLength)
+  {
+    CHECK_NOTNULL(input);
+    CHECK_NOTNULL(context);
+    CHECK_NOTNULL(output);
+
+    // Save the input.
+    Option<std::string>* principal =
+      static_cast<Option<std::string>*>(context);
+    CHECK(principal->isNone());
+    *principal = std::string(input, inputLength);
+
+    // Tell SASL that the canonical username is the same as the
+    // client-supplied username.
+    memcpy(output, input, inputLength);
+    *outputLength = inputLength;
+
+    return SASL_OK;
+  }
+
+  // Helper for handling result of server start and step.
+  void handle(int result, const char* output, unsigned length)
+  {
+    if (result == SASL_OK) {
+      // Principal must have been set if authentication succeeded.
+      CHECK_SOME(principal);
+
+      LOG(INFO) << "Authentication success";
+      // Note that we're not using SASL_SUCCESS_DATA which means that
+      // we should not have any data to send when we get a SASL_OK.
+      CHECK(output == NULL);
+      send(pid, AuthenticationCompletedMessage());
+      status = COMPLETED;
+      promise.set(principal);
+    } else if (result == SASL_CONTINUE) {
+      LOG(INFO) << "Authentication requires more steps";
+      AuthenticationStepMessage message;
+      message.set_data(CHECK_NOTNULL(output), length);
+      send(pid, message);
+      status = STEPPING;
+    } else if (result == SASL_NOUSER || result == SASL_BADAUTH) {
+      LOG(WARNING) << "Authentication failure: "
+                   << sasl_errstring(result, NULL, NULL);
+      send(pid, AuthenticationFailedMessage());
+      status = FAILED;
+      promise.set(Option<std::string>::none());
+    } else {
+      LOG(ERROR) << "Authentication error: "
+                 << sasl_errstring(result, NULL, NULL);
+      AuthenticationErrorMessage message;
+      std::string error(sasl_errdetail(connection));
+      message.set_error(error);
+      send(pid, message);
+      status = ERROR;
+      promise.fail(message.error());
+    }
+  }
+
+  enum {
+    READY,
+    STARTING,
+    STEPPING,
+    COMPLETED,
+    FAILED,
+    ERROR,
+    DISCARDED
+  } status;
+
+  sasl_callback_t callbacks[3];
+
+  const process::UPID pid;
+
+  sasl_conn_t* connection;
+
+  process::Promise<Option<std::string> > promise;
+
+  Option<std::string> principal;
+};
+
+
+Authenticator::Authenticator(const process::UPID& pid)
+{
+  process = new AuthenticatorProcess(pid);
+  process::spawn(process);
+}
+
+
+Authenticator::~Authenticator()
+{
+  // TODO(vinod): As a short term fix for the race condition #1 in
+  // MESOS-1866, we inject the 'terminate' event at the end of the
+  // AuthenticatorProcess queue instead of at the front.
+  // The long term fix for this https://reviews.apache.org/r/25945/.
+  process::terminate(process, false);
+
+  process::wait(process);
+  delete process;
+}
+
+
+process::Future<Option<std::string> > Authenticator::authenticate()
+{
+  return process::dispatch(process, &AuthenticatorProcess::authenticate);
+}
+
+
+namespace secrets {
+
+// Loads secrets (principal -> secret) into the in-memory auxiliary
+// property plugin that is used by the authenticators.
+void load(const std::map<std::string, std::string>& secrets)
+{
+  Multimap<std::string, Property> properties;
+
+  foreachpair (const std::string& principal,
+               const std::string& secret, secrets) {
+    Property property;
+    property.name = SASL_AUX_PASSWORD_PROP;
+    property.values.push_back(secret);
+    properties.put(principal, property);
+  }
+
+  InMemoryAuxiliaryPropertyPlugin::load(properties);
+}
+
+void load(const Credentials& credentials)
+{
+  std::map<std::string, std::string> secrets;
+  foreach(const Credential& credential, credentials.credentials()) {
+    secrets[credential.principal()] = credential.secret();
+  }
+  load(secrets);
+}
+
+} // namespace secrets {
+
+} // namespace cram_md5 {
+} // namespace internal {
+} // namespace mesos {
+
+#endif //__AUTHENTICATION_CRAM_MD5_AUTHENTICATOR_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/authentication/cram_md5/auxprop.cpp
----------------------------------------------------------------------
diff --git a/src/authentication/cram_md5/auxprop.cpp 
b/src/authentication/cram_md5/auxprop.cpp
new file mode 100644
index 0000000..cf503a2
--- /dev/null
+++ b/src/authentication/cram_md5/auxprop.cpp
@@ -0,0 +1,204 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "authentication/cram_md5/auxprop.hpp"
+
+#include "logging/logging.hpp"
+
+using std::list;
+using std::string;
+
+namespace mesos {
+namespace internal {
+namespace cram_md5 {
+
+// Storage for the static members.
+Multimap<string, Property> InMemoryAuxiliaryPropertyPlugin::properties;
+sasl_auxprop_plug_t InMemoryAuxiliaryPropertyPlugin::plugin;
+
+
+int InMemoryAuxiliaryPropertyPlugin::initialize(
+    const sasl_utils_t* utils,
+    int api,
+    int* version,
+    sasl_auxprop_plug_t** plug,
+    const char* name)
+{
+  if (version == NULL || plug == NULL) {
+    return SASL_BADPARAM;
+  }
+
+  // Check if SASL API is older than the one we were compiled against.
+  if (api < SASL_AUXPROP_PLUG_VERSION) {
+    return SASL_BADVERS;
+  }
+
+  *version = SASL_AUXPROP_PLUG_VERSION;
+
+  plugin.features = 0;
+  plugin.spare_int1 = 0;
+  plugin.glob_context = NULL;
+  plugin.auxprop_free = NULL;
+  plugin.auxprop_lookup = &InMemoryAuxiliaryPropertyPlugin::lookup;
+  plugin.name = const_cast<char*>(InMemoryAuxiliaryPropertyPlugin::name());
+  plugin.auxprop_store = NULL;
+
+  *plug = &plugin;
+
+  VLOG(1) << "Initialized in-memory auxiliary property plugin";
+
+  return SASL_OK;
+}
+
+
+#if SASL_AUXPROP_PLUG_VERSION <= 4
+  void InMemoryAuxiliaryPropertyPlugin::lookup(
+#else
+  int InMemoryAuxiliaryPropertyPlugin::lookup(
+#endif
+    void* context,
+    sasl_server_params_t* sparams,
+    unsigned flags,
+    const char* user,
+    unsigned length)
+{
+  // Pull out the utils.
+  const sasl_utils_t* utils = sparams->utils;
+
+  // We determine the properties we should be looking up by doing a
+  // 'prop_get' on the property context. Note that some of the
+  // properties we get might might need to be skipped depending on the
+  // flags (see below).
+  const propval* properties = utils->prop_get(sparams->propctx);
+
+  CHECK(properties != NULL)
+    << "Invalid auxiliary properties requested for lookup";
+
+  // TODO(benh): Consider "parsing" 'user' if it has an '@' separating
+  // the actual user and a realm.
+
+  string realm = sparams->user_realm != NULL
+    ? sparams->user_realm
+    : sparams->serverFQDN;
+
+  VLOG(1)
+    << "Request to lookup properties for "
+    << "user: '" << user << "' "
+    << "realm: '" << realm << "' "
+    << "server FQDN: '" << sparams->serverFQDN << "' "
+#ifdef SASL_AUXPROP_VERIFY_AGAINST_HASH
+    << "SASL_AUXPROP_VERIFY_AGAINST_HASH: "
+    << (flags & SASL_AUXPROP_VERIFY_AGAINST_HASH ? "true ": "false ")
+#endif
+    << "SASL_AUXPROP_OVERRIDE: "
+    << (flags & SASL_AUXPROP_OVERRIDE ? "true ": "false ")
+    << "SASL_AUXPROP_AUTHZID: "
+    << (flags & SASL_AUXPROP_AUTHZID ? "true ": "false ");
+
+  // Now iterate through each property requested.
+  const propval* property = properties;
+  for (; property->name != NULL; property++) {
+    const char* name = property->name;
+
+    // Skip properties that don't apply to this lookup given the flags.
+    if (flags & SASL_AUXPROP_AUTHZID) {
+      if (name[0] == '*') {
+        VLOG(1) << "Skipping auxiliary property '" << name
+                << "' since SASL_AUXPROP_AUTHZID == true";
+        continue;
+      }
+    } else {
+      // Only consider properties that start with '*' if
+      // SASL_AUXPROP_AUTHZID is not set but don't include the '*'
+      // when looking up the property name.
+      if (name[0] != '*') {
+        VLOG(1) << "Skipping auxiliary property '" << name
+                << "' since SASL_AUXPROP_AUTHZID == false "
+                << "but property name starts with '*'";
+        continue;
+      } else {
+        name = name + 1;
+      }
+    }
+
+    // Don't override already set values unless instructed otherwise.
+    if (property->values != NULL && !(flags & SASL_AUXPROP_OVERRIDE)) {
+#ifdef SASL_AUXPROP_VERIFY_AGAINST_HASH
+      // Regardless of SASL_AUXPROP_OVERRIDE we're expected to
+      // override property 'userPassword' when the
+      // SASL_AUXPROP_VERIFY_AGAINST_HASH flag is set, so we erase it
+      // here.
+      if (flags & SASL_AUXPROP_VERIFY_AGAINST_HASH &&
+          string(name) == string(SASL_AUX_PASSWORD_PROP)) {
+        VLOG(1) << "Erasing auxiliary property '" << name
+                << "' even though SASL_AUXPROP_OVERRIDE == true "
+                << "since SASL_AUXPROP_VERIFY_AGAINST_HASH == true";
+        utils->prop_erase(sparams->propctx, property->name);
+      } else {
+        VLOG(1) << "Skipping auxiliary property '" << name
+                << "' since SASL_AUXPROP_OVERRIDE == false "
+                << "and value(s) already set";
+        continue;
+      }
+#else
+      VLOG(1) << "Skipping auxiliary property '" << name
+              << "' since SASL_AUXPROP_OVERRIDE == false "
+              << "and value(s) already set";
+      continue;
+#endif
+    } else if (property->values != NULL) {
+      CHECK(flags & SASL_AUXPROP_OVERRIDE);
+      VLOG(1) << "Erasing auxiliary property '" << name
+              << "' since SASL_AUXPROP_OVERRIDE == true";
+      utils->prop_erase(sparams->propctx, property->name);
+    }
+
+    VLOG(1) << "Looking up auxiliary property '" << property->name << "'";
+
+    Option<list<string> > values = lookup(user, name);
+
+    if (values.isSome()) {
+      if (values.get().empty()) {
+        // Add the 'NULL' value to indicate there were no values.
+        utils->prop_set(sparams->propctx, property->name, NULL, 0);
+      } else {
+        // Add all the values. Note that passing NULL as the property
+        // name for 'prop_set' will append values to the same name as
+        // the previous 'prop_set' calls which is the behavior we want
+        // after adding the first value.
+        bool append = false;
+        foreach (const string& value, values.get()) {
+          sparams->utils->prop_set(
+              sparams->propctx,
+              append ? NULL : property->name,
+              value.c_str(),
+              -1); // Let 'prop_set' use strlen.
+          append = true;
+        }
+      }
+    }
+  }
+
+#if SASL_AUXPROP_PLUG_VERSION > 4
+  return SASL_OK;
+#endif
+}
+
+} // namespace cram_md5 {
+} // namespace internal {
+} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/authentication/cram_md5/auxprop.hpp
----------------------------------------------------------------------
diff --git a/src/authentication/cram_md5/auxprop.hpp 
b/src/authentication/cram_md5/auxprop.hpp
new file mode 100644
index 0000000..b894386
--- /dev/null
+++ b/src/authentication/cram_md5/auxprop.hpp
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AUTHENTICATION_CRAM_MD5_AUXPROP_HPP__
+#define __AUTHENTICATION_CRAM_MD5_AUXPROP_HPP__
+
+#include <string>
+
+#include <sasl/sasl.h>
+#include <sasl/saslplug.h>
+
+#include <stout/foreach.hpp>
+#include <stout/multimap.hpp>
+#include <stout/none.hpp>
+#include <stout/option.hpp>
+
+namespace mesos {
+namespace internal {
+namespace cram_md5 {
+
+struct Property
+{
+  std::string name;
+  std::list<std::string> values;
+};
+
+
+class InMemoryAuxiliaryPropertyPlugin
+{
+public:
+  static const char* name() { return "in-memory-auxprop"; }
+
+  static void load(const Multimap<std::string, Property>& _properties)
+  {
+    properties = _properties;
+  }
+
+  static Option<std::list<std::string> > lookup(
+      const std::string& user,
+      const std::string& name)
+  {
+    if (properties.contains(user)) {
+      foreach (const Property& property, properties.get(user)) {
+        if (property.name == name) {
+          return property.values;
+        }
+      }
+    }
+    return None();
+  }
+
+  // SASL plugin initialize entry.
+  static int initialize(
+      const sasl_utils_t* utils,
+      int api,
+      int* version,
+      sasl_auxprop_plug_t** plug,
+      const char* name);
+
+private:
+#if SASL_AUXPROP_PLUG_VERSION <= 4
+  static void lookup(
+#else
+  static int lookup(
+#endif
+      void* context,
+      sasl_server_params_t* sparams,
+      unsigned flags,
+      const char* user,
+      unsigned length);
+
+  static Multimap<std::string, Property> properties;
+
+  static sasl_auxprop_plug_t plugin;
+};
+
+} // namespace cram_md5 {
+} // namespace internal {
+} // namespace mesos {
+
+#endif // __AUTHENTICATION_CRAM_MD5_AUXPROP_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 762d2ff..39e27c5 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -51,9 +51,9 @@
 #include <stout/utils.hpp>
 #include <stout/uuid.hpp>
 
-#include "authorizer/authorizer.hpp"
+#include "authentication/cram_md5/authenticator.hpp"
 
-#include "sasl/authenticator.hpp"
+#include "authorizer/authorizer.hpp"
 
 #include "common/build.hpp"
 #include "common/date_utils.hpp"
@@ -380,8 +380,8 @@ void Master::initialize()
     // Store credentials in master to use them in routes.
     credentials = _credentials.get();
 
-    // Load "registration" credentials into SASL based Authenticator.
-    sasl::secrets::load(_credentials.get());
+    // Load "registration" credentials into CRAM-MD5 Authenticator.
+    cram_md5::secrets::load(_credentials.get());
 
   } else if (flags.authenticate_frameworks || flags.authenticate_slaves) {
     EXIT(1) << "Authentication requires a credentials file"
@@ -3857,7 +3857,8 @@ void Master::authenticate(const UPID& from, const UPID& 
pid)
   Owned<Promise<Nothing> > promise(new Promise<Nothing>());
 
   // Create the authenticator.
-  Owned<sasl::Authenticator> authenticator(new sasl::Authenticator(from));
+  Owned<cram_md5::Authenticator> authenticator(
+    new cram_md5::Authenticator(from));
 
   // Start authentication.
   const Future<Option<string> >& future = authenticator->authenticate()

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index b1a2cd0..468b6e1 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -72,7 +72,7 @@ namespace registry {
 class Slaves;
 }
 
-namespace sasl {
+namespace cram_md5 {
 class Authenticator;
 }
 
@@ -584,7 +584,8 @@ private:
   // authenticated.
   hashmap<process::UPID, process::Future<Nothing> > authenticating;
 
-  hashmap<process::UPID, process::Owned<sasl::Authenticator> > authenticators;
+  hashmap<process::UPID, process::Owned<cram_md5::Authenticator> >
+    authenticators;
 
   // Principals of authenticated frameworks/slaves keyed by PID.
   hashmap<process::UPID, std::string> authenticated;

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/sasl/authenticatee.hpp
----------------------------------------------------------------------
diff --git a/src/sasl/authenticatee.hpp b/src/sasl/authenticatee.hpp
deleted file mode 100644
index ec2c841..0000000
--- a/src/sasl/authenticatee.hpp
+++ /dev/null
@@ -1,412 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SASL_AUTHENTICATEE_HPP__
-#define __SASL_AUTHENTICATEE_HPP__
-
-#include <sasl/sasl.h>
-
-#include <mesos/mesos.hpp>
-
-#include <process/defer.hpp>
-#include <process/future.hpp>
-#include <process/id.hpp>
-#include <process/once.hpp>
-#include <process/process.hpp>
-#include <process/protobuf.hpp>
-
-#include <stout/strings.hpp>
-
-#include "messages/messages.hpp"
-
-namespace mesos {
-namespace internal {
-namespace sasl {
-
-// Forward declaration.
-class AuthenticateeProcess;
-
-
-class Authenticatee
-{
-public:
-  // 'credential' is used to authenticate the 'client'.
-  Authenticatee(const Credential& credential, const process::UPID& client);
-  ~Authenticatee();
-
-  // Returns true if successfully authenticated otherwise false or an
-  // error. Note that we distinguish authentication failure (false)
-  // from a failed future in the event the future failed due to a
-  // transient error and authentication can (should) be
-  // retried. Discarding the future will cause the future to fail if
-  // it hasn't already completed since we have already started the
-  // authentication procedure and can't reliably cancel.
-  process::Future<bool> authenticate(const process::UPID& pid);
-
-private:
-  AuthenticateeProcess* process;
-};
-
-
-class AuthenticateeProcess : public ProtobufProcess<AuthenticateeProcess>
-{
-public:
-  AuthenticateeProcess(const Credential& _credential,
-                       const process::UPID& _client)
-    : ProcessBase(process::ID::generate("authenticatee")),
-      credential(_credential),
-      client(_client),
-      status(READY),
-      connection(NULL)
-  {
-    const char* data = credential.secret().data();
-    size_t length = credential.secret().length();
-
-    // Need to allocate the secret via 'malloc' because SASL is
-    // expecting the data appended to the end of the struct. *sigh*
-    secret = (sasl_secret_t*) malloc(sizeof(sasl_secret_t) + length);
-
-    CHECK(secret != NULL) << "Failed to allocate memory for secret";
-
-    memcpy(secret->data, data, length);
-    secret->len = length;
-  }
-
-  virtual ~AuthenticateeProcess()
-  {
-    if (connection != NULL) {
-      sasl_dispose(&connection);
-    }
-    free(secret);
-  }
-
-  virtual void finalize()
-  {
-    discarded(); // Fail the promise.
-  }
-
-  process::Future<bool> authenticate(const process::UPID& pid)
-  {
-    static process::Once* initialize = new process::Once();
-    static bool initialized = false;
-
-    if (!initialize->once()) {
-      LOG(INFO) << "Initializing client SASL";
-      int result = sasl_client_init(NULL);
-      if (result != SASL_OK) {
-        status = ERROR;
-        std::string error(sasl_errstring(result, NULL, NULL));
-        promise.fail("Failed to initialize SASL: " + error);
-        initialize->done();
-        return promise.future();
-      }
-
-      initialized = true;
-
-      initialize->done();
-    }
-
-    if (!initialized) {
-      promise.fail("Failed to initialize SASL");
-      return promise.future();
-    }
-
-    if (status != READY) {
-      return promise.future();
-    }
-
-    LOG(INFO) << "Creating new client SASL connection";
-
-    callbacks[0].id = SASL_CB_GETREALM;
-    callbacks[0].proc = NULL;
-    callbacks[0].context = NULL;
-
-    callbacks[1].id = SASL_CB_USER;
-    callbacks[1].proc = (int(*)()) &user;
-    callbacks[2].context = (void*) credential.principal().c_str();
-
-    // NOTE: Some SASL mechanisms do not allow/enable "proxying",
-    // i.e., authorization. Therefore, some mechanisms send _only_ the
-    // authoriation name rather than both the user (authentication
-    // name) and authorization name. Thus, for now, we assume
-    // authorization is handled out of band. Consider the
-    // SASL_NEED_PROXY flag if we want to reconsider this in the
-    // future.
-    callbacks[2].id = SASL_CB_AUTHNAME;
-    callbacks[2].proc = (int(*)()) &user;
-    callbacks[2].context = (void*) credential.principal().c_str();
-
-    callbacks[3].id = SASL_CB_PASS;
-    callbacks[3].proc = (int(*)()) &pass;
-    callbacks[3].context = (void*) secret;
-
-    callbacks[4].id = SASL_CB_LIST_END;
-    callbacks[4].proc = NULL;
-    callbacks[4].context = NULL;
-
-    int result = sasl_client_new(
-        "mesos",    // Registered name of service.
-        NULL,       // Server's FQDN.
-        NULL, NULL, // IP Address information strings.
-        callbacks,  // Callbacks supported only for this connection.
-        0,          // Security flags (security layers are enabled
-                    // using security properties, separately).
-        &connection);
-
-    if (result != SASL_OK) {
-      status = ERROR;
-      std::string error(sasl_errstring(result, NULL, NULL));
-      promise.fail("Failed to create client SASL connection: " + error);
-      return promise.future();
-    }
-
-    AuthenticateMessage message;
-    message.set_pid(client);
-    send(pid, message);
-
-    status = STARTING;
-
-    // Stop authenticating if nobody cares.
-    promise.future().onDiscard(defer(self(), &Self::discarded));
-
-    return promise.future();
-  }
-
-protected:
-  virtual void initialize()
-  {
-    // Anticipate mechanisms and steps from the server.
-    install<AuthenticationMechanismsMessage>(
-        &AuthenticateeProcess::mechanisms,
-        &AuthenticationMechanismsMessage::mechanisms);
-
-    install<AuthenticationStepMessage>(
-        &AuthenticateeProcess::step,
-        &AuthenticationStepMessage::data);
-
-    install<AuthenticationCompletedMessage>(
-        &AuthenticateeProcess::completed);
-
-    install<AuthenticationFailedMessage>(
-        &AuthenticateeProcess::failed);
-
-    install<AuthenticationErrorMessage>(
-        &AuthenticateeProcess::error,
-        &AuthenticationErrorMessage::error);
-  }
-
-  void mechanisms(const std::vector<std::string>& mechanisms)
-  {
-    if (status != STARTING) {
-      status = ERROR;
-      promise.fail("Unexpected authentication 'mechanisms' received");
-      return;
-    }
-
-    // TODO(benh): Store 'from' in order to ensure we only communicate
-    // with the same Authenticator.
-
-    LOG(INFO) << "Received SASL authentication mechanisms: "
-              << strings::join(",", mechanisms);
-
-    sasl_interact_t* interact = NULL;
-    const char* output = NULL;
-    unsigned length = 0;
-    const char* mechanism = NULL;
-
-    int result = sasl_client_start(
-        connection,
-        strings::join(" ", mechanisms).c_str(),
-        &interact,     // Set if an interaction is needed.
-        &output,       // The output string (to send to server).
-        &length,       // The length of the output string.
-        &mechanism);   // The chosen mechanism.
-
-    CHECK_NE(SASL_INTERACT, result)
-      << "Not expecting an interaction (ID: " << interact->id << ")";
-
-    if (result != SASL_OK && result != SASL_CONTINUE) {
-      std::string error(sasl_errdetail(connection));
-      status = ERROR;
-      promise.fail("Failed to start the SASL client: " + error);
-      return;
-    }
-
-    LOG(INFO) << "Attempting to authenticate with mechanism '"
-              << mechanism << "'";
-
-    AuthenticationStartMessage message;
-    message.set_mechanism(mechanism);
-    message.set_data(output, length);
-
-    reply(message);
-
-    status = STEPPING;
-  }
-
-  void step(const std::string& data)
-  {
-    if (status != STEPPING) {
-      status = ERROR;
-      promise.fail("Unexpected authentication 'step' received");
-      return;
-    }
-
-    LOG(INFO) << "Received SASL authentication step";
-
-    sasl_interact_t* interact = NULL;
-    const char* output = NULL;
-    unsigned length = 0;
-
-    int result = sasl_client_step(
-        connection,
-        data.length() == 0 ? NULL : data.data(),
-        data.length(),
-        &interact,
-        &output,
-        &length);
-
-    CHECK_NE(SASL_INTERACT, result)
-      << "Not expecting an interaction (ID: " << interact->id << ")";
-
-    if (result == SASL_OK || result == SASL_CONTINUE) {
-      // We don't start the client with SASL_SUCCESS_DATA so we may
-      // need to send one more "empty" message to the server.
-      AuthenticationStepMessage message;
-      if (output != NULL && length > 0) {
-        message.set_data(output, length);
-      }
-      reply(message);
-    } else {
-      status = ERROR;
-      std::string error(sasl_errdetail(connection));
-      promise.fail("Failed to perform authentication step: " + error);
-    }
-  }
-
-  void completed()
-  {
-    if (status != STEPPING) {
-      status = ERROR;
-      promise.fail("Unexpected authentication 'completed' received");
-      return;
-    }
-
-    LOG(INFO) << "Authentication success";
-
-    status = COMPLETED;
-    promise.set(true);
-  }
-
-  void failed()
-  {
-    status = FAILED;
-    promise.set(false);
-  }
-
-  void error(const std::string& error)
-  {
-    status = ERROR;
-    promise.fail("Authentication error: " + error);
-  }
-
-  void discarded()
-  {
-    status = DISCARDED;
-    promise.fail("Authentication discarded");
-  }
-
-private:
-  static int user(
-      void* context,
-      int id,
-      const char** result,
-      unsigned* length)
-  {
-    CHECK(SASL_CB_USER == id || SASL_CB_AUTHNAME == id);
-    *result = static_cast<const char*>(context);
-    if (length != NULL) {
-      *length = strlen(*result);
-    }
-    return SASL_OK;
-  }
-
-  static int pass(
-      sasl_conn_t* connection,
-      void* context,
-      int id,
-      sasl_secret_t** secret)
-  {
-    CHECK_EQ(SASL_CB_PASS, id);
-    *secret = static_cast<sasl_secret_t*>(context);
-    return SASL_OK;
-  }
-
-  const Credential credential;
-
-  // PID of the client that needs to be authenticated.
-  const process::UPID client;
-
-  sasl_secret_t* secret;
-
-  sasl_callback_t callbacks[5];
-
-  enum {
-    READY,
-    STARTING,
-    STEPPING,
-    COMPLETED,
-    FAILED,
-    ERROR,
-    DISCARDED
-  } status;
-
-  sasl_conn_t* connection;
-
-  process::Promise<bool> promise;
-};
-
-
-inline Authenticatee::Authenticatee(
-    const Credential& credential,
-    const process::UPID& client)
-{
-  process = new AuthenticateeProcess(credential, client);
-  process::spawn(process);
-}
-
-
-inline Authenticatee::~Authenticatee()
-{
-  process::terminate(process);
-  process::wait(process);
-  delete process;
-}
-
-
-inline process::Future<bool> Authenticatee::authenticate(
-    const process::UPID& pid)
-{
-  return process::dispatch(process, &AuthenticateeProcess::authenticate, pid);
-}
-
-} // namespace sasl {
-} // namespace internal {
-} // namespace mesos {
-
-#endif //__SASL_AUTHENTICATEE_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/sasl/authenticator.hpp
----------------------------------------------------------------------
diff --git a/src/sasl/authenticator.hpp b/src/sasl/authenticator.hpp
deleted file mode 100644
index 6f4d3db..0000000
--- a/src/sasl/authenticator.hpp
+++ /dev/null
@@ -1,494 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SASL_AUTHENTICATOR_HPP__
-#define __SASL_AUTHENTICATOR_HPP__
-
-#include <sasl/sasl.h>
-#include <sasl/saslplug.h>
-
-#include <string>
-#include <vector>
-
-#include <mesos/mesos.hpp>
-
-#include <process/defer.hpp>
-#include <process/future.hpp>
-#include <process/id.hpp>
-#include <process/once.hpp>
-#include <process/process.hpp>
-#include <process/protobuf.hpp>
-
-#include <stout/check.hpp>
-
-#include "messages/messages.hpp"
-
-#include "sasl/auxprop.hpp"
-
-namespace mesos {
-namespace internal {
-namespace sasl {
-
-// Forward declaration.
-class AuthenticatorProcess;
-
-
-class Authenticator
-{
-public:
-  explicit Authenticator(const process::UPID& pid);
-  ~Authenticator();
-
-  // Returns the principal of the Authenticatee if successfully
-  // authenticated otherwise None or an error. Note that we
-  // distinguish authentication failure (None) from a failed future
-  // in the event the future failed due to a transient error and
-  // authentication can (should) be retried. Discarding the future
-  // will cause the future to fail if it hasn't already completed
-  // since we have already started the authentication procedure and
-  // can't reliably cancel.
-  process::Future<Option<std::string> > authenticate();
-
-private:
-  AuthenticatorProcess* process;
-};
-
-
-class AuthenticatorProcess : public ProtobufProcess<AuthenticatorProcess>
-{
-public:
-  explicit AuthenticatorProcess(const process::UPID& _pid)
-    : ProcessBase(process::ID::generate("authenticator")),
-      status(READY),
-      pid(_pid),
-      connection(NULL) {}
-
-  virtual ~AuthenticatorProcess()
-  {
-    if (connection != NULL) {
-      sasl_dispose(&connection);
-    }
-  }
-
-  virtual void finalize()
-  {
-    discarded(); // Fail the promise.
-  }
-
-  process::Future<Option<std::string> > authenticate()
-  {
-    static process::Once* initialize = new process::Once();
-    static bool initialized = false;
-
-    if (!initialize->once()) {
-      LOG(INFO) << "Initializing server SASL";
-
-      int result = sasl_server_init(NULL, "mesos");
-
-      if (result != SASL_OK) {
-        std::string error = "Failed to initialize SASL: ";
-        error += sasl_errstring(result, NULL, NULL);
-        LOG(ERROR) << error;
-        AuthenticationErrorMessage message;
-        message.set_error(error);
-        send(pid, message);
-        status = ERROR;
-        promise.fail(error);
-        initialize->done();
-        return promise.future();
-      }
-
-      result = sasl_auxprop_add_plugin(
-          InMemoryAuxiliaryPropertyPlugin::name(),
-          &InMemoryAuxiliaryPropertyPlugin::initialize);
-
-      if (result != SASL_OK) {
-        std::string error =
-          "Failed to add \"in-memory\" auxiliary property plugin: ";
-        error += sasl_errstring(result, NULL, NULL);
-        LOG(ERROR) << error;
-        AuthenticationErrorMessage message;
-        message.set_error(error);
-        send(pid, message);
-        status = ERROR;
-        promise.fail(error);
-        initialize->done();
-        return promise.future();
-      }
-
-      initialized = true;
-
-      initialize->done();
-    }
-
-    if (!initialized) {
-      promise.fail("Failed to initialize SASL");
-      return promise.future();
-    }
-
-    if (status != READY) {
-      return promise.future();
-    }
-
-    callbacks[0].id = SASL_CB_GETOPT;
-    callbacks[0].proc = (int(*)()) &getopt;
-    callbacks[0].context = NULL;
-
-    callbacks[1].id = SASL_CB_CANON_USER;
-    callbacks[1].proc = (int(*)()) &canonicalize;
-    // Pass in the principal so we can set it in canon_user().
-    callbacks[1].context = &principal;
-
-    callbacks[2].id = SASL_CB_LIST_END;
-    callbacks[2].proc = NULL;
-    callbacks[2].context = NULL;
-
-    LOG(INFO) << "Creating new server SASL connection";
-
-    int result = sasl_server_new(
-        "mesos",    // Registered name of service.
-        NULL,       // Server's FQDN; NULL uses gethostname().
-        NULL,       // The user realm used for password lookups;
-                    // NULL means default to FQDN.
-                    // NOTE: This does not affect Kerberos.
-        NULL, NULL, // IP address information strings.
-        callbacks,  // Callbacks supported only for this connection.
-        0,          // Security flags (security layers are enabled
-                    // using security properties, separately).
-        &connection);
-
-    if (result != SASL_OK) {
-      std::string error = "Failed to create server SASL connection: ";
-      error += sasl_errstring(result, NULL, NULL);
-      LOG(ERROR) << error;
-      AuthenticationErrorMessage message;
-      message.set_error(error);
-      send(pid, message);
-      status = ERROR;
-      promise.fail(error);
-      return promise.future();
-    }
-
-    // Get the list of mechanisms.
-    const char* output = NULL;
-    unsigned length = 0;
-    int count = 0;
-
-    result = sasl_listmech(
-        connection,  // The context for this connection.
-        NULL,        // Not supported.
-        "",          // What to prepend to the output string.
-        ",",         // What to separate mechanisms with.
-        "",          // What to append to the output string.
-        &output,     // The output string.
-        &length,     // The length of the output string.
-        &count);     // The count of the mechanisms in output.
-
-    if (result != SASL_OK) {
-      std::string error = "Failed to get list of mechanisms: ";
-      LOG(WARNING) << error << sasl_errstring(result, NULL, NULL);
-      AuthenticationErrorMessage message;
-      error += sasl_errdetail(connection);
-      message.set_error(error);
-      send(pid, message);
-      status = ERROR;
-      promise.fail(error);
-      return promise.future();
-    }
-
-    std::vector<std::string> mechanisms = strings::tokenize(output, ",");
-
-    // Send authentication mechanisms.
-    AuthenticationMechanismsMessage message;
-    foreach (const std::string& mechanism, mechanisms) {
-      message.add_mechanisms(mechanism);
-    }
-
-    send(pid, message);
-
-    status = STARTING;
-
-    // Stop authenticating if nobody cares.
-    promise.future().onDiscard(defer(self(), &Self::discarded));
-
-    return promise.future();
-  }
-
-protected:
-  virtual void initialize()
-  {
-    link(pid); // Don't bother waiting for a lost authenticatee.
-
-    // Anticipate start and steps messages from the client.
-    install<AuthenticationStartMessage>(
-        &AuthenticatorProcess::start,
-        &AuthenticationStartMessage::mechanism,
-        &AuthenticationStartMessage::data);
-
-    install<AuthenticationStepMessage>(
-        &AuthenticatorProcess::step,
-        &AuthenticationStepMessage::data);
-  }
-
-  virtual void exited(const process::UPID& _pid)
-  {
-    if (pid == _pid) {
-      status = ERROR;
-      promise.fail("Failed to communicate with authenticatee");
-    }
-  }
-
-  void start(const std::string& mechanism, const std::string& data)
-  {
-    if (status != STARTING) {
-      AuthenticationErrorMessage message;
-      message.set_error("Unexpected authentication 'start' received");
-      send(pid, message);
-      status = ERROR;
-      promise.fail(message.error());
-      return;
-    }
-
-    LOG(INFO) << "Received SASL authentication start";
-
-    // Start the server.
-    const char* output = NULL;
-    unsigned length = 0;
-
-    int result = sasl_server_start(
-        connection,
-        mechanism.c_str(),
-        data.length() == 0 ? NULL : data.data(),
-        data.length(),
-        &output,
-        &length);
-
-    handle(result, output, length);
-  }
-
-  void step(const std::string& data)
-  {
-    if (status != STEPPING) {
-      AuthenticationErrorMessage message;
-      message.set_error("Unexpected authentication 'step' received");
-      send(pid, message);
-      status = ERROR;
-      promise.fail(message.error());
-      return;
-    }
-
-    LOG(INFO) << "Received SASL authentication step";
-
-    const char* output = NULL;
-    unsigned length = 0;
-
-    int result = sasl_server_step(
-        connection,
-        data.length() == 0 ? NULL : data.data(),
-        data.length(),
-        &output,
-        &length);
-
-    handle(result, output, length);
-  }
-
-  void discarded()
-  {
-    status = DISCARDED;
-    promise.fail("Authentication discarded");
-  }
-
-private:
-  static int getopt(
-      void* context,
-      const char* plugin,
-      const char* option,
-      const char** result,
-      unsigned* length)
-  {
-    bool found = false;
-    if (std::string(option) == "auxprop_plugin") {
-      *result = "in-memory-auxprop";
-      found = true;
-    } else if (std::string(option) == "mech_list") {
-      *result = "CRAM-MD5";
-      found = true;
-    } else if (std::string(option) == "pwcheck_method") {
-      *result = "auxprop";
-      found = true;
-    }
-
-    if (found && length != NULL) {
-      *length = strlen(*result);
-    }
-
-    return SASL_OK;
-  }
-
-  // Callback for canonicalizing the username (principal). We use it
-  // to record the principal in Authenticator.
-  static int canonicalize(
-      sasl_conn_t* connection,
-      void* context,
-      const char* input,
-      unsigned inputLength,
-      unsigned flags,
-      const char* userRealm,
-      char* output,
-      unsigned outputMaxLength,
-      unsigned* outputLength)
-  {
-    CHECK_NOTNULL(input);
-    CHECK_NOTNULL(context);
-    CHECK_NOTNULL(output);
-
-    // Save the input.
-    Option<std::string>* principal =
-      static_cast<Option<std::string>*>(context);
-    CHECK(principal->isNone());
-    *principal = std::string(input, inputLength);
-
-    // Tell SASL that the canonical username is the same as the
-    // client-supplied username.
-    memcpy(output, input, inputLength);
-    *outputLength = inputLength;
-
-    return SASL_OK;
-  }
-
-  // Helper for handling result of server start and step.
-  void handle(int result, const char* output, unsigned length)
-  {
-    if (result == SASL_OK) {
-      // Principal must have been set if authentication succeeded.
-      CHECK_SOME(principal);
-
-      LOG(INFO) << "Authentication success";
-      // Note that we're not using SASL_SUCCESS_DATA which means that
-      // we should not have any data to send when we get a SASL_OK.
-      CHECK(output == NULL);
-      send(pid, AuthenticationCompletedMessage());
-      status = COMPLETED;
-      promise.set(principal);
-    } else if (result == SASL_CONTINUE) {
-      LOG(INFO) << "Authentication requires more steps";
-      AuthenticationStepMessage message;
-      message.set_data(CHECK_NOTNULL(output), length);
-      send(pid, message);
-      status = STEPPING;
-    } else if (result == SASL_NOUSER || result == SASL_BADAUTH) {
-      LOG(WARNING) << "Authentication failure: "
-                   << sasl_errstring(result, NULL, NULL);
-      send(pid, AuthenticationFailedMessage());
-      status = FAILED;
-      promise.set(Option<std::string>::none());
-    } else {
-      LOG(ERROR) << "Authentication error: "
-                 << sasl_errstring(result, NULL, NULL);
-      AuthenticationErrorMessage message;
-      std::string error(sasl_errdetail(connection));
-      message.set_error(error);
-      send(pid, message);
-      status = ERROR;
-      promise.fail(message.error());
-    }
-  }
-
-  enum {
-    READY,
-    STARTING,
-    STEPPING,
-    COMPLETED,
-    FAILED,
-    ERROR,
-    DISCARDED
-  } status;
-
-  sasl_callback_t callbacks[3];
-
-  const process::UPID pid;
-
-  sasl_conn_t* connection;
-
-  process::Promise<Option<std::string> > promise;
-
-  Option<std::string> principal;
-};
-
-
-Authenticator::Authenticator(const process::UPID& pid)
-{
-  process = new AuthenticatorProcess(pid);
-  process::spawn(process);
-}
-
-
-Authenticator::~Authenticator()
-{
-  // TODO(vinod): As a short term fix for the race condition #1 in
-  // MESOS-1866, we inject the 'terminate' event at the end of the
-  // AuthenticatorProcess queue instead of at the front.
-  // The long term fix for this https://reviews.apache.org/r/25945/.
-  process::terminate(process, false);
-
-  process::wait(process);
-  delete process;
-}
-
-
-process::Future<Option<std::string> > Authenticator::authenticate()
-{
-  return process::dispatch(process, &AuthenticatorProcess::authenticate);
-}
-
-
-namespace secrets {
-
-// Loads secrets (principal -> secret) into the in-memory auxiliary
-// property plugin that is used by the authenticators.
-void load(const std::map<std::string, std::string>& secrets)
-{
-  Multimap<std::string, Property> properties;
-
-  foreachpair (const std::string& principal,
-               const std::string& secret, secrets) {
-    Property property;
-    property.name = SASL_AUX_PASSWORD_PROP;
-    property.values.push_back(secret);
-    properties.put(principal, property);
-  }
-
-  InMemoryAuxiliaryPropertyPlugin::load(properties);
-}
-
-void load(const Credentials& credentials)
-{
-  std::map<std::string, std::string> secrets;
-  foreach(const Credential& credential, credentials.credentials()) {
-    secrets[credential.principal()] = credential.secret();
-  }
-  load(secrets);
-}
-
-} // namespace secrets {
-
-} // namespace sasl {
-} // namespace internal {
-} // namespace mesos {
-
-#endif //__SASL_AUTHENTICATOR_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/sasl/auxprop.cpp
----------------------------------------------------------------------
diff --git a/src/sasl/auxprop.cpp b/src/sasl/auxprop.cpp
deleted file mode 100644
index 6de1222..0000000
--- a/src/sasl/auxprop.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-#include "logging/logging.hpp"
-
-#include "sasl/auxprop.hpp"
-
-using std::list;
-using std::string;
-
-namespace mesos {
-namespace internal {
-namespace sasl {
-
-// Storage for the static members.
-Multimap<string, Property> InMemoryAuxiliaryPropertyPlugin::properties;
-sasl_auxprop_plug_t InMemoryAuxiliaryPropertyPlugin::plugin;
-
-
-int InMemoryAuxiliaryPropertyPlugin::initialize(
-    const sasl_utils_t* utils,
-    int api,
-    int* version,
-    sasl_auxprop_plug_t** plug,
-    const char* name)
-{
-  if (version == NULL || plug == NULL) {
-    return SASL_BADPARAM;
-  }
-
-  // Check if SASL API is older than the one we were compiled against.
-  if (api < SASL_AUXPROP_PLUG_VERSION) {
-    return SASL_BADVERS;
-  }
-
-  *version = SASL_AUXPROP_PLUG_VERSION;
-
-  plugin.features = 0;
-  plugin.spare_int1 = 0;
-  plugin.glob_context = NULL;
-  plugin.auxprop_free = NULL;
-  plugin.auxprop_lookup = &InMemoryAuxiliaryPropertyPlugin::lookup;
-  plugin.name = const_cast<char*>(InMemoryAuxiliaryPropertyPlugin::name());
-  plugin.auxprop_store = NULL;
-
-  *plug = &plugin;
-
-  VLOG(1) << "Initialized in-memory auxiliary property plugin";
-
-  return SASL_OK;
-}
-
-
-#if SASL_AUXPROP_PLUG_VERSION <= 4
-  void InMemoryAuxiliaryPropertyPlugin::lookup(
-#else
-  int InMemoryAuxiliaryPropertyPlugin::lookup(
-#endif
-    void* context,
-    sasl_server_params_t* sparams,
-    unsigned flags,
-    const char* user,
-    unsigned length)
-{
-  // Pull out the utils.
-  const sasl_utils_t* utils = sparams->utils;
-
-  // We determine the properties we should be looking up by doing a
-  // 'prop_get' on the property context. Note that some of the
-  // properties we get might might need to be skipped depending on the
-  // flags (see below).
-  const propval* properties = utils->prop_get(sparams->propctx);
-
-  CHECK(properties != NULL)
-    << "Invalid auxiliary properties requested for lookup";
-
-  // TODO(benh): Consider "parsing" 'user' if it has an '@' separating
-  // the actual user and a realm.
-
-  string realm = sparams->user_realm != NULL
-    ? sparams->user_realm
-    : sparams->serverFQDN;
-
-  VLOG(1)
-    << "Request to lookup properties for "
-    << "user: '" << user << "' "
-    << "realm: '" << realm << "' "
-    << "server FQDN: '" << sparams->serverFQDN << "' "
-#ifdef SASL_AUXPROP_VERIFY_AGAINST_HASH
-    << "SASL_AUXPROP_VERIFY_AGAINST_HASH: "
-    << (flags & SASL_AUXPROP_VERIFY_AGAINST_HASH ? "true ": "false ")
-#endif
-    << "SASL_AUXPROP_OVERRIDE: "
-    << (flags & SASL_AUXPROP_OVERRIDE ? "true ": "false ")
-    << "SASL_AUXPROP_AUTHZID: "
-    << (flags & SASL_AUXPROP_AUTHZID ? "true ": "false ");
-
-  // Now iterate through each property requested.
-  const propval* property = properties;
-  for (; property->name != NULL; property++) {
-    const char* name = property->name;
-
-    // Skip properties that don't apply to this lookup given the flags.
-    if (flags & SASL_AUXPROP_AUTHZID) {
-      if (name[0] == '*') {
-        VLOG(1) << "Skipping auxiliary property '" << name
-                << "' since SASL_AUXPROP_AUTHZID == true";
-        continue;
-      }
-    } else {
-      // Only consider properties that start with '*' if
-      // SASL_AUXPROP_AUTHZID is not set but don't include the '*'
-      // when looking up the property name.
-      if (name[0] != '*') {
-        VLOG(1) << "Skipping auxiliary property '" << name
-                << "' since SASL_AUXPROP_AUTHZID == false "
-                << "but property name starts with '*'";
-        continue;
-      } else {
-        name = name + 1;
-      }
-    }
-
-    // Don't override already set values unless instructed otherwise.
-    if (property->values != NULL && !(flags & SASL_AUXPROP_OVERRIDE)) {
-#ifdef SASL_AUXPROP_VERIFY_AGAINST_HASH
-      // Regardless of SASL_AUXPROP_OVERRIDE we're expected to
-      // override property 'userPassword' when the
-      // SASL_AUXPROP_VERIFY_AGAINST_HASH flag is set, so we erase it
-      // here.
-      if (flags & SASL_AUXPROP_VERIFY_AGAINST_HASH &&
-          string(name) == string(SASL_AUX_PASSWORD_PROP)) {
-        VLOG(1) << "Erasing auxiliary property '" << name
-                << "' even though SASL_AUXPROP_OVERRIDE == true "
-                << "since SASL_AUXPROP_VERIFY_AGAINST_HASH == true";
-        utils->prop_erase(sparams->propctx, property->name);
-      } else {
-        VLOG(1) << "Skipping auxiliary property '" << name
-                << "' since SASL_AUXPROP_OVERRIDE == false "
-                << "and value(s) already set";
-        continue;
-      }
-#else
-      VLOG(1) << "Skipping auxiliary property '" << name
-              << "' since SASL_AUXPROP_OVERRIDE == false "
-              << "and value(s) already set";
-      continue;
-#endif
-    } else if (property->values != NULL) {
-      CHECK(flags & SASL_AUXPROP_OVERRIDE);
-      VLOG(1) << "Erasing auxiliary property '" << name
-              << "' since SASL_AUXPROP_OVERRIDE == true";
-      utils->prop_erase(sparams->propctx, property->name);
-    }
-
-    VLOG(1) << "Looking up auxiliary property '" << property->name << "'";
-
-    Option<list<string> > values = lookup(user, name);
-
-    if (values.isSome()) {
-      if (values.get().empty()) {
-        // Add the 'NULL' value to indicate there were no values.
-        utils->prop_set(sparams->propctx, property->name, NULL, 0);
-      } else {
-        // Add all the values. Note that passing NULL as the property
-        // name for 'prop_set' will append values to the same name as
-        // the previous 'prop_set' calls which is the behavior we want
-        // after adding the first value.
-        bool append = false;
-        foreach (const string& value, values.get()) {
-          sparams->utils->prop_set(
-              sparams->propctx,
-              append ? NULL : property->name,
-              value.c_str(),
-              -1); // Let 'prop_set' use strlen.
-          append = true;
-        }
-      }
-    }
-  }
-
-#if SASL_AUXPROP_PLUG_VERSION > 4
-  return SASL_OK;
-#endif
-}
-
-} // namespace sasl {
-} // namespace internal {
-} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/sasl/auxprop.hpp
----------------------------------------------------------------------
diff --git a/src/sasl/auxprop.hpp b/src/sasl/auxprop.hpp
deleted file mode 100644
index 44e201b..0000000
--- a/src/sasl/auxprop.hpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SASL_AUXPROP_HPP__
-#define __SASL_AUXPROP_HPP__
-
-#include <sasl/sasl.h>
-#include <sasl/saslplug.h>
-
-#include <string>
-
-#include <stout/foreach.hpp>
-#include <stout/multimap.hpp>
-#include <stout/none.hpp>
-#include <stout/option.hpp>
-
-namespace mesos {
-namespace internal {
-namespace sasl {
-
-struct Property
-{
-  std::string name;
-  std::list<std::string> values;
-};
-
-
-class InMemoryAuxiliaryPropertyPlugin
-{
-public:
-  static const char* name() { return "in-memory-auxprop"; }
-
-  static void load(const Multimap<std::string, Property>& _properties)
-  {
-    properties = _properties;
-  }
-
-  static Option<std::list<std::string> > lookup(
-      const std::string& user,
-      const std::string& name)
-  {
-    if (properties.contains(user)) {
-      foreach (const Property& property, properties.get(user)) {
-        if (property.name == name) {
-          return property.values;
-        }
-      }
-    }
-    return None();
-  }
-
-  // SASL plugin initialize entry.
-  static int initialize(
-      const sasl_utils_t* utils,
-      int api,
-      int* version,
-      sasl_auxprop_plug_t** plug,
-      const char* name);
-
-private:
-#if SASL_AUXPROP_PLUG_VERSION <= 4
-  static void lookup(
-#else
-  static int lookup(
-#endif
-      void* context,
-      sasl_server_params_t* sparams,
-      unsigned flags,
-      const char* user,
-      unsigned length);
-
-  static Multimap<std::string, Property> properties;
-
-  static sasl_auxprop_plug_t plugin;
-};
-
-} // namespace sasl {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __SASL_AUXPROP_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/sched/sched.cpp
----------------------------------------------------------------------
diff --git a/src/sched/sched.cpp b/src/sched/sched.cpp
index 0fb8c7b..d84465c 100644
--- a/src/sched/sched.cpp
+++ b/src/sched/sched.cpp
@@ -59,7 +59,7 @@
 #include <stout/utils.hpp>
 #include <stout/uuid.hpp>
 
-#include "sasl/authenticatee.hpp"
+#include "authentication/cram_md5/authenticatee.hpp"
 
 #include "common/lock.hpp"
 #include "common/type_utils.hpp"
@@ -285,7 +285,7 @@ protected:
     CHECK_SOME(credential);
 
     CHECK(authenticatee == NULL);
-    authenticatee = new sasl::Authenticatee(credential.get(), self());
+    authenticatee = new cram_md5::Authenticatee(credential.get(), self());
 
     // NOTE: We do not pass 'Owned<Authenticatee>' here because doing
     // so could make 'AuthenticateeProcess' responsible for deleting
@@ -1024,7 +1024,7 @@ private:
 
   const Option<Credential> credential;
 
-  sasl::Authenticatee* authenticatee;
+  cram_md5::Authenticatee* authenticatee;
 
   // Indicates if an authentication attempt is in progress.
   Option<Future<bool> > authenticating;

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/scheduler/scheduler.cpp
----------------------------------------------------------------------
diff --git a/src/scheduler/scheduler.cpp b/src/scheduler/scheduler.cpp
index fb88a3e..c74187c 100644
--- a/src/scheduler/scheduler.cpp
+++ b/src/scheduler/scheduler.cpp
@@ -53,7 +53,7 @@
 #include <stout/os.hpp>
 #include <stout/uuid.hpp>
 
-#include "sasl/authenticatee.hpp"
+#include "authentication/cram_md5/authenticatee.hpp"
 
 #include "common/type_utils.hpp"
 
@@ -465,7 +465,7 @@ protected:
     CHECK_SOME(credential);
 
     CHECK(authenticatee == NULL);
-    authenticatee = new sasl::Authenticatee(credential.get(), self());
+    authenticatee = new cram_md5::Authenticatee(credential.get(), self());
 
     // NOTE: We do not pass 'Owned<Authenticatee>' here because doing
     // so could make 'AuthenticateeProcess' responsible for deleting
@@ -808,7 +808,7 @@ private:
 
   Option<UPID> master;
 
-  sasl::Authenticatee* authenticatee;
+  cram_md5::Authenticatee* authenticatee;
 
   // Indicates if an authentication attempt is in progress.
   Option<Future<bool> > authenticating;

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/slave/slave.cpp
----------------------------------------------------------------------
diff --git a/src/slave/slave.cpp b/src/slave/slave.cpp
index 5e9b0e4..b893517 100644
--- a/src/slave/slave.cpp
+++ b/src/slave/slave.cpp
@@ -62,6 +62,8 @@
 #include "linux/cgroups.hpp"
 #endif // __linux__
 
+#include "authentication/cram_md5/authenticatee.hpp"
+
 #include "common/build.hpp"
 #include "common/protobuf_utils.hpp"
 #include "common/type_utils.hpp"
@@ -71,8 +73,6 @@
 
 #include "logging/logging.hpp"
 
-#include "sasl/authenticatee.hpp"
-
 #include "slave/constants.hpp"
 #include "slave/flags.hpp"
 #include "slave/paths.hpp"
@@ -667,7 +667,7 @@ void Slave::authenticate()
   CHECK_SOME(credential);
 
   CHECK(authenticatee == NULL);
-  authenticatee = new sasl::Authenticatee(credential.get(), self());
+  authenticatee = new cram_md5::Authenticatee(credential.get(), self());
 
   authenticating = authenticatee->authenticate(master.get())
     .onAny(defer(self(), &Self::_authenticate));

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/slave/slave.hpp
----------------------------------------------------------------------
diff --git a/src/slave/slave.hpp b/src/slave/slave.hpp
index eb5de73..6c183f8 100644
--- a/src/slave/slave.hpp
+++ b/src/slave/slave.hpp
@@ -70,9 +70,9 @@ namespace internal {
 
 class MasterDetector; // Forward declaration.
 
-namespace sasl {
+namespace cram_md5 {
 class Authenticatee;
-} // namespace sasl {
+} // namespace cram_md5 {
 
 namespace slave {
 
@@ -481,7 +481,7 @@ private:
 
   Option<Credential> credential;
 
-  sasl::Authenticatee* authenticatee;
+  cram_md5::Authenticatee* authenticatee;
 
   // Indicates if an authentication attempt is in progress.
   Option<Future<bool> > authenticating;

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51f5550/src/tests/cram_md5_authentication_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/cram_md5_authentication_tests.cpp 
b/src/tests/cram_md5_authentication_tests.cpp
new file mode 100644
index 0000000..d27c905
--- /dev/null
+++ b/src/tests/cram_md5_authentication_tests.cpp
@@ -0,0 +1,209 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <map>
+#include <string>
+
+#include <process/gmock.hpp>
+#include <process/gtest.hpp>
+#include <process/pid.hpp>
+#include <process/process.hpp>
+
+#include <stout/gtest.hpp>
+
+#include "authentication/cram_md5/authenticatee.hpp"
+#include "authentication/cram_md5/authenticator.hpp"
+
+#include "tests/mesos.hpp"
+
+using namespace mesos::internal::tests;
+
+using namespace process;
+
+using std::map;
+using std::string;
+
+using testing::_;
+using testing::Eq;
+
+namespace mesos {
+namespace internal {
+namespace cram_md5 {
+
+TEST(CRAMMD5Authentication, success)
+{
+  // Set up secrets.
+  map<string, string> secrets;
+  secrets["benh"] = "secret";
+  cram_md5::secrets::load(secrets);
+
+  // Launch a dummy process (somebody to send the AuthenticateMessage).
+  UPID pid = spawn(new ProcessBase(), true);
+
+  Credential credential;
+  credential.set_principal("benh");
+  credential.set_secret("secret");
+
+  Authenticatee authenticatee(credential, UPID());
+
+  Future<Message> message =
+    FUTURE_MESSAGE(Eq(AuthenticateMessage().GetTypeName()), _, _);
+
+  Future<bool> client = authenticatee.authenticate(pid);
+
+  AWAIT_READY(message);
+
+  Authenticator authenticator(message.get().from);
+
+  Future<Option<string> > principal = authenticator.authenticate();
+
+  AWAIT_EQ(true, client);
+  AWAIT_READY(principal);
+  EXPECT_SOME_EQ("benh", principal.get());
+
+  terminate(pid);
+}
+
+
+// Bad password should return an authentication failure.
+TEST(CRAMMD5Authentication, failed1)
+{
+  // Set up secrets.
+  map<string, string> secrets;
+  secrets["benh"] = "secret1";
+  cram_md5::secrets::load(secrets);
+
+  // Launch a dummy process (somebody to send the AuthenticateMessage).
+  UPID pid = spawn(new ProcessBase(), true);
+
+  Credential credential;
+  credential.set_principal("benh");
+  credential.set_secret("secret");
+
+  Authenticatee authenticatee(credential, UPID());
+
+  Future<Message> message =
+    FUTURE_MESSAGE(Eq(AuthenticateMessage().GetTypeName()), _, _);
+
+  Future<bool> client = authenticatee.authenticate(pid);
+
+  AWAIT_READY(message);
+
+  Authenticator authenticator(message.get().from);
+
+  Future<Option<string> > server = authenticator.authenticate();
+
+  AWAIT_EQ(false, client);
+  AWAIT_READY(server);
+  EXPECT_NONE(server.get());
+
+  terminate(pid);
+}
+
+
+// No user should return an authentication failure.
+TEST(CRAMMD5Authentication, failed2)
+{
+  // Set up secrets.
+  map<string, string> secrets;
+  secrets["vinod"] = "secret";
+  cram_md5::secrets::load(secrets);
+
+  // Launch a dummy process (somebody to send the AuthenticateMessage).
+  UPID pid = spawn(new ProcessBase(), true);
+
+  Credential credential;
+  credential.set_principal("benh");
+  credential.set_secret("secret");
+
+  Authenticatee authenticatee(credential, UPID());
+
+  Future<Message> message =
+    FUTURE_MESSAGE(Eq(AuthenticateMessage().GetTypeName()), _, _);
+
+  Future<bool> client = authenticatee.authenticate(pid);
+
+  AWAIT_READY(message);
+
+  Authenticator authenticator(message.get().from);
+
+  Future<Option<string> > server = authenticator.authenticate();
+
+  AWAIT_EQ(false, client);
+  AWAIT_READY(server);
+  EXPECT_NONE(server.get());
+
+  terminate(pid);
+}
+
+
+// This test verifies that the pending future returned by
+// 'Authenticator::authenticate()' is properly failed when the Authenticator is
+// destructed in the middle of authentication.
+TEST(CRAMMD5Authentication, AuthenticatorDestructionRace)
+{
+  // Set up secrets.
+  map<string, string> secrets;
+  secrets["benh"] = "secret";
+  cram_md5::secrets::load(secrets);
+
+  // Launch a dummy process (somebody to send the AuthenticateMessage).
+  UPID pid = spawn(new ProcessBase(), true);
+
+  Credential credential;
+  credential.set_principal("benh");
+  credential.set_secret("secret");
+
+  Authenticatee authenticatee(credential, UPID());
+
+  Future<Message> message =
+    FUTURE_MESSAGE(Eq(AuthenticateMessage().GetTypeName()), _, _);
+
+  Future<bool> client = authenticatee.authenticate(pid);
+
+  AWAIT_READY(message);
+
+  Authenticator* authenticator = new Authenticator(message.get().from);
+
+  // Drop the AuthenticationStepMessage from authenticator to keep
+  // the authentication from getting completed.
+  Future<AuthenticationStepMessage> authenticationStepMessage =
+    DROP_PROTOBUF(AuthenticationStepMessage(), _, _);
+
+  Future<Option<string> > principal = authenticator->authenticate();
+
+  AWAIT_READY(authenticationStepMessage);
+
+  // At this point 'AuthenticatorProcess::authenticate()' has been
+  // executed and its promise associated with the promise returned
+  // by 'Authenticator::authenticate()'.
+  // Authentication should be pending.
+  ASSERT_TRUE(principal.isPending());
+
+  // Now delete the authenticator.
+  delete authenticator;
+
+  // The future should be failed at this point.
+  AWAIT_FAILED(principal);
+
+  terminate(pid);
+}
+
+} // namespace cram_md5 {
+} // namespace internal {
+} // namespace mesos {

Reply via email to