Merge pull request #3024 from stianst/KEYCLOAK-3267

KEYCLOAK-3267 Fix identity broker login with brute force enabled
This commit is contained in:
Stian Thorgersen 2016-07-13 07:37:52 +02:00 committed by GitHub
commit d7649c2547
3 changed files with 86 additions and 2 deletions

View file

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

View file

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

View file

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