summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2022-11-25 11:32:43 -0500
committerKjetil Orbekk <kj@orbekk.com>2022-11-25 11:32:43 -0500
commitf4713b1ccf508c0ec1192ce8d800f21111e655e1 (patch)
tree25d5641b006af4533c2a25e762526428dc397a85
parent24c71b3ddbcd793e533ee518bc1f82b1b5fa3d9e (diff)
Extract authenticator logic into a trait
This is in preparation for providing a fake authenticator backend
-rw-r--r--.gitignore3
-rw-r--r--flake.nix4
-rw-r--r--server/src/auth.rs98
-rw-r--r--server/src/main.rs9
-rw-r--r--server/src/server.rs2
5 files changed, 68 insertions, 48 deletions
diff --git a/.gitignore b/.gitignore
index 15ed889..ff49b2f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,5 @@ tmp/
target/
**/*.rs.bk
webapp/dist
-result \ No newline at end of file
+result
+.env \ No newline at end of file
diff --git a/flake.nix b/flake.nix
index e5c91dc..edba281 100644
--- a/flake.nix
+++ b/flake.nix
@@ -4,6 +4,10 @@
nixpkgs.url = "nixpkgs";
};
+ # TODO: Stuff to include in rust development environment:
+ # - trunk
+ # - cargo-watch
+ # - sqlx-cli
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = nixpkgs.legacyPackages.${system};
diff --git a/server/src/auth.rs b/server/src/auth.rs
index 445a0d2..7222199 100644
--- a/server/src/auth.rs
+++ b/server/src/auth.rs
@@ -42,7 +42,19 @@ pub struct AuthenticatedSession {
refresh_token: RefreshToken,
}
-pub struct Authenticator {
+#[async_trait]
+pub trait Authenticator {
+ async fn user_info(&self, session: &mut AuthenticatedSession) -> Result<String, BridgeError>;
+ async fn authenticate(
+ &self,
+ pool: &PgPool,
+ session_id: SessionId,
+ auth_params: HashMap<String, String>,
+ ) -> Result<AuthenticatedSession, BridgeError>;
+ async fn get_login_url(&self) -> (SessionId, Url);
+}
+
+pub struct OauthAuthenticator {
pub client: CoreClient,
pub login_cache: Arc<Mutex<LruCache<SessionId, LoginState>>>,
pub db: PgPool,
@@ -82,7 +94,7 @@ fn redirect_url(app_url: &str) -> RedirectUrl {
RedirectUrl::new(format!("{}{}", app_url, LOGIN_CALLBACK)).unwrap()
}
-impl Authenticator {
+impl OauthAuthenticator {
pub async fn new(
db: PgPool,
issuer_url: IssuerUrl,
@@ -111,7 +123,7 @@ impl Authenticator {
pub async fn from_env(db: PgPool) -> Self {
let app_url = env::var("APP_URL").unwrap();
- Authenticator::new(
+ OauthAuthenticator::new(
db,
IssuerUrl::new(env::var("OPENID_ISSUER_URL").unwrap()).unwrap(),
ClientId::new(env::var("OPENID_CLIENT_ID").unwrap()),
@@ -121,26 +133,7 @@ impl Authenticator {
.await
}
- pub async fn get_login_url(&self) -> (SessionId, Url) {
- let (auth_url, csrf_token, nonce) = self
- .client
- .authorize_url(
- AuthenticationFlow::<CoreResponseType>::AuthorizationCode,
- CsrfToken::new_random,
- Nonce::new_random,
- )
- .add_scope(Scope::new("email".to_string()))
- .add_scope(Scope::new("profile".to_string()))
- .url();
- let user_id = SessionId::new();
- self.login_cache
- .lock()
- .unwrap()
- .put(user_id.clone(), LoginState { csrf_token, nonce });
- (user_id, auth_url)
- }
-
- pub async fn maybe_refresh_token(
+ async fn maybe_refresh_token(
&self,
session: &mut AuthenticatedSession,
) -> Result<(), BridgeError> {
@@ -168,8 +161,46 @@ impl Authenticator {
store_authenticated_session(&self.db, session).await?;
Ok(())
}
+}
- pub async fn authenticate(
+#[async_trait]
+impl Authenticator for OauthAuthenticator {
+ async fn get_login_url(&self) -> (SessionId, Url) {
+ let (auth_url, csrf_token, nonce) = self
+ .client
+ .authorize_url(
+ AuthenticationFlow::<CoreResponseType>::AuthorizationCode,
+ CsrfToken::new_random,
+ Nonce::new_random,
+ )
+ .add_scope(Scope::new("email".to_string()))
+ .add_scope(Scope::new("profile".to_string()))
+ .url();
+ let user_id = SessionId::new();
+ self.login_cache
+ .lock()
+ .unwrap()
+ .put(user_id.clone(), LoginState { csrf_token, nonce });
+ (user_id, auth_url)
+ }
+
+ async fn user_info(&self, session: &mut AuthenticatedSession) -> Result<String, BridgeError> {
+ self.maybe_refresh_token(session).await?;
+ let user_info: CoreUserInfoClaims = self
+ .client
+ .user_info(session.access_token.clone(), None)?
+ .request_async(async_http_client)
+ .await?;
+ debug!("Resolved user info: {user_info:#?}");
+ Ok(user_info
+ .preferred_username()
+ .ok_or(BridgeError::Internal(
+ "missing preferred username".to_string(),
+ ))?
+ .to_string())
+ }
+
+ async fn authenticate(
&self,
pool: &PgPool,
session_id: SessionId,
@@ -240,25 +271,6 @@ impl Authenticator {
store_authenticated_session(pool, &mut session).await?;
Ok(session)
}
-
- pub async fn user_info(
- &self,
- session: &mut AuthenticatedSession,
- ) -> Result<String, BridgeError> {
- self.maybe_refresh_token(session).await?;
- let user_info: CoreUserInfoClaims = self
- .client
- .user_info(session.access_token.clone(), None)?
- .request_async(async_http_client)
- .await?;
- debug!("Resolved user info: {user_info:#?}");
- Ok(user_info
- .preferred_username()
- .ok_or(BridgeError::Internal(
- "missing preferred username".to_string(),
- ))?
- .to_string())
- }
}
async fn store_authenticated_session(
diff --git a/server/src/main.rs b/server/src/main.rs
index 130506c..2363110 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -13,14 +13,14 @@ use protocol::{bridge_engine::{self, TableView, Player}, Table, UserInfo};
use server::ContextExtension;
use tower_cookies::{Cookie, CookieManagerLayer, Cookies};
use tower_http::trace::TraceLayer;
-use tracing::info;
+use tracing::{info, log::warn};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
mod auth;
mod error;
mod play;
mod server;
use crate::{
- auth::{Authenticator, SessionId},
+ auth::{OauthAuthenticator, SessionId},
server::ServerContext,
};
use crate::{
@@ -61,9 +61,12 @@ async fn main() {
let app_url = env::var("APP_URL").unwrap();
+ #[cfg(debug_assertions)]
+ warn!("Running a debug build.");
+
let state = Arc::new(ServerContext {
app_url,
- authenticator: Authenticator::from_env(db_pool.clone()).await,
+ authenticator: Box::new(OauthAuthenticator::from_env(db_pool.clone()).await),
db: db_pool,
});
diff --git a/server/src/server.rs b/server/src/server.rs
index eddba94..647abf9 100644
--- a/server/src/server.rs
+++ b/server/src/server.rs
@@ -7,7 +7,7 @@ use crate::auth::Authenticator;
pub struct ServerContext {
pub app_url: String,
- pub authenticator: Authenticator,
+ pub authenticator: Box<dyn Authenticator + Send + Sync>,
pub db: PgPool,
}
pub type ContextExtension = Extension<Arc<ServerContext>>;