mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 01:57:45 +08:00 
			
		
		
		
	feat(users): add endpoint for terminate auth select (#5135)
This commit is contained in:
		| @ -10,16 +10,17 @@ use crate::user::{ | ||||
|     dashboard_metadata::{ | ||||
|         GetMetaDataRequest, GetMetaDataResponse, GetMultipleMetaDataPayload, SetMetaDataRequest, | ||||
|     }, | ||||
|     AcceptInviteFromEmailRequest, AuthorizeResponse, BeginTotpResponse, ChangePasswordRequest, | ||||
|     ConnectAccountRequest, CreateInternalUserRequest, CreateUserAuthenticationMethodRequest, | ||||
|     DashboardEntryResponse, ForgotPasswordRequest, GetSsoAuthUrlRequest, | ||||
|     GetUserAuthenticationMethodsRequest, GetUserDetailsResponse, GetUserRoleDetailsRequest, | ||||
|     GetUserRoleDetailsResponse, InviteUserRequest, ListUsersResponse, ReInviteUserRequest, | ||||
|     RecoveryCodes, ResetPasswordRequest, RotatePasswordRequest, SendVerifyEmailRequest, | ||||
|     SignInResponse, SignUpRequest, SignUpWithMerchantIdRequest, SsoSignInRequest, | ||||
|     SwitchMerchantIdRequest, TokenOrPayloadResponse, TokenResponse, TwoFactorAuthStatusResponse, | ||||
|     UpdateUserAccountDetailsRequest, UpdateUserAuthenticationMethodRequest, UserFromEmailRequest, | ||||
|     UserMerchantCreate, VerifyEmailRequest, VerifyRecoveryCodeRequest, VerifyTotpRequest, | ||||
|     AcceptInviteFromEmailRequest, AuthSelectRequest, AuthorizeResponse, BeginTotpResponse, | ||||
|     ChangePasswordRequest, ConnectAccountRequest, CreateInternalUserRequest, | ||||
|     CreateUserAuthenticationMethodRequest, DashboardEntryResponse, ForgotPasswordRequest, | ||||
|     GetSsoAuthUrlRequest, GetUserAuthenticationMethodsRequest, GetUserDetailsResponse, | ||||
|     GetUserRoleDetailsRequest, GetUserRoleDetailsResponse, InviteUserRequest, ListUsersResponse, | ||||
|     ReInviteUserRequest, RecoveryCodes, ResetPasswordRequest, RotatePasswordRequest, | ||||
|     SendVerifyEmailRequest, SignInResponse, SignUpRequest, SignUpWithMerchantIdRequest, | ||||
|     SsoSignInRequest, SwitchMerchantIdRequest, TokenOrPayloadResponse, TokenResponse, | ||||
|     TwoFactorAuthStatusResponse, UpdateUserAccountDetailsRequest, | ||||
|     UpdateUserAuthenticationMethodRequest, UserFromEmailRequest, UserMerchantCreate, | ||||
|     VerifyEmailRequest, VerifyRecoveryCodeRequest, VerifyTotpRequest, | ||||
| }; | ||||
|  | ||||
| impl ApiEventMetric for DashboardEntryResponse { | ||||
| @ -83,7 +84,8 @@ common_utils::impl_misc_api_event_type!( | ||||
|     CreateUserAuthenticationMethodRequest, | ||||
|     UpdateUserAuthenticationMethodRequest, | ||||
|     GetSsoAuthUrlRequest, | ||||
|     SsoSignInRequest | ||||
|     SsoSignInRequest, | ||||
|     AuthSelectRequest | ||||
| ); | ||||
|  | ||||
| #[cfg(feature = "dummy_connector")] | ||||
|  | ||||
| @ -372,3 +372,8 @@ pub struct SsoSignInRequest { | ||||
| pub struct AuthIdQueryParam { | ||||
|     pub auth_id: Option<String>, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, serde::Deserialize, serde::Serialize)] | ||||
| pub struct AuthSelectRequest { | ||||
|     pub id: String, | ||||
| } | ||||
|  | ||||
| @ -2312,3 +2312,41 @@ pub async fn sso_sign( | ||||
|  | ||||
|     auth::cookies::set_cookie_response(response, token) | ||||
| } | ||||
|  | ||||
| pub async fn terminate_auth_select( | ||||
|     state: SessionState, | ||||
|     user_token: auth::UserFromSinglePurposeToken, | ||||
|     req: user_api::AuthSelectRequest, | ||||
| ) -> UserResponse<user_api::TokenResponse> { | ||||
|     let user_from_db: domain::UserFromStorage = state | ||||
|         .global_store | ||||
|         .find_user_by_id(&user_token.user_id) | ||||
|         .await | ||||
|         .change_context(UserErrors::InternalServerError)? | ||||
|         .into(); | ||||
|  | ||||
|     let user_authentication_method = state | ||||
|         .store | ||||
|         .get_user_authentication_method_by_id(&req.id) | ||||
|         .await | ||||
|         .change_context(UserErrors::InternalServerError)?; | ||||
|  | ||||
|     let current_flow = domain::CurrentFlow::new(user_token, domain::SPTFlow::AuthSelect.into())?; | ||||
|     let mut next_flow = current_flow.next(user_from_db.clone(), &state).await?; | ||||
|  | ||||
|     // Skip SSO if continue with password(TOTP) | ||||
|     if next_flow.get_flow() == domain::UserFlow::SPTFlow(domain::SPTFlow::SSO) | ||||
|         && user_authentication_method.auth_type != common_enums::UserAuthType::OpenIdConnect | ||||
|     { | ||||
|         next_flow = next_flow.skip(user_from_db, &state).await?; | ||||
|     } | ||||
|     let token = next_flow.get_token(&state).await?; | ||||
|  | ||||
|     auth::cookies::set_cookie_response( | ||||
|         user_api::TokenResponse { | ||||
|             token: token.clone(), | ||||
|             token_type: next_flow.get_flow().into(), | ||||
|         }, | ||||
|         token, | ||||
|     ) | ||||
| } | ||||
|  | ||||
| @ -1417,7 +1417,8 @@ impl User { | ||||
|                 .service( | ||||
|                     web::resource("/list").route(web::get().to(list_user_authentication_methods)), | ||||
|                 ) | ||||
|                 .service(web::resource("/url").route(web::get().to(get_sso_auth_url))), | ||||
|                 .service(web::resource("/url").route(web::get().to(get_sso_auth_url))) | ||||
|                 .service(web::resource("/select").route(web::post().to(terminate_auth_select))), | ||||
|         ); | ||||
|  | ||||
|         #[cfg(feature = "email")] | ||||
|  | ||||
| @ -232,7 +232,8 @@ impl From<Flow> for ApiIdentifier { | ||||
|             | Flow::UpdateUserAuthenticationMethod | ||||
|             | Flow::ListUserAuthenticationMethods | ||||
|             | Flow::GetSsoAuthUrl | ||||
|             | Flow::SignInWithSso => Self::User, | ||||
|             | Flow::SignInWithSso | ||||
|             | Flow::AuthSelect => Self::User, | ||||
|  | ||||
|             Flow::ListRoles | ||||
|             | Flow::GetRole | ||||
|  | ||||
| @ -876,3 +876,22 @@ pub async fn list_user_authentication_methods( | ||||
|     )) | ||||
|     .await | ||||
| } | ||||
|  | ||||
| pub async fn terminate_auth_select( | ||||
|     state: web::Data<AppState>, | ||||
|     req: HttpRequest, | ||||
|     json_payload: web::Json<user_api::AuthSelectRequest>, | ||||
| ) -> HttpResponse { | ||||
|     let flow = Flow::AuthSelect; | ||||
|  | ||||
|     Box::pin(api::server_wrap( | ||||
|         flow, | ||||
|         state.clone(), | ||||
|         &req, | ||||
|         json_payload.into_inner(), | ||||
|         |state, user, req, _| user_core::terminate_auth_select(state, user, req), | ||||
|         &auth::SinglePurposeJWTAuth(TokenPurpose::AuthSelect), | ||||
|         api_locking::LockAction::NotApplicable, | ||||
|     )) | ||||
|     .await | ||||
| } | ||||
|  | ||||
| @ -51,9 +51,8 @@ impl SPTFlow { | ||||
|     ) -> UserResult<bool> { | ||||
|         match self { | ||||
|             // Auth | ||||
|             // AuthSelect and SSO flow are not enabled, once the terminate SSO API is ready, we can enable these flows | ||||
|             Self::AuthSelect => Ok(false), | ||||
|             Self::SSO => Ok(false), | ||||
|             Self::AuthSelect => Ok(true), | ||||
|             Self::SSO => Ok(true), | ||||
|             // TOTP | ||||
|             Self::TOTP => Ok(!path.contains(&TokenPurpose::SSO)), | ||||
|             // Main email APIs | ||||
| @ -311,6 +310,26 @@ impl NextFlow { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub async fn skip(self, user: UserFromStorage, state: &SessionState) -> UserResult<Self> { | ||||
|         let flows = self.origin.get_flows(); | ||||
|         let index = flows | ||||
|             .iter() | ||||
|             .position(|flow| flow == &self.get_flow()) | ||||
|             .ok_or(UserErrors::InternalServerError)?; | ||||
|         let remaining_flows = flows.iter().skip(index + 1); | ||||
|         for flow in remaining_flows { | ||||
|             if flow.is_required(&user, &self.path, state).await? { | ||||
|                 return Ok(Self { | ||||
|                     origin: self.origin.clone(), | ||||
|                     next_flow: *flow, | ||||
|                     user, | ||||
|                     path: self.path, | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|         Err(UserErrors::InternalServerError.into()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<UserFlow> for TokenPurpose { | ||||
|  | ||||
| @ -155,7 +155,7 @@ pub enum Flow { | ||||
|     PaymentsStart, | ||||
|     /// Payments list flow. | ||||
|     PaymentsList, | ||||
|     // Payments filters flow | ||||
|     /// Payments filters flow | ||||
|     PaymentsFilters, | ||||
|     #[cfg(feature = "payouts")] | ||||
|     /// Payouts create flow | ||||
| @ -412,7 +412,7 @@ pub enum Flow { | ||||
|     UserFromEmail, | ||||
|     /// Begin TOTP | ||||
|     TotpBegin, | ||||
|     // Reset TOTP | ||||
|     /// Reset TOTP | ||||
|     TotpReset, | ||||
|     /// Verify TOTP | ||||
|     TotpVerify, | ||||
| @ -422,20 +422,22 @@ pub enum Flow { | ||||
|     RecoveryCodeVerify, | ||||
|     /// Generate or Regenerate recovery codes | ||||
|     RecoveryCodesGenerate, | ||||
|     // Terminate two factor authentication | ||||
|     /// Terminate two factor authentication | ||||
|     TerminateTwoFactorAuth, | ||||
|     // Check 2FA status | ||||
|     /// Check 2FA status | ||||
|     TwoFactorAuthStatus, | ||||
|     // Create user authentication method | ||||
|     /// Create user authentication method | ||||
|     CreateUserAuthenticationMethod, | ||||
|     // Update user authentication method | ||||
|     /// Update user authentication method | ||||
|     UpdateUserAuthenticationMethod, | ||||
|     // List user authentication methods | ||||
|     /// List user authentication methods | ||||
|     ListUserAuthenticationMethods, | ||||
|     /// Get sso auth url | ||||
|     GetSsoAuthUrl, | ||||
|     /// Signin with SSO | ||||
|     SignInWithSso, | ||||
|     /// Auth Select | ||||
|     AuthSelect, | ||||
|     /// List initial webhook delivery attempts | ||||
|     WebhookEventInitialDeliveryAttemptList, | ||||
|     /// List delivery attempts for a webhook event | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Apoorv Dixit
					Apoorv Dixit