51 lines
1.5 KiB
Rust
51 lines
1.5 KiB
Rust
|
|
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)
|
||
|
|
}
|