diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationModel.java b/model/api/src/main/java/org/keycloak/migration/MigrationModel.java index df24b3d009..cb08418238 100755 --- a/model/api/src/main/java/org/keycloak/migration/MigrationModel.java +++ b/model/api/src/main/java/org/keycloak/migration/MigrationModel.java @@ -11,7 +11,7 @@ public interface MigrationModel { /** * Must have the form of major.minor.micro as the version is parsed and numbers are compared */ - public static final String LATEST_VERSION = "1.3.0.Beta1"; + public static final String LATEST_VERSION = "1.4.0"; String getStoredVersion(); void setStoredVersion(String version); diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java b/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java index 722bc5e021..b7910037fb 100755 --- a/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java +++ b/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java @@ -2,6 +2,7 @@ package org.keycloak.migration; import org.jboss.logging.Logger; import org.keycloak.migration.migrators.MigrateTo1_3_0; +import org.keycloak.migration.migrators.MigrateTo1_4_0; import org.keycloak.migration.migrators.MigrationTo1_2_0_CR1; import org.keycloak.models.KeycloakSession; @@ -33,6 +34,12 @@ public class MigrationModelManager { } new MigrateTo1_3_0().migrate(session); } + if (stored == null || stored.lessThan(MigrateTo1_4_0.VERSION)) { + if (stored != null) { + logger.debug("Migrating older model to 1.4.0 updates"); + } + new MigrateTo1_4_0().migrate(session); + } model.setStoredVersion(MigrationModel.LATEST_VERSION); } diff --git a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java new file mode 100755 index 0000000000..cc15d00e89 --- /dev/null +++ b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java @@ -0,0 +1,28 @@ +package org.keycloak.migration.migrators; + +import org.keycloak.migration.ModelVersion; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.utils.DefaultAuthenticationFlows; + +import java.util.List; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class MigrateTo1_4_0 { + public static final ModelVersion VERSION = new ModelVersion("1.4.0"); + + + public void migrate(KeycloakSession session) { + List realms = session.realms().getRealms(); + for (RealmModel realm : realms) { + if (realm.getAuthenticationFlows().size() == 0) { + DefaultAuthenticationFlows.addFlows(realm); + } + + } + + } +} diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java index af6a67166d..f7d73866bc 100755 --- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java +++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java @@ -19,6 +19,7 @@ import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.services.ErrorPage; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.BruteForceProtector; +import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.messages.Messages; import javax.ws.rs.core.Response; @@ -317,6 +318,13 @@ public class AuthenticationProcessor { public String getForwardedErrorMessage() { return AuthenticationProcessor.this.forwardedErrorMessage; } + + @Override + public String generateAccessCode() { + ClientSessionCode accessCode = new ClientSessionCode(getRealm(), getClientSession()); + accessCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name()); + return accessCode.getCode(); + } } public static class AuthException extends RuntimeException { @@ -518,10 +526,7 @@ public class AuthenticationProcessor { if (model.isUserSetupAllowed()) { logger.debugv("authenticator SETUP_REQUIRED: {0}", authenticatorModel.getProviderId()); clientSession.setAuthenticatorStatus(model.getId(), UserSessionModel.AuthenticatorStatus.SETUP_REQUIRED); - String requiredAction = authenticator.getRequiredAction(); - if (!authUser.getRequiredActions().contains(requiredAction)) { - authUser.addRequiredAction(requiredAction); - } + authenticator.setRequiredActions(session, realm, clientSession.getAuthenticatedUser()); continue; } else { throw new AuthException(Error.CREDENTIAL_SETUP_REQUIRED); diff --git a/services/src/main/java/org/keycloak/authentication/Authenticator.java b/services/src/main/java/org/keycloak/authentication/Authenticator.java index ee9d43500b..8245f82fe7 100755 --- a/services/src/main/java/org/keycloak/authentication/Authenticator.java +++ b/services/src/main/java/org/keycloak/authentication/Authenticator.java @@ -13,7 +13,12 @@ public interface Authenticator extends Provider { boolean requiresUser(); void authenticate(AuthenticatorContext context); boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user); - String getRequiredAction(); + + /** + * Set actions to configure authenticator + * + */ + void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user); } diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java index a8f5aadc8f..637d3a8399 100755 --- a/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java +++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java @@ -73,4 +73,11 @@ public interface AuthenticatorContext { * whatever form is challenging. */ String getForwardedErrorMessage(); + + /** + * Generates access code and updates clientsession timestamp + * + * @return + */ + String generateAccessCode(); } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java index 44d11fdbf9..9184034e20 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java @@ -5,9 +5,7 @@ import org.keycloak.authentication.AuthenticationProcessor; import org.keycloak.authentication.AuthenticatorContext; import org.keycloak.events.Errors; import org.keycloak.login.LoginFormsProvider; -import org.keycloak.models.ClientSessionModel; import org.keycloak.models.UserModel; -import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.LoginActionsService; @@ -29,22 +27,21 @@ public class AbstractFormAuthenticator { } protected LoginFormsProvider loginForm(AuthenticatorContext context) { - ClientSessionCode code = new ClientSessionCode(context.getRealm(), context.getClientSession()); - code.setAction(ClientSessionModel.Action.AUTHENTICATE.name()); - URI action = getActionUrl(context, code, LOGIN_FORM_ACTION); + String accessCode = context.generateAccessCode(); + URI action = getActionUrl(context, accessCode, LOGIN_FORM_ACTION); LoginFormsProvider provider = context.getSession().getProvider(LoginFormsProvider.class) .setUser(context.getUser()) .setActionUri(action) - .setClientSessionCode(code.getCode()); + .setClientSessionCode(accessCode); if (context.getForwardedErrorMessage() != null) { provider.setError(context.getForwardedErrorMessage()); } return provider; } - public static URI getActionUrl(AuthenticatorContext context, ClientSessionCode code, String action) { + public static URI getActionUrl(AuthenticatorContext context, String code, String action) { return LoginActionsService.authenticationFormProcessor(context.getUriInfo()) - .queryParam(OAuth2Constants.CODE, code.getCode()) + .queryParam(OAuth2Constants.CODE, code) .queryParam(ACTION, action) .build(context.getRealm().getName()); } @@ -52,25 +49,21 @@ public class AbstractFormAuthenticator { protected Response invalidUser(AuthenticatorContext context) { return loginForm(context) .setError(Messages.INVALID_USER) - .setClientSessionCode(new ClientSessionCode(context.getRealm(), context.getClientSession()).getCode()) .createLogin(); } protected Response disabledUser(AuthenticatorContext context) { return loginForm(context) - .setClientSessionCode(new ClientSessionCode(context.getRealm(), context.getClientSession()).getCode()) .setError(Messages.ACCOUNT_DISABLED).createLogin(); } protected Response temporarilyDisabledUser(AuthenticatorContext context) { return loginForm(context) - .setClientSessionCode(new ClientSessionCode(context.getRealm(), context.getClientSession()).getCode()) .setError(Messages.ACCOUNT_TEMPORARILY_DISABLED).createLogin(); } protected Response invalidCredentials(AuthenticatorContext context) { return loginForm(context) - .setClientSessionCode(new ClientSessionCode(context.getRealm(), context.getClientSession()).getCode()) .setError(Messages.INVALID_USER).createLogin(); } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticator.java index 1455b2f6c9..a4d64301d5 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticator.java @@ -38,8 +38,7 @@ public class CookieAuthenticator implements Authenticator { } @Override - public String getRequiredAction() { - return null; + public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) { } @Override diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java index bac37f7822..56ef93a96b 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java @@ -68,8 +68,11 @@ public class LoginFormOTPAuthenticator extends LoginFormUsernameAuthenticator { } @Override - public String getRequiredAction() { - return UserModel.RequiredAction.CONFIGURE_TOTP.name(); + public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) { + if (!user.getRequiredActions().contains(UserModel.RequiredAction.CONFIGURE_TOTP.name())) { + user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP.name()); + } + } @Override diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java index fb393e2fe7..cdd49b95fd 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java @@ -70,8 +70,11 @@ public class LoginFormPasswordAuthenticator extends LoginFormUsernameAuthenticat } @Override - public String getRequiredAction() { - return UserModel.RequiredAction.UPDATE_PASSWORD.name(); + public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) { + if (!user.getRequiredActions().contains(UserModel.RequiredAction.UPDATE_PASSWORD.name())) { + user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.name()); + } + } @Override diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java index 62e964318d..6c3759a6c7 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java @@ -111,8 +111,7 @@ public class LoginFormUsernameAuthenticator extends AbstractFormAuthenticator im } @Override - public String getRequiredAction() { - return null; + public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) { } @Override diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticator.java index 325f3cd77d..bce060b4da 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticator.java @@ -11,7 +11,6 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserModel; import org.keycloak.representations.idm.CredentialRepresentation; -import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.messages.Messages; import javax.ws.rs.core.MultivaluedMap; @@ -69,11 +68,11 @@ public class OTPFormAuthenticator extends AbstractFormAuthenticator implements A } protected Response challenge(AuthenticatorContext context, String error) { - ClientSessionCode clientSessionCode = new ClientSessionCode(context.getRealm(), context.getClientSession()); - URI action = AbstractFormAuthenticator.getActionUrl(context, clientSessionCode, TOTP_FORM_ACTION); + String accessCode = context.generateAccessCode(); + URI action = AbstractFormAuthenticator.getActionUrl(context, accessCode, TOTP_FORM_ACTION); LoginFormsProvider forms = context.getSession().getProvider(LoginFormsProvider.class) .setActionUri(action) - .setClientSessionCode(clientSessionCode.getCode()); + .setClientSessionCode(accessCode); if (error != null) forms.setError(error); return forms.createLoginTotp(); @@ -85,8 +84,11 @@ public class OTPFormAuthenticator extends AbstractFormAuthenticator implements A } @Override - public String getRequiredAction() { - return UserModel.RequiredAction.CONFIGURE_TOTP.name(); + public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) { + if (!user.getRequiredActions().contains(UserModel.RequiredAction.CONFIGURE_TOTP.name())) { + user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP.name()); + } + } @Override diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticator.java index 3970fa8916..eb6c1eeea0 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticator.java @@ -15,7 +15,6 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; -import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.messages.Messages; import javax.ws.rs.core.HttpHeaders; @@ -131,9 +130,8 @@ public class SpnegoAuthenticator extends AbstractFormAuthenticator implements Au * @return */ protected Response optionalChallengeRedirect(AuthenticatorContext context, String negotiateHeader) { - ClientSessionCode code = new ClientSessionCode(context.getRealm(), context.getClientSession()); - code.setAction(ClientSessionModel.Action.AUTHENTICATE.name()); - URI action = getActionUrl(context, code, KERBEROS_DISABLED); + String accessCode = context.generateAccessCode(); + URI action = getActionUrl(context, accessCode, KERBEROS_DISABLED); StringBuilder builder = new StringBuilder(); @@ -162,11 +160,10 @@ public class SpnegoAuthenticator extends AbstractFormAuthenticator implements Au } protected Response formChallenge(AuthenticatorContext context, String negotiateHeader) { - ClientSessionCode code = new ClientSessionCode(context.getRealm(), context.getClientSession()); - code.setAction(ClientSessionModel.Action.AUTHENTICATE.name()); - URI action = getActionUrl(context, code, KERBEROS_DISABLED); + String accessCode = context.generateAccessCode(); + URI action = getActionUrl(context, accessCode, KERBEROS_DISABLED); return context.getSession().getProvider(LoginFormsProvider.class) - .setClientSessionCode(new ClientSessionCode(context.getRealm(), context.getClientSession()).getCode()) + .setClientSessionCode(accessCode) .setActionUri(action) .setStatus(Response.Status.UNAUTHORIZED) .setResponseHeader(HttpHeaders.WWW_AUTHENTICATE, negotiateHeader) @@ -181,8 +178,7 @@ public class SpnegoAuthenticator extends AbstractFormAuthenticator implements Au } @Override - public String getRequiredAction() { - return null; + public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) { } @Override