From 8b7bc5b153d1c7b425cf7aa0a8879105e609de38 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 22 Jan 2016 18:39:55 -0500 Subject: [PATCH] redirect after post in flow --- .../AuthenticationProcessor.java | 23 +++++++++++++++ .../DefaultAuthenticationFlow.java | 8 ++++++ .../FormAuthenticationFlow.java | 1 + .../resources/LoginActionsService.java | 28 +++++++++++-------- 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java index 0ea6ad99b8..184df85f3f 100755 --- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java +++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java @@ -57,6 +57,7 @@ public class AuthenticationProcessor { protected String flowPath; protected boolean browserFlow; protected BruteForceProtector protector; + protected boolean oneActionWasSuccessful; /** * This could be an error message forwarded from another authenticator */ @@ -761,6 +762,28 @@ public class AuthenticationProcessor { return challenge; } + /** + * Marks that at least one action was successful + * + */ + public void setActionSuccessful() { + oneActionWasSuccessful = true; + } + + public Response checkWasSuccessfulBrowserAction() { + if (oneActionWasSuccessful && isBrowserFlow()) { + // redirect to non-action url so browser refresh button works without reposting past data + String code = generateCode(); + + URI redirect = LoginActionsService.loginActionsBaseUrl(getUriInfo()) + .path(flowPath) + .queryParam(OAuth2Constants.CODE, code).build(getRealm().getName()); + return Response.status(302).location(redirect).build(); + } else { + return null; + } + } + public void attachSession() { String username = clientSession.getAuthenticatedUser().getUsername(); String attemptedUsername = clientSession.getNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME); diff --git a/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java index ff140b6ce9..46e651fc33 100755 --- a/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java +++ b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java @@ -68,6 +68,10 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow { Response response = processResult(result); if (response == null) { processor.getClientSession().removeNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION); + if (result.status == FlowStatus.SUCCESS) { + // we do this so that flow can redirect to a non-action URL + processor.setActionSuccessful(); + } return processFlow(); } else return response; } @@ -153,6 +157,10 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow { } } } + // skip if action as successful already + Response redirect = processor.checkWasSuccessfulBrowserAction(); + if (redirect != null) return redirect; + AuthenticationProcessor.Result context = processor.createAuthenticatorContext(model, authenticator, executions); logger.debug("invoke authenticator.authenticate"); authenticator.authenticate(context); diff --git a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java index a83f49e7b1..52262fad3d 100755 --- a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java +++ b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java @@ -221,6 +221,7 @@ public class FormAuthenticationFlow implements AuthenticationFlow { } processor.getClientSession().setExecutionStatus(actionExecution, ClientSessionModel.ExecutionStatus.SUCCESS); processor.getClientSession().removeNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION); + processor.setActionSuccessful(); return null; } diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java index 2967b67214..e46cbcad5e 100755 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java @@ -812,15 +812,16 @@ public class LoginActionsService { final ClientSessionCode clientCode = checks.clientCode; final ClientSessionModel clientSession = clientCode.getClientSession(); - if (clientSession.getUserSession() == null) { + final UserSessionModel userSession = clientSession.getUserSession(); + if (userSession == null) { logger.userSessionNull(); event.error(Errors.USER_SESSION_NOT_FOUND); throw new WebApplicationException(ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE)); } - if (action == null && clientSession.getUserSession() != null) { // do next required action only if user is already authenticated + if (action == null && userSession != null) { // do next required action only if user is already authenticated initEvent(clientSession); event.event(EventType.LOGIN); - return AuthenticationManager.nextActionAfterAuthentication(session, clientSession.getUserSession(), clientSession, clientConnection, request, uriInfo, event); + return AuthenticationManager.nextActionAfterAuthentication(session, userSession, clientSession, clientConnection, request, uriInfo, event); } if (!action.equals(clientSession.getNote(AuthenticationManager.CURRENT_REQUIRED_ACTION))) { @@ -841,7 +842,7 @@ public class LoginActionsService { event.event(EventType.CUSTOM_REQUIRED_ACTION); - RequiredActionContextResult context = new RequiredActionContextResult(clientSession.getUserSession(), clientSession, realm, event, session, request, clientSession.getUserSession().getUser(), factory) { + RequiredActionContextResult context = new RequiredActionContextResult(userSession, clientSession, realm, event, session, request, userSession.getUser(), factory) { @Override public void ignore() { throw new RuntimeException("Cannot call ignore within processAction()"); @@ -850,16 +851,19 @@ public class LoginActionsService { provider.processAction(context); if (context.getStatus() == RequiredActionContext.Status.SUCCESS) { event.clone().success(); - // do both - clientSession.removeRequiredAction(factory.getId()); - clientSession.getUserSession().getUser().removeRequiredAction(factory.getId()); - clientSession.removeNote(AuthenticationManager.CURRENT_REQUIRED_ACTION); - // redirect to a generic code URI so that browser refresh will work - //return redirectToRequiredActions(code); - event.removeDetail(Details.CUSTOM_REQUIRED_ACTION); initEvent(clientSession); event.event(EventType.LOGIN); - return AuthenticationManager.nextActionAfterAuthentication(session, clientSession.getUserSession(), clientSession, clientConnection, request, uriInfo, event); + clientSession.removeRequiredAction(factory.getId()); + userSession.getUser().removeRequiredAction(factory.getId()); + clientSession.removeNote(AuthenticationManager.CURRENT_REQUIRED_ACTION); + + if (AuthenticationManager.isActionRequired(session, userSession, clientSession, clientConnection, request, uriInfo, event)) { + // redirect to a generic code URI so that browser refresh will work + return redirectToRequiredActions(code); + } else { + return AuthenticationManager.finishedRequiredActions(session, userSession, clientSession, clientConnection, request, uriInfo, event); + + } } if (context.getStatus() == RequiredActionContext.Status.CHALLENGE) { return context.getChallenge();