Merge remote-tracking branch 'upstream/master' into fixDataTable

This commit is contained in:
mhajas 2015-12-09 07:41:45 +01:00
commit 4ca3bf530f
100 changed files with 828 additions and 652 deletions

View file

@ -1103,6 +1103,7 @@ module.factory('PasswordPolicy', function() {
var p = {}; var p = {};
p.policyMessages = { p.policyMessages = {
hashAlgorithm: "Default hashing algorithm. Default is 'pbkdf2'.",
hashIterations: "Number of hashing iterations. Default is 1. Recommended is 50000.", hashIterations: "Number of hashing iterations. Default is 1. Recommended is 50000.",
length: "Minimal password length (integer type). Default value is 8.", length: "Minimal password length (integer type). Default value is 8.",
digits: "Minimal number (integer type) of digits in password. Default value is 1.", digits: "Minimal number (integer type) of digits in password. Default value is 1.",
@ -1116,6 +1117,7 @@ module.factory('PasswordPolicy', function() {
} }
p.allPolicies = [ p.allPolicies = [
{ name: 'hashAlgorithm', value: 'pbkdf2' },
{ name: 'hashIterations', value: 1 }, { name: 'hashIterations', value: 1 },
{ name: 'length', value: 8 }, { name: 'length', value: 8 },
{ name: 'digits', value: 1 }, { name: 'digits', value: 1 },

View file

@ -0,0 +1,30 @@
package org.keycloak.hash;
import org.keycloak.models.*;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class PasswordHashManager {
public static UserCredentialValueModel encode(KeycloakSession session, RealmModel realm, String rawPassword) {
PasswordPolicy passwordPolicy = realm.getPasswordPolicy();
String algorithm = passwordPolicy.getHashAlgorithm();
int iterations = passwordPolicy.getHashIterations();
if (iterations < 1) {
iterations = 1;
}
PasswordHashProvider provider = session.getProvider(PasswordHashProvider.class, algorithm);
if (provider == null) {
throw new RuntimeException("Password hash provider for algorithm " + algorithm + " not found");
}
return provider.encode(rawPassword, iterations);
}
public static boolean verify(KeycloakSession session, RealmModel realm, String password, UserCredentialValueModel credential) {
String algorithm = credential.getAlgorithm() != null ? credential.getAlgorithm() : realm.getPasswordPolicy().getHashAlgorithm();
PasswordHashProvider provider = session.getProvider(PasswordHashProvider.class, algorithm);
return provider.verify(password, credential);
}
}

View file

@ -0,0 +1,15 @@
package org.keycloak.hash;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.provider.Provider;
/**
* @author <a href="mailto:me@tsudot.com">Kunal Kerkar</a>
*/
public interface PasswordHashProvider extends Provider {
UserCredentialValueModel encode(String rawPassword, int iterations);
boolean verify(String rawPassword, UserCredentialValueModel credential);
}

View file

@ -0,0 +1,10 @@
package org.keycloak.hash;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:me@tsudot.com">Kunal Kerkar</a>
*/
public interface PasswordHashProviderFactory extends ProviderFactory<PasswordHashProvider> {
}

View file

@ -0,0 +1,31 @@
package org.keycloak.hash;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
/**
* @author <a href="mailto:me@tsudot.com">Kunal Kerkar</a>
*/
public class PasswordHashSpi implements Spi {
@Override
public boolean isInternal() {
return false;
}
@Override
public String getName() {
return "password-hash";
}
@Override
public Class<? extends Provider> getProviderClass() {
return PasswordHashProvider.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return PasswordHashProviderFactory.class;
}
}

View file

@ -0,0 +1,91 @@
package org.keycloak.hash;
import org.keycloak.Config;
import org.keycloak.common.util.Base64;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
/**
* @author <a href="mailto:me@tsudot.com">Kunal Kerkar</a>
*/
public class Pbkdf2PasswordHashProvider implements PasswordHashProviderFactory, PasswordHashProvider {
public static final String ID = "pbkdf2";
private static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
private static final int DERIVED_KEY_SIZE = 512;
public UserCredentialValueModel encode(String rawPassword, int iterations) {
byte[] salt = getSalt();
String encodedPassword = encode(rawPassword, iterations, salt);
UserCredentialValueModel credentials = new UserCredentialValueModel();
credentials.setAlgorithm(ID);
credentials.setType(UserCredentialModel.PASSWORD);
credentials.setSalt(salt);
credentials.setHashIterations(iterations);
credentials.setValue(encodedPassword);
return credentials;
}
public boolean verify(String rawPassword, UserCredentialValueModel credential) {
return encode(rawPassword, credential.getHashIterations(), credential.getSalt()).equals(credential.getValue());
}
@Override
public PasswordHashProvider create(KeycloakSession session) {
return this;
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
public void close() {
}
@Override
public String getId() {
return ID;
}
private String encode(String rawPassword, int iterations, byte[] salt) {
KeySpec spec = new PBEKeySpec(rawPassword.toCharArray(), salt, iterations, DERIVED_KEY_SIZE);
try {
byte[] key = getSecretKeyFactory().generateSecret(spec).getEncoded();
return Base64.encodeBytes(key);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("Credential could not be encoded");
}
}
private byte[] getSalt() {
byte[] buffer = new byte[16];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(buffer);
return buffer;
}
private SecretKeyFactory getSecretKeyFactory() {
try {
return SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("PBKDF2 algorithm not found");
}
}
}

View file

@ -21,6 +21,8 @@ public interface Constants {
String[] BROKER_SERVICE_ROLES = {READ_TOKEN_ROLE}; String[] BROKER_SERVICE_ROLES = {READ_TOKEN_ROLE};
String OFFLINE_ACCESS_ROLE = OAuth2Constants.OFFLINE_ACCESS; String OFFLINE_ACCESS_ROLE = OAuth2Constants.OFFLINE_ACCESS;
String DEFAULT_HASH_ALGORITHM = "pbkdf2";
// 15 minutes // 15 minutes
int DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT = 900; int DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT = 900;
// 30 days // 30 days

View file

@ -1,6 +1,7 @@
package org.keycloak.models; package org.keycloak.models;
import org.keycloak.models.utils.Pbkdf2PasswordEncoder; import org.keycloak.hash.PasswordHashManager;
import org.keycloak.hash.PasswordHashProvider;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
@ -67,6 +68,8 @@ public class PasswordPolicy implements Serializable {
list.add(new SpecialChars(arg)); list.add(new SpecialChars(arg));
} else if (name.equals(NotUsername.NAME)) { } else if (name.equals(NotUsername.NAME)) {
list.add(new NotUsername(arg)); list.add(new NotUsername(arg));
} else if (name.equals(HashAlgorithm.NAME)) {
list.add(new HashAlgorithm(arg));
} else if (name.equals(HashIterations.NAME)) { } else if (name.equals(HashIterations.NAME)) {
list.add(new HashIterations(arg)); list.add(new HashIterations(arg));
} else if (name.equals(RegexPatterns.NAME)) { } else if (name.equals(RegexPatterns.NAME)) {
@ -83,6 +86,18 @@ public class PasswordPolicy implements Serializable {
return list; return list;
} }
public String getHashAlgorithm() {
if (policies == null)
return Constants.DEFAULT_HASH_ALGORITHM;
for (Policy p : policies) {
if (p instanceof HashAlgorithm) {
return ((HashAlgorithm) p).algorithm;
}
}
return Constants.DEFAULT_HASH_ALGORITHM;
}
/** /**
* *
* @return -1 if no hash iterations setting * @return -1 if no hash iterations setting
@ -131,9 +146,9 @@ public class PasswordPolicy implements Serializable {
return -1; return -1;
} }
public Error validate(UserModel user, String password) { public Error validate(KeycloakSession session, UserModel user, String password) {
for (Policy p : policies) { for (Policy p : policies) {
Error error = p.validate(user, password); Error error = p.validate(session, user, password);
if (error != null) { if (error != null) {
return error; return error;
} }
@ -141,9 +156,9 @@ public class PasswordPolicy implements Serializable {
return null; return null;
} }
public Error validate(String user, String password) { public Error validate(KeycloakSession session, String user, String password) {
for (Policy p : policies) { for (Policy p : policies) {
Error error = p.validate(user, password); Error error = p.validate(session, user, password);
if (error != null) { if (error != null) {
return error; return error;
} }
@ -152,8 +167,8 @@ public class PasswordPolicy implements Serializable {
} }
private static interface Policy extends Serializable { private static interface Policy extends Serializable {
public Error validate(UserModel user, String password); public Error validate(KeycloakSession session, UserModel user, String password);
public Error validate(String user, String password); public Error validate(KeycloakSession session, String user, String password);
} }
public static class Error { public static class Error {
@ -174,6 +189,25 @@ public class PasswordPolicy implements Serializable {
} }
} }
private static class HashAlgorithm implements Policy {
private static final String NAME = "hashAlgorithm";
private String algorithm;
public HashAlgorithm(String arg) {
algorithm = stringArg(NAME, Constants.DEFAULT_HASH_ALGORITHM, arg);
}
@Override
public Error validate(KeycloakSession session, String user, String password) {
return null;
}
@Override
public Error validate(KeycloakSession session, UserModel user, String password) {
return null;
}
}
private static class HashIterations implements Policy { private static class HashIterations implements Policy {
private static final String NAME = "hashIterations"; private static final String NAME = "hashIterations";
private int iterations; private int iterations;
@ -181,14 +215,14 @@ public class PasswordPolicy implements Serializable {
public HashIterations(String arg) { public HashIterations(String arg) {
iterations = intArg(NAME, 1, arg); iterations = intArg(NAME, 1, arg);
} }
@Override @Override
public Error validate(String user, String password) { public Error validate(KeycloakSession session, String user, String password) {
return null; return null;
} }
@Override @Override
public Error validate(UserModel user, String password) { public Error validate(KeycloakSession session, UserModel user, String password) {
return null; return null;
} }
} }
@ -200,13 +234,13 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(String username, String password) { public Error validate(KeycloakSession session, String username, String password) {
return username.equals(password) ? new Error(INVALID_PASSWORD_NOT_USERNAME) : null; return username.equals(password) ? new Error(INVALID_PASSWORD_NOT_USERNAME) : null;
} }
@Override @Override
public Error validate(UserModel user, String password) { public Error validate(KeycloakSession session, UserModel user, String password) {
return validate(user.getUsername(), password); return validate(session, user.getUsername(), password);
} }
} }
@ -221,13 +255,13 @@ public class PasswordPolicy implements Serializable {
@Override @Override
public Error validate(String username, String password) { public Error validate(KeycloakSession session, String username, String password) {
return password.length() < min ? new Error(INVALID_PASSWORD_MIN_LENGTH_MESSAGE, min) : null; return password.length() < min ? new Error(INVALID_PASSWORD_MIN_LENGTH_MESSAGE, min) : null;
} }
@Override @Override
public Error validate(UserModel user, String password) { public Error validate(KeycloakSession session, UserModel user, String password) {
return validate(user.getUsername(), password); return validate(session, user.getUsername(), password);
} }
} }
@ -242,7 +276,7 @@ public class PasswordPolicy implements Serializable {
@Override @Override
public Error validate(String username, String password) { public Error validate(KeycloakSession session, String username, String password) {
int count = 0; int count = 0;
for (char c : password.toCharArray()) { for (char c : password.toCharArray()) {
if (Character.isDigit(c)) { if (Character.isDigit(c)) {
@ -253,8 +287,8 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(UserModel user, String password) { public Error validate(KeycloakSession session, UserModel user, String password) {
return validate(user.getUsername(), password); return validate(session, user.getUsername(), password);
} }
} }
@ -268,7 +302,7 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(String username, String password) { public Error validate(KeycloakSession session, String username, String password) {
int count = 0; int count = 0;
for (char c : password.toCharArray()) { for (char c : password.toCharArray()) {
if (Character.isLowerCase(c)) { if (Character.isLowerCase(c)) {
@ -279,8 +313,8 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(UserModel user, String password) { public Error validate(KeycloakSession session, UserModel user, String password) {
return validate(user.getUsername(), password); return validate(session, user.getUsername(), password);
} }
} }
@ -293,7 +327,7 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(String username, String password) { public Error validate(KeycloakSession session, String username, String password) {
int count = 0; int count = 0;
for (char c : password.toCharArray()) { for (char c : password.toCharArray()) {
if (Character.isUpperCase(c)) { if (Character.isUpperCase(c)) {
@ -304,8 +338,8 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(UserModel user, String password) { public Error validate(KeycloakSession session, UserModel user, String password) {
return validate(user.getUsername(), password); return validate(session, user.getUsername(), password);
} }
} }
@ -319,7 +353,7 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(String username, String password) { public Error validate(KeycloakSession session, String username, String password) {
int count = 0; int count = 0;
for (char c : password.toCharArray()) { for (char c : password.toCharArray()) {
if (!Character.isLetterOrDigit(c)) { if (!Character.isLetterOrDigit(c)) {
@ -330,8 +364,8 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(UserModel user, String password) { public Error validate(KeycloakSession session, UserModel user, String password) {
return validate(user.getUsername(), password); return validate(session, user.getUsername(), password);
} }
} }
@ -345,7 +379,7 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(String username, String password) { public Error validate(KeycloakSession session, String username, String password) {
Pattern pattern = Pattern.compile(regexPattern); Pattern pattern = Pattern.compile(regexPattern);
Matcher matcher = pattern.matcher(password); Matcher matcher = pattern.matcher(password);
if (!matcher.matches()) { if (!matcher.matches()) {
@ -355,8 +389,8 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(UserModel user, String password) { public Error validate(KeycloakSession session, UserModel user, String password) {
return validate(user.getUsername(), password); return validate(session, user.getUsername(), password);
} }
} }
@ -370,18 +404,19 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(String user, String password) { public Error validate(KeycloakSession session, String user, String password) {
return null; return null;
} }
@Override @Override
public Error validate(UserModel user, String password) { public Error validate(KeycloakSession session, UserModel user, String password) {
if (passwordHistoryPolicyValue != -1) { if (passwordHistoryPolicyValue != -1) {
UserCredentialValueModel cred = getCredentialValueModel(user, UserCredentialModel.PASSWORD); UserCredentialValueModel cred = getCredentialValueModel(user, UserCredentialModel.PASSWORD);
if (cred != null) { if (cred != null) {
if(new Pbkdf2PasswordEncoder(cred.getSalt()).verify(password, cred.getValue(), cred.getHashIterations())) { PasswordHashProvider hashProvider = session.getProvider(PasswordHashProvider.class, cred.getAlgorithm());
if(hashProvider.verify(password, cred)) {
return new Error(INVALID_PASSWORD_HISTORY, passwordHistoryPolicyValue); return new Error(INVALID_PASSWORD_HISTORY, passwordHistoryPolicyValue);
} }
} }
@ -389,7 +424,8 @@ public class PasswordPolicy implements Serializable {
List<UserCredentialValueModel> passwordExpiredCredentials = getCredentialValueModels(user, passwordHistoryPolicyValue - 1, List<UserCredentialValueModel> passwordExpiredCredentials = getCredentialValueModels(user, passwordHistoryPolicyValue - 1,
UserCredentialModel.PASSWORD_HISTORY); UserCredentialModel.PASSWORD_HISTORY);
for (UserCredentialValueModel credential : passwordExpiredCredentials) { for (UserCredentialValueModel credential : passwordExpiredCredentials) {
if (new Pbkdf2PasswordEncoder(credential.getSalt()).verify(password, credential.getValue(), credential.getHashIterations())) { PasswordHashProvider hashProvider = session.getProvider(PasswordHashProvider.class, cred.getAlgorithm());
if (hashProvider.verify(password, credential)) {
return new Error(INVALID_PASSWORD_HISTORY, passwordHistoryPolicyValue); return new Error(INVALID_PASSWORD_HISTORY, passwordHistoryPolicyValue);
} }
} }
@ -444,12 +480,12 @@ public class PasswordPolicy implements Serializable {
} }
@Override @Override
public Error validate(String username, String password) { public Error validate(KeycloakSession session, String username, String password) {
return null; return null;
} }
@Override @Override
public Error validate(UserModel user, String password) { public Error validate(KeycloakSession session, UserModel user, String password) {
return null; return null;
} }
} }
@ -462,6 +498,14 @@ public class PasswordPolicy implements Serializable {
} }
} }
private static String stringArg(String policy, String defaultValue, String arg) {
if (arg == null) {
return defaultValue;
} else {
return arg;
}
}
@Override @Override
public String toString() { public String toString() {
return policyString; return policyString;

View file

@ -21,6 +21,7 @@ public class UserCredentialModel {
protected String type; protected String type;
protected String value; protected String value;
protected String device; protected String device;
protected String algorithm;
public UserCredentialModel() { public UserCredentialModel() {
} }
@ -107,4 +108,12 @@ public class UserCredentialModel {
public void setDevice(String device) { public void setDevice(String device) {
this.device = device; this.device = device;
} }
public String getAlgorithm() {
return algorithm;
}
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
} }

View file

@ -395,7 +395,7 @@ public class UserFederationManager implements UserProvider {
public void updateCredential(RealmModel realm, UserModel user, UserCredentialModel credential) { public void updateCredential(RealmModel realm, UserModel user, UserCredentialModel credential) {
if (credential.getType().equals(UserCredentialModel.PASSWORD)) { if (credential.getType().equals(UserCredentialModel.PASSWORD)) {
if (realm.getPasswordPolicy() != null) { if (realm.getPasswordPolicy() != null) {
PasswordPolicy.Error error = realm.getPasswordPolicy().validate(user, credential.getValue()); PasswordPolicy.Error error = realm.getPasswordPolicy().validate(session, user, credential.getValue());
if (error != null) throw new ModelException(error.getMessage(), error.getParameters()); if (error != null) throw new ModelException(error.getMessage(), error.getParameters());
} }
} }
@ -403,7 +403,7 @@ public class UserFederationManager implements UserProvider {
} }
@Override @Override
public boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> input) { public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input) {
UserFederationProvider link = getFederationLink(realm, user); UserFederationProvider link = getFederationLink(realm, user);
if (link != null) { if (link != null) {
validateUser(realm, user); validateUser(realm, user);
@ -421,10 +421,10 @@ public class UserFederationManager implements UserProvider {
if (!link.validCredentials(realm, user, fedCreds)) { if (!link.validCredentials(realm, user, fedCreds)) {
return false; return false;
} }
return session.userStorage().validCredentials(realm, user, localCreds); return session.userStorage().validCredentials(session, realm, user, localCreds);
} }
} }
return session.userStorage().validCredentials(realm, user, input); return session.userStorage().validCredentials(session, realm, user, input);
} }
/** /**
@ -466,12 +466,12 @@ public class UserFederationManager implements UserProvider {
@Override @Override
public boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input) { public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input) {
return validCredentials(realm, user, Arrays.asList(input)); return validCredentials(session, realm, user, Arrays.asList(input));
} }
@Override @Override
public CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel... input) { public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
List<UserFederationProviderModel> fedProviderModels = realm.getUserFederationProviders(); List<UserFederationProviderModel> fedProviderModels = realm.getUserFederationProviders();
List<UserFederationProvider> fedProviders = new ArrayList<UserFederationProvider>(); List<UserFederationProvider> fedProviders = new ArrayList<UserFederationProvider>();
for (UserFederationProviderModel fedProviderModel : fedProviderModels) { for (UserFederationProviderModel fedProviderModel : fedProviderModels) {

View file

@ -59,9 +59,9 @@ public interface UserProvider extends Provider {
void preRemove(RealmModel realm, ClientModel client); void preRemove(RealmModel realm, ClientModel client);
void preRemove(ClientModel realm, ProtocolMapperModel protocolMapper); void preRemove(ClientModel realm, ProtocolMapperModel protocolMapper);
boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> input); boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input);
boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input); boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input);
CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel... input); CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input);
void close(); void close();
} }

View file

@ -1,8 +1,11 @@
package org.keycloak.models.utils; package org.keycloak.models.utils;
import org.keycloak.hash.PasswordHashManager;
import org.keycloak.jose.jws.JWSInput; import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.JWSInputException; import org.keycloak.jose.jws.JWSInputException;
import org.keycloak.jose.jws.crypto.RSAProvider; import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OTPPolicy; import org.keycloak.models.OTPPolicy;
import org.keycloak.models.PasswordPolicy; import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
@ -11,8 +14,8 @@ import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.representations.PasswordToken; import org.keycloak.representations.PasswordToken;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.hash.PasswordHashProvider;
import java.io.IOException;
import java.util.List; import java.util.List;
/** /**
@ -38,7 +41,7 @@ public class CredentialValidation {
* @param password * @param password
* @return * @return
*/ */
public static boolean validPassword(RealmModel realm, UserModel user, String password) { public static boolean validPassword(KeycloakSession session, RealmModel realm, UserModel user, String password) {
UserCredentialValueModel passwordCred = null; UserCredentialValueModel passwordCred = null;
for (UserCredentialValueModel cred : user.getCredentialsDirectly()) { for (UserCredentialValueModel cred : user.getCredentialsDirectly()) {
if (cred.getType().equals(UserCredentialModel.PASSWORD)) { if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
@ -47,25 +50,23 @@ public class CredentialValidation {
} }
if (passwordCred == null) return false; if (passwordCred == null) return false;
return validateHashedCredential(realm, user, password, passwordCred); return validateHashedCredential(session, realm, user, password, passwordCred);
} }
public static boolean validateHashedCredential(RealmModel realm, UserModel user, String unhashedCredValue, UserCredentialValueModel credential) {
public static boolean validateHashedCredential(KeycloakSession session, RealmModel realm, UserModel user, String unhashedCredValue, UserCredentialValueModel credential) {
if(unhashedCredValue == null){ if(unhashedCredValue == null){
return false; return false;
} }
boolean validated = new Pbkdf2PasswordEncoder(credential.getSalt()).verify(unhashedCredValue, credential.getValue(), credential.getHashIterations()); boolean validated = PasswordHashManager.verify(session, realm, unhashedCredValue, credential);
if (validated) { if (validated) {
int iterations = hashIterations(realm); int iterations = hashIterations(realm);
if (iterations > -1 && iterations != credential.getHashIterations()) { if (iterations > -1 && iterations != credential.getHashIterations()) {
UserCredentialValueModel newCred = new UserCredentialValueModel();
newCred.setType(credential.getType()); UserCredentialValueModel newCred = PasswordHashManager.encode(session, realm, unhashedCredValue);
newCred.setDevice(credential.getDevice());
newCred.setSalt(credential.getSalt());
newCred.setHashIterations(iterations);
newCred.setValue(new Pbkdf2PasswordEncoder(newCred.getSalt()).encode(unhashedCredValue, iterations));
user.updateCredentialDirectly(newCred); user.updateCredentialDirectly(newCred);
} }
@ -157,9 +158,9 @@ public class CredentialValidation {
* @param credentials * @param credentials
* @return * @return
*/ */
public static boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> credentials) { public static boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> credentials) {
for (UserCredentialModel credential : credentials) { for (UserCredentialModel credential : credentials) {
if (!validCredential(realm, user, credential)) return false; if (!validCredential(session, realm, user, credential)) return false;
} }
return true; return true;
} }
@ -172,16 +173,16 @@ public class CredentialValidation {
* @param credentials * @param credentials
* @return * @return
*/ */
public static boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... credentials) { public static boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... credentials) {
for (UserCredentialModel credential : credentials) { for (UserCredentialModel credential : credentials) {
if (!validCredential(realm, user, credential)) return false; if (!validCredential(session, realm, user, credential)) return false;
} }
return true; return true;
} }
private static boolean validCredential(RealmModel realm, UserModel user, UserCredentialModel credential) { private static boolean validCredential(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel credential) {
if (credential.getType().equals(UserCredentialModel.PASSWORD)) { if (credential.getType().equals(UserCredentialModel.PASSWORD)) {
if (!validPassword(realm, user, credential.getValue())) { if (!validPassword(session, realm, user, credential.getValue())) {
return false; return false;
} }
} else if (credential.getType().equals(UserCredentialModel.PASSWORD_TOKEN)) { } else if (credential.getType().equals(UserCredentialModel.PASSWORD_TOKEN)) {

View file

@ -1,106 +0,0 @@
package org.keycloak.models.utils;
import org.keycloak.common.util.Base64;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
/**
* <p>
* Encoder that uses PBKDF2 function to cryptographically derive passwords.
* </p>
* <p>Passwords are returned with a Base64 encoding.</p>
*
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
*
*/
public class Pbkdf2PasswordEncoder {
public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
public static final String RNG_ALGORITHM = "SHA1PRNG";
private static final int DERIVED_KEY_SIZE = 512;
private static final int ITERATIONS = 1;
private final int iterations;
private byte[] salt;
public Pbkdf2PasswordEncoder(byte[] salt, int iterations) {
this.salt = salt;
this.iterations = iterations;
}
public Pbkdf2PasswordEncoder(byte[] salt) {
this(salt, ITERATIONS);
}
/**
* Encode the raw password provided
* @param rawPassword The password used as a master key to derive into a session key
* @return encoded password in Base64
*/
public String encode(String rawPassword, int iterations) {
String encodedPassword;
KeySpec spec = new PBEKeySpec(rawPassword.toCharArray(), salt, iterations, DERIVED_KEY_SIZE);
try {
byte[] key = getSecretKeyFactory().generateSecret(spec).getEncoded();
encodedPassword = Base64.encodeBytes(key);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("Credential could not be encoded");
}
return encodedPassword;
}
public String encode(String rawPassword) {
return encode(rawPassword, iterations);
}
/**
* Encode the password provided and compare with the hash stored into the database
* @param rawPassword The password provided
* @param encodedPassword Encoded hash stored into the database
* @return true if the password is valid, otherwise false for invalid credentials
*/
public boolean verify(String rawPassword, String encodedPassword) {
return encode(rawPassword).equals(encodedPassword);
}
/**
* Encode the password provided and compare with the hash stored into the database
* @param rawPassword The password provided
* @param encodedPassword Encoded hash stored into the database
* @return true if the password is valid, otherwise false for invalid credentials
*/
public boolean verify(String rawPassword, String encodedPassword, int iterations) {
return encode(rawPassword, iterations).equals(encodedPassword);
}
/**
* Generate a salt for each password
* @return cryptographically strong random number
*/
public static byte[] getSalt() {
byte[] buffer = new byte[16];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(buffer);
return buffer;
}
private static SecretKeyFactory getSecretKeyFactory() {
try {
return SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("PBKDF2 algorithm not found");
}
}
}

View file

@ -0,0 +1 @@
org.keycloak.hash.Pbkdf2PasswordHashProvider

View file

@ -4,4 +4,5 @@ org.keycloak.models.RealmSpi
org.keycloak.models.UserSessionSpi org.keycloak.models.UserSessionSpi
org.keycloak.models.UserSpi org.keycloak.models.UserSpi
org.keycloak.models.session.UserSessionPersisterSpi org.keycloak.models.session.UserSessionPersisterSpi
org.keycloak.migration.MigrationSpi org.keycloak.migration.MigrationSpi
org.keycloak.hash.PasswordHashSpi

View file

@ -15,73 +15,73 @@ public class PasswordPolicyTest {
@Test @Test
public void testLength() { public void testLength() {
PasswordPolicy policy = new PasswordPolicy("length"); PasswordPolicy policy = new PasswordPolicy("length");
Assert.assertEquals("invalidPasswordMinLengthMessage", policy.validate("jdoe", "1234567").getMessage()); Assert.assertEquals("invalidPasswordMinLengthMessage", policy.validate(null, "jdoe", "1234567").getMessage());
Assert.assertArrayEquals(new Object[]{8}, policy.validate("jdoe", "1234567").getParameters()); Assert.assertArrayEquals(new Object[]{8}, policy.validate(null, "jdoe", "1234567").getParameters());
Assert.assertNull(policy.validate("jdoe", "12345678")); Assert.assertNull(policy.validate(null, "jdoe", "12345678"));
policy = new PasswordPolicy("length(4)"); policy = new PasswordPolicy("length(4)");
Assert.assertEquals("invalidPasswordMinLengthMessage", policy.validate("jdoe", "123").getMessage()); Assert.assertEquals("invalidPasswordMinLengthMessage", policy.validate(null, "jdoe", "123").getMessage());
Assert.assertArrayEquals(new Object[]{4}, policy.validate("jdoe", "123").getParameters()); Assert.assertArrayEquals(new Object[]{4}, policy.validate(null, "jdoe", "123").getParameters());
Assert.assertNull(policy.validate("jdoe", "1234")); Assert.assertNull(policy.validate(null, "jdoe", "1234"));
} }
@Test @Test
public void testDigits() { public void testDigits() {
PasswordPolicy policy = new PasswordPolicy("digits"); PasswordPolicy policy = new PasswordPolicy("digits");
Assert.assertEquals("invalidPasswordMinDigitsMessage", policy.validate("jdoe", "abcd").getMessage()); Assert.assertEquals("invalidPasswordMinDigitsMessage", policy.validate(null, "jdoe", "abcd").getMessage());
Assert.assertArrayEquals(new Object[]{1}, policy.validate("jdoe", "abcd").getParameters()); Assert.assertArrayEquals(new Object[]{1}, policy.validate(null, "jdoe", "abcd").getParameters());
Assert.assertNull(policy.validate("jdoe", "abcd1")); Assert.assertNull(policy.validate(null, "jdoe", "abcd1"));
policy = new PasswordPolicy("digits(2)"); policy = new PasswordPolicy("digits(2)");
Assert.assertEquals("invalidPasswordMinDigitsMessage", policy.validate("jdoe", "abcd1").getMessage()); Assert.assertEquals("invalidPasswordMinDigitsMessage", policy.validate(null, "jdoe", "abcd1").getMessage());
Assert.assertArrayEquals(new Object[]{2}, policy.validate("jdoe", "abcd1").getParameters()); Assert.assertArrayEquals(new Object[]{2}, policy.validate(null, "jdoe", "abcd1").getParameters());
Assert.assertNull(policy.validate("jdoe", "abcd12")); Assert.assertNull(policy.validate(null, "jdoe", "abcd12"));
} }
@Test @Test
public void testLowerCase() { public void testLowerCase() {
PasswordPolicy policy = new PasswordPolicy("lowerCase"); PasswordPolicy policy = new PasswordPolicy("lowerCase");
Assert.assertEquals("invalidPasswordMinLowerCaseCharsMessage", policy.validate("jdoe", "ABCD1234").getMessage()); Assert.assertEquals("invalidPasswordMinLowerCaseCharsMessage", policy.validate(null, "jdoe", "ABCD1234").getMessage());
Assert.assertArrayEquals(new Object[]{1}, policy.validate("jdoe", "ABCD1234").getParameters()); Assert.assertArrayEquals(new Object[]{1}, policy.validate(null, "jdoe", "ABCD1234").getParameters());
Assert.assertNull(policy.validate("jdoe", "ABcD1234")); Assert.assertNull(policy.validate(null, "jdoe", "ABcD1234"));
policy = new PasswordPolicy("lowerCase(2)"); policy = new PasswordPolicy("lowerCase(2)");
Assert.assertEquals("invalidPasswordMinLowerCaseCharsMessage", policy.validate("jdoe", "ABcD1234").getMessage()); Assert.assertEquals("invalidPasswordMinLowerCaseCharsMessage", policy.validate(null, "jdoe", "ABcD1234").getMessage());
Assert.assertArrayEquals(new Object[]{2}, policy.validate("jdoe", "ABcD1234").getParameters()); Assert.assertArrayEquals(new Object[]{2}, policy.validate(null, "jdoe", "ABcD1234").getParameters());
Assert.assertNull(policy.validate("jdoe", "aBcD1234")); Assert.assertNull(policy.validate(null, "jdoe", "aBcD1234"));
} }
@Test @Test
public void testUpperCase() { public void testUpperCase() {
PasswordPolicy policy = new PasswordPolicy("upperCase"); PasswordPolicy policy = new PasswordPolicy("upperCase");
Assert.assertEquals("invalidPasswordMinUpperCaseCharsMessage", policy.validate("jdoe", "abcd1234").getMessage()); Assert.assertEquals("invalidPasswordMinUpperCaseCharsMessage", policy.validate(null, "jdoe", "abcd1234").getMessage());
Assert.assertArrayEquals(new Object[]{1}, policy.validate("jdoe", "abcd1234").getParameters()); Assert.assertArrayEquals(new Object[]{1}, policy.validate(null, "jdoe", "abcd1234").getParameters());
Assert.assertNull(policy.validate("jdoe", "abCd1234")); Assert.assertNull(policy.validate(null, "jdoe", "abCd1234"));
policy = new PasswordPolicy("upperCase(2)"); policy = new PasswordPolicy("upperCase(2)");
Assert.assertEquals("invalidPasswordMinUpperCaseCharsMessage", policy.validate("jdoe", "abCd1234").getMessage()); Assert.assertEquals("invalidPasswordMinUpperCaseCharsMessage", policy.validate(null, "jdoe", "abCd1234").getMessage());
Assert.assertArrayEquals(new Object[]{2}, policy.validate("jdoe", "abCd1234").getParameters()); Assert.assertArrayEquals(new Object[]{2}, policy.validate(null, "jdoe", "abCd1234").getParameters());
Assert.assertNull(policy.validate("jdoe", "AbCd1234")); Assert.assertNull(policy.validate(null, "jdoe", "AbCd1234"));
} }
@Test @Test
public void testSpecialChars() { public void testSpecialChars() {
PasswordPolicy policy = new PasswordPolicy("specialChars"); PasswordPolicy policy = new PasswordPolicy("specialChars");
Assert.assertEquals("invalidPasswordMinSpecialCharsMessage", policy.validate("jdoe", "abcd1234").getMessage()); Assert.assertEquals("invalidPasswordMinSpecialCharsMessage", policy.validate(null, "jdoe", "abcd1234").getMessage());
Assert.assertArrayEquals(new Object[]{1}, policy.validate("jdoe", "abcd1234").getParameters()); Assert.assertArrayEquals(new Object[]{1}, policy.validate(null, "jdoe", "abcd1234").getParameters());
Assert.assertNull(policy.validate("jdoe", "ab&d1234")); Assert.assertNull(policy.validate(null, "jdoe", "ab&d1234"));
policy = new PasswordPolicy("specialChars(2)"); policy = new PasswordPolicy("specialChars(2)");
Assert.assertEquals("invalidPasswordMinSpecialCharsMessage", policy.validate("jdoe", "ab&d1234").getMessage()); Assert.assertEquals("invalidPasswordMinSpecialCharsMessage", policy.validate(null, "jdoe", "ab&d1234").getMessage());
Assert.assertArrayEquals(new Object[]{2}, policy.validate("jdoe", "ab&d1234").getParameters()); Assert.assertArrayEquals(new Object[]{2}, policy.validate(null, "jdoe", "ab&d1234").getParameters());
Assert.assertNull(policy.validate("jdoe", "ab&d-234")); Assert.assertNull(policy.validate(null, "jdoe", "ab&d-234"));
} }
@Test @Test
public void testNotUsername() { public void testNotUsername() {
PasswordPolicy policy = new PasswordPolicy("notUsername"); PasswordPolicy policy = new PasswordPolicy("notUsername");
Assert.assertEquals("invalidPasswordNotUsernameMessage", policy.validate("jdoe", "jdoe").getMessage()); Assert.assertEquals("invalidPasswordNotUsernameMessage", policy.validate(null, "jdoe", "jdoe").getMessage());
Assert.assertNull(policy.validate("jdoe", "ab&d1234")); Assert.assertNull(policy.validate(null, "jdoe", "ab&d1234"));
} }
@Test @Test
@ -119,33 +119,33 @@ public class PasswordPolicyTest {
//Fails to match one of the regex pattern //Fails to match one of the regex pattern
policy = new PasswordPolicy("regexPattern(jdoe) and regexPattern(j*d)"); policy = new PasswordPolicy("regexPattern(jdoe) and regexPattern(j*d)");
Assert.assertEquals("invalidPasswordRegexPatternMessage", policy.validate("jdoe", "jdoe").getMessage()); Assert.assertEquals("invalidPasswordRegexPatternMessage", policy.validate(null, "jdoe", "jdoe").getMessage());
////Fails to match all of the regex patterns ////Fails to match all of the regex patterns
policy = new PasswordPolicy("regexPattern(j*p) and regexPattern(j*d) and regexPattern(adoe)"); policy = new PasswordPolicy("regexPattern(j*p) and regexPattern(j*d) and regexPattern(adoe)");
Assert.assertEquals("invalidPasswordRegexPatternMessage", policy.validate("jdoe", "jdoe").getMessage()); Assert.assertEquals("invalidPasswordRegexPatternMessage", policy.validate(null, "jdoe", "jdoe").getMessage());
policy = new PasswordPolicy("regexPattern([a-z][a-z][a-z][a-z][0-9])"); policy = new PasswordPolicy("regexPattern([a-z][a-z][a-z][a-z][0-9])");
Assert.assertEquals("invalidPasswordRegexPatternMessage", policy.validate("jdoe", "jdoe").getMessage()); Assert.assertEquals("invalidPasswordRegexPatternMessage", policy.validate(null, "jdoe", "jdoe").getMessage());
policy = new PasswordPolicy("regexPattern(jdoe)"); policy = new PasswordPolicy("regexPattern(jdoe)");
Assert.assertNull(policy.validate("jdoe", "jdoe")); Assert.assertNull(policy.validate(null, "jdoe", "jdoe"));
policy = new PasswordPolicy("regexPattern([a-z][a-z][a-z][a-z][0-9])"); policy = new PasswordPolicy("regexPattern([a-z][a-z][a-z][a-z][0-9])");
Assert.assertNull(policy.validate("jdoe", "jdoe0")); Assert.assertNull(policy.validate(null, "jdoe", "jdoe0"));
} }
@Test @Test
public void testComplex() { public void testComplex() {
PasswordPolicy policy = new PasswordPolicy("length(8) and digits(2) and lowerCase(2) and upperCase(2) and specialChars(2) and notUsername()"); PasswordPolicy policy = new PasswordPolicy("length(8) and digits(2) and lowerCase(2) and upperCase(2) and specialChars(2) and notUsername()");
Assert.assertNotNull(policy.validate("jdoe", "12aaBB&")); Assert.assertNotNull(policy.validate(null, "jdoe", "12aaBB&"));
Assert.assertNotNull(policy.validate("jdoe", "aaaaBB&-")); Assert.assertNotNull(policy.validate(null, "jdoe", "aaaaBB&-"));
Assert.assertNotNull(policy.validate("jdoe", "12AABB&-")); Assert.assertNotNull(policy.validate(null, "jdoe", "12AABB&-"));
Assert.assertNotNull(policy.validate("jdoe", "12aabb&-")); Assert.assertNotNull(policy.validate(null, "jdoe", "12aabb&-"));
Assert.assertNotNull(policy.validate("jdoe", "12aaBBcc")); Assert.assertNotNull(policy.validate(null, "jdoe", "12aaBBcc"));
Assert.assertNotNull(policy.validate("12aaBB&-", "12aaBB&-")); Assert.assertNotNull(policy.validate(null, "12aaBB&-", "12aaBB&-"));
Assert.assertNull(policy.validate("jdoe", "12aaBB&-")); Assert.assertNull(policy.validate(null, "jdoe", "12aaBB&-"));
} }
} }

View file

@ -299,18 +299,18 @@ public class DefaultCacheUserProvider implements CacheUserProvider {
} }
@Override @Override
public boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> input) { public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input) {
return getDelegate().validCredentials(realm, user, input); return getDelegate().validCredentials(session, realm, user, input);
} }
@Override @Override
public boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input) { public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input) {
return getDelegate().validCredentials(realm, user, input); return getDelegate().validCredentials(session, realm, user, input);
} }
@Override @Override
public CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel... input) { public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
return getDelegate().validCredentials(realm, input); return getDelegate().validCredentials(session, realm, input);
} }
@Override @Override

View file

@ -4,6 +4,7 @@ import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel; import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException; import org.keycloak.models.ModelException;
import org.keycloak.models.OTPPolicy; import org.keycloak.models.OTPPolicy;
@ -29,7 +30,6 @@ import org.keycloak.models.jpa.entities.UserEntity;
import org.keycloak.models.jpa.entities.UserRequiredActionEntity; import org.keycloak.models.jpa.entities.UserRequiredActionEntity;
import org.keycloak.models.jpa.entities.UserRoleMappingEntity; import org.keycloak.models.jpa.entities.UserRoleMappingEntity;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
@ -43,8 +43,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $

View file

@ -59,7 +59,7 @@ public class JpaUserProvider implements UserProvider {
entity.setRealmId(realm.getId()); entity.setRealmId(realm.getId());
em.persist(entity); em.persist(entity);
em.flush(); em.flush();
UserModel userModel = new UserAdapter(realm, em, entity); UserModel userModel = new UserAdapter(session, realm, em, entity);
if (addDefaultRoles) { if (addDefaultRoles) {
for (String r : realm.getDefaultRoles()) { for (String r : realm.getDefaultRoles()) {
@ -241,7 +241,7 @@ public class JpaUserProvider implements UserProvider {
List<UserModel> users = new ArrayList<UserModel>(); List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity user : results) { for (UserEntity user : results) {
users.add(new UserAdapter(realm, em, user)); users.add(new UserAdapter(session, realm, em, user));
} }
return users; return users;
} }
@ -259,7 +259,7 @@ public class JpaUserProvider implements UserProvider {
query.setParameter("realmId", realm.getId()); query.setParameter("realmId", realm.getId());
List<UserEntity> entities = query.getResultList(); List<UserEntity> entities = query.getResultList();
if (entities.size() == 0) return null; if (entities.size() == 0) return null;
return new UserAdapter(realm, em, entities.get(0)); return new UserAdapter(session, realm, em, entities.get(0));
} }
@Override @Override
@ -269,7 +269,7 @@ public class JpaUserProvider implements UserProvider {
query.setParameter("realmId", realm.getId()); query.setParameter("realmId", realm.getId());
List<UserEntity> results = query.getResultList(); List<UserEntity> results = query.getResultList();
if (results.size() == 0) return null; if (results.size() == 0) return null;
return new UserAdapter(realm, em, results.get(0)); return new UserAdapter(session, realm, em, results.get(0));
} }
@Override @Override
@ -278,7 +278,7 @@ public class JpaUserProvider implements UserProvider {
query.setParameter("email", email.toLowerCase()); query.setParameter("email", email.toLowerCase());
query.setParameter("realmId", realm.getId()); query.setParameter("realmId", realm.getId());
List<UserEntity> results = query.getResultList(); List<UserEntity> results = query.getResultList();
return results.isEmpty() ? null : new UserAdapter(realm, em, results.get(0)); return results.isEmpty() ? null : new UserAdapter(session, realm, em, results.get(0));
} }
@Override @Override
@ -299,7 +299,7 @@ public class JpaUserProvider implements UserProvider {
", userId=" + identity.getUserId() + ", results=" + results); ", userId=" + identity.getUserId() + ", results=" + results);
} else { } else {
UserEntity user = results.get(0); UserEntity user = results.get(0);
return new UserAdapter(realm, em, user); return new UserAdapter(session, realm, em, user);
} }
} }
@ -316,7 +316,7 @@ public class JpaUserProvider implements UserProvider {
", results=" + results); ", results=" + results);
} else { } else {
UserEntity user = results.get(0); UserEntity user = results.get(0);
return new UserAdapter(client.getRealm(), em, user); return new UserAdapter(session, client.getRealm(), em, user);
} }
} }
@ -347,7 +347,7 @@ public class JpaUserProvider implements UserProvider {
} }
List<UserEntity> results = query.getResultList(); List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>(); List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity)); for (UserEntity entity : results) users.add(new UserAdapter(session, realm, em, entity));
return users; return users;
} }
@ -365,7 +365,7 @@ public class JpaUserProvider implements UserProvider {
List<UserModel> users = new ArrayList<UserModel>(); List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity user : results) { for (UserEntity user : results) {
users.add(new UserAdapter(realm, em, user)); users.add(new UserAdapter(session, realm, em, user));
} }
return users; return users;
} }
@ -388,7 +388,7 @@ public class JpaUserProvider implements UserProvider {
} }
List<UserEntity> results = query.getResultList(); List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>(); List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity)); for (UserEntity entity : results) users.add(new UserAdapter(session, realm, em, entity));
return users; return users;
} }
@ -446,7 +446,7 @@ public class JpaUserProvider implements UserProvider {
} }
List<UserEntity> results = query.getResultList(); List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>(); List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity)); for (UserEntity entity : results) users.add(new UserAdapter(session, realm, em, entity));
return users; return users;
} }
@ -460,7 +460,7 @@ public class JpaUserProvider implements UserProvider {
List<UserModel> users = new ArrayList<UserModel>(); List<UserModel> users = new ArrayList<UserModel>();
for (UserAttributeEntity attr : results) { for (UserAttributeEntity attr : results) {
UserEntity user = attr.getUser(); UserEntity user = attr.getUser();
users.add(new UserAdapter(realm, em, user)); users.add(new UserAdapter(session, realm, em, user));
} }
return users; return users;
} }
@ -495,17 +495,17 @@ public class JpaUserProvider implements UserProvider {
} }
@Override @Override
public boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> input) { public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input) {
return CredentialValidation.validCredentials(realm, user, input); return CredentialValidation.validCredentials(session, realm, user, input);
} }
@Override @Override
public boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input) { public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input) {
return CredentialValidation.validCredentials(realm, user, input); return CredentialValidation.validCredentials(session, realm, user, input);
} }
@Override @Override
public CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel... input) { public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
// Not supported yet // Not supported yet
return null; return null;
} }

View file

@ -1,7 +1,9 @@
package org.keycloak.models.jpa; package org.keycloak.models.jpa;
import org.keycloak.hash.PasswordHashManager;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel; import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OTPPolicy; import org.keycloak.models.OTPPolicy;
import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserConsentModel; import org.keycloak.models.UserConsentModel;
@ -24,9 +26,9 @@ import org.keycloak.models.jpa.entities.UserGroupMembershipEntity;
import org.keycloak.models.jpa.entities.UserRequiredActionEntity; import org.keycloak.models.jpa.entities.UserRequiredActionEntity;
import org.keycloak.models.jpa.entities.UserRoleMappingEntity; import org.keycloak.models.jpa.entities.UserRoleMappingEntity;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.hash.PasswordHashProvider;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
@ -41,8 +43,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
@ -52,11 +52,13 @@ public class UserAdapter implements UserModel {
protected UserEntity user; protected UserEntity user;
protected EntityManager em; protected EntityManager em;
protected RealmModel realm; protected RealmModel realm;
private final KeycloakSession session;
public UserAdapter(RealmModel realm, EntityManager em, UserEntity user) { public UserAdapter(KeycloakSession session, RealmModel realm, EntityManager em, UserEntity user) {
this.em = em; this.em = em;
this.user = user; this.user = user;
this.realm = realm; this.realm = realm;
this.session = session;
} }
public UserEntity getUser() { public UserEntity getUser() {
@ -387,18 +389,12 @@ public class UserAdapter implements UserModel {
} }
private void setValue(CredentialEntity credentialEntity, UserCredentialModel cred) { private void setValue(CredentialEntity credentialEntity, UserCredentialModel cred) {
byte[] salt = getSalt(); UserCredentialValueModel encoded = PasswordHashManager.encode(session, realm, cred.getValue());
int hashIterations = 1;
PasswordPolicy policy = realm.getPasswordPolicy();
if (policy != null) {
hashIterations = policy.getHashIterations();
if (hashIterations == -1)
hashIterations = 1;
}
credentialEntity.setCreatedDate(Time.toMillis(Time.currentTime())); credentialEntity.setCreatedDate(Time.toMillis(Time.currentTime()));
credentialEntity.setValue(new Pbkdf2PasswordEncoder(salt).encode(cred.getValue(), hashIterations)); credentialEntity.setAlgorithm(encoded.getAlgorithm());
credentialEntity.setSalt(salt); credentialEntity.setValue(encoded.getValue());
credentialEntity.setHashIterations(hashIterations); credentialEntity.setSalt(encoded.getSalt());
credentialEntity.setHashIterations(encoded.getHashIterations());
} }
private CredentialEntity getCredentialEntity(UserEntity userEntity, String credType) { private CredentialEntity getCredentialEntity(UserEntity userEntity, String credType) {

View file

@ -474,17 +474,17 @@ public class MongoUserProvider implements UserProvider {
} }
@Override @Override
public boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> input) { public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input) {
return CredentialValidation.validCredentials(realm, user, input); return CredentialValidation.validCredentials(session, realm, user, input);
} }
@Override @Override
public boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input) { public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input) {
return CredentialValidation.validCredentials(realm, user, input); return CredentialValidation.validCredentials(session, realm, user, input);
} }
@Override @Override
public CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel... input) { public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
// Not supported yet // Not supported yet
return null; return null;
} }

View file

@ -1,11 +1,10 @@
package org.keycloak.models.mongo.keycloak.adapters; package org.keycloak.models.mongo.keycloak.adapters;
import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
import com.mongodb.DBObject; import com.mongodb.DBObject;
import com.mongodb.QueryBuilder; import com.mongodb.QueryBuilder;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext; import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.hash.PasswordHashManager;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel; import org.keycloak.models.GroupModel;
import org.keycloak.models.OTPPolicy; import org.keycloak.models.OTPPolicy;
@ -26,8 +25,8 @@ import org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity; import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
import org.keycloak.models.mongo.utils.MongoModelUtils; import org.keycloak.models.mongo.utils.MongoModelUtils;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.hash.PasswordHashProvider;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -329,18 +328,12 @@ public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implement
} }
private void setValue(CredentialEntity credentialEntity, UserCredentialModel cred) { private void setValue(CredentialEntity credentialEntity, UserCredentialModel cred) {
byte[] salt = getSalt(); UserCredentialValueModel encoded = PasswordHashManager.encode(session, realm, cred.getValue());
int hashIterations = 1;
PasswordPolicy policy = realm.getPasswordPolicy();
if (policy != null) {
hashIterations = policy.getHashIterations();
if (hashIterations == -1)
hashIterations = 1;
}
credentialEntity.setCreatedDate(Time.toMillis(Time.currentTime())); credentialEntity.setCreatedDate(Time.toMillis(Time.currentTime()));
credentialEntity.setValue(new Pbkdf2PasswordEncoder(salt).encode(cred.getValue(), hashIterations)); credentialEntity.setAlgorithm(encoded.getAlgorithm());
credentialEntity.setSalt(salt); credentialEntity.setValue(encoded.getValue());
credentialEntity.setHashIterations(hashIterations); credentialEntity.setSalt(encoded.getSalt());
credentialEntity.setHashIterations(encoded.getHashIterations());
} }
private CredentialEntity getCredentialEntity(MongoUserEntity userEntity, String credType) { private CredentialEntity getCredentialEntity(MongoUserEntity userEntity, String credType) {

View file

@ -149,7 +149,7 @@ public abstract class AbstractUsernameFormAuthenticator extends AbstractFormAuth
List<UserCredentialModel> credentials = new LinkedList<>(); List<UserCredentialModel> credentials = new LinkedList<>();
String password = inputData.getFirst(CredentialRepresentation.PASSWORD); String password = inputData.getFirst(CredentialRepresentation.PASSWORD);
credentials.add(UserCredentialModel.password(password)); credentials.add(UserCredentialModel.password(password));
boolean valid = context.getSession().users().validCredentials(context.getRealm(), user, credentials); boolean valid = context.getSession().users().validCredentials(context.getSession(), context.getRealm(), user, credentials);
if (!valid) { if (!valid) {
context.getEvent().user(user); context.getEvent().user(user);
context.getEvent().error(Errors.INVALID_USER_CREDENTIALS); context.getEvent().error(Errors.INVALID_USER_CREDENTIALS);

View file

@ -49,7 +49,7 @@ public class OTPFormAuthenticator extends AbstractUsernameFormAuthenticator impl
return; return;
} }
credentials.add(UserCredentialModel.otp(context.getRealm().getOTPPolicy().getType(), password)); credentials.add(UserCredentialModel.otp(context.getRealm().getOTPPolicy().getType(), password));
boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials); boolean valid = context.getSession().users().validCredentials(context.getSession(), context.getRealm(), context.getUser(), credentials);
if (!valid) { if (!valid) {
context.getEvent().user(context.getUser()) context.getEvent().user(context.getUser())
.error(Errors.INVALID_USER_CREDENTIALS); .error(Errors.INVALID_USER_CREDENTIALS);

View file

@ -69,7 +69,7 @@ public class SpnegoAuthenticator extends AbstractUsernameFormAuthenticator imple
String spnegoToken = tokens[1]; String spnegoToken = tokens[1];
UserCredentialModel spnegoCredential = UserCredentialModel.kerberos(spnegoToken); UserCredentialModel spnegoCredential = UserCredentialModel.kerberos(spnegoToken);
CredentialValidationOutput output = context.getSession().users().validCredentials(context.getRealm(), spnegoCredential); CredentialValidationOutput output = context.getSession().users().validCredentials(context.getSession(), context.getRealm(), spnegoCredential);
if (output.getAuthStatus() == CredentialValidationOutput.Status.AUTHENTICATED) { if (output.getAuthStatus() == CredentialValidationOutput.Status.AUTHENTICATED) {
context.setUser(output.getAuthenticatedUser()); context.setUser(output.getAuthenticatedUser());

View file

@ -51,7 +51,7 @@ public class ValidateOTP extends AbstractDirectGrantAuthenticator {
return; return;
} }
credentials.add(UserCredentialModel.otp(context.getRealm().getOTPPolicy().getType(), otp)); credentials.add(UserCredentialModel.otp(context.getRealm().getOTPPolicy().getType(), otp));
boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials); boolean valid = context.getSession().users().validCredentials(context.getSession(), context.getRealm(), context.getUser(), credentials);
if (!valid) { if (!valid) {
context.getEvent().user(context.getUser()); context.getEvent().user(context.getUser());
context.getEvent().error(Errors.INVALID_USER_CREDENTIALS); context.getEvent().error(Errors.INVALID_USER_CREDENTIALS);

View file

@ -32,7 +32,7 @@ public class ValidatePassword extends AbstractDirectGrantAuthenticator {
List<UserCredentialModel> credentials = new LinkedList<>(); List<UserCredentialModel> credentials = new LinkedList<>();
String password = inputData.getFirst(CredentialRepresentation.PASSWORD); String password = inputData.getFirst(CredentialRepresentation.PASSWORD);
credentials.add(UserCredentialModel.password(password)); credentials.add(UserCredentialModel.password(password));
boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials); boolean valid = context.getSession().users().validCredentials(context.getSession(), context.getRealm(), context.getUser(), credentials);
if (!valid) { if (!valid) {
context.getEvent().user(context.getUser()); context.getEvent().user(context.getUser());
context.getEvent().error(Errors.INVALID_USER_CREDENTIALS); context.getEvent().error(Errors.INVALID_USER_CREDENTIALS);

View file

@ -53,7 +53,7 @@ public class RegistrationPassword implements FormAction, FormActionFactory {
errors.add(new FormMessage(RegistrationPage.FIELD_PASSWORD_CONFIRM, Messages.INVALID_PASSWORD_CONFIRM)); errors.add(new FormMessage(RegistrationPage.FIELD_PASSWORD_CONFIRM, Messages.INVALID_PASSWORD_CONFIRM));
} }
if (formData.getFirst(RegistrationPage.FIELD_PASSWORD) != null) { if (formData.getFirst(RegistrationPage.FIELD_PASSWORD) != null) {
PasswordPolicy.Error err = context.getRealm().getPasswordPolicy().validate(context.getRealm().isRegistrationEmailAsUsername() ? formData.getFirst(RegistrationPage.FIELD_EMAIL) : formData.getFirst(RegistrationPage.FIELD_USERNAME), formData.getFirst(RegistrationPage.FIELD_PASSWORD)); PasswordPolicy.Error err = context.getRealm().getPasswordPolicy().validate(context.getSession(), context.getRealm().isRegistrationEmailAsUsername() ? formData.getFirst(RegistrationPage.FIELD_EMAIL) : formData.getFirst(RegistrationPage.FIELD_USERNAME), formData.getFirst(RegistrationPage.FIELD_PASSWORD));
if (err != null) if (err != null)
errors.add(new FormMessage(RegistrationPage.FIELD_PASSWORD, err.getMessage(), err.getParameters())); errors.add(new FormMessage(RegistrationPage.FIELD_PASSWORD, err.getMessage(), err.getParameters()));
} }

View file

@ -73,7 +73,7 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory
UserCredentialModel cred = new UserCredentialModel(); UserCredentialModel cred = new UserCredentialModel();
cred.setType(context.getRealm().getOTPPolicy().getType()); cred.setType(context.getRealm().getOTPPolicy().getType());
cred.setValue(totp); cred.setValue(totp);
context.getSession().users().validCredentials(context.getRealm(), context.getUser(), cred); context.getSession().users().validCredentials(context.getSession(), context.getRealm(), context.getUser(), cred);
context.getUser().setOtpEnabled(true); context.getUser().setOtpEnabled(true);
context.success(); context.success();

View file

@ -572,7 +572,7 @@ public class AccountService extends AbstractSecuredLocalService {
UserCredentialModel cred = new UserCredentialModel(); UserCredentialModel cred = new UserCredentialModel();
cred.setType(realm.getOTPPolicy().getType()); cred.setType(realm.getOTPPolicy().getType());
cred.setValue(totp); cred.setValue(totp);
session.users().validCredentials(realm, user, cred); session.users().validCredentials(session, realm, user, cred);
event.event(EventType.UPDATE_TOTP).client(auth.getClient()).user(auth.getUser()).success(); event.event(EventType.UPDATE_TOTP).client(auth.getClient()).user(auth.getUser()).success();
@ -619,7 +619,7 @@ public class AccountService extends AbstractSecuredLocalService {
} }
UserCredentialModel cred = UserCredentialModel.password(password); UserCredentialModel cred = UserCredentialModel.password(password);
if (!session.users().validCredentials(realm, user, cred)) { if (!session.users().validCredentials(session, realm, user, cred)) {
setReferrerOnPage(); setReferrerOnPage();
return account.setError(Messages.INVALID_PASSWORD_EXISTING).createResponse(AccountPages.PASSWORD); return account.setError(Messages.INVALID_PASSWORD_EXISTING).createResponse(AccountPages.PASSWORD);
} }

View file

@ -1,6 +1,7 @@
package org.keycloak.services.validation; package org.keycloak.services.validation;
import org.keycloak.authentication.requiredactions.util.UpdateProfileContext; import org.keycloak.authentication.requiredactions.util.UpdateProfileContext;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.PasswordPolicy; import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.FormMessage; import org.keycloak.models.utils.FormMessage;
@ -25,7 +26,7 @@ public class Validation {
// Actually allow same emails like angular. See ValidationTest.testEmailValidation() // Actually allow same emails like angular. See ValidationTest.testEmailValidation()
private static final Pattern EMAIL_PATTERN = Pattern.compile("[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*"); private static final Pattern EMAIL_PATTERN = Pattern.compile("[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*");
public static List<FormMessage> validateRegistrationForm(RealmModel realm, MultivaluedMap<String, String> formData, List<String> requiredCredentialTypes, PasswordPolicy policy) { public static List<FormMessage> validateRegistrationForm(KeycloakSession session, RealmModel realm, MultivaluedMap<String, String> formData, List<String> requiredCredentialTypes, PasswordPolicy policy) {
List<FormMessage> errors = new ArrayList<>(); List<FormMessage> errors = new ArrayList<>();
if (!realm.isRegistrationEmailAsUsername() && isBlank(formData.getFirst(FIELD_USERNAME))) { if (!realm.isRegistrationEmailAsUsername() && isBlank(formData.getFirst(FIELD_USERNAME))) {
@ -55,7 +56,7 @@ public class Validation {
} }
if (formData.getFirst(FIELD_PASSWORD) != null) { if (formData.getFirst(FIELD_PASSWORD) != null) {
PasswordPolicy.Error err = policy.validate(realm.isRegistrationEmailAsUsername()?formData.getFirst(FIELD_EMAIL):formData.getFirst(FIELD_USERNAME), formData.getFirst(FIELD_PASSWORD)); PasswordPolicy.Error err = policy.validate(session, realm.isRegistrationEmailAsUsername()?formData.getFirst(FIELD_EMAIL):formData.getFirst(FIELD_USERNAME), formData.getFirst(FIELD_PASSWORD));
if (err != null) if (err != null)
errors.add(new FormMessage(FIELD_PASSWORD, err.getMessage(), err.getParameters())); errors.add(new FormMessage(FIELD_PASSWORD, err.getMessage(), err.getParameters()));
} }

View file

@ -8,4 +8,4 @@ org.keycloak.authentication.ClientAuthenticatorSpi
org.keycloak.authentication.RequiredActionSpi org.keycloak.authentication.RequiredActionSpi
org.keycloak.authentication.FormAuthenticatorSpi org.keycloak.authentication.FormAuthenticatorSpi
org.keycloak.authentication.FormActionSpi org.keycloak.authentication.FormActionSpi
org.keycloak.services.clientregistration.ClientRegistrationSpi org.keycloak.services.clientregistration.ClientRegistrationSpi

View file

@ -41,5 +41,4 @@
</pluginManagement> </pluginManagement>
</build> </build>
</project> </project>

View file

@ -5,7 +5,7 @@ import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.graphene.findby.FindByJQuery; import org.jboss.arquillian.graphene.findby.FindByJQuery;
import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.arquillian.test.api.ArquillianResource;
import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl; import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
import org.keycloak.testsuite.util.WaitUtils; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
/** /**
@ -61,7 +61,7 @@ public class CustomerPortalExample extends AbstractPageWithInjectedUrl {
} }
public void customerSession() { public void customerSession() {
WaitUtils.waitGuiForElement(customerSessionLink); waitUntilElement(customerSessionLink).is().present();
customerSessionLink.click(); customerSessionLink.click();
} }
@ -70,11 +70,11 @@ public class CustomerPortalExample extends AbstractPageWithInjectedUrl {
} }
public void waitForCustomerListingHeader() { public void waitForCustomerListingHeader() {
WaitUtils.waitGuiForElementNotPresent(customerListingHeader); waitUntilElement(customerListingHeader).is().not().present();
} }
public void waitForCustomerSessionHeader() { public void waitForCustomerSessionHeader() {
WaitUtils.waitGuiForElementNotPresent(customerSessionHeader); waitUntilElement(customerSessionHeader).is().not().present();
} }
} }

View file

@ -5,7 +5,7 @@ import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.graphene.findby.FindByJQuery; import org.jboss.arquillian.graphene.findby.FindByJQuery;
import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.arquillian.test.api.ArquillianResource;
import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl; import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
import org.keycloak.testsuite.util.WaitUtils; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
/** /**
@ -48,7 +48,7 @@ public class ProductPortalExample extends AbstractPageWithInjectedUrl {
} }
public void waitForProductListingHeader() { public void waitForProductListingHeader() {
WaitUtils.waitGuiForElementNotPresent(productListingHeader); waitUntilElement(productListingHeader).is().not().present();
} }
public void logOut() { public void logOut() {

View file

@ -2,8 +2,7 @@ package org.keycloak.testsuite.auth.page.account;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.page.Form; import org.keycloak.testsuite.page.Form;
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElementNotPresent;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -49,11 +48,11 @@ public class AccountFields extends Form {
} }
public void waitForUsernameInputPresent() { public void waitForUsernameInputPresent() {
waitAjaxForElement(usernameInput); waitUntilElement(usernameInput).is().present();
} }
public void waitForUsernameInputNotPresent() { public void waitForUsernameInputNotPresent() {
waitAjaxForElementNotPresent(usernameInput); waitUntilElement(usernameInput).is().not().present();
} }
} }

View file

@ -21,7 +21,7 @@ import javax.ws.rs.core.UriBuilder;
import org.jboss.arquillian.graphene.findby.FindByJQuery; import org.jboss.arquillian.graphene.findby.FindByJQuery;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.testsuite.auth.page.AuthRealm; import org.keycloak.testsuite.auth.page.AuthRealm;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementPresent; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -66,10 +66,10 @@ public class AccountManagement extends AuthRealm {
private WebElement error; private WebElement error;
public String getErrorMessage() { public String getErrorMessage() {
waitGuiForElementPresent(error, "Error message should be visible"); waitUntilElement(error, "Error message should be present").is().present();
return error.getText(); return error.getText();
} }
public void backToReferer() { public void backToReferer() {
backToRefererLink.click(); backToRefererLink.click();
} }
@ -101,12 +101,12 @@ public class AccountManagement extends AuthRealm {
public void save() { public void save() {
save.click(); save.click();
} }
public RealmResource realmResource() { public RealmResource realmResource() {
return keycloak().realm(getAuthRealm()); return keycloak().realm(getAuthRealm());
} }
public void waitForAccountLinkPresent() { public void waitForAccountLinkPresent() {
waitGuiForElementPresent(accountLink, "account link should be present"); waitUntilElement(accountLink, "account link should be present").is().present();
} }
} }

View file

@ -18,7 +18,7 @@
package org.keycloak.testsuite.auth.page.account; package org.keycloak.testsuite.auth.page.account;
import org.keycloak.testsuite.page.Form; import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.WaitUtils; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -54,6 +54,6 @@ public class PasswordFields extends Form {
} }
public void waitForConfirmPasswordInputPresent() { public void waitForConfirmPasswordInputPresent() {
WaitUtils.waitGuiForElement(confirmPasswordInput); waitUntilElement(confirmPasswordInput).is().present();
} }
} }

View file

@ -0,0 +1,32 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.auth.page.account.fragment;
import org.keycloak.testsuite.page.AbstractAlert;
/**
*
* @author tkyjovsk
*/
public class AccountManagementAlert extends AbstractAlert {
public boolean isError() {
return getAttributeClass().contains("alert-error");
}
}

View file

@ -20,8 +20,7 @@ package org.keycloak.testsuite.auth.page.login;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.testsuite.auth.page.AuthRealm; import org.keycloak.testsuite.auth.page.AuthRealm;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementNotPresent;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -62,11 +61,11 @@ public abstract class Login extends AuthRealm {
private WebElement keycloakTheme; private WebElement keycloakTheme;
public void waitForKeycloakThemeNotPresent() { public void waitForKeycloakThemeNotPresent() {
waitGuiForElementNotPresent(keycloakTheme); waitUntilElement(keycloakTheme).is().not().present();
} }
public void waitForKeycloakThemePresent() { public void waitForKeycloakThemePresent() {
waitGuiForElement(keycloakTheme); waitUntilElement(keycloakTheme).is().present();
} }
} }

View file

@ -19,7 +19,7 @@ package org.keycloak.testsuite.auth.page.login;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import org.keycloak.testsuite.auth.page.AuthRealm; import org.keycloak.testsuite.auth.page.AuthRealm;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementPresent; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -45,7 +45,7 @@ public class LoginActions extends AuthRealm {
private WebElement feedbackText; private WebElement feedbackText;
public String getFeedbackText() { public String getFeedbackText() {
waitGuiForElementPresent(feedbackText, "Feedback message should be visible"); waitUntilElement(feedbackText, "Feedback message should be present").is().present();
return feedbackText.getText(); return feedbackText.getText();
} }

View file

@ -70,20 +70,20 @@ public class LoginForm extends Form {
public void register() { public void register() {
waitForUsernameInputPresent(); waitForUsernameInputPresent();
waitAjaxForElement(registerLink); waitUntilElement(registerLink).is().present();
registerLink.click(); registerLink.click();
} }
public void login() { public void login() {
waitAjaxForElement(loginButton); waitUntilElement(loginButton).is().present();
loginButton.click(); loginButton.click();
} }
public void forgotPassword() { public void forgotPassword() {
waitAjaxForElement(forgottenPassword); waitUntilElement(forgottenPassword).is().present();
forgottenPassword.click(); forgottenPassword.click();
} }
public void rememberMe(boolean value) { public void rememberMe(boolean value) {
waitForRememberMePresent(); waitForRememberMePresent();
boolean selected = rememberMe.isSelected(); boolean selected = rememberMe.isSelected();
@ -94,32 +94,31 @@ public class LoginForm extends Form {
// @Override // @Override
// public void cancel() { // public void cancel() {
// waitAjaxForElement(cancelButton); // waitUntilElement(cancelButton).is().present();
// cancelButton.click(); // cancelButton.click();
// } // }
public void waitForUsernameInputPresent() { public void waitForUsernameInputPresent() {
accountFields.waitForUsernameInputPresent(); accountFields.waitForUsernameInputPresent();
} }
public void waitForRegisterLinkNotPresent() { public void waitForRegisterLinkNotPresent() {
waitAjaxForElementNotPresent(registerLink); waitUntilElement(registerLink).is().not().present();
} }
public void waitForResetPasswordLinkNotPresent() { public void waitForResetPasswordLinkNotPresent() {
waitAjaxForElementNotPresent(forgottenPassword); waitUntilElement(forgottenPassword).is().not().present();
} }
public void waitForRememberMePresent() { public void waitForRememberMePresent() {
waitAjaxForElement(rememberMe); waitUntilElement(rememberMe).is().present();
} }
public void waitForRememberMeNotPresent() { public void waitForRememberMeNotPresent() {
waitAjaxForElementNotPresent(rememberMe); waitUntilElement(rememberMe).is().not().present();
} }
public void waitForLoginButtonPresent() { public void waitForLoginButtonPresent() {
waitGuiForElement(loginButton); waitUntilElement(loginButton).is().present();
} }
} }

View file

@ -21,7 +21,7 @@ import javax.ws.rs.core.UriBuilder;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.testsuite.auth.page.account.AccountFields; import org.keycloak.testsuite.auth.page.account.AccountFields;
import org.keycloak.testsuite.auth.page.account.PasswordFields; import org.keycloak.testsuite.auth.page.account.PasswordFields;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementPresent; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -57,7 +57,7 @@ public class ResetCredentials extends LoginActions {
} }
public String getInfoMessage() { public String getInfoMessage() {
waitGuiForElementPresent(info, "Info message should be visible"); waitUntilElement(info, "Info message should be visible").is().present();
return info.getText(); return info.getText();
} }
} }

View file

@ -21,7 +21,7 @@
*/ */
package org.keycloak.testsuite.auth.page.login; package org.keycloak.testsuite.auth.page.login;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -35,7 +35,7 @@ public class VerifyEmail extends Authenticate {
private WebElement instruction; private WebElement instruction;
public String getInstructionMessage() { public String getInstructionMessage() {
waitGuiForElement(instruction); waitUntilElement(instruction).is().present();
return instruction.getText(); return instruction.getText();
} }
} }

View file

@ -3,8 +3,7 @@ package org.keycloak.testsuite.console.page;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST; import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
import org.keycloak.testsuite.util.WaitUtils; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
import org.openqa.selenium.By; import org.openqa.selenium.By;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -39,7 +38,7 @@ public class AdminConsoleRealm extends AdminConsoleRealmsRoot {
private ConfigureMenu configureMenu; private ConfigureMenu configureMenu;
public ConfigureMenu configure() { public ConfigureMenu configure() {
waitGuiForElement(By.xpath("//div[./h2[text()='Configure']]")); waitUntilElement(By.xpath("//div[./h2[text()='Configure']]")).is().present();
return configureMenu; return configureMenu;
} }
@ -92,7 +91,7 @@ public class AdminConsoleRealm extends AdminConsoleRealmsRoot {
protected ManageMenu manageMenu; protected ManageMenu manageMenu;
public ManageMenu manage() { public ManageMenu manage() {
WaitUtils.waitGuiForElement(By.xpath("//div[./h2[text()='Manage']]")); waitUntilElement(By.xpath("//div[./h2[text()='Manage']]")).is().present();
return manageMenu; return manageMenu;
} }

View file

@ -24,12 +24,12 @@ public class Authentication extends AdminConsoleRealm {
private WebElement close; private WebElement close;
public String getSuccessMessage() { public String getSuccessMessage() {
waitAjaxForElement(success); waitUntilElement(success).is().present();
return success.getText(); return success.getText();
} }
public String getErrorMessage() { public String getErrorMessage() {
waitAjaxForElement(error); waitUntilElement(error).is().present();
return error.getText(); return error.getText();
} }
@ -37,7 +37,7 @@ public class Authentication extends AdminConsoleRealm {
if (close.isDisplayed()) { if (close.isDisplayed()) {
close.click(); close.click();
} }
waitAjaxForElementNotVisible(close); waitUntilElement(close).is().not().visible();
} }
public AuthenticationTabs tabs() { public AuthenticationTabs tabs() {

View file

@ -8,7 +8,7 @@ import org.openqa.selenium.support.ui.Select;
import java.util.List; import java.util.List;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
/** /**
* @author Petr Mensik * @author Petr Mensik
@ -32,7 +32,7 @@ public class PasswordPolicy extends Authentication {
private List<WebElement> allRows; private List<WebElement> allRows;
public void addPolicy(PasswordPolicy.Type policy, String value) { public void addPolicy(PasswordPolicy.Type policy, String value) {
waitGuiForElement(addPolicySelectElement); waitUntilElement(addPolicySelectElement).is().present();
addPolicySelect.selectByVisibleText(policy.getName()); addPolicySelect.selectByVisibleText(policy.getName());
setPolicyValue(policy, value); setPolicyValue(policy, value);
primaryButton.click(); primaryButton.click();

View file

@ -21,7 +21,7 @@
*/ */
package org.keycloak.testsuite.console.page.authentication.flows; package org.keycloak.testsuite.console.page.authentication.flows;
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.By; import org.openqa.selenium.By;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -71,7 +71,7 @@ public class FlowsTable {
private WebElement getRowByLabelText(String text) { private WebElement getRowByLabelText(String text) {
WebElement row = tbody.findElement(By.xpath("//span[text() = '" + text + "']/../..")); WebElement row = tbody.findElement(By.xpath("//span[text() = '" + text + "']/../.."));
waitAjaxForElement(row); waitUntilElement(row).is().present();
return row; return row;
} }

View file

@ -38,17 +38,17 @@ public class ClientMappers extends Client {
} }
public void createMapper() { public void createMapper() {
waitAjaxForBody(); waitForBody();
clickHeaderLink(CREATE); clickHeaderLink(CREATE);
} }
public void addBuiltin() { public void addBuiltin() {
waitAjaxForBody(); waitForBody();
clickHeaderLink(ADD_BUILTIN); clickHeaderLink(ADD_BUILTIN);
} }
public void clickMapper(String mapperName) { public void clickMapper(String mapperName) {
waitAjaxForBody(); waitForBody();
body().findElement(By.linkText(mapperName)).click(); body().findElement(By.linkText(mapperName)).click();
} }
@ -57,7 +57,7 @@ public class ClientMappers extends Client {
} }
private void clickMapperActionButton(String mapperName, String buttonText) { private void clickMapperActionButton(String mapperName, String buttonText) {
waitAjaxForBody(); waitForBody();
clickRowActionButton(getRowByLinkText(mapperName), buttonText); clickRowActionButton(getRowByLinkText(mapperName), buttonText);
} }

View file

@ -62,32 +62,32 @@ public class Clients extends AdminConsoleRealm {
} }
public void createClient() { public void createClient() {
waitAjaxForBody(); waitForBody();
clickHeaderLink(CREATE); clickHeaderLink(CREATE);
} }
public void importClient() { public void importClient() {
waitAjaxForBody(); waitForBody();
clickHeaderLink(IMPORT); clickHeaderLink(IMPORT);
} }
public void clickClient(ClientRepresentation client) { public void clickClient(ClientRepresentation client) {
waitAjaxForBody(); waitForBody();
clickClient(client.getClientId()); clickClient(client.getClientId());
} }
public void clickClient(String clientId) { public void clickClient(String clientId) {
waitAjaxForBody(); waitForBody();
body().findElement(linkText(clientId)).click(); body().findElement(linkText(clientId)).click();
} }
public void editClient(String clientId) { public void editClient(String clientId) {
waitAjaxForBody(); waitForBody();
clickRowActionButton(getRowByLinkText(clientId), EDIT); clickRowActionButton(getRowByLinkText(clientId), EDIT);
} }
public void deleteClient(String clientId) { public void deleteClient(String clientId) {
waitAjaxForBody(); waitForBody();
clickRowActionButton(getRowByLinkText(clientId), DELETE); clickRowActionButton(getRowByLinkText(clientId), DELETE);
} }

View file

@ -8,7 +8,7 @@ import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
import org.keycloak.testsuite.page.Form; import org.keycloak.testsuite.page.Form;
import static org.keycloak.testsuite.page.Form.getInputValue; import static org.keycloak.testsuite.page.Form.getInputValue;
import static org.keycloak.testsuite.util.WaitUtils.pause; import static org.keycloak.testsuite.util.WaitUtils.pause;
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.keycloak.testsuite.util.Timer; import org.keycloak.testsuite.util.Timer;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -69,7 +69,7 @@ public class CreateClientForm extends Form {
private List<WebElement> deleteRedirectUriIcons; private List<WebElement> deleteRedirectUriIcons;
public void setValues(ClientRepresentation client) { public void setValues(ClientRepresentation client) {
waitAjaxForElement(clientIdInput); waitUntilElement(clientIdInput).is().present();
setClientId(client.getClientId()); setClientId(client.getClientId());
setName(client.getName()); setName(client.getName());
@ -230,7 +230,7 @@ public class CreateClientForm extends Form {
} }
public String getProtocol() { public String getProtocol() {
waitAjaxForElement(protocolSelect.getFirstSelectedOption()); waitUntilElement(protocolSelect.getFirstSelectedOption()).is().present();
return protocolSelect.getFirstSelectedOption().getText(); return protocolSelect.getFirstSelectedOption().getText();
} }

View file

@ -33,17 +33,17 @@ public class AdminEvents extends Events {
private AdminEventsTableFilterForm filterForm; private AdminEventsTableFilterForm filterForm;
public void update() { public void update() {
waitAjaxForBody(); waitForBody();
clickHeaderButton("Update"); clickHeaderButton("Update");
} }
public void reset() { public void reset() {
waitAjaxForBody(); waitForBody();
clickHeaderButton("Reset"); clickHeaderButton("Reset");
} }
public void filter() { public void filter() {
waitAjaxForBody(); waitForBody();
filterButton.click(); filterButton.click();
} }

View file

@ -104,7 +104,7 @@ public class Config extends Events {
} }
public void waitForClearEventsButtonPresent() { public void waitForClearEventsButtonPresent() {
waitAjaxForElement(clearLoginEventsButton); waitUntilElement(clearLoginEventsButton).is().present();
} }
} }
} }

View file

@ -33,17 +33,17 @@ public class LoginEvents extends Events {
private LoginEventsTableFilterForm filterForm; private LoginEventsTableFilterForm filterForm;
public void update() { public void update() {
waitAjaxForBody(); waitForBody();
clickHeaderButton("Update"); clickHeaderButton("Update");
} }
public void reset() { public void reset() {
waitAjaxForBody(); waitForBody();
clickHeaderButton("Reset"); clickHeaderButton("Reset");
} }
public void filter() { public void filter() {
waitAjaxForBody(); waitForBody();
filterButton.click(); filterButton.click();
} }

View file

@ -1,6 +1,6 @@
package org.keycloak.testsuite.console.page.federation; package org.keycloak.testsuite.console.page.federation;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch; import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
import org.keycloak.testsuite.page.Form; import org.keycloak.testsuite.page.Form;
@ -50,7 +50,7 @@ public class KerberosUserProviderForm extends Form {
} }
public void setKerberosRealmInput(String kerberosRealm) { public void setKerberosRealmInput(String kerberosRealm) {
waitGuiForElement(By.id("kerberosRealm")); waitUntilElement(By.id("kerberosRealm")).is().present();
setInputValue(kerberosRealmInput, kerberosRealm); setInputValue(kerberosRealmInput, kerberosRealm);
} }
@ -71,7 +71,7 @@ public class KerberosUserProviderForm extends Form {
} }
public void selectEditMode(String mode) { public void selectEditMode(String mode) {
waitGuiForElement(By.id("editMode")); waitUntilElement(By.id("editMode")).is().present();
editModeSelect.selectByVisibleText(mode); editModeSelect.selectByVisibleText(mode);
} }

View file

@ -1,7 +1,7 @@
package org.keycloak.testsuite.console.page.federation; package org.keycloak.testsuite.console.page.federation;
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.jboss.arquillian.graphene.findby.FindByJQuery; import org.jboss.arquillian.graphene.findby.FindByJQuery;
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch; import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
@ -156,17 +156,14 @@ public class LdapUserProviderForm extends Form {
} }
public void setKerberosRealmInput(String kerberosRealm) { public void setKerberosRealmInput(String kerberosRealm) {
waitAjaxForElement(kerberosRealmInput);
setInputValue(kerberosRealmInput, kerberosRealm); setInputValue(kerberosRealmInput, kerberosRealm);
} }
public void setServerPrincipalInput(String serverPrincipal) { public void setServerPrincipalInput(String serverPrincipal) {
waitAjaxForElement(serverPrincipalInput);
setInputValue(serverPrincipalInput, serverPrincipal); setInputValue(serverPrincipalInput, serverPrincipal);
} }
public void setKeyTabInput(String keyTab) { public void setKeyTabInput(String keyTab) {
waitAjaxForElement(keyTabInput);
setInputValue(keyTabInput, keyTab); setInputValue(keyTabInput, keyTab);
} }
@ -175,22 +172,22 @@ public class LdapUserProviderForm extends Form {
} }
public void selectEditMode(String mode) { public void selectEditMode(String mode) {
waitGuiForElement(By.id("editMode")); waitUntilElement(By.id("editMode")).is().present();
editModeSelect.selectByVisibleText(mode); editModeSelect.selectByVisibleText(mode);
} }
public void selectVendor(String vendor) { public void selectVendor(String vendor) {
waitGuiForElement(By.id("vendor")); waitUntilElement(By.id("vendor")).is().present();
vendorSelect.selectByVisibleText(vendor); vendorSelect.selectByVisibleText(vendor);
} }
public void selectAuthenticationType(String authenticationType) { public void selectAuthenticationType(String authenticationType) {
waitGuiForElement(By.id("authType")); waitUntilElement(By.id("authType")).is().present();
authTypeSelect.selectByVisibleText(authenticationType); authTypeSelect.selectByVisibleText(authenticationType);
} }
public void selectSearchScope(String searchScope) { public void selectSearchScope(String searchScope) {
waitGuiForElement(By.id("searchScope")); waitUntilElement(By.id("searchScope")).is().present();
searchScopeSelect.selectByVisibleText(searchScope); searchScopeSelect.selectByVisibleText(searchScope);
} }
@ -248,7 +245,7 @@ public class LdapUserProviderForm extends Form {
} }
public void synchronizeAllUsers() { public void synchronizeAllUsers() {
waitAjaxForElement(synchronizeAllUsersButton); waitUntilElement(synchronizeAllUsersButton).is().present();
synchronizeAllUsersButton.click(); synchronizeAllUsersButton.click();
} }
} }

View file

@ -5,7 +5,7 @@ import org.keycloak.testsuite.console.page.AdminConsoleRealm;
import org.openqa.selenium.By; import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.Select; import org.openqa.selenium.support.ui.Select;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
/** /**
* Created by fkiss. * Created by fkiss.
@ -21,7 +21,7 @@ public class UserFederation extends AdminConsoleRealm {
private Select addProviderSelect; private Select addProviderSelect;
public void addProvider(String provider) { public void addProvider(String provider) {
waitGuiForElement(By.cssSelector("select[ng-model*='selectedProvider']")); waitUntilElement(By.cssSelector("select[ng-model*='selectedProvider']")).is().present();
addProviderSelect.selectByVisibleText(provider); addProviderSelect.selectByVisibleText(provider);
} }

View file

@ -0,0 +1,50 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.fragment;
import org.keycloak.testsuite.page.AbstractAlert;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
/**
*
* @author Petr Mensik
* @author tkyjovsk
*/
public class AdminConsoleAlert extends AbstractAlert {
@FindBy(xpath = "//button[@class='close']")
protected WebElement closeButton;
public boolean isInfo() {
return getAttributeClass().contains("alert-info");
}
public boolean isWarning() {
return getAttributeClass().contains("alert-warning");
}
public boolean isDanger() {
return getAttributeClass().contains("alert-danger");
}
public void close() {
closeButton.click();
}
}

View file

@ -7,7 +7,8 @@ import org.openqa.selenium.support.FindBy;
import java.util.List; import java.util.List;
import static org.keycloak.testsuite.util.WaitUtils.pause; import static org.keycloak.testsuite.util.WaitUtils.pause;
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.By;
import static org.openqa.selenium.By.xpath; import static org.openqa.selenium.By.xpath;
/** /**
@ -32,18 +33,18 @@ public class DataTable {
private WebElement infoRow; private WebElement infoRow;
public void search(String pattern) { public void search(String pattern) {
waitAjaxForBody(); waitForBody();
searchInput.sendKeys(pattern); searchInput.sendKeys(pattern);
searchButton.click(); searchButton.click();
} }
public void clickHeaderButton(String buttonText) { public void clickHeaderButton(String buttonText) {
waitAjaxForBody(); waitForBody();
header.findElement(By.xpath(".//button[text()='" + buttonText + "']")).click(); header.findElement(By.xpath(".//button[text()='" + buttonText + "']")).click();
} }
public void clickHeaderLink(String linkText) { public void clickHeaderLink(String linkText) {
waitAjaxForBody(); waitForBody();
header.findElement(By.linkText(linkText)).click(); header.findElement(By.linkText(linkText)).click();
} }
@ -51,19 +52,19 @@ public class DataTable {
return body; return body;
} }
public void waitAjaxForBody() { public void waitForBody() {
waitAjaxForElement(body); waitUntilElement(body).is().present();
} }
public List<WebElement> rows() { public List<WebElement> rows() {
waitAjaxForBody(); waitForBody();
pause(250); pause(250);
return rows; return rows;
} }
public WebElement getRowByLinkText(String text) { public WebElement getRowByLinkText(String text) {
WebElement row = body.findElement(By.xpath(".//tr[./td/a[text()='" + text + "']]")); WebElement row = body.findElement(By.xpath(".//tr[./td/a[text()='" + text + "']]"));
waitAjaxForElement(row); waitUntilElement(row).is().present();
return row; return row;
} }

View file

@ -1,66 +0,0 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.fragment;
import static org.jboss.arquillian.graphene.Graphene.waitGui;
import org.jboss.arquillian.graphene.fragment.Root;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementPresent;
import org.openqa.selenium.WebElement;
/**
*
* @author Petr Mensik
*/
public class FlashMessage {
@Root
private WebElement root;
public boolean isSuccess() {
waitGui().until("Flash message should be success")
.element(root)
.attribute("class")
.contains("success");
return root.getAttribute("class").contains("success");
}
public boolean isError() {
waitGui().until("Flash message should be error")
.element(root)
.attribute("class")
.contains("error");
return root.getAttribute("class").contains("error");
}
public boolean isDanger() {
waitGui().until("Flash message should be danger")
.element(root)
.attribute("class")
.contains("danger");
return root.getAttribute("class").contains("danger");
}
public String getText() {
return root.getText();
}
public void waitUntilPresent() {
waitGuiForElementPresent(root, "Flash message should be visible.");
}
}

View file

@ -18,7 +18,7 @@
package org.keycloak.testsuite.console.page.fragment; package org.keycloak.testsuite.console.page.fragment;
import java.util.List; import java.util.List;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.By; import org.openqa.selenium.By;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
@ -53,7 +53,7 @@ public class Menu {
} }
public String getCurrentRealm() { public String getCurrentRealm() {
waitGuiForElement(By.cssSelector(MENU_LOCATOR)); waitUntilElement(By.cssSelector(MENU_LOCATOR)).is().present();
return toggle.get(1).getText(); return toggle.get(1).getText();
} }
@ -67,7 +67,7 @@ public class Menu {
menuOrder = 0; menuOrder = 0;
break; break;
} }
waitGuiForElement(By.cssSelector(MENU_LOCATOR)); waitUntilElement(By.cssSelector(MENU_LOCATOR)).is().present();
if (!menuList.get(menuOrder).isDisplayed()) { if (!menuList.get(menuOrder).isDisplayed()) {
toggle.get(menuOrder).click(); toggle.get(menuOrder).click();
} }

View file

@ -1,6 +1,6 @@
package org.keycloak.testsuite.console.page.fragment; package org.keycloak.testsuite.console.page.fragment;
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -21,22 +21,22 @@ public class ModalDialog {
private WebElement nameInput; private WebElement nameInput;
public void ok() { public void ok() {
waitAjaxForElement(okButton); waitUntilElement(okButton).is().present();
okButton.click(); okButton.click();
} }
public void confirmDeletion() { public void confirmDeletion() {
waitAjaxForElement(deleteButton); waitUntilElement(deleteButton).is().present();
deleteButton.click(); deleteButton.click();
} }
public void cancel() { public void cancel() {
waitAjaxForElement(cancelButton); waitUntilElement(cancelButton).is().present();
cancelButton.click(); cancelButton.click();
} }
public void setName(String name) { public void setName(String name) {
waitAjaxForElement(nameInput); waitUntilElement(nameInput).is().present();
nameInput.clear(); nameInput.clear();
nameInput.sendKeys(name); nameInput.sendKeys(name);
} }

View file

@ -19,7 +19,7 @@ package org.keycloak.testsuite.console.page.fragment;
import org.jboss.arquillian.graphene.fragment.Root; import org.jboss.arquillian.graphene.fragment.Root;
import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.arquillian.test.api.ArquillianResource;
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.By; import org.openqa.selenium.By;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.interactions.Actions;
@ -45,12 +45,12 @@ public class OnOffSwitch {
} }
public boolean isOn() { public boolean isOn() {
waitAjaxForElement(root); waitUntilElement(root).is().present();
return root.findElement(By.tagName("input")).isSelected(); return root.findElement(By.tagName("input")).isSelected();
} }
private void click() { private void click() {
waitAjaxForElement(root); waitUntilElement(root).is().present();
actions.moveToElement(root.findElements(By.tagName("span")).get(0)) actions.moveToElement(root.findElements(By.tagName("span")).get(0))
.click().build().perform(); .click().build().perform();
} }

View file

@ -20,7 +20,7 @@ package org.keycloak.testsuite.console.page.realm;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select; import org.openqa.selenium.support.ui.Select;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.By; import org.openqa.selenium.By;
/** /**
@ -47,7 +47,7 @@ public class ThemeSettings extends RealmSettings {
private Select emailThemeSelect; private Select emailThemeSelect;
public void changeLoginTheme(String themeName) { public void changeLoginTheme(String themeName) {
waitGuiForElement(By.id("loginTheme")); waitUntilElement(By.id("loginTheme")).is().present();
loginThemeSelect.selectByVisibleText(themeName); loginThemeSelect.selectByVisibleText(themeName);
} }

View file

@ -23,7 +23,7 @@ import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select; import org.openqa.selenium.support.ui.Select;
import static java.lang.String.valueOf; import static java.lang.String.valueOf;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import static org.apache.commons.lang3.text.WordUtils.capitalize; import static org.apache.commons.lang3.text.WordUtils.capitalize;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.testsuite.page.Form; import org.keycloak.testsuite.page.Form;
@ -70,7 +70,7 @@ public class TokenSettings extends RealmSettings {
private void setTimeout(Select timeoutElement, WebElement unitElement, private void setTimeout(Select timeoutElement, WebElement unitElement,
int timeout, TimeUnit unit) { int timeout, TimeUnit unit) {
waitGuiForElement(sessionTimeout); waitUntilElement(sessionTimeout).is().present();
timeoutElement.selectByValue(capitalize(unit.name().toLowerCase())); timeoutElement.selectByValue(capitalize(unit.name().toLowerCase()));
unitElement.clear(); unitElement.clear();
unitElement.sendKeys(valueOf(timeout)); unitElement.sendKeys(valueOf(timeout));

View file

@ -9,7 +9,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.keycloak.representations.idm.RoleRepresentation.Composites; import org.keycloak.representations.idm.RoleRepresentation.Composites;
import org.keycloak.testsuite.page.Form; import org.keycloak.testsuite.page.Form;
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.By; import org.openqa.selenium.By;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -127,7 +127,7 @@ public class RoleCompositeRoles extends Form {
// *** original methods *** // *** original methods ***
public void addAvailableRole(String... roles) { public void addAvailableRole(String... roles) {
waitGuiForElement(By.id("available")); waitUntilElement(By.id("available")).is().present();
for (String role : roles) { for (String role : roles) {
availableRealmRolesSelect.selectByVisibleText(role); availableRealmRolesSelect.selectByVisibleText(role);
addSelectedRealmRolesButton.click(); addSelectedRealmRolesButton.click();
@ -135,13 +135,13 @@ public class RoleCompositeRoles extends Form {
} }
public void removeAssignedRole(String role) { public void removeAssignedRole(String role) {
waitGuiForElement(By.id("assigned")); waitUntilElement(By.id("assigned")).is().present();
assignedRealmRolesSelect.selectByVisibleText(role); assignedRealmRolesSelect.selectByVisibleText(role);
removeSelectedRealmRolesButton.click(); removeSelectedRealmRolesButton.click();
} }
public boolean isAssignedRole(String role) { public boolean isAssignedRole(String role) {
waitGuiForElement(By.id("assigned")); waitUntilElement(By.id("assigned")).is().present();
try { try {
assignedRealmRolesSelect.selectByVisibleText(role); assignedRealmRolesSelect.selectByVisibleText(role);
} catch (Exception ex) { } catch (Exception ex) {
@ -151,7 +151,7 @@ public class RoleCompositeRoles extends Form {
} }
public boolean isAssignedClientRole(String role) { public boolean isAssignedClientRole(String role) {
waitGuiForElement(By.id("assigned")); waitUntilElement(By.id("assigned")).is().present();
try { try {
assignedClientRolesSelect.selectByVisibleText(role); assignedClientRolesSelect.selectByVisibleText(role);
} catch (Exception ex) { } catch (Exception ex) {
@ -161,12 +161,12 @@ public class RoleCompositeRoles extends Form {
} }
public void selectClientRole(String client) { public void selectClientRole(String client) {
waitGuiForElement(By.id("clients")); waitUntilElement(By.id("clients")).is().present();
clientSelect.selectByVisibleText(client); clientSelect.selectByVisibleText(client);
} }
public void addAvailableClientRole(String... roles) { public void addAvailableClientRole(String... roles) {
waitGuiForElement(By.id("available-client")); waitUntilElement(By.id("available-client")).is().present();
for (String role : roles) { for (String role : roles) {
availableClientRolesSelect.selectByVisibleText(role); availableClientRolesSelect.selectByVisibleText(role);
addSelectedClientRolesButton.click(); addSelectedClientRolesButton.click();
@ -174,7 +174,7 @@ public class RoleCompositeRoles extends Form {
} }
public void removeAssignedClientRole(String client) { public void removeAssignedClientRole(String client) {
waitGuiForElement(By.id("assigned-client")); waitUntilElement(By.id("assigned-client")).is().present();
assignedClientRolesSelect.selectByVisibleText(client); assignedClientRolesSelect.selectByVisibleText(client);
removeSelectedClientRolesButton.click(); removeSelectedClientRolesButton.click();
} }

View file

@ -28,7 +28,7 @@ public class RolesTable extends DataTable {
} }
public void clickRole(String name) { public void clickRole(String name) {
waitAjaxForBody(); waitForBody();
clickRowByLinkText(name); clickRowByLinkText(name);
} }

View file

@ -4,7 +4,7 @@ import java.util.List;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch; import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
import org.keycloak.testsuite.page.Form; import org.keycloak.testsuite.page.Form;
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select; import org.openqa.selenium.support.ui.Select;
@ -125,7 +125,7 @@ public class UserAttributesForm extends Form {
} }
public void setValues(UserRepresentation user) { public void setValues(UserRepresentation user) {
waitAjaxForElement(usernameInput); waitUntilElement(usernameInput).is().present();
setUsername(user.getUsername()); setUsername(user.getUsername());
setEmail(user.getEmail()); setEmail(user.getEmail());
setFirstName(user.getFirstName()); setFirstName(user.getFirstName());

View file

@ -27,7 +27,7 @@ import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.console.page.AdminConsoleRealm; import org.keycloak.testsuite.console.page.AdminConsoleRealm;
import org.keycloak.testsuite.console.page.fragment.DataTable; import org.keycloak.testsuite.console.page.fragment.DataTable;
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import static org.openqa.selenium.By.*; import static org.openqa.selenium.By.*;
/** /**
@ -73,7 +73,7 @@ public class Users extends AdminConsoleRealm {
} }
public void clickUser(String username) { public void clickUser(String username) {
waitAjaxForElement(body()); waitUntilElement(body()).is().present();
body().findElement(linkText(username)).click(); body().findElement(linkText(username)).click();
} }

View file

@ -0,0 +1,51 @@
package org.keycloak.testsuite.page;
import com.google.common.base.Predicate;
import static org.jboss.arquillian.graphene.Graphene.waitModel;
import org.jboss.arquillian.graphene.fragment.Root;
import org.jboss.logging.Logger;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
/**
*
* @author tkyjovsk
*/
public abstract class AbstractAlert {
protected final Logger log = Logger.getLogger(this.getClass());
@Root
protected WebElement root;
public void waitUntilPresent() {
waitUntilElement(root, "Flash message should be present.").is().present();
}
public void waitUntilPresentAndClassSet() {
waitUntilPresent();
waitModel().until(new Predicate<WebDriver>() {
@Override
public boolean apply(WebDriver input) {
return !getAttributeClass().endsWith("alert-");
}
});
}
public String getText() {
return root.getText();
}
public String getAttributeClass() {
String attrClass = root.getAttribute("class");
log.debug("Alert @class = '" + attrClass + "'");
return attrClass;
}
public boolean isSuccess() {
log.debug("Alert.isSuccess()");
return getAttributeClass().contains("alert-success");
}
}

View file

@ -3,7 +3,7 @@ package org.keycloak.testsuite.page;
import org.jboss.arquillian.drone.api.annotation.Drone; import org.jboss.arquillian.drone.api.annotation.Drone;
import static org.jboss.arquillian.graphene.Graphene.guardAjax; import static org.jboss.arquillian.graphene.Graphene.guardAjax;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement; import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBy;
@ -36,14 +36,14 @@ public class Form {
} }
public static String getInputValue(WebElement input) { public static String getInputValue(WebElement input) {
waitAjaxForElement(input); waitUntilElement(input).is().present();
return input.getAttribute(VALUE); return input.getAttribute(VALUE);
} }
public static final String VALUE = "value"; public static final String VALUE = "value";
public static void setInputValue(WebElement input, String value) { public static void setInputValue(WebElement input, String value) {
waitAjaxForElement(input); waitUntilElement(input).is().present();
if (input.isEnabled()) { if (input.isEnabled()) {
input.clear(); input.clear();
if (value != null) { if (value != null) {

View file

@ -17,11 +17,10 @@
*/ */
package org.keycloak.testsuite.util; package org.keycloak.testsuite.util;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import static org.jboss.arquillian.graphene.Graphene.waitAjax;
import static org.jboss.arquillian.graphene.Graphene.waitGui; import static org.jboss.arquillian.graphene.Graphene.waitGui;
import org.jboss.arquillian.graphene.wait.ElementBuilder;
import org.openqa.selenium.By; import org.openqa.selenium.By;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
@ -33,52 +32,19 @@ import org.openqa.selenium.WebElement;
public final class WaitUtils { public final class WaitUtils {
public static final String PAGELOAD_TIMEOUT_PROP = "pageload.timeout"; public static final String PAGELOAD_TIMEOUT_PROP = "pageload.timeout";
public static final String IMPLICIT_TIMEOUT_PROP = "implicit.timeout";
public static final String SCRIPT_TIMEOUT_PROP = "script.timeout";
public static final String POLLING_INTERVAL_PROP = "polling.interval";
public static final Integer PAGELOAD_TIMEOUT = Integer.parseInt(System.getProperty(PAGELOAD_TIMEOUT_PROP, "5000")); public static final Integer PAGELOAD_TIMEOUT = Integer.parseInt(System.getProperty(PAGELOAD_TIMEOUT_PROP, "60000"));
public static final Integer IMPLICIT_TIMEOUT = Integer.parseInt(System.getProperty(IMPLICIT_TIMEOUT_PROP, "3000"));
public static final Integer SCRIPT_TIMEOUT = Integer.parseInt(System.getProperty(SCRIPT_TIMEOUT_PROP, "3000"));
public static final Integer POLLING_INTERVAL = Integer.parseInt(System.getProperty(POLLING_INTERVAL_PROP, "1000")); public static ElementBuilder<Void> waitUntilElement(By by) {
return waitGui().until().element(by);
public static void waitAjaxForElement(WebElement element) {
waitAjax().withTimeout(SCRIPT_TIMEOUT, TimeUnit.MILLISECONDS).pollingEvery(POLLING_INTERVAL, TimeUnit.MILLISECONDS)
.until().element(element).is().present();
} }
public static void waitAjaxForElementNotPresent(WebElement element) { public static ElementBuilder<Void> waitUntilElement(WebElement element) {
waitAjax().withTimeout(SCRIPT_TIMEOUT, TimeUnit.MILLISECONDS).pollingEvery(POLLING_INTERVAL, TimeUnit.MILLISECONDS) return waitGui().until().element(element);
.until().element(element).is().not().present();
} }
public static void waitAjaxForElementNotVisible(WebElement element) { public static ElementBuilder<Void> waitUntilElement(WebElement element, String failMessage) {
waitAjax().withTimeout(SCRIPT_TIMEOUT, TimeUnit.MILLISECONDS).pollingEvery(POLLING_INTERVAL, TimeUnit.MILLISECONDS) return waitGui().until(failMessage).element(element);
.until().element(element).is().not().visible();
}
public static void waitGuiForElement(By element, String message) {
waitGui().withTimeout(IMPLICIT_TIMEOUT, TimeUnit.MILLISECONDS).pollingEvery(POLLING_INTERVAL, TimeUnit.MILLISECONDS)
.until(message).element(element).is().present();
}
public static void waitGuiForElement(By element) {
waitGuiForElement(element, null);
}
public static void waitGuiForElement(WebElement element) {
waitGuiForElementPresent(element, null);
}
public static void waitGuiForElementPresent(WebElement element, String message) {
waitGui().withTimeout(IMPLICIT_TIMEOUT, TimeUnit.MILLISECONDS).pollingEvery(POLLING_INTERVAL, TimeUnit.MILLISECONDS)
.until(message).element(element).is().present();
}
public static void waitGuiForElementNotPresent(WebElement element) {
waitGui().withTimeout(IMPLICIT_TIMEOUT, TimeUnit.MILLISECONDS).pollingEvery(POLLING_INTERVAL, TimeUnit.MILLISECONDS)
.until().element(element).is().not().present();
} }
public static void pause(long millis) { public static void pause(long millis) {

View file

@ -19,9 +19,7 @@ package org.keycloak.testsuite;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.List; import java.util.List;
import org.jboss.arquillian.graphene.findby.FindByJQuery;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import static org.junit.Assert.assertTrue;
import org.junit.Before; import org.junit.Before;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD; import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
@ -32,7 +30,6 @@ import static org.keycloak.testsuite.admin.Users.setPasswordFor;
import org.keycloak.testsuite.auth.page.AuthRealm; import org.keycloak.testsuite.auth.page.AuthRealm;
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST; import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
import org.keycloak.testsuite.auth.page.login.OIDCLogin; import org.keycloak.testsuite.auth.page.login.OIDCLogin;
import org.keycloak.testsuite.console.page.fragment.FlashMessage;
import org.openqa.selenium.Cookie; import org.openqa.selenium.Cookie;
/** /**
@ -48,9 +45,6 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest {
protected UserRepresentation testUser; protected UserRepresentation testUser;
@FindByJQuery(".alert")
protected FlashMessage flashMessage;
@Override @Override
public void addTestRealms(List<RealmRepresentation> testRealms) { public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmRepresentation testRealmRep = new RealmRepresentation(); RealmRepresentation testRealmRep = new RealmRepresentation();
@ -68,12 +62,12 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest {
deleteAllCookiesForTestRealm(); deleteAllCookiesForTestRealm();
} }
public void createTestUserWithAdminClient() { public void createTestUserWithAdminClient() {
log.debug("creating test user"); log.debug("creating test user");
String id = createUserAndResetPasswordWithAdminClient(testRealmResource(), testUser, PASSWORD); String id = createUserAndResetPasswordWithAdminClient(testRealmResource(), testUser, PASSWORD);
testUser.setId(id); testUser.setId(id);
assignClientRoles(testRealmResource(), id, "realm-management", "view-realm"); assignClientRoles(testRealmResource(), id, "realm-management", "view-realm");
} }
@ -101,21 +95,6 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest {
} }
} }
public void assertFlashMessageSuccess() {
flashMessage.waitUntilPresent();
assertTrue(flashMessage.getText(), flashMessage.isSuccess());
}
public void assertFlashMessageDanger() {
flashMessage.waitUntilPresent();
assertTrue(flashMessage.getText(), flashMessage.isDanger());
}
public void assertFlashMessageError() {
flashMessage.waitUntilPresent();
assertTrue(flashMessage.getText(), flashMessage.isError());
}
public RealmResource testRealmResource() { public RealmResource testRealmResource() {
return adminClient.realm(testRealmPage.getAuthRealm()); return adminClient.realm(testRealmPage.getAuthRealm());
} }

View file

@ -118,8 +118,6 @@ public abstract class AbstractKeycloakTest {
protected void driverSettings() { protected void driverSettings() {
driver.manage().timeouts().pageLoadTimeout(WaitUtils.PAGELOAD_TIMEOUT, TimeUnit.MILLISECONDS); driver.manage().timeouts().pageLoadTimeout(WaitUtils.PAGELOAD_TIMEOUT, TimeUnit.MILLISECONDS);
driver.manage().timeouts().implicitlyWait(WaitUtils.IMPLICIT_TIMEOUT, TimeUnit.MILLISECONDS);
driver.manage().timeouts().setScriptTimeout(WaitUtils.SCRIPT_TIMEOUT, TimeUnit.MILLISECONDS);
driver.manage().window().maximize(); driver.manage().window().maximize();
} }

View file

@ -1,10 +1,13 @@
package org.keycloak.testsuite.account; package org.keycloak.testsuite.account;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import static org.junit.Assert.assertTrue;
import org.junit.Before; import org.junit.Before;
import org.keycloak.testsuite.AbstractAuthTest; import org.keycloak.testsuite.AbstractAuthTest;
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST; import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
import org.keycloak.testsuite.auth.page.account.AccountManagement; import org.keycloak.testsuite.auth.page.account.AccountManagement;
import org.keycloak.testsuite.auth.page.account.fragment.AccountManagementAlert;
import org.openqa.selenium.support.FindBy;
/** /**
* *
@ -15,6 +18,9 @@ public abstract class AbstractAccountManagementTest extends AbstractAuthTest {
@Page @Page
protected AccountManagement testRealmAccountManagementPage; protected AccountManagement testRealmAccountManagementPage;
@FindBy(className = "alert")
protected AccountManagementAlert alert;
@Override @Override
public void setDefaultPageUriParameters() { public void setDefaultPageUriParameters() {
super.setDefaultPageUriParameters(); super.setDefaultPageUriParameters();
@ -27,5 +33,15 @@ public abstract class AbstractAccountManagementTest extends AbstractAuthTest {
// make user test user exists in test realm // make user test user exists in test realm
createTestUserWithAdminClient(); createTestUserWithAdminClient();
} }
public void assertAlertSuccess() {
alert.waitUntilPresentAndClassSet();
assertTrue(alert.isSuccess());
}
public void assertAlertError() {
alert.waitUntilPresentAndClassSet();
assertTrue(alert.isError());
}
} }

View file

@ -66,7 +66,7 @@ public class AccountTest extends AbstractAccountManagementTest {
testRealmAccountPage.setFirstName(NEW_FIRST_NAME); testRealmAccountPage.setFirstName(NEW_FIRST_NAME);
testRealmAccountPage.setLastName(NEW_LAST_NAME); testRealmAccountPage.setLastName(NEW_LAST_NAME);
testRealmAccountPage.save(); testRealmAccountPage.save();
assertFlashMessageSuccess(); assertAlertSuccess();
testRealmAccountManagementPage.signOut(); testRealmAccountManagementPage.signOut();
testRealmLoginPage.form().login(testUser); testRealmLoginPage.form().login(testUser);

View file

@ -38,20 +38,20 @@ public class ChangePasswordTest extends AbstractAccountManagementTest {
@Test @Test
public void invalidChangeAttempts() { public void invalidChangeAttempts() {
testRealmChangePasswordPage.save(); testRealmChangePasswordPage.save();
assertFlashMessageError(); assertAlertError();
testRealmChangePasswordPage.changePasswords(WRONG_PASSWORD, NEW_PASSWORD, NEW_PASSWORD); testRealmChangePasswordPage.changePasswords(WRONG_PASSWORD, NEW_PASSWORD, NEW_PASSWORD);
assertFlashMessageError(); assertAlertError();
testRealmChangePasswordPage.changePasswords(correctPassword, NEW_PASSWORD, NEW_PASSWORD + "-mismatch"); testRealmChangePasswordPage.changePasswords(correctPassword, NEW_PASSWORD, NEW_PASSWORD + "-mismatch");
assertFlashMessageError(); assertAlertError();
} }
@Test @Test
public void successfulChangeAttempts() { public void successfulChangeAttempts() {
// change password successfully // change password successfully
testRealmChangePasswordPage.changePasswords(correctPassword, NEW_PASSWORD, NEW_PASSWORD); testRealmChangePasswordPage.changePasswords(correctPassword, NEW_PASSWORD, NEW_PASSWORD);
assertFlashMessageSuccess(); assertAlertSuccess();
// login using new password // login using new password
testRealmAccountManagementPage.signOut(); testRealmAccountManagementPage.signOut();
@ -61,7 +61,7 @@ public class ChangePasswordTest extends AbstractAccountManagementTest {
// change password back // change password back
testRealmAccountManagementPage.password(); testRealmAccountManagementPage.password();
testRealmChangePasswordPage.changePasswords(NEW_PASSWORD, correctPassword, correctPassword); testRealmChangePasswordPage.changePasswords(NEW_PASSWORD, correctPassword, correctPassword);
assertFlashMessageSuccess(); assertAlertSuccess();
} }
} }

View file

@ -17,7 +17,9 @@
*/ */
package org.keycloak.testsuite.console; package org.keycloak.testsuite.console;
import org.jboss.arquillian.graphene.findby.FindByJQuery;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import static org.junit.Assert.assertTrue;
import org.junit.Before; import org.junit.Before;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AbstractAuthTest; import org.keycloak.testsuite.AbstractAuthTest;
@ -27,6 +29,7 @@ import org.keycloak.testsuite.console.page.AdminConsoleRealm.ConfigureMenu;
import org.keycloak.testsuite.console.page.AdminConsoleRealm.ManageMenu; import org.keycloak.testsuite.console.page.AdminConsoleRealm.ManageMenu;
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST; import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
import org.keycloak.testsuite.auth.page.login.Login; import org.keycloak.testsuite.auth.page.login.Login;
import org.keycloak.testsuite.console.page.fragment.AdminConsoleAlert;
import org.keycloak.testsuite.console.page.fragment.ModalDialog; import org.keycloak.testsuite.console.page.fragment.ModalDialog;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf; import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
@ -46,10 +49,13 @@ public abstract class AbstractConsoleTest extends AbstractAuthTest {
@Page @Page
protected AdminConsole testRealmAdminConsolePage; protected AdminConsole testRealmAdminConsolePage;
@FindBy(xpath = "//div[@class='modal-dialog']") @FindBy(xpath = "//div[@class='modal-dialog']")
protected ModalDialog modalDialog; protected ModalDialog modalDialog;
@FindBy(className = "alert")
protected AdminConsoleAlert alert;
protected boolean adminLoggedIn = false; protected boolean adminLoggedIn = false;
@Override @Override
@ -100,6 +106,18 @@ public abstract class AbstractConsoleTest extends AbstractAuthTest {
assertCurrentUrlStartsWithLoginUrlOf(adminConsole); assertCurrentUrlStartsWithLoginUrlOf(adminConsole);
} }
public void assertAlertSuccess() {
alert.waitUntilPresentAndClassSet();
assertTrue(alert.isSuccess());
alert.close();
}
public void assertAlertDanger() {
alert.waitUntilPresentAndClassSet();
assertTrue(alert.isDanger());
alert.close();
}
public ConfigureMenu configure() { public ConfigureMenu configure() {
return adminConsoleRealmPage.configure(); return adminConsoleRealmPage.configure();
} }

View file

@ -50,18 +50,18 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
passwordPolicyPage.navigateTo(); passwordPolicyPage.navigateTo();
passwordPolicyPage.addPolicy(HASH_ITERATIONS, 5); passwordPolicyPage.addPolicy(HASH_ITERATIONS, 5);
passwordPolicyPage.removePolicy(HASH_ITERATIONS); passwordPolicyPage.removePolicy(HASH_ITERATIONS);
assertFlashMessageSuccess(); assertAlertSuccess();
} }
@Test @Test
public void testInvalidPolicyValues() { public void testInvalidPolicyValues() {
passwordPolicyPage.navigateTo(); passwordPolicyPage.navigateTo();
passwordPolicyPage.addPolicy(HASH_ITERATIONS, "asd"); passwordPolicyPage.addPolicy(HASH_ITERATIONS, "asd");
assertFlashMessageDanger(); assertAlertDanger();
passwordPolicyPage.removePolicy(HASH_ITERATIONS); passwordPolicyPage.removePolicy(HASH_ITERATIONS);
passwordPolicyPage.addPolicy(REGEX_PATTERN, "(["); passwordPolicyPage.addPolicy(REGEX_PATTERN, "([");
assertFlashMessageDanger(); assertAlertDanger();
} }
@Test @Test
@ -72,10 +72,10 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
testUserCredentialsPage.navigateTo(); testUserCredentialsPage.navigateTo();
testUserCredentialsPage.resetPassword("1234567"); testUserCredentialsPage.resetPassword("1234567");
assertFlashMessageDanger(); assertAlertDanger();
testUserCredentialsPage.resetPassword("12345678"); testUserCredentialsPage.resetPassword("12345678");
assertFlashMessageSuccess(); assertAlertSuccess();
} }
@Test @Test
@ -86,10 +86,10 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
testUserCredentialsPage.navigateTo(); testUserCredentialsPage.navigateTo();
testUserCredentialsPage.resetPassword("invalidPassword1"); testUserCredentialsPage.resetPassword("invalidPassword1");
assertFlashMessageDanger(); assertAlertDanger();
testUserCredentialsPage.resetPassword("validPassword12"); testUserCredentialsPage.resetPassword("validPassword12");
assertFlashMessageSuccess(); assertAlertSuccess();
} }
@Test @Test
@ -100,10 +100,10 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
testUserCredentialsPage.navigateTo(); testUserCredentialsPage.navigateTo();
testUserCredentialsPage.resetPassword("iNVALIDPASSWORD"); testUserCredentialsPage.resetPassword("iNVALIDPASSWORD");
assertFlashMessageDanger(); assertAlertDanger();
testUserCredentialsPage.resetPassword("vaLIDPASSWORD"); testUserCredentialsPage.resetPassword("vaLIDPASSWORD");
assertFlashMessageSuccess(); assertAlertSuccess();
} }
@Test @Test
@ -114,10 +114,10 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
testUserCredentialsPage.navigateTo(); testUserCredentialsPage.navigateTo();
testUserCredentialsPage.resetPassword("Invalidpassword"); testUserCredentialsPage.resetPassword("Invalidpassword");
assertFlashMessageDanger(); assertAlertDanger();
testUserCredentialsPage.resetPassword("VAlidpassword"); testUserCredentialsPage.resetPassword("VAlidpassword");
assertFlashMessageSuccess(); assertAlertSuccess();
} }
@Test @Test
@ -128,10 +128,10 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
testUserCredentialsPage.navigateTo(); testUserCredentialsPage.navigateTo();
testUserCredentialsPage.resetPassword("invalidPassword*"); testUserCredentialsPage.resetPassword("invalidPassword*");
assertFlashMessageDanger(); assertAlertDanger();
testUserCredentialsPage.resetPassword("validPassword*#"); testUserCredentialsPage.resetPassword("validPassword*#");
assertFlashMessageSuccess(); assertAlertSuccess();
} }
@Test @Test
@ -142,10 +142,10 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
testUserCredentialsPage.navigateTo(); testUserCredentialsPage.navigateTo();
testUserCredentialsPage.resetPassword(testUser.getUsername()); testUserCredentialsPage.resetPassword(testUser.getUsername());
assertFlashMessageDanger(); assertAlertDanger();
testUserCredentialsPage.resetPassword("validpassword"); testUserCredentialsPage.resetPassword("validpassword");
assertFlashMessageSuccess(); assertAlertSuccess();
} }
@Test @Test
@ -156,10 +156,10 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
testUserCredentialsPage.navigateTo(); testUserCredentialsPage.navigateTo();
testUserCredentialsPage.resetPassword("invalidPassword"); testUserCredentialsPage.resetPassword("invalidPassword");
assertFlashMessageDanger(); assertAlertDanger();
testUserCredentialsPage.resetPassword("VALID#password"); testUserCredentialsPage.resetPassword("VALID#password");
assertFlashMessageSuccess(); assertAlertSuccess();
} }
@Test @Test
@ -170,13 +170,13 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
testUserCredentialsPage.navigateTo(); testUserCredentialsPage.navigateTo();
testUserCredentialsPage.resetPassword("firstPassword"); testUserCredentialsPage.resetPassword("firstPassword");
assertFlashMessageSuccess(); assertAlertSuccess();
testUserCredentialsPage.resetPassword("secondPassword"); testUserCredentialsPage.resetPassword("secondPassword");
assertFlashMessageSuccess(); assertAlertSuccess();
testUserCredentialsPage.resetPassword("firstPassword"); testUserCredentialsPage.resetPassword("firstPassword");
assertFlashMessageDanger(); assertAlertDanger();
} }
} }

View file

@ -60,7 +60,7 @@ public class RequiredActionsTest extends AbstractConsoleTest {
public void termsAndConditionsDefaultActionTest() { public void termsAndConditionsDefaultActionTest() {
requiredActionsPage.setTermsAndConditionEnabled(true); requiredActionsPage.setTermsAndConditionEnabled(true);
requiredActionsPage.setTermsAndConditionDefaultAction(true); requiredActionsPage.setTermsAndConditionDefaultAction(true);
assertFlashMessageSuccess(); assertAlertSuccess();
allowTestRealmUserRegistration(); allowTestRealmUserRegistration();
@ -74,7 +74,7 @@ public class RequiredActionsTest extends AbstractConsoleTest {
@Test @Test
public void configureTotpDefaultActionTest() { public void configureTotpDefaultActionTest() {
requiredActionsPage.setConfigureTotpDefaultAction(true); requiredActionsPage.setConfigureTotpDefaultAction(true);
assertFlashMessageSuccess(); assertAlertSuccess();
allowTestRealmUserRegistration(); allowTestRealmUserRegistration();

View file

@ -36,7 +36,7 @@ public class ClientRolesTest extends AbstractClientTest {
// assertCurrentUrl(createClientRole); // can't do this, need client id to build uri // assertCurrentUrl(createClientRole); // can't do this, need client id to build uri
createClientRolePage.form().setBasicAttributes(roleRep); createClientRolePage.form().setBasicAttributes(roleRep);
createClientRolePage.form().save(); createClientRolePage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
createClientRolePage.form().setCompositeRoles(roleRep); createClientRolePage.form().setCompositeRoles(roleRep);
// TODO add verification of notification message when KEYCLOAK-1497 gets resolved // TODO add verification of notification message when KEYCLOAK-1497 gets resolved
} }
@ -47,11 +47,10 @@ public class ClientRolesTest extends AbstractClientTest {
RoleRepresentation newRole = new RoleRepresentation("client-role", "", false); RoleRepresentation newRole = new RoleRepresentation("client-role", "", false);
createClient(newClient); createClient(newClient);
assertFlashMessageSuccess(); assertAlertSuccess();
clientPage.tabs().roles(); clientPage.tabs().roles();
addClientRole(newRole); addClientRole(newRole);
assertFlashMessageSuccess();
clientRolePage.backToClientRolesViaBreadcrumb(); clientRolePage.backToClientRolesViaBreadcrumb();
assertFalse(clientRolesPage.roles().getRolesFromTableRows().isEmpty()); assertFalse(clientRolesPage.roles().getRolesFromTableRows().isEmpty());
@ -60,7 +59,7 @@ public class ClientRolesTest extends AbstractClientTest {
clientsPage.table().search(newClient.getClientId()); clientsPage.table().search(newClient.getClientId());
clientsPage.table().deleteClient(newClient.getClientId()); clientsPage.table().deleteClient(newClient.getClientId());
modalDialog.confirmDeletion(); modalDialog.confirmDeletion();
assertFlashMessageSuccess(); assertAlertSuccess();
assertNull(clientsPage.table().findClient(newClient.getClientId())); assertNull(clientsPage.table().findClient(newClient.getClientId()));
} }

View file

@ -48,7 +48,7 @@ public class ClientSettingsTest extends AbstractClientTest {
public void crudOIDCConfidential() { public void crudOIDCConfidential() {
newClient = createClientRepresentation("oidc-confidential", "http://example.test/app/*"); newClient = createClientRepresentation("oidc-confidential", "http://example.test/app/*");
createClient(newClient); createClient(newClient);
assertFlashMessageSuccess(); assertAlertSuccess();
clientPage.backToClientsViaBreadcrumb(); clientPage.backToClientsViaBreadcrumb();
assertCurrentUrlEquals(clientsPage); assertCurrentUrlEquals(clientsPage);
@ -70,7 +70,7 @@ public class ClientSettingsTest extends AbstractClientTest {
newClient = createClientRepresentation("oidc-public", "http://example.test/app/*"); newClient = createClientRepresentation("oidc-public", "http://example.test/app/*");
newClient.setPublicClient(true); newClient.setPublicClient(true);
createClient(newClient); createClient(newClient);
assertFlashMessageSuccess(); assertAlertSuccess();
clientPage.backToClientsViaBreadcrumb(); clientPage.backToClientsViaBreadcrumb();
assertCurrentUrlEquals(clientsPage); assertCurrentUrlEquals(clientsPage);
@ -81,7 +81,7 @@ public class ClientSettingsTest extends AbstractClientTest {
newClient = createClientRepresentation("oidc-bearer-only", "http://example.test/app/*"); newClient = createClientRepresentation("oidc-bearer-only", "http://example.test/app/*");
newClient.setBearerOnly(true); newClient.setBearerOnly(true);
createClient(newClient); createClient(newClient);
assertFlashMessageSuccess(); assertAlertSuccess();
clientPage.backToClientsViaBreadcrumb(); clientPage.backToClientsViaBreadcrumb();
assertCurrentUrlEquals(clientsPage); assertCurrentUrlEquals(clientsPage);
@ -99,11 +99,11 @@ public class ClientSettingsTest extends AbstractClientTest {
public void invalidSettings() { public void invalidSettings() {
clientsPage.table().createClient(); clientsPage.table().createClient();
createClientPage.form().save(); createClientPage.form().save();
assertFlashMessageDanger(); assertAlertDanger();
createClientPage.form().setClientId("test-client"); createClientPage.form().setClientId("test-client");
createClientPage.form().save(); createClientPage.form().save();
assertFlashMessageDanger(); assertAlertDanger();
} }
public void assertClientSettingsEqual(ClientRepresentation c1, ClientRepresentation c2) { public void assertClientSettingsEqual(ClientRepresentation c1, ClientRepresentation c2) {

View file

@ -30,7 +30,7 @@ public class ConfigTest extends AbstractConsoleTest {
configPage.form().removeSaveType("LOGIN"); configPage.form().removeSaveType("LOGIN");
configPage.form().setExpiration("50", "Days"); configPage.form().setExpiration("50", "Days");
configPage.form().save(); configPage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
RealmRepresentation realm = testRealmResource().toRepresentation(); RealmRepresentation realm = testRealmResource().toRepresentation();
assertTrue(realm.isEventsEnabled()); assertTrue(realm.isEventsEnabled());
@ -44,7 +44,7 @@ public class ConfigTest extends AbstractConsoleTest {
configPage.form().setSaveAdminEvents(true); configPage.form().setSaveAdminEvents(true);
configPage.form().setIncludeRepresentation(true); configPage.form().setIncludeRepresentation(true);
configPage.form().save(); configPage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
RealmRepresentation realm = testRealmResource().toRepresentation(); RealmRepresentation realm = testRealmResource().toRepresentation();
assertTrue(realm.isAdminEventsEnabled()); assertTrue(realm.isAdminEventsEnabled());

View file

@ -33,7 +33,7 @@ public class KerberosUserFederationTest extends AbstractConsoleTest {
createKerberosUserProvider.form().selectEditMode(READ_ONLY); createKerberosUserProvider.form().selectEditMode(READ_ONLY);
createKerberosUserProvider.form().setUpdateProfileFirstLogin(true); createKerberosUserProvider.form().setUpdateProfileFirstLogin(true);
createKerberosUserProvider.form().save(); createKerberosUserProvider.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
RealmRepresentation realm = testRealmResource().toRepresentation(); RealmRepresentation realm = testRealmResource().toRepresentation();
UserFederationProviderRepresentation ufpr = realm.getUserFederationProviders().get(0); UserFederationProviderRepresentation ufpr = realm.getUserFederationProviders().get(0);
assertKerberosSetings(ufpr, "KEYCLOAK.ORG", "HTTP/localhost@KEYCLOAK.ORG", "http.keytab", "true", "true", "true"); assertKerberosSetings(ufpr, "KEYCLOAK.ORG", "HTTP/localhost@KEYCLOAK.ORG", "http.keytab", "true", "true", "true");
@ -50,18 +50,18 @@ public class KerberosUserFederationTest extends AbstractConsoleTest {
createKerberosUserProvider.form().selectEditMode(UNSYNCED); createKerberosUserProvider.form().selectEditMode(UNSYNCED);
createKerberosUserProvider.form().setUpdateProfileFirstLogin(true); createKerberosUserProvider.form().setUpdateProfileFirstLogin(true);
createKerberosUserProvider.form().save(); createKerberosUserProvider.form().save();
assertFlashMessageDanger(); assertAlertDanger();
createKerberosUserProvider.form().setServerPrincipalInput(""); createKerberosUserProvider.form().setServerPrincipalInput("");
createKerberosUserProvider.form().setKerberosRealmInput("KEYCLOAK.ORG");; createKerberosUserProvider.form().setKerberosRealmInput("KEYCLOAK.ORG");;
createKerberosUserProvider.form().save(); createKerberosUserProvider.form().save();
assertFlashMessageDanger(); assertAlertDanger();
createKerberosUserProvider.form().setServerPrincipalInput("HTTP/localhost@KEYCLOAK.ORG");; createKerberosUserProvider.form().setServerPrincipalInput("HTTP/localhost@KEYCLOAK.ORG");;
createKerberosUserProvider.form().setKeyTabInput(""); createKerberosUserProvider.form().setKeyTabInput("");
createKerberosUserProvider.form().save(); createKerberosUserProvider.form().save();
assertFlashMessageDanger(); assertAlertDanger();
createKerberosUserProvider.form().setKeyTabInput("http.keytab");; createKerberosUserProvider.form().setKeyTabInput("http.keytab");;
createKerberosUserProvider.form().save(); createKerberosUserProvider.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
} }
private void assertKerberosSetings(UserFederationProviderRepresentation ufpr, String kerberosRealm, String serverPrincipal, String keyTab, String debug, String useKerberosForPasswordAuthentication, String updateProfileFirstLogin) { private void assertKerberosSetings(UserFederationProviderRepresentation ufpr, String kerberosRealm, String serverPrincipal, String keyTab, String debug, String useKerberosForPasswordAuthentication, String updateProfileFirstLogin) {

View file

@ -49,7 +49,7 @@ public class LdapUserFederationTest extends AbstractConsoleTest {
createLdapUserProvider.form().setKeyTabInput("http.keytab"); createLdapUserProvider.form().setKeyTabInput("http.keytab");
createLdapUserProvider.form().setDebugEnabled(true); createLdapUserProvider.form().setDebugEnabled(true);
createLdapUserProvider.form().save(); createLdapUserProvider.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
RealmRepresentation realm = testRealmResource().toRepresentation(); RealmRepresentation realm = testRealmResource().toRepresentation();
UserFederationProviderRepresentation ufpr = realm.getUserFederationProviders().get(0); UserFederationProviderRepresentation ufpr = realm.getUserFederationProviders().get(0);
@ -71,7 +71,7 @@ public class LdapUserFederationTest extends AbstractConsoleTest {
createLdapUserProvider.form().setLdapUserDnInput("ou=People,dc=keycloak,dc=org"); createLdapUserProvider.form().setLdapUserDnInput("ou=People,dc=keycloak,dc=org");
createLdapUserProvider.form().setLdapBindCredentialInput("secret"); createLdapUserProvider.form().setLdapBindCredentialInput("secret");
createLdapUserProvider.form().save(); createLdapUserProvider.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
RealmRepresentation realm = testRealmResource().toRepresentation(); RealmRepresentation realm = testRealmResource().toRepresentation();
UserFederationProviderRepresentation ufpr = realm.getUserFederationProviders().get(0); UserFederationProviderRepresentation ufpr = realm.getUserFederationProviders().get(0);
@ -92,22 +92,22 @@ public class LdapUserFederationTest extends AbstractConsoleTest {
createLdapUserProvider.form().setLdapUserDnInput("ou=People,dc=keycloak,dc=org"); createLdapUserProvider.form().setLdapUserDnInput("ou=People,dc=keycloak,dc=org");
createLdapUserProvider.form().setLdapBindCredentialInput("secret"); createLdapUserProvider.form().setLdapBindCredentialInput("secret");
createLdapUserProvider.form().save(); createLdapUserProvider.form().save();
assertFlashMessageDanger(); assertAlertDanger();
createLdapUserProvider.form().setLdapUserDnInput(""); createLdapUserProvider.form().setLdapUserDnInput("");
createLdapUserProvider.form().setLdapConnectionUrlInput("ldap://localhost:389"); createLdapUserProvider.form().setLdapConnectionUrlInput("ldap://localhost:389");
createLdapUserProvider.form().save(); createLdapUserProvider.form().save();
assertFlashMessageDanger(); assertAlertDanger();
createLdapUserProvider.form().setLdapUserDnInput("ou=People,dc=keycloak,dc=org"); createLdapUserProvider.form().setLdapUserDnInput("ou=People,dc=keycloak,dc=org");
createLdapUserProvider.form().setLdapBindDnInput(""); createLdapUserProvider.form().setLdapBindDnInput("");
createLdapUserProvider.form().save(); createLdapUserProvider.form().save();
assertFlashMessageDanger(); assertAlertDanger();
createLdapUserProvider.form().setLdapBindDnInput("uid=admin,ou=system"); createLdapUserProvider.form().setLdapBindDnInput("uid=admin,ou=system");
createLdapUserProvider.form().setLdapBindCredentialInput(""); createLdapUserProvider.form().setLdapBindCredentialInput("");
createLdapUserProvider.form().save(); createLdapUserProvider.form().save();
assertFlashMessageDanger(); assertAlertDanger();
createLdapUserProvider.form().setLdapBindCredentialInput("secret"); createLdapUserProvider.form().setLdapBindCredentialInput("secret");
createLdapUserProvider.form().save(); createLdapUserProvider.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
} }
@Test @Test
@ -122,19 +122,19 @@ public class LdapUserFederationTest extends AbstractConsoleTest {
createLdapUserProvider.form().setLdapBindCredentialInput("secret"); createLdapUserProvider.form().setLdapBindCredentialInput("secret");
createLdapUserProvider.form().setAccountAfterPasswordUpdateEnabled(true); createLdapUserProvider.form().setAccountAfterPasswordUpdateEnabled(true);
createLdapUserProvider.form().save(); createLdapUserProvider.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
LDAPEmbeddedServer ldapServer = null; LDAPEmbeddedServer ldapServer = null;
try { try {
ldapServer = startEmbeddedLdapServer(); ldapServer = startEmbeddedLdapServer();
createLdapUserProvider.form().testConnection(); createLdapUserProvider.form().testConnection();
assertFlashMessageSuccess(); assertAlertSuccess();
createLdapUserProvider.form().testAuthentication(); createLdapUserProvider.form().testAuthentication();
assertFlashMessageSuccess(); assertAlertSuccess();
createLdapUserProvider.form().synchronizeAllUsers(); createLdapUserProvider.form().synchronizeAllUsers();
assertFlashMessageSuccess(); assertAlertSuccess();
createLdapUserProvider.form().setLdapBindCredentialInput("secret1"); createLdapUserProvider.form().setLdapBindCredentialInput("secret1");
createLdapUserProvider.form().testAuthentication(); createLdapUserProvider.form().testAuthentication();
assertFlashMessageDanger(); assertAlertDanger();
} finally { } finally {
if (ldapServer != null) { if (ldapServer != null) {
ldapServer.stop(); ldapServer.stop();

View file

@ -38,8 +38,7 @@ public class IdentityProviderTest extends AbstractConsoleTest {
// @Test // @Test
public void testAddNewProvider() { public void testAddNewProvider() {
idpSettingsPage.addNewProvider(new Provider(SocialProvider.FACEBOOK, "klic", "secret")); idpSettingsPage.addNewProvider(new Provider(SocialProvider.FACEBOOK, "klic", "secret"));
flashMessage.waitUntilPresent(); assertAlertSuccess();
assertTrue("Success message should be displayed", flashMessage.isSuccess());
} }
// @Test(expected = NoSuchElementException.class) // @Test(expected = NoSuchElementException.class)

View file

@ -74,7 +74,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
bruteForceDetectionPage.form().setWaitIncrementSelect(BruteForceDetection.TimeSelectValues.SECONDS); bruteForceDetectionPage.form().setWaitIncrementSelect(BruteForceDetection.TimeSelectValues.SECONDS);
bruteForceDetectionPage.form().setWaitIncrementInput(String.valueOf(secondsToWait)); bruteForceDetectionPage.form().setWaitIncrementInput(String.valueOf(secondsToWait));
bruteForceDetectionPage.form().save(); bruteForceDetectionPage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
testRealmAccountPage.navigateTo(); testRealmAccountPage.navigateTo();
@ -115,7 +115,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
bruteForceDetectionPage.form().setMinQuickLoginWaitSelect(BruteForceDetection.TimeSelectValues.SECONDS); bruteForceDetectionPage.form().setMinQuickLoginWaitSelect(BruteForceDetection.TimeSelectValues.SECONDS);
bruteForceDetectionPage.form().setMinQuickLoginWaitInput(String.valueOf(secondsToWait)); bruteForceDetectionPage.form().setMinQuickLoginWaitInput(String.valueOf(secondsToWait));
bruteForceDetectionPage.form().save(); bruteForceDetectionPage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
testRealmAccountPage.navigateTo(); testRealmAccountPage.navigateTo();
@ -195,7 +195,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
bruteForceDetectionPage.form().setFailureResetTimeSelect(BruteForceDetection.TimeSelectValues.SECONDS); bruteForceDetectionPage.form().setFailureResetTimeSelect(BruteForceDetection.TimeSelectValues.SECONDS);
bruteForceDetectionPage.form().setFailureResetTimeInput(String.valueOf(secondsToWait)); bruteForceDetectionPage.form().setFailureResetTimeInput(String.valueOf(secondsToWait));
bruteForceDetectionPage.form().save(); bruteForceDetectionPage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
testRealmAccountPage.navigateTo(); testRealmAccountPage.navigateTo();
@ -228,7 +228,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
bruteForceDetectionPage.form().setWaitIncrementSelect(BruteForceDetection.TimeSelectValues.MINUTES); bruteForceDetectionPage.form().setWaitIncrementSelect(BruteForceDetection.TimeSelectValues.MINUTES);
bruteForceDetectionPage.form().setWaitIncrementInput("10"); bruteForceDetectionPage.form().setWaitIncrementInput("10");
bruteForceDetectionPage.form().save(); bruteForceDetectionPage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
testRealmAccountPage.navigateTo(); testRealmAccountPage.navigateTo();

View file

@ -44,7 +44,7 @@ public class DefaultRolesTest extends AbstractRolesTest {
String defaultRoleName = defaultRoleRep.getName(); String defaultRoleName = defaultRoleRep.getName();
defaultRolesPage.form().addAvailableRole(defaultRoleName); defaultRolesPage.form().addAvailableRole(defaultRoleName);
assertFlashMessageSuccess(); assertAlertSuccess();
UserRepresentation newUser = new UserRepresentation(); UserRepresentation newUser = new UserRepresentation();
newUser.setUsername("new_user"); newUser.setUsername("new_user");

View file

@ -42,7 +42,7 @@ public class RealmRolesTest extends AbstractRolesTest {
assertCurrentUrlEquals(createRolePage); assertCurrentUrlEquals(createRolePage);
createRolePage.form().setBasicAttributes(roleRep); createRolePage.form().setBasicAttributes(roleRep);
createRolePage.form().save(); createRolePage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
createRolePage.form().setCompositeRoles(roleRep); createRolePage.form().setCompositeRoles(roleRep);
// TODO add verification of notification message when KEYCLOAK-1497 gets resolved // TODO add verification of notification message when KEYCLOAK-1497 gets resolved
} }
@ -53,7 +53,7 @@ public class RealmRolesTest extends AbstractRolesTest {
// assertCurrentUrl(role); // can't do this, role id needed as uri param // assertCurrentUrl(role); // can't do this, role id needed as uri param
rolePage.form().setBasicAttributes(roleRep); rolePage.form().setBasicAttributes(roleRep);
rolePage.form().save(); rolePage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
rolePage.form().setCompositeRoles(roleRep); rolePage.form().setCompositeRoles(roleRep);
} }
@ -64,6 +64,7 @@ public class RealmRolesTest extends AbstractRolesTest {
} }
@Test @Test
@Ignore
public void crudRole() { public void crudRole() {
addRole(testRole); addRole(testRole);
@ -77,7 +78,7 @@ public class RealmRolesTest extends AbstractRolesTest {
testRole.setDescription("updated role description"); testRole.setDescription("updated role description");
rolePage.form().setDescription(testRole.getDescription()); rolePage.form().setDescription(testRole.getDescription());
rolePage.form().save(); rolePage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
configure().roles(); configure().roles();
foundRole = realmRolesPage.table().findRole(testRole.getName()); // search & get role from table foundRole = realmRolesPage.table().findRole(testRole.getName()); // search & get role from table
@ -111,13 +112,12 @@ public class RealmRolesTest extends AbstractRolesTest {
@Test @Test
public void testAddExistingRole() { public void testAddExistingRole() {
addRole(testRole); addRole(testRole);
assertFlashMessageSuccess();
configure().roles(); configure().roles();
realmRolesPage.table().addRole(); realmRolesPage.table().addRole();
createRolePage.form().setBasicAttributes(testRole); createRolePage.form().setBasicAttributes(testRole);
createRolePage.form().save(); createRolePage.form().save();
assertFlashMessageDanger(); assertAlertDanger();
} }
public void createTestRoles(String namePrefix, int count) { public void createTestRoles(String namePrefix, int count) {

View file

@ -67,7 +67,7 @@ public class RequiredUserActionsTest extends AbstractUserTest {
public void updatePassword() { public void updatePassword() {
userAttributesPage.form().addRequiredAction(UPDATE_PASSWORD.getActionName()); userAttributesPage.form().addRequiredAction(UPDATE_PASSWORD.getActionName());
userAttributesPage.form().save(); userAttributesPage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
testRealmAccountPage.navigateTo(); testRealmAccountPage.navigateTo();
@ -91,7 +91,7 @@ public class RequiredUserActionsTest extends AbstractUserTest {
public void updateProfile() { public void updateProfile() {
userAttributesPage.form().addRequiredAction(UPDATE_PROFILE.getActionName()); userAttributesPage.form().addRequiredAction(UPDATE_PROFILE.getActionName());
userAttributesPage.form().save(); userAttributesPage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
testRealmAccountPage.navigateTo(); testRealmAccountPage.navigateTo();
@ -128,7 +128,7 @@ public class RequiredUserActionsTest extends AbstractUserTest {
userAttributesPage.form().addRequiredAction(TERMS_AND_CONDITIONS.getActionName()); userAttributesPage.form().addRequiredAction(TERMS_AND_CONDITIONS.getActionName());
userAttributesPage.form().save(); userAttributesPage.form().save();
assertFlashMessageSuccess(); assertAlertSuccess();
testRealmAccountPage.navigateTo(); testRealmAccountPage.navigateTo();

View file

@ -49,7 +49,7 @@ public class UserAttributesTest extends AbstractUserTest {
setPasswordFor(newTestRealmUser, "pass"); setPasswordFor(newTestRealmUser, "pass");
newTestRealmUser.setEmail(invalidEmail); newTestRealmUser.setEmail(invalidEmail);
createUser(newTestRealmUser); createUser(newTestRealmUser);
assertFlashMessageDanger(); assertAlertDanger();
userAttributesPage.backToUsersViaBreadcrumb(); userAttributesPage.backToUsersViaBreadcrumb();
assertNull(usersPage.table().findUser(testUsername)); assertNull(usersPage.table().findUser(testUsername));
@ -58,7 +58,7 @@ public class UserAttributesTest extends AbstractUserTest {
@Test @Test
public void noUsername() { public void noUsername() {
createUser(newTestRealmUser); createUser(newTestRealmUser);
assertFlashMessageDanger(); assertAlertDanger();
} }
@Test @Test
@ -66,7 +66,7 @@ public class UserAttributesTest extends AbstractUserTest {
String testUsername = "test_duplicated_user"; String testUsername = "test_duplicated_user";
newTestRealmUser.setUsername(testUsername); newTestRealmUser.setUsername(testUsername);
createUser(newTestRealmUser); createUser(newTestRealmUser);
assertFlashMessageSuccess(); assertAlertSuccess();
userAttributesPage.backToUsersViaBreadcrumb(); userAttributesPage.backToUsersViaBreadcrumb();
assertNotNull(usersPage.table().findUser(testUsername)); assertNotNull(usersPage.table().findUser(testUsername));
@ -74,7 +74,7 @@ public class UserAttributesTest extends AbstractUserTest {
UserRepresentation testUser2 = new UserRepresentation(); UserRepresentation testUser2 = new UserRepresentation();
testUser2.setUsername(testUsername); testUser2.setUsername(testUsername);
createUser(testUser2); createUser(testUser2);
assertFlashMessageDanger(); assertAlertDanger();
} }
@Test @Test
@ -83,7 +83,7 @@ public class UserAttributesTest extends AbstractUserTest {
disabledUser.setEnabled(false); disabledUser.setEnabled(false);
disabledUser.setUsername("disabled_user"); disabledUser.setUsername("disabled_user");
createUser(disabledUser); createUser(disabledUser);
assertFlashMessageSuccess(); assertAlertSuccess();
// TODO try to log in // TODO try to log in
} }

View file

@ -9,6 +9,13 @@
<property name="browser">${browser}</property> <property name="browser">${browser}</property>
</extension> </extension>
<extension qualifier="graphene">
<property name="waitGuiInterval">5</property>
<property name="waitAjaxInterval">5</property>
<property name="waitModelInterval">10</property>
<property name="waitGuardInterval">5</property>
</extension>
<extension qualifier="graphene-secondbrowser"> <extension qualifier="graphene-secondbrowser">
<property name="browser">${browser}</property> <property name="browser">${browser}</property>
</extension> </extension>

View file

@ -609,6 +609,7 @@
</pluginManagement> </pluginManagement>
</build> </build>
</profile> </profile>
</profiles> </profiles>
</project> </project>

View file

@ -1,16 +1,17 @@
package org.keycloak.testsuite.adduser; package org.keycloak.testsuite.adduser;
import org.codehaus.jackson.type.TypeReference; import org.codehaus.jackson.type.TypeReference;
import org.junit.*; import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.RoleMappingResource;
import org.keycloak.admin.client.resource.RoleScopeResource;
import org.keycloak.admin.client.resource.UserResource; import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64;
import org.keycloak.hash.Pbkdf2PasswordHashProvider;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
import org.keycloak.representations.idm.*; import org.keycloak.representations.idm.*;
import org.keycloak.testsuite.KeycloakServer; import org.keycloak.testsuite.KeycloakServer;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
@ -19,7 +20,6 @@ import org.keycloak.wildfly.adduser.AddUser;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -59,7 +59,11 @@ public class AddUserTest {
UserRepresentation user = realms.get(0).getUsers().get(0); UserRepresentation user = realms.get(0).getUsers().get(0);
assertEquals(new Integer(100000), user.getCredentials().get(0).getHashIterations()); assertEquals(new Integer(100000), user.getCredentials().get(0).getHashIterations());
assertNull(user.getCredentials().get(0).getValue()); assertNull(user.getCredentials().get(0).getValue());
assertEquals(new Pbkdf2PasswordEncoder(Base64Url.decode(user.getCredentials().get(0).getSalt()), 100000).encode("password"), user.getCredentials().get(0).getHashedSaltedValue());
CredentialRepresentation credentials = user.getCredentials().get(0);
assertEquals(Pbkdf2PasswordHashProvider.ID, credentials.getAlgorithm());
assertEquals(new Integer(100000), credentials.getHashIterations());
KeycloakServer server = new KeycloakServer(); KeycloakServer server = new KeycloakServer();
try { try {

View file

@ -322,7 +322,12 @@ public class ExportImportTest {
Assert.fail("user " + username + " not found"); Assert.fail("user " + username + " not found");
} }
Assert.assertTrue(userProvider.validCredentials(realm, user, UserCredentialModel.password(password))); KeycloakSession session = keycloakRule.startSession();
try {
Assert.assertTrue(userProvider.validCredentials(session, realm, user, UserCredentialModel.password(password)));
} finally {
keycloakRule.stopSession(session, true);
}
} }
private void assertNotAuthenticated(UserProvider userProvider, RealmProvider realmProvider, String realmName, String username, String password) { private void assertNotAuthenticated(UserProvider userProvider, RealmProvider realmProvider, String realmName, String username, String password) {
@ -336,7 +341,12 @@ public class ExportImportTest {
return; return;
} }
Assert.assertFalse(userProvider.validCredentials(realm, user, UserCredentialModel.password(password))); KeycloakSession session = keycloakRule.startSession();
try {
Assert.assertFalse(userProvider.validCredentials(session, realm, user, UserCredentialModel.password(password)));
} finally {
keycloakRule.stopSession(session, true);
}
} }
private static void addUser(UserProvider userProvider, RealmModel appRealm, String username, String password) { private static void addUser(UserProvider userProvider, RealmModel appRealm, String username, String password) {

View file

@ -678,7 +678,7 @@ public class FederationProvidersIntegrationTest {
user.updateCredential(cred); user.updateCredential(cred);
UserCredentialValueModel userCredentialValueModel = user.getCredentialsDirectly().get(0); UserCredentialValueModel userCredentialValueModel = user.getCredentialsDirectly().get(0);
Assert.assertEquals(UserCredentialModel.PASSWORD, userCredentialValueModel.getType()); Assert.assertEquals(UserCredentialModel.PASSWORD, userCredentialValueModel.getType());
Assert.assertTrue(session.users().validCredentials(appRealm, user, cred)); Assert.assertTrue(session.users().validCredentials(session, appRealm, user, cred));
// LDAP password is still unchanged // LDAP password is still unchanged
LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, model); LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, model);

View file

@ -144,11 +144,11 @@ public class AdapterTest extends AbstractModelTest {
cred.setType(CredentialRepresentation.PASSWORD); cred.setType(CredentialRepresentation.PASSWORD);
cred.setValue("geheim"); cred.setValue("geheim");
user.updateCredential(cred); user.updateCredential(cred);
Assert.assertTrue(userProvider.validCredentials(realmModel, user, UserCredentialModel.password("geheim"))); Assert.assertTrue(userProvider.validCredentials(session, realmModel, user, UserCredentialModel.password("geheim")));
List<UserCredentialValueModel> creds = user.getCredentialsDirectly(); List<UserCredentialValueModel> creds = user.getCredentialsDirectly();
Assert.assertEquals(creds.get(0).getHashIterations(), 1); Assert.assertEquals(creds.get(0).getHashIterations(), 1);
realmModel.setPasswordPolicy(new PasswordPolicy("hashIterations(200)")); realmModel.setPasswordPolicy(new PasswordPolicy("hashIterations(200)"));
Assert.assertTrue(userProvider.validCredentials(realmModel, user, UserCredentialModel.password("geheim"))); Assert.assertTrue(userProvider.validCredentials(session, realmModel, user, UserCredentialModel.password("geheim")));
creds = user.getCredentialsDirectly(); creds = user.getCredentialsDirectly();
Assert.assertEquals(creds.get(0).getHashIterations(), 200); Assert.assertEquals(creds.get(0).getHashIterations(), 200);
realmModel.setPasswordPolicy(new PasswordPolicy("hashIterations(1)")); realmModel.setPasswordPolicy(new PasswordPolicy("hashIterations(1)"));

View file

@ -39,10 +39,10 @@ public class MultipleRealmsTest extends AbstractModelTest {
r1user1.updateCredential(UserCredentialModel.password("pass1")); r1user1.updateCredential(UserCredentialModel.password("pass1"));
r2user1.updateCredential(UserCredentialModel.password("pass2")); r2user1.updateCredential(UserCredentialModel.password("pass2"));
Assert.assertTrue(session.users().validCredentials(realm1, r1user1, UserCredentialModel.password("pass1"))); Assert.assertTrue(session.users().validCredentials(session, realm1, r1user1, UserCredentialModel.password("pass1")));
Assert.assertFalse(session.users().validCredentials(realm1, r1user1, UserCredentialModel.password("pass2"))); Assert.assertFalse(session.users().validCredentials(session, realm1, r1user1, UserCredentialModel.password("pass2")));
Assert.assertFalse(session.users().validCredentials(realm2, r2user1, UserCredentialModel.password("pass1"))); Assert.assertFalse(session.users().validCredentials(session, realm2, r2user1, UserCredentialModel.password("pass1")));
Assert.assertTrue(session.users().validCredentials(realm2, r2user1, UserCredentialModel.password("pass2"))); Assert.assertTrue(session.users().validCredentials(session, realm2, r2user1, UserCredentialModel.password("pass2")));
// Test searching // Test searching
Assert.assertEquals(2, session.users().searchForUser("user", realm1).size()); Assert.assertEquals(2, session.users().searchForUser("user", realm1).size());

View file

@ -102,7 +102,7 @@ public class ReadUsersWorker implements Worker {
// Validate password (shoould be same as username) // Validate password (shoould be same as username)
if (readPassword) { if (readPassword) {
session.users().validCredentials(realm, user, UserCredentialModel.password(username)); session.users().validCredentials(session, realm, user, UserCredentialModel.password(username));
} }
// Read federatedIdentities of user // Read federatedIdentities of user

View file

@ -12,8 +12,8 @@ import org.jboss.aesh.console.command.invocation.CommandInvocation;
import org.jboss.aesh.console.command.registry.AeshCommandRegistryBuilder; import org.jboss.aesh.console.command.registry.AeshCommandRegistryBuilder;
import org.jboss.aesh.console.command.registry.CommandRegistry; import org.jboss.aesh.console.command.registry.CommandRegistry;
import org.keycloak.common.util.Base64; import org.keycloak.common.util.Base64;
import org.keycloak.models.Constants; import org.keycloak.hash.Pbkdf2PasswordHashProvider;
import org.keycloak.models.utils.Pbkdf2PasswordEncoder; import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
@ -138,14 +138,14 @@ public class AddUser {
user.setUsername(userName); user.setUsername(userName);
user.setCredentials(new LinkedList<CredentialRepresentation>()); user.setCredentials(new LinkedList<CredentialRepresentation>());
byte[] salt = Pbkdf2PasswordEncoder.getSalt(); UserCredentialValueModel credentialValueModel = new Pbkdf2PasswordHashProvider().encode(password, iterations > 0 ? iterations : DEFAULT_HASH_ITERATIONS);
iterations = iterations > 0 ? iterations : DEFAULT_HASH_ITERATIONS;
CredentialRepresentation credentials = new CredentialRepresentation(); CredentialRepresentation credentials = new CredentialRepresentation();
credentials.setType(CredentialRepresentation.PASSWORD); credentials.setType(credentialValueModel.getType());
credentials.setHashIterations(iterations); credentials.setAlgorithm(credentialValueModel.getAlgorithm());
credentials.setSalt(Base64.encodeBytes(salt)); credentials.setHashIterations(credentialValueModel.getHashIterations());
credentials.setHashedSaltedValue(new Pbkdf2PasswordEncoder(salt).encode(password, iterations)); credentials.setSalt(Base64.encodeBytes(credentialValueModel.getSalt()));
credentials.setHashedSaltedValue(credentialValueModel.getValue());
user.getCredentials().add(credentials); user.getCredentials().add(credentials);
@ -289,4 +289,4 @@ public class AddUser {
} }
} }
} }