Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions auth/server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,8 @@ impl mogh_auth_server::AuthImpl for AppAuthImpl {
// = OIDC AUTH =
// =============

fn oidc_config(&self) -> &OidcConfig {
&core_config().oidc
fn oidc_config(&self) -> Option<&OidcConfig> {
Some(&core_config().oidc)
}

fn find_user_with_oidc_subject(
Expand Down Expand Up @@ -286,6 +286,26 @@ impl mogh_auth_server::AuthImpl for AppAuthImpl {
})
}

fn on_oidc_login(
&self,
user_id: String,
claims: mogh_auth_server::OidcClaims,
) -> mogh_auth_server::DynFuture<mogh_error::Result<()>> {
Box::pin(async move {
let groups = claims
.claim("groups")
.and_then(|groups| groups.as_array())
.into_iter()
.flatten()
.filter_map(|group| group.as_str().map(ToString::to_string))
.collect::<Vec<_>>();

sync_user_groups_from_oidc(user_id, groups)
.await
.map_err(Into::into)
})
}

// ===============
// = GITHUB AUTH =
// ===============
Expand Down Expand Up @@ -539,4 +559,4 @@ impl mogh_server::session::SessionConfig for MemorySessionConfig {
axum::Router::new()
.nest("/auth", mogh_auth_server::api::router::<AppAuthImpl>())
.layer(mogh_server::session::memory_session_layer(MemorySessionConfig))
```
```
27 changes: 24 additions & 3 deletions auth/server/src/api/oidc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,19 @@ pub async fn oidc_callback<I: AuthImpl>(
&nonce,
)
.await?;
let claims = provider
.get_verified_claims(config, &subject, &token, &nonce)
.await?;

let user =
auth.find_user_with_oidc_subject(subject.clone()).await?;

let user_id_or_two_factor = match user {
// Log in existing user
Some(user) => {
auth
.on_oidc_login(user.id().to_string(), claims.clone())
.await?;
get_user_id_or_two_factor(&auth, &session, &user).await?
}
// Sign up user
Expand All @@ -250,8 +256,7 @@ pub async fn oidc_callback<I: AuthImpl>(
);
}

let mut username =
provider.get_username(&subject, &token, &nonce).await;
let mut username = provider.get_username_from_claims(&claims);

// Modify username if it already exists
if auth
Expand All @@ -271,6 +276,13 @@ pub async fn oidc_callback<I: AuthImpl>(
)
.await?;

auth
.on_oidc_signup(user_id.clone(), claims.clone())
.await?;
auth
.on_oidc_login(user_id.clone(), claims.clone())
.await?;

info!(user_id, username, "New user registration (OIDC)");

session.insert_authenticated_user_id(&user_id).await?;
Expand Down Expand Up @@ -308,7 +320,7 @@ async fn link_oidc_callback<I: AuthImpl>(
.context("OIDC login is not set up")
.status_code(StatusCode::BAD_REQUEST)?;

let (subject, _) = provider
let (subject, token) = provider
.validate_extract_subject_and_token(
config,
(state, csrf_token),
Expand All @@ -317,13 +329,19 @@ async fn link_oidc_callback<I: AuthImpl>(
&nonce,
)
.await?;
let claims = provider
.get_verified_claims(config, &subject, &token, &nonce)
.await?;

// Ensure there are no other existing users with this login linked.
if let Some(existing_user) =
auth.find_user_with_oidc_subject(subject.clone()).await?
{
if existing_user.id() == user_id {
// Link is already complete, this is a no-op
auth
.on_oidc_link(user_id.clone(), claims.clone())
.await?;
return Ok(Redirect::to(auth.post_link_redirect()));
} else {
return Err(
Expand All @@ -333,6 +351,9 @@ async fn link_oidc_callback<I: AuthImpl>(
}

auth.link_oidc_login(user_id.clone(), subject).await?;
auth
.on_oidc_link(user_id.clone(), claims.clone())
.await?;

info!(user_id, "OIDC login linked");

Expand Down
32 changes: 32 additions & 0 deletions auth/server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ use crate::{
},
};

pub use provider::oidc::OidcClaims;

pub mod request_ip {
pub use mogh_request_ip::*;
}
Expand Down Expand Up @@ -347,6 +349,36 @@ pub trait AuthImpl: Send + Sync + 'static {
})
}

/// Runs after a verified OIDC login has been mapped to an app user id.
/// This runs for both existing users and newly-created users. If the user
/// has 2FA enabled, this hook runs before the second-factor challenge is
/// completed, after the OIDC identity itself has been validated.
fn on_oidc_login(
&self,
_user_id: String,
_claims: OidcClaims,
) -> DynFuture<mogh_error::Result<()>> {
Box::pin(async { Ok(()) })
}

/// Runs after an OIDC user is created, before the login redirect returns.
fn on_oidc_signup(
&self,
_user_id: String,
_claims: OidcClaims,
) -> DynFuture<mogh_error::Result<()>> {
Box::pin(async { Ok(()) })
}

/// Runs after an OIDC login is linked to an existing app user.
fn on_oidc_link(
&self,
_user_id: String,
_claims: OidcClaims,
) -> DynFuture<mogh_error::Result<()>> {
Box::pin(async { Ok(()) })
}

// ==============
// = NAMED AUTH =
// ==============
Expand Down
Loading