Add authentication from upstream providers #107

Merged
pierre merged 25 commits from feat-upstream-providers into master 2023-04-27 10:10:29 +00:00
2 changed files with 37 additions and 6 deletions
Showing only changes of commit 4152444a83 - Show all commits

View File

@ -1,7 +1,8 @@
use std::sync::Arc;
use actix::Addr;
use actix_web::{web, HttpResponse, Responder};
use actix_identity::Identity;
use actix_web::{web, HttpRequest, HttpResponse, Responder};
use askama::Template;
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_configuration::ProviderConfigurationHelper;
use crate::data::remote_ip::RemoteIP;
use crate::data::session_identity::{SessionIdentity, SessionStatus};
#[derive(askama::Template)]
#[template(path = "login/prov_login_error.html")]
@ -59,7 +61,13 @@ pub async fn start_login(
states: web::Data<Addr<ProvidersStatesActor>>,
query: web::Query<StartLoginQuery>,
logger: ActionLogger,
id: Option<Identity>,
) -> impl Responder {
// Check if user is already authenticated
if SessionIdentity(id.as_ref()).is_authenticated() {
return redirect_user(query.redirect.get());
}
// Get provider information
let provider = match providers.find_by_id(&query.id) {
None => {
@ -125,6 +133,7 @@ pub struct FinishLoginQuery {
}
/// Finish user authentication using a provider
#[allow(clippy::too_many_arguments)]
pub async fn finish_login(
remote_ip: RemoteIP,
providers: web::Data<Arc<ProvidersManager>>,
@ -133,7 +142,14 @@ pub async fn finish_login(
bruteforce: web::Data<Addr<BruteForceActor>>,
query: web::Query<FinishLoginQuery>,
logger: ActionLogger,
id: Option<Identity>,
http_req: HttpRequest,
) -> impl Responder {
// Check if user is already authenticated
if SessionIdentity(id.as_ref()).is_authenticated() {
return redirect_user("/");
}
let query = match query.0.success {
Some(q) => q,
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
// TODO : redirect user to login route
// TODO : add proper logging
HttpResponse::Ok().body("continue")
let status = if user.has_two_factor() && !user.can_bypass_two_factors_for_ip(remote_ip.0) {
logger.log(Action::UserNeed2FAOnLogin(&user));
SessionStatus::Need2FA
} 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()))
}

View File

@ -70,6 +70,10 @@ pub enum Action<'a> {
provider: &'a Provider,
email: &'a str,
},
ProviderLoginSuccessful {
provider: &'a Provider,
user: &'a User,
},
Signout,
UserNeed2FAOnLogin(&'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),
Action::ProviderLoginFailed { provider, email } =>
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::UserNeed2FAOnLogin(user) => {
format!(