1use jsonwebtoken::EncodingKey;
2
3use crate::auth::AuthenticationContext;
4
5use self::auth::{
6 AuthErrorCode, AuthErrorResponse, AuthRequest, AuthResponse, RequestPrompt, ResponseType,
7};
8
9pub mod auth;
10pub mod token;
11
12#[cfg(test)]
13pub mod tests;
14
15pub struct OAuthManager {}
16
17#[derive(Copy, Clone)]
18pub enum AuthErrorType {
19 MissingParameter = 10000,
20 MissingParameterClientId = 10001,
21 MissingParameterScope = 10002,
22 MissingParameterRedirectUri = 10003,
23 MissingParameterResponseType = 10004,
24 MissingParameterCodeChallenge = 10005,
25 InvalidParameter = 11000,
26 InvalidParameterResponseType = 11004,
27 MaxValue = 65535,
28}
29
30impl AuthErrorType {
31 fn as_u16(&mut self) -> u16 {
32 *self as u16
33 }
34}
35
36fn create_error(
37 error: AuthErrorCode,
38 error_type_code: AuthErrorType,
39 error_description: &str,
40 callback_uri: Option<String>,
41) -> AuthErrorResponse {
42 let mut error_message = String::from("");
43 let error_type = format!("WSA{:?}", error_type_code.to_owned().as_u16());
44 error_message.push_str(error_type.to_owned().as_str());
45 error_message.push_str(": ");
46 error_message.push_str(error_description);
47
48 AuthErrorResponse {
49 error: Some(error),
50 error_description: Some(error_message),
51 callback_uri: callback_uri.to_owned(),
52 }
53}
54
55fn validate_request(req: &AuthRequest) -> Option<AuthErrorResponse> {
56 let mut callback_uri = String::from("http://192.168.88.220:9000/error");
58
59 if req.redirect_uri.is_some() {
60 callback_uri = req.redirect_uri.to_owned().unwrap();
61 }
62
63 if req.client_id.is_none() {
64 return Some(create_error(
65 AuthErrorCode::InvalidRequest,
66 AuthErrorType::MissingParameterClientId,
67 "Request is missing a required parameter, `client_id`",
68 Some(callback_uri),
69 ));
70 }
71
72 if req.scope.is_none() {
73 return Some(create_error(
74 AuthErrorCode::InvalidRequest,
75 AuthErrorType::MissingParameterScope,
76 "Request is missing a required parameter, `scope`",
77 Some(callback_uri),
78 ));
79 }
80
81 if req.redirect_uri.is_none() {
82 return Some(create_error(
83 AuthErrorCode::InvalidRequest,
84 AuthErrorType::MissingParameterRedirectUri,
85 "Request is missing a required parameter, `redirect_uri`",
86 Some(callback_uri),
87 ));
88 }
89
90 if req.response_type.is_none() {
91 return Some(create_error(
92 AuthErrorCode::InvalidRequest,
93 AuthErrorType::MissingParameterResponseType,
94 "Request is missing a required parameter, `response_type`",
95 Some(callback_uri),
96 ));
97 }
98
99 if req.get_response_types().len() == 0 {
100 return Some(create_error(
101 AuthErrorCode::InvalidRequest,
102 AuthErrorType::InvalidParameterResponseType,
103 "Invalid parameter `response_type`",
104 Some(callback_uri),
105 ));
106 }
107
108 if !req.code_challenge_method.is_none() && req.code_challenge.is_none() {
109 return Some(create_error(
110 AuthErrorCode::InvalidRequest,
111 AuthErrorType::MissingParameterCodeChallenge,
112 "Request is missing a required parameter, `code_challenge`",
113 Some(callback_uri),
114 ));
115 }
116
117 return Option::None;
118}
119
120impl OAuthManager {
121 pub fn new() -> OAuthManager {
122 OAuthManager {}
123 }
124
125 pub fn authorize(
126 &mut self,
127 req: &AuthRequest,
128 ctx: &AuthenticationContext,
129 ) -> Result<AuthResponse, AuthErrorResponse> {
130 let validation_response = validate_request(req);
131
132 if !validation_response.is_none() {
133 return Err(validation_response.unwrap());
134 }
135
136 let identity = ctx.get_identity();
137
138 if (!req.prompt.is_none() && req.prompt.to_owned().unwrap() == RequestPrompt::None)
140 && identity.is_none()
141 {
142 return Err(AuthErrorResponse {
144 error: Some(AuthErrorCode::InteractionRequired),
145 error_description: Some("A user is not currently signed-in.".to_owned()),
146 callback_uri: Some("".to_owned()),
147 });
148 }
149
150 let mut response = AuthResponse {
151 code: Option::None,
152 access_token: Option::None,
153 expires_in: Option::None,
154 token_type: Option::None,
155 id_token: Option::None,
156 refresh_token: Option::None,
157 scope: Option::None,
158 state: req.state.to_owned(),
159 callback_uri: req.redirect_uri.to_owned(),
160 };
161
162 for response_type in req.get_response_types() {
163 match response_type {
164 ResponseType::Code => {
165 todo!();
166 }
167 ResponseType::Token => {
168 let signing_key =
169 EncodingKey::from_rsa_pem(&std::fs::read("localhost.key").unwrap())
170 .unwrap();
171 response.access_token = Some(identity.to_owned().unwrap().as_jwt(signing_key));
172 }
173 ResponseType::IdToken => {
174 todo!();
175 }
176 _ => {}
177 }
178 }
179
180 Ok(response)
182 }
183
184 pub fn token_exchange(
185 &mut self,
186 _req: &token::TokenRequest,
187 _ctx: &super::auth::AuthenticationContext,
188 ) {
189 }
190}