access code checks

This commit is contained in:
Bill Burke 2015-06-16 07:59:53 -04:00
parent 9638c0dd83
commit cd84e78b27
13 changed files with 89 additions and 42 deletions

View file

@ -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);

View file

@ -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);
}

View file

@ -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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MigrateTo1_4_0 {
public static final ModelVersion VERSION = new ModelVersion("1.4.0");
public void migrate(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms();
for (RealmModel realm : realms) {
if (realm.getAuthenticationFlows().size() == 0) {
DefaultAuthenticationFlows.addFlows(realm);
}
}
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -73,4 +73,11 @@ public interface AuthenticatorContext {
* whatever form is challenging.
*/
String getForwardedErrorMessage();
/**
* Generates access code and updates clientsession timestamp
*
* @return
*/
String generateAccessCode();
}

View file

@ -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();
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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