Skip to content
This repository has been archived by the owner on Jun 23, 2022. It is now read-only.

feat(security): init sasl #599

Merged
merged 16 commits into from
Aug 26, 2020
2 changes: 2 additions & 0 deletions include/dsn/utility/error_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,6 @@ DEFINE_ERR_CODE(ERR_CHILD_REGISTERED)
DEFINE_ERR_CODE(ERR_INGESTION_FAILED)
DEFINE_ERR_CODE(ERR_UNAUTHENTICATED)
DEFINE_ERR_CODE(ERR_KRB5_INTERNAL)

DEFINE_ERR_CODE(ERR_SASL_INTERNAL)
} // namespace dsn
8 changes: 7 additions & 1 deletion src/runtime/security/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// under the License.

#include "kinit_context.h"
#include "sasl_utils.h"

#include <dsn/dist/fmt_logging.h>
#include <dsn/utility/flags.h>
Expand Down Expand Up @@ -55,7 +56,12 @@ bool init(bool is_server)
}
ddebug("initialize kerberos succeed");

// TODO(zlw): init sasl
err = init_sasl(is_server);
if (!err.is_ok()) {
derror_f("initialize sasl failed, with err = {}", err.description());
return false;
}
ddebug("initialize sasl succeed");

return true;
}
Expand Down
18 changes: 10 additions & 8 deletions src/runtime/security/kinit_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,18 @@ error_s check_configuration()
return error_s::ok();
}

class kinit_context
class kinit_context : public utils::singleton<kinit_context>
{
public:
kinit_context() : _opt(nullptr) {}
virtual ~kinit_context();
~kinit_context();

// implementation of 'kinit -k -t <keytab_file> <principal>'
error_s kinit();
const std::string &username() const { return _user_name; }

private:
kinit_context() = default;

// init kerberos context
void init_krb5_ctx();

Expand Down Expand Up @@ -109,6 +112,8 @@ class kinit_context

uint64_t _cred_expire_timestamp;
std::shared_ptr<boost::asio::deadline_timer> _timer;

friend class utils::singleton<kinit_context>;
};

kinit_context::~kinit_context() { krb5_get_init_creds_opt_free(_krb5_context, _opt); }
Expand Down Expand Up @@ -310,11 +315,8 @@ error_s kinit_context::wrap_krb5_err(krb5_error_code krb5_err, const std::string
return result_err;
}

error_s run_kinit()
{
static kinit_context context;
return context.kinit();
}
error_s run_kinit() { return kinit_context::instance().kinit(); }

const std::string &get_username() { return kinit_context::instance().username(); }
} // namespace security
} // namespace dsn
1 change: 1 addition & 0 deletions src/runtime/security/kinit_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
namespace dsn {
namespace security {
extern error_s run_kinit();
extern const std::string &get_username();
} // namespace security
} // namespace dsn
152 changes: 152 additions & 0 deletions src/runtime/security/sasl_utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// 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 "sasl_utils.h"
#include "kinit_context.h"

#include <sasl/sasl.h>
#include <sasl/saslplug.h>
#include <functional>

#include <dsn/c/api_utilities.h>
#include <dsn/dist/fmt_logging.h>
#include <dsn/utility/flags.h>
#include <dsn/utility/synchronize.h>

namespace dsn {
namespace security {
DSN_DEFINE_string("security", sasl_plugin_path, "/usr/lib/sasl2", "path to search sasl plugins");

dsn_log_level_t get_dsn_log_level(int level)
{
// The log levels of LOG_LEVEL_DEBUG and LOG_LEVEL_INFORMATION are in reverse order.
// So here we should compatible with this case.
switch (level) {
case SASL_LOG_ERR:
return LOG_LEVEL_ERROR;
case SASL_LOG_FAIL:
case SASL_LOG_WARN:
return LOG_LEVEL_WARNING;
case SASL_LOG_NOTE:
return LOG_LEVEL_DEBUG;
default:
return LOG_LEVEL_INFORMATION;
}
}

int sasl_simple_logger(void *context, int level, const char *msg)
{
if (SASL_LOG_NONE == level || nullptr == msg) {
return SASL_OK;
}

dlog_f(get_dsn_log_level(level), "sasl log info: {}", msg);
return SASL_OK;
}

int sasl_get_path(void *context, char **path)
{
if (nullptr == path) {
return SASL_BADPARAM;
}
*path = const_cast<char *>(FLAGS_sasl_plugin_path);
return SASL_OK;
}

int sasl_get_username(void *context, int id, const char **result, unsigned *len)
{
if (nullptr == result) {
return SASL_BADPARAM;
}
static const std::string username = get_username();
switch (id) {
case SASL_CB_USER:
case SASL_CB_AUTHNAME:
*result = username.c_str();
if (len != nullptr) {
*len = username.length();
}
return SASL_OK;
default:
dassert_f(false, "unexpected SASL callback type: {}", id);
return SASL_BADPARAM;
}
}

sasl_callback_t client_callbacks[] = {
{SASL_CB_USER, (sasl_callback_ft)&sasl_get_username, nullptr},
{SASL_CB_GETPATH, (sasl_callback_ft)&sasl_get_path, nullptr},
{SASL_CB_AUTHNAME, (sasl_callback_ft)&sasl_get_username, nullptr},
{SASL_CB_LOG, (sasl_callback_ft)&sasl_simple_logger, nullptr},
{SASL_CB_LIST_END, nullptr, nullptr}};
hycdong marked this conversation as resolved.
Show resolved Hide resolved

sasl_callback_t server_callbacks[] = {{SASL_CB_LOG, (sasl_callback_ft)&sasl_simple_logger, nullptr},
{SASL_CB_GETPATH, (sasl_callback_ft)&sasl_get_path, nullptr},
{SASL_CB_LIST_END, nullptr, nullptr}};

// provide mutex function for sasl
void *sasl_mutex_alloc_local() { return static_cast<void *>(new utils::ex_lock_nr); }

void sasl_mutex_free_local(void *m) { delete static_cast<utils::ex_lock_nr *>(m); }

int sasl_mutex_lock_local(void *m)
{
static_cast<utils::ex_lock_nr *>(m)->lock();
return 0;
}

int sasl_mutex_unlock_local(void *m)
{
static_cast<utils::ex_lock_nr *>(m)->unlock();
return 0;
}

void sasl_set_mutex_local()
{
// sasl_set_mutex is a function in <sasl/sasl.h>
sasl_set_mutex(&sasl_mutex_alloc_local,
levy5307 marked this conversation as resolved.
Show resolved Hide resolved
&sasl_mutex_lock_local,
&sasl_mutex_unlock_local,
&sasl_mutex_free_local);
}

error_s init_sasl(bool is_server)
{
// server is also a client to other server.
// for example: replica server is a client of meta server.
sasl_set_mutex_local();
int err = sasl_client_init(&client_callbacks[0]);
levy5307 marked this conversation as resolved.
Show resolved Hide resolved
error_s ret = error_s::make(ERR_OK);
if (err != SASL_OK) {
ret = error_s::make(ERR_SASL_INTERNAL);
ret << "initialize sasl client failed with error: "
<< sasl_errstring(err, nullptr, nullptr);
return ret;
}
if (is_server) {
err = sasl_server_init(&server_callbacks[0], "pegasus");
if (err != SASL_OK) {
ret = error_s::make(ERR_SASL_INTERNAL);
ret << "initialize sasl server failed with error: "
<< sasl_errstring(err, nullptr, nullptr);
return ret;
}
}
return ret;
}
} // namespace security
} // namespace dsn
27 changes: 27 additions & 0 deletions src/runtime/security/sasl_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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.

#pragma once

#include <dsn/utility/errors.h>

namespace dsn {
namespace security {
// you must have already initialized kerberos before call init_sasl
error_s init_sasl(bool is_server);
} // namespace security
} // namespace dsn