Merge pull request #3024 from stianst/KEYCLOAK-3267
KEYCLOAK-3267 Fix identity broker login with brute force enabled
This commit is contained in:
commit
d7649c2547
3 changed files with 86 additions and 2 deletions
|
@ -55,6 +55,7 @@ import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.services.managers.AppAuthManager;
|
import org.keycloak.services.managers.AppAuthManager;
|
||||||
import org.keycloak.services.managers.AuthenticationManager.AuthResult;
|
import org.keycloak.services.managers.AuthenticationManager.AuthResult;
|
||||||
|
import org.keycloak.services.managers.BruteForceProtector;
|
||||||
import org.keycloak.services.managers.ClientSessionCode;
|
import org.keycloak.services.managers.ClientSessionCode;
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
import org.keycloak.services.ErrorResponse;
|
import org.keycloak.services.ErrorResponse;
|
||||||
|
@ -338,8 +339,10 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
||||||
return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
|
return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
|
||||||
}
|
}
|
||||||
if (realm.isBruteForceProtected()) {
|
if (realm.isBruteForceProtected()) {
|
||||||
event.error(Errors.USER_TEMPORARILY_DISABLED);
|
if (session.getProvider(BruteForceProtector.class).isTemporarilyDisabled(session, realm, user)) {
|
||||||
return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
|
event.error(Errors.USER_TEMPORARILY_DISABLED);
|
||||||
|
return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,15 +9,21 @@ import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
import org.keycloak.services.messages.Messages;
|
||||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||||
import org.keycloak.testsuite.Assert;
|
import org.keycloak.testsuite.Assert;
|
||||||
|
import org.keycloak.testsuite.pages.AccountPasswordPage;
|
||||||
|
import org.keycloak.testsuite.pages.ErrorPage;
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
import org.keycloak.testsuite.pages.UpdateAccountInformationPage;
|
import org.keycloak.testsuite.pages.UpdateAccountInformationPage;
|
||||||
|
import org.keycloak.testsuite.util.RealmBuilder;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jgroups.util.Util.assertTrue;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
|
import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
|
||||||
import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword;
|
import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword;
|
||||||
|
|
||||||
|
@ -42,9 +48,16 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
|
||||||
|
|
||||||
@Page
|
@Page
|
||||||
protected LoginPage accountLoginPage;
|
protected LoginPage accountLoginPage;
|
||||||
|
|
||||||
@Page
|
@Page
|
||||||
protected UpdateAccountInformationPage updateAccountInformationPage;
|
protected UpdateAccountInformationPage updateAccountInformationPage;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected AccountPasswordPage accountPasswordPage;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected ErrorPage errorPage;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||||
RealmRepresentation providerRealm = createProviderRealm();
|
RealmRepresentation providerRealm = createProviderRealm();
|
||||||
|
@ -171,6 +184,60 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
|
||||||
testSingleLogout();
|
testSingleLogout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loginWithExistingUser() {
|
||||||
|
logInAsUserInIDP();
|
||||||
|
|
||||||
|
Integer userCount = adminClient.realm(consumerRealmName()).users().count();
|
||||||
|
|
||||||
|
driver.navigate().to(getAccountUrl(consumerRealmName()));
|
||||||
|
|
||||||
|
log.debug("Clicking social " + getIDPAlias());
|
||||||
|
accountLoginPage.clickSocial(getIDPAlias());
|
||||||
|
|
||||||
|
Assert.assertTrue("Driver should be on the provider realm page right now", driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/"));
|
||||||
|
|
||||||
|
accountLoginPage.login(getUserLogin(), getUserPassword());
|
||||||
|
|
||||||
|
System.out.println(driver.getPageSource());
|
||||||
|
assertEquals(accountPage.buildUri().toASCIIString().replace("master", "consumer") + "/", driver.getCurrentUrl());
|
||||||
|
|
||||||
|
assertEquals(userCount, adminClient.realm(consumerRealmName()).users().count());
|
||||||
|
}
|
||||||
|
|
||||||
|
// KEYCLOAK-3267
|
||||||
|
@Test
|
||||||
|
public void loginWithExistingUserWithBruteForceEnabled() {
|
||||||
|
adminClient.realm(consumerRealmName()).update(RealmBuilder.create().bruteForceProtected(true).failureFactor(2).build());
|
||||||
|
|
||||||
|
loginWithExistingUser();
|
||||||
|
|
||||||
|
driver.navigate().to(getAccountPasswordUrl(consumerRealmName()));
|
||||||
|
|
||||||
|
accountPasswordPage.changePassword("password", "password");
|
||||||
|
|
||||||
|
driver.navigate().to(getAuthRoot()
|
||||||
|
+ "/auth/realms/" + providerRealmName()
|
||||||
|
+ "/protocol/" + "openid-connect"
|
||||||
|
+ "/logout");
|
||||||
|
|
||||||
|
driver.navigate().to(getAccountUrl(consumerRealmName()));
|
||||||
|
|
||||||
|
accountLoginPage.login(getUserLogin(), "invalid");
|
||||||
|
accountLoginPage.login(getUserLogin(), "invalid");
|
||||||
|
accountLoginPage.login(getUserLogin(), "invalid");
|
||||||
|
|
||||||
|
assertEquals("Invalid username or password.", accountLoginPage.getError());
|
||||||
|
|
||||||
|
accountLoginPage.clickSocial(getIDPAlias());
|
||||||
|
|
||||||
|
Assert.assertTrue("Driver should be on the provider realm page right now", driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/"));
|
||||||
|
|
||||||
|
accountLoginPage.login(getUserLogin(), getUserPassword());
|
||||||
|
|
||||||
|
assertEquals("Account is disabled, contact admin.", errorPage.getError());
|
||||||
|
}
|
||||||
|
|
||||||
protected void testSingleLogout() {
|
protected void testSingleLogout() {
|
||||||
log.debug("Testing single log out");
|
log.debug("Testing single log out");
|
||||||
|
|
||||||
|
@ -203,4 +270,8 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
|
||||||
private String getAccountUrl(String realmName) {
|
private String getAccountUrl(String realmName) {
|
||||||
return getAuthRoot() + "/auth/realms/" + realmName + "/account";
|
return getAuthRoot() + "/auth/realms/" + realmName + "/account";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getAccountPasswordUrl(String realmName) {
|
||||||
|
return getAuthRoot() + "/auth/realms/" + realmName + "/account/password";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,16 @@ public class RealmBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RealmBuilder bruteForceProtected(boolean bruteForceProtected) {
|
||||||
|
rep.setBruteForceProtected(bruteForceProtected);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RealmBuilder failureFactor(int failureFactor) {
|
||||||
|
rep.setFailureFactor(failureFactor);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public RealmBuilder otpDigits(int i) {
|
public RealmBuilder otpDigits(int i) {
|
||||||
rep.setOtpPolicyDigits(i);
|
rep.setOtpPolicyDigits(i);
|
||||||
return this;
|
return this;
|
||||||
|
|
Loading…
Reference in a new issue