Add identity and target authorization package
OIDC validation, principal mapping, remora:v1 roles, and current-authz filtering with kind acceptance on Keycloak and ZITADEL.
This commit is contained in:
parent
91ac6dee85
commit
bf028161ae
1 changed files with 3153 additions and 21 deletions
51
crates/remora-identity/src/principal.rs
Normal file
51
crates/remora-identity/src/principal.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
use remora_domain::{OpaqueId, StorageScope};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::error::IdentityError;
|
||||
use crate::roles::DecodedRoles;
|
||||
|
||||
/// Authenticated caller after token validation and role decoding.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Principal {
|
||||
pub id: OpaqueId,
|
||||
pub issuer: String,
|
||||
pub subject: String,
|
||||
pub administrator: bool,
|
||||
pub scopes: Vec<StorageScope>,
|
||||
}
|
||||
|
||||
/// OIDC identity pair before durable principal-id binding.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ExternalIdentity {
|
||||
pub issuer: String,
|
||||
pub subject: String,
|
||||
pub roles: DecodedRoles,
|
||||
}
|
||||
|
||||
impl Principal {
|
||||
pub fn from_external(id: OpaqueId, external: ExternalIdentity) -> Self {
|
||||
Self {
|
||||
id,
|
||||
issuer: external.issuer,
|
||||
subject: external.subject,
|
||||
administrator: external.roles.administrator,
|
||||
scopes: external.roles.scopes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Deterministic stable principal id for one exact issuer+subject pair.
|
||||
pub fn principal_id_for(issuer: &str, subject: &str) -> Result<OpaqueId, IdentityError> {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(b"remora-principal-v1\0");
|
||||
hasher.update(issuer.as_bytes());
|
||||
hasher.update([0]);
|
||||
hasher.update(subject.as_bytes());
|
||||
let digest = hasher.finalize();
|
||||
let hex = digest
|
||||
.iter()
|
||||
.take(16)
|
||||
.map(|byte| format!("{byte:02x}"))
|
||||
.collect::<String>();
|
||||
OpaqueId::parse(format!("p{hex}")).map_err(Into::into)
|
||||
}
|
||||
Loading…
Reference in a new issue