diff options
author | Kjetil Orbekk <kj@orbekk.com> | 2022-11-25 11:32:43 -0500 |
---|---|---|
committer | Kjetil Orbekk <kj@orbekk.com> | 2022-11-25 11:32:43 -0500 |
commit | f4713b1ccf508c0ec1192ce8d800f21111e655e1 (patch) | |
tree | 25d5641b006af4533c2a25e762526428dc397a85 /server/src/auth.rs | |
parent | 24c71b3ddbcd793e533ee518bc1f82b1b5fa3d9e (diff) |
Extract authenticator logic into a trait
This is in preparation for providing a fake authenticator backend
Diffstat (limited to 'server/src/auth.rs')
-rw-r--r-- | server/src/auth.rs | 98 |
1 files changed, 55 insertions, 43 deletions
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( |