Can enforce 2FA for specific clients
This commit is contained in:
		| @@ -22,6 +22,8 @@ You can configure a list of clients (Relying Parties) in a `clients.yaml` file w | ||||
|   default: true | ||||
|   # If you want the client to be granted to every users, regardless their account configuration | ||||
|   granted_to_all_users: true | ||||
|   # If you want users to have performed recent second factor authentication before accessing this client, set this setting to true | ||||
|   enforce_mfa_auth: true | ||||
| ``` | ||||
|  | ||||
| On the first run, BasicOIDC will create a new administrator with credentials `admin` / `admin`. On first login you will have to change these default credentials. | ||||
| @@ -32,7 +34,7 @@ In order to run BasicOIDC for development, you will need to create a least an em | ||||
| * [x] `authorization_code` flow | ||||
| * [x] Client authentication using secrets  | ||||
| * [x] Bruteforce protection  | ||||
| * [x] 2 factor authentication | ||||
| * [x] 2 factors authentication | ||||
|   * [x] TOTP (authenticator app) | ||||
|   * [x] Using a security key (Webauthn) | ||||
| * [ ] Fully responsive webui | ||||
|   | ||||
| @@ -13,7 +13,7 @@ use crate::actors::openid_sessions_actor::{OpenIDSessionsActor, Session, Session | ||||
| use crate::actors::users_actor::UsersActor; | ||||
| use crate::actors::{openid_sessions_actor, users_actor}; | ||||
| use crate::constants::*; | ||||
| use crate::controllers::base_controller::build_fatal_error_page; | ||||
| use crate::controllers::base_controller::{build_fatal_error_page, redirect_user}; | ||||
| use crate::data::action_logger::{Action, ActionLogger}; | ||||
| use crate::data::app_config::AppConfig; | ||||
| use crate::data::client::{ClientID, ClientManager}; | ||||
| @@ -21,6 +21,7 @@ use crate::data::code_challenge::CodeChallenge; | ||||
| use crate::data::current_user::CurrentUser; | ||||
| use crate::data::id_token::IdToken; | ||||
| use crate::data::jwt_signer::{JWTSigner, JsonWebKey}; | ||||
| use crate::data::login_redirect::{get_2fa_url, LoginRedirect}; | ||||
|  | ||||
| use crate::data::session_identity::SessionIdentity; | ||||
| use crate::data::user::User; | ||||
| @@ -128,6 +129,7 @@ fn error_redirect(query: &AuthorizeQuery, error: &str, description: &str) -> Htt | ||||
| } | ||||
|  | ||||
| pub async fn authorize( | ||||
|     req: HttpRequest, | ||||
|     user: CurrentUser, | ||||
|     id: Identity, | ||||
|     query: web::Query<AuthorizeQuery>, | ||||
| @@ -142,6 +144,12 @@ pub async fn authorize( | ||||
|         Some(c) => c, | ||||
|     }; | ||||
|  | ||||
|     // Check if 2FA is required | ||||
|     if client.enforce_2fa_auth && user.should_request_2fa_for_critical_functions() { | ||||
|         let uri = get_2fa_url(&LoginRedirect::from_req(&req), true); | ||||
|         return redirect_user(&uri); | ||||
|     } | ||||
|  | ||||
|     let redirect_uri = query.redirect_uri.trim().to_string(); | ||||
|     if !redirect_uri.starts_with(&client.redirect_uri) { | ||||
|         return HttpResponse::BadRequest().body(build_fatal_error_page("Redirect URI is invalid!")); | ||||
|   | ||||
| @@ -28,6 +28,10 @@ pub struct Client { | ||||
|     /// Specify whether a client is granted to all users | ||||
|     #[serde(default = "bool::default")] | ||||
|     pub granted_to_all_users: bool, | ||||
|  | ||||
|     /// Specify whether recent Second Factor Authentication is required to access this client | ||||
|     #[serde(default = "bool::default")] | ||||
|     pub enforce_2fa_auth: bool, | ||||
| } | ||||
|  | ||||
| impl PartialEq for Client { | ||||
|   | ||||
| @@ -20,10 +20,10 @@ impl FromRequest for CriticalRoute { | ||||
|                 .await | ||||
|                 .expect("Failed to extract user identity!"); | ||||
|  | ||||
|             if current_user.should_request_2fa_for_critical_function() { | ||||
|                 let url = get_2fa_url(&LoginRedirect::from_req(&req), true); | ||||
|             if current_user.should_request_2fa_for_critical_functions() { | ||||
|                 let uri = get_2fa_url(&LoginRedirect::from_req(&req), true); | ||||
|  | ||||
|                 return Err(FromRequestRedirect::new(url)); | ||||
|                 return Err(FromRequestRedirect::new(uri)); | ||||
|             } | ||||
|  | ||||
|             Ok(Self) | ||||
|   | ||||
| @@ -22,7 +22,7 @@ pub struct CurrentUser { | ||||
| } | ||||
|  | ||||
| impl CurrentUser { | ||||
|     pub fn should_request_2fa_for_critical_function(&self) -> bool { | ||||
|     pub fn should_request_2fa_for_critical_functions(&self) -> bool { | ||||
|         self.user.has_two_factor() | ||||
|             && self | ||||
|                 .last_2fa_auth | ||||
|   | ||||
		Reference in New Issue
	
	Block a user