Cedarling Rust Developer Guide#
Including in the project#
The Cedarling library is not yet uploaded to crates.io, so the only way to use it right now is by including it directly from the source in your project.
1. Clone the Jans repository
git clone https://github.com/JanssenProject/jans.git
cd jans/jans-cedarling/cedarling
2. Add to your Cargo.toml
[dependencies]
cedarling = { path = "path/to/jans/jans-cedarling/cedarling" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }
3. Alternative: Using Git Dependency
[dependencies]
cedarling = { git = "https://github.com/JanssenProject/jans", package = "cedarling" }
Building#
Building Cedarling#
To build an executable library for Cedarling, follow the instructions here.
Building Examples#
The Cedarling project includes several examples that demonstrate different use cases. Follow the steps below to build these examples.
Building Examples#
1. Clone the repository
git clone https://github.com/JanssenProject/jans.git
cd jans/jans-cedarling
2. Build the library
cargo build --release
3. Run tests
cargo test --workspace
4. Generate documentation
cargo doc -p cedarling --no-deps --open
5. Build examples
# Run JWT validation example
cargo run -p cedarling --example authorize_with_jwt_validation
# Run unsigned authorization example
cargo run -p cedarling --example authorize_unsigned
# Stdout logging
cargo run -p cedarling --example log_init -- stdout
# Memory logging with TTL
cargo run -p cedarling --example log_init -- memory 3600
# Disable logging
cargo run -p cedarling --example log_init -- off
# Lock Server Integration
cargo run -p cedarling --example lock_integration
Complete Example#
Here's a complete example showing initialization, authorization, and logging:
use cedarling::*;
use std::collections::{HashMap, HashSet};
use jsonwebtoken::Algorithm;
use serde_json::json;
static POLICY_STORE_YAML: &str = include_str!("../../test_files/policy-store_ok.yaml");
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize Cedarling
let cedarling = Cedarling::new(&BootstrapConfig {
application_name: "example_app".to_string(),
log_config: LogConfig {
log_type: LogTypeConfig::Memory(MemoryLogConfig {
log_ttl: 3600, // 1 hour
max_item_size: None,
max_items: None,
}),
log_level: LogLevel::INFO,
},
policy_store_config: PolicyStoreConfig {
source: PolicyStoreSource::Yaml(POLICY_STORE_YAML.to_string()),
},
jwt_config: JwtConfig {
jwks: None,
jwt_sig_validation: false,
jwt_status_validation: false,
signature_algorithms_supported: HashSet::new(),
}.allow_all_algorithms(),
authorization_config: AuthorizationConfig {
use_user_principal: true,
use_workload_principal: true,
principal_bool_operator: JsonRule::new(serde_json::json!(
{"===": [{"var": "Jans::User"}, "ALLOW"]}
)).unwrap(),
..Default::default()
},
entity_builder_config: EntityBuilderConfig::default()
.with_user()
.with_workload(),
lock_config: None,
}).await?;
// Perform unsigned authorization
let principals = vec![EntityData {
cedar_entity_mapping: CedarEntityMapping {
entity_type: "Jans::User".to_string(),
id: "test_user".to_string(),
},
attributes: HashMap::from_iter([
("roles".to_string(), json!(["admin"])),
("email".to_string(), json!("admin@example.com")),
]),
}];
let resource = EntityData {
cedar_entity_mapping: CedarEntityMapping {
entity_type: "Jans::Application".to_string(),
id: "admin_panel".to_string(),
},
attributes: HashMap::from_iter([
("permission_level".to_string(), json!("admin")),
]),
};
let request = RequestUnsigned {
principals,
action: r#"Jans::Action::"Read""#.to_string(),
resource,
context: json!({}),
};
let result = cedarling.authorize_unsigned(request).await?;
println!("Authorization result: {}", result.decision);
// Retrieve logs
let logs = cedarling.pop_logs();
println!("Retrieved {} log entries", logs.len());
Ok(())
}
API Reference#
Core Types#
-
Cedarling
The main struct for interacting with Cedarling.
pub struct Cedarling { // Implementation details }
BootstrapConfig
#
Configuration for initializing Cedarling.
pub struct BootstrapConfig {
pub application_name: String,
pub log_config: LogConfig,
pub policy_store_config: PolicyStoreConfig,
pub jwt_config: JwtConfig,
pub authorization_config: AuthorizationConfig,
pub entity_builder_config: EntityBuilderConfig,
pub lock_config: Option<LockConfig>,
}
Request
#
Token-based authorization request.
pub struct Request {
pub tokens: HashMap<String, String>,
pub action: String,
pub resource: EntityData,
pub context: serde_json::Value,
}
RequestUnsigned
#
Unsigned authorization request.
pub struct RequestUnsigned {
pub principals: Vec<EntityData>,
pub action: String,
pub resource: EntityData,
pub context: serde_json::Value,
}
EntityData
#
Represents an entity in the authorization system.
pub struct EntityData {
pub cedar_entity_mapping: CedarEntityMapping,
pub attributes: HashMap<String, serde_json::Value>,
}
CedarEntityMapping
#
Represents the entity type and id mapping.
pub struct CedarEntityMapping {
pub entity_type: String,
pub id: String,
}
Main Methods#
Cedarling::new()
#
Initialize a new Cedarling instance.
pub async fn new(config: &BootstrapConfig) -> Result<Self, CedarlingError>
authorize()
#
Perform token-based authorization.
pub async fn authorize(&self, request: Request) -> Result<AuthorizeResult, CedarlingError>
authorize_unsigned()
#
Perform unsigned authorization.
pub async fn authorize_unsigned(&self, request: RequestUnsigned) -> Result<AuthorizeResult, CedarlingError>
pop_logs()
#
Retrieve and clear all logs.
pub fn pop_logs(&self) -> Vec<LogEntry>
get_log_ids()
#
Get all available log IDs.
pub fn get_log_ids(&self) -> Vec<String>
get_log_by_id()
#
Get a specific log entry by ID.
pub fn get_log_by_id(&self, id: &str) -> Option<LogEntry>
Configuration#
Bootstrap Properties#
Cedarling can be configured using bootstrap properties. See the bootstrap properties documentation for complete configuration options.
Environment Variables#
You can also configure Cedarling using environment variables:
export CEDARLING_APPLICATION_NAME="my_app"
export CEDARLING_LOG_TYPE="stdout"
export CEDARLING_LOG_LEVEL="INFO"
export CEDARLING_POLICY_STORE_LOCAL_FN="/path/to/policy-store.yaml"
Configuration Loading#
use cedarling::*;
// Load from environment variables
let config = BootstrapConfig::from_env();
// Load from JSON string
let config = BootstrapConfig::from_json(json_string)?;
// Load from file
let config = BootstrapConfig::from_file("config.json")?;
Testing and Debugging#
Running Tests#
# Run all tests
cargo test --workspace
# Run specific test
cargo test -p cedarling test_name
# Run tests with output
cargo test -- --nocapture
Running Benchmarks#
# Run all benchmarks
cargo bench -p cedarling
# Run specific benchmark
cargo bench -p cedarling benchmark_name
Code Coverage#
# Install coverage tool
cargo install cargo-llvm-cov
# Generate coverage report
cargo llvm-cov --html --open
Profiling#
# Run profiling example
cargo run --example profiling
Debugging#
Enable debug logging:
let config = BootstrapConfig {
log_config: LogConfig {
log_level: LogLevel::DEBUG,
..Default::default()
},
// ... other config
};