JavaScript is disabled, refresh for a better experience. ambee/giterated

ambee/giterated

Git repository hosting, collaboration, and discovery for the Fediverse.

Update for auth

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨3ef0383

Showing ⁨⁨7⁩ changed files⁩ with ⁨⁨106⁩ insertions⁩ and ⁨⁨24⁩ deletions⁩

giterated-daemon/.sqlx/query-4707bb69d91fa6df545148c281bae53365c53011bea92e75996f030397ae6b07.json

View file
@@ -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

View file
@@ -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

View file
@@ -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

View file
@@ -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

View file
@@ -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

View file
@@ -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

View file
@@ -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 }