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 assets_controller;
 | 
				
			||||||
pub mod base_controller;
 | 
					pub mod base_controller;
 | 
				
			||||||
pub mod login_controller;
 | 
					pub mod login_controller;
 | 
				
			||||||
 | 
					pub mod login_api;
 | 
				
			||||||
pub mod settings_controller;
 | 
					pub mod settings_controller;
 | 
				
			||||||
pub mod admin_controller;
 | 
					pub mod admin_controller;
 | 
				
			||||||
pub mod admin_api;
 | 
					pub mod admin_api;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use actix_web::web;
 | 
					use actix_web::web;
 | 
				
			||||||
use webauthn_rs::{AuthenticationState, RegistrationState, Webauthn, WebauthnConfig};
 | 
					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::constants::APP_NAME;
 | 
				
			||||||
use crate::data::app_config::AppConfig;
 | 
					use crate::data::app_config::AppConfig;
 | 
				
			||||||
@@ -45,6 +45,7 @@ pub struct RegisterKeyRequest {
 | 
				
			|||||||
struct RegisterKeyOpaqueData {
 | 
					struct RegisterKeyOpaqueData {
 | 
				
			||||||
    registration_state: RegistrationState,
 | 
					    registration_state: RegistrationState,
 | 
				
			||||||
    user_id: UserID,
 | 
					    user_id: UserID,
 | 
				
			||||||
 | 
					    // TODO : add time
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct AuthRequest {
 | 
					pub struct AuthRequest {
 | 
				
			||||||
@@ -56,6 +57,7 @@ pub struct AuthRequest {
 | 
				
			|||||||
struct AuthStateOpaqueData {
 | 
					struct AuthStateOpaqueData {
 | 
				
			||||||
    authentication_state: AuthenticationState,
 | 
					    authentication_state: AuthenticationState,
 | 
				
			||||||
    user_id: UserID,
 | 
					    user_id: UserID,
 | 
				
			||||||
 | 
					    // TODO : add time
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -123,4 +125,17 @@ impl WebAuthManager {
 | 
				
			|||||||
            login_challenge,
 | 
					            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
 | 
					            // Assets serving
 | 
				
			||||||
            .route("/assets/{path:.*}", web::get().to(assets_route))
 | 
					            .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::get().to(login_controller::login_route))
 | 
				
			||||||
            .route("/login", web::post().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))
 | 
					            .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_otp", web::post().to(login_controller::login_with_otp))
 | 
				
			||||||
            .route("/2fa_webauthn", web::get().to(login_controller::login_with_webauthn))
 | 
					            .route("/2fa_webauthn", web::get().to(login_controller::login_with_webauthn))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Logout page
 | 
					            // Login api
 | 
				
			||||||
            .route("/logout", web::get().to(login_controller::logout_route))
 | 
					            .route("/login/api/auth_webauthn", web::post().to(login_api::auth_webauthn))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Settings routes
 | 
					            // Settings routes
 | 
				
			||||||
            .route("/settings", web::get().to(settings_controller::account_settings_details_route))
 | 
					            .route("/settings", web::get().to(settings_controller::account_settings_details_route))
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user