pub struct Permission { /* private fields */ }Expand description
Represents a permission from JWT claims.
Serializes to format: "{tenant_id}:{resource_pattern}:{resource_id}:{action}"
where tenant_id and resource_id are “*” if None.
This is compatible with modkit_security::Permission.
Implementations§
Source§impl Permission
impl Permission
Sourcepub fn builder() -> PermissionBuilder
pub fn builder() -> PermissionBuilder
Examples found in repository?
examples/dispatcher_usage.rs (line 72)
26 fn normalize(&self, raw: &Value) -> Result<Claims, ClaimsError> {
27 let issuer_value = raw
28 .get("iss")
29 .ok_or_else(|| ClaimsError::MissingClaim("iss".to_owned()))?;
30 let issuer = extract_string(issuer_value, "iss")?;
31
32 let sub_value = raw
33 .get("sub")
34 .ok_or_else(|| ClaimsError::MissingClaim("sub".to_owned()))?;
35 let subject = parse_uuid_from_value(sub_value, "sub")?;
36
37 let audiences = raw.get("aud").map(extract_audiences).unwrap_or_default();
38
39 let expires_at = raw
40 .get("exp")
41 .map(|value| parse_timestamp(value, "exp"))
42 .transpose()?;
43
44 let not_before = raw
45 .get("nbf")
46 .map(|value| parse_timestamp(value, "nbf"))
47 .transpose()?;
48
49 let issued_at = raw
50 .get("iat")
51 .map(|value| parse_timestamp(value, "iat"))
52 .transpose()?;
53
54 let jwt_id = raw
55 .get("jti")
56 .and_then(|v| v.as_str())
57 .map(ToString::to_string);
58
59 let tenant_id_value = raw
60 .get("tenant_id")
61 .ok_or_else(|| ClaimsError::MissingClaim("tenant_id".to_owned()))?;
62 let tenant_id = parse_uuid_from_value(tenant_id_value, "tenant_id")?;
63
64 let permissions: Vec<Permission> = raw
65 .get("roles")
66 .and_then(Value::as_array)
67 .map(|arr| {
68 arr.iter()
69 .filter_map(|value| value.as_str())
70 .filter_map(|role| {
71 if let Some(pos) = role.rfind(':') {
72 Permission::builder()
73 .resource_pattern(&role[..pos])
74 .action(&role[pos + 1..])
75 .build()
76 .ok()
77 } else {
78 Permission::builder()
79 .resource_pattern(role)
80 .action("*")
81 .build()
82 .ok()
83 }
84 })
85 .collect()
86 })
87 .unwrap_or_default();
88
89 Ok(Claims {
90 issuer,
91 subject,
92 audiences,
93 expires_at,
94 not_before,
95 issued_at,
96 jwt_id,
97 tenant_id,
98 permissions,
99 extras: serde_json::Map::new(),
100 })
101 }pub fn tenant_id(&self) -> Option<Uuid>
Sourcepub fn resource_pattern(&self) -> &str
pub fn resource_pattern(&self) -> &str
Examples found in repository?
examples/dispatcher_usage.rs (line 181)
127async fn main() -> Result<(), Box<dyn std::error::Error>> {
128 let mut plugins = PluginRegistry::default();
129 plugins.register("demo", Arc::new(DemoClaimsPlugin));
130
131 let mut plugin_configs = HashMap::new();
132 plugin_configs.insert(
133 "demo".to_owned(),
134 PluginConfig::Oidc {
135 tenant_claim: "tenants".to_owned(),
136 roles_claim: "roles".to_owned(),
137 },
138 );
139
140 let config = AuthConfig {
141 mode: AuthModeConfig {
142 provider: "demo".to_owned(),
143 },
144 issuers: vec!["https://issuer.local".to_owned()],
145 audiences: vec!["demo-api".to_owned()],
146 plugins: plugin_configs,
147 ..AuthConfig::default()
148 };
149
150 let validation = ValidationConfig {
151 allowed_issuers: config.issuers.clone(),
152 allowed_audiences: config.audiences.clone(),
153 leeway_seconds: config.leeway_seconds,
154 require_uuid_subject: true,
155 require_uuid_tenants: true,
156 };
157
158 let subject = Uuid::new_v4();
159 let tenant = Uuid::new_v4();
160 let expires_at = OffsetDateTime::now_utc() + Duration::minutes(15);
161
162 let raw_claims = serde_json::json!({
163 "iss": "https://issuer.local",
164 "sub": subject.to_string(),
165 "aud": ["demo-api"],
166 "exp": expires_at.unix_timestamp(),
167 "tenant_id": tenant.to_string(),
168 "roles": ["viewer:read"]
169 });
170
171 let dispatcher = AuthDispatcher::new(validation, &config, &plugins)?
172 .with_key_provider(Arc::new(StaticKeyProvider::new(raw_claims)));
173
174 let claims = dispatcher.validate_jwt("demo-token").await?;
175 let perm_list = if claims.permissions.is_empty() {
176 "none".to_owned()
177 } else {
178 claims
179 .permissions
180 .iter()
181 .map(|p| format!("{}:{}", p.resource_pattern(), p.action()))
182 .collect::<Vec<_>>()
183 .join(", ")
184 };
185 println!(
186 "Validated token for subject {} with permissions {}",
187 claims.subject, perm_list
188 );
189
190 Ok(())
191}pub fn resource_id(&self) -> Option<Uuid>
Sourcepub fn action(&self) -> &str
pub fn action(&self) -> &str
Examples found in repository?
examples/dispatcher_usage.rs (line 181)
127async fn main() -> Result<(), Box<dyn std::error::Error>> {
128 let mut plugins = PluginRegistry::default();
129 plugins.register("demo", Arc::new(DemoClaimsPlugin));
130
131 let mut plugin_configs = HashMap::new();
132 plugin_configs.insert(
133 "demo".to_owned(),
134 PluginConfig::Oidc {
135 tenant_claim: "tenants".to_owned(),
136 roles_claim: "roles".to_owned(),
137 },
138 );
139
140 let config = AuthConfig {
141 mode: AuthModeConfig {
142 provider: "demo".to_owned(),
143 },
144 issuers: vec!["https://issuer.local".to_owned()],
145 audiences: vec!["demo-api".to_owned()],
146 plugins: plugin_configs,
147 ..AuthConfig::default()
148 };
149
150 let validation = ValidationConfig {
151 allowed_issuers: config.issuers.clone(),
152 allowed_audiences: config.audiences.clone(),
153 leeway_seconds: config.leeway_seconds,
154 require_uuid_subject: true,
155 require_uuid_tenants: true,
156 };
157
158 let subject = Uuid::new_v4();
159 let tenant = Uuid::new_v4();
160 let expires_at = OffsetDateTime::now_utc() + Duration::minutes(15);
161
162 let raw_claims = serde_json::json!({
163 "iss": "https://issuer.local",
164 "sub": subject.to_string(),
165 "aud": ["demo-api"],
166 "exp": expires_at.unix_timestamp(),
167 "tenant_id": tenant.to_string(),
168 "roles": ["viewer:read"]
169 });
170
171 let dispatcher = AuthDispatcher::new(validation, &config, &plugins)?
172 .with_key_provider(Arc::new(StaticKeyProvider::new(raw_claims)));
173
174 let claims = dispatcher.validate_jwt("demo-token").await?;
175 let perm_list = if claims.permissions.is_empty() {
176 "none".to_owned()
177 } else {
178 claims
179 .permissions
180 .iter()
181 .map(|p| format!("{}:{}", p.resource_pattern(), p.action()))
182 .collect::<Vec<_>>()
183 .join(", ")
184 };
185 println!(
186 "Validated token for subject {} with permissions {}",
187 claims.subject, perm_list
188 );
189
190 Ok(())
191}Trait Implementations§
Source§impl Clone for Permission
impl Clone for Permission
Source§fn clone(&self) -> Permission
fn clone(&self) -> Permission
Returns a duplicate of the value. Read more
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreSource§impl Debug for Permission
impl Debug for Permission
Source§impl<'de> Deserialize<'de> for Permission
impl<'de> Deserialize<'de> for Permission
Source§fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
Deserialize this value from the given Serde deserializer. Read more
Source§impl Ord for Permission
impl Ord for Permission
Source§fn cmp(&self, other: &Permission) -> Ordering
fn cmp(&self, other: &Permission) -> Ordering
1.21.0 · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
Compares and returns the maximum of two values. Read more
Source§impl PartialEq for Permission
impl PartialEq for Permission
Source§impl PartialOrd for Permission
impl PartialOrd for Permission
Source§impl Serialize for Permission
impl Serialize for Permission
impl Eq for Permission
impl StructuralPartialEq for Permission
Auto Trait Implementations§
impl Freeze for Permission
impl RefUnwindSafe for Permission
impl Send for Permission
impl Sync for Permission
impl Unpin for Permission
impl UnwindSafe for Permission
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more