This change appears quite large, but is logically fairly simple. Previously, the `auth` module was structured around global state in a number of ways: - There existed global instances for the authenticator and the authorizer, which were accessed pervasively throughout the system through `auth::authenticator::get()` and `auth::authorizer::get()`, respectively. These instances needed to be initialized before they could be used with `auth::authenticator::setup(sstring type_name)` and `auth::authorizer::setup(sstring type_name)`. - The implementation of the `auth::auth` functions and the authenticator and authorizer depended on resources accessed globally through `cql3::get_local_query_processor()` and `service::get_local_migration_manager()`. - CQL statements would check for access and manage users through static functions in `auth::auth`. These functions would access the global authenticator and authorizer instances and depended on the necessary systems being started before they were used. This change eliminates global state from all of these. The specific changes are: - Move out `allow_all_authenticator` and `allow_all_authorizer` into their own files so that they're constructed like any other authenticator or authorizer. - Delete `auth.hh` and `auth.cc`. Constants and helper functions useful for implementing functionality in the `auth` module have moved to `common.hh`. - Remove silent global dependency in `auth::authenticated_user::is_super()` on the auth* service in favour of a new function `auth::is_super_user()` with an explicit auth* service argument. - Remove global authenticator and authorizer instances, as well as the `setup()` functions. - Expose dependency on the auth* service in `auth::authorizer::authorize()` and `auth::authorizer::list()`, which is necessary to check for superuser status. - Add an explicit `service::migration_manager` argument to the authenticators and authorizers so they can announce metadata tables. - The permissions cache now requires an auth* service reference instead of just an authorizer since authorizing also requires this. - The permissions cache configuration can now easily be created from the DB configuration. - Move the static functions in `auth::auth` to the new `auth::service`. Where possible, previously static resources like the `delayed_tasks` are now members. - Validating `cql3::user_options` requires an authenticator, which was previously accessed globally. - Instances of the auth* service are accessed through `external` instances of `client_state` instead of globally. This includes several CQL statements including `alter_user_statement`, `create_user_statement`, `drop_user_statement`, `grant_statement`, `list_permissions_statement`, `permissions_altering_statement`, and `revoke_statement`. For `internal` `client_state`, this is `nullptr`. - Since the `cql_server` is responsible for instantiating connections and each connection gets a new `client_state`, the `cql_server` is instantiated with a reference to the auth* service. - Similarly, the Thrift server is now also instantiated with a reference to the auth* service. - Since the storage service is responsible for instantiating and starting the sharded servers, it is instantiated with the sharded auth* service which it threads through. All relevant factory functions have been updated. - The storage service is still responsible for starting the auth* service it has been provided, and shutting it down. - The `cql_test_env` is now instantiated with an instance of the auth* service, and can be accessed through a member function. - All unit tests have been updated and pass. Fixes #2929.
191 lines
6.5 KiB
C++
191 lines
6.5 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2016 ScyllaDB
|
|
*
|
|
* Modified by 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/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
#include <set>
|
|
#include <stdexcept>
|
|
#include <boost/any.hpp>
|
|
|
|
#include <seastar/core/sstring.hh>
|
|
#include <seastar/core/future.hh>
|
|
#include <seastar/core/shared_ptr.hh>
|
|
#include <seastar/core/enum.hh>
|
|
|
|
#include "bytes.hh"
|
|
#include "data_resource.hh"
|
|
#include "enum_set.hh"
|
|
#include "exceptions/exceptions.hh"
|
|
|
|
namespace db {
|
|
class config;
|
|
}
|
|
|
|
namespace auth {
|
|
|
|
class authenticated_user;
|
|
|
|
class authenticator {
|
|
public:
|
|
static const sstring USERNAME_KEY;
|
|
static const sstring PASSWORD_KEY;
|
|
|
|
/**
|
|
* Supported CREATE USER/ALTER USER options.
|
|
* Currently only PASSWORD is available.
|
|
*/
|
|
enum class option {
|
|
PASSWORD
|
|
};
|
|
|
|
static option string_to_option(const sstring&);
|
|
static sstring option_to_string(option);
|
|
|
|
using option_set = enum_set<super_enum<option, option::PASSWORD>>;
|
|
using option_map = std::unordered_map<option, boost::any, enum_hash<option>>;
|
|
using credentials_map = std::unordered_map<sstring, sstring>;
|
|
|
|
virtual ~authenticator()
|
|
{}
|
|
|
|
virtual future<> start() = 0;
|
|
|
|
virtual future<> stop() = 0;
|
|
|
|
virtual const sstring& qualified_java_name() const = 0;
|
|
|
|
/**
|
|
* Whether or not the authenticator requires explicit login.
|
|
* If false will instantiate user with AuthenticatedUser.ANONYMOUS_USER.
|
|
*/
|
|
virtual bool require_authentication() const = 0;
|
|
|
|
/**
|
|
* Set of options supported by CREATE USER and ALTER USER queries.
|
|
* Should never return null - always return an empty set instead.
|
|
*/
|
|
virtual option_set supported_options() const = 0;
|
|
|
|
/**
|
|
* Subset of supportedOptions that users are allowed to alter when performing ALTER USER [themselves].
|
|
* Should never return null - always return an empty set instead.
|
|
*/
|
|
virtual option_set alterable_options() const = 0;
|
|
|
|
/**
|
|
* Authenticates a user given a Map<String, String> of credentials.
|
|
* Should never return null - always throw AuthenticationException instead.
|
|
* Returning AuthenticatedUser.ANONYMOUS_USER is an option as well if authentication is not required.
|
|
*
|
|
* @throws authentication_exception if credentials don't match any known user.
|
|
*/
|
|
virtual future<::shared_ptr<authenticated_user>> authenticate(const credentials_map& credentials) const = 0;
|
|
|
|
/**
|
|
* Called during execution of CREATE USER query (also may be called on startup, see seedSuperuserOptions method).
|
|
* If authenticator is static then the body of the method should be left blank, but don't throw an exception.
|
|
* options are guaranteed to be a subset of supportedOptions().
|
|
*
|
|
* @param username Username of the user to create.
|
|
* @param options Options the user will be created with.
|
|
* @throws exceptions::request_validation_exception
|
|
* @throws exceptions::request_execution_exception
|
|
*/
|
|
virtual future<> create(sstring username, const option_map& options) = 0;
|
|
|
|
/**
|
|
* Called during execution of ALTER USER query.
|
|
* options are always guaranteed to be a subset of supportedOptions(). Furthermore, if the user performing the query
|
|
* is not a superuser and is altering himself, then options are guaranteed to be a subset of alterableOptions().
|
|
* Keep the body of the method blank if your implementation doesn't support any options.
|
|
*
|
|
* @param username Username of the user that will be altered.
|
|
* @param options Options to alter.
|
|
* @throws exceptions::request_validation_exception
|
|
* @throws exceptions::request_execution_exception
|
|
*/
|
|
virtual future<> alter(sstring username, const option_map& options) = 0;
|
|
|
|
|
|
/**
|
|
* Called during execution of DROP USER query.
|
|
*
|
|
* @param username Username of the user that will be dropped.
|
|
* @throws exceptions::request_validation_exception
|
|
* @throws exceptions::request_execution_exception
|
|
*/
|
|
virtual future<> drop(sstring username) = 0;
|
|
|
|
/**
|
|
* Set of resources that should be made inaccessible to users and only accessible internally.
|
|
*
|
|
* @return Keyspaces, column families that will be unmodifiable by users; other resources.
|
|
* @see resource_ids
|
|
*/
|
|
virtual const resource_ids& protected_resources() const = 0;
|
|
|
|
class sasl_challenge {
|
|
public:
|
|
virtual ~sasl_challenge() {}
|
|
virtual bytes evaluate_response(bytes_view client_response) = 0;
|
|
virtual bool is_complete() const = 0;
|
|
virtual future<::shared_ptr<authenticated_user>> get_authenticated_user() const = 0;
|
|
};
|
|
|
|
/**
|
|
* Provide a sasl_challenge to be used by the CQL binary protocol server. If
|
|
* the configured authenticator requires authentication but does not implement this
|
|
* interface we refuse to start the binary protocol server as it will have no way
|
|
* of authenticating clients.
|
|
* @return sasl_challenge implementation
|
|
*/
|
|
virtual ::shared_ptr<sasl_challenge> new_sasl_challenge() const = 0;
|
|
};
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, authenticator::option opt) {
|
|
return os << authenticator::option_to_string(opt);
|
|
}
|
|
|
|
}
|
|
|