Skip to content

Commit

Permalink
Merge branch 'main' of github.com:l-kli/cedar-local-agent
Browse files Browse the repository at this point in the history
  • Loading branch information
l-kli committed Nov 19, 2024
2 parents e709740 + 54a28e2 commit faead02
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 53 deletions.
3 changes: 2 additions & 1 deletion benches/data_gen/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ use rand::Rng;

/// Alphabet as an &str
pub const ALPHA: &str = "abcdefghijklmnopqrstuvwxyz";
#[allow(clippy::single_char_add_str)]
pub fn random_string(n: u32, charset: &str) -> String {
let mut rng = rand::thread_rng();

let mut res = "".to_string();
for _i in 0..n as usize {
let random_index: usize = rng.gen_range(0..charset.len());
res.push_str(&charset.chars().nth(random_index).unwrap().to_string());
res.push(&charset.chars().nth(random_index).unwrap());
}
res
}
2 changes: 1 addition & 1 deletion src/public/log/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub const DEFAULT_REQUESTER_NAME: &str = "cedar::simple::authorizer";
#[builder(setter(into))]
pub struct Config {
/// `format` is used to specify the log rotation format.
/// By default the log rotation format is OpenCyberSecurityFramework (OCSF).
/// By default the log rotation format is `OpenCyberSecurityFramework` (OCSF).
#[builder(default)]
pub format: Format,

Expand Down
34 changes: 17 additions & 17 deletions src/public/log/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ const VENDOR_NAME: &str = "cedar::simple::authorizer";
const SECRET_STRING: &str = "Sensitive<REDACTED>";

/// A basic Open Cyber Security Framework structure
///
/// Entity Management events report activity. The activity can be a
/// create, read, update, and delete operation on a managed entity.
///
/// <https://schema.ocsf.io/1.0.0/classes/entity_management?extensions=>
#[derive(Default, Builder, Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
#[builder(
Expand All @@ -53,7 +55,7 @@ pub struct OpenCyberSecurityFramework {
/// The category unique identifier of the event. The authorization log will always be 3
#[builder(default = "3u8")]
pub category_uid: u8,
/// The event class name, as defined by class_uid value: `Entity Management`
/// The event class name, as defined by `class_uid` value: `Entity Management`
#[builder(default = "Some(\"Entity Management\".to_string())")]
#[serde(skip_serializing_if = "Option::is_none")]
pub class_name: Option<String>,
Expand All @@ -69,7 +71,7 @@ pub struct OpenCyberSecurityFramework {
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<u64>,
/// The event duration or aggregate time, the amount of time the event covers from start_time to end_time in milliseconds
/// The event duration or aggregate time, the amount of time the event covers from `start_time` to `end_time` in milliseconds
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub duration: Option<i64>,
Expand Down Expand Up @@ -105,7 +107,7 @@ pub struct OpenCyberSecurityFramework {
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub raw_data: Option<String>,
/// The event severity, normalized to the caption of the severity_id value
/// The event severity, normalized to the caption of the `severity_id` value
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub severity: Option<String>,
Expand All @@ -115,7 +117,7 @@ pub struct OpenCyberSecurityFramework {
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<i64>,
/// The event status, normalized to the caption of the status_id value
/// The event status, normalized to the caption of the `status_id` value
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
Expand All @@ -137,9 +139,9 @@ pub struct OpenCyberSecurityFramework {
#[serde(skip_serializing_if = "Option::is_none")]
pub timezone_offset: Option<i32>,
/// The event type ID. It identifies the event's semantics and structure.
/// the value is calculated by the logging system as: class_uid * 100 + activity_id
/// the value is calculated by the logging system as: `class_uid` * 100 + `activity_id`
pub type_uid: TypeUid,
/// The event type name, as defined by the type_uid
/// The event type name, as defined by the `type_uid`
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub type_name: Option<String>,
Expand Down Expand Up @@ -548,9 +550,9 @@ pub enum ObservableTypeId {
IPAddress = 2,
/// Media Access Control (MAC) address. For example: 18:36:F3:98:4F:9A
MACAddress = 3,
/// User name. For example: john_doe
/// User name. For example: `john_doe`
UserName = 4,
/// Email address. For example: [email protected]
/// Email address. For example: `[email protected]`
EmailAddress = 5,
/// Uniform Resource Locator (URL) string
URLString = 6,
Expand All @@ -564,7 +566,7 @@ pub enum ObservableTypeId {
ResourceUID = 10,
/// Endpoints, whether physical or virtual, connect to and interact with computer networks.
/// Examples include mobile devices, computers, virtual machines, embedded devices, servers,
/// and IoT devices like cameras and smart speakers
/// and `IoT` devices like cameras and smart speakers
Endpoint = 20,
/// The User object describes the characteristics of a user/person or a security principal.
/// Defined by D3FEND [d3f:UserAccount](https://d3fend.mitre.org/dao/artifact/d3f:UserAccount/)
Expand Down Expand Up @@ -691,7 +693,7 @@ pub struct Reputation {
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub provider: Option<String>,
/// The reputation score, normalized to the caption of the score_id value. In the case of 'Other',
/// The reputation score, normalized to the caption of the `score_id` value. In the case of 'Other',
/// it is defined by the event source
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -835,6 +837,7 @@ pub struct Product {

/// Encompasses details related to the capabilities, components, user interface (UI) design,
/// and performance upgrades associated with the feature.
///
/// <https://schema.ocsf.io/1.0.0/objects/feature?extensions=>
#[derive(Default, Serialize, Deserialize, Builder, Eq, PartialEq, Debug, Clone)]
#[builder(setter(into))]
Expand Down Expand Up @@ -882,12 +885,12 @@ struct FilteredRequest {
/// authorization decision.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub(crate) enum EntityComponent {
/// A concrete EntityUID
/// A concrete `EntityUID`
Concrete(EntityUid),
/// An entity that is not specified / concrete.
Unspecified,
#[default]
/// No EntityUID because it was filtered out.
/// No `EntityUID` because it was filtered out.
None,
}

Expand Down Expand Up @@ -935,15 +938,12 @@ impl From<Option<EntityUid>> for EntityComponent {

#[cfg(test)]
mod test {
use core::num;
use std::collections::{HashMap, HashSet};
use std::str::FromStr;

use cedar_policy::{
AuthorizationError, Authorizer, Context, Entities, EntityId, EntityTypeName, EntityUid,
EvaluationError, PolicyId, PolicySet, Request, Response,
Context, Entities, EntityId, EntityTypeName, EntityUid, PolicyId, Request, Response,
};
use cedar_policy_core::ast::{PolicyID, RestrictedExpr, Value};
use cedar_policy_core::authorizer::Decision;
use serde_json::{from_str, to_string, to_value, Map};

Expand Down Expand Up @@ -1088,7 +1088,7 @@ mod test {
// }),
// })
// .collect();

println!("Number of errors needed: {}", { num_of_error });
// Uses a empty vector now instead of giving num_of_error errors. Tests have been changed to reflect this
// Leads to problems in test coverage
Response::new(decision, policy_ids, vec![])
Expand Down
72 changes: 38 additions & 34 deletions src/public/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use std::sync::Arc;

#[cfg(feature = "partial-eval")]
use cedar_policy::PartialResponse;
use cedar_policy::{Diagnostics, PartialResponse};
use cedar_policy::{Entities, Request, Response};
use derive_builder::Builder;
use thiserror::Error;
Expand Down Expand Up @@ -214,26 +214,31 @@ where
);
info!("Fetched Authorization data from Policy Set Provider and Entity Provider");

let concrete_response = partial_response.clone().concretize();

// Skip logging for now
info!("Generated OCSF log record.");
match &partial_response {
Concrete(response) => self.log(request, response, entities),
Residual(residual_response) => self.log_residual(request, residual_response, entities),
};
// match &partial_response {
// Concrete(response) => self.log(request, response, entities),
// Residual(residual_response) => self.log_residual(request, residual_response, entities),
// };
match partial_response.decision() {
Some(_) => self.log(request, &concrete_response, entities),
None => self.log_residual(
request,
concrete_response.diagnostics(),
&partial_response,
entities,
),
}

info!(
"Is_authorized_partial completed: response_decision={}",
match &partial_response {
Concrete(response) => format!("{:?}", response.decision()),
Residual(residual_response) => format!("{:?}", residual_response.residuals()),
}
"Is_authorized_partial completed: response_decision={:?}",
partial_response.decision()
);
debug!(
"This decision was reached because: response_diagnostics={:?}",
match &partial_response {
Concrete(response) => response.diagnostics(),
Residual(residual_response) => residual_response.diagnostics(),
}
partial_response.clone().concretize().diagnostics()
);

Ok(partial_response)
Expand All @@ -244,19 +249,24 @@ where
fn log_residual(
&self,
request: &Request,
residual_response: &ResidualResponse,
// residual_response: &ResidualResponse,
diagnostics: &Diagnostics,
policies: &PartialResponse,
entities: &Entities,
) {
event!(target: "cedar::simple::authorizer", Level::INFO, "{}",
serde_json::to_string(
&OpenCyberSecurityFramework::create_generic(
request,
residual_response.diagnostics(),
residual_response.residuals().policies()
//residual_response.diagnostics(),
diagnostics,
// residual_response.residuals().policies()
policies.all_residuals()
.map(|policy| format!("{}", policy.id()))
.collect::<Vec<String>>()
.join(", ")
.as_str(),

String::from("Residuals"),
entities,
&self.log_config.field_set,
Expand Down Expand Up @@ -423,7 +433,7 @@ mod test_partial {
use std::sync::Arc;

use async_trait::async_trait;
use cedar_policy::{Context, Entities, PartialResponse, Policy, PolicySet, Request};
use cedar_policy::{Context, Entities, Policy, PolicyId, PolicySet, Request};
use cedar_policy_core::authorizer::Decision;
use cool_asserts::assert_matches;

Expand All @@ -445,18 +455,16 @@ mod test_partial {
let result = authorizer
.is_authorized_partial(
&Request::builder()
.principal(Some(r#"User::"Mike""#.parse().unwrap()))
.action(Some(r#"Action::"View""#.parse().unwrap()))
.principal(r#"User::"Mike""#.parse().unwrap())
.action(r#"Action::"View""#.parse().unwrap())
.context(Context::empty())
.build(),
&Entities::empty(),
)
.await;

assert_matches!(result, Ok(partial_response) =>
assert_matches!(partial_response, PartialResponse::Concrete(response) =>
assert_eq!(response.decision(), Decision::Deny)
)
assert_eq!(partial_response.decision(), Some(Decision::Deny))
);
assert_eq!(authorizer.log_config.requester, DEFAULT_REQUESTER_NAME);
assert!(!authorizer.log_config.field_set.principal);
Expand All @@ -475,18 +483,16 @@ mod test_partial {
let result = authorizer
.is_authorized_partial(
&Request::builder()
.action(Some(r#"Action::"View""#.parse().unwrap()))
.resource(Some(r#"Box::"10""#.parse().unwrap()))
.action(r#"Action::"View""#.parse().unwrap())
.resource(r#"Box::"10""#.parse().unwrap())
.context(Context::empty())
.build(),
&Entities::empty(),
)
.await;

assert_matches!(result, Ok(partial_response) =>
assert_matches!(partial_response, PartialResponse::Concrete(response) =>
assert_eq!(response.decision(), Decision::Deny)
)
assert_eq!(partial_response.decision(), Some(Decision::Deny))
);
assert_eq!(authorizer.log_config.requester, DEFAULT_REQUESTER_NAME);
assert!(!authorizer.log_config.field_set.principal);
Expand All @@ -502,7 +508,7 @@ mod test_partial {
_: &Request,
) -> Result<Arc<PolicySet>, PolicySetProviderError> {
let policy = Policy::parse(
Some("test".into()),
Some(PolicyId::new("test")),
r#"permit(principal == User::"Mike", action, resource == Box::"10");"#,
)
.expect("Failed to parse");
Expand All @@ -526,18 +532,16 @@ mod test_partial {
let result = authorizer
.is_authorized_partial(
&Request::builder()
.action(Some(r#"Action::"View""#.parse().unwrap()))
.resource(Some(r#"Box::"10""#.parse().unwrap()))
.action(r#"Action::"View""#.parse().unwrap())
.resource(r#"Box::"10""#.parse().unwrap())
.context(Context::empty())
.build(),
&Entities::empty(),
)
.await;

assert_matches!(result, Ok(partial_response) =>
assert_matches!(partial_response, PartialResponse::Residual(residual_response) => {
assert_eq!(residual_response.residuals().policies().count(), 1);
})
assert_eq!(partial_response.all_residuals().count(), 1)
);
assert_eq!(authorizer.log_config.requester, DEFAULT_REQUESTER_NAME);
assert!(!authorizer.log_config.field_set.principal);
Expand Down

0 comments on commit faead02

Please sign in to comment.