diff options
author | Kjetil Orbekk <kj@orbekk.com> | 2022-11-25 14:09:09 -0500 |
---|---|---|
committer | Kjetil Orbekk <kj@orbekk.com> | 2022-11-25 14:09:09 -0500 |
commit | 2f35026022827cd86615135c6397f03b74fe1b46 (patch) | |
tree | 17c96f91330003aace047ae6b84aabd876d0ee5a /server/src | |
parent | 9d191019757eae3bba45e8e1a021fefdc69a9fae (diff) |
Hook up fake authenticator backend for testing
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/auth.rs | 20 | ||||
-rw-r--r-- | server/src/error.rs | 3 | ||||
-rw-r--r-- | server/src/fake_auth.rs | 62 | ||||
-rw-r--r-- | server/src/main.rs | 33 |
4 files changed, 107 insertions, 11 deletions
diff --git a/server/src/auth.rs b/server/src/auth.rs index 7222199..fc0de62 100644 --- a/server/src/auth.rs +++ b/server/src/auth.rs @@ -42,6 +42,24 @@ pub struct AuthenticatedSession { refresh_token: RefreshToken, } +impl AuthenticatedSession { + pub fn new( + player_id: String, + session_id: SessionId, + expiration: DateTime<Utc>, + access_token: AccessToken, + refresh_token: RefreshToken, + ) -> Self { + Self { + player_id, + session_id, + expiration, + access_token, + refresh_token, + } + } +} + #[async_trait] pub trait Authenticator { async fn user_info(&self, session: &mut AuthenticatedSession) -> Result<String, BridgeError>; @@ -273,7 +291,7 @@ impl Authenticator for OauthAuthenticator { } } -async fn store_authenticated_session( +pub async fn store_authenticated_session( pool: &PgPool, session: &mut AuthenticatedSession, ) -> Result<(), BridgeError> { diff --git a/server/src/error.rs b/server/src/error.rs index 611d8e4..344624c 100644 --- a/server/src/error.rs +++ b/server/src/error.rs @@ -63,6 +63,9 @@ pub enum BridgeError { impl BridgeError { pub fn as_rejection(&self) -> (http::StatusCode, String) { match self { + BridgeError::NotLoggedIn => { + (StatusCode::UNAUTHORIZED, format!("Must be logged in")) + }, BridgeError::OpenidRequestTokenError(_) => { (StatusCode::UNAUTHORIZED, format!("Error fetching token")) } diff --git a/server/src/fake_auth.rs b/server/src/fake_auth.rs index 5ef9cc8..d19d858 100644 --- a/server/src/fake_auth.rs +++ b/server/src/fake_auth.rs @@ -1,13 +1,31 @@ -use std::collections::HashMap; +use std::{ + collections::HashMap, + env, + sync::{Arc, Mutex}, +}; use async_trait::async_trait; +use chrono::{DateTime, Utc}; +use openidconnect::{RefreshToken, AccessToken}; +use reqwest::Url; +use tracing::info; use crate::{ - auth::{AuthenticatedSession, Authenticator, SessionId}, + auth::{AuthenticatedSession, Authenticator, SessionId, store_authenticated_session}, error::{self, BridgeError}, }; -pub struct FakeAuthenticator {} +pub struct FakeAuthenticator { + login_cache: Arc<Mutex<HashMap<SessionId, Option<String>>>>, +} + +impl FakeAuthenticator { + pub fn new() -> Self { + Self { + login_cache: Arc::new(Mutex::new(HashMap::new())), + } + } +} #[async_trait] impl Authenticator for FakeAuthenticator { @@ -15,7 +33,15 @@ impl Authenticator for FakeAuthenticator { &self, session: &mut AuthenticatedSession, ) -> Result<String, error::BridgeError> { - Err(BridgeError::NotLoggedIn) + let user: String = self + .login_cache + .lock() + .unwrap() + .get(&session.session_id) + .and_then(|u| u.as_ref()) + .ok_or(BridgeError::NotLoggedIn)? + .clone(); + Ok(user) } async fn authenticate( @@ -24,10 +50,34 @@ impl Authenticator for FakeAuthenticator { session_id: SessionId, auth_params: HashMap<String, String>, ) -> Result<AuthenticatedSession, error::BridgeError> { - Err(BridgeError::Internal("not implemented".to_string())) + let user = auth_params + .get("user") + .ok_or(BridgeError::Internal("missing 'user' param".to_string()))?; + self.login_cache + .lock() + .unwrap() + .insert(session_id.clone(), Some(user.clone())); + + let mut session = AuthenticatedSession::new( + user.clone(), + session_id, + Utc::now() + chrono::Duration::days(10000), + AccessToken::new("fake".to_string()), + RefreshToken::new("fake".to_string()), + ); + + store_authenticated_session(pool, &mut session).await?; + Ok(session) } async fn get_login_url(&self) -> (SessionId, reqwest::Url) { - todo!() + let auth_url = + Url::parse(&format!("{}/api/fake_login", env::var("APP_URL").unwrap())).unwrap(); + let user_id = SessionId::new(); + self.login_cache + .lock() + .unwrap() + .insert(user_id.clone(), None); + (user_id, auth_url) } } diff --git a/server/src/main.rs b/server/src/main.rs index 39425d6..ca65d86 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -5,11 +5,12 @@ use uuid::Uuid; use auth::AuthenticatedSession; use axum::{ extract::{Extension, Path, Query}, - response::Redirect, + response::{Html, Redirect}, routing::{delete, get, post}, Json, Router, }; -use protocol::{bridge_engine::{self, TableView, Player}, Table, UserInfo}; +use protocol::{Table, UserInfo}; +use protocol::bridge_engine::{TableView, Player}; use server::ContextExtension; use tower_cookies::{Cookie, CookieManagerLayer, Cookies}; use tower_http::trace::TraceLayer; @@ -19,6 +20,7 @@ mod auth; mod error; mod play; mod server; +#[cfg(debug_assertions)] mod fake_auth; use crate::{ auth::{OauthAuthenticator, SessionId}, @@ -39,7 +41,7 @@ async fn create_default_authenticator(db_pool: &PgPool) -> Box<dyn Authenticator async fn create_authenticator(db_pool: &PgPool) -> Box<dyn Authenticator + Send + Sync> { const FAKE_AUTHENTICATOR: &str = "fake"; if std::env::var("AUTHENTICATOR").unwrap_or("".to_string()) == FAKE_AUTHENTICATOR { - Box::new(fake_auth::FakeAuthenticator {}) + Box::new(fake_auth::FakeAuthenticator::new()) } else { create_default_authenticator(db_pool).await } @@ -91,7 +93,13 @@ async fn main() { db: db_pool, }); - let app = Router::new() + let app = Router::new(); + + #[cfg(debug_assertions)] + let app = app + .route("/api/fake_login", get(fake_login)); + + let app = app .route("/api/user/info", get(user_info)) .route("/api/table", post(create_table)) .route("/api/table", delete(leave_table)) @@ -109,6 +117,23 @@ async fn main() { .unwrap(); } +#[cfg(debug_assertions)] +async fn fake_login() -> Html<&'static str> { + use axum::response::Html; + + Html(r#" + <!DOCTYPE html> + <html lang="en"> + <body> + <p>Log in as:</p> + <ul> + <li><a href="/api/login_callback?user=alice">alice</a></li> + </ul> + </body> + </html> + "#) +} + async fn get_table_view( _session: AuthenticatedSession, extension: ContextExtension, |