Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4.6.x] fix(mfa): avoid infinite loop if session expired #5450

Merged
merged 1 commit into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ private void renderPage(RoutingContext routingContext) {
try {
if (routingContext.user() == null) {
logger.warn("User must be authenticated to enroll MFA challenge.");
routingContext.fail(401);
routingContext.fail(401, new InvalidRequestException("Authentication required to enroll a factor"));
return;
}
var context = new MfaFilterContext(routingContext, routingContext.get(ConstantKeys.CLIENT_CONTEXT_KEY), factorManager, ruleEngine);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public void doHandle(RoutingContext context) {
private String getRedirectUrl(RoutingContext context, String errorDescription){
MultiMap queryParams = updateQueryParams(context, errorDescription);
String path = context.get(CONTEXT_PATH) + errorPage;
if (context.user() == null) {
// user is missing, that mean he didn't signed in so the session may have expired
// redirect to the login page
path = context.get(CONTEXT_PATH) + RootProvider.PATH_LOGIN;
}
return resolveProxyRequest(context.request(), path, queryParams, true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.gravitee.am.service.exception.EnrollmentChannelValidationException;
import io.vertx.rxjava3.core.http.HttpServerRequest;
import io.vertx.rxjava3.core.http.HttpServerResponse;
import io.vertx.rxjava3.ext.auth.User;
import io.vertx.rxjava3.ext.web.RoutingContext;
import io.vertx.rxjava3.ext.web.Session;
import org.junit.Before;
Expand All @@ -35,6 +36,7 @@
import static io.gravitee.am.gateway.handler.common.vertx.utils.UriBuilderRequest.CONTEXT_PATH;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;

@RunWith(MockitoJUnitRunner.class)
public class MFAEnrollFailureHandlerTest {
Expand All @@ -61,9 +63,23 @@ public void setUp() throws Exception {
Mockito.when(ctx.get(CONTEXT_PATH)).thenReturn("test-domain");
}

@Test
public void should_put_redirect_on_login_if_no_user(){
// given
Mockito.when(ctx.failure()).thenReturn(new EnrollmentChannelValidationException("errorMessage"));
Mockito.when(request.uri()).thenReturn("https://am.com/mfa/enroll");

// when
handler.doHandle(ctx);

// verify
Mockito.verify(response).putHeader(eq("Location"), eq("test-domain/login?error=mfa_enroll_failed&error_code=enrollment_channel_invalid&error_description=errorMessage"));
}

@Test
public void should_put_error_message_from_exception(){
// given
Mockito.when(ctx.user()).thenReturn(mock(User.class));
Mockito.when(ctx.failure()).thenReturn(new EnrollmentChannelValidationException("errorMessage"));
Mockito.when(request.uri()).thenReturn("https://am.com/mfa/enroll");

Expand All @@ -78,6 +94,7 @@ public void should_put_error_message_from_exception(){
public void should_put_default_error_message_then_ex_is_missing(){
// given
Mockito.when(request.uri()).thenReturn("https://am.com/mfa/enroll");
Mockito.when(ctx.user()).thenReturn(mock(User.class));

// when
handler.doHandle(ctx);
Expand All @@ -100,4 +117,4 @@ public void should_put_error_hash_to_session(){
Mockito.verify(session).put(eq(ERROR_HASH), eq(expectedHash));
}

}
}