factoriauth/src/server.rs

149 lines
3.8 KiB
Rust
Raw Normal View History

2024-02-10 19:34:07 +01:00
use std::{net::Ipv6Addr, sync::Arc};
2024-02-10 14:25:33 +01:00
2024-02-10 11:44:31 +01:00
use axum::{
2024-02-10 19:34:07 +01:00
extract::{Query, State},
http::StatusCode,
response::IntoResponse,
2024-02-10 11:44:31 +01:00
routing::{get, post},
Form, Json, Router,
};
2024-02-10 12:39:34 +01:00
use secrecy::ExposeSecret;
2024-02-10 11:44:31 +01:00
use serde::{Deserialize, Serialize};
use tracing::{event, instrument, Level};
2024-02-10 19:34:07 +01:00
use crate::auth::{
AuthenticationError, ServerPadlockGenerator, UserAuthenticator, UserServerKeyGenerator,
};
use crate::secrets::{Password, ServerHash, UserToken};
2024-02-10 11:13:11 +01:00
2024-02-10 19:34:07 +01:00
#[derive(Debug)]
struct AppState {
user_authenticator: Arc<UserAuthenticator>,
server_padlock_generator: Arc<ServerPadlockGenerator>,
user_server_key_generator: Arc<UserServerKeyGenerator>,
}
2024-02-10 11:13:11 +01:00
#[instrument]
2024-02-10 19:34:07 +01:00
pub async fn run(
port: u16,
user_authenticator: Arc<UserAuthenticator>,
server_padlock_generator: Arc<ServerPadlockGenerator>,
user_server_key_generator: Arc<UserServerKeyGenerator>,
) -> color_eyre::Result<()> {
let app_state = Arc::new(AppState {
user_authenticator,
server_padlock_generator,
user_server_key_generator,
});
2024-02-10 11:44:31 +01:00
let app = Router::new()
.route("/tls-check/success", get(|| async { "OK" }))
.route("/api-login", post(api_login))
.route(
"/generate-user-server-key-2",
post(generate_user_server_key_2),
2024-02-10 19:34:07 +01:00
)
.with_state(app_state);
2024-02-10 14:25:33 +01:00
let listener = tokio::net::TcpListener::bind((Ipv6Addr::UNSPECIFIED, port)).await?;
2024-02-10 11:13:11 +01:00
axum::serve(listener, app).await?;
Ok(())
}
2024-02-10 11:44:31 +01:00
2024-02-10 11:49:36 +01:00
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
struct ApiError {
#[serde(skip_serializing)]
status: StatusCode,
2024-02-10 11:49:36 +01:00
error: String,
message: String,
}
impl From<AuthenticationError> for ApiError {
fn from(err: AuthenticationError) -> Self {
Self {
status: StatusCode::UNAUTHORIZED,
error: "authentication-failed".to_owned(),
message: err.to_string(),
}
}
}
impl IntoResponse for ApiError {
fn into_response(self) -> axum::response::Response {
(self.status, Json(self)).into_response()
}
}
type ApiResult<T> = Result<T, ApiError>;
2024-02-10 11:49:36 +01:00
2024-02-10 11:44:31 +01:00
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
struct ApiVersion {
api_version: String,
}
#[derive(Debug, Clone, Deserialize)]
struct LoginRequest {
username: String,
password: Password,
}
#[derive(Debug, Clone, Serialize)]
struct LoginResponse {
username: String,
token: String,
}
#[instrument]
async fn api_login(
2024-02-10 19:34:07 +01:00
State(state): State<Arc<AppState>>,
2024-02-10 11:44:31 +01:00
Query(ApiVersion { api_version }): Query<ApiVersion>,
Form(LoginRequest { username, password }): Form<LoginRequest>,
2024-02-10 11:49:36 +01:00
) -> ApiResult<Json<LoginResponse>> {
2024-02-10 19:34:07 +01:00
event!(Level::INFO, "Generating user key");
let user_token = state
.user_authenticator
.create_user_token(&username, &password)
.await?;
2024-02-10 11:44:31 +01:00
Ok(Json(LoginResponse {
username,
2024-02-10 12:39:34 +01:00
token: user_token.0.expose_secret().to_owned(),
2024-02-10 11:44:31 +01:00
}))
}
#[derive(Debug, Clone, Deserialize)]
struct UserServerKeyRequest {
username: String,
token: UserToken,
server_hash: ServerHash,
}
#[derive(Debug, Clone, Serialize)]
struct UserServerKeyResponse {
server_key: String,
server_key_timestamp: String,
}
#[instrument]
async fn generate_user_server_key_2(
2024-02-10 19:34:07 +01:00
State(state): State<Arc<AppState>>,
Query(ApiVersion { api_version }): Query<ApiVersion>,
Form(UserServerKeyRequest {
username,
token,
server_hash,
}): Form<UserServerKeyRequest>,
) -> ApiResult<Json<UserServerKeyResponse>> {
2024-02-10 19:34:07 +01:00
event!(Level::INFO, "Creating user_server_key");
2024-02-10 19:34:07 +01:00
let (server_key, server_key_timestamp) = state
.user_server_key_generator
.generate_user_server_key(&username, &token, &server_hash)
.await?;
Ok(Json(UserServerKeyResponse {
server_key: server_key.0.expose_secret().to_owned(),
server_key_timestamp,
}))
}