Finish authentication
This commit is contained in:
		@@ -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!(
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user