auth_framework/server/oauth/
oauth2.rs1use crate::errors::Result;
7use crate::server::core::client_registry::{ClientConfig, ClientRegistry};
8use crate::storage::core::AuthStorage;
9use serde::{Deserialize, Serialize};
10use std::sync::Arc;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct OAuth2ServerConfig {
15 pub issuer: String,
17 pub supported_scopes: Vec<String>,
19 pub supported_response_types: Vec<String>,
21 pub supported_grant_types: Vec<String>,
23}
24
25impl Default for OAuth2ServerConfig {
26 fn default() -> Self {
27 Self {
28 issuer: "https://auth.example.com".to_string(), supported_scopes: vec![
30 "openid".to_string(),
31 "profile".to_string(),
32 "email".to_string(),
33 "address".to_string(),
34 "phone".to_string(),
35 "offline_access".to_string(),
36 ],
37 supported_response_types: vec![
38 "code".to_string(),
39 "token".to_string(),
40 "id_token".to_string(),
41 "code token".to_string(),
42 "code id_token".to_string(),
43 "token id_token".to_string(),
44 "code token id_token".to_string(),
45 ],
46 supported_grant_types: vec![
47 "authorization_code".to_string(),
48 "implicit".to_string(),
49 "password".to_string(),
50 "client_credentials".to_string(),
51 "refresh_token".to_string(),
52 "urn:ietf:params:oauth:grant-type:device_code".to_string(),
53 "urn:ietf:params:oauth:grant-type:token-exchange".to_string(),
54 ],
55 }
56 }
57}
58
59#[derive(Clone)]
61pub struct OAuth2Server {
62 config: OAuth2ServerConfig,
64 client_registry: Arc<ClientRegistry>,
66}
67
68impl OAuth2Server {
69 pub async fn new(storage: Arc<dyn AuthStorage>) -> Result<Self> {
71 let client_registry = Arc::new(ClientRegistry::new(storage).await?);
72 let config = OAuth2ServerConfig::default();
73
74 Ok(Self {
75 config,
76 client_registry,
77 })
78 }
79
80 pub async fn new_with_config(
82 storage: Arc<dyn AuthStorage>,
83 config: OAuth2ServerConfig,
84 ) -> Result<Self> {
85 let client_registry = Arc::new(ClientRegistry::new(storage).await?);
86
87 Ok(Self {
88 config,
89 client_registry,
90 })
91 }
92
93 pub async fn register_client(&self, config: ClientConfig) -> Result<ClientConfig> {
95 self.client_registry.register_client(config).await
96 }
97
98 pub async fn get_client(&self, client_id: &str) -> Result<Option<ClientConfig>> {
100 self.client_registry.get_client(client_id).await
101 }
102
103 pub async fn update_client(&self, client_id: &str, config: ClientConfig) -> Result<()> {
105 self.client_registry.update_client(client_id, config).await
106 }
107
108 pub async fn delete_client(&self, client_id: &str) -> Result<()> {
110 self.client_registry.delete_client(client_id).await
111 }
112
113 pub async fn get_server_configuration(&self) -> Result<serde_json::Value> {
115 let issuer = &self.config.issuer;
118 let config = serde_json::json!({
119 "issuer": issuer,
120 "authorization_endpoint": format!("{}/oauth/authorize", issuer),
121 "token_endpoint": format!("{}/oauth/token", issuer),
122 "scopes_supported": self.config.supported_scopes,
123 "response_types_supported": self.config.supported_response_types,
124 "grant_types_supported": self.config.supported_grant_types,
125 "revocation_endpoint": format!("{}/oauth/revoke", issuer),
126 "introspection_endpoint": format!("{}/oauth/introspect", issuer)
127 });
128
129 Ok(config)
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use crate::server::core::client_registry::{ClientConfig, ClientType};
137 use crate::storage::memory::InMemoryStorage;
138
139 #[tokio::test]
140 async fn test_oauth2_server_creation() {
141 let storage = Arc::new(InMemoryStorage::new());
142 let server = OAuth2Server::new(storage).await.unwrap();
143
144 let client_config = ClientConfig {
146 client_id: "test_client".to_string(),
147 client_type: ClientType::Public,
148 redirect_uris: vec!["https://example.com/callback".to_string()],
149 ..Default::default()
150 };
151
152 let registered_client = server.register_client(client_config).await.unwrap();
153 assert_eq!(registered_client.client_id, "test_client");
154
155 let retrieved_client = server.get_client("test_client").await.unwrap().unwrap();
157 assert_eq!(retrieved_client.client_id, "test_client");
158 }
159}
160
161