Commit Graph

1217 Commits

Author SHA1 Message Date
Jesse Haber-Kucharsky
464f41d2bb cql: Eliminate uses of legacy username rule
All users of `username` are replaced with `userOrRoleName`, except in
USER-specific (legacy) statements: CREATE USER, ALTER USER, DROP USER.
2018-03-01 12:06:59 -05:00
Jesse Haber-Kucharsky
b84e22acdd cql: Elaborate error for quoted user names
Since quoted names are allowed for role names, we add a more descriptive
error message when a quoted name is (erroneously) used for a user name.

This behavior is consistent with Apache Cassandra.
2018-03-01 12:06:59 -05:00
Jesse Haber-Kucharsky
b5264d8bf7 cql: Allow role names to be string literals
This behavior matches that of Apache Cassandra. When a role name is
specified as a string literal (single quotes), the case is preserved.
2018-03-01 12:06:59 -05:00
Jesse Haber-Kucharsky
d7f2035dea cql: Make role syntax more consistent
This patch changes the syntax for CQL statements related to roles to
favor a form like

    CREATE ROLE sam WITH PASSWORD = 'shire' AND LOGIN = false;

instead of

    CREATE ROLE sam WITH PASSWORD 'shire' NOLOGIN;

This new syntax has the benefit of not imposing any ordering constraints
on the modifiers for roles and being consistent with other parts of the
CQL grammar. It is also consistent with syntax in Apache Cassandra.

The old USER-based statements (CREATE USER and ALTER USER) still have
the old forms for backwards compatibility.

A previous change modified the USER-related statements to allow for the
OPTIONS option. However, this was a mistake; only the PASSWORD option
should have been allowed. This patch also corrects this mistake.
2018-03-01 12:04:40 -05:00
Avi Kivity
d973445a94 Merge "sstable/schema extensions" from Calle
"
Adds extension points to schema/sstables to enable hooking in
stuff, like, say, something that modifies how sstable disk io
works. (Cough, cough, *encryption*)

Extensions are processed as property keywords in CQL. To add
an extension, a "module" must register it into the extensions
object on boot time. To avoid globals (and yet don't),
extensions are reachable from config (and thus from db).

Table/view tables already contain an extension element, so
we utilize this to persist config.

schema_tables tables/views from mutations now require a "context"
object (currently only extensions, but abstracted for easier
further changes.

Because of how schemas currently operate, there is a super
lame workaround to allow "schema_registry" access to config
and by extension extensions. DB, upon instansiation, calls
a thread local global "init" in schema_registry and registers
the config. It, in turn, can then call table_from_mutations
as required.

Includes the (modified) patch to encapsulate compression
into objects, mainly because it is nice to encapsulate, and
isolate a little.
"

* 'calle/extensions-v5' of github.com:scylladb/seastar-dev:
  extensions: Small unit test
  sstables: Process extensions on file open
  sstables::types: Add optional extensions attribute to scylla metadata
  sstables::disk_types: Add hash and comparator(sstring) to disk_string
  schema_tables: Load/save extensions table
  cql: Add schema extensions processing to properties
  schema_tables: Require context object in schema load path
  schema_tables: Add opaque context object
  config_file_impl: Remove ostream operators
  main/init: Formalize configurables + add extensions to init call
  db::config: Add extensions as a config sub-object
  db::extensions: Configuration object to store various extensions
  cql3::statements::property_definitions: Use std::variant instead of any
  sstables: Add extension type for wrapping file io
  schema: Add opaque type to represent extensions
  sstables::compress/compress: Make compression a virtual object
2018-02-26 17:15:29 +02:00
Jesse Haber-Kucharsky
2348c303df cql3: Remove some unimplemented warnings
While there are some small remaining features for roles, all the old
user-based statements still exist as they did before (except now they're
backed by roles) and should not log warnings.
2018-02-14 14:16:00 -05:00
Jesse Haber-Kucharsky
114cfd4e5a cql3: Prevent unhandled exception for anonymous user
Since `validate` is called after `check_access`, an anonymous user would
not get the expected error message about restrictions on anonymous
users.
2018-02-14 14:16:00 -05:00
Jesse Haber-Kucharsky
a83af20311 auth: Add alias for set of role names
This shortens some type names considerably.
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
89b5bf2d7a cql3: Fix life-time of user from client_state 2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
fbc97626c4 auth: Migrate legacy data on boot
This change allows for seamless migration of the legacy users metadata
to the new role-based metadata tables. This process is summarized in
`docs/migrating-from-users-to-roles.md`.

In general, if any nondefault metadata exists in the new tables, then
no migration happens. If, in this case, legacy metadata still exists
then a warning is written to the log.

If no nondefault metadata exists in the new tables and the legacy tables
exist, then each node will copy the data from the legacy tables to the
new tables, performing transformations as necessary. An informational
message is written to the log when the migration process starts, and
when the process ends. During the process of copying, data is
overwritten so that multiple nodes racing to migrate data do not
conflict.

Since Apache Cassandra's auth. schema uses the same table for managing
roles and authentication information, some useful functions in
`roles-metadata.hh` have been added to avoid code duplication.

Because a superuser should be able to drop the legacy users tables from
`system_auth` once the cluster has migrated to roles and is functioning
correctly, we remove the restriction on altering anything in the
"system_auth" keyspace. Individual tables in `system_auth` are still
protected later in the function.

When a cluster is upgrading from one that does not support roles to one
that does, some nodes will be running old code which accesses old
metadata and some will be running new code which access new metadata.

With the help of the gossiper `feature` mechanism, clients connecting to
upgraded nodes will be notified (through code in the relevant CQL
statements) that modifications are not allowed until the entire cluster
has upgraded.
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
f9f03bc2e1 cql3: Fix error handling for GRANT and REVOKE
This change gets rid of duplicated code for checking if the grantee or
revokee exist by moving this functionality to the auth. service.
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
c1a03dbf54 cql3: Rename variables to reflect roles 2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
5be16247cc auth: Decouple authorization and role management
auth: Decouple authorization and role management

Access control in Scylla consists of three main modules: authentication,
authorization, and role-management.

Each of these modules is intended to be interchangeable with alternative
implementations. The `auth::service` class composes these modules
together to perform all access-control functionality, including caching.

This architecture implies two main properties of the individual
access-control modules:

- Independence of modules. An implementation of authentication should
  have no dependence or knowledge of authorization or role-management,
  for example.

- Simplicity of implementing the interface. Functionality that is common
  to all implementations should not have to be duplicated in each
  implementation. The abstract interface for a module should capture
  only the differences between particular implementations.

Previously, the authorization interface depended on an instance of
`auth::service` for certain operations, since it required aggregation
over all the roles granted to a particular role or required checking if
a given role had superuser.

This change decouples authorization entirely from role-management: the
authorizer now manages only permissions granted directly to a role, and
not those inherited through other roles.

When a query needs to be authorized, `auth::service::get_permissions`
first uses the role manager to check if the role has superuser. Then, it
aggregates calls to `auth::authorizer::authorize` for each role granted
to the role (again, from the role-manager) to determine the sum-total
permission set. This information is cached for future queries.

This structure allows for easier error handling and
management (something I hope to improve in the future for both the
authorizer and authenticator interfaces), easier system testing, easier
implementation of the abstract interfaces, and clearer system
boundaries (so the code is easier to grok).

Some authorizers, like the "TransitionalAuthorizer", grant permissions
to anonymous users. Therefore, we could not unconditionally authorize an
empty permission set in `auth::service` for anonymous users. To account
for this, the interface of the authorizer has changed to accept an
optional name in `authorize`.

One additional notable change to the authorizer is the
`auth::authorizer::list`: previously, the filtering happened at the CQL
query layer and depended on the roles granted to the role in question.
I've changed the function to simply query for all roles and I do the
filtering in `auth::system` in-memory with the STL. This was necessary
to allow the authorizer to be decoupled from role-management. This
function is only called for LIST PERMISSIONS (so performance is not a
concern), and it significantly reduces demand on the implementation.

Finally, we unconditionally create a user in `cql_test_env` since
authorization requires its existence.
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
d0ddb354d0 cql: Also add username col. for LIST PERMISSIONS
the value for the `role` column is equal to the value for the `username`
column.

This change makes LIST PERMISSIONS backwards compatible with clients
that expect the `username` column to exist. This functionality also
exists in Apache Cassandra.
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
cccfe269cf cql3: Fix error handling in LIST PERMISSIONS
This patch replaces duplicated code for checking the existence of a user
with the same mechanism for doing so as elsewhere: by checking for
`auth::nonexistent_role` being thrown during the course of checking
access-control.

This patch also ensures that exceptions thrown while querying the list
of permissions on a resource get handled correctly.
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
13ba128967 auth: Change error messages to pass dtests
The fixed dtests which only failed due to differences in wording and
grammar for error messages are:

- altering_nonexistent_user_throws_exception_test
- cant_create_existing_user_test
- dropping_nonexistent_user_throws_exception_test
- users_cant_alter_their_superuser_status_test
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
f372bbb4bc cql3: Handle errors more precisely for roles
This patch ensures that all the CQL statements for managing roles
correctly catch exceptions in the underlying `role_manager` and re-throw
them as top-level exceptions (like "invalid request").

This patch also refines exception handling so that only the applicable
errors are explicitly caught. This should allow easier auditing in the
future and help to reveal faulty assumptions.
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
ce3be07556 auth: Move resource existence checks
Previously, a "data" auth. resource knew how to check it's own existence by
accessing a global variable.

This patch accomplishes two things: it adds existence checking to all
kinds of resources, and moves these checks outside of `auth::resource`
itself and into `auth::service` (so that global variables are no longer
accessed).
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
5f323a3530 cql3: Check only filtered permissions
When a user executes GRANT or REVOKE, Scylla ensures that they
themselves are granted the permissions they are changing.

The code previously checked a static list of permissions, which we could
have replaced with `auth::permissions::ALL`. Even better, we now expand
the set of filtered permissions into an iterable container.
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
7db675b298 cql3: Remove std::move on return value
This prevents guaranteed return-value optimization (RVO).
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
b1d9d0e4ff auth: Reorder authorizer args for consistency 2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
c1504cd4ff auth: Pass resource by const ref.
This has the dual benefit of not enforcing copying on implementations of
the abstract interface and also limiting unnecessary copies.

As usual with Seastar, we follow the convention that a reference
parameter to a function is assumed valid for the duration of the
`future` that is returned. `do_with` helps here.

By adding some constants for root resources, we can avoid using
`seastar::do_with` at some call-sites involving `resource` instances.
2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
7fd3539d94 cql3: Avoid redundant return when throwing 2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
81f38edc61 auth/service: Rename function for consistency 2018-02-14 14:15:59 -05:00
Jesse Haber-Kucharsky
a3eaf9e697 auth: Remove unused "performer" argument
This argument used to be used for access-control checks, but this has
all moved to the CQL layer.
2018-02-14 14:15:58 -05:00
Jesse Haber-Kucharsky
5fe464d999 auth/default_authorizer: Move access-checks to CQL
All authorization checking lives in the CQL layer. The individual
authenticator, authorizer, and role-manager enforce no access-checks.

It may be a good idea to move these checks a level downward in the
future for ease of testing, but for now we aim for consistency.
2018-02-14 14:15:58 -05:00
Jesse Haber-Kucharsky
4d2c4177df cql3/list_permissions_statement: Fix formatting
Something strange must have happened with somebody's editor.
2018-02-14 14:15:58 -05:00
Jesse Haber-Kucharsky
2dc9f00fe3 cql3: Use authenticated_user-specific overload
This prevents us from accidentally accessing a non-existent value.
2018-02-14 14:15:58 -05:00
Jesse Haber-Kucharsky
68ba6a481b auth: Add has_role helper 2018-02-14 14:15:58 -05:00
Jesse Haber-Kucharsky
a0f0e07554 auth: Check for unsupported authentication options
While it's undefined behavior to pass an unsupported option to a
specific authenticator directly, the `auth::service` layer will check
options and throw this exception. It is turned into a
`invalid_request_exception` by the CQL layer.
2018-02-14 14:15:58 -05:00
Jesse Haber-Kucharsky
e6363e15de auth/resource: Construct from ctor
The motivation behind this change is the idea that constructing a new
instance of an object is the job of the constructor.

One big benefit of this structure (with the addition of helpers for
convenience) is that calls for emplacing instances (like
`std::make_shared`, or `std::vector::emplace_back`) work without any
difficulty. This would not be true for static construction functions.
2018-02-14 14:15:58 -05:00
Jesse Haber-Kucharsky
12d6f5817d auth: Switch to std::optional
Now that Scylla is a C++17 application, we should no longer use
`std::experimental::optional` (which is a distinct type from
`std::optional`).
2018-02-14 14:15:58 -05:00
Jesse Haber-Kucharsky
de33124c39 Don't store authenticated_user in shared_ptr
All we require are value semantics.

`client_state` still stores `authenticated_user` in a `shared_ptr`, but
the behavior of that class is complex enough to warrant its own
discussion/design/refactor.
2018-02-14 14:15:58 -05:00
Jesse Haber-Kucharsky
e11de26d50 auth: Simplify authenticated_user interface
The most important change is replacing `auth::authenticated_user::name`
with a public `std::optional<sstring>` member. Anonymous users have no
name. This replaces the insecure and bug-prone special-string of
"anonymous" for anonymous users, which does unfortunate things with the
authorizer.

The new `auth::is_anonymous` function exists for convenience since
checking the absence of a `std::optional` value can be tedious.

When a caller really wants a name unconditionally, a new stream output
function is also available.
2018-02-14 14:15:58 -05:00
Jesse Haber-Kucharsky
f18dd25e7e cql3: Fix DROP ROLE IF EXISTS
Checking if the role to be dropped has superuser requires that the role
exists, which means `auth::nonexistent_role` was thrown even when IF
EXISTS was specified.
2018-02-14 14:15:57 -05:00
Jesse Haber-Kucharsky
741d215516 auth: Switch to roles from users
This is a large change, but it's a necessary evil.

This change brings us to a minimally-functional implementation of roles.
There are many additional changes that are necessary, including refined
grammar, bug fixes, code hygiene, and internal code structure changes.
In the interest of keeping this patch somewhat read-able, those changes
will come in subsequent patches. Until that time, roles are still marked
"unimplemented".

IMPORTANT: This code does not include any mechanism for transitioning a
cluster from user-based access-control to role-based access control. All
existing access-control metadata will be ignored (though not deleted).

Specific changes:

- All user-specific CQL statements now delegate to their roles
  equivalent. The statements are effectively the same, but CREATE USER
  will include LOGIN automatically. Also, LIST USERS only lists roles
  with LOGIN.

- A call to LIST PERMISSIONS will now also list permissions of roles
  that have been granted to the caller, in addition to permissions which
  have been granted directly.

- Much of the logic of creating, altering, and deleting roles has been
  moved to `auth::service`, since these operations require cooperation
  between the authenticator, authorizer, and role-manager.

- LIST USERS actually works as expected now (fixes #2968).
2018-02-14 14:15:57 -05:00
Jesse Haber-Kucharsky
41f893d676 Don't use "experimental" optional
We're in C++17 country now.
2018-02-14 14:15:57 -05:00
Jesse Haber-Kucharsky
8878ce456c cql3/statements: Use convenient type alias 2018-02-14 14:15:57 -05:00
Jesse Haber-Kucharsky
b3dc90d5d2 auth: Refactor authentication options
The set of allowed options is quite small, so we benefit from a static
representation (member variables) over a dynamic map.

We also logically move the "OPTIONS" option to the domain of the
authenticator (from user management), since this is where it is applied.

This refactor also aims to reduce compilation time by moving
`authentication_options` into its own header file.

While changes to `user_options` were necessary to accommodate the new
structure, that class will be deprecated shortly in the switch to roles.
Therefore, the changes are strictly temporary.
2018-02-14 14:15:57 -05:00
Duarte Nunes
6f7233fbaf cql3/statements/truncate_statement: Prevent MV from being truncated
To truncate an MV, one must truncate the base table.

Fixes #3188

Signed-off-by: Duarte Nunes <duarte@scylladb.com>
Message-Id: <20180209162720.32757-1-duarte@scylladb.com>
2018-02-13 11:37:27 +00:00
Duarte Nunes
ac6abf8021 Merge 'CQL clustering column secondary indexing support' from Pekka
"This patch series adds support for clustering column secondary indexing.

Fixes #2961

Tests: unit-tests (release)"

* 'penberg/cql-2i-clustering-key-indexing/v2' of github.com:penberg/scylla:
  tests/cql_query_test: Add indexed clustering key query test
  cql3: Fix clustering column secondary indexing
  cql3/statements: Add values() helper to restrictions
  cql3/restrictions: Fix multi_column_restriction::values()
  cql3/restrictions: Fix single_column_primary_key_restrictions::values()
2018-02-12 18:49:34 +00:00
Duarte Nunes
d757c87107 cql3/query_processor: Remove prepared statements upon dropping a view
Fixes #3198

Signed-off-by: Duarte Nunes <duarte@scylladb.com>
Message-Id: <20180209143652.31852-1-duarte@scylladb.com>
2018-02-09 16:30:28 +00:00
Paweł Dziepak
b635fec9bf cql3/select_statement: do not capture stack variables by reference
Default capture by reference considered harmful in async code.
2018-02-08 14:46:10 +00:00
Calle Wilund
dcc75263c6 cql: Add schema extensions processing to properties
Automatically accept registered schema extensions into the properties
set, and when building, generate the corresponding extension object into
the resulting schema.
2018-02-07 10:11:46 +00:00
Calle Wilund
3e8cfbf2a0 cql3::statements::property_definitions: Use std::variant instead of any
Formalizing what stuff we actually keep in the props. And c++17.
2018-02-07 10:11:46 +00:00
Pekka Enberg
0128f802ed cql3: Fix clustering column secondary indexing
Fix clustering column indexing by lifting the limitation of only
considering non-primary key restrictions in
select_statement::find_index_partition_ranges().
2018-02-06 16:57:27 +02:00
Pekka Enberg
1fdc13d230 cql3/statements: Add values() helper to restrictions
Add values() helper to restrictions class so that we can easily obtain
restriction values for all indexed restrictions.
2018-02-06 16:57:27 +02:00
Paweł Dziepak
c2a5fd520f cql3/role-management: avoid static local shared_ptr
Even if shared_ptr is const it doesn't mean that its internal state is
immutable and it still cannot be freely shared across shards.

Fixes assertion failure in build/debug/tests/cql_roles_query_test.

Message-Id: <20180201125221.30531-1-pdziepak@scylladb.com>
2018-02-01 16:28:36 +02:00
José Guilherme Vanz
380bc0aa0d Swap arguments order of mutation constructor
Swap arguments in the mutation constructor keeping the same standard
from the constructor variants. Refs #3084

Signed-off-by: José Guilherme Vanz <guilherme.sft@gmail.com>
Message-Id: <20180120000154.3823-1-guilherme.sft@gmail.com>
2018-01-21 12:58:42 +02:00
Pekka Enberg
fab73dbdc3 cql3/restrictions: Fix multi_column_restriction::values()
Fix multi_column_restriction::values() similar to
single_column_primary_key_restrictions::values().
2018-01-18 14:38:06 +02:00