ones_oidc/
oidc_types.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
use super::{IdentifierType, NewIdentifier};
use openidconnect::ClientId;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Debug, Clone)]
pub struct AuthenticatedEntity {
    pub entity: AuthenticatedEntityKind,
    pub method: AuthenticationMethod,
    /**
     *  - https://idp.example.com/oidc
     */
    pub iss: String,
    /**
     * - User: User ID (IDP)
     * - Device: Device ID (IDP)
     * - Mobile: User ID (IDP)
     */
    pub subject: Uuid,
    /**
     * - User: User ID (IDP, local user record)
     * - Device: Relay ID (local relay record)
     */
    pub entity_id: Uuid,
    pub aud: Option<Uuid>,
    pub scope: Option<String>,
    pub has_idp_master_role: bool,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct AuthenticationResult {
    pub entity: AuthenticatedEntityKind,
    pub iss: String,
    pub sub: Uuid,
    pub aud: Option<Uuid>,
    pub scope: Option<String>,
    pub username: Option<String>,
    pub client_id: Option<String>,
    pub method: AuthenticationMethod,
    /** User role claim */
    pub idp_role: Option<String>,
}

impl AuthenticationResult {
    pub fn get_user_identifiers(&self) -> Vec<NewIdentifier> {
        let mut user_identifier = Vec::new();
        let identifier = NewIdentifier {
            kind: IdentifierType::UserId,
            value: self.sub.to_string(),
            issuer: self.iss.clone(),
            user_id: self.sub,
        };
        user_identifier.push(identifier);
        if self.username.is_some() {
            let identifier = NewIdentifier {
                kind: IdentifierType::Username,
                value: self.username.clone().unwrap(),
                issuer: self.iss.clone(),
                user_id: self.sub,
            };
            user_identifier.push(identifier);
        }
        if self.client_id.is_some() {
            let identifier = NewIdentifier {
                kind: IdentifierType::UserClientId,
                value: self.client_id.clone().unwrap().to_string(),
                issuer: self.iss.clone(),
                user_id: self.sub,
            };
            user_identifier.push(identifier);
        }
        user_identifier
    }
}

/**
 * - UserJWT: Best case
 * - UserDevice: only client_id (user mobile), exp, iat, iss, token_type
 * - UserIdp: exp, iat, iss, token_type, scope, sub
 */
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub enum AuthenticationMethod {
    UserJwt,
    UserDevice,
    UserIdp,
    IdpJwt,
    Device,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct JwtPayload {
    pub iss: String,
    // #[serde(skip_serializing_if = "Option::is_none")]
    pub sub: Uuid,
    pub aud: Option<String>,
    pub jti: Option<String>,
    pub iat: u64,
    pub exp: u64,
    pub nbf: Option<u64>,
    pub scope: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub binding_message: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub login_hint: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub login_hint_token: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub resource: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub client_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub username: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub user_client_id: Option<String>,
    /** User role claim */
    #[serde(skip_serializing_if = "Option::is_none")]
    pub idp_role: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub qr_session_id: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum LoginHintKind {
    LoginHint,
    LoginHintToken,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct LoginHint {
    pub kind: LoginHintKind,
    pub value: String,
}

#[derive(Deserialize, Debug)]
pub struct OidcErrorResponse {
    pub error: String,
    pub error_description: String,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum AuthenticatedEntityKind {
    Device,
    User,
}

// Mobile {"active":true,"client_id":"RJq3ENpGMioYZetmY01r4","exp":1721239533,"iat":1721238933,"iss":"http://127.0.0.1:4000/oidc","token_type":"Bearer"}
// User {"active":true,"client_id":"d4cb9c70-ce95-4ebd-9238-3809da722564","exp":1721243491,"iat":1721239891,"iss":"http://127.0.0.1:4000/oidc","scope":"openid offline_access profile","sub":"a9fa6083-10a2-4128-829e-df20ed9b43af","token_type":"Bearer"}

#[derive(Serialize, Deserialize, Debug)]
pub struct ClientCredentialsIntrospection {
    /** Mobile, User */
    pub active: bool,
    /** Mobile, User */
    pub client_id: Option<ClientId>,
    /** Mobile, User */
    pub exp: u64,
    pub iat: u64,
    /** Mobile, User */
    pub iss: String,
    /** Mobile, User */
    pub token_type: String,
    /** User */
    pub scope: Option<String>,
    /** User */
    pub sub: Option<String>,
    /** User role claim */
    pub idp_role: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct CibaResponse {
    // #[serde(rename = "authRequestId")]
    pub auth_req_id: String,
    pub expires_in: u64,
    pub interval: Option<u64>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct CibaStatusResponse {
    access_token: String,
    expires_in: u64,
    id_token: Option<String>,
    refresh_token: Option<String>,
    scope: String,
    token_type: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct SubjectIdentity {
    pub subject_type: AuthenticatedEntityKind,
    pub subject: Uuid,
    pub username: Option<String>,
    pub client_id: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub enum LoginStrategy {
    #[serde(rename = "bc")]
    Ciba,
    #[serde(rename = "qr")]
    Qr,
    #[serde(rename = "qr_client")]
    QrClient,
    #[serde(rename = "qr_legacy")]
    QrLegacy,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct QrAuthSessionIdp {
    pub kind: LoginStrategy,
    // transform from sessionId
    #[serde(rename = "sessionId")]
    pub session_id: String,
    // transform from cbUrl
    #[serde(rename = "cbUrl")]
    pub cb_url: String,
    // transform from expIn
    #[serde(rename = "expIn")]
    pub exp_in: u64,
    // transform from exp
    pub exp: Option<u64>,
    pub interval: u64,
    pub aud: Option<String>,
    // transform from authRequestId
    #[serde(rename = "authRequestId")]
    pub auth_request_id: Option<String>,
    // transform from cibaRequestInvoked
    #[serde(rename = "cibaRequestInvoked")]
    pub ciba_request_invoked: bool,
    // transform from loginHintToken
    #[serde(rename = "loginHintToken")]
    pub login_hint_token: Option<String>,
}