From 7be0e420d4f830b5aebd3afde6df82a16bb9a5c1 Mon Sep 17 00:00:00 2001 From: Valentin Tolmer Date: Wed, 16 Jun 2021 22:04:11 +0200 Subject: [PATCH] Add a handler for OPAQUE messages --- src/domain/error.rs | 2 + src/domain/handler.rs | 11 +- src/domain/mod.rs | 2 + src/domain/opaque_handler.rs | 36 +++ src/domain/sql_backend_handler.rs | 63 +---- src/domain/sql_opaque_handler.rs | 396 ++++++++++++++++++++++++++++++ src/infra/auth_service.rs | 10 +- src/infra/ldap_handler.rs | 6 +- src/infra/ldap_server.rs | 11 +- src/infra/tcp_backend_handler.rs | 5 +- src/infra/tcp_server.rs | 13 +- 11 files changed, 476 insertions(+), 79 deletions(-) create mode 100644 src/domain/opaque_handler.rs create mode 100644 src/domain/sql_opaque_handler.rs diff --git a/src/domain/error.rs b/src/domain/error.rs index 955fac3..5147b5c 100644 --- a/src/domain/error.rs +++ b/src/domain/error.rs @@ -8,6 +8,8 @@ pub enum Error { DatabaseError(#[from] sqlx::Error), #[error("Authentication protocol error for `{0}`")] AuthenticationProtocolError(#[from] lldap_model::opaque::AuthenticationError), + #[error("Internal error: `{0}`")] + InternalError(String), } pub type Result = std::result::Result; diff --git a/src/domain/handler.rs b/src/domain/handler.rs index 0d741fd..76698cb 100644 --- a/src/domain/handler.rs +++ b/src/domain/handler.rs @@ -5,8 +5,12 @@ use std::collections::HashSet; pub use lldap_model::*; #[async_trait] -pub trait BackendHandler: Clone + Send { +pub trait LoginHandler: Clone + Send { async fn bind(&self, request: BindRequest) -> Result<()>; +} + +#[async_trait] +pub trait BackendHandler: Clone + Send { async fn list_users(&self, request: ListUsersRequest) -> Result>; async fn list_groups(&self) -> Result>; async fn create_user(&self, request: CreateUserRequest) -> Result<()>; @@ -24,7 +28,6 @@ mockall::mock! { } #[async_trait] impl BackendHandler for TestBackendHandler { - async fn bind(&self, request: BindRequest) -> Result<()>; async fn list_users(&self, request: ListUsersRequest) -> Result>; async fn list_groups(&self) -> Result>; async fn create_user(&self, request: CreateUserRequest) -> Result<()>; @@ -33,4 +36,8 @@ mockall::mock! { async fn get_user_groups(&self, user: String) -> Result>; async fn add_user_to_group(&self, request: AddUserToGroupRequest) -> Result<()>; } + #[async_trait] + impl LoginHandler for TestBackendHandler { + async fn bind(&self, request: BindRequest) -> Result<()>; + } } diff --git a/src/domain/mod.rs b/src/domain/mod.rs index ede7b41..ce0afa9 100644 --- a/src/domain/mod.rs +++ b/src/domain/mod.rs @@ -1,4 +1,6 @@ pub mod error; pub mod handler; +pub mod opaque_handler; pub mod sql_backend_handler; +pub mod sql_opaque_handler; pub mod sql_tables; diff --git a/src/domain/opaque_handler.rs b/src/domain/opaque_handler.rs new file mode 100644 index 0000000..a0c0300 --- /dev/null +++ b/src/domain/opaque_handler.rs @@ -0,0 +1,36 @@ +use super::error::*; +use async_trait::async_trait; + +pub use lldap_model::{login, registration}; + +#[async_trait] +pub trait OpaqueHandler: Clone + Send { + async fn login_start( + &self, + request: login::ClientLoginStartRequest, + ) -> Result; + async fn login_finish(&self, request: login::ClientLoginFinishRequest) -> Result; + async fn registration_start( + &self, + request: registration::ClientRegistrationStartRequest, + ) -> Result; + async fn registration_finish( + &self, + request: registration::ClientRegistrationFinishRequest, + ) -> Result<()>; +} + +#[cfg(test)] +mockall::mock! { + pub TestOpaqueHandler{} + impl Clone for TestOpaqueHandler { + fn clone(&self) -> Self; + } + #[async_trait] + impl OpaqueHandler for TestOpaqueHandler { + async fn login_start(&self, request: login::ClientLoginStartRequest) -> Result; + async fn login_finish(&self, request: login::ClientLoginFinishRequest ) -> Result; + async fn registration_start(&self, request: registration::ClientRegistrationStartRequest) -> Result; + async fn registration_finish(&self, request: registration::ClientRegistrationFinishRequest ) -> Result<()>; + } +} diff --git a/src/domain/sql_backend_handler.rs b/src/domain/sql_backend_handler.rs index 2d0b1e8..ec08e12 100644 --- a/src/domain/sql_backend_handler.rs +++ b/src/domain/sql_backend_handler.rs @@ -4,7 +4,6 @@ use async_trait::async_trait; use futures_util::StreamExt; use futures_util::TryStreamExt; use lldap_model::opaque; -use log::*; use sea_query::{Expr, Iden, Order, Query, SimpleExpr, Value}; use sqlx::Row; use std::collections::HashSet; @@ -21,7 +20,7 @@ impl SqlBackendHandler { } } -fn get_password_file( +pub fn get_password_file( clear_password: &str, server_public_key: &opaque::PublicKey, ) -> Result { @@ -48,30 +47,6 @@ fn get_password_file( )?) } -fn passwords_match( - password_file_bytes: &[u8], - clear_password: &str, - server_private_key: &opaque::PrivateKey, -) -> Result<()> { - use opaque::{client, server}; - let mut rng = rand::rngs::OsRng; - let client_login_start_result = client::login::start_login(clear_password, &mut rng)?; - - let password_file = server::ServerRegistration::deserialize(password_file_bytes) - .map_err(opaque::AuthenticationError::ProtocolError)?; - let server_login_start_result = server::login::start_login( - &mut rng, - password_file, - server_private_key, - client_login_start_result.message, - )?; - client::login::finish_login( - client_login_start_result.state, - server_login_start_result.message, - )?; - Ok(()) -} - fn get_filter_expr(filter: RequestFilter) -> SimpleExpr { use RequestFilter::*; fn get_repeated_filter( @@ -95,42 +70,6 @@ fn get_filter_expr(filter: RequestFilter) -> SimpleExpr { #[async_trait] impl BackendHandler for SqlBackendHandler { - async fn bind(&self, request: BindRequest) -> Result<()> { - if request.name == self.config.ldap_user_dn { - if request.password == self.config.ldap_user_pass { - return Ok(()); - } else { - debug!(r#"Invalid password for LDAP bind user"#); - return Err(Error::AuthenticationError(request.name)); - } - } - let query = Query::select() - .column(Users::PasswordHash) - .from(Users::Table) - .and_where(Expr::col(Users::UserId).eq(request.name.as_str())) - .to_string(DbQueryBuilder {}); - if let Ok(row) = sqlx::query(&query).fetch_one(&self.sql_pool).await { - if let Some(password_hash) = - row.get::>, _>(&*Users::PasswordHash.to_string()) - { - if let Err(e) = passwords_match( - &&password_hash, - &request.password, - self.config.get_server_keys().private(), - ) { - debug!(r#"Invalid password for "{}": {}"#, request.name, e); - } else { - return Ok(()); - } - } else { - debug!(r#"User "{}" has no password"#, request.name); - } - } else { - debug!(r#"No user found for "{}""#, request.name); - } - Err(Error::AuthenticationError(request.name)) - } - async fn list_users(&self, request: ListUsersRequest) -> Result> { let query = { let mut query_builder = Query::select() diff --git a/src/domain/sql_opaque_handler.rs b/src/domain/sql_opaque_handler.rs new file mode 100644 index 0000000..3fdcfe0 --- /dev/null +++ b/src/domain/sql_opaque_handler.rs @@ -0,0 +1,396 @@ +use super::{ + error::*, handler::LoginHandler, opaque_handler::*, sql_backend_handler::SqlBackendHandler, + sql_tables::*, +}; +use async_trait::async_trait; +use lldap_model::{opaque, BindRequest}; +use log::*; +use rand::{CryptoRng, RngCore}; +use sea_query::{Expr, Iden, Query}; +use sqlx::Row; + +type SqlOpaqueHandler = SqlBackendHandler; + +fn generate_random_id(rng: &mut R) -> String { + use rand::{distributions::Alphanumeric, Rng}; + std::iter::repeat(()) + .map(|()| rng.sample(Alphanumeric)) + .map(char::from) + .take(32) + .collect() +} + +fn passwords_match( + password_file_bytes: &[u8], + clear_password: &str, + server_private_key: &opaque::PrivateKey, +) -> Result<()> { + use opaque::{client, server}; + let mut rng = rand::rngs::OsRng; + let client_login_start_result = client::login::start_login(clear_password, &mut rng)?; + + let password_file = server::ServerRegistration::deserialize(password_file_bytes) + .map_err(opaque::AuthenticationError::ProtocolError)?; + let server_login_start_result = server::login::start_login( + &mut rng, + password_file, + server_private_key, + client_login_start_result.message, + )?; + client::login::finish_login( + client_login_start_result.state, + server_login_start_result.message, + )?; + Ok(()) +} + +#[async_trait] +impl LoginHandler for SqlBackendHandler { + async fn bind(&self, request: BindRequest) -> Result<()> { + if request.name == self.config.ldap_user_dn { + if request.password == self.config.ldap_user_pass { + return Ok(()); + } else { + debug!(r#"Invalid password for LDAP bind user"#); + return Err(Error::AuthenticationError(request.name)); + } + } + let query = Query::select() + .column(Users::PasswordHash) + .from(Users::Table) + .and_where(Expr::col(Users::UserId).eq(request.name.as_str())) + .to_string(DbQueryBuilder {}); + if let Ok(row) = sqlx::query(&query).fetch_one(&self.sql_pool).await { + if let Some(password_hash) = + row.get::>, _>(&*Users::PasswordHash.to_string()) + { + if let Err(e) = passwords_match( + &&password_hash, + &request.password, + self.config.get_server_keys().private(), + ) { + debug!(r#"Invalid password for "{}": {}"#, request.name, e); + } else { + return Ok(()); + } + } else { + debug!(r#"User "{}" has no password"#, request.name); + } + } else { + debug!(r#"No user found for "{}""#, request.name); + } + Err(Error::AuthenticationError(request.name)) + } +} + +#[async_trait] +impl OpaqueHandler for SqlOpaqueHandler { + async fn login_start( + &self, + request: login::ClientLoginStartRequest, + ) -> Result { + // Fetch the previously registered password file from the DB. + let password_file_bytes = { + let query = Query::select() + .column(Users::PasswordHash) + .from(Users::Table) + .and_where(Expr::col(Users::UserId).eq(request.username.as_str())) + .to_string(DbQueryBuilder {}); + sqlx::query(&query) + .fetch_one(&self.sql_pool) + .await? + .get::>, _>(&*Users::PasswordHash.to_string()) + // If no password, always fail. + .ok_or_else(|| Error::AuthenticationError(request.username.clone()))? + }; + let password_file = opaque::server::ServerRegistration::deserialize(&password_file_bytes) + .map_err(|_| { + Error::InternalError(format!("Corrupted password file for {}", request.username)) + })?; + + let mut rng = rand::rngs::OsRng; + let start_response = opaque::server::login::start_login( + &mut rng, + password_file, + self.config.get_server_keys().private(), + request.login_start_request, + )?; + let login_attempt_id = generate_random_id(&mut rng); + + { + // Insert the current login attempt in the DB. + let query = Query::insert() + .into_table(LoginAttempts::Table) + .columns(vec![ + LoginAttempts::RandomId, + LoginAttempts::UserId, + LoginAttempts::ServerLoginData, + LoginAttempts::Timestamp, + ]) + .values_panic(vec![ + login_attempt_id.as_str().into(), + request.username.as_str().into(), + start_response.state.serialize().into(), + chrono::Utc::now().naive_utc().into(), + ]) + .to_string(DbQueryBuilder {}); + sqlx::query(&query).execute(&self.sql_pool).await?; + } + + Ok(login::ServerLoginStartResponse { + login_key: login_attempt_id, + credential_response: start_response.message, + }) + } + + async fn login_finish(&self, request: login::ClientLoginFinishRequest) -> Result { + // Fetch the previous data from this login attempt. + let row = { + let query = Query::select() + .column(LoginAttempts::UserId) + .column(LoginAttempts::ServerLoginData) + .from(LoginAttempts::Table) + .and_where(Expr::col(LoginAttempts::RandomId).eq(request.login_key.as_str())) + .and_where( + Expr::col(LoginAttempts::Timestamp) + .gt(chrono::Utc::now().naive_utc() - chrono::Duration::minutes(5)), + ) + .to_string(DbQueryBuilder {}); + sqlx::query(&query).fetch_one(&self.sql_pool).await? + }; + let username = row.get::(&*LoginAttempts::UserId.to_string()); + let login_data = opaque::server::login::ServerLogin::deserialize( + &row.get::, _>(&*LoginAttempts::ServerLoginData.to_string()), + ) + .map_err(|_| { + Error::InternalError(format!( + "Corrupted login data for user `{}` [id `{}`]", + username, request.login_key + )) + })?; + // Finish the login: this makes sure the client data is correct, and gives a session key we + // don't need. + let _session_key = + opaque::server::login::finish_login(login_data, request.credential_finalization)? + .session_key; + + { + // Login was successful, we can delete the login attempt from the table. + let delete_query = Query::delete() + .from_table(LoginAttempts::Table) + .and_where(Expr::col(LoginAttempts::RandomId).eq(request.login_key)) + .to_string(DbQueryBuilder {}); + sqlx::query(&delete_query).execute(&self.sql_pool).await?; + } + Ok(username) + } + + async fn registration_start( + &self, + request: registration::ClientRegistrationStartRequest, + ) -> Result { + let mut rng = rand::rngs::OsRng; + // Generate the server-side key and derive the data to send back. + let start_response = opaque::server::registration::start_registration( + &mut rng, + request.registration_start_request, + self.config.get_server_keys().public(), + )?; + // Unique ID to identify the registration attempt. + let registration_attempt_id = generate_random_id(&mut rng); + { + // Write the registration attempt to the DB for the later turn. + let query = Query::insert() + .into_table(RegistrationAttempts::Table) + .columns(vec![ + RegistrationAttempts::RandomId, + RegistrationAttempts::UserId, + RegistrationAttempts::ServerRegistrationData, + RegistrationAttempts::Timestamp, + ]) + .values_panic(vec![ + registration_attempt_id.as_str().into(), + request.username.as_str().into(), + start_response.state.serialize().into(), + chrono::Utc::now().naive_utc().into(), + ]) + .to_string(DbQueryBuilder {}); + sqlx::query(&query).execute(&self.sql_pool).await?; + } + Ok(registration::ServerRegistrationStartResponse { + registration_key: registration_attempt_id, + registration_response: start_response.message, + }) + } + + async fn registration_finish( + &self, + request: registration::ClientRegistrationFinishRequest, + ) -> Result<()> { + // Fetch the previous state. + let row = { + let query = Query::select() + .column(RegistrationAttempts::UserId) + .column(RegistrationAttempts::ServerRegistrationData) + .from(RegistrationAttempts::Table) + .and_where( + Expr::col(RegistrationAttempts::RandomId).eq(request.registration_key.as_str()), + ) + .and_where( + Expr::col(RegistrationAttempts::Timestamp) + .gt(chrono::Utc::now().naive_utc() - chrono::Duration::minutes(5)), + ) + .to_string(DbQueryBuilder {}); + sqlx::query(&query).fetch_one(&self.sql_pool).await? + }; + let username = row.get::(&*RegistrationAttempts::UserId.to_string()); + let registration_data = opaque::server::registration::ServerRegistration::deserialize( + &row.get::, _>(&*RegistrationAttempts::ServerRegistrationData.to_string()), + ) + .map_err(|_| { + Error::InternalError(format!( + "Corrupted registration data for user `{}` [id `{}`]", + username, request.registration_key + )) + })?; + + let password_file = opaque::server::registration::get_password_file( + registration_data, + request.registration_upload, + )?; + { + // Set the user password to the new password. + let update_query = Query::update() + .table(Users::Table) + .values(vec![( + Users::PasswordHash, + password_file.serialize().into(), + )]) + .and_where(Expr::col(Users::UserId).eq(username)) + .to_string(DbQueryBuilder {}); + sqlx::query(&update_query).execute(&self.sql_pool).await?; + } + { + // Delete the registration attempt. + let delete_query = Query::delete() + .from_table(RegistrationAttempts::Table) + .and_where(Expr::col(RegistrationAttempts::RandomId).eq(request.registration_key)) + .to_string(DbQueryBuilder {}); + sqlx::query(&delete_query).execute(&self.sql_pool).await?; + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + domain::{ + handler::BackendHandler, sql_backend_handler::SqlBackendHandler, sql_tables::init_table, + }, + infra::configuration::{Configuration, ConfigurationBuilder}, + }; + use lldap_model::*; + + fn get_default_config() -> Configuration { + ConfigurationBuilder::default() + .verbose(true) + .build() + .unwrap() + } + + async fn get_in_memory_db() -> Pool { + PoolOptions::new().connect("sqlite::memory:").await.unwrap() + } + + async fn get_initialized_db() -> Pool { + let sql_pool = get_in_memory_db().await; + init_table(&sql_pool).await.unwrap(); + sql_pool + } + + async fn insert_user_no_password(handler: &SqlBackendHandler, name: &str) { + handler + .create_user(CreateUserRequest { + user_id: name.to_string(), + email: "bob@bob.bob".to_string(), + ..Default::default() + }) + .await + .unwrap(); + } + + async fn attempt_login( + opaque_handler: &SqlOpaqueHandler, + username: &str, + password: &str, + ) -> Result<()> { + let mut rng = rand::rngs::OsRng; + use login::*; + let login_start = opaque::client::login::start_login(password, &mut rng)?; + let start_response = opaque_handler + .login_start(ClientLoginStartRequest { + username: username.to_string(), + login_start_request: login_start.message, + }) + .await?; + let login_finish = opaque::client::login::finish_login( + login_start.state, + start_response.credential_response, + )?; + opaque_handler + .login_finish(ClientLoginFinishRequest { + login_key: start_response.login_key, + credential_finalization: login_finish.message, + }) + .await?; + Ok(()) + } + + async fn attempt_registration( + opaque_handler: &SqlOpaqueHandler, + username: &str, + password: &str, + ) -> Result<()> { + let mut rng = rand::rngs::OsRng; + use registration::*; + let registration_start = + opaque::client::registration::start_registration(password, &mut rng)?; + let start_response = opaque_handler + .registration_start(ClientRegistrationStartRequest { + username: username.to_string(), + registration_start_request: registration_start.message, + }) + .await?; + let registration_finish = opaque::client::registration::finish_registration( + registration_start.state, + start_response.registration_response, + &mut rng, + )?; + opaque_handler + .registration_finish(ClientRegistrationFinishRequest { + registration_key: start_response.registration_key, + registration_upload: registration_finish.message, + }) + .await + } + + #[tokio::test] + async fn test_flow() -> Result<()> { + let sql_pool = get_initialized_db().await; + let config = get_default_config(); + let backend_handler = SqlBackendHandler::new(config.clone(), sql_pool.clone()); + let opaque_handler = SqlOpaqueHandler::new(config, sql_pool); + insert_user_no_password(&backend_handler, "bob").await; + attempt_login(&opaque_handler, "bob", "bob00") + .await + .unwrap_err(); + attempt_registration(&opaque_handler, "bob", "bob00").await?; + attempt_login(&opaque_handler, "bob", "wrong_password") + .await + .unwrap_err(); + attempt_login(&opaque_handler, "bob", "bob00").await?; + Ok(()) + } +} diff --git a/src/infra/auth_service.rs b/src/infra/auth_service.rs index 744bc0d..378c2a0 100644 --- a/src/infra/auth_service.rs +++ b/src/infra/auth_service.rs @@ -1,10 +1,14 @@ use crate::{ - domain::handler::*, + domain::{ + handler::{BackendHandler, LoginHandler}, + opaque_handler::OpaqueHandler, + }, infra::{ tcp_backend_handler::*, tcp_server::{error_to_http_response, AppState}, }, }; +use lldap_model::{JWTClaims, BindRequest}; use actix_web::{ cookie::{Cookie, SameSite}, dev::{Service, ServiceRequest, ServiceResponse, Transform}, @@ -166,7 +170,7 @@ async fn post_authorize( request: web::Json, ) -> HttpResponse where - Backend: TcpBackendHandler + BackendHandler + 'static, + Backend: TcpBackendHandler + BackendHandler + LoginHandler + 'static, { let req: BindRequest = request.clone(); data.backend_handler @@ -299,7 +303,7 @@ where pub fn configure_server(cfg: &mut web::ServiceConfig) where - Backend: TcpBackendHandler + BackendHandler + 'static, + Backend: TcpBackendHandler + LoginHandler + OpaqueHandler + BackendHandler + 'static, { cfg.service(web::resource("").route(web::post().to(post_authorize::))) .service(web::resource("/refresh").route(web::get().to(get_refresh::))) diff --git a/src/infra/ldap_handler.rs b/src/infra/ldap_handler.rs index 5bbc8d2..438dfdf 100644 --- a/src/infra/ldap_handler.rs +++ b/src/infra/ldap_handler.rs @@ -1,4 +1,4 @@ -use crate::domain::handler::{BackendHandler, ListUsersRequest, RequestFilter, User}; +use crate::domain::handler::{BackendHandler, ListUsersRequest, LoginHandler, RequestFilter, User}; use anyhow::{bail, Result}; use ldap3_server::simple::*; @@ -147,7 +147,7 @@ fn convert_filter(filter: &LdapFilter) -> Result { } } -pub struct LdapHandler { +pub struct LdapHandler { dn: String, backend_handler: Backend, pub base_dn: Vec<(String, String)>, @@ -155,7 +155,7 @@ pub struct LdapHandler { ldap_user_dn: String, } -impl LdapHandler { +impl LdapHandler { pub fn new(backend_handler: Backend, ldap_base_dn: String, ldap_user_dn: String) -> Self { Self { dn: "Unauthenticated".to_string(), diff --git a/src/infra/ldap_server.rs b/src/infra/ldap_server.rs index ab943fa..771527e 100644 --- a/src/infra/ldap_server.rs +++ b/src/infra/ldap_server.rs @@ -1,4 +1,4 @@ -use crate::domain::handler::BackendHandler; +use crate::domain::handler::{BackendHandler, LoginHandler}; use crate::infra::configuration::Configuration; use crate::infra::ldap_handler::LdapHandler; use actix_rt::net::TcpStream; @@ -12,11 +12,14 @@ use log::*; use tokio::net::tcp::WriteHalf; use tokio_util::codec::{FramedRead, FramedWrite}; -async fn handle_incoming_message( +async fn handle_incoming_message( msg: Result, resp: &mut FramedWrite, LdapCodec>, session: &mut LdapHandler, -) -> Result { +) -> Result +where + Backend: BackendHandler + LoginHandler, +{ use futures_util::SinkExt; use std::convert::TryFrom; let server_op = match msg.map_err(|_e| ()).and_then(ServerOps::try_from) { @@ -56,7 +59,7 @@ pub fn build_ldap_server( server_builder: ServerBuilder, ) -> Result where - Backend: BackendHandler + 'static, + Backend: BackendHandler + LoginHandler + 'static, { use futures_util::StreamExt; diff --git a/src/infra/tcp_backend_handler.rs b/src/infra/tcp_backend_handler.rs index 6837ff8..60541ae 100644 --- a/src/infra/tcp_backend_handler.rs +++ b/src/infra/tcp_backend_handler.rs @@ -22,8 +22,11 @@ mockall::mock! { fn clone(&self) -> Self; } #[async_trait] - impl BackendHandler for TestTcpBackendHandler { + impl LoginHandler for TestTcpBackendHandler { async fn bind(&self, request: BindRequest) -> DomainResult<()>; + } + #[async_trait] + impl BackendHandler for TestTcpBackendHandler { async fn list_users(&self, request: ListUsersRequest) -> DomainResult>; async fn list_groups(&self) -> DomainResult>; async fn get_user_groups(&self, user: String) -> DomainResult>; diff --git a/src/infra/tcp_server.rs b/src/infra/tcp_server.rs index 581dd9f..e2e3d7a 100644 --- a/src/infra/tcp_server.rs +++ b/src/infra/tcp_server.rs @@ -1,5 +1,8 @@ use crate::{ - domain::handler::*, + domain::{ + handler::{BackendHandler, LoginHandler}, + opaque_handler::OpaqueHandler, + }, infra::{auth_service, configuration::Configuration, tcp_api, tcp_backend_handler::*}, }; use actix_files::{Files, NamedFile}; @@ -28,7 +31,9 @@ pub(crate) fn error_to_http_response(error: DomainError) -> HttpResponse { DomainError::AuthenticationError(_) | DomainError::AuthenticationProtocolError(_) => { HttpResponse::Unauthorized() } - DomainError::DatabaseError(_) => HttpResponse::InternalServerError(), + DomainError::DatabaseError(_) | DomainError::InternalError(_) => { + HttpResponse::InternalServerError() + } } .body(error.to_string()) } @@ -39,7 +44,7 @@ fn http_config( jwt_secret: String, jwt_blacklist: HashSet, ) where - Backend: TcpBackendHandler + BackendHandler + 'static, + Backend: TcpBackendHandler + BackendHandler + LoginHandler + OpaqueHandler + 'static, { cfg.data(AppState:: { backend_handler, @@ -83,7 +88,7 @@ pub async fn build_tcp_server( server_builder: ServerBuilder, ) -> Result where - Backend: TcpBackendHandler + BackendHandler + 'static, + Backend: TcpBackendHandler + BackendHandler + LoginHandler + OpaqueHandler + 'static, { let jwt_secret = config.jwt_secret.clone(); let jwt_blacklist = backend_handler.get_jwt_blacklist().await?;