478 lines
17 KiB
Rust
478 lines
17 KiB
Rust
//! Proto <-> types conversions
|
|
//!
|
|
//! Converts between protobuf types and IAM domain types.
|
|
|
|
use iam_types::{
|
|
Condition as TypesCondition, ConditionExpr as TypesConditionExpr,
|
|
Organization as TypesOrganization, Permission as TypesPermission,
|
|
PolicyBinding as TypesBinding, Principal as TypesPrincipal,
|
|
PrincipalKind as TypesPrincipalKind, PrincipalRef as TypesPrincipalRef,
|
|
Project as TypesProject, Role as TypesRole, Scope as TypesScope,
|
|
};
|
|
|
|
use crate::proto::{
|
|
self, condition_expr, scope, Condition, ConditionExpr, Organization, Permission, PolicyBinding,
|
|
Principal, PrincipalKind, PrincipalRef, Project, Role, Scope,
|
|
};
|
|
|
|
// ============================================================================
|
|
// PrincipalKind conversions
|
|
// ============================================================================
|
|
|
|
/// Convert types PrincipalKind to proto enum value
|
|
pub fn principal_kind_to_proto(kind: &TypesPrincipalKind) -> i32 {
|
|
match kind {
|
|
TypesPrincipalKind::User => PrincipalKind::User as i32,
|
|
TypesPrincipalKind::ServiceAccount => PrincipalKind::ServiceAccount as i32,
|
|
TypesPrincipalKind::Group => PrincipalKind::Group as i32,
|
|
}
|
|
}
|
|
|
|
/// Convert proto enum value to types PrincipalKind
|
|
pub fn proto_to_principal_kind(value: i32) -> Result<TypesPrincipalKind, &'static str> {
|
|
match PrincipalKind::try_from(value) {
|
|
Ok(PrincipalKind::User) => Ok(TypesPrincipalKind::User),
|
|
Ok(PrincipalKind::ServiceAccount) => Ok(TypesPrincipalKind::ServiceAccount),
|
|
Ok(PrincipalKind::Group) => Ok(TypesPrincipalKind::Group),
|
|
_ => Err("invalid principal kind"),
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// PrincipalRef conversions
|
|
// ============================================================================
|
|
|
|
impl From<TypesPrincipalRef> for PrincipalRef {
|
|
fn from(r: TypesPrincipalRef) -> Self {
|
|
PrincipalRef {
|
|
kind: principal_kind_to_proto(&r.kind),
|
|
id: r.id,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Convert proto PrincipalRef to types PrincipalRef
|
|
pub fn proto_to_principal_ref(r: &PrincipalRef) -> Result<TypesPrincipalRef, &'static str> {
|
|
let kind = proto_to_principal_kind(r.kind)?;
|
|
Ok(TypesPrincipalRef::new(kind, &r.id))
|
|
}
|
|
|
|
// ============================================================================
|
|
// Principal conversions
|
|
// ============================================================================
|
|
|
|
impl From<TypesPrincipal> for Principal {
|
|
fn from(p: TypesPrincipal) -> Self {
|
|
Principal {
|
|
id: p.id,
|
|
kind: principal_kind_to_proto(&p.kind),
|
|
name: p.name,
|
|
org_id: p.org_id,
|
|
project_id: p.project_id,
|
|
email: p.email,
|
|
oidc_sub: p.oidc_sub,
|
|
node_id: p.node_id,
|
|
metadata: p.metadata,
|
|
created_at: p.created_at,
|
|
updated_at: p.updated_at,
|
|
enabled: p.enabled,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Principal> for TypesPrincipal {
|
|
fn from(p: Principal) -> Self {
|
|
TypesPrincipal {
|
|
id: p.id,
|
|
kind: proto_to_principal_kind(p.kind).unwrap_or(TypesPrincipalKind::User),
|
|
name: p.name,
|
|
org_id: p.org_id,
|
|
project_id: p.project_id,
|
|
email: p.email,
|
|
oidc_sub: p.oidc_sub,
|
|
node_id: p.node_id,
|
|
metadata: p.metadata,
|
|
created_at: p.created_at,
|
|
updated_at: p.updated_at,
|
|
enabled: p.enabled,
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// Organization / Project conversions
|
|
// ============================================================================
|
|
|
|
impl From<TypesOrganization> for Organization {
|
|
fn from(org: TypesOrganization) -> Self {
|
|
Organization {
|
|
id: org.id,
|
|
name: org.name,
|
|
description: org.description,
|
|
metadata: org.metadata,
|
|
created_at: org.created_at,
|
|
updated_at: org.updated_at,
|
|
enabled: org.enabled,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Organization> for TypesOrganization {
|
|
fn from(org: Organization) -> Self {
|
|
TypesOrganization {
|
|
id: org.id,
|
|
name: org.name,
|
|
description: org.description,
|
|
metadata: org.metadata,
|
|
created_at: org.created_at,
|
|
updated_at: org.updated_at,
|
|
enabled: org.enabled,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<TypesProject> for Project {
|
|
fn from(project: TypesProject) -> Self {
|
|
Project {
|
|
id: project.id,
|
|
org_id: project.org_id,
|
|
name: project.name,
|
|
description: project.description,
|
|
metadata: project.metadata,
|
|
created_at: project.created_at,
|
|
updated_at: project.updated_at,
|
|
enabled: project.enabled,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Project> for TypesProject {
|
|
fn from(project: Project) -> Self {
|
|
TypesProject {
|
|
id: project.id,
|
|
org_id: project.org_id,
|
|
name: project.name,
|
|
description: project.description,
|
|
metadata: project.metadata,
|
|
created_at: project.created_at,
|
|
updated_at: project.updated_at,
|
|
enabled: project.enabled,
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// Scope conversions
|
|
// ============================================================================
|
|
|
|
impl From<TypesScope> for Scope {
|
|
fn from(s: TypesScope) -> Self {
|
|
Scope {
|
|
scope: Some(match s {
|
|
TypesScope::System => scope::Scope::System(true),
|
|
TypesScope::Org { id } => scope::Scope::Org(proto::OrgScope { id }),
|
|
TypesScope::Project { id, org_id } => {
|
|
scope::Scope::Project(proto::ProjectScope { id, org_id })
|
|
}
|
|
TypesScope::Resource {
|
|
id,
|
|
project_id,
|
|
org_id,
|
|
} => scope::Scope::Resource(proto::ResourceScope {
|
|
id,
|
|
project_id,
|
|
org_id,
|
|
}),
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Scope> for TypesScope {
|
|
fn from(s: Scope) -> Self {
|
|
match s.scope {
|
|
Some(scope::Scope::System(true)) => TypesScope::System,
|
|
Some(scope::Scope::Org(org)) => TypesScope::org(org.id),
|
|
Some(scope::Scope::Project(proj)) => TypesScope::project(proj.id, proj.org_id),
|
|
Some(scope::Scope::Resource(res)) => {
|
|
TypesScope::resource(res.id, res.project_id, res.org_id)
|
|
}
|
|
_ => TypesScope::System,
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// Permission conversions
|
|
// ============================================================================
|
|
|
|
impl From<TypesPermission> for Permission {
|
|
fn from(p: TypesPermission) -> Self {
|
|
Permission {
|
|
action: p.action,
|
|
resource_pattern: p.resource_pattern,
|
|
condition: p.condition.map(|c| c.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Permission> for TypesPermission {
|
|
fn from(p: Permission) -> Self {
|
|
TypesPermission {
|
|
action: p.action,
|
|
resource_pattern: p.resource_pattern,
|
|
condition: p.condition.map(|c| c.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// Role conversions
|
|
// ============================================================================
|
|
|
|
impl From<TypesRole> for Role {
|
|
fn from(r: TypesRole) -> Self {
|
|
Role {
|
|
name: r.name,
|
|
display_name: r.display_name,
|
|
description: r.description,
|
|
scope: Some(r.scope.into()),
|
|
permissions: r.permissions.into_iter().map(|p| p.into()).collect(),
|
|
builtin: r.builtin,
|
|
created_at: r.created_at,
|
|
updated_at: r.updated_at,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Role> for TypesRole {
|
|
fn from(r: Role) -> Self {
|
|
TypesRole {
|
|
name: r.name,
|
|
display_name: r.display_name,
|
|
description: r.description,
|
|
scope: r
|
|
.scope
|
|
.unwrap_or(Scope {
|
|
scope: Some(scope::Scope::System(true)),
|
|
})
|
|
.into(),
|
|
permissions: r.permissions.into_iter().map(Into::into).collect(),
|
|
builtin: r.builtin,
|
|
created_at: r.created_at,
|
|
updated_at: r.updated_at,
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// PolicyBinding conversions
|
|
// ============================================================================
|
|
|
|
impl From<TypesBinding> for PolicyBinding {
|
|
fn from(b: TypesBinding) -> Self {
|
|
PolicyBinding {
|
|
id: b.id,
|
|
principal: Some(b.principal_ref.into()),
|
|
role: b.role_ref,
|
|
scope: Some(b.scope.into()),
|
|
condition: b.condition.map(|c| c.into()),
|
|
created_at: b.created_at,
|
|
updated_at: b.updated_at,
|
|
created_by: b.created_by,
|
|
expires_at: b.expires_at,
|
|
enabled: b.enabled,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<PolicyBinding> for TypesBinding {
|
|
fn from(b: PolicyBinding) -> Self {
|
|
TypesBinding {
|
|
id: b.id,
|
|
principal_ref: proto_to_principal_ref(&b.principal.unwrap_or_else(|| PrincipalRef {
|
|
kind: PrincipalKind::User as i32,
|
|
id: String::new(),
|
|
}))
|
|
.unwrap_or_else(|_| TypesPrincipalRef::user("")),
|
|
role_ref: b.role,
|
|
scope: b
|
|
.scope
|
|
.unwrap_or(Scope {
|
|
scope: Some(scope::Scope::System(true)),
|
|
})
|
|
.into(),
|
|
condition: b.condition.map(|c| c.into()),
|
|
created_at: b.created_at,
|
|
updated_at: b.updated_at,
|
|
created_by: b.created_by,
|
|
expires_at: b.expires_at,
|
|
enabled: b.enabled,
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// Condition conversions
|
|
// ============================================================================
|
|
|
|
impl From<TypesCondition> for Condition {
|
|
fn from(c: TypesCondition) -> Self {
|
|
Condition {
|
|
expression: Some(c.expression.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Condition> for TypesCondition {
|
|
fn from(c: Condition) -> Self {
|
|
TypesCondition {
|
|
expression: c
|
|
.expression
|
|
.map(|e| e.into())
|
|
.unwrap_or(TypesConditionExpr::And(vec![])),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<TypesConditionExpr> for ConditionExpr {
|
|
fn from(e: TypesConditionExpr) -> Self {
|
|
let expr = match e {
|
|
TypesConditionExpr::StringEquals { key, value } => {
|
|
condition_expr::Expr::StringEquals(proto::StringEqualsExpr { key, value })
|
|
}
|
|
TypesConditionExpr::StringNotEquals { key, value } => {
|
|
condition_expr::Expr::StringNotEquals(proto::StringNotEqualsExpr { key, value })
|
|
}
|
|
TypesConditionExpr::StringLike { key, pattern } => {
|
|
condition_expr::Expr::StringLike(proto::StringLikeExpr { key, pattern })
|
|
}
|
|
TypesConditionExpr::StringNotLike { key, pattern } => {
|
|
condition_expr::Expr::StringNotLike(proto::StringNotLikeExpr { key, pattern })
|
|
}
|
|
TypesConditionExpr::NumericEquals { key, value } => {
|
|
condition_expr::Expr::NumericEquals(proto::NumericEqualsExpr { key, value })
|
|
}
|
|
TypesConditionExpr::NumericLessThan { key, value } => {
|
|
condition_expr::Expr::NumericLessThan(proto::NumericLessThanExpr { key, value })
|
|
}
|
|
TypesConditionExpr::NumericLessThanEquals { key, value } => {
|
|
condition_expr::Expr::NumericLessThan(proto::NumericLessThanExpr { key, value })
|
|
}
|
|
TypesConditionExpr::NumericGreaterThan { key, value } => {
|
|
condition_expr::Expr::NumericGreaterThan(proto::NumericGreaterThanExpr {
|
|
key,
|
|
value,
|
|
})
|
|
}
|
|
TypesConditionExpr::NumericGreaterThanEquals { key, value } => {
|
|
condition_expr::Expr::NumericGreaterThan(proto::NumericGreaterThanExpr {
|
|
key,
|
|
value,
|
|
})
|
|
}
|
|
TypesConditionExpr::IpAddress { key, cidr } => {
|
|
condition_expr::Expr::IpAddress(proto::IpAddressExpr { key, cidr })
|
|
}
|
|
TypesConditionExpr::NotIpAddress { key, cidr } => {
|
|
condition_expr::Expr::NotIpAddress(proto::NotIpAddressExpr { key, cidr })
|
|
}
|
|
TypesConditionExpr::TimeBetween { start, end } => {
|
|
condition_expr::Expr::TimeBetween(proto::TimeBetweenExpr { start, end })
|
|
}
|
|
TypesConditionExpr::Exists { key } => {
|
|
condition_expr::Expr::Exists(proto::ExistsExpr { key })
|
|
}
|
|
TypesConditionExpr::StringEqualsAny { key, values } => {
|
|
condition_expr::Expr::StringEqualsAny(proto::StringEqualsAnyExpr { key, values })
|
|
}
|
|
TypesConditionExpr::Bool { key, value } => {
|
|
condition_expr::Expr::BoolExpr(proto::BoolExpr { key, value })
|
|
}
|
|
TypesConditionExpr::And(exprs) => condition_expr::Expr::AndExpr(proto::AndExpr {
|
|
expressions: exprs.into_iter().map(|e| e.into()).collect(),
|
|
}),
|
|
TypesConditionExpr::Or(exprs) => condition_expr::Expr::OrExpr(proto::OrExpr {
|
|
expressions: exprs.into_iter().map(|e| e.into()).collect(),
|
|
}),
|
|
TypesConditionExpr::Not(expr) => {
|
|
condition_expr::Expr::NotExpr(Box::new(proto::NotExpr {
|
|
expression: Some(Box::new((*expr).into())),
|
|
}))
|
|
}
|
|
};
|
|
ConditionExpr { expr: Some(expr) }
|
|
}
|
|
}
|
|
|
|
impl From<ConditionExpr> for TypesConditionExpr {
|
|
fn from(e: ConditionExpr) -> Self {
|
|
match e.expr {
|
|
Some(condition_expr::Expr::StringEquals(e)) => TypesConditionExpr::StringEquals {
|
|
key: e.key,
|
|
value: e.value,
|
|
},
|
|
Some(condition_expr::Expr::StringNotEquals(e)) => TypesConditionExpr::StringNotEquals {
|
|
key: e.key,
|
|
value: e.value,
|
|
},
|
|
Some(condition_expr::Expr::StringLike(e)) => TypesConditionExpr::StringLike {
|
|
key: e.key,
|
|
pattern: e.pattern,
|
|
},
|
|
Some(condition_expr::Expr::StringNotLike(e)) => TypesConditionExpr::StringNotLike {
|
|
key: e.key,
|
|
pattern: e.pattern,
|
|
},
|
|
Some(condition_expr::Expr::NumericEquals(e)) => TypesConditionExpr::NumericEquals {
|
|
key: e.key,
|
|
value: e.value,
|
|
},
|
|
Some(condition_expr::Expr::NumericLessThan(e)) => TypesConditionExpr::NumericLessThan {
|
|
key: e.key,
|
|
value: e.value,
|
|
},
|
|
Some(condition_expr::Expr::NumericGreaterThan(e)) => {
|
|
TypesConditionExpr::NumericGreaterThan {
|
|
key: e.key,
|
|
value: e.value,
|
|
}
|
|
}
|
|
Some(condition_expr::Expr::IpAddress(e)) => TypesConditionExpr::IpAddress {
|
|
key: e.key,
|
|
cidr: e.cidr,
|
|
},
|
|
Some(condition_expr::Expr::NotIpAddress(e)) => TypesConditionExpr::NotIpAddress {
|
|
key: e.key,
|
|
cidr: e.cidr,
|
|
},
|
|
Some(condition_expr::Expr::TimeBetween(e)) => TypesConditionExpr::TimeBetween {
|
|
start: e.start,
|
|
end: e.end,
|
|
},
|
|
Some(condition_expr::Expr::Exists(e)) => TypesConditionExpr::Exists { key: e.key },
|
|
Some(condition_expr::Expr::StringEqualsAny(e)) => TypesConditionExpr::StringEqualsAny {
|
|
key: e.key,
|
|
values: e.values,
|
|
},
|
|
Some(condition_expr::Expr::BoolExpr(e)) => TypesConditionExpr::Bool {
|
|
key: e.key,
|
|
value: e.value,
|
|
},
|
|
Some(condition_expr::Expr::AndExpr(e)) => {
|
|
TypesConditionExpr::And(e.expressions.into_iter().map(|x| x.into()).collect())
|
|
}
|
|
Some(condition_expr::Expr::OrExpr(e)) => {
|
|
TypesConditionExpr::Or(e.expressions.into_iter().map(|x| x.into()).collect())
|
|
}
|
|
Some(condition_expr::Expr::NotExpr(e)) => {
|
|
let inner = e
|
|
.expression
|
|
.map(|x| (*x).into())
|
|
.unwrap_or(TypesConditionExpr::And(vec![]));
|
|
TypesConditionExpr::Not(Box::new(inner))
|
|
}
|
|
None => TypesConditionExpr::And(vec![]),
|
|
}
|
|
}
|
|
}
|