Skip to content

Commit

Permalink
chore(jans-cedarling): move cedarling from jans-lock to `jans-ced…
Browse files Browse the repository at this point in the history
…arling` top level

Squash all previous changes:

chore(jans-cedarling): refactor, improve organization of config entity imports
docs(jans-cedarling): add to README how to generate documentation
chore(jans-cedarling): rename unexported field in the writer
feat(jans-cedarling): add Authz to the Cedarling instance
feat(jans-cedarling): add Cedarling instance
docs(jans-cedarling): fix docstring
test(jans-cedarling): fix log/test, import LogWriter
docs(jans-cedarling): added to README information how to run unit tests
test(jans-cedarling): move unit test for LogStrategy to log/test module
docs(jans-cedarling): added to README information how to get code-coverage
test(jans-cedarling): add unit test for LogStrategy
test(jans-cedarling): add unit test for MemoryLogger
chore(jans-cedarling): make fields in AuthorizationLogInfo struct public
test(jans-cedarling): add unit test for StdOutLogger
docs(jans-cedarling): added README to log module
chore(jans-cedarling): add note about using uuids in different situation
docs(jans-cedarling): improved README, added not about `log_init.rs`  file. And information about each log type.
chore(jans-cedarling): fix clippy warnings about doc identation
chore(jans-cedarling): fix clippy warnings
docs(jans-cedarling): improved documentation in the log crate.
docs(jans-cedarling): add links to the bootstrap properties in the documentation
docs(jans-cedarling): improved documentation in the log crate. Made it public to see message from autogenerated documentation page
chore(jans-cedarling): remove unused imports
chore(jans-cedarling): add macros allow(dead_code) to the Authz struct
chore(jans-cedarling): refactor make StdOutLogger more simple
chore(jans-cedarling): refactor to use imported names for shorter match cases
feat(jans-cedarling): add example of run cedarling Authz and updated Readme
chore(jans-cedarling): refactor implementation  MemoryLogger method log
chore(jans-cedarling): rename method get_logs to get_log_ids according to last changes in the `Final Cedarling Log Design`
chore(jans-cedarling): change name on init Authz
chore(jans-cedarling): add derive Clone, Copy to the LogType and MemoryLogConfig
chore(jans-cedarling): added doc message to MemoryLogConfig
chore(jans-cedarling): add documentation notes for LogStrategy
chore(jans-cedarling): add copyright note
chore(jans-cedarling): add simple Authz with initialization logger service
chore(jans-cedarling): add init_logger function
chore(jans-cedarling): fix missed documentation
chore(jans-cedarling): initialize logger using configuration settings
chore(jans-cedarling): add configs for logger
chore(jans-cedarling): add LogStrategy to unify multiple implementations under a common API
chore(jans-cedarling): add MemoryLogger
chore(jans-cedarling): add MemoryLogger and implement  LogWriter trait
chore(jans-cedarling): make LogEntry properties public
chore(jans-cedarling): added to sparkv error text error message
chore(jans-cedarling): added сopyright note to sparkv
chore(jans-cedarling): added StdOutLogger
chore(jans-cedarling): added NopLogger, that do nothing.
chore(jans-cedarling): added log interfaces
chore(jans-cedarling): added log LogEntry struct and related to it.
feat(jans-cedarling): added fork of the SparKV as is

Signed-off-by: Oleh Bohzok <olehbozhok@gmail.com>
  • Loading branch information
olehbozhok committed Sep 23, 2024
1 parent 4dcd3a3 commit 55b33a2
Show file tree
Hide file tree
Showing 28 changed files with 1,803 additions and 1 deletion.
6 changes: 5 additions & 1 deletion jans-cedarling/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
[workspace]
resolver = "2"
members = ["cedarling"]
members = ["cedarling", "sparkv"]

[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
sparkv = { path = "sparkv" }


[profile.release]
Expand Down
88 changes: 88 additions & 0 deletions jans-cedarling/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Cedarling

The Cedarling is a performant local authorization service that runs the Rust Cedar Engine.
Cedar policies and schema are loaded at startup from a locally cached "Policy Store".
In simple terms, the Cedarling returns the answer: should the application allow this action on this resource given these JWT tokens.
Expand All @@ -7,10 +8,97 @@ For example, why display form fields that a user is not authorized to see?
The Cedarling is a more productive and flexible way to handle authorization.

## Rust Cedarling

Cedarling is written in the Rust programming language (folder `cedarling`). And you can import it into your project as a dependency.

## Cedarling bindings

We have support binding for this platforms:

- [ ] Python
- [ ] Wasm

## Examples of rust Cedarling

Rust examples of using Cedarling contains in the folder `cedarling/examples`.

### Example of initialization logger

File with example is `log_init.rs`.
We support 4 types of loggers according to the [bootstrap properties](https://github.com/JanssenProject/jans/wiki/Cedarling-Nativity-Plan#bootstrap-properties).

To run example you need execute next command according to the logger:

- `off` - This log type is do nothing. It means that all logs will be ignored.

```bash
cargo run -p cedarling --example log_init -- off
```

- `stdout`- This log type writes all logs to `stdout`. Without storing or additional handling log messages.
[Standart streams](https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html).

```bash
cargo run -p cedarling --example log_init -- stdout
```

- `memory` - This log type holds all logs in database (in memory) with eviction policy.

```bash
cargo run -p cedarling --example log_init -- memory 60
```

60 - ttl (time to live log entry) in seconds.
But actually the example execute very fast, so we no need to wait.

- `lock` - This log type will send logs to the server (corporate feature). (in development)

```bash
cargo run -p cedarling --example log_init -- lock
```

## Unit tests

To run all unit tests in the project you need execute next commands:

```bash
cargo test --workspace
```

## Code coverage

We use `cargo-llvm-cov` for code coverage.

To install run:

```bash
cargo install cargo-llvm-cov
```

Get coverage report in console with:

```bash
cargo llvm-cov
```

Get coverage report in html format with:

```bash
cargo llvm-cov --html --open
```

Getting coverage report in `lcov.info`:

```bash
cargo llvm-cov --workspace --lcov --output-path lcov.info
```

Using `lcov.info` you can configure your IDE to display line-by-line code coverage.

## Autogenerated docs

To generate autogenerated docs run:

```bash
cargo doc -p cedarling --no-deps --open
```
5 changes: 5 additions & 0 deletions jans-cedarling/cedarling/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ version = "0.1.0"
edition = "2021"

[dependencies]
serde = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
sparkv = { workspace = true }
uuid7 = { version = "1.1.0", features = ["serde", "uuid"] }
73 changes: 73 additions & 0 deletions jans-cedarling/cedarling/examples/log_init.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use cedarling::{
AuthzConfig, BootstrapConfig, Cedarling, LogConfig, LogStorage, LogType, MemoryLogConfig,
};
use std::env;

fn main() {
// Collect command-line arguments
let args: Vec<String> = env::args().collect();

// Ensure at least one argument is provided (the program name itself is the first argument)
if args.len() < 2 {
eprintln!("Usage: {} <log_type> [ttl in seconds]", args[0]);
eprintln!("<log_type> can be one of off,stdout,memory");
std::process::exit(1);
}

// Parse the log type from the first argument
let log_type_arg = &args[1];
let log_type = match log_type_arg.as_str() {
"off" => LogType::Off,
"stdout" => LogType::StdOut,
"lock" => LogType::Lock,
"memory" => extract_memory_config(args),
_ => {
eprintln!("Invalid log type, defaulting to StdOut.");
LogType::StdOut
},
};

println!("Authz initialized with log type: {:?}", log_type);

// Create the Authz instance with the selected log type
let authz = Cedarling::new(BootstrapConfig {
authz_config: AuthzConfig {
application_name: "test_app".to_string(),
},
log_config: LogConfig { log_type },
});

println!("Stage 1:");
let logs_ids = authz.get_log_ids();
println!(
"Show results of get_logs(): returns a list of all log ids: {:?}",
&logs_ids
);
println!("\n\n Stage 2:\nShow result of get_log_by_id for each key.");
for id in logs_ids {
let entry = authz
.get_log_by_id(&id)
.map(|v| serde_json::json!(v).to_string());
println!("\nkey:{}\nvalue:{:?}", id, entry);
}

println!("\n\n Stage 3:\nShow result of pop_logs");
for (i, entry) in authz.pop_logs().iter().enumerate() {
println!("entry n:{i}\nvalue: {}", serde_json::json!(entry))
}

println!("\n\n Stage 4:\nShow len of keys left using get_log_ids");
println!("Number of keys left: {:?}", authz.get_log_ids().len());
}

fn extract_memory_config(args: Vec<String>) -> LogType {
if args.len() < 3 {
eprintln!("Memory log type requires two additional arguments: ttl value in seconds");
std::process::exit(1);
}
// Parse additional arguments for MemoryLogConfig
let log_ttl: u64 = args[2]
.parse()
.expect("Invalid ttl value, should be integer");
LogType::Memory(MemoryLogConfig { log_ttl })
}
35 changes: 35 additions & 0 deletions jans-cedarling/cedarling/src/authz/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,38 @@
//! Part of Cedarling that main purpose is:
//! - evaluate if authorization is granted for *user*
//! - evaluate if authorization is granted for *client*
use crate::log::{LogWriter, Logger};
use crate::models::authz_config::AuthzConfig;
use crate::models::log_entry::{LogEntry, LogType};
use uuid7::{uuid4, Uuid};

/// Authorization Service
/// The primary service of the Cedarling application responsible for evaluating authorization requests.
/// It leverages other services as needed to complete its evaluations.
#[allow(dead_code)]
pub struct Authz {
log_service: Logger,
pdp_id: Uuid,
application_name: String,
}

impl Authz {
/// Create a new Authorization Service
pub fn new(config: AuthzConfig, log: Logger) -> Self {
// we use uuid v4 because it is generated based on random numbers.
let pdp_id = uuid4();
let application_name = config.application_name;

log.log(
LogEntry::new_with_data(pdp_id, application_name.clone(), LogType::System)
.set_message("Cedarling Authz initialized successfully".to_string()),
);

Self {
log_service: log,
pdp_id,
application_name,
}
}
}
44 changes: 44 additions & 0 deletions jans-cedarling/cedarling/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,47 @@ mod models;
#[doc(hidden)]
#[cfg(test)]
mod tests;

use std::rc::Rc;

use authz::Authz;
use log::init_logger;
pub use log::LogStorage;
pub use models::config::*;

/// The instance of the Cedarling application.
#[derive(Clone)]
pub struct Cedarling {
log: log::Logger,
#[allow(dead_code)]
authz: Rc<Authz>,
}

impl Cedarling {
/// Create a new instance of the Cedarling application.
pub fn new(config: BootstrapConfig) -> Cedarling {
let log = init_logger(config.log_config);
let authz = Authz::new(config.authz_config, log.clone());

Cedarling {
log,
authz: Rc::new(authz),
}
}
}

// implements LogStorage for Cedarling
// we can use this methods outside crate only when import trait
impl LogStorage for Cedarling {
fn pop_logs(&self) -> Vec<models::log_entry::LogEntry> {
self.log.pop_logs()
}

fn get_log_by_id(&self, id: &str) -> Option<models::log_entry::LogEntry> {
self.log.get_log_by_id(id)
}

fn get_log_ids(&self) -> Vec<String> {
self.log.get_log_ids()
}
}
48 changes: 48 additions & 0 deletions jans-cedarling/cedarling/src/log/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Log Engine

Log Engine is responsible for log all authz and init events.

## Cedarling log types

In Cedarling framework [Bootstrap properties](https://github.com/JanssenProject/jans/wiki/Cedarling-Nativity-Plan#bootstrap-properties), a configuration property called`CEDARLING_LOG_TYPE` can take on one of the following values::

* off
* memory
* std_out
* lock

### Log type `off`

This log type is do nothing. It means that all logs will be ignored.

#### Log type `memory`

This log type stores all logs in memory with a time-to-live (TTL) eviction policy.

`CEDARLING_LOG_TTL` - variable determines how long logs are stored in memory, measured in seconds.

### Log type `std_out`

This log type writes all logs to `stdout`. Without storing or additional handling log messages.
[Standart streams](https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html).

### Log type `lock`

This log type is send logs to the server (corporate feature). Will be discussed later.

## Log Strategy

We use `LogStrategy` logger to implement all types of logger under one interface.
On creating (method new()) it consumes the `LogConfig` with all information about log type and it configuration. And this **factory** method

## Interfaces

Currently we have 2 interfaces (traits):

* `LogWriter` (not public) it is used to write logs.

All log implementations should implement this.

* `LogStorage` are used to gettting logs from storage.

Currently only `MemoryLogger` implement it.
31 changes: 31 additions & 0 deletions jans-cedarling/cedarling/src/log/interface.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* This software is available under the Apache-2.0 license.
* See https://www.apache.org/licenses/LICENSE-2.0.txt for full text.
*
* Copyright (c) 2024, Gluu, Inc.
*/

//! Log interface
//! Contains the interface for logging. And getting log information from storage.
use crate::models::log_entry::LogEntry;

/// Log Writer
/// interface for logging events
pub(crate) trait LogWriter {
/// log logging entry
fn log(&self, entry: LogEntry);
}

/// Log Storage
/// interface for getting log entries from the storage
pub trait LogStorage {
/// return logs and remove them from the storage
fn pop_logs(&self) -> Vec<LogEntry>;

/// get specific log entry
fn get_log_by_id(&self, id: &str) -> Option<LogEntry>;

/// returns a list of all log ids
fn get_log_ids(&self) -> Vec<String>;
}
Loading

0 comments on commit 55b33a2

Please sign in to comment.