Change forwarding
parent: tbd commit: 2556801
Showing 8 changed files with 79 insertions and 17 deletions
giterated-daemon/src/connection/authentication.rs
@@ -1,9 +1,15 @@ | ||
1 | use std::sync::Arc; | |
2 | ||
1 | 3 | use anyhow::Error; |
2 | 4 | use thiserror::Error; |
5 | use tokio::{fs::File, io::AsyncReadExt}; | |
3 | 6 | |
4 | 7 | use crate::message::{AuthenticatedInstance, Message, MessageHandler, NetworkMessage, State}; |
5 | use giterated_models::messages::authentication::{ | |
6 | AuthenticationTokenRequest, RegisterAccountRequest, TokenExtensionRequest, | |
8 | use giterated_models::{ | |
9 | messages::authentication::{ | |
10 | AuthenticationTokenRequest, RegisterAccountRequest, TokenExtensionRequest, AuthenticationTokenResponse, | |
11 | }, | |
12 | model::authenticated::InstanceAuthenticator, | |
7 | 13 | }; |
8 | 14 | |
9 | 15 | use super::wrapper::ConnectionState; |
@@ -69,6 +75,38 @@ async fn authentication_token_request( | ||
69 | 75 | Message(request): Message<AuthenticationTokenRequest>, |
70 | 76 | instance: AuthenticatedInstance, |
71 | 77 | ) -> Result<(), AuthenticationConnectionError> { |
78 | if request.instance != connection_state.instance { | |
79 | // We need to perform the authentication request on behalf of | |
80 | // the user. TODO: Oauth-style flow | |
81 | let mut connections = connection_state.instance_connections.lock().await; | |
82 | ||
83 | let connection = connections.get_or_open(&request.instance).unwrap(); | |
84 | ||
85 | let private_key = { | |
86 | let mut file = File::open(connection_state.config["giterated"]["keys"]["private"].as_str().unwrap()).await.unwrap(); | |
87 | ||
88 | let mut key = String::new(); | |
89 | file.read_to_string(&mut key).await.unwrap(); | |
90 | ||
91 | key | |
92 | }; | |
93 | ||
94 | let authenticator = InstanceAuthenticator { | |
95 | instance: connection_state.instance.clone(), | |
96 | private_key, | |
97 | }; | |
98 | ||
99 | let response = giterated_api::request::request_local(request) | |
100 | .authenticate(authenticator) | |
101 | .execute_expect::<AuthenticationTokenResponse>(&connection) | |
102 | .await.unwrap(); | |
103 | drop(connection); | |
104 | ||
105 | connection_state.send(response).await.map_err(|e| AuthenticationConnectionError::Sending(e))?; | |
106 | ||
107 | return Ok(()); | |
108 | } | |
109 | ||
72 | 110 | let issued_for = instance.inner().clone(); |
73 | 111 | |
74 | 112 | let mut token_granter = connection_state.auth_granter.lock().await; |
@@ -121,3 +159,12 @@ pub enum AuthenticationConnectionError { | ||
121 | 159 | #[error("error issuing token")] |
122 | 160 | TokenIssuance(Error), |
123 | 161 | } |
162 | ||
163 | async fn private_key(path: &str) -> Vec<u8> { | |
164 | let mut file = File::open(path).await.unwrap(); | |
165 | ||
166 | let mut key = vec![]; | |
167 | file.read_to_end(&mut key).await.unwrap(); | |
168 | ||
169 | key | |
170 | } |
giterated-daemon/src/connection/forwarded.rs
@@ -55,6 +55,4 @@ pub async fn wrap_forwarded(pool: &DaemonConnectionPool, message: AuthenticatedP | ||
55 | 55 | } |
56 | 56 | } |
57 | 57 | } |
58 | ||
59 | todo!() | |
60 | 58 | } |
giterated-daemon/src/connection/wrapper.rs
@@ -17,6 +17,7 @@ use serde::Serialize; | ||
17 | 17 | |
18 | 18 | use tokio::{net::TcpStream, sync::Mutex}; |
19 | 19 | use tokio_tungstenite::{tungstenite::Message, WebSocketStream}; |
20 | use toml::Table; | |
20 | 21 | |
21 | 22 | use crate::{ |
22 | 23 | authentication::AuthenticationTokenGranter, |
@@ -42,6 +43,7 @@ pub async fn connection_wrapper( | ||
42 | 43 | addr: SocketAddr, |
43 | 44 | instance: impl ToOwned<Owned = Instance>, |
44 | 45 | instance_connections: Arc<Mutex<InstanceConnections>>, |
46 | config: Table, | |
45 | 47 | ) { |
46 | 48 | let connection_state = ConnectionState { |
47 | 49 | socket: Arc::new(Mutex::new(socket)), |
@@ -54,6 +56,8 @@ pub async fn connection_wrapper( | ||
54 | 56 | instance: instance.to_owned(), |
55 | 57 | handshaked: Arc::new(AtomicBool::new(false)), |
56 | 58 | key_cache: Arc::default(), |
59 | instance_connections: instance_connections.clone(), | |
60 | config, | |
57 | 61 | }; |
58 | 62 | |
59 | 63 | let mut handshaked = false; |
@@ -179,6 +183,8 @@ pub struct ConnectionState { | ||
179 | 183 | pub instance: Instance, |
180 | 184 | pub handshaked: Arc<AtomicBool>, |
181 | 185 | pub key_cache: Arc<Mutex<PublicKeyCache>>, |
186 | pub instance_connections: Arc<Mutex<InstanceConnections>>, | |
187 | pub config: Table, | |
182 | 188 | } |
183 | 189 | |
184 | 190 | impl ConnectionState { |
giterated-daemon/src/main.rs
@@ -26,15 +26,15 @@ extern crate tracing; | ||
26 | 26 | #[tokio::main] |
27 | 27 | async fn main() -> Result<(), Error> { |
28 | 28 | tracing_subscriber::fmt::init(); |
29 | let mut listener = TcpListener::bind("0.0.0.0:7270").await?; | |
30 | let connections: Arc<Mutex<Connections>> = Arc::default(); | |
31 | let instance_connections: Arc<Mutex<InstanceConnections>> = Arc::default(); | |
32 | 29 | let config: Table = { |
33 | 30 | let mut file = File::open("Giterated.toml").await?; |
34 | 31 | let mut text = String::new(); |
35 | 32 | file.read_to_string(&mut text).await?; |
36 | 33 | text.parse()? |
37 | 34 | }; |
35 | let mut listener = TcpListener::bind(config["giterated"]["bind"].as_str().unwrap()).await?; | |
36 | let connections: Arc<Mutex<Connections>> = Arc::default(); | |
37 | let instance_connections: Arc<Mutex<InstanceConnections>> = Arc::default(); | |
38 | 38 | let db_conn_options = PgConnectOptions::new() |
39 | 39 | .host(config["postgres"]["host"].as_str().unwrap()) |
40 | 40 | .port(config["postgres"]["port"].as_integer().unwrap() as u16) |
@@ -117,6 +117,7 @@ async fn main() -> Result<(), Error> { | ||
117 | 117 | address, |
118 | 118 | Instance::from_str("giterated.dev").unwrap(), |
119 | 119 | instance_connections.clone(), |
120 | config.clone(), | |
120 | 121 | )), |
121 | 122 | }; |
122 | 123 |
giterated-models/src/messages/authentication.rs
@@ -1,6 +1,6 @@ | ||
1 | 1 | use serde::{Deserialize, Serialize}; |
2 | 2 | |
3 | use crate::model::authenticated::UserAuthenticationToken; | |
3 | use crate::model::{authenticated::UserAuthenticationToken, instance::Instance}; | |
4 | 4 | |
5 | 5 | /// An account registration request. |
6 | 6 | /// |
@@ -32,6 +32,7 @@ pub struct RegisterAccountResponse { | ||
32 | 32 | /// - Decrypts user private key to issue to |
33 | 33 | #[derive(Clone, Debug, Serialize, Deserialize)] |
34 | 34 | pub struct AuthenticationTokenRequest { |
35 | pub instance: Instance, | |
35 | 36 | pub username: String, |
36 | 37 | pub password: String, |
37 | 38 | } |
giterated-models/src/messages/repository.rs
@@ -149,7 +149,6 @@ pub struct RepositoryInfoRequest { | ||
149 | 149 | pub path: Option<String>, |
150 | 150 | } |
151 | 151 | |
152 | ||
153 | 152 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] |
154 | 153 | pub struct RepositorySettingsRequest { |
155 | 154 | pub repository: Repository, |
giterated-models/src/model/authenticated.rs
@@ -22,7 +22,7 @@ pub struct UserTokenMetadata { | ||
22 | 22 | #[derive(Debug)] |
23 | 23 | pub struct Authenticated<T: Serialize> { |
24 | 24 | pub target_instance: Option<Instance>, |
25 | pub source: Vec<Box<dyn AuthenticationSourceProvider>>, | |
25 | pub source: Vec<Box<dyn AuthenticationSourceProvider + Send + Sync>>, | |
26 | 26 | pub message_type: String, |
27 | 27 | pub message: T, |
28 | 28 | } |
@@ -109,7 +109,10 @@ impl<T: Serialize + Debug> Authenticated<T> { | ||
109 | 109 | } |
110 | 110 | } |
111 | 111 | |
112 | pub fn append_authentication<P: AuthenticationSourceProvider + 'static>(&mut self, authentication: P) { | |
112 | pub fn append_authentication<P: AuthenticationSourceProvider + 'static + Send + Sync>( | |
113 | &mut self, | |
114 | authentication: P, | |
115 | ) { | |
113 | 116 | let message_payload = serde_json::to_vec(&self.message).unwrap(); |
114 | 117 | |
115 | 118 | info!( |
@@ -117,7 +120,8 @@ impl<T: Serialize + Debug> Authenticated<T> { | ||
117 | 120 | std::str::from_utf8(&message_payload).unwrap() |
118 | 121 | ); |
119 | 122 | |
120 | self.source.push(Box::new(authentication) as Box<dyn AuthenticationSourceProvider>); | |
123 | self.source | |
124 | .push(Box::new(authentication) as Box<dyn AuthenticationSourceProvider + Send + Sync>); | |
121 | 125 | } |
122 | 126 | |
123 | 127 | pub fn into_payload(self) -> AuthenticatedPayload { |
@@ -143,16 +147,16 @@ impl AuthenticationSourceProvider for UserAuthenticator { | ||
143 | 147 | } |
144 | 148 | |
145 | 149 | #[derive(Debug, Clone)] |
146 | pub struct InstanceAuthenticator<'a> { | |
150 | pub struct InstanceAuthenticator { | |
147 | 151 | pub instance: Instance, |
148 | pub private_key: &'a str, | |
152 | pub private_key: String, | |
149 | 153 | } |
150 | 154 | |
151 | impl AuthenticationSourceProvider for InstanceAuthenticator<'_> { | |
155 | impl AuthenticationSourceProvider for InstanceAuthenticator { | |
152 | 156 | fn authenticate(&self, payload: &Vec<u8>) -> AuthenticationSource { |
153 | 157 | let mut rng = rand::thread_rng(); |
154 | 158 | |
155 | let private_key = RsaPrivateKey::from_pkcs1_pem(self.private_key).unwrap(); | |
159 | let private_key = RsaPrivateKey::from_pkcs1_pem(&self.private_key).unwrap(); | |
156 | 160 | let signing_key = SigningKey::<Sha256>::new(private_key); |
157 | 161 | let signature = signing_key.sign_with_rng(&mut rng, &payload); |
158 | 162 |
giterated-models/src/model/repository.rs
@@ -174,7 +174,13 @@ impl From<git2::Commit<'_>> for Commit { | ||
174 | 174 | Self { |
175 | 175 | oid: commit.id().to_string(), |
176 | 176 | // This shouldn't ever fail, as we already know the object has an oid. |
177 | short_oid: commit.as_object().short_id().unwrap().as_str().unwrap().to_string(), | |
177 | short_oid: commit | |
178 | .as_object() | |
179 | .short_id() | |
180 | .unwrap() | |
181 | .as_str() | |
182 | .unwrap() | |
183 | .to_string(), | |
178 | 184 | message: commit.message().map(|message| message.to_string()), |
179 | 185 | author: commit.author().into(), |
180 | 186 | committer: commit.committer().into(), |