You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by me...@apache.org on 2015/03/27 23:51:03 UTC
[3/3] mesos git commit: Split cram_md5 authenticator into declaration
and implementation without functional changes.
Split cram_md5 authenticator into declaration and implementation without functional changes.
Review: https://reviews.apache.org/r/31961
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/4809d161
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/4809d161
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/4809d161
Branch: refs/heads/master
Commit: 4809d161ee6ba51983027f358691af1c779fb915
Parents: 17a0658
Author: Till Toenshoff <to...@me.com>
Authored: Fri Mar 27 15:25:04 2015 -0700
Committer: Adam B <ad...@mesosphere.io>
Committed: Fri Mar 27 15:25:04 2015 -0700
----------------------------------------------------------------------
src/Makefile.am | 1 +
src/authentication/cram_md5/authenticator.cpp | 483 +++++++++++++++++++++
src/authentication/cram_md5/authenticator.hpp | 444 +------------------
3 files changed, 488 insertions(+), 440 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/4809d161/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 84a62d4..9ce85a6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -297,6 +297,7 @@ nodist_libmesos_no_3rdparty_la_SOURCES = \
# TODO(tillt): Remove authentication/cram_md5/* which will enable us to
# lose the immediate cyrus-sasl2 dependency.
libmesos_no_3rdparty_la_SOURCES = \
+ authentication/cram_md5/authenticator.cpp \
authentication/cram_md5/auxprop.cpp \
authorizer/authorizer.cpp \
common/attributes.cpp \
http://git-wip-us.apache.org/repos/asf/mesos/blob/4809d161/src/authentication/cram_md5/authenticator.cpp
----------------------------------------------------------------------
diff --git a/src/authentication/cram_md5/authenticator.cpp b/src/authentication/cram_md5/authenticator.cpp
new file mode 100644
index 0000000..2125b45
--- /dev/null
+++ b/src/authentication/cram_md5/authenticator.cpp
@@ -0,0 +1,483 @@
+/**
+ * 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 <stddef.h> // For size_t needed by sasl.h.
+
+#include <sasl/sasl.h>
+#include <sasl/saslplug.h>
+
+#include <map>
+#include <vector>
+
+#include <mesos/mesos.hpp>
+
+#include <process/defer.hpp>
+#include <process/once.hpp>
+#include <process/protobuf.hpp>
+
+#include <stout/check.hpp>
+
+#include "authentication/cram_md5/auxprop.hpp"
+
+#include "authenticator.hpp"
+
+#include "messages/messages.hpp"
+
+namespace mesos {
+namespace internal {
+namespace cram_md5 {
+
+using namespace process;
+using std::string;
+
+class CRAMMD5AuthenticatorProcess
+ : public ProtobufProcess<CRAMMD5AuthenticatorProcess>
+{
+public:
+ explicit CRAMMD5AuthenticatorProcess(const UPID& _pid)
+ : ProcessBase(ID::generate("crammd5_authenticator")),
+ status(READY),
+ pid(_pid),
+ connection(NULL) {}
+
+ virtual ~CRAMMD5AuthenticatorProcess()
+ {
+ if (connection != NULL) {
+ sasl_dispose(&connection);
+ }
+ }
+
+ virtual void finalize()
+ {
+ discarded(); // Fail the promise.
+ }
+
+ Future<Option<string>> authenticate()
+ {
+ static Once* initialize = new Once();
+ static bool initialized = false;
+
+ if (!initialize->once()) {
+ LOG(INFO) << "Initializing server SASL";
+
+ int result = sasl_server_init(NULL, "mesos");
+
+ if (result != SASL_OK) {
+ 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) {
+ 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) {
+ 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) {
+ 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<string> mechanisms = strings::tokenize(output, ",");
+
+ // Send authentication mechanisms.
+ AuthenticationMechanismsMessage message;
+ foreach (const 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>(
+ &CRAMMD5AuthenticatorProcess::start,
+ &AuthenticationStartMessage::mechanism,
+ &AuthenticationStartMessage::data);
+
+ install<AuthenticationStepMessage>(
+ &CRAMMD5AuthenticatorProcess::step,
+ &AuthenticationStepMessage::data);
+ }
+
+ virtual void exited(const UPID& _pid)
+ {
+ if (pid == _pid) {
+ status = ERROR;
+ promise.fail("Failed to communicate with authenticatee");
+ }
+ }
+
+ void start(const string& mechanism, const 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 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 (string(option) == "auxprop_plugin") {
+ *result = "in-memory-auxprop";
+ found = true;
+ } else if (string(option) == "mech_list") {
+ *result = "CRAM-MD5";
+ found = true;
+ } else if (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 CRAMMD5Authenticator.
+ 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<string>* principal =
+ static_cast<Option<string>*>(context);
+ CHECK(principal->isNone());
+ *principal = 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<string>::none());
+ } else {
+ LOG(ERROR) << "Authentication error: "
+ << sasl_errstring(result, NULL, NULL);
+ AuthenticationErrorMessage message;
+ 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 UPID pid;
+
+ sasl_conn_t* connection;
+
+ Promise<Option<string>> promise;
+
+ Option<string> principal;
+};
+
+
+namespace secrets {
+
+// Loads secrets (principal -> secret) into the in-memory auxiliary
+// property plugin that is used by the authenticators.
+void load(const std::map<string, string>& secrets)
+{
+ Multimap<string, Property> properties;
+
+ foreachpair (const string& principal,
+ const 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<string, string> secrets;
+ foreach(const Credential& credential, credentials.credentials()) {
+ secrets[credential.principal()] = credential.secret();
+ }
+ load(secrets);
+}
+
+} // namespace secrets {
+
+
+Try<Authenticator*> CRAMMD5Authenticator::create()
+{
+ return new CRAMMD5Authenticator();
+}
+
+
+CRAMMD5Authenticator::CRAMMD5Authenticator() : process(NULL) {}
+
+
+CRAMMD5Authenticator::~CRAMMD5Authenticator()
+{
+ if (process != NULL) {
+ // 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
+ // CRAMMD5AuthenticatorProcess queue instead of at the front.
+ // The long term fix for this is https://reviews.apache.org/r/25945/.
+ terminate(process, false);
+
+ wait(process);
+ delete process;
+ }
+}
+
+
+void CRAMMD5Authenticator::initialize(const UPID& pid)
+{
+ CHECK(process == NULL) << "Authenticator has already been initialized";
+ process = new CRAMMD5AuthenticatorProcess(pid);
+ spawn(process);
+}
+
+
+Future<Option<string>> CRAMMD5Authenticator::authenticate(void)
+{
+ CHECK(process != NULL) << "Authenticator has not been initialized";
+ return dispatch(
+ process, &CRAMMD5AuthenticatorProcess::authenticate);
+}
+
+} // namespace cram_md5 {
+} // namespace internal {
+} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/4809d161/src/authentication/cram_md5/authenticator.hpp
----------------------------------------------------------------------
diff --git a/src/authentication/cram_md5/authenticator.hpp b/src/authentication/cram_md5/authenticator.hpp
index c6f465f..3463d7c 100644
--- a/src/authentication/cram_md5/authenticator.hpp
+++ b/src/authentication/cram_md5/authenticator.hpp
@@ -19,28 +19,15 @@
#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 <mesos/module/authenticator.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"
+#include <stout/option.hpp>
+#include <stout/try.hpp>
namespace mesos {
namespace internal {
@@ -77,439 +64,16 @@ private:
};
-class CRAMMD5AuthenticatorProcess
- : public ProtobufProcess<CRAMMD5AuthenticatorProcess>
-{
-public:
- explicit CRAMMD5AuthenticatorProcess(const process::UPID& _pid)
- : ProcessBase(process::ID::generate("crammd5_authenticator")),
- status(READY),
- pid(_pid),
- connection(NULL) {}
-
- virtual ~CRAMMD5AuthenticatorProcess()
- {
- 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>(
- &CRAMMD5AuthenticatorProcess::start,
- &AuthenticationStartMessage::mechanism,
- &AuthenticationStartMessage::data);
-
- install<AuthenticationStepMessage>(
- &CRAMMD5AuthenticatorProcess::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 CRAMMD5Authenticator.
- 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;
-};
-
-
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;
+void load(const std::map<std::string, std::string>& secrets);
- 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);
-}
+void load(const Credentials& credentials);
} // namespace secrets {
-
-Try<Authenticator*> CRAMMD5Authenticator::create()
-{
- return new CRAMMD5Authenticator();
-}
-
-
-CRAMMD5Authenticator::CRAMMD5Authenticator() : process(NULL) {}
-
-
-CRAMMD5Authenticator::~CRAMMD5Authenticator()
-{
- if (process != NULL) {
- // 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
- // CRAMMD5AuthenticatorProcess queue instead of at the front.
- // The long term fix for this is https://reviews.apache.org/r/25945/.
- process::terminate(process, false);
-
- process::wait(process);
- delete process;
- }
-}
-
-
-void CRAMMD5Authenticator::initialize(const process::UPID& pid)
-{
- CHECK(process == NULL) << "Authenticator has already been initialized";
- process = new CRAMMD5AuthenticatorProcess(pid);
- process::spawn(process);
-}
-
-
-process::Future<Option<std::string>> CRAMMD5Authenticator::authenticate(void)
-{
- CHECK(process != NULL) << "Authenticator has not been initialized";
- return process::dispatch(
- process, &CRAMMD5AuthenticatorProcess::authenticate);
-}
-
} // namespace cram_md5 {
} // namespace internal {
} // namespace mesos {