Managed to authenticate user using Webauthn
This commit is contained in:
		
							
								
								
									
										33
									
								
								src/controllers/login_api.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/controllers/login_api.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
use actix_identity::Identity;
 | 
			
		||||
use actix_web::{HttpResponse, Responder, web};
 | 
			
		||||
use webauthn_rs::proto::PublicKeyCredential;
 | 
			
		||||
 | 
			
		||||
use crate::data::session_identity::{SessionIdentity, SessionStatus};
 | 
			
		||||
use crate::data::webauthn_manager::WebAuthManagerReq;
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize)]
 | 
			
		||||
pub struct AuthWebauthnRequest {
 | 
			
		||||
    opaque_state: String,
 | 
			
		||||
    credential: PublicKeyCredential,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn auth_webauthn(id: Identity,
 | 
			
		||||
                           req: web::Json<AuthWebauthnRequest>,
 | 
			
		||||
                           manager: WebAuthManagerReq) -> impl Responder {
 | 
			
		||||
    if !SessionIdentity(&id).need_2fa_auth() {
 | 
			
		||||
        return HttpResponse::Unauthorized().json("No 2FA required!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let user_id = SessionIdentity(&id).user_id();
 | 
			
		||||
 | 
			
		||||
    match manager.finish_authentication(&user_id, &req.opaque_state, &req.credential) {
 | 
			
		||||
        Ok(_) => {
 | 
			
		||||
            SessionIdentity(&id).set_status(SessionStatus::SignedIn);
 | 
			
		||||
            HttpResponse::Ok().body("You are authenticated!")
 | 
			
		||||
        }
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to authenticate user using webauthn! {:?}", e);
 | 
			
		||||
            HttpResponse::InternalServerError().body("Failed to validate security key!")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
pub mod assets_controller;
 | 
			
		||||
pub mod base_controller;
 | 
			
		||||
pub mod login_controller;
 | 
			
		||||
pub mod login_api;
 | 
			
		||||
pub mod settings_controller;
 | 
			
		||||
pub mod admin_controller;
 | 
			
		||||
pub mod admin_api;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
use actix_web::web;
 | 
			
		||||
use webauthn_rs::{AuthenticationState, RegistrationState, Webauthn, WebauthnConfig};
 | 
			
		||||
use webauthn_rs::proto::{CreationChallengeResponse, Credential, RegisterPublicKeyCredential, RequestChallengeResponse};
 | 
			
		||||
use webauthn_rs::proto::{CreationChallengeResponse, Credential, PublicKeyCredential, RegisterPublicKeyCredential, RequestChallengeResponse};
 | 
			
		||||
 | 
			
		||||
use crate::constants::APP_NAME;
 | 
			
		||||
use crate::data::app_config::AppConfig;
 | 
			
		||||
@@ -45,6 +45,7 @@ pub struct RegisterKeyRequest {
 | 
			
		||||
struct RegisterKeyOpaqueData {
 | 
			
		||||
    registration_state: RegistrationState,
 | 
			
		||||
    user_id: UserID,
 | 
			
		||||
    // TODO : add time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct AuthRequest {
 | 
			
		||||
@@ -56,6 +57,7 @@ pub struct AuthRequest {
 | 
			
		||||
struct AuthStateOpaqueData {
 | 
			
		||||
    authentication_state: AuthenticationState,
 | 
			
		||||
    user_id: UserID,
 | 
			
		||||
    // TODO : add time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -123,4 +125,17 @@ impl WebAuthManager {
 | 
			
		||||
            login_challenge,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn finish_authentication(&self, user_id: &UserID, opaque_state: &str,
 | 
			
		||||
                                 pub_cred: &PublicKeyCredential) -> Res {
 | 
			
		||||
        let state: AuthStateOpaqueData = self.crypto_wrapper.decrypt(opaque_state)?;
 | 
			
		||||
        if &state.user_id != user_id {
 | 
			
		||||
            return Err(Box::new(
 | 
			
		||||
                std::io::Error::new(ErrorKind::Other, "Invalid user for pubkey!")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.core.authenticate_credential(pub_cred, &state.authentication_state)?;
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -111,7 +111,8 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
            // Assets serving
 | 
			
		||||
            .route("/assets/{path:.*}", web::get().to(assets_route))
 | 
			
		||||
 | 
			
		||||
            // Login page
 | 
			
		||||
            // Login pages
 | 
			
		||||
            .route("/logout", web::get().to(login_controller::logout_route))
 | 
			
		||||
            .route("/login", web::get().to(login_controller::login_route))
 | 
			
		||||
            .route("/login", web::post().to(login_controller::login_route))
 | 
			
		||||
            .route("/reset_password", web::get().to(login_controller::reset_password_route))
 | 
			
		||||
@@ -121,8 +122,8 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
            .route("/2fa_otp", web::post().to(login_controller::login_with_otp))
 | 
			
		||||
            .route("/2fa_webauthn", web::get().to(login_controller::login_with_webauthn))
 | 
			
		||||
 | 
			
		||||
            // Logout page
 | 
			
		||||
            .route("/logout", web::get().to(login_controller::logout_route))
 | 
			
		||||
            // Login api
 | 
			
		||||
            .route("/login/api/auth_webauthn", web::post().to(login_api::auth_webauthn))
 | 
			
		||||
 | 
			
		||||
            // Settings routes
 | 
			
		||||
            .route("/settings", web::get().to(settings_controller::account_settings_details_route))
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user