use std::fmt;
use crate::redact::REDACTED;
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum OnBehalfOf {
User(User),
System,
}
impl OnBehalfOf {
#[must_use]
pub fn user(&self) -> Option<&User> {
match self {
Self::User(user) => Some(user),
Self::System => None,
}
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct User {
issuer: Option<String>,
subject: String,
client_id: Option<String>,
audience: Option<String>,
purposes: Vec<PurposeOfUse>,
organisation: Option<String>,
alt_id: Option<String>,
stated: Box<Stated>,
}
#[derive(Clone, Default, PartialEq, Eq)]
struct Stated {
name: Option<String>,
provider_identifier: Option<String>,
assurance: Option<Code>,
roles: Vec<Code>,
token_id: Option<String>,
policies: Vec<String>,
person_id: Option<PersonId>,
}
impl User {
#[must_use]
pub fn new(issuer: String, subject: String, client_id: String) -> Self {
Self {
issuer: Some(issuer),
client_id: Some(client_id),
..Self::local(subject)
}
}
#[must_use]
pub fn local(subject: String) -> Self {
Self {
issuer: None,
subject,
client_id: None,
audience: None,
purposes: Vec::new(),
organisation: None,
alt_id: None,
stated: Box::default(),
}
}
#[must_use]
pub fn with_name(mut self, name: Option<String>) -> Self {
self.stated.name = name;
self
}
#[must_use]
pub fn name(&self) -> Option<&str> {
self.stated.name.as_deref()
}
#[must_use]
pub fn with_provider_identifier(mut self, identifier: Option<String>) -> Self {
self.stated.provider_identifier = identifier;
self
}
#[must_use]
pub fn provider_identifier(&self) -> Option<&str> {
self.stated.provider_identifier.as_deref()
}
#[must_use]
pub fn with_person_id(mut self, person_id: Option<PersonId>) -> Self {
self.stated.person_id = person_id;
self
}
#[must_use]
pub fn person_id(&self) -> Option<&PersonId> {
self.stated.person_id.as_ref()
}
#[must_use]
pub fn with_assurance(mut self, assurance: Option<Code>) -> Self {
self.stated.assurance = assurance;
self
}
#[must_use]
pub fn assurance(&self) -> Option<&Code> {
self.stated.assurance.as_ref()
}
#[must_use]
pub fn with_roles(mut self, roles: Vec<Code>) -> Self {
self.stated.roles = roles;
self
}
#[must_use]
pub fn roles(&self) -> &[Code] {
&self.stated.roles
}
#[must_use]
pub fn with_organisation(mut self, organisation: Option<String>) -> Self {
self.organisation = organisation;
self
}
#[must_use]
pub fn with_alt_id(mut self, alt_id: Option<String>) -> Self {
self.alt_id = alt_id;
self
}
#[must_use]
pub fn organisation(&self) -> Option<&str> {
self.organisation.as_deref()
}
#[must_use]
pub fn alt_id(&self) -> Option<&str> {
self.alt_id.as_deref()
}
#[must_use]
pub fn with_audience(mut self, audience: Option<String>) -> Self {
self.audience = audience;
self
}
#[must_use]
pub fn with_purposes(mut self, purposes: Vec<PurposeOfUse>) -> Self {
self.purposes = purposes;
self
}
#[must_use]
pub fn with_token_id(mut self, token_id: Option<String>) -> Self {
self.stated.token_id = token_id;
self
}
#[must_use]
pub fn token_id(&self) -> Option<&str> {
self.stated.token_id.as_deref()
}
#[must_use]
pub fn with_policies(mut self, policies: Vec<String>) -> Self {
self.stated.policies = policies;
self
}
#[must_use]
pub fn policies(&self) -> &[String] {
&self.stated.policies
}
#[must_use]
pub fn with_issuer(mut self, issuer: Option<String>) -> Self {
self.issuer = issuer;
self
}
#[must_use]
pub fn with_client_id(mut self, client_id: Option<String>) -> Self {
self.client_id = client_id;
self
}
#[must_use]
pub fn issuer(&self) -> Option<&str> {
self.issuer.as_deref()
}
#[must_use]
pub fn subject(&self) -> &str {
&self.subject
}
#[must_use]
pub fn client_id(&self) -> Option<&str> {
self.client_id.as_deref()
}
#[must_use]
pub fn audience(&self) -> Option<&str> {
self.audience.as_deref()
}
#[must_use]
pub fn purposes(&self) -> &[PurposeOfUse] {
&self.purposes
}
#[must_use]
pub fn atna_user_name(&self) -> String {
match &self.issuer {
Some(issuer) => format!(
"{}<{}@{}>",
self.audience.as_deref().unwrap_or_default(),
self.subject,
issuer
),
None => self.subject.clone(),
}
}
}
impl fmt::Debug for User {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("User").field(&REDACTED).finish()
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Code {
pub system: Option<String>,
pub code: String,
}
#[derive(Clone, PartialEq, Eq)]
pub struct PersonId {
pub system: Option<String>,
pub value: String,
}
impl fmt::Debug for PersonId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PersonId")
.field("system", &self.system.is_some())
.field("value", &REDACTED)
.finish()
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PurposeOfUse {
pub system: Option<String>,
pub code: String,
}