Invalidate session secretly
Signed-off-by: Douglas Palmer <dpalmer@redhat.com>
This commit is contained in:
parent
18d0105de0
commit
e7d842ea32
4 changed files with 19 additions and 10 deletions
|
@ -38,6 +38,7 @@ public interface Errors {
|
||||||
String USER_DISABLED = "user_disabled";
|
String USER_DISABLED = "user_disabled";
|
||||||
String USER_TEMPORARILY_DISABLED = "user_temporarily_disabled";
|
String USER_TEMPORARILY_DISABLED = "user_temporarily_disabled";
|
||||||
String INVALID_USER_CREDENTIALS = "invalid_user_credentials";
|
String INVALID_USER_CREDENTIALS = "invalid_user_credentials";
|
||||||
|
String INVALID_AUTHENTICATION_SESSION = "invalid_authentication_session";
|
||||||
String DIFFERENT_USER_AUTHENTICATING = "different_user_authenticating";
|
String DIFFERENT_USER_AUTHENTICATING = "different_user_authenticating";
|
||||||
String DIFFERENT_USER_AUTHENTICATED = "different_user_authenticated";
|
String DIFFERENT_USER_AUTHENTICATED = "different_user_authenticated";
|
||||||
String USER_DELETE_ERROR = "user_delete_error";
|
String USER_DELETE_ERROR = "user_delete_error";
|
||||||
|
|
|
@ -53,6 +53,7 @@ public abstract class AbstractUsernameFormAuthenticator extends AbstractFormAuth
|
||||||
|
|
||||||
public static final String REGISTRATION_FORM_ACTION = "registration_form";
|
public static final String REGISTRATION_FORM_ACTION = "registration_form";
|
||||||
public static final String ATTEMPTED_USERNAME = "ATTEMPTED_USERNAME";
|
public static final String ATTEMPTED_USERNAME = "ATTEMPTED_USERNAME";
|
||||||
|
public static final String SESSION_INVALID = "SESSION_INVALID";
|
||||||
|
|
||||||
// Flag is true if user was already set in the authContext before this authenticator was triggered. In this case we skip clearing of the user after unsuccessful password authentication
|
// Flag is true if user was already set in the authContext before this authenticator was triggered. In this case we skip clearing of the user after unsuccessful password authentication
|
||||||
protected static final String USER_SET_BEFORE_USERNAME_PASSWORD_AUTH = "USER_SET_BEFORE_USERNAME_PASSWORD_AUTH";
|
protected static final String USER_SET_BEFORE_USERNAME_PASSWORD_AUTH = "USER_SET_BEFORE_USERNAME_PASSWORD_AUTH";
|
||||||
|
|
|
@ -35,7 +35,6 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.credential.OTPCredentialModel;
|
import org.keycloak.models.credential.OTPCredentialModel;
|
||||||
import org.keycloak.services.managers.AuthenticationSessionManager;
|
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
import org.keycloak.services.validation.Validation;
|
import org.keycloak.services.validation.Validation;
|
||||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||||
|
@ -88,9 +87,15 @@ public class OTPFormAuthenticator extends AbstractUsernameFormAuthenticator impl
|
||||||
context.form().setAttribute(SELECTED_OTP_CREDENTIAL_ID, credentialId);
|
context.form().setAttribute(SELECTED_OTP_CREDENTIAL_ID, credentialId);
|
||||||
|
|
||||||
UserModel userModel = context.getUser();
|
UserModel userModel = context.getUser();
|
||||||
|
if("true".equals(context.getAuthenticationSession().getAuthNote(AbstractUsernameFormAuthenticator.SESSION_INVALID))) {
|
||||||
|
context.getEvent().user(context.getUser()).error(Errors.INVALID_AUTHENTICATION_SESSION);
|
||||||
|
Response challengeResponse = challenge(context, Messages.INVALID_TOTP, Validation.FIELD_OTP_CODE);
|
||||||
|
context.forceChallenge(challengeResponse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!enabledUser(context, userModel)) {
|
if (!enabledUser(context, userModel)) {
|
||||||
// error in context is set in enabledUser/isDisabledByBruteForce
|
// error in context is set in enabledUser/isDisabledByBruteForce
|
||||||
new AuthenticationSessionManager(context.getSession()).removeAuthenticationSession(context.getRealm(), context.getAuthenticationSession(), true);
|
context.getAuthenticationSession().setAuthNote(AbstractUsernameFormAuthenticator.SESSION_INVALID, "true");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,7 @@ public class BruteForceTest extends AbstractTestRealmKeycloakTest {
|
||||||
Assert.assertNotNull(response.getError());
|
Assert.assertNotNull(response.getError());
|
||||||
Assert.assertEquals("invalid_grant", response.getError());
|
Assert.assertEquals("invalid_grant", response.getError());
|
||||||
Assert.assertEquals("Invalid user credentials", response.getErrorDescription());
|
Assert.assertEquals("Invalid user credentials", response.getErrorDescription());
|
||||||
assertUserDisabledEvent();
|
assertUserDisabledEvent(Errors.USER_TEMPORARILY_DISABLED);
|
||||||
events.clear();
|
events.clear();
|
||||||
}
|
}
|
||||||
clearUserFailures();
|
clearUserFailures();
|
||||||
|
@ -256,7 +256,7 @@ public class BruteForceTest extends AbstractTestRealmKeycloakTest {
|
||||||
Assert.assertNotNull(response.getError());
|
Assert.assertNotNull(response.getError());
|
||||||
Assert.assertEquals(response.getError(), "invalid_grant");
|
Assert.assertEquals(response.getError(), "invalid_grant");
|
||||||
Assert.assertEquals("Invalid user credentials", response.getErrorDescription());
|
Assert.assertEquals("Invalid user credentials", response.getErrorDescription());
|
||||||
assertUserDisabledEvent();
|
assertUserDisabledEvent(Errors.USER_TEMPORARILY_DISABLED);
|
||||||
events.clear();
|
events.clear();
|
||||||
}
|
}
|
||||||
clearUserFailures();
|
clearUserFailures();
|
||||||
|
@ -304,7 +304,7 @@ public class BruteForceTest extends AbstractTestRealmKeycloakTest {
|
||||||
Assert.assertNotNull(response.getError());
|
Assert.assertNotNull(response.getError());
|
||||||
Assert.assertEquals(response.getError(), "invalid_grant");
|
Assert.assertEquals(response.getError(), "invalid_grant");
|
||||||
Assert.assertEquals("Invalid user credentials", response.getErrorDescription());
|
Assert.assertEquals("Invalid user credentials", response.getErrorDescription());
|
||||||
assertUserDisabledEvent();
|
assertUserDisabledEvent(Errors.USER_TEMPORARILY_DISABLED);
|
||||||
events.clear();
|
events.clear();
|
||||||
}
|
}
|
||||||
clearUserFailures();
|
clearUserFailures();
|
||||||
|
@ -466,11 +466,14 @@ public class BruteForceTest extends AbstractTestRealmKeycloakTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBrowserTotpSessionClosedAfterLockout() throws Exception {
|
public void testBrowserTotpSessionInvalidAfterLockout() throws Exception {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
loginWithTotpFailure();
|
loginWithTotpFailure();
|
||||||
continueLoginWithInvalidTotp();
|
continueLoginWithInvalidTotp();
|
||||||
loginPage.assertCurrent();
|
continueLoginWithInvalidTotp();
|
||||||
|
events.clear();
|
||||||
|
continueLoginWithInvalidTotp();
|
||||||
|
assertUserDisabledEvent(Errors.INVALID_AUTHENTICATION_SESSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -724,7 +727,6 @@ public class BruteForceTest extends AbstractTestRealmKeycloakTest {
|
||||||
|
|
||||||
loginTotpPage.assertCurrent();
|
loginTotpPage.assertCurrent();
|
||||||
Assert.assertEquals("Invalid authenticator code.", loginTotpPage.getInputError());
|
Assert.assertEquals("Invalid authenticator code.", loginTotpPage.getInputError());
|
||||||
events.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void continueLoginWithMissingTotp() {
|
public void continueLoginWithMissingTotp() {
|
||||||
|
@ -793,8 +795,8 @@ public class BruteForceTest extends AbstractTestRealmKeycloakTest {
|
||||||
events.clear();
|
events.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertUserDisabledEvent() {
|
private void assertUserDisabledEvent(String error) {
|
||||||
events.expect(EventType.LOGIN_ERROR).error(Errors.USER_TEMPORARILY_DISABLED).assertEvent();
|
events.expect(EventType.LOGIN_ERROR).error(error).assertEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertUserDisabledReason(String expected) {
|
private void assertUserDisabledReason(String expected) {
|
||||||
|
|
Loading…
Reference in a new issue