Skip to content

Commit

Permalink
feat(jans-cedarling): add building types from other namespace if defi…
Browse files Browse the repository at this point in the history
…ned.
  • Loading branch information
olehbozhok committed Feb 7, 2025
1 parent f082fec commit 2a84175
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 101 deletions.
2 changes: 1 addition & 1 deletion jans-cedarling/cedarling/src/authz/build_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ fn build_entity_refs_from_attr(
Attribute::Entity { name, .. } => map_entity_id(namespace, name, type_ids),
Attribute::EntityOrCommon { name, .. } => {
if let Some((type_name, _type_schema)) = schema
.get_entity_schema(name)
.get_entity_schema(name, Some(namespace))
.map_err(|e| BuildContextError::ParseEntityName(name.to_string(), e))?
{
if namespace == type_name.namespace() {
Expand Down
26 changes: 18 additions & 8 deletions jans-cedarling/cedarling/src/authz/entity_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,19 @@ fn build_entity(

// Get entity namespace and type
let (entity_type_name, type_schema) = schema
.get_entity_schema(entity_name)?
.get_entity_schema(entity_name, None)?
.ok_or(BuildEntityError::EntityNotInSchema(entity_name.to_string()))?;
let default_namespace = entity_type_name.namespace();

// Build entity attributes
let entity_attrs =
build_entity_attrs_from_tkn(schema, type_schema, token, claim_aliases, built_entities)?;
let entity_attrs = build_entity_attrs_from_tkn(
schema,
type_schema,
token,
Some(default_namespace.as_str()),
claim_aliases,
built_entities,
)?;

// Build cedar entity
let entity_id = EntityId::from_str(&entity_id).map_err(BuildEntityError::ParseEntityId)?;
Expand Down Expand Up @@ -328,8 +335,8 @@ mod test {
"attributes": {
"access_token": { "type": "Entity", "name": "Access_token" },
"id_token": { "type": "Entity", "name": "Id_token" },
"userinfo_token": { "type": "Entity", "name": "Userinfo_token" },
"custom_token": { "type": "Entity", "name": "Custom_token" },
"userinfo_token": { "type": "Entity", "name": "Custom::Userinfo_token" },
"custom_token": { "type": "Entity", "name": "Custom::Custom_token" },
},
}
}
Expand All @@ -348,13 +355,16 @@ mod test {
schema,
EntityNames {
tokens: HashMap::from([
("access_token".to_string(), "Access_token".to_string()),
("access_token".to_string(), "Jans::Access_token".to_string()),
("id_token".to_string(), "Jans::Id_token".to_string()),
(
"userinfo_token".to_string(),
"Custom::Userinfo_token".to_string(),
),
("custom_token".to_string(), "Custom_token".to_string()),
(
"custom_token".to_string(),
"Custom::Custom_token".to_string(),
),
]),
..Default::default()
},
Expand Down Expand Up @@ -382,7 +392,7 @@ mod test {

let entities = entity_builder
.build_entities(&tokens, &ResourceData {
resource_type: "Resource".to_string(),
resource_type: "Jans::Resource".to_string(),
id: "res-123".to_string(),
payload: HashMap::new(),
})
Expand Down
33 changes: 19 additions & 14 deletions jans-cedarling/cedarling/src/authz/entity_builder/build_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub fn build_entity_attrs_from_tkn(
schema: &CedarSchemaJson,
entity_type: &EntityType,
token: &Token,
default_namespace: Option<&str>,
claim_aliases: Vec<ClaimAliasMap>,
built_entities: &BuiltEntities,
) -> Result<HashMap<String, RestrictedExpression>, BuildAttrError> {
Expand All @@ -39,10 +40,16 @@ pub fn build_entity_attrs_from_tkn(
)
})?;
let mapped_claim = mapping.apply_mapping(claim);
attr.build_expr(&mapped_claim, attr_name, schema, built_entities)
.map_err(|e| BuildAttrError::new(attr_name, e.into()))?
attr.build_expr(
&mapped_claim,
attr_name,
default_namespace,
schema,
built_entities,
)
.map_err(|e| BuildAttrError::new(attr_name, e.into()))?
} else {
match attr.build_expr(&claims, attr_name, schema, built_entities) {
match attr.build_expr(&claims, attr_name, default_namespace, schema, built_entities) {
Ok(expr) => expr,
Err(err) if attr.is_required() => Err(BuildAttrError::new(attr_name, err.into()))?,
// just skip when attribute isn't required even if it errors
Expand All @@ -61,6 +68,7 @@ pub fn build_entity_attrs_from_tkn(

pub fn build_entity_attrs_from_values(
schema: &CedarSchemaJson,
default_namespace: Option<&str>,
entity_type: &EntityType,
src: &HashMap<String, Value>,
) -> Result<HashMap<String, RestrictedExpression>, BuildAttrError> {
Expand Down Expand Up @@ -90,7 +98,7 @@ pub fn build_entity_attrs_from_values(
src
};

let expression = match attr.build_expr(src, attr_name, schema, &BuiltEntities::default()) {
let expression = match attr.build_expr(src, attr_name, default_namespace, schema, &BuiltEntities::default()) {
Ok(expr) => expr,
Err(err) if attr.is_required() => {
return Err(BuildAttrError::new(attr_name, err.into()))?;
Expand Down Expand Up @@ -185,17 +193,15 @@ mod test {
let iss = TrustedIssuer::default();
let token = Token::new(
"access_token",
HashMap::from([(
"client_id".to_string(),
json!("workload-123"),
)]).into(),
HashMap::from([("client_id".to_string(), json!("workload-123"))]).into(),
Some(&iss),
);

let attrs = build_entity_attrs_from_tkn(
&schema,
&entity_type,
&token,
None,
Vec::new(),
&BuiltEntities::default(),
)
Expand Down Expand Up @@ -236,6 +242,7 @@ mod test {
&schema,
&entity_type,
&token,
None,
Vec::new(),
&BuiltEntities::default(),
)
Expand Down Expand Up @@ -277,9 +284,8 @@ mod test {
};
let src_values = HashMap::from([("client_id".to_string(), json!("workload-123"))]);

let attrs =
build_entity_attrs_from_values(&schema, &entity_type, &src_values)
.expect("should build entity attrs");
let attrs = build_entity_attrs_from_values(&schema,Some("Jans"), &entity_type, &src_values)
.expect("should build entity attrs");
// RestrictedExpression does not implement PartialEq so the best we can do is check
// if the attribute was created
assert!(
Expand Down Expand Up @@ -311,9 +317,8 @@ mod test {
};
let src_values = HashMap::new();

let err =
build_entity_attrs_from_values(&schema, &entity_type, &src_values)
.expect_err("should error due to missing source");
let err = build_entity_attrs_from_values(&schema, Some("Jans"), &entity_type, &src_values)
.expect_err("should error due to missing source");
assert!(
matches!(
err,
Expand Down
57 changes: 38 additions & 19 deletions jans-cedarling/cedarling/src/authz/entity_builder/build_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ impl Attribute {
&self,
attr_src: &HashMap<String, Value>,
src_key: &str,
default_namespace: Option<&str>,
schema: &CedarSchemaJson,
built_entities: &BuiltEntities,
) -> Result<Option<RestrictedExpression>, BuildExprError> {
Expand Down Expand Up @@ -82,7 +83,9 @@ impl Attribute {
Attribute::Record { attrs, required } => {
let mut fields = HashMap::new();
for (name, kind) in attrs.iter() {
if let Some(expr) = kind.build_expr(attr_src, name, schema, built_entities)? {
if let Some(expr) =
kind.build_expr(attr_src, name, default_namespace, schema, built_entities)?
{
fields.insert(name.to_string(), expr);
}
}
Expand All @@ -107,6 +110,7 @@ impl Attribute {
if let Some(expr) = element.build_expr(
&HashMap::from([(claim_name.clone(), val.clone())]),
&claim_name,
default_namespace,
schema,
built_entities,
)? {
Expand All @@ -125,7 +129,7 @@ impl Attribute {
Attribute::Entity { required, name } => {
// Check if the entity is in the schema
let entity_type_name = if let Some((type_name, _type_schema)) = schema
.get_entity_schema(name)
.get_entity_schema(name, default_namespace)
.map_err(|e| BuildExprError::ParseTypeName(name.clone(), e))?
{
type_name
Expand Down Expand Up @@ -181,20 +185,23 @@ impl Attribute {
// Handle EntityOrCommon attributes
Attribute::EntityOrCommon { required, name } => {
if let Some((_namespace_name, attr)) = schema.get_common_type(name) {
attr.build_expr(attr_src, src_key, schema, built_entities)
// It is common type, so we can build the expression directly.
attr.build_expr(attr_src, src_key, default_namespace, schema, built_entities)
} else if schema
.get_entity_schema(name)
.get_entity_schema(name, default_namespace)
.map_err(|e| BuildExprError::ParseTypeName(name.clone(), e))?
.is_some()
{
// it is entity type, so we build expression with "link" to the entity
let attr = Attribute::Entity {
required: *required,
name: name.to_string(),
};
attr.build_expr(attr_src, src_key, schema, built_entities)
attr.build_expr(attr_src, src_key, default_namespace, schema, built_entities)
} else if let Some(attr) = str_to_primitive_type(*required, name) {
attr.build_expr(attr_src, src_key, schema, built_entities)
attr.build_expr(attr_src, src_key, default_namespace, schema, built_entities)
} else if *required {
// TODO: try to check if it has namespace and if has load from it
Err(BuildExprError::UnkownType(name.to_string()))
} else {
Ok(None)
Expand Down Expand Up @@ -293,7 +300,7 @@ mod test {
let attr = Attribute::string();
let src = HashMap::from([("src_key".to_string(), json!("attr-val"))]);
let expr = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(&src, "src_key", None, &schema, &BuiltEntities::default())
.expect("should not error");
assert!(expr.is_some(), "a restricted expression should be built")
}
Expand All @@ -314,7 +321,7 @@ mod test {
let attr = Attribute::long();
let src = HashMap::from([("src_key".to_string(), json!(123))]);
let expr = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(&src, "src_key", None, &schema, &BuiltEntities::default())
.expect("should not error");
assert!(expr.is_some(), "a restricted expression should be built")
}
Expand All @@ -335,7 +342,7 @@ mod test {
let attr = Attribute::boolean();
let src = HashMap::from([("src_key".to_string(), json!(true))]);
let expr = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(&src, "src_key", None, &schema, &BuiltEntities::default())
.expect("should not error");
assert!(expr.is_some(), "a restricted expression should be built")
}
Expand Down Expand Up @@ -364,7 +371,7 @@ mod test {
)]));
let src = HashMap::from([("inner_attr".to_string(), json!("test"))]);
let expr = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(&src, "src_key", None, &schema, &BuiltEntities::default())
.expect("should not error");
assert!(expr.is_some(), "a restricted expression should be built")
}
Expand All @@ -390,7 +397,7 @@ mod test {
let attr = Attribute::set(Attribute::string());
let src = HashMap::from([("src_key".to_string(), json!(["admin", "user"]))]);
let expr = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(&src, "src_key", None, &schema, &BuiltEntities::default())
.expect("should not error");
assert!(expr.is_some(), "a restricted expression should be built")
}
Expand All @@ -416,7 +423,7 @@ mod test {
let attr = Attribute::set(Attribute::string());
let src = HashMap::from([("src_key".to_string(), json!(["admin", 123]))]);
let err = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(&src, "src_key", None, &schema, &BuiltEntities::default())
.expect_err("should error");
assert!(
matches!(err, BuildExprError::TypeMismatch(_)),
Expand Down Expand Up @@ -447,7 +454,13 @@ mod test {
let attr = Attribute::entity("OtherEntity");
let src = HashMap::from([("src_key".to_string(), json!("test"))]);
let expr = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(
&src,
"src_key",
Some("Jans"),
&schema,
&BuiltEntities::default(),
)
.expect("should not error");
assert!(expr.is_some(), "a restricted expression should be built");
}
Expand All @@ -474,7 +487,13 @@ mod test {
let attr = Attribute::entity("OtherEntity");
let src = HashMap::from([("src_key".to_string(), json!("test"))]);
let expr = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(
&src,
"src_key",
Some("Jans"),
&schema,
&BuiltEntities::default(),
)
.expect("should not error");
assert!(expr.is_some(), "a restricted expression should be built");
}
Expand All @@ -498,7 +517,7 @@ mod test {
let attr = Attribute::entity("OtherEntity");
let src = HashMap::from([("src_key".to_string(), json!("test"))]);
let err = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(&src, "src_key", None, &schema, &BuiltEntities::default())
.expect_err("should error");
assert!(
matches!(
Expand Down Expand Up @@ -527,7 +546,7 @@ mod test {
let attr = Attribute::string();
let src = HashMap::from([("src_key".to_string(), json!("0.0.0.0"))]);
let expr = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(&src, "src_key", None, &schema, &BuiltEntities::default())
.expect("should not error");
assert!(expr.is_some(), "a restricted expression should be built")
}
Expand All @@ -548,7 +567,7 @@ mod test {
let attr = Attribute::string();
let src = HashMap::from([("src_key".to_string(), json!("1.1"))]);
let expr = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(&src, "src_key", None, &schema, &BuiltEntities::default())
.expect("should not error");
assert!(expr.is_some(), "a restricted expression should be built")
}
Expand All @@ -569,7 +588,7 @@ mod test {
let attr = Attribute::String { required: false };
let src = HashMap::new();
let expr = attr
.build_expr(&src, "client_id", &schema, &BuiltEntities::default())
.build_expr(&src, "client_id", None, &schema, &BuiltEntities::default())
.expect("should not error");
assert!(expr.is_none(), "a restricted expression shouldn't built")
}
Expand All @@ -590,7 +609,7 @@ mod test {
let attr = Attribute::string();
let src = HashMap::from([("src_key".to_string(), json!(123))]);
let err = attr
.build_expr(&src, "src_key", &schema, &BuiltEntities::default())
.build_expr(&src, "src_key", None, &schema, &BuiltEntities::default())
.expect_err("should error");
assert!(
matches!(err, BuildExprError::TypeMismatch(_)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@ impl EntityBuilder {
) -> Result<Entity, BuildResourceEntityError> {
let (entity_type_name, entity_type) = self
.schema
.get_entity_schema(&resource.resource_type)?
.get_entity_schema(&resource.resource_type, None)?
.ok_or(BuildEntityError::EntityNotInSchema(
resource.resource_type.clone(),
))?;

let entity_attrs =
build_entity_attrs_from_values(&self.schema, entity_type, &resource.payload)?;
let default_namespace = entity_type_name.namespace();

let entity_attrs = build_entity_attrs_from_values(
&self.schema,
Some(default_namespace.as_str()),
entity_type,
&resource.payload,
)?;

// Build cedar entity
let entity_id =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl EntityBuilder {
// Check if the entity is in the schema
let entity_name = self.entity_names.role.to_string();
self.schema
.get_entity_schema(&entity_name)
.get_entity_schema(&entity_name, None)
.map_err(|e| BuildRoleEntityError::ParseTypeName(entity_name.clone(), e))?
.ok_or(BuildRoleEntityError::EntityNotInSchema(entity_name.clone()))?;

Expand Down
Loading

0 comments on commit 2a84175

Please sign in to comment.