Update for auth
parent: tbd commit: 3ef0383
Showing 7 changed files with 106 insertions and 24 deletions
giterated-daemon/.sqlx/query-4707bb69d91fa6df545148c281bae53365c53011bea92e75996f030397ae6b07.json
@@ -0,0 +1,16 @@ | ||
1 | { | |
2 | "db_name": "PostgreSQL", | |
3 | "query": "INSERT INTO repository_settings VALUES ($1, $2, $3) ON CONFLICT (repository, name) DO UPDATE SET value = $3", | |
4 | "describe": { | |
5 | "columns": [], | |
6 | "parameters": { | |
7 | "Left": [ | |
8 | "Text", | |
9 | "Text", | |
10 | "Text" | |
11 | ] | |
12 | }, | |
13 | "nullable": [] | |
14 | }, | |
15 | "hash": "4707bb69d91fa6df545148c281bae53365c53011bea92e75996f030397ae6b07" | |
16 | } |
giterated-daemon/.sqlx/query-d20bc04a9a3883bc2dbd9068d1a77264fff64d9f220f95b78f35e4f371cce160.json
@@ -0,0 +1,34 @@ | ||
1 | { | |
2 | "db_name": "PostgreSQL", | |
3 | "query": "SELECT * FROM repository_settings WHERE repository = $1", | |
4 | "describe": { | |
5 | "columns": [ | |
6 | { | |
7 | "ordinal": 0, | |
8 | "name": "repository", | |
9 | "type_info": "Text" | |
10 | }, | |
11 | { | |
12 | "ordinal": 1, | |
13 | "name": "name", | |
14 | "type_info": "Text" | |
15 | }, | |
16 | { | |
17 | "ordinal": 2, | |
18 | "name": "value", | |
19 | "type_info": "Text" | |
20 | } | |
21 | ], | |
22 | "parameters": { | |
23 | "Left": [ | |
24 | "Text" | |
25 | ] | |
26 | }, | |
27 | "nullable": [ | |
28 | false, | |
29 | false, | |
30 | false | |
31 | ] | |
32 | }, | |
33 | "hash": "d20bc04a9a3883bc2dbd9068d1a77264fff64d9f220f95b78f35e4f371cce160" | |
34 | } |
giterated-daemon/src/backend/user.rs
@@ -3,7 +3,7 @@ use std::sync::Arc; | ||
3 | 3 | use anyhow::Error; |
4 | 4 | |
5 | 5 | use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, Key, KeyInit}; |
6 | use argon2::{password_hash::SaltString, Argon2, PasswordHasher}; | |
6 | use argon2::{password_hash::SaltString, Argon2, PasswordHasher, PasswordHash, PasswordVerifier}; | |
7 | 7 | use base64::{engine::general_purpose::STANDARD, Engine as _}; |
8 | 8 | use giterated_models::{ |
9 | 9 | messages::{ |
@@ -19,7 +19,7 @@ use giterated_models::{ | ||
19 | 19 | model::{ |
20 | 20 | instance::Instance, |
21 | 21 | settings::{Setting, UserBio, UserDisplayImage, UserDisplayName}, |
22 | user::User, | |
22 | user::User, authenticated::UserAuthenticationToken, | |
23 | 23 | }, |
24 | 24 | }; |
25 | 25 | use rsa::{ |
@@ -221,9 +221,29 @@ impl AuthBackend for UserAuth { | ||
221 | 221 | |
222 | 222 | async fn login( |
223 | 223 | &mut self, |
224 | _request: AuthenticationTokenRequest, | |
224 | request: AuthenticationTokenRequest, | |
225 | 225 | ) -> Result<AuthenticationTokenResponse, Error> { |
226 | todo!() | |
226 | let user = sqlx::query_as!(UserRow, r#"SELECT * FROM users WHERE username = $1"#, request.username).fetch_one(&self.pg_pool).await?; | |
227 | ||
228 | let hash = PasswordHash::new(&user.password).unwrap(); | |
229 | ||
230 | if !matches!(Argon2::default().verify_password(request.password.as_bytes(), &hash), Ok(())) { | |
231 | // Invalid password! | |
232 | return Err(Error::from(AuthenticationError::InvalidPassword)); | |
233 | } | |
234 | ||
235 | let mut granter = self.auth_granter.lock().await; | |
236 | let token = granter | |
237 | .create_token_for( | |
238 | &User { | |
239 | username: user.username, | |
240 | instance: self.this_instance.clone(), | |
241 | }, | |
242 | &request.issued_for.unwrap_or_else(|| self.this_instance.clone()), | |
243 | ) | |
244 | .await; | |
245 | ||
246 | Ok(AuthenticationTokenResponse { token: UserAuthenticationToken::from(token) }) | |
227 | 247 | } |
228 | 248 | } |
229 | 249 | |
@@ -236,3 +256,9 @@ struct UserRow { | ||
236 | 256 | pub public_key: String, |
237 | 257 | pub enc_private_key: Vec<u8>, |
238 | 258 | } |
259 | ||
260 | #[derive(Debug, thiserror::Error)] | |
261 | pub enum AuthenticationError { | |
262 | #[error("invalid password")] | |
263 | InvalidPassword | |
264 | } | |
264 | \ No newline at end of file |
giterated-daemon/src/connection/authentication.rs
@@ -79,6 +79,8 @@ async fn authentication_token_request( | ||
79 | 79 | // the user. TODO: Oauth-style flow |
80 | 80 | let mut connections = connection_state.instance_connections.lock().await; |
81 | 81 | |
82 | let issued_for = instance.inner().clone(); | |
83 | ||
82 | 84 | let connection = connections.get_or_open(&request.instance).unwrap(); |
83 | 85 | |
84 | 86 | let private_key = { |
@@ -103,6 +105,11 @@ async fn authentication_token_request( | ||
103 | 105 | private_key, |
104 | 106 | }; |
105 | 107 | |
108 | let request = AuthenticationTokenRequest { | |
109 | issued_for: Some(issued_for), | |
110 | ..request | |
111 | }; | |
112 | ||
106 | 113 | let response = giterated_api::request::request_local(request) |
107 | 114 | .authenticate(authenticator) |
108 | 115 | .execute_expect::<AuthenticationTokenResponse>(&connection) |
@@ -118,14 +125,9 @@ async fn authentication_token_request( | ||
118 | 125 | return Ok(()); |
119 | 126 | } |
120 | 127 | |
121 | let issued_for = instance.inner().clone(); | |
122 | ||
123 | let mut token_granter = connection_state.auth_granter.lock().await; | |
128 | let mut user_backend = connection_state.user_backend.lock().await; | |
124 | 129 | |
125 | let response = token_granter | |
126 | .token_request(issued_for, request.username, request.password) | |
127 | .await | |
128 | .map_err(|e| AuthenticationConnectionError::TokenIssuance(e))?; | |
130 | let response = user_backend.login(request).await.map_err(|e| AuthenticationConnectionError::TokenIssuance(e))?; | |
129 | 131 | |
130 | 132 | connection_state |
131 | 133 | .send(response) |
giterated-daemon/src/connection/wrapper.rs
@@ -80,6 +80,7 @@ pub async fn connection_wrapper( | ||
80 | 80 | Message::Close(_) => return, |
81 | 81 | _ => continue, |
82 | 82 | }; |
83 | info!("one payload"); | |
83 | 84 | |
84 | 85 | let message = NetworkMessage(payload.clone()); |
85 | 86 | |
@@ -94,19 +95,21 @@ pub async fn connection_wrapper( | ||
94 | 95 | let raw = serde_json::from_slice::<AuthenticatedPayload>(&payload).unwrap(); |
95 | 96 | |
96 | 97 | if let Some(target_instance) = &raw.target_instance { |
97 | // Forward request | |
98 | info!("Forwarding message to {}", target_instance.url); | |
99 | let mut instance_connections = instance_connections.lock().await; | |
100 | let pool = instance_connections.get_or_open(&target_instance).unwrap(); | |
101 | let pool_clone = pool.clone(); | |
102 | drop(pool); | |
98 | if connection_state.instance != *target_instance { | |
99 | // Forward request | |
100 | info!("Forwarding message to {}", target_instance.url); | |
101 | let mut instance_connections = instance_connections.lock().await; | |
102 | let pool = instance_connections.get_or_open(&target_instance).unwrap(); | |
103 | let pool_clone = pool.clone(); | |
104 | drop(pool); | |
103 | 105 | |
104 | let result = wrap_forwarded(&pool_clone, raw).await; | |
106 | let result = wrap_forwarded(&pool_clone, raw).await; | |
105 | 107 | |
106 | let mut socket = connection_state.socket.lock().await; | |
107 | let _ = socket.send(result).await; | |
108 | let mut socket = connection_state.socket.lock().await; | |
109 | let _ = socket.send(result).await; | |
108 | 110 | |
109 | continue; | |
111 | continue; | |
112 | } | |
110 | 113 | } |
111 | 114 | |
112 | 115 | let message_type = &raw.message_type; |
giterated-daemon/src/main.rs
@@ -60,17 +60,17 @@ async fn main() -> Result<(), Error> { | ||
60 | 60 | .as_str() |
61 | 61 | .unwrap(), |
62 | 62 | ), |
63 | instance: Instance::from_str("giterated.dev").unwrap(), | |
63 | instance: Instance::from_str(config["giterated"]["instance"].as_str().unwrap()).unwrap(), | |
64 | 64 | })); |
65 | 65 | |
66 | 66 | let token_granter = Arc::new(Mutex::new(AuthenticationTokenGranter { |
67 | 67 | config: config.clone(), |
68 | instance: Instance::from_str("giterated.dev").unwrap(), | |
68 | instance: Instance::from_str(config["giterated"]["instance"].as_str().unwrap()).unwrap(), | |
69 | 69 | })); |
70 | 70 | |
71 | 71 | let user_backend: Arc<Mutex<dyn UserBackend + Send>> = Arc::new(Mutex::new(UserAuth::new( |
72 | 72 | db_pool.clone(), |
73 | &Instance::from_str("giterated.dev").unwrap(), | |
73 | &Instance::from_str(config["giterated"]["instance"].as_str().unwrap()).unwrap(), | |
74 | 74 | token_granter.clone(), |
75 | 75 | settings.clone(), |
76 | 76 | ))); |
giterated-models/src/messages/authentication.rs
@@ -41,6 +41,7 @@ pub struct RegisterAccountResponse { | ||
41 | 41 | #[derive(Clone, Debug, Serialize, Deserialize)] |
42 | 42 | pub struct AuthenticationTokenRequest { |
43 | 43 | pub instance: Instance, |
44 | pub issued_for: Option<Instance>, | |
44 | 45 | pub username: String, |
45 | 46 | pub password: String, |
46 | 47 | } |