Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Bill Burke 2016-08-03 19:16:45 -04:00
commit 534ee2e50c
10 changed files with 171 additions and 38 deletions

View file

@ -4,6 +4,7 @@ embed-server --server-config=standalone-ha.xml
/subsystem=infinispan/cache-container=keycloak/transport=TRANSPORT:add(lock-timeout=60000)
/subsystem=infinispan/cache-container=keycloak/invalidation-cache=realms:add(mode="SYNC")
/subsystem=infinispan/cache-container=keycloak/invalidation-cache=users:add(mode="SYNC")
/subsystem=infinispan/cache-container=keycloak/invalidation-cache=users/eviction=EVICTION:add(max-entries=10000,strategy=LRU)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions:add(mode="SYNC",owners="1")
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions:add(mode="SYNC",owners="1")
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures:add(mode="SYNC",owners="1")

View file

@ -3,11 +3,12 @@ embed-server --server-config=standalone.xml
/subsystem=infinispan/cache-container=keycloak:add(jndi-name="infinispan/Keycloak")
/subsystem=infinispan/cache-container=keycloak/local-cache=realms:add()
/subsystem=infinispan/cache-container=keycloak/local-cache=users:add()
/subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:add(max-entries=10000,strategy=LRU)
/subsystem=infinispan/cache-container=keycloak/local-cache=sessions:add()
/subsystem=infinispan/cache-container=keycloak/local-cache=offlineSessions:add()
/subsystem=infinispan/cache-container=keycloak/local-cache=loginFailures:add()
/subsystem=infinispan/cache-container=keycloak/local-cache=work:add()
/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions:add()
/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/transaction=TRANSACTION:add(mode=BATCH,locking=PESSIMISTIC)
/subsystem=infinispan/cache-container=keycloak/local-cache=authorization:add()
/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:add(max-entries=100,strategy=LRU)
/extension=org.keycloak.keycloak-server-subsystem/:add(module=org.keycloak.keycloak-server-subsystem)
/subsystem=keycloak-server:add(web-context=auth)

View file

@ -193,9 +193,13 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
private Configuration getRevisionCacheConfig(boolean managed, long maxEntries) {
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.invocationBatching().enable().transaction().transactionMode(TransactionMode.TRANSACTIONAL);
if (!managed) {
// Workaround: Use Dummy manager even in managed ( wildfly/eap ) environment. Without this workaround, there is an issue in EAP7 overlay.
// After start+end revisions batch is left the JTA transaction in committed state. This is incorrect and causes other issues afterwards.
// TODO: Investigate
// if (!managed)
cb.transaction().transactionManagerLookup(new DummyTransactionManagerLookup());
}
cb.transaction().lockingMode(LockingMode.PESSIMISTIC);
cb.eviction().strategy(EvictionStrategy.LRU).type(EvictionType.COUNT).size(maxEntries);

View file

@ -159,7 +159,7 @@
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(4096)"/>
<column name="VALUE" type="VARCHAR(4000)"/>
</createTable>
<createTable tableName="COMPONENT">
<column name="ID" type="VARCHAR(36)">

View file

@ -375,8 +375,15 @@ public class SamlProtocol implements LoginProtocol {
Document samlDocument = null;
try {
ResponseType samlModel = builder.buildModel();
transformAttributeStatement(attributeStatementMappers, samlModel, session, userSession, clientSession);
populateRoles(roleListMapper, samlModel, session, userSession, clientSession);
final AttributeStatementType attributeStatement = populateAttributeStatements(attributeStatementMappers, session, userSession, clientSession);
populateRoles(roleListMapper, session, userSession, clientSession, attributeStatement);
// SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute
if (attributeStatement.getAttributes().size() > 0) {
AssertionType assertion = samlModel.getAssertions().get(0).getAssertion();
assertion.addStatement(attributeStatement);
}
samlModel = transformLoginResponse(loginResponseMappers, samlModel, session, userSession, clientSession);
samlDocument = builder.buildDocument(samlModel);
} catch (Exception e) {
@ -437,19 +444,14 @@ public class SamlProtocol implements LoginProtocol {
}
}
public void transformAttributeStatement(List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers, ResponseType response, KeycloakSession session, UserSessionModel userSession,
public AttributeStatementType populateAttributeStatements(List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers, KeycloakSession session, UserSessionModel userSession,
ClientSessionModel clientSession) {
AssertionType assertion = response.getAssertions().get(0).getAssertion();
AttributeStatementType attributeStatement = new AttributeStatementType();
for (ProtocolMapperProcessor<SAMLAttributeStatementMapper> processor : attributeStatementMappers) {
processor.mapper.transformAttributeStatement(attributeStatement, processor.model, session, userSession, clientSession);
}
// SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute
if (attributeStatement.getAttributes().size() > 0) {
assertion.addStatement(attributeStatement);
}
return attributeStatement;
}
public ResponseType transformLoginResponse(List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> mappers, ResponseType response, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
@ -459,17 +461,11 @@ public class SamlProtocol implements LoginProtocol {
return response;
}
public void populateRoles(ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper, ResponseType response, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
public void populateRoles(ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession,
final AttributeStatementType existingAttributeStatement) {
if (roleListMapper == null)
return;
AssertionType assertion = response.getAssertions().get(0).getAssertion();
AttributeStatementType attributeStatement = new AttributeStatementType();
roleListMapper.mapper.mapRoles(attributeStatement, roleListMapper.model, session, userSession, clientSession);
// SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute
if (attributeStatement.getAttributes().size() > 0) {
assertion.addStatement(attributeStatement);
}
roleListMapper.mapper.mapRoles(existingAttributeStatement, roleListMapper.model, session, userSession, clientSession);
}
public static String getLogoutServiceUrl(UriInfo uriInfo, ClientModel client, String bindingType) {

View file

@ -32,6 +32,7 @@
<description></description>
<properties>
<exclude.test>-</exclude.test>
<exclude.console>-</exclude.console>
<exclude.account>-</exclude.account>
<exclude.client>-</exclude.client>
@ -97,6 +98,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>${exclude.test}</exclude>
<exclude>${exclude.console}</exclude>
<exclude>${exclude.account}</exclude>
<exclude>${exclude.client}</exclude>

View file

@ -45,6 +45,7 @@ import javax.ws.rs.core.UriBuilder;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.EventRepresentation;
@ -207,10 +208,9 @@ public class AccountTest extends TestRealmKeycloakTest {
testRealm.setPasswordPolicy(policy);
testRealm().update(testRealm);
}
@Test
public void changePasswordWithLengthPasswordPolicy() {
setPasswordPolicy("length");
@Test
public void changePasswordWithBlankCurrentPassword() {
changePasswordPage.open();
loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
@ -219,7 +219,130 @@ public class AccountTest extends TestRealmKeycloakTest {
Assert.assertEquals("Please specify password.", profilePage.getError());
events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_MISSING).assertEvent();
changePasswordPage.changePassword("password", "new-password", "new-password");
changePasswordPage.changePassword("password", "new", "new");
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
}
@Test
public void changePasswordWithLengthPasswordPolicy() {
setPasswordPolicy("length(8)");
changePasswordPage.open();
loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
changePasswordPage.changePassword("password", "1234", "1234");
Assert.assertEquals("Invalid password: minimum length 8.", profilePage.getError());
events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
changePasswordPage.changePassword("password", "12345678", "12345678");
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
}
@Test
public void changePasswordWithDigitsPolicy() {
setPasswordPolicy("digits(2)");
changePasswordPage.open();
loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
changePasswordPage.changePassword("password", "invalidPassword1", "invalidPassword1");
Assert.assertEquals("Invalid password: must contain at least 2 numerical digits.", profilePage.getError());
events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
changePasswordPage.changePassword("password", "validPassword12", "validPassword12");
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
}
@Test
public void changePasswordWithLowerCasePolicy() {
setPasswordPolicy("lowerCase(2)");
changePasswordPage.open();
loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
changePasswordPage.changePassword("password", "iNVALIDPASSWORD", "iNVALIDPASSWORD");
Assert.assertEquals("Invalid password: must contain at least 2 lower case characters.", profilePage.getError());
events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
changePasswordPage.changePassword("password", "vaLIDPASSWORD", "vaLIDPASSWORD");
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
}
@Test
public void changePasswordWithUpperCasePolicy() {
setPasswordPolicy("upperCase(2)");
changePasswordPage.open();
loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
changePasswordPage.changePassword("password", "Invalidpassword", "Invalidpassword");
Assert.assertEquals("Invalid password: must contain at least 2 upper case characters.", profilePage.getError());
events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
changePasswordPage.changePassword("password", "VAlidpassword", "VAlidpassword");
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
}
@Test
public void changePasswordWithSpecialCharsPolicy() {
setPasswordPolicy("specialChars(2)");
changePasswordPage.open();
loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
changePasswordPage.changePassword("password", "invalidPassword*", "invalidPassword*");
Assert.assertEquals("Invalid password: must contain at least 2 special characters.", profilePage.getError());
events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
changePasswordPage.changePassword("password", "validPassword*#", "validPassword*#");
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
}
@Test
public void changePasswordWithNotUsernamePolicy() {
setPasswordPolicy("notUsername(1)");
changePasswordPage.open();
loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
changePasswordPage.changePassword("password", "test-user@localhost", "test-user@localhost");
Assert.assertEquals("Invalid password: must not be equal to the username.", profilePage.getError());
events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
changePasswordPage.changePassword("password", "newPassword", "newPassword");
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
}
@Test
public void changePasswordWithRegexPatternsPolicy() {
setPasswordPolicy("regexPattern(^[A-Z]+#[a-z]{8}$)");
changePasswordPage.open();
loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
changePasswordPage.changePassword("password", "invalidPassword", "invalidPassword");
Assert.assertEquals("Invalid password: fails to match regex pattern(s).", profilePage.getError());
events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
changePasswordPage.changePassword("password", "VALID#password", "VALID#password");
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
}

View file

@ -77,10 +77,10 @@ public class PasswordPolicy extends Authentication {
public enum Type {
HASH_ITERATIONS("HashIterations"), LENGTH("Length"), DIGITS("Digits"), LOWER_CASE("LowerCase"),
UPPER_CASE("UpperCase"), SPECIAL_CHARS("SpecialChars"), NOT_USERNAME("NotUsername"),
REGEX_PATTERN("RegexPattern"), PASSWORD_HISTORY("PasswordHistory"),
FORCE_EXPIRED_PASSWORD_CHANGE("ForceExpiredPasswordChange");
HASH_ITERATIONS("Hashing Iterations"), LENGTH("Minimum Length"), DIGITS("Digits"), LOWER_CASE("Lowercase Characters"),
UPPER_CASE("Uppercase Characters"), SPECIAL_CHARS("Special Characters"), NOT_USERNAME("Not Username"),
REGEX_PATTERN("Regular Expression"), PASSWORD_HISTORY("Not Recently Used"),
FORCE_EXPIRED_PASSWORD_CHANGE("Expire Password"), HASH_ALGORITHM("Hashing Algorithm");
private String name;

View file

@ -178,6 +178,12 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
testUserCredentialsPage.resetPassword("firstPassword");
assertAlertDanger();
testUserCredentialsPage.resetPassword("thirdPassword");
assertAlertSuccess();
testUserCredentialsPage.resetPassword("firstPassword");
assertAlertSuccess();
}
}

View file

@ -73,7 +73,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
@Test
public void maxLoginFailuresTest() throws InterruptedException {
final short secondsToWait = 3;
final short secondsToWait = 10; // For slower browsers/webdrivers (like IE) we need higher value
final short maxLoginFailures = 2;
bruteForceDetectionPage.form().setProtectionEnabled(true);
@ -89,7 +89,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
@Test
public void quickLoginCheck() throws InterruptedException {
final short secondsToWait = 3;
final short secondsToWait = 10;
bruteForceDetectionPage.form().setProtectionEnabled(true);
bruteForceDetectionPage.form().setMaxLoginFailures("100");
@ -104,7 +104,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
@Test
public void maxWaitLoginFailures() throws InterruptedException {
final short secondsToWait = 5;
final short secondsToWait = 15;
bruteForceDetectionPage.form().setProtectionEnabled(true);
bruteForceDetectionPage.form().setMaxLoginFailures("1");
@ -120,7 +120,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
@Test
public void failureResetTime() throws InterruptedException {
final short failureResetTime = 3;
final short waitIncrement = 3;
final short waitIncrement = 5;
bruteForceDetectionPage.form().setProtectionEnabled(true);
bruteForceDetectionPage.form().setMaxLoginFailures("1");
@ -199,8 +199,8 @@ public class SecurityDefensesTest extends AbstractRealmTest {
wait *= 1000;
log.debug("Wait: " + wait);
Thread.sleep(wait);
log.info("Wait: " + wait);
pause(wait);
if (finalLogin) {
testRealmLoginPage.form().login(testUser);