securitydept_oidc_client/
models.rs1use std::collections::HashMap;
2
3use chrono::{DateTime, Utc};
4use openidconnect::{
5 AdditionalClaims, CsrfToken, EmptyExtraTokenFields, IdTokenClaims, IdTokenFields, Nonce,
6 UserInfoClaims,
7 core::{CoreGenderClaim, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm},
8};
9use serde::{Deserialize, Serialize};
10use url::{Url, form_urlencoded};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct ClaimsCheckResult {
14 pub display_name: String,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub picture: Option<String>,
17 pub claims: HashMap<String, serde_json::Value>,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
22pub struct ExtraOidcClaims {
23 #[serde(flatten)]
24 pub extra: HashMap<String, serde_json::Value>,
25}
26
27impl AdditionalClaims for ExtraOidcClaims {}
28
29pub type UserInfoClaimsWithExtra = UserInfoClaims<ExtraOidcClaims, CoreGenderClaim>;
30pub type IdTokenClaimsWithExtra = IdTokenClaims<ExtraOidcClaims, CoreGenderClaim>;
31
32pub type IdTokenFieldsWithExtra = IdTokenFields<
33 ExtraOidcClaims,
34 EmptyExtraTokenFields,
35 CoreGenderClaim,
36 CoreJweContentEncryptionAlgorithm,
37 CoreJwsSigningAlgorithm,
38>;
39
40#[derive(Debug)]
41pub struct OidcCodeFlowAuthorizationRequest {
42 pub authorization_url: Url,
43 pub csrf_token: CsrfToken,
44 pub nonce: Nonce,
45 pub pkce_verifier_secret: Option<String>,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct OidcDeviceAuthorizationResult {
50 pub device_code: String,
51 pub user_code: String,
52 pub verification_uri: String,
53 #[serde(skip_serializing_if = "Option::is_none")]
54 pub verification_uri_complete: Option<String>,
55 #[serde(with = "humantime_serde")]
56 pub expires_in: std::time::Duration,
57 #[serde(
58 default,
59 skip_serializing_if = "Option::is_none",
60 with = "humantime_serde::option"
61 )]
62 pub interval: Option<std::time::Duration>,
63}
64
65impl OidcDeviceAuthorizationResult {
66 pub fn poll_interval(&self, fallback: std::time::Duration) -> std::time::Duration {
67 self.interval.unwrap_or(fallback)
68 }
69}
70
71#[derive(Debug, Clone, Serialize)]
72#[serde(tag = "status", rename_all = "snake_case")]
73pub enum OidcDeviceTokenPollResult {
74 Pending {
75 #[serde(with = "humantime_serde")]
76 interval: std::time::Duration,
77 },
78 SlowDown {
79 #[serde(with = "humantime_serde")]
80 interval: std::time::Duration,
81 },
82 Denied {
83 #[serde(skip_serializing_if = "Option::is_none")]
84 error_description: Option<String>,
85 },
86 Expired {
87 #[serde(skip_serializing_if = "Option::is_none")]
88 error_description: Option<String>,
89 },
90 Complete {
91 token_result: Box<OidcDeviceTokenResult>,
92 },
93}
94
95#[derive(Debug, Clone, Serialize)]
96pub struct OidcDeviceTokenResult {
97 pub access_token: String,
98 pub access_token_expiration: Option<DateTime<Utc>>,
99 pub id_token: String,
100 pub refresh_token: Option<String>,
101 pub id_token_claims: IdTokenClaimsWithExtra,
102 pub user_info_claims: Option<UserInfoClaimsWithExtra>,
103 pub claims_check_result: ClaimsCheckResult,
104}
105
106impl TokenSetTrait for OidcDeviceTokenResult {
107 fn access_token(&self) -> &str {
108 &self.access_token
109 }
110 fn id_token(&self) -> Option<&str> {
111 Some(&self.id_token)
112 }
113 fn refresh_token(&self) -> Option<&str> {
114 self.refresh_token.as_deref()
115 }
116 fn access_token_expiration(&self) -> Option<&DateTime<Utc>> {
117 self.access_token_expiration.as_ref()
118 }
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
122#[serde(tag = "kind", content = "token", rename_all = "snake_case")]
123pub enum OidcRevocableToken {
124 AccessToken(String),
125 RefreshToken(String),
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct OidcTokenSet {
130 pub access_token: String,
131 #[serde(skip_serializing_if = "Option::is_none")]
132 pub id_token: Option<String>,
133 #[serde(skip_serializing_if = "Option::is_none")]
134 pub refresh_token: Option<String>,
135}
136
137pub trait TokenSetTrait {
138 fn access_token(&self) -> &str;
139 fn id_token(&self) -> Option<&str>;
140 fn refresh_token(&self) -> Option<&str>;
141 fn access_token_expiration(&self) -> Option<&DateTime<Utc>>;
142
143 fn to_fragment(&self) -> String {
144 let mut fragment = &mut form_urlencoded::Serializer::new(String::new());
145
146 fragment = fragment.append_pair("access_token", self.access_token());
147
148 if let Some(refresh_token) = self.refresh_token() {
149 fragment = fragment.append_pair("refresh_token", refresh_token)
150 };
151
152 if let Some(id_token) = self.id_token() {
153 fragment = fragment.append_pair("id_token", id_token)
154 }
155
156 if let Some(access_token_expiration) = self.access_token_expiration() {
157 fragment = fragment.append_pair("expires_at", &access_token_expiration.to_rfc3339())
158 }
159
160 fragment.finish()
161 }
162}
163
164#[derive(Deserialize)]
165pub struct OidcCodeCallbackSearchParams {
166 pub code: String,
167 pub state: Option<String>,
169}
170
171pub struct OidcCodeExchangeResult {
172 pub access_token: String,
173 pub access_token_expiration: Option<DateTime<Utc>>,
174 pub id_token: String,
175 pub refresh_token: Option<String>,
176 pub id_token_claims: IdTokenClaimsWithExtra,
177 pub user_info_claims: Option<UserInfoClaimsWithExtra>,
178}
179
180pub struct OidcCodeCallbackResult {
181 pub code: String,
182 pub pkce_verifier_secret: Option<String>,
183 pub state: Option<String>,
184 pub nonce: String,
185 pub pending_extra_data: Option<serde_json::Value>,
186 pub access_token: String,
187 pub access_token_expiration: Option<DateTime<Utc>>,
188 pub id_token: String,
189 pub refresh_token: Option<String>,
190 pub id_token_claims: IdTokenClaimsWithExtra,
191 pub user_info_claims: Option<UserInfoClaimsWithExtra>,
192 pub claims_check_result: ClaimsCheckResult,
193}
194
195impl TokenSetTrait for OidcCodeCallbackResult {
196 fn access_token(&self) -> &str {
197 &self.access_token
198 }
199 fn id_token(&self) -> Option<&str> {
200 Some(&self.id_token)
201 }
202 fn refresh_token(&self) -> Option<&str> {
203 self.refresh_token.as_deref()
204 }
205 fn access_token_expiration(&self) -> Option<&DateTime<Utc>> {
206 self.access_token_expiration.as_ref()
207 }
208}
209
210pub struct OidcRefreshTokenResult {
211 pub access_token: String,
212 pub access_token_expiration: Option<DateTime<Utc>>,
213 pub id_token: Option<String>,
214 pub refresh_token: Option<String>,
215 pub id_token_claims: Option<IdTokenClaimsWithExtra>,
216 pub user_info_claims: Option<UserInfoClaimsWithExtra>,
217 pub claims_check_result: Option<ClaimsCheckResult>,
218}
219
220impl TokenSetTrait for OidcRefreshTokenResult {
221 fn access_token(&self) -> &str {
222 &self.access_token
223 }
224 fn id_token(&self) -> Option<&str> {
225 self.id_token.as_deref()
226 }
227 fn refresh_token(&self) -> Option<&str> {
228 self.refresh_token.as_deref()
229 }
230 fn access_token_expiration(&self) -> Option<&DateTime<Utc>> {
231 self.access_token_expiration.as_ref()
232 }
233}
234
235#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct UserInfoExchangeResult {
243 pub subject: String,
245 pub display_name: String,
247 #[serde(skip_serializing_if = "Option::is_none")]
249 pub picture: Option<String>,
250 #[serde(skip_serializing_if = "Option::is_none")]
252 pub issuer: Option<String>,
253 #[serde(skip_serializing_if = "Option::is_none")]
255 pub claims: Option<HashMap<String, serde_json::Value>>,
256}