There are additional validation steps that the server executes in addition to simply invoking the authenticator, so we adapt the tests to also perform that validation. We also eliminate lots of code duplication.
166 lines
6.1 KiB
C++
166 lines
6.1 KiB
C++
/*
|
|
* Copyright (C) 2016 ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* This file is part of Scylla.
|
|
*
|
|
* Scylla is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Scylla is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#include <boost/range/irange.hpp>
|
|
#include <boost/range/adaptors.hpp>
|
|
#include <boost/range/algorithm.hpp>
|
|
#include <boost/test/unit_test.hpp>
|
|
#include <stdint.h>
|
|
|
|
#include <seastar/core/future-util.hh>
|
|
#include <seastar/core/shared_ptr.hh>
|
|
#include <seastar/core/thread.hh>
|
|
|
|
#include <seastar/testing/test_case.hh>
|
|
#include "tests/cql_test_env.hh"
|
|
#include "tests/cql_assertions.hh"
|
|
|
|
#include "auth/allow_all_authenticator.hh"
|
|
#include "auth/authenticator.hh"
|
|
#include "auth/password_authenticator.hh"
|
|
#include "auth/service.hh"
|
|
#include "auth/authenticated_user.hh"
|
|
#include "auth/resource.hh"
|
|
|
|
#include "db/config.hh"
|
|
#include "cql3/query_processor.hh"
|
|
|
|
SEASTAR_TEST_CASE(test_default_authenticator) {
|
|
return do_with_cql_env([](cql_test_env& env) {
|
|
auto& a = env.local_auth_service().underlying_authenticator();
|
|
BOOST_REQUIRE_EQUAL(a.require_authentication(), false);
|
|
BOOST_REQUIRE_EQUAL(a.qualified_java_name(), auth::allow_all_authenticator_name());
|
|
return make_ready_future();
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_password_authenticator_attributes) {
|
|
db::config cfg;
|
|
cfg.authenticator(auth::password_authenticator_name());
|
|
|
|
return do_with_cql_env([](cql_test_env& env) {
|
|
auto& a = env.local_auth_service().underlying_authenticator();
|
|
BOOST_REQUIRE_EQUAL(a.require_authentication(), true);
|
|
BOOST_REQUIRE_EQUAL(a.qualified_java_name(), auth::password_authenticator_name());
|
|
return make_ready_future();
|
|
}, cfg);
|
|
}
|
|
|
|
static future<auth::authenticated_user>
|
|
authenticate(cql_test_env& env, std::string_view username, std::string_view password) {
|
|
auto& c = env.local_client_state();
|
|
auto& a = env.local_auth_service().underlying_authenticator();
|
|
|
|
return do_with(
|
|
auth::authenticator::credentials_map{
|
|
{auth::authenticator::USERNAME_KEY, sstring(username)},
|
|
{auth::authenticator::PASSWORD_KEY, sstring(password)}},
|
|
[&a, &c, username](const auto& credentials) {
|
|
return a.authenticate(credentials).then([&c, username](auth::authenticated_user u) {
|
|
c.set_login(::make_shared<auth::authenticated_user>(std::move(u)));
|
|
return c.check_user_exists().then([&c] { return *c.user(); });
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_password_authenticator_operations) {
|
|
db::config cfg;
|
|
cfg.authenticator(auth::password_authenticator_name());
|
|
|
|
/**
|
|
* Not using seastar::async due to apparent ASan bug.
|
|
* Enjoy the slightly less readable code.
|
|
*/
|
|
return do_with_cql_env([](cql_test_env& env) {
|
|
static const sstring username("fisk");
|
|
static const sstring password("notter");
|
|
|
|
using namespace auth;
|
|
|
|
auto& a = env.local_auth_service().underlying_authenticator();
|
|
|
|
// check non-existing user
|
|
return authenticate(env, username, password).then_wrapped([&a](future<auth::authenticated_user>&& f) {
|
|
try {
|
|
f.get();
|
|
BOOST_FAIL("should not reach");
|
|
} catch (exceptions::authentication_exception&) {
|
|
// ok
|
|
}
|
|
}).then([&env, &a] {
|
|
return do_with(role_config{}, authentication_options{}, [&env, &a](auto& config, auto& options) {
|
|
config.can_login = true;
|
|
options.password = password;
|
|
|
|
return auth::create_role(env.local_auth_service(), username, config, options).then([&env, &a] {
|
|
return authenticate(env, username, password).then([](auth::authenticated_user user) {
|
|
BOOST_REQUIRE_EQUAL(auth::is_anonymous(user), false);
|
|
BOOST_REQUIRE_EQUAL(*user.name, username);
|
|
});
|
|
});
|
|
});
|
|
}).then([&env, &a] {
|
|
// check wrong password
|
|
return authenticate(env, username, "hejkotte").then_wrapped([](future<auth::authenticated_user>&& f) {
|
|
try {
|
|
f.get();
|
|
BOOST_FAIL("should not reach");
|
|
} catch (exceptions::authentication_exception&) {
|
|
// ok
|
|
}
|
|
});
|
|
}).then([&a] {
|
|
// sasl
|
|
auto sasl = a.new_sasl_challenge();
|
|
|
|
BOOST_REQUIRE_EQUAL(sasl->is_complete(), false);
|
|
|
|
bytes b;
|
|
int8_t i = 0;
|
|
b.append(&i, 1);
|
|
b.insert(b.end(), username.begin(), username.end());
|
|
b.append(&i, 1);
|
|
b.insert(b.end(), password.begin(), password.end());
|
|
|
|
sasl->evaluate_response(b);
|
|
BOOST_REQUIRE_EQUAL(sasl->is_complete(), true);
|
|
|
|
return sasl->get_authenticated_user().then([](auth::authenticated_user user) {
|
|
BOOST_REQUIRE_EQUAL(auth::is_anonymous(user), false);
|
|
BOOST_REQUIRE_EQUAL(*user.name, username);
|
|
});
|
|
}).then([&env, &a] {
|
|
// check deleted user
|
|
return auth::drop_role(env.local_auth_service(), username).then([&env, &a] {
|
|
return authenticate(env, username, password).then_wrapped([](future<auth::authenticated_user>&& f) {
|
|
try {
|
|
f.get();
|
|
BOOST_FAIL("should not reach");
|
|
} catch (exceptions::authentication_exception&) {
|
|
// ok
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}, cfg);
|
|
}
|