Files
scylladb/cql3/statements/authorization_statement.cc
Wojciech Mitros 6b8c1823a3 cql3: allow UDTs in permissions on UDFs
Currently, when preparing an authorization statement on a specific
function, we're trying to "prepare" all cql types that appear in
the function signature while parsing the statement. We cannot
do that for UDTs, because we don't know the UDTs that are present
in the databse at parsing time. As a result, such authorization
statements fail.
To work around this problem, we postpone the "preparation" of cql
types until the actual statement validation and execution time.
Until then, we store all type strings in the resource object.
The "preparation" happens in the `maybe_correct_resource` method,
which is called before every `execute` during a `check_access` call.
At that point, we have access to the `query_processor`, and as a
result, to `user_types_metadata` which allows us to prepare the
argument types even for UDTs.
2023-03-10 11:02:33 +01:00

84 lines
3.2 KiB
C++

/*
* Copyright 2016-present ScyllaDB
*
* Modified by ScyllaDB
*/
/*
* SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
*/
#include "authorization_statement.hh"
#include "transport/messages/result_message.hh"
#include "service/client_state.hh"
#include "auth/resource.hh"
#include "cql3/query_processor.hh"
#include "exceptions/exceptions.hh"
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include "cql3/util.hh"
#include "db/cql_type_parser.hh"
uint32_t cql3::statements::authorization_statement::get_bound_terms() const {
return 0;
}
bool cql3::statements::authorization_statement::depends_on(std::string_view ks_name, std::optional<std::string_view> cf_name) const {
return false;
}
void cql3::statements::authorization_statement::validate(
query_processor&,
const service::client_state& state) const {
}
future<> cql3::statements::authorization_statement::check_access(query_processor& qp, const service::client_state& state) const {
return make_ready_future<>();
}
void cql3::statements::authorization_statement::maybe_correct_resource(auth::resource& resource, const service::client_state& state, query_processor& qp) {
if (resource.kind() == auth::resource_kind::data) {
const auto data_view = auth::data_resource_view(resource);
const auto keyspace = data_view.keyspace();
const auto table = data_view.table();
if (table && keyspace->empty()) {
resource = auth::make_data_resource(state.get_keyspace(), *table);
}
} else if (resource.kind() == auth::resource_kind::functions) {
// Maybe correct the resource for a specific function.
const auto functions_view = auth::functions_resource_view(resource);
const auto keyspace = functions_view.keyspace();
if (!keyspace) {
// This is an "ALL FUNCTIONS" resource.
return;
}
if (!qp.db().has_keyspace(*keyspace)) {
throw exceptions::invalid_request_exception(format("{} doesn't exist.", resource));
}
if (functions_view.function_signature()) {
// The resource is already corrected.
return;
}
if (!functions_view.function_name()) {
// This is an "ALL FUNCTIONS IN KEYSPACE" resource.
return;
}
const auto& utm = qp.db().find_keyspace(*keyspace).user_types();
auto function_name = *functions_view.function_name();
auto function_args = functions_view.function_args();
std::vector<data_type> parsed_types;
if (function_args) {
parsed_types = boost::copy_range<std::vector<data_type>>(
*function_args | boost::adaptors::transformed([&] (std::string_view raw_type) {
auto parsed = db::cql_type_parser::parse(sstring(keyspace->data(), keyspace->size()), sstring(raw_type.data(), raw_type.size()), utm);
return parsed->is_user_type() ? parsed->freeze() : parsed;
})
);
}
resource = auth::make_functions_resource(*keyspace, auth::encode_signature(function_name, parsed_types));
}
}