diff options
Diffstat (limited to 'server')
| -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,  | 
