1use crate::errors::{AuthError, Result};
7use crate::security::secure_utils::constant_time_compare;
8use crate::server::oauth::oauth2_enhanced_storage::{
9 EnhancedAuthorizationCode, EnhancedClientCredentials, EnhancedTokenStorage, RefreshToken,
10};
11use crate::tokens::{AuthToken, TokenManager};
12use crate::user_context::{SessionStore, UserContext};
13use serde::{Deserialize, Serialize};
14use sha2::{Digest, Sha256};
15use std::sync::Arc;
16use std::time::Duration;
17use tokio::sync::RwLock;
18
19#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
21pub enum GrantType {
22 AuthorizationCode,
23 RefreshToken,
24 ClientCredentials,
25 DeviceCode,
26 TokenExchange,
27}
28
29impl std::fmt::Display for GrantType {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 match self {
32 GrantType::AuthorizationCode => write!(f, "authorization_code"),
33 GrantType::RefreshToken => write!(f, "refresh_token"),
34 GrantType::ClientCredentials => write!(f, "client_credentials"),
35 GrantType::DeviceCode => write!(f, "urn:ietf:params:oauth:grant-type:device_code"),
36 GrantType::TokenExchange => {
37 write!(f, "urn:ietf:params:oauth:grant-type:token-exchange")
38 }
39 }
40 }
41}
42
43impl std::str::FromStr for GrantType {
44 type Err = AuthError;
45
46 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
47 match s {
48 "authorization_code" => Ok(Self::AuthorizationCode),
49 "refresh_token" => Ok(Self::RefreshToken),
50 "client_credentials" => Ok(Self::ClientCredentials),
51 "urn:ietf:params:oauth:grant-type:device_code" => Ok(Self::DeviceCode),
52 "urn:ietf:params:oauth:grant-type:token-exchange" => Ok(Self::TokenExchange),
53 other => Err(AuthError::auth_method(
54 "oauth2",
55 &format!("Unsupported grant type: {other}"),
56 )),
57 }
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
63pub enum ResponseType {
64 Code,
65 Token,
66 IdToken,
67}
68
69impl std::fmt::Display for ResponseType {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 match self {
72 ResponseType::Code => write!(f, "code"),
73 ResponseType::Token => write!(f, "token"),
74 ResponseType::IdToken => write!(f, "id_token"),
75 }
76 }
77}
78
79impl std::str::FromStr for ResponseType {
80 type Err = AuthError;
81
82 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
83 match s {
84 "code" => Ok(Self::Code),
85 "token" => Ok(Self::Token),
86 "id_token" => Ok(Self::IdToken),
87 other => Err(AuthError::auth_method(
88 "oauth2",
89 &format!("Unsupported response type: {other}"),
90 )),
91 }
92 }
93}
94
95#[derive(Debug, Clone)]
97pub struct OAuth2Config {
98 pub issuer: String,
100 pub authorization_code_lifetime: Duration,
102 pub access_token_lifetime: Duration,
104 pub refresh_token_lifetime: Duration,
106 pub device_code_lifetime: Duration,
108 pub default_scope: Option<String>,
110 pub max_scope_lifetime: Duration,
112 pub require_pkce: bool,
114 pub enable_introspection: bool,
116 pub enable_revocation: bool,
118}
119
120impl Default for OAuth2Config {
121 fn default() -> Self {
122 Self {
123 issuer: "https://auth.example.com".to_string(),
124 authorization_code_lifetime: Duration::from_secs(600), access_token_lifetime: Duration::from_secs(3600), refresh_token_lifetime: Duration::from_secs(86400 * 7), device_code_lifetime: Duration::from_secs(600), default_scope: Some("read".to_string()),
129 max_scope_lifetime: Duration::from_secs(86400 * 30), require_pkce: true,
131 enable_introspection: true,
132 enable_revocation: true,
133 }
134 }
135}
136
137impl OAuth2Config {
138 pub fn builder() -> OAuth2ConfigBuilder {
153 OAuth2ConfigBuilder::default()
154 }
155}
156
157#[derive(Debug, Clone)]
162pub struct OAuth2ConfigBuilder {
163 config: OAuth2Config,
164}
165
166impl Default for OAuth2ConfigBuilder {
167 fn default() -> Self {
168 Self {
169 config: OAuth2Config::default(),
170 }
171 }
172}
173
174impl OAuth2ConfigBuilder {
175 pub fn issuer(mut self, issuer: impl Into<String>) -> Self {
177 self.config.issuer = issuer.into();
178 self
179 }
180
181 pub fn authorization_code_lifetime(mut self, lifetime: Duration) -> Self {
183 self.config.authorization_code_lifetime = lifetime;
184 self
185 }
186
187 pub fn access_token_lifetime(mut self, lifetime: Duration) -> Self {
189 self.config.access_token_lifetime = lifetime;
190 self
191 }
192
193 pub fn refresh_token_lifetime(mut self, lifetime: Duration) -> Self {
195 self.config.refresh_token_lifetime = lifetime;
196 self
197 }
198
199 pub fn device_code_lifetime(mut self, lifetime: Duration) -> Self {
201 self.config.device_code_lifetime = lifetime;
202 self
203 }
204
205 pub fn default_scope(mut self, scope: impl Into<String>) -> Self {
207 self.config.default_scope = Some(scope.into());
208 self
209 }
210
211 pub fn max_scope_lifetime(mut self, lifetime: Duration) -> Self {
213 self.config.max_scope_lifetime = lifetime;
214 self
215 }
216
217 pub fn require_pkce(mut self, require: bool) -> Self {
219 self.config.require_pkce = require;
220 self
221 }
222
223 pub fn enable_introspection(mut self, enable: bool) -> Self {
225 self.config.enable_introspection = enable;
226 self
227 }
228
229 pub fn enable_revocation(mut self, enable: bool) -> Self {
231 self.config.enable_revocation = enable;
232 self
233 }
234
235 pub fn build(self) -> OAuth2Config {
237 self.config
238 }
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize, Default)]
263pub struct TokenRequest {
264 pub grant_type: String,
265 #[serde(default)]
268 pub client_id: Option<String>,
269 pub client_secret: Option<String>,
270 pub code: Option<String>,
271 pub redirect_uri: Option<String>,
272 pub refresh_token: Option<String>,
273 pub scope: Option<String>,
274 pub code_verifier: Option<String>,
275 pub username: Option<String>,
276 pub password: Option<String>,
277 pub device_code: Option<String>,
278 #[serde(default)]
280 pub resource: Option<Vec<String>>,
281}
282
283impl TokenRequest {
284 pub fn authorization_code(code: impl Into<String>) -> Self {
286 Self {
287 grant_type: "authorization_code".to_string(),
288 code: Some(code.into()),
289 ..Default::default()
290 }
291 }
292
293 pub fn refresh(token: impl Into<String>) -> Self {
295 Self {
296 grant_type: "refresh_token".to_string(),
297 refresh_token: Some(token.into()),
298 ..Default::default()
299 }
300 }
301
302 pub fn client_credentials(
304 client_id: impl Into<String>,
305 client_secret: impl Into<String>,
306 ) -> Self {
307 Self {
308 grant_type: "client_credentials".to_string(),
309 client_id: Some(client_id.into()),
310 client_secret: Some(client_secret.into()),
311 ..Default::default()
312 }
313 }
314
315 pub fn client_id(mut self, id: impl Into<String>) -> Self {
317 self.client_id = Some(id.into());
318 self
319 }
320
321 pub fn client_secret(mut self, secret: impl Into<String>) -> Self {
323 self.client_secret = Some(secret.into());
324 self
325 }
326
327 pub fn redirect_uri(mut self, uri: impl Into<String>) -> Self {
329 self.redirect_uri = Some(uri.into());
330 self
331 }
332
333 pub fn code_verifier(mut self, verifier: impl Into<String>) -> Self {
335 self.code_verifier = Some(verifier.into());
336 self
337 }
338
339 pub fn scope(mut self, scope: impl Into<String>) -> Self {
341 self.scope = Some(scope.into());
342 self
343 }
344
345 pub fn resource(mut self, uris: Vec<String>) -> Self {
347 self.resource = Some(uris);
348 self
349 }
350}
351
352#[derive(Debug, Clone, Serialize, Deserialize)]
354pub struct TokenResponse {
355 pub access_token: String,
356 pub token_type: String,
357 pub expires_in: u64,
358 pub refresh_token: Option<String>,
359 pub scope: Option<String>,
360 pub id_token: Option<String>,
361}
362
363#[derive(Debug, Clone, Serialize, Deserialize)]
376pub struct AuthorizationRequest {
377 pub client_id: String,
378 pub response_type: String,
379 pub redirect_uri: String,
380 pub scope: Option<String>,
381 pub state: Option<String>,
382 pub code_challenge: Option<String>,
383 pub code_challenge_method: Option<String>,
384 pub nonce: Option<String>,
385 #[serde(default)]
387 pub resource: Option<Vec<String>>,
388}
389
390impl AuthorizationRequest {
391 pub fn new(
393 client_id: impl Into<String>,
394 response_type: impl Into<String>,
395 redirect_uri: impl Into<String>,
396 ) -> Self {
397 Self {
398 client_id: client_id.into(),
399 response_type: response_type.into(),
400 redirect_uri: redirect_uri.into(),
401 scope: None,
402 state: None,
403 code_challenge: None,
404 code_challenge_method: None,
405 nonce: None,
406 resource: None,
407 }
408 }
409
410 pub fn scope(mut self, scope: impl Into<String>) -> Self {
412 self.scope = Some(scope.into());
413 self
414 }
415
416 pub fn state(mut self, state: impl Into<String>) -> Self {
418 self.state = Some(state.into());
419 self
420 }
421
422 pub fn pkce(mut self, challenge: impl Into<String>, method: impl Into<String>) -> Self {
424 self.code_challenge = Some(challenge.into());
425 self.code_challenge_method = Some(method.into());
426 self
427 }
428
429 pub fn nonce(mut self, nonce: impl Into<String>) -> Self {
431 self.nonce = Some(nonce.into());
432 self
433 }
434
435 pub fn resource(mut self, uris: Vec<String>) -> Self {
437 self.resource = Some(uris);
438 self
439 }
440}
441
442pub struct OAuth2Server {
444 config: OAuth2Config,
445 token_storage: Arc<RwLock<EnhancedTokenStorage>>,
446 session_store: Arc<RwLock<SessionStore>>,
447 token_manager: Arc<TokenManager>,
448}
449
450impl OAuth2Server {
451 pub async fn new(config: OAuth2Config, token_manager: Arc<TokenManager>) -> Result<Self> {
452 Ok(Self {
453 config,
454 token_storage: Arc::new(RwLock::new(EnhancedTokenStorage::new())),
455 session_store: Arc::new(RwLock::new(SessionStore::new())),
456 token_manager,
457 })
458 }
459
460 pub async fn register_confidential_client(
462 &self,
463 client_id: String,
464 client_secret: &str,
465 redirect_uris: Vec<String>,
466 allowed_scopes: Vec<String>,
467 grant_types: Vec<String>,
468 ) -> Result<()> {
469 if client_secret.len() < 32 {
471 return Err(AuthError::auth_method(
472 "oauth2",
473 "Client secret must be at least 32 characters",
474 ));
475 }
476
477 let credentials = EnhancedClientCredentials::new_confidential(
478 client_id,
479 client_secret,
480 redirect_uris,
481 allowed_scopes,
482 grant_types,
483 )?;
484
485 let mut storage = self.token_storage.write().await;
486 storage.store_client_credentials(credentials).await?;
487
488 Ok(())
489 }
490
491 pub async fn register_public_client(
493 &self,
494 client_id: String,
495 redirect_uris: Vec<String>,
496 allowed_scopes: Vec<String>,
497 grant_types: Vec<String>,
498 ) -> Result<()> {
499 let credentials = EnhancedClientCredentials::new_public(
500 client_id,
501 redirect_uris,
502 allowed_scopes,
503 grant_types,
504 );
505
506 let mut storage = self.token_storage.write().await;
507 storage.store_client_credentials(credentials).await?;
508
509 Ok(())
510 }
511
512 pub async fn create_authorization_code(
514 &self,
515 request: AuthorizationRequest,
516 user_context: UserContext,
517 ) -> Result<EnhancedAuthorizationCode> {
518 let storage = self.token_storage.read().await;
520 let client = storage
521 .get_client_credentials(&request.client_id)
522 .await?
523 .ok_or_else(|| AuthError::auth_method("oauth2", "Invalid client_id"))?;
524
525 if !client.supports_grant_type("authorization_code") {
526 return Err(AuthError::auth_method(
527 "oauth2",
528 "Client does not support authorization code grant",
529 ));
530 }
531
532 if !client.redirect_uris.contains(&request.redirect_uri) {
533 return Err(AuthError::auth_method("oauth2", "Invalid redirect_uri"));
534 }
535
536 let requested_scopes = self.parse_scopes(request.scope.as_deref())?;
538 let authorized_scopes = self.authorize_scopes(&client, &user_context, &requested_scopes)?;
539
540 let auth_code = EnhancedAuthorizationCode::new(
542 client.client_id.clone(),
543 user_context.user_id.clone(), request.redirect_uri,
545 authorized_scopes,
546 request.code_challenge,
547 request.code_challenge_method,
548 self.config.authorization_code_lifetime,
549 );
550
551 drop(storage);
553 let mut storage = self.token_storage.write().await;
554 storage.store_authorization_code(auth_code.clone()).await?;
555
556 Ok(auth_code)
557 }
558
559 pub async fn token_exchange(&self, request: TokenRequest) -> Result<TokenResponse> {
561 match request.grant_type.as_str() {
562 "authorization_code" => self.handle_authorization_code_grant(request).await,
563 "refresh_token" => self.handle_refresh_token_grant(request).await,
564 "client_credentials" => self.handle_client_credentials_grant(request).await,
565 _ => Err(AuthError::auth_method("oauth2", "Unsupported grant type")),
566 }
567 }
568
569 async fn handle_authorization_code_grant(
571 &self,
572 request: TokenRequest,
573 ) -> Result<TokenResponse> {
574 let client_id = request
575 .client_id
576 .ok_or_else(|| AuthError::auth_method("oauth2", "client_id is required"))?;
577 let storage = self.token_storage.read().await;
579 let _client = storage
580 .get_client_credentials(&client_id)
581 .await?
582 .ok_or_else(|| AuthError::auth_method("oauth2", "Invalid client_id"))?;
583
584 if !storage
586 .validate_client_credentials(&client_id, request.client_secret.as_deref())
587 .await?
588 {
589 return Err(AuthError::auth_method(
590 "oauth2",
591 "Invalid client credentials",
592 ));
593 }
594
595 let code = request
597 .code
598 .ok_or_else(|| AuthError::auth_method("oauth2", "Missing authorization code"))?;
599
600 drop(storage);
601 let mut storage = self.token_storage.write().await;
602 let auth_code = storage
603 .consume_authorization_code(&code)
604 .await?
605 .ok_or_else(|| {
606 AuthError::auth_method("oauth2", "Invalid or expired authorization code")
607 })?;
608
609 if auth_code.client_id != client_id {
611 return Err(AuthError::auth_method(
612 "oauth2",
613 "Authorization code does not belong to client",
614 ));
615 }
616
617 if let Some(challenge) = &auth_code.code_challenge {
619 let verifier = request
620 .code_verifier
621 .ok_or_else(|| AuthError::auth_method("oauth2", "PKCE code verifier required"))?;
622
623 if !self.validate_pkce_challenge(
624 challenge,
625 &verifier,
626 &auth_code.code_challenge_method,
627 )? {
628 return Err(AuthError::auth_method(
629 "oauth2",
630 "Invalid PKCE code verifier",
631 ));
632 }
633 }
634
635 let access_token = self
637 .generate_access_token(
638 &auth_code.client_id,
639 Some(&auth_code.user_id), &auth_code.scopes,
641 )
642 .await?;
643
644 let refresh_token = RefreshToken::new(
646 auth_code.client_id.clone(),
647 auth_code.user_id.clone(), auth_code.scopes.clone(), self.config.refresh_token_lifetime,
650 );
651
652 let refresh_token_id = storage.store_refresh_token(refresh_token).await?;
653
654 Ok(TokenResponse {
655 access_token: access_token.access_token,
656 token_type: "Bearer".to_string(),
657 expires_in: self.config.access_token_lifetime.as_secs(),
658 refresh_token: Some(refresh_token_id),
659 scope: Some(auth_code.scopes.join(" ")),
660 id_token: None,
661 })
662 }
663
664 async fn handle_refresh_token_grant(&self, request: TokenRequest) -> Result<TokenResponse> {
666 let client_id = request
667 .client_id
668 .ok_or_else(|| AuthError::auth_method("oauth2", "client_id is required"))?;
669 let storage = self.token_storage.read().await;
671 if !storage
672 .validate_client_credentials(&client_id, request.client_secret.as_deref())
673 .await?
674 {
675 return Err(AuthError::auth_method(
676 "oauth2",
677 "Invalid client credentials",
678 ));
679 }
680
681 let refresh_token_id = request
683 .refresh_token
684 .ok_or_else(|| AuthError::auth_method("oauth2", "Missing refresh token"))?;
685
686 let stored_token = storage
688 .get_refresh_token(&refresh_token_id)
689 .await?
690 .ok_or_else(|| AuthError::auth_method("oauth2", "Invalid refresh token"))?;
691
692 if !stored_token.is_valid() {
693 return Err(AuthError::auth_method(
694 "oauth2",
695 "Refresh token is expired or revoked",
696 ));
697 }
698
699 if stored_token.client_id != client_id {
701 return Err(AuthError::auth_method(
702 "oauth2",
703 "Refresh token does not belong to client",
704 ));
705 }
706
707 let requested_scopes = self.parse_scopes(request.scope.as_deref())?;
709 let authorized_scopes = if requested_scopes.is_empty() {
710 stored_token.scopes.clone() } else {
712 self.validate_scope_subset(&stored_token.scopes, &requested_scopes)?
713 };
714
715 drop(storage);
716
717 let access_token = self
719 .generate_access_token(
720 &stored_token.client_id,
721 Some(&stored_token.user_id), &authorized_scopes,
723 )
724 .await?;
725
726 let mut storage = self.token_storage.write().await;
728 storage.revoke_refresh_token(&refresh_token_id).await?; let new_refresh_token = RefreshToken::new(
731 stored_token.client_id.clone(),
732 stored_token.user_id.clone(),
733 authorized_scopes.clone(),
734 self.config.refresh_token_lifetime,
735 );
736
737 let new_refresh_token_id = storage.store_refresh_token(new_refresh_token).await?;
738
739 Ok(TokenResponse {
740 access_token: access_token.access_token,
741 token_type: "Bearer".to_string(),
742 expires_in: self.config.access_token_lifetime.as_secs(),
743 refresh_token: Some(new_refresh_token_id),
744 scope: Some(authorized_scopes.join(" ")),
745 id_token: None,
746 })
747 }
748
749 async fn handle_client_credentials_grant(
751 &self,
752 request: TokenRequest,
753 ) -> Result<TokenResponse> {
754 let client_id = request
755 .client_id
756 .ok_or_else(|| AuthError::auth_method("oauth2", "client_id is required"))?;
757 let storage = self.token_storage.read().await;
759 let client = storage
760 .get_client_credentials(&client_id)
761 .await?
762 .ok_or_else(|| AuthError::auth_method("oauth2", "Invalid client_id"))?;
763
764 if !storage
766 .validate_client_credentials(&client_id, request.client_secret.as_deref())
767 .await?
768 {
769 return Err(AuthError::auth_method(
770 "oauth2",
771 "Invalid client credentials",
772 ));
773 }
774
775 if !client.supports_grant_type("client_credentials") {
776 return Err(AuthError::auth_method(
777 "oauth2",
778 "Client does not support client credentials grant",
779 ));
780 }
781
782 let requested_scopes = self.parse_scopes(request.scope.as_deref())?;
784 let authorized_scopes = requested_scopes
785 .iter()
786 .filter(|scope| client.has_scope(scope))
787 .cloned()
788 .collect::<Vec<_>>();
789
790 if authorized_scopes.is_empty() && !requested_scopes.is_empty() {
791 return Err(AuthError::auth_method("oauth2", "No authorized scopes"));
792 }
793
794 drop(storage);
795
796 let access_token = self
798 .generate_access_token(&client_id, None, &authorized_scopes)
799 .await?;
800
801 Ok(TokenResponse {
802 access_token: access_token.access_token,
803 token_type: "Bearer".to_string(),
804 expires_in: self.config.access_token_lifetime.as_secs(),
805 refresh_token: None, scope: Some(authorized_scopes.join(" ")),
807 id_token: None,
808 })
809 }
810
811 async fn generate_access_token(
813 &self,
814 client_id: &str,
815 user_id: Option<&str>,
816 scopes: &[String],
817 ) -> Result<AuthToken> {
818 let subject = user_id.unwrap_or(client_id);
819 let mut token = self.token_manager.create_auth_token(
820 subject,
821 crate::types::Scopes::from(
822 scopes
823 .iter()
824 .map(|s| s.to_string())
825 .collect::<Vec<String>>(),
826 ),
827 "oauth2",
828 Some(self.config.access_token_lifetime),
829 )?;
830
831 token.add_custom_claim(
833 "client_id".to_string(),
834 serde_json::Value::String(client_id.to_string()),
835 );
836
837 if let Some(uid) = user_id {
839 token.add_custom_claim(
840 "user_id".to_string(),
841 serde_json::Value::String(uid.to_string()),
842 );
843 }
844
845 Ok(token)
846 }
847
848 fn parse_scopes(&self, scope_str: Option<&str>) -> Result<Vec<String>> {
850 match scope_str {
851 Some(scopes) => Ok(scopes.split_whitespace().map(|s| s.to_string()).collect()),
852 None => match &self.config.default_scope {
853 Some(default) => Ok(vec![default.clone()]),
854 None => Ok(vec![]),
855 },
856 }
857 }
858
859 fn authorize_scopes(
861 &self,
862 client: &EnhancedClientCredentials,
863 user_context: &UserContext,
864 requested_scopes: &[String],
865 ) -> Result<Vec<String>> {
866 let mut authorized = Vec::new();
867
868 for scope in requested_scopes {
869 if client.has_scope(scope) {
871 if user_context.has_scope(scope) {
873 authorized.push(scope.clone());
874 }
875 }
876 }
877
878 if authorized.is_empty() && !requested_scopes.is_empty() {
879 return Err(AuthError::auth_method("oauth2", "No authorized scopes"));
880 }
881
882 Ok(authorized)
883 }
884
885 fn validate_scope_subset(
887 &self,
888 original_scopes: &[String],
889 requested_scopes: &[String],
890 ) -> Result<Vec<String>> {
891 let mut validated = Vec::new();
892
893 for scope in requested_scopes {
894 if original_scopes.contains(scope) {
895 validated.push(scope.clone());
896 } else {
897 return Err(AuthError::auth_method(
898 "oauth2",
899 format!("Requested scope '{}' not in original grant", scope),
900 ));
901 }
902 }
903
904 Ok(validated)
905 }
906
907 fn validate_pkce_challenge(
909 &self,
910 challenge: &str,
911 verifier: &str,
912 method: &Option<String>,
913 ) -> Result<bool> {
914 let method = method.as_deref().unwrap_or("plain");
915
916 match method {
917 "plain" => Ok(constant_time_compare(
918 challenge.as_bytes(),
919 verifier.as_bytes(),
920 )),
921 "S256" => {
922 use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
923 use sha2::{Digest, Sha256};
924
925 let hash = Sha256::digest(verifier.as_bytes());
926 let encoded = URL_SAFE_NO_PAD.encode(hash);
927 Ok(constant_time_compare(
928 challenge.as_bytes(),
929 encoded.as_bytes(),
930 ))
931 }
932 _ => Err(AuthError::auth_method("oauth2", "Unsupported PKCE method")),
933 }
934 }
935
936 pub async fn revoke_token(&self, token: &str, client_id: &str) -> Result<bool> {
938 let mut storage = self.token_storage.write().await;
939
940 if client_id.is_empty() {
942 return Err(AuthError::auth_method(
943 "oauth2",
944 "Client ID is required for token revocation",
945 ));
946 }
947
948 if storage.get_client_credentials(client_id).await.is_err() {
950 return Err(AuthError::auth_method("oauth2", "Invalid client"));
951 }
952
953 if storage.validate_refresh_token(token).await? {
955 return storage.revoke_refresh_token(token).await;
956 }
957
958 Ok(false)
961 }
962
963 pub async fn cleanup_expired_tokens(&self) -> Result<usize> {
965 let mut storage = self.token_storage.write().await;
966 storage.cleanup_expired_tokens().await
967 }
968
969 pub async fn add_user_credentials(
976 &self,
977 creds: crate::server::oauth::oauth2_enhanced_storage::UserCredentials,
978 ) -> Result<()> {
979 let mut storage = self.token_storage.write().await;
980 storage.store_user_credentials(creds).await
981 }
982
983 pub async fn authenticate_user(
985 &self,
986 username: &str,
987 password: &str,
988 scopes: Vec<String>,
989 ) -> Result<UserContext> {
990 let storage = self.token_storage.read().await;
992
993 if !self
995 .validate_user_credentials_against_storage(&storage, username, password)
996 .await?
997 {
998 return Err(AuthError::auth_method(
999 "oauth2",
1000 "Invalid username or password",
1001 ));
1002 }
1003
1004 let authorized_scopes = self
1006 .validate_user_scopes_against_storage(&storage, username, &scopes)
1007 .await?;
1008
1009 drop(storage);
1010
1011 let user_context = UserContext::new(
1013 self.generate_user_id(username).await?,
1014 username.to_string(),
1015 self.get_user_email(username).await?,
1016 )
1017 .with_scopes(authorized_scopes);
1018
1019 let mut session_store = self.session_store.write().await;
1020 session_store.create_session(user_context.clone());
1021
1022 Ok(user_context)
1023 }
1024
1025 async fn validate_user_credentials_against_storage(
1027 &self,
1028 storage: &EnhancedTokenStorage,
1029 username: &str,
1030 password: &str,
1031 ) -> Result<bool> {
1032 let is_empty = username.is_empty() || password.is_empty();
1034 let is_too_short = password.len() < 8;
1035
1036 match storage.get_user_credentials(username).await {
1038 Ok(Some(stored_credentials)) => {
1039 use bcrypt::verify;
1041 match verify(password, &stored_credentials.password_hash) {
1042 Ok(is_valid) => {
1043 Ok(is_valid && !is_empty && !is_too_short)
1045 }
1046 Err(_) => {
1047 Ok(false)
1049 }
1050 }
1051 }
1052 Ok(None) => {
1053 use bcrypt::verify;
1055 let _dummy_result = verify(
1056 password,
1057 "$2b$12$K2CtDP7zMH7VgxScmHTa/.EUm5nd9.xnZM8Cl/p9RMb5QZaJUHgBm",
1058 );
1059 Ok(false)
1060 }
1061 Err(_) => {
1062 use bcrypt::verify;
1064 let _dummy_result = verify(
1065 password,
1066 "$2b$12$K2CtDP7zMH7VgxScmHTa/.EUm5nd9.xnZM8Cl/p9RMb5QZaJUHgBm",
1067 );
1068 Ok(false)
1069 }
1070 }
1071 }
1072
1073 async fn validate_user_scopes_against_storage(
1075 &self,
1076 storage: &EnhancedTokenStorage,
1077 username: &str,
1078 requested_scopes: &[String],
1079 ) -> Result<Vec<String>> {
1080 let user_permissions = match storage.get_user_permissions(username).await {
1082 Ok(Some(permissions)) => permissions.scopes,
1083 Ok(None) => {
1084 return Err(AuthError::auth_method(
1085 "oauth2",
1086 "User not found in permission store",
1087 ));
1088 }
1089 Err(_) => {
1090 return Err(AuthError::auth_method(
1091 "oauth2",
1092 "Failed to retrieve user permissions",
1093 ));
1094 }
1095 };
1096
1097 let mut authorized = Vec::new();
1098 for scope in requested_scopes {
1099 if user_permissions.contains(scope) {
1100 authorized.push(scope.clone());
1101 }
1102 }
1103
1104 if authorized.is_empty() && !requested_scopes.is_empty() {
1106 return Err(AuthError::auth_method(
1107 "oauth2",
1108 "User not authorized for requested scopes",
1109 ));
1110 }
1111
1112 if authorized.is_empty() {
1113 if user_permissions.contains(&"read".to_string()) {
1115 authorized.push("read".to_string());
1116 } else {
1117 return Err(AuthError::auth_method(
1118 "oauth2",
1119 "User has no authorized scopes",
1120 ));
1121 }
1122 }
1123
1124 Ok(authorized)
1125 }
1126
1127 async fn generate_user_id(&self, username: &str) -> Result<String> {
1129 let hash = Sha256::digest(format!("user_id_{}", username).as_bytes());
1132 let hash_str = format!("{:x}", hash);
1133 Ok(format!("user_{}", &hash_str[0..16]))
1134 }
1135
1136 async fn get_user_email(&self, username: &str) -> Result<Option<String>> {
1138 let storage = self.token_storage.read().await;
1139 match storage.get_user_credentials(username).await {
1140 Ok(Some(creds)) => Ok(creds.email),
1141 _ => Ok(None),
1143 }
1144 }
1145
1146 pub async fn get_user_context(&self, session_id: &str) -> Result<Option<UserContext>> {
1148 let session_store = self.session_store.read().await;
1149 Ok(session_store.get_session(session_id).cloned())
1150 }
1151
1152 pub async fn invalidate_session(&self, session_id: &str) -> Result<bool> {
1154 let mut session_store = self.session_store.write().await;
1155 Ok(session_store.invalidate_session(session_id))
1156 }
1157}