diff --git a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java index 2167996101..1733c06850 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java +++ b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java @@ -18,14 +18,17 @@ public class DefaultAuthenticationFlows { public static final String REGISTRATION_FLOW = "registration"; public static final String REGISTRATION_FORM_FLOW = "registration form"; public static final String BROWSER_FLOW = "browser"; + public static final String DIRECT_GRANT_FLOW = "direct grant"; public static final String LOGIN_FORMS_FLOW = "forms"; public static void addFlows(RealmModel realm) { if (realm.getFlowByAlias(BROWSER_FLOW) == null) browserFlow(realm); + if (realm.getFlowByAlias(DIRECT_GRANT_FLOW) == null) directGrantFlow(realm, false); if (realm.getFlowByAlias(REGISTRATION_FLOW) == null) registrationFlow(realm); } public static void migrateFlows(RealmModel realm) { browserFlow(realm, true); + directGrantFlow(realm, true); if (realm.getFlowByAlias(REGISTRATION_FLOW) == null) registrationFlow(realm); } @@ -123,6 +126,55 @@ public class DefaultAuthenticationFlows { return false; } + public static void directGrantFlow(RealmModel realm, boolean migrate) { + AuthenticationFlowModel grant = new AuthenticationFlowModel(); + grant.setAlias(DIRECT_GRANT_FLOW); + grant.setDescription("OpenID Connect Resource Owner Grant"); + grant.setProviderId("basic-flow"); + grant.setTopLevel(true); + grant.setBuiltIn(true); + grant = realm.addAuthenticationFlow(grant); + + // username + AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); + execution.setParentFlow(grant.getId()); + execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); + execution.setAuthenticator("direct-grant-validate-username"); + execution.setPriority(10); + execution.setUserSetupAllowed(false); + execution.setAutheticatorFlow(false); + realm.addAuthenticatorExecution(execution); + + // password + execution = new AuthenticationExecutionModel(); + execution.setParentFlow(grant.getId()); + execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); + if (migrate && !hasCredentialType(realm, RequiredCredentialModel.PASSWORD.getType())) { + execution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED); + } + execution.setAuthenticator("direct-grant-validate-password"); + execution.setPriority(20); + execution.setUserSetupAllowed(false); + execution.setAutheticatorFlow(false); + realm.addAuthenticatorExecution(execution); + + // otp + execution = new AuthenticationExecutionModel(); + execution.setParentFlow(grant.getId()); + execution.setRequirement(AuthenticationExecutionModel.Requirement.OPTIONAL); + if (migrate && hasCredentialType(realm, RequiredCredentialModel.TOTP.getType())) { + execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); + } + execution.setAuthenticator("direct-grant-validate-otp"); + execution.setPriority(30); + execution.setUserSetupAllowed(false); + execution.setAutheticatorFlow(false); + realm.addAuthenticatorExecution(execution); + + + + } + public static void browserFlow(RealmModel realm, boolean migrate) { AuthenticationFlowModel browser = new AuthenticationFlowModel(); browser.setAlias(BROWSER_FLOW); diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java index 436762f245..1508746222 100755 --- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java +++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java @@ -3,7 +3,7 @@ package org.keycloak.authentication; import org.jboss.logging.Logger; import org.jboss.resteasy.spi.HttpRequest; import org.keycloak.ClientConnection; -import org.keycloak.authentication.authenticators.AbstractFormAuthenticator; +import org.keycloak.authentication.authenticators.browser.AbstractFormAuthenticator; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; @@ -561,9 +561,18 @@ public class AuthenticationProcessor { validateUser(authUser); AuthenticationFlow authenticationFlow = createFlowExecution(this.flowId, null); Response challenge = authenticationFlow.processFlow(); - if (challenge != null) return challenge; + return challenge; + } + public Response attachSessionExecutionRequiredActions() { + attachSession(); + return AuthenticationManager.actionRequired(session, userSession, clientSession, connection, request, uriInfo, event); + } + + public void attachSession() { String username = clientSession.getAuthenticatedUser().getUsername(); + String attemptedUsername = clientSession.getNote(AbstractFormAuthenticator.ATTEMPTED_USERNAME); + if (attemptedUsername != null) username = attemptedUsername; if (userSession == null) { // if no authenticator attached a usersession userSession = session.sessions().createUserSession(realm, clientSession.getAuthenticatedUser(), username, connection.getRemoteAddr(), "form", false, null, null); userSession.setState(UserSessionModel.State.LOGGING_IN); @@ -573,8 +582,10 @@ public class AuthenticationProcessor { event.user(userSession.getUser()) .detail(Details.USERNAME, username) .session(userSession); + } - return AuthenticationManager.actionRequired(session, userSession, clientSession, connection, request, uriInfo, event); + public void evaluateRequiredActionTriggers() { + AuthenticationManager.evaluateRequiredActionTriggers(session, userSession, clientSession, connection, request, uriInfo, event, realm, clientSession.getAuthenticatedUser()); } public Response finishAuthentication() { diff --git a/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java index 058903c8d9..524d7a9f6d 100755 --- a/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java +++ b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java @@ -105,6 +105,9 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow { } AuthenticatorFactory factory = (AuthenticatorFactory) processor.getSession().getKeycloakSessionFactory().getProviderFactory(Authenticator.class, model.getAuthenticator()); + if (factory == null) { + throw new AuthenticationProcessor.AuthException("Could not find AuthenticatorFactory for: " + model.getAuthenticator(), AuthenticationProcessor.Error.INTERNAL_ERROR); + } Authenticator authenticator = factory.create(); AuthenticationProcessor.logger.debugv("authenticator: {0}", factory.getId()); UserModel authUser = processor.getClientSession().getAuthenticatedUser(); diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractFormAuthenticator.java similarity index 99% rename from services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java rename to services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractFormAuthenticator.java index 3fc70987f5..5e16237837 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractFormAuthenticator.java @@ -1,4 +1,4 @@ -package org.keycloak.authentication.authenticators; +package org.keycloak.authentication.authenticators.browser; import org.jboss.logging.Logger; import org.keycloak.OAuth2Constants; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java similarity index 95% rename from services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticator.java rename to services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java index 0d5a1fb500..e814191bde 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java @@ -1,4 +1,4 @@ -package org.keycloak.authentication.authenticators; +package org.keycloak.authentication.authenticators.browser; import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorContext; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticatorFactory.java similarity index 94% rename from services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java rename to services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticatorFactory.java index 5dcc99e0b0..da9209dacb 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticatorFactory.java @@ -1,10 +1,9 @@ -package org.keycloak.authentication.authenticators; +package org.keycloak.authentication.authenticators.browser; import org.keycloak.Config; import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorFactory; import org.keycloak.models.AuthenticationExecutionModel; -import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.provider.ProviderConfigProperty; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/OTPFormAuthenticator.java similarity index 97% rename from services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticator.java rename to services/src/main/java/org/keycloak/authentication/authenticators/browser/OTPFormAuthenticator.java index 2df69f1fe1..c6036865a3 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/OTPFormAuthenticator.java @@ -1,11 +1,10 @@ -package org.keycloak.authentication.authenticators; +package org.keycloak.authentication.authenticators.browser; import org.keycloak.authentication.AuthenticationProcessor; import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorContext; import org.keycloak.events.Errors; import org.keycloak.login.LoginFormsProvider; -import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserCredentialModel; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/OTPFormAuthenticatorFactory.java similarity index 95% rename from services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticatorFactory.java rename to services/src/main/java/org/keycloak/authentication/authenticators/browser/OTPFormAuthenticatorFactory.java index 2215d84a12..29b1c636cb 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/OTPFormAuthenticatorFactory.java @@ -1,10 +1,9 @@ -package org.keycloak.authentication.authenticators; +package org.keycloak.authentication.authenticators.browser; import org.keycloak.Config; import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorFactory; import org.keycloak.models.AuthenticationExecutionModel; -import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.UserCredentialModel; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java similarity index 96% rename from services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticator.java rename to services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java index 902deb3e0c..6caa1ab59d 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java @@ -1,4 +1,4 @@ -package org.keycloak.authentication.authenticators; +package org.keycloak.authentication.authenticators.browser; import org.jboss.logging.Logger; import org.jboss.resteasy.spi.HttpRequest; @@ -8,24 +8,19 @@ import org.keycloak.authentication.AuthenticatorContext; import org.keycloak.constants.KerberosConstants; import org.keycloak.events.Errors; import org.keycloak.login.LoginFormsProvider; -import org.keycloak.models.ClientSessionModel; import org.keycloak.models.CredentialValidationOutput; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserModel; -import org.keycloak.models.UserSessionModel; import org.keycloak.services.messages.Messages; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.net.URI; -import java.util.HashMap; import java.util.Map; -import static org.keycloak.util.HtmlUtils.escapeAttribute; - /** * @author Bill Burke * @version $Revision: 1 $ diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticatorFactory.java similarity index 95% rename from services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticatorFactory.java rename to services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticatorFactory.java index 36b84e0b4e..462967580e 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/SpnegoAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticatorFactory.java @@ -1,10 +1,9 @@ -package org.keycloak.authentication.authenticators; +package org.keycloak.authentication.authenticators.browser; import org.keycloak.Config; import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorFactory; import org.keycloak.models.AuthenticationExecutionModel; -import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.UserCredentialModel; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordForm.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java similarity index 97% rename from services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordForm.java rename to services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java index 6632c82813..ec7163f00e 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordForm.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java @@ -1,4 +1,4 @@ -package org.keycloak.authentication.authenticators; +package org.keycloak.authentication.authenticators.browser; import org.jboss.resteasy.specimpl.MultivaluedMapImpl; import org.keycloak.authentication.AuthenticationProcessor; @@ -6,7 +6,6 @@ import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorContext; import org.keycloak.events.Errors; import org.keycloak.login.LoginFormsProvider; -import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordFormFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordFormFactory.java similarity index 94% rename from services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordFormFactory.java rename to services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordFormFactory.java index ac2afee753..adc2815b48 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordFormFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordFormFactory.java @@ -1,10 +1,9 @@ -package org.keycloak.authentication.authenticators; +package org.keycloak.authentication.authenticators.browser; import org.keycloak.Config; import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorFactory; import org.keycloak.models.AuthenticationExecutionModel; -import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.UserCredentialModel; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java new file mode 100755 index 0000000000..965395fd05 --- /dev/null +++ b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java @@ -0,0 +1,59 @@ +package org.keycloak.authentication.authenticators.directgrant; + +import org.keycloak.Config; +import org.keycloak.OAuth2Constants; +import org.keycloak.authentication.Authenticator; +import org.keycloak.authentication.AuthenticatorContext; +import org.keycloak.authentication.AuthenticatorFactory; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public abstract class AbstractDirectGrantAuthenticator implements Authenticator, AuthenticatorFactory { + public Response errorResponse(int status, String error, String errorDescription) { + Map e = new HashMap(); + e.put(OAuth2Constants.ERROR, error); + if (errorDescription != null) { + e.put(OAuth2Constants.ERROR_DESCRIPTION, errorDescription); + } + return Response.status(status).entity(e).type(MediaType.APPLICATION_JSON_TYPE).build(); + } + + @Override + public void action(AuthenticatorContext context) { + + } + + @Override + public Authenticator create() { + return this; + } + + @Override + public void close() { + + } + + @Override + public Authenticator create(KeycloakSession session) { + return this; + } + + @Override + public void init(Config.Scope config) { + + } + + @Override + public void postInit(KeycloakSessionFactory factory) { + + } +} diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateOTP.java b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateOTP.java new file mode 100755 index 0000000000..8a71f52a87 --- /dev/null +++ b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateOTP.java @@ -0,0 +1,125 @@ +package org.keycloak.authentication.authenticators.directgrant; + +import org.jboss.logging.Logger; +import org.keycloak.authentication.AuthenticationProcessor; +import org.keycloak.authentication.AuthenticatorContext; +import org.keycloak.events.Errors; +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserCredentialModel; +import org.keycloak.models.UserModel; +import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.representations.idm.CredentialRepresentation; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class ValidateOTP extends AbstractDirectGrantAuthenticator { + + private static final Logger logger = Logger.getLogger(ValidateOTP.class); + public static final String PROVIDER_ID = "direct-grant-validate-otp"; + + @Override + public void authenticate(AuthenticatorContext context) { + if (!isConfigured(context.getSession(), context.getRealm(), context.getUser())) { + if (context.getExecution().isOptional()) { + context.attempted(); + } else if (context.getExecution().isRequired()) { + context.getEvent().error(Errors.INVALID_USER_CREDENTIALS); + Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_grant", "Invalid user credentials"); + context.failure(AuthenticationProcessor.Error.INVALID_USER, challengeResponse); + } + return; + } + MultivaluedMap inputData = context.getHttpRequest().getDecodedFormParameters(); + List credentials = new LinkedList<>(); + String otp = inputData.getFirst(CredentialRepresentation.TOTP); + if (otp == null) { + if (context.getUser() != null) { + context.getEvent().user(context.getUser()); + } + context.getEvent().error(Errors.INVALID_USER_CREDENTIALS); + Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_grant", "Invalid user credentials"); + context.failure(AuthenticationProcessor.Error.INVALID_USER, challengeResponse); + return; + } + credentials.add(UserCredentialModel.totp(otp)); + boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials); + if (!valid) { + context.getEvent().user(context.getUser()); + context.getEvent().error(Errors.INVALID_USER_CREDENTIALS); + Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_grant", "Invalid user credentials"); + context.failure(AuthenticationProcessor.Error.INVALID_USER, challengeResponse); + return; + } + + context.success(); + } + + @Override + public boolean requiresUser() { + return true; + } + + @Override + public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) { + return true; + } + + private boolean isConfigured(KeycloakSession session, RealmModel realm, UserModel user) { + return session.users().configuredForCredentialType(UserCredentialModel.TOTP, realm, user) && user.isTotp(); + } + + @Override + public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) { + + } + + @Override + public String getDisplayType() { + return "OTP"; + } + + @Override + public String getReferenceCategory() { + return null; + } + + @Override + public boolean isConfigurable() { + return false; + } + + public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { + AuthenticationExecutionModel.Requirement.REQUIRED, + AuthenticationExecutionModel.Requirement.OPTIONAL, + AuthenticationExecutionModel.Requirement.DISABLED + }; + + @Override + public AuthenticationExecutionModel.Requirement[] getRequirementChoices() { + return REQUIREMENT_CHOICES; + } + + @Override + public String getHelpText() { + return "Validates the one time password supplied as a 'totp' form parameter in direct grant request"; + } + + @Override + public List getConfigProperties() { + return new LinkedList<>(); + } + + @Override + public String getId() { + return PROVIDER_ID; + } +} diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidatePassword.java b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidatePassword.java new file mode 100755 index 0000000000..55ba2f8278 --- /dev/null +++ b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidatePassword.java @@ -0,0 +1,115 @@ +package org.keycloak.authentication.authenticators.directgrant; + +import org.jboss.logging.Logger; +import org.keycloak.authentication.AuthenticationProcessor; +import org.keycloak.authentication.AuthenticatorContext; +import org.keycloak.authentication.authenticators.browser.AbstractFormAuthenticator; +import org.keycloak.events.Details; +import org.keycloak.events.Errors; +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelDuplicateException; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserCredentialModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.representations.idm.CredentialRepresentation; +import org.keycloak.services.managers.AuthenticationManager; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class ValidatePassword extends AbstractDirectGrantAuthenticator { + + private static final Logger logger = Logger.getLogger(ValidatePassword.class); + public static final String PROVIDER_ID = "direct-grant-validate-password"; + + @Override + public void authenticate(AuthenticatorContext context) { + MultivaluedMap inputData = context.getHttpRequest().getDecodedFormParameters(); + List credentials = new LinkedList<>(); + String password = inputData.getFirst(CredentialRepresentation.PASSWORD); + if (password == null) { + if (context.getUser() != null) { + context.getEvent().user(context.getUser()); + } + context.getEvent().error(Errors.INVALID_USER_CREDENTIALS); + Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_grant", "Invalid user credentials"); + context.failure(AuthenticationProcessor.Error.INVALID_USER, challengeResponse); + return; + } + credentials.add(UserCredentialModel.password(password)); + boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials); + if (!valid) { + context.getEvent().user(context.getUser()); + context.getEvent().error(Errors.INVALID_USER_CREDENTIALS); + Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_grant", "Invalid user credentials"); + context.failure(AuthenticationProcessor.Error.INVALID_USER, challengeResponse); + return; + } + + context.success(); + } + + @Override + public boolean requiresUser() { + return true; + } + + @Override + public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) { + return true; + } + + @Override + public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) { + + } + + @Override + public String getDisplayType() { + return "Password"; + } + + @Override + public String getReferenceCategory() { + return null; + } + + @Override + public boolean isConfigurable() { + return false; + } + + public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { + AuthenticationExecutionModel.Requirement.REQUIRED, + AuthenticationExecutionModel.Requirement.DISABLED + }; + + @Override + public AuthenticationExecutionModel.Requirement[] getRequirementChoices() { + return REQUIREMENT_CHOICES; + } + + @Override + public String getHelpText() { + return "Validates the password supplied as a 'password' form parameter in direct grant request"; + } + + @Override + public List getConfigProperties() { + return new LinkedList<>(); + } + + @Override + public String getId() { + return PROVIDER_ID; + } +} diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java new file mode 100755 index 0000000000..330860b1a6 --- /dev/null +++ b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java @@ -0,0 +1,144 @@ +package org.keycloak.authentication.authenticators.directgrant; + +import org.jboss.logging.Logger; +import org.keycloak.Config; +import org.keycloak.OAuth2Constants; +import org.keycloak.authentication.AuthenticationProcessor; +import org.keycloak.authentication.Authenticator; +import org.keycloak.authentication.AuthenticatorContext; +import org.keycloak.authentication.AuthenticatorFactory; +import org.keycloak.authentication.authenticators.browser.AbstractFormAuthenticator; +import org.keycloak.events.Details; +import org.keycloak.events.Errors; +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.models.ModelDuplicateException; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.services.managers.AuthenticationManager; +import org.keycloak.services.messages.Messages; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class ValidateUsername extends AbstractDirectGrantAuthenticator { + + private static final Logger logger = Logger.getLogger(ValidateUsername.class); + public static final String PROVIDER_ID = "direct-grant-validate-username"; + + @Override + public void authenticate(AuthenticatorContext context) { + MultivaluedMap inputData = context.getHttpRequest().getDecodedFormParameters(); + String username = inputData.getFirst(AuthenticationManager.FORM_USERNAME); + if (username == null) { + context.getEvent().error(Errors.USER_NOT_FOUND); + Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_request", "Missing parameter: username"); + context.failure(AuthenticationProcessor.Error.INVALID_USER, challengeResponse); + return; + } + context.getEvent().detail(Details.USERNAME, username); + context.getClientSession().setNote(AbstractFormAuthenticator.ATTEMPTED_USERNAME, username); + + UserModel user = null; + try { + user = KeycloakModelUtils.findUserByNameOrEmail(context.getSession(), context.getRealm(), username); + } catch (ModelDuplicateException mde) { + logger.error(mde.getMessage(), mde); + Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_request", "Invalid user credentials"); + context.failure(AuthenticationProcessor.Error.INVALID_USER, challengeResponse); + return; + } + + + if (user == null) { + context.getEvent().error(Errors.INVALID_USER_CREDENTIALS); + Response challengeResponse = errorResponse(Response.Status.UNAUTHORIZED.getStatusCode(), "invalid_grant", "Invalid user credentials"); + context.failure(AuthenticationProcessor.Error.INVALID_USER, challengeResponse); + return; + } + if (!user.isEnabled()) { + context.getEvent().user(user); + context.getEvent().error(Errors.USER_DISABLED); + Response challengeResponse = errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "invalid_grant", "Account disabled"); + context.failure(AuthenticationProcessor.Error.INVALID_USER, challengeResponse); + return; + } + if (context.getRealm().isBruteForceProtected()) { + if (context.getProtector().isTemporarilyDisabled(context.getSession(), context.getRealm(), user.getUsername())) { + context.getEvent().user(user); + context.getEvent().error(Errors.USER_TEMPORARILY_DISABLED); + Response challengeResponse = errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "invalid_grant", "Account temporarily disabled"); + context.failure(AuthenticationProcessor.Error.INVALID_USER, challengeResponse); + return; + } + } + context.setUser(user); + context.success(); + } + + @Override + public boolean requiresUser() { + return false; + } + + @Override + public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) { + return true; + } + + @Override + public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) { + + } + + @Override + public String getDisplayType() { + return "Username Validation"; + } + + @Override + public String getReferenceCategory() { + return null; + } + + @Override + public boolean isConfigurable() { + return false; + } + + public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { + AuthenticationExecutionModel.Requirement.REQUIRED + }; + + @Override + public AuthenticationExecutionModel.Requirement[] getRequirementChoices() { + return REQUIREMENT_CHOICES; + } + + @Override + public String getHelpText() { + return "Validates the username supplied as a 'username' form parameter in direct grant request"; + } + + @Override + public List getConfigProperties() { + return new LinkedList<>(); + } + + @Override + public String getId() { + return PROVIDER_ID; + } +} diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java index 0919cf7050..bb4e0d38d4 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java @@ -277,6 +277,9 @@ public class AuthorizationEndpoint { Response challenge = null; try { challenge = processor.authenticateOnly(); + if (challenge == null) { + challenge = processor.attachSessionExecutionRequiredActions(); + } } catch (Exception e) { return processor.handleBrowserException(e); } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java index eea4c1d702..3bff39ad86 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java @@ -5,11 +5,13 @@ import org.jboss.resteasy.spi.HttpRequest; import org.keycloak.ClientConnection; import org.keycloak.OAuth2Constants; import org.keycloak.OAuthErrorException; +import org.keycloak.authentication.AuthenticationProcessor; import org.keycloak.constants.AdapterConstants; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventType; +import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientSessionModel; import org.keycloak.models.KeycloakSession; @@ -17,6 +19,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionProvider; +import org.keycloak.models.utils.DefaultAuthenticationFlows; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.protocol.oidc.TokenManager; @@ -307,46 +310,38 @@ public class TokenEndpoint { public Response buildResourceOwnerPasswordCredentialsGrant() { event.detail(Details.AUTH_METHOD, "oauth_credentials").detail(Details.RESPONSE_TYPE, "token"); - String username = formParams.getFirst(AuthenticationManager.FORM_USERNAME); - if (username == null) { - event.error(Errors.USERNAME_MISSING); - throw new ErrorResponseException("invalid_request", "Missing parameter: username", Response.Status.UNAUTHORIZED); + if (client.isConsentRequired()) { + throw new ErrorResponseException("invalid_client", "Client requires user consent", Response.Status.BAD_REQUEST); } - event.detail(Details.USERNAME, username); - - UserModel user = KeycloakModelUtils.findUserByNameOrEmail(session, realm, username); - if (user != null) event.user(user); - - AuthenticationManager.AuthenticationStatus authenticationStatus = authManager.authenticateForm(session, clientConnection, realm, formParams); - Map err; - - switch (authenticationStatus) { - case SUCCESS: - break; - case ACCOUNT_TEMPORARILY_DISABLED: - case ACTIONS_REQUIRED: - event.error(Errors.USER_TEMPORARILY_DISABLED); - throw new ErrorResponseException("invalid_grant", "Account temporarily disabled", Response.Status.BAD_REQUEST); - case ACCOUNT_DISABLED: - event.error(Errors.USER_DISABLED); - throw new ErrorResponseException("invalid_grant", "Account disabled", Response.Status.BAD_REQUEST); - default: - event.error(Errors.INVALID_USER_CREDENTIALS); - throw new ErrorResponseException("invalid_grant", "Invalid user credentials", Response.Status.UNAUTHORIZED); - } - String scope = formParams.getFirst(OAuth2Constants.SCOPE); UserSessionProvider sessions = session.sessions(); - - UserSessionModel userSession = sessions.createUserSession(realm, user, username, clientConnection.getRemoteAddr(), "oauth_credentials", false, null, null); - event.session(userSession); - ClientSessionModel clientSession = sessions.createClientSession(realm, client); clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL); + clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name()); clientSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName())); + AuthenticationFlowModel flow = realm.getFlowByAlias(DefaultAuthenticationFlows.DIRECT_GRANT_FLOW); + String flowId = flow.getId(); + AuthenticationProcessor processor = new AuthenticationProcessor(); + processor.setClientSession(clientSession) + .setFlowId(flowId) + .setConnection(clientConnection) + .setEventBuilder(event) + .setProtector(authManager.getProtector()) + .setRealm(realm) + .setSession(session) + .setUriInfo(uriInfo) + .setRequest(request); + Response challenge = processor.authenticateOnly(); + if (challenge != null) return challenge; + processor.evaluateRequiredActionTriggers(); + UserModel user = clientSession.getAuthenticatedUser(); + if (user.getRequiredActions() != null && user.getRequiredActions().size() > 0) { + throw new ErrorResponseException("invalid_grant", "Account is not fully set up", Response.Status.BAD_REQUEST); - TokenManager.attachClientSession(userSession, clientSession); + } + processor.attachSession(); + UserSessionModel userSession = processor.getUserSession(); AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event, session, userSession, clientSession) .generateAccessToken(session, scope, client, user, userSession, clientSession) @@ -354,6 +349,7 @@ public class TokenEndpoint { .generateIDToken() .build(); + event.success(); return Cors.add(request, Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build(); diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java index eacb927c1f..c9ca6dee28 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -429,66 +429,7 @@ public class AuthenticationManager { final UserModel user = userSession.getUser(); final ClientModel client = clientSession.getClient(); - RequiredActionContext context = new RequiredActionContext() { - @Override - public EventBuilder getEvent() { - return event; - } - - @Override - public UserModel getUser() { - return user; - } - - @Override - public RealmModel getRealm() { - return realm; - } - - @Override - public ClientSessionModel getClientSession() { - return clientSession; - } - - @Override - public UserSessionModel getUserSession() { - return userSession; - } - - @Override - public ClientConnection getConnection() { - return clientConnection; - } - - @Override - public UriInfo getUriInfo() { - return uriInfo; - } - - @Override - public KeycloakSession getSession() { - return session; - } - - @Override - public HttpRequest getHttpRequest() { - return request; - } - - @Override - public String generateAccessCode(String action) { - ClientSessionCode code = new ClientSessionCode(getRealm(), getClientSession()); - code.setAction(action); - return code.getCode(); - } - }; - - // see if any required actions need triggering, i.e. an expired password - for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) { - if (!model.isEnabled()) continue; - RequiredActionProvider provider = session.getProvider(RequiredActionProvider.class, model.getProviderId()); - provider.evaluateTriggers(context); - } + RequiredActionContext context = evaluateRequiredActionTriggers(session, userSession, clientSession, clientConnection, request, uriInfo, event, realm, user); logger.debugv("processAccessCode: go to oauth page?: {0}", client.isConsentRequired()); @@ -554,6 +495,70 @@ public class AuthenticationManager { } + public static RequiredActionContext evaluateRequiredActionTriggers(final KeycloakSession session, final UserSessionModel userSession, final ClientSessionModel clientSession, final ClientConnection clientConnection, final HttpRequest request, final UriInfo uriInfo, final EventBuilder event, final RealmModel realm, final UserModel user) { + RequiredActionContext context = new RequiredActionContext() { + @Override + public EventBuilder getEvent() { + return event; + } + + @Override + public UserModel getUser() { + return user; + } + + @Override + public RealmModel getRealm() { + return realm; + } + + @Override + public ClientSessionModel getClientSession() { + return clientSession; + } + + @Override + public UserSessionModel getUserSession() { + return userSession; + } + + @Override + public ClientConnection getConnection() { + return clientConnection; + } + + @Override + public UriInfo getUriInfo() { + return uriInfo; + } + + @Override + public KeycloakSession getSession() { + return session; + } + + @Override + public HttpRequest getHttpRequest() { + return request; + } + + @Override + public String generateAccessCode(String action) { + ClientSessionCode code = new ClientSessionCode(getRealm(), getClientSession()); + code.setAction(action); + return code.getCode(); + } + }; + + // see if any required actions need triggering, i.e. an expired password + for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) { + if (!model.isEnabled()) continue; + RequiredActionProvider provider = session.getProvider(RequiredActionProvider.class, model.getProviderId()); + provider.evaluateTriggers(context); + } + return context; + } + protected static AuthResult verifyIdentityToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, boolean checkActive, String tokenString, HttpHeaders headers) { try { 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 55ddb9b50b..95f9be6590 100755 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java @@ -23,14 +23,10 @@ package org.keycloak.services.resources; import org.jboss.logging.Logger; import org.jboss.resteasy.spi.HttpRequest; -import org.jboss.resteasy.spi.InternalServerErrorException; import org.keycloak.ClientConnection; import org.keycloak.authentication.AuthenticationProcessor; -import org.keycloak.authentication.AuthenticatorUtil; import org.keycloak.authentication.RequiredActionContext; import org.keycloak.authentication.RequiredActionProvider; -import org.keycloak.authentication.authenticators.AbstractFormAuthenticator; -import org.keycloak.authentication.authenticators.UsernamePasswordFormFactory; import org.keycloak.email.EmailException; import org.keycloak.email.EmailProvider; import org.keycloak.events.Details; @@ -55,8 +51,6 @@ import org.keycloak.models.utils.DefaultAuthenticationFlows; import org.keycloak.models.utils.FormMessage; import org.keycloak.models.utils.TimeBasedOTP; import org.keycloak.protocol.LoginProtocol; -import org.keycloak.protocol.oidc.OIDCLoginProtocol; -import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.services.managers.AuthenticationManager; @@ -84,7 +78,6 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.Providers; -import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; diff --git a/services/src/main/java/org/keycloak/utils/CredentialHelper.java b/services/src/main/java/org/keycloak/utils/CredentialHelper.java index 9b3af31618..dc43b370f2 100755 --- a/services/src/main/java/org/keycloak/utils/CredentialHelper.java +++ b/services/src/main/java/org/keycloak/utils/CredentialHelper.java @@ -5,16 +5,10 @@ import org.keycloak.authentication.AuthenticatorFactory; import org.keycloak.authentication.ConfigurableAuthenticatorFactory; import org.keycloak.authentication.FormAction; import org.keycloak.authentication.FormActionFactory; -import org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory; -import org.keycloak.authentication.authenticators.SpnegoAuthenticatorFactory; -import org.keycloak.authentication.authenticators.UsernamePasswordFormFactory; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; -import org.keycloak.models.UserCredentialModel; -import org.keycloak.models.utils.DefaultAuthenticationFlows; -import org.keycloak.representations.idm.CredentialRepresentation; /** * used to set an execution a state based on type. diff --git a/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory index 409e84bdc1..14fa990bdd 100755 --- a/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory +++ b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory @@ -1,4 +1,7 @@ -org.keycloak.authentication.authenticators.CookieAuthenticatorFactory -org.keycloak.authentication.authenticators.UsernamePasswordFormFactory -org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory -org.keycloak.authentication.authenticators.SpnegoAuthenticatorFactory +org.keycloak.authentication.authenticators.browser.CookieAuthenticatorFactory +org.keycloak.authentication.authenticators.browser.UsernamePasswordFormFactory +org.keycloak.authentication.authenticators.browser.OTPFormAuthenticatorFactory +org.keycloak.authentication.authenticators.browser.SpnegoAuthenticatorFactory +org.keycloak.authentication.authenticators.directgrant.ValidateOTP +org.keycloak.authentication.authenticators.directgrant.ValidatePassword +org.keycloak.authentication.authenticators.directgrant.ValidateUsername \ No newline at end of file diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java index b307baa024..ee6c5c69f1 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java @@ -18,7 +18,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.keycloak.adapters.HttpClientBuilder; -import org.keycloak.authentication.authenticators.SpnegoAuthenticator; +import org.keycloak.authentication.authenticators.browser.SpnegoAuthenticator; import org.keycloak.events.Details; import org.keycloak.federation.kerberos.CommonKerberosConfig; import org.keycloak.constants.KerberosConstants; diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java index 23d2e5e907..e5b44a9e0b 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java @@ -86,7 +86,6 @@ public class ResourceOwnerPasswordCredentialsGrantTest { .client("resource-owner") .user(userId) .session(accessToken.getSessionState()) - .detail(Details.AUTH_METHOD, "oauth_credentials") .detail(Details.RESPONSE_TYPE, "token") .detail(Details.TOKEN_ID, accessToken.getId()) .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId()) @@ -123,7 +122,6 @@ public class ResourceOwnerPasswordCredentialsGrantTest { events.expectLogin() .client("resource-owner") .session(accessToken.getSessionState()) - .detail(Details.AUTH_METHOD, "oauth_credentials") .detail(Details.RESPONSE_TYPE, "token") .detail(Details.TOKEN_ID, accessToken.getId()) .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId()) @@ -178,7 +176,6 @@ public class ResourceOwnerPasswordCredentialsGrantTest { events.expectLogin() .client("resource-owner") .session((String) null) - .detail(Details.AUTH_METHOD, "oauth_credentials") .detail(Details.RESPONSE_TYPE, "token") .removeDetail(Details.CODE_ID) .removeDetail(Details.REDIRECT_URI) @@ -201,7 +198,6 @@ public class ResourceOwnerPasswordCredentialsGrantTest { .client("resource-owner") .user((String) null) .session((String) null) - .detail(Details.AUTH_METHOD, "oauth_credentials") .detail(Details.RESPONSE_TYPE, "token") .detail(Details.USERNAME, "invalid") .removeDetail(Details.CODE_ID)