mz_frontegg_mock/handlers/
auth.rs1use crate::models::*;
11use crate::server::Context;
12use crate::utils::{
13 RefreshTokenTarget, generate_access_token, generate_refresh_token, get_user_groups,
14};
15use axum::{Json, extract::State, http::StatusCode};
16use mz_frontegg_auth::{ApiTokenResponse, ClaimTokenType};
17use serde::{Deserialize, Serialize};
18use std::sync::Arc;
19use std::sync::atomic::Ordering;
20
21pub async fn handle_post_auth_api_token(
22 State(context): State<Arc<Context>>,
23 Json(request): Json<ApiToken>,
24) -> Result<Json<ApiTokenResponse>, StatusCode> {
25 *context.auth_requests.lock().unwrap() += 1;
26
27 if !context.enable_auth.load(Ordering::Relaxed) {
28 return Err(StatusCode::UNAUTHORIZED);
29 }
30
31 let user_api_tokens = context.user_api_tokens.lock().unwrap();
32 let access_token = match user_api_tokens
33 .iter()
34 .find(|(token, _)| token.client_id == request.client_id && token.secret == request.secret)
35 {
36 Some((_, email)) => {
37 let users = context.users.lock().unwrap();
38 let user = users
39 .get(email)
40 .expect("API tokens are only created by logged in valid users.");
41 let groups = get_user_groups(&context, &user.id);
42 generate_access_token(
43 &context,
44 ClaimTokenType::UserApiToken,
45 request.client_id,
46 Some(email.to_owned()),
47 Some(user.id),
48 user.tenant_id,
49 user.roles.clone(),
50 groups,
51 None,
52 )
53 }
54 None => {
55 let tenant_api_tokens = context.tenant_api_tokens.lock().unwrap();
56 match tenant_api_tokens.iter().find(|(token, _)| {
57 token.client_id == request.client_id && token.secret == request.secret
58 }) {
59 Some((_, config)) => generate_access_token(
60 &context,
61 ClaimTokenType::TenantApiToken,
62 request.client_id,
63 None,
64 None,
65 config.tenant_id,
66 config.roles.clone(),
67 Vec::new(),
68 config.metadata.clone(),
69 ),
70 None => return Err(StatusCode::UNAUTHORIZED),
71 }
72 }
73 };
74 let refresh_token = generate_refresh_token(&context, RefreshTokenTarget::ApiToken(request));
75 Ok(Json(ApiTokenResponse {
76 expires: "".to_string(),
77 expires_in: context.expires_in_secs,
78 access_token,
79 refresh_token,
80 }))
81}
82
83pub async fn handle_post_auth_user(
84 State(context): State<Arc<Context>>,
85 Json(request): Json<AuthUserRequest>,
86) -> Result<Json<ApiTokenResponse>, StatusCode> {
87 *context.auth_requests.lock().unwrap() += 1;
88
89 if !context.enable_auth.load(Ordering::Relaxed) {
90 return Err(StatusCode::UNAUTHORIZED);
91 }
92
93 let users = context.users.lock().unwrap();
94 let user = match users.get(&request.email) {
95 Some(user) if request.password == user.password => user.to_owned(),
96 _ => return Err(StatusCode::UNAUTHORIZED),
97 };
98 let groups = get_user_groups(&context, &user.id);
99 let access_token = generate_access_token(
100 &context,
101 ClaimTokenType::UserToken,
102 user.id,
103 Some(request.email.clone()),
104 Some(user.id),
105 user.tenant_id,
106 user.roles.clone(),
107 groups,
108 None,
109 );
110 let refresh_token = generate_refresh_token(&context, RefreshTokenTarget::User(request));
111 Ok(Json(ApiTokenResponse {
112 expires: "".to_string(),
113 expires_in: context.expires_in_secs,
114 access_token,
115 refresh_token,
116 }))
117}
118
119pub async fn handle_post_token_refresh(
120 State(context): State<Arc<Context>>,
121 Json(previous_refresh_token): Json<RefreshTokenRequest>,
122) -> Result<Json<ApiTokenResponse>, StatusCode> {
123 *context.refreshes.lock().unwrap() += 1;
125
126 if !context.enable_auth.load(Ordering::Relaxed) {
127 return Err(StatusCode::UNAUTHORIZED);
128 }
129
130 let maybe_target = context
131 .refresh_tokens
132 .lock()
133 .unwrap()
134 .remove(&previous_refresh_token.refresh_token);
135 let Some(target) = maybe_target else {
136 return Err(StatusCode::UNAUTHORIZED);
137 };
138
139 match target {
140 RefreshTokenTarget::User(request) => {
141 handle_post_auth_user(State(context), Json(request)).await
142 }
143 RefreshTokenTarget::ApiToken(request) => {
144 handle_post_auth_api_token(State(context), Json(request)).await
145 }
146 }
147}
148
149#[derive(Debug, Clone, Deserialize)]
151#[serde(rename_all = "camelCase")]
152pub struct VendorAuthRequest {
153 pub client_id: String,
154 pub secret: String,
155}
156
157#[derive(Debug, Clone, Serialize)]
159#[serde(rename_all = "camelCase")]
160pub struct VendorAuthResponse {
161 pub token: String,
162 pub expires_in: i64,
163}
164
165pub async fn handle_post_auth_vendor(
168 State(context): State<Arc<Context>>,
169 Json(_request): Json<VendorAuthRequest>,
170) -> Result<Json<VendorAuthResponse>, StatusCode> {
171 let now_secs = context.now.as_secs();
174 let exp_secs = now_secs + context.expires_in_secs;
175 let token = jsonwebtoken::encode(
176 &jsonwebtoken::Header::new(jsonwebtoken::Algorithm::RS256),
177 &serde_json::json!({
178 "sub": "vendor",
179 "iss": context.issuer,
180 "iat": now_secs,
181 "exp": exp_secs,
182 }),
183 &context.encoding_key,
184 )
185 .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
186
187 Ok(Json(VendorAuthResponse {
188 token,
189 expires_in: context.expires_in_secs,
190 }))
191}