Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/vadim-kovalyov/allow-me
An authorization library with json-based policy definition.
https://github.com/vadim-kovalyov/allow-me
Last synced: 27 days ago
JSON representation
An authorization library with json-based policy definition.
- Host: GitHub
- URL: https://github.com/vadim-kovalyov/allow-me
- Owner: vadim-kovalyov
- License: mit
- Created: 2020-07-30T20:39:02.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2021-01-08T02:17:13.000Z (almost 4 years ago)
- Last Synced: 2024-10-06T20:14:26.624Z (about 1 month ago)
- Language: Rust
- Homepage:
- Size: 68.4 KB
- Stars: 11
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Allow-me
[![Crates.io](https://img.shields.io/crates/v/allow-me.svg)](https://crates.io/crates/allow-me)
[![Docs.rs](https://docs.rs/allow-me/badge.svg)](https://docs.rs/allow-me)
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/vadim-kovalyov/allow-me/master/LICENSE)
![CI](https://github.com/vadim-kovalyov/allow-me/workflows/CI/badge.svg)An authorization library with json-based policy definition.
Define your authorization rules in a simple `Identity` (I), `Operation` (O), `Resource` (R) model. Evaluate requests against your policy rules.
# Getting Started
```toml
[dependencies]
allow-me = "0.1"
```
# Example Usage
## Json definition
A simple example for a policy with one statement and a request evaluated against that policy.
```rust
let json = r#"{
"statements": [
{
"effect": "allow",
"identities": [
"actor_a"
],
"operations": [
"write"
],
"resources": [
"resource_1"
]
}
]
}"#;// Construct the policy.
let policy = PolicyBuilder::from_json(json).build()?;// Prepare request (e.g. from user input).
let request = Request::new("actor_a", "write", "resource_1")?;// Evaluate the request.
match policy.evaluate(&request)? {
Decision::Allowed => println!("Allowed"),
Decision::Denied => {
panic!("Denied!")
}
};
```
### Try it
```
cargo run --example json
```## Variable rules
The following example shows a rule that allows any identity to read/write to it's own resource.
```rust
let json = r#"{
"statements": [
{
"effect": "allow",
"identities": [
"{{any}}"
],
"operations": [
"read",
"write"
],
"resources": [
"/home/{{identity}}/"
]
}
]
}"#;// Construct the policy.
let policy = PolicyBuilder::from_json(json)
// use "starts with" matching for resources.
.with_matcher(matcher::StartsWith)
.with_default_decision(Decision::Denied)
.build()?;// Prepare request (e.g. from user input).
let request = Request::new("johndoe", "write", "/home/johndoe/my.resource")?;// Evaluate the request.
match policy.evaluate(&request)? {
Decision::Allowed => println!("Allowed"),
Decision::Denied => {
panic!("Denied!")
}
};```
### Try it
```
cargo run --example vars
```## Rules ordering
Order of rules matter. In case of conflicting rules, the first rule wins. In the example below, we allow `actor_a` write to `resource_1`, and deny write to anything else. Note that any other request will be allowed (default decision).
```rust
let json = r#"{
"statements": [
{
"effect": "allow",
"identities": [
"actor_a"
],
"operations": [
"write"
],
"resources": [
"resource_1"
]
},
{
"effect": "deny",
"identities": [
"actor_a"
],
"operations": [
"write"
],
"resources": [
"{{any}}"
]
}
]
}"#;// Construct the policy.
let policy = PolicyBuilder::from_json(json)
// default to Allow all requests.
.with_default_decision(Decision::Allowed)
.build()?;// Prepare request (e.g. from user input).
let request = Request::new("actor_a", "write", "resource_1")?;// Evaluate specific request.
match policy.evaluate(&request)? {
Decision::Allowed => println!("allowed write resource_1"),
Decision::Denied => {
panic!("Denied!")
}
};let request = Request::new("actor_a", "write", "some_other_resource")?;
// Everything else denies.
assert_matches!(policy.evaluate(&request), Ok(Decision::Denied));
```
### Try it
```
cargo run --example order
```# Customizations
There are several extension points in the library:
- `ResourceMatcher` trait - responsible for performing resource matching logic.
- `Substituter` trait - you can add custom variables that can be substituted.
- `Validator` trait - validates policy definition. If your need custom validation for policy rules.
- Request Context - you can have custom datatype associated with `Request`. Useful with custom `Substituter` or `ResourceMatcher` to implement custom variables or matching logic.## ResourceMatcher
Custom ResourceMatcher that implements "start with" matching.
```rust
pub struct StartsWith;impl ResourceMatcher for StartsWith {
type Context = ();fn do_match(&self, _context: &Request, input: &str, policy: &str) -> bool {
input.starts_with(policy)
}
}```
## Substituter and custom Request Context
Custom Substituter that supports `{{any}}` and `{{role}}` variables. `{{role}}` variable substituted with a value from a request context.
```rust
// custom context
struct MyContext {
role: String
};// custom substituter
struct RoleSubstituter;impl Substituter for RoleSubstituter {
type Context = MyContext;fn visit_resource(&self, value: &str, context: &Request) -> Result {
match context.context() {
Some(role_context) => {
let mut result = value.to_owned();
for variable in VariableIter::new(value) {
result = match variable {
"{{any}}" => replace(&result, variable, context.resource()),
"{{role}}" => replace(&result, variable, &role_context.role),
_ => result,
};
}
Ok(result)
}
None => Ok(value.to_owned()),
}
}...
}
```
### Try it
```
cargo run --example customizations
```# Roadmap
- [ ] Fluent API for PolicyBuilder
- [ ] Regex support
- [ ] Benches# Contribution
All contributions and comments are welcome! Don't be afraid to open an issue or PR whenever you find a bug or have an idea to improve this crate.