Add authentication from upstream providers #107
@ -1,7 +1,8 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use actix::Addr;
|
use actix::Addr;
|
||||||
use actix_web::{web, HttpResponse, Responder};
|
use actix_identity::Identity;
|
||||||
|
use actix_web::{web, HttpRequest, HttpResponse, Responder};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
|
||||||
use crate::actors::bruteforce_actor::BruteForceActor;
|
use crate::actors::bruteforce_actor::BruteForceActor;
|
||||||
@ -16,6 +17,7 @@ use crate::data::login_redirect::LoginRedirect;
|
|||||||
use crate::data::provider::{ProviderID, ProvidersManager};
|
use crate::data::provider::{ProviderID, ProvidersManager};
|
||||||
use crate::data::provider_configuration::ProviderConfigurationHelper;
|
use crate::data::provider_configuration::ProviderConfigurationHelper;
|
||||||
use crate::data::remote_ip::RemoteIP;
|
use crate::data::remote_ip::RemoteIP;
|
||||||
|
use crate::data::session_identity::{SessionIdentity, SessionStatus};
|
||||||
|
|
||||||
#[derive(askama::Template)]
|
#[derive(askama::Template)]
|
||||||
#[template(path = "login/prov_login_error.html")]
|
#[template(path = "login/prov_login_error.html")]
|
||||||
@ -59,7 +61,13 @@ pub async fn start_login(
|
|||||||
states: web::Data<Addr<ProvidersStatesActor>>,
|
states: web::Data<Addr<ProvidersStatesActor>>,
|
||||||
query: web::Query<StartLoginQuery>,
|
query: web::Query<StartLoginQuery>,
|
||||||
logger: ActionLogger,
|
logger: ActionLogger,
|
||||||
|
id: Option<Identity>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
|
// Check if user is already authenticated
|
||||||
|
if SessionIdentity(id.as_ref()).is_authenticated() {
|
||||||
|
return redirect_user(query.redirect.get());
|
||||||
|
}
|
||||||
|
|
||||||
// Get provider information
|
// Get provider information
|
||||||
let provider = match providers.find_by_id(&query.id) {
|
let provider = match providers.find_by_id(&query.id) {
|
||||||
None => {
|
None => {
|
||||||
@ -125,6 +133,7 @@ pub struct FinishLoginQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish user authentication using a provider
|
/// Finish user authentication using a provider
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn finish_login(
|
pub async fn finish_login(
|
||||||
remote_ip: RemoteIP,
|
remote_ip: RemoteIP,
|
||||||
providers: web::Data<Arc<ProvidersManager>>,
|
providers: web::Data<Arc<ProvidersManager>>,
|
||||||
@ -133,7 +142,14 @@ pub async fn finish_login(
|
|||||||
bruteforce: web::Data<Addr<BruteForceActor>>,
|
bruteforce: web::Data<Addr<BruteForceActor>>,
|
||||||
query: web::Query<FinishLoginQuery>,
|
query: web::Query<FinishLoginQuery>,
|
||||||
logger: ActionLogger,
|
logger: ActionLogger,
|
||||||
|
id: Option<Identity>,
|
||||||
|
http_req: HttpRequest,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
|
// Check if user is already authenticated
|
||||||
|
if SessionIdentity(id.as_ref()).is_authenticated() {
|
||||||
|
return redirect_user("/");
|
||||||
|
}
|
||||||
|
|
||||||
let query = match query.0.success {
|
let query = match query.0.success {
|
||||||
Some(q) => q,
|
Some(q) => q,
|
||||||
None => {
|
None => {
|
||||||
@ -339,10 +355,19 @@ pub async fn finish_login(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
log::info!("user={:#?}", user);
|
logger.log(Action::ProviderLoginSuccessful {
|
||||||
|
provider: &provider,
|
||||||
|
user: &user,
|
||||||
|
});
|
||||||
|
|
||||||
// TODO : check if 2FA is enabled
|
let status = if user.has_two_factor() && !user.can_bypass_two_factors_for_ip(remote_ip.0) {
|
||||||
// TODO : redirect user to login route
|
logger.log(Action::UserNeed2FAOnLogin(&user));
|
||||||
// TODO : add proper logging
|
SessionStatus::Need2FA
|
||||||
HttpResponse::Ok().body("continue")
|
} else {
|
||||||
|
logger.log(Action::UserSuccessfullyAuthenticated(&user));
|
||||||
|
SessionStatus::SignedIn
|
||||||
|
};
|
||||||
|
|
||||||
|
SessionIdentity(id.as_ref()).set_user(&http_req, &user, status);
|
||||||
|
redirect_user(&format!("/login?redirect={}", state.redirect.get_encoded()))
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,10 @@ pub enum Action<'a> {
|
|||||||
provider: &'a Provider,
|
provider: &'a Provider,
|
||||||
email: &'a str,
|
email: &'a str,
|
||||||
},
|
},
|
||||||
|
ProviderLoginSuccessful {
|
||||||
|
provider: &'a Provider,
|
||||||
|
user: &'a User,
|
||||||
|
},
|
||||||
Signout,
|
Signout,
|
||||||
UserNeed2FAOnLogin(&'a User),
|
UserNeed2FAOnLogin(&'a User),
|
||||||
UserSuccessfullyAuthenticated(&'a User),
|
UserSuccessfullyAuthenticated(&'a User),
|
||||||
@ -153,6 +157,8 @@ impl<'a> Action<'a> {
|
|||||||
format!("could not login using provider {} because the account associated to the email {email} is not allowed to authenticate using this provider!", &provider.id.0),
|
format!("could not login using provider {} because the account associated to the email {email} is not allowed to authenticate using this provider!", &provider.id.0),
|
||||||
Action::ProviderLoginFailed { provider, email } =>
|
Action::ProviderLoginFailed { provider, email } =>
|
||||||
format!("could not login using provider {} with the email {email} for an unknown reason!", &provider.id.0),
|
format!("could not login using provider {} with the email {email} for an unknown reason!", &provider.id.0),
|
||||||
|
Action::ProviderLoginSuccessful {provider, user} =>
|
||||||
|
format!("successfully authenticated using provider {} as {}", provider.id.0, user.quick_identity()),
|
||||||
Action::Signout => "signed out".to_string(),
|
Action::Signout => "signed out".to_string(),
|
||||||
Action::UserNeed2FAOnLogin(user) => {
|
Action::UserNeed2FAOnLogin(user) => {
|
||||||
format!(
|
format!(
|
||||||
|
Loading…
Reference in New Issue
Block a user