summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2022-11-25 14:09:09 -0500
committerKjetil Orbekk <kj@orbekk.com>2022-11-25 14:09:09 -0500
commit2f35026022827cd86615135c6397f03b74fe1b46 (patch)
tree17c96f91330003aace047ae6b84aabd876d0ee5a
parent9d191019757eae3bba45e8e1a021fefdc69a9fae (diff)
Hook up fake authenticator backend for testing
-rw-r--r--server/src/auth.rs20
-rw-r--r--server/src/error.rs3
-rw-r--r--server/src/fake_auth.rs62
-rw-r--r--server/src/main.rs33
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,