summaryrefslogtreecommitdiff
path: root/server/src/auth.rs
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2022-12-27 19:55:10 -0500
committerKjetil Orbekk <kj@orbekk.com>2022-12-27 19:58:45 -0500
commit21b7b57336cd3bf7bd328ada38c6069a48504f85 (patch)
treec0d47337f584403febcfc9ec365ea1ea810e782e /server/src/auth.rs
parent3418ebf4db2375e0dfe2343da57d674e1f4fd57f (diff)
`cargo fmt`
Diffstat (limited to 'server/src/auth.rs')
-rw-r--r--server/src/auth.rs96
1 files changed, 60 insertions, 36 deletions
diff --git a/server/src/auth.rs b/server/src/auth.rs
index a924f44..2831929 100644
--- a/server/src/auth.rs
+++ b/server/src/auth.rs
@@ -6,21 +6,27 @@ use std::{
sync::{Arc, Mutex},
};
-use crate::{error::BridgeError, server::{ServerState, ServerContext}};
+use crate::{
+ error::BridgeError,
+ server::{ServerContext, ServerState},
+};
use async_trait::async_trait;
use axum::{
- extract::{FromRequestParts, State, FromRef},
- response::{IntoResponse, Response}, http::request::Parts,
+ extract::{FromRef, FromRequestParts, State},
+ http::request::Parts,
+ response::{IntoResponse, Response},
};
use chrono::{DateTime, Utc};
use lru::LruCache;
use openidconnect::{
- core::{CoreClient, CoreProviderMetadata, CoreResponseType, CoreUserInfoClaims},
+ core::{
+ CoreClient, CoreProviderMetadata, CoreResponseType, CoreUserInfoClaims,
+ },
reqwest::async_http_client,
url::Url,
- AccessToken, AccessTokenHash, AuthenticationFlow, AuthorizationCode, ClientId, ClientSecret,
- CsrfToken, IssuerUrl, Nonce, OAuth2TokenResponse, RedirectUrl, RefreshToken, Scope,
- TokenResponse,
+ AccessToken, AccessTokenHash, AuthenticationFlow, AuthorizationCode,
+ ClientId, ClientSecret, CsrfToken, IssuerUrl, Nonce, OAuth2TokenResponse,
+ RedirectUrl, RefreshToken, Scope, TokenResponse,
};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
@@ -62,7 +68,10 @@ impl AuthenticatedSession {
#[async_trait]
pub trait Authenticator {
- async fn user_info(&self, session: &mut AuthenticatedSession) -> Result<String, BridgeError>;
+ async fn user_info(
+ &self,
+ session: &mut AuthenticatedSession,
+ ) -> Result<String, BridgeError>;
async fn authenticate(
&self,
pool: &PgPool,
@@ -121,14 +130,18 @@ impl OauthAuthenticator {
redirect_uri: RedirectUrl,
) -> Self {
// Use OpenID Connect Discovery to fetch the provider metadata.
- let provider_metadata = CoreProviderMetadata::discover_async(issuer_url, async_http_client)
- .await
- .unwrap();
-
- let client =
- CoreClient::from_provider_metadata(provider_metadata, client_id, Some(client_secret))
- // Set the URL the user will be redirected to after the authorization process.
- .set_redirect_uri(redirect_uri);
+ let provider_metadata =
+ CoreProviderMetadata::discover_async(issuer_url, async_http_client)
+ .await
+ .unwrap();
+
+ let client = CoreClient::from_provider_metadata(
+ provider_metadata,
+ client_id,
+ Some(client_secret),
+ )
+ // Set the URL the user will be redirected to after the authorization process.
+ .set_redirect_uri(redirect_uri);
Self {
db,
@@ -168,9 +181,12 @@ impl OauthAuthenticator {
debug!("Got new token: {new_token:#?}");
// TODO: Validate token?
if let Some(expires_in) = new_token.expires_in() {
- session.expiration = refresh_start + chrono::Duration::from_std(expires_in)?;
+ session.expiration =
+ refresh_start + chrono::Duration::from_std(expires_in)?;
} else {
- error!("Token is missing expiration! Will refresh token every time.");
+ error!(
+ "Token is missing expiration! Will refresh token every time."
+ );
}
if let Some(refresh_token) = new_token.refresh_token() {
session.refresh_token = refresh_token.clone();
@@ -202,7 +218,10 @@ impl Authenticator for OauthAuthenticator {
(user_id, auth_url)
}
- async fn user_info(&self, session: &mut AuthenticatedSession) -> Result<String, BridgeError> {
+ async fn user_info(
+ &self,
+ session: &mut AuthenticatedSession,
+ ) -> Result<String, BridgeError> {
self.maybe_refresh_token(session).await?;
let user_info: CoreUserInfoClaims = self
.client
@@ -225,12 +244,10 @@ impl Authenticator for OauthAuthenticator {
auth_params: HashMap<String, String>,
) -> Result<AuthenticatedSession, BridgeError> {
// TODO: If the token is missing from the cache, client should retry logging in.
- let state = self
- .login_cache
- .lock()
- .unwrap()
- .pop(&session_id)
- .ok_or(BridgeError::InvalidRequest("token missing".to_string()))?;
+ let state =
+ self.login_cache.lock().unwrap().pop(&session_id).ok_or(
+ BridgeError::InvalidRequest("token missing".to_string()),
+ )?;
if Some(state.csrf_token.secret()) != auth_params.get("state") {
return Err(BridgeError::InvalidRequest(
"token validation failed".to_string(),
@@ -254,12 +271,15 @@ impl Authenticator for OauthAuthenticator {
let id_token = token.id_token().ok_or(BridgeError::InvalidRequest(
"Server did not return an IdToken".to_string(),
))?;
- let claims = id_token.claims(&self.client.id_token_verifier(), &state.nonce)?;
+ let claims =
+ id_token.claims(&self.client.id_token_verifier(), &state.nonce)?;
// Verify access token hash.
if let Some(expected_access_token_hash) = claims.access_token_hash() {
- let actual_access_token_hash =
- AccessTokenHash::from_token(token.access_token(), &id_token.signing_alg()?)?;
+ let actual_access_token_hash = AccessTokenHash::from_token(
+ token.access_token(),
+ &id_token.signing_alg()?,
+ )?;
if actual_access_token_hash != *expected_access_token_hash {
return Err(BridgeError::InvalidRequest(
"Invalid access token".to_string(),
@@ -274,9 +294,9 @@ impl Authenticator for OauthAuthenticator {
)));
}
- let refresh_token = token
- .refresh_token()
- .ok_or(BridgeError::Internal("Expected refresh token".to_string()))?;
+ let refresh_token = token.refresh_token().ok_or(
+ BridgeError::Internal("Expected refresh token".to_string()),
+ )?;
let mut session = AuthenticatedSession {
player_id: claims.subject().to_string(),
@@ -371,12 +391,13 @@ pub async fn fetch_authenticated_session(
impl<S> FromRequestParts<S> for AuthenticatedSession
where
S: Send + Sync,
- Arc<ServerContext>: FromRef<S>
+ Arc<ServerContext>: FromRef<S>,
{
type Rejection = Response;
async fn from_request_parts(
- parts: &mut Parts, state: &S
+ parts: &mut Parts,
+ state: &S,
) -> Result<Self, Self::Rejection> {
let cookies = Cookies::from_request_parts(parts, state)
.await
@@ -395,9 +416,12 @@ where
}
Ok(s) => s,
};
- let session = match crate::auth::fetch_authenticated_session(&state.db, &session_id)
- .await
- .map_err(|e| e.into_response())?
+ let session = match crate::auth::fetch_authenticated_session(
+ &state.db,
+ &session_id,
+ )
+ .await
+ .map_err(|e| e.into_response())?
{
None => return Err(BridgeError::NotLoggedIn.into_response()),
Some(v) => v,