Skip to content

Commit

Permalink
feat(security): implement replica server access controller (XiaoMi#670)
Browse files Browse the repository at this point in the history
  • Loading branch information
levy5307 committed Dec 21, 2020
1 parent 289346e commit dfa58fd
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/replica/replica.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "duplication/replica_duplicator_manager.h"
#include "backup/replica_backup_manager.h"
#include "bulk_load/replica_bulk_loader.h"
#include "runtime/security/access_controller.h"

#include <dsn/utils/latency_tracer.h>
#include <dsn/cpp/json_helper.h>
Expand Down Expand Up @@ -101,6 +102,8 @@ replica::replica(
_extra_envs.insert(
std::make_pair(backup_restore_constant::FORCE_RESTORE, std::string("true")));
}

_access_controller = security::create_replica_access_controller(name());
}

void replica::update_last_checkpoint_generate_time()
Expand Down Expand Up @@ -157,6 +160,10 @@ replica::~replica(void)

void replica::on_client_read(dsn::message_ex *request)
{
if (!_access_controller->allowed(request)) {
response_client_read(request, ERR_ACL_DENY);
}

if (status() == partition_status::PS_INACTIVE ||
status() == partition_status::PS_POTENTIAL_SECONDARY) {
response_client_read(request, ERR_INVALID_STATE);
Expand Down
5 changes: 5 additions & 0 deletions src/replica/replica.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
#include "utils/throttling_controller.h"

namespace dsn {
namespace security {
class access_controller;
} // namespace security
namespace replication {

class replication_app_base;
Expand Down Expand Up @@ -562,6 +565,8 @@ class replica : public serverlet<replica>, public ref_counter, public replica_ba
dsn::task_tracker _tracker;
// the thread access checker
dsn::thread_access_checker _checker;

std::unique_ptr<security::access_controller> _access_controller;
};
typedef dsn::ref_ptr<replica> replica_ptr;
} // namespace replication
Expand Down
5 changes: 5 additions & 0 deletions src/replica/replica_2pc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "mutation_log.h"
#include "replica_stub.h"
#include "bulk_load/replica_bulk_loader.h"
#include "runtime/security/access_controller.h"
#include <dsn/utils/latency_tracer.h>
#include <dsn/dist/replication/replication_app_base.h>
#include <dsn/dist/fmt_logging.h>
Expand All @@ -40,6 +41,10 @@ void replica::on_client_write(dsn::message_ex *request, bool ignore_throttling)
{
_checker.only_one_thread_access();

if (!_access_controller->allowed(request)) {
response_client_read(request, ERR_ACL_DENY);
}

if (_deny_client_write) {
// Do not relay any message to the peer client to let it timeout, it's OK coz some users
// may retry immediately when they got a not success code which will make the server side
Expand Down
6 changes: 6 additions & 0 deletions src/runtime/security/access_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <dsn/utility/strings.h>
#include <dsn/utility/smart_pointers.h>
#include "meta_access_controller.h"
#include "replica_access_controller.h"

namespace dsn {
namespace security {
Expand All @@ -43,5 +44,10 @@ std::unique_ptr<access_controller> create_meta_access_controller()
{
return make_unique<meta_access_controller>();
}

std::unique_ptr<access_controller> create_replica_access_controller(const std::string &name)
{
return make_unique<replica_access_controller>(name);
}
} // namespace security
} // namespace dsn
2 changes: 2 additions & 0 deletions src/runtime/security/access_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,7 @@ class access_controller
};

std::unique_ptr<access_controller> create_meta_access_controller();

std::unique_ptr<access_controller> create_replica_access_controller(const std::string &name);
} // namespace security
} // namespace dsn
45 changes: 45 additions & 0 deletions src/runtime/security/replica_access_controller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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 "replica_access_controller.h"

#include <dsn/tool-api/rpc_message.h>
#include <dsn/dist/fmt_logging.h>
#include <dsn/tool-api/network.h>

namespace dsn {
namespace security {
replica_access_controller::replica_access_controller(const std::string &name) { _name = name; }

bool replica_access_controller::allowed(message_ex *msg)
{
const std::string &user_name = msg->io_session->get_client_username();
if (pre_check(user_name)) {
return true;
}

{
utils::auto_read_lock l(_lock);
if (_users.find(user_name) == _users.end()) {
ddebug_f("{}: user_name {} doesn't exist in acls map", _name, user_name);
return false;
}
return true;
}
}
} // namespace security
} // namespace dsn
40 changes: 40 additions & 0 deletions src/runtime/security/replica_access_controller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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/synchronize.h>
#include "access_controller.h"

namespace dsn {
namespace security {
class replica_access_controller : public access_controller
{
public:
replica_access_controller(const std::string &name);
bool allowed(message_ex *msg);

private:
utils::rw_lock_nr _lock; // [
std::unordered_set<std::string> _users;
// ]
std::string _name;

friend class replica_access_controller_test;
};
} // namespace security
} // namespace dsn
76 changes: 76 additions & 0 deletions src/runtime/test/replica_access_controller_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// 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 <gtest/gtest.h>
#include <dsn/utility/flags.h>
#include <dsn/dist/replication.h>
#include "runtime/security/replica_access_controller.h"
#include "runtime/rpc/network.sim.h"

namespace dsn {
namespace security {
DSN_DECLARE_bool(enable_acl);

class replica_access_controller_test : public testing::Test
{
public:
replica_access_controller_test()
{
_replica_access_controller = make_unique<replica_access_controller>("test");
}

bool allowed(dsn::message_ex *msg) { return _replica_access_controller->allowed(msg); }

void set_replica_users(std::unordered_set<std::string> &&replica_users)
{
_replica_access_controller->_users.swap(replica_users);
}

std::unique_ptr<replica_access_controller> _replica_access_controller;
};

TEST_F(replica_access_controller_test, allowed)
{
struct
{
std::unordered_set<std::string> replica_users;
std::string client_user;
bool result;
} tests[] = {{{"replica_user1", "replica_user2"}, "replica_user1", true},
{{"replica_user1", "replica_user2"}, "not_replica_user", false},
{{}, "user_name", false}};

bool origin_enable_acl = FLAGS_enable_acl;
FLAGS_enable_acl = true;

std::unique_ptr<tools::sim_network_provider> sim_net(
new tools::sim_network_provider(nullptr, nullptr));
auto sim_session = sim_net->create_client_session(rpc_address("localhost", 10086));
dsn::message_ptr msg = message_ex::create_request(RPC_CM_LIST_APPS);
msg->io_session = sim_session;

for (auto &test : tests) {
set_replica_users(std::move(test.replica_users));
sim_session->set_client_username(test.client_user);

ASSERT_EQ(allowed(msg), test.result);
}

FLAGS_enable_acl = origin_enable_acl;
}
} // namespace security
} // namespace dsn

0 comments on commit dfa58fd

Please sign in to comment.