AuthZ Client
The application, acting as a Policy Enforcement Point (PEP), enforces policies defined by the Policy Decision Point (PDP). The Permguard Go SDK facilitates communication with the Permguard PDP.
This communication occurs through the AuthZ Client, a component that provides a straightforward interface for interacting with the Permguard AuthZ Server.
The Basic Structure of an Authorization Request
A standard authorization request is composed of the following key elements:
let endpoint = AzEndpoint::new("http", 9094, "localhost");
let config = AzConfig::new().with_endpoint(Some(endpoint));
let client = AzClient::new(config);
let mut file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
file_path.push("./json/ok_onlyone.json");
if !file_path.exists() {
eprintln!("❌ Failed to load the JSON file");
return Err(Err(Box::new(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Failed to load the JSON file",
))));
}
let json_content = fs::read_to_string(&file_path).await;
let request: AzRequest = match serde_json::from_str(&json_content.unwrap()) {
Ok(req) => req,
Err(e) => {
eprintln!("❌ Failed to parse JSON: {}", e);
return Err(Err(Box::new(e) as Box<dyn std::error::Error>));
}
};
match client.check_auth(Some(request)).await {
Ok(response) => {
if response.decision {
println!("✅ Authorization Permitted");
} else {
println!("❌ Authorization Denied");
}
}
Err(e) => {
eprintln!("❌ Failed to check auth: {}", e);
return Err(Err(e.into()));
}
}Perform an Atomic Authorization Request
An atomic authorization request can be performed using the AuthZ Client by creating a new client instance and invoking the Check method.
let endpoint = AzEndpoint::new("http", 9094, "localhost");
let config = AzConfig::new().with_endpoint(Some(endpoint));
let client = AzClient::new(config);
let principal = PrincipalBuilder::new("amy.smith@acmecorp.com")
.with_source("keycloak")
.with_kind("user")
.build();
let entity = {
let mut map = HashMap::new();
map.insert("uid".to_string(), json!({
"type": "MagicFarmacia::Platform::BranchInfo",
"id": "subscription"
}));
map.insert("attrs".to_string(), json!({"active": true}));
map.insert("parents".to_string(), json!([]));
Some(map)
};
let entities = vec![entity];
let request = AzAtomicRequestBuilder::new(
189106194833,
"48335ae72b3b405eae9e4bd5b07732df",
"platform-creator",
"MagicFarmacia::Platform::Subscription",
"MagicFarmacia::Platform::Action::create",
)
.with_request_id("31243")
.with_principal(principal)
.with_subject_property("isSuperUser", Value::from(true))
.with_subject_kind("role-actor")
.with_subject_source("keycloak")
.with_resource_id("e3a786fd07e24bfa95ba4341d3695ae8")
.with_resource_property("isEnabled", json!(true))
.with_entities_map("cedar", entities)
.with_action_property("isEnabled", json!(true))
.with_context_property("isSubscriptionActive", json!(true))
.with_context_property("time", json!("2025-01-23T16:17:46+00:00"))
.build();
match client.check_auth(Some(request)).await {
Ok(response) => {
if response.decision {
println!("✅ Authorization Permitted");
} else {
println!("❌ Authorization Denied");
}
}
Err(e) => {
eprintln!("❌ Failed to check auth: {}", e);
return Err(Err(e.into()));
}
}Perform a Composed Authorization Request
To perform a composed authorization request using the AuthZ Client, you need to create a new client and call the Check method.
This type of request is designed for scenarios requiring greater control over the authorization request creation, as well as cases where multiple evaluations must be executed within a single request.
let endpoint = AzEndpoint::new("http", 9094, "localhost");
let config = AzConfig::new().with_endpoint(Some(endpoint));
let client = AzClient::new(config);
// Create the Principal
let principal = PrincipalBuilder::new("amy.smith@acmecorp.com")
.with_source("keycloak")
.with_kind("user")
.build();
// Create a new subject
let subject = SubjectBuilder::new("platform-creator")
.with_source("keycloak")
.with_kind("role-actor")
.with_property("isSuperUser", serde_json::json!(true))
.build();
// Create a new resource
let resource = ResourceBuilder::new("MagicFarmacia::Platform::Subscription")
.with_id("e3a786fd07e24bfa95ba4341d3695ae8")
.with_property("isEnabled", serde_json::json!(true))
.build();
// Create actions
let action_view = ActionBuilder::new("MagicFarmacia::Platform::Action::create")
.with_property("isEnabled", serde_json::json!(true))
.build();
let action_create = ActionBuilder::new("MagicFarmacia::Platform::Action::create")
.with_property("isEnabled", serde_json::json!(false))
.build();
// Create a new Context
let context = ContextBuilder::new()
.with_property("time", serde_json::json!("2025-01-23T16:17:46+00:00"))
.with_property("isSubscriptionActive", serde_json::json!(true))
.build();
// Create evaluations
let evaluation_view = EvaluationBuilder::new(Some(subject.clone()), Some(resource.clone()), Some(action_view.clone()))
.with_request_id("134")
.build();
let evaluation_create = EvaluationBuilder::new(Some(subject.clone()), Some(resource.clone()), Some(action_create.clone()))
.with_request_id("435")
.build();
// Create the entities
let mut entity = HashMap::new();
entity.insert(
"uid".to_string(),
serde_json::json!({
"type": "MagicFarmacia::Platform::BranchInfo",
"id": "subscription"
}),
);
entity.insert(
"attrs".to_string(),
serde_json::json!({
"active": true
}),
);
entity.insert("parents".to_string(), serde_json::json!([]));
let entities = vec![Some(entity)];
// Create a new authorization request
let request = AzRequestBuilder::new(189106194833, "48335ae72b3b405eae9e4bd5b07732df")
.with_request_id(Some("7567".to_string()))
.with_subject(Some(subject))
.with_principal(Some(principal))
.with_entities_map("cedar", entities)
.with_context(Some(context))
.with_evaluation(evaluation_view)
.with_evaluation(evaluation_create)
.build();
match client.check_auth(Some(request)).await {
Ok(response) => {
if response.decision {
println!("✅ Authorization Permitted");
} else {
println!("❌ Authorization Denied");
if let Some(ctx) = response.context {
if let Some(admin) = ctx.reason_admin {
println!("-> Reason Admin: {}", admin.message);
}
if let Some(user) = ctx.reason_user {
println!("-> Reason User: {}", user.message);
}
}
for eval in response.evaluations {
if eval.decision {
println!("-> ✅ Authorization Permitted");
}
if let Some(ctx) = eval.context {
if let Some(admin) = ctx.reason_admin {
println!("-> Reason Admin: {}", admin.message);
}
if let Some(user) = ctx.reason_user {
println!("-> Reason User: {}", user.message);
}
}
}
}
}
Err(e) => {
eprintln!("❌ Failed to check auth: {}", e);
return Err(Err(e.into()));
}
}