Crate bonsaidb::core::actionable
Expand description
Actionable provides the basic functionality needed to build an async-based API that has a flexible permissions system integrated.
This crate was designed to be used by BonsaiDb
internally, and as a way for users of BonsaiDb
to extend their database
servers with their own APIs.
Permissions
The Permissions
struct is constructed from a list of Statement
s. The
Statement
struct is inspired by statements in
IAM.
By default, all actions are denied for all resources.
The ResourceName
struct describes a unique name/id of anything in your
application. This is meant to be similar to ARNs in
IAM,
but instead of being restricted to a format by this library, you are able to
define your own syntax.
The Action
trait is derive-able, and will convert any enum to something
that can be permitted or denied to any ResourceName
. This derive macro
only supports enums with variants that have no parameters, or only have a
single name-less parameter that also implements Action
.
An example Action
enum might look like:
#[derive(Action, Debug)]
pub enum AllActions {
FlushCache,
User(UserActions),
}
#[derive(Action, Debug)]
pub enum UserActions {
Create,
ChangeUsername,
Delete,
}
An example permissions check for users.42
might look like:
let allowed = permissions.allowed_to(
&ResourceName::named("users").and(42),
&AllActions::User(UserActions::Delete),
);
Configuration
Along with allowing actions to be taken, Actionable can be used to configure values that may change on a per-role basis. Rate limits are an example of what this API is designed to handle:
let permissions = Permissions::from(Statement::for_any().with("rate-limit", 500_u64));
let effective_rate_limit = permissions
.get(&ResourceName::named("core-api"), "rate-limit")
.and_then(Configuration::to_unsigned);
assert_eq!(effective_rate_limit, Some(500));
Permission-driven async API
At the core of many networked APIs written in Rust is an enum that represents a request, and similarly there are usually common response/error types. In these applications, there is usually a manually-written match statement that, for readability and maintainability, simply pass the parameters from the request to a helper method to handle the actual logic of the request.
The goal of the API portion of this crate is to replace the aforementioned
boilerplate match statement with a simple derive macro. For a commented
example, check out
actionable/examples/api-simulator.rs
.
Structs
- A unique name of an action.
- An
action
was denied. - A collection of allowed permissions. This is constructed from a
Vec<
Statement
>
. By default, no actions are allowed on any resources. - A unique name/identifier of a resource.
- A statement of permissions. A statement describes whether one or more
actions
should beallowed
to be taken againstresources
.
Enums
- A list of
ActionName
s. - A configured value for a resource.
- A single element of a
ResourceName
Traits
- An action that can be allowed or disallowed.
- Dispatches
T
to an appropriate handler. This trait is derivable.
Attribute Macros
Derive Macros
- Derives the
actionable::Action
trait. - Derives a set of traits that can be used to implement a permissions-driven API. There are options that can be customized with the
#[actionable]
attribute at the enum level: - Derives the
Dispatcher
trait.