diff --git a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java old mode 100644 new mode 100755 index 5c6b8344588..730f3f44c7c --- a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java +++ b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java @@ -66,7 +66,7 @@ public abstract class AbstractModelAuthenticationProvider implements Authenticat cred.setType(CredentialRepresentation.PASSWORD); cred.setValue(password); - realm.updateCredential(user, cred); + user.updateCredential(cred); return true; } diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java index cdfdcab44fa..660ce101296 100755 --- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java +++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java @@ -255,7 +255,7 @@ public class ModelExporter { userEntity.setRoleIds(roleIds); // credentials - List credentials = realm.getCredentialsDirectly(userModel); + List credentials = userModel.getCredentialsDirectly(); List credEntities = new ArrayList(); for (UserCredentialValueModel credModel : credentials) { CredentialEntity credEntity = new CredentialEntity(); diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java index be7809923c8..0bfbd4dbc7c 100755 --- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java +++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java @@ -302,7 +302,7 @@ public class ModelImporter { UserCredentialValueModel credModel = new UserCredentialValueModel(); this.propertiesManager.setBasicPropertiesToModel(credModel, credEntity); - realm.updateCredentialDirectly(user, credModel); + user.updateCredentialDirectly(credModel); } } } diff --git a/model/api/src/main/java/org/keycloak/models/KeycloakSession.java b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java index aa61bec51b1..a99a09e7dad 100755 --- a/model/api/src/main/java/org/keycloak/models/KeycloakSession.java +++ b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java @@ -15,6 +15,9 @@ public interface KeycloakSession extends Provider { RealmModel createRealm(String id, String name); RealmModel getRealm(String id); RealmModel getRealmByName(String name); + UserModel getUserById(String id, String realmId); + UserModel getUserByUsername(String username, String realmId); + UserModel getUserByEmail(String email, String realmId); List getRealms(); boolean removeRealm(String id); diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java index c2ec9f3ac09..829b9b0fb38 100755 --- a/model/api/src/main/java/org/keycloak/models/RealmModel.java +++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java @@ -110,12 +110,6 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa boolean validateTOTP(UserModel user, String password, String token); - void updateCredential(UserModel user, UserCredentialModel cred); - - List getCredentialsDirectly(UserModel user); - - void updateCredentialDirectly(UserModel user, UserCredentialValueModel cred); - UserModel getUser(String name); UserModel getUserByEmail(String email); diff --git a/model/api/src/main/java/org/keycloak/models/UserModel.java b/model/api/src/main/java/org/keycloak/models/UserModel.java index b01cf93e1fe..f0e34b819ed 100755 --- a/model/api/src/main/java/org/keycloak/models/UserModel.java +++ b/model/api/src/main/java/org/keycloak/models/UserModel.java @@ -1,5 +1,6 @@ package org.keycloak.models; +import java.util.List; import java.util.Map; import java.util.Set; @@ -60,6 +61,14 @@ public interface UserModel { int getNotBefore(); void setNotBefore(int notBefore); + void updateCredential(UserCredentialModel cred); + + List getCredentialsDirectly(); + + void updateCredentialDirectly(UserCredentialValueModel cred); + + + public static enum RequiredAction { VERIFY_EMAIL, UPDATE_PROFILE, CONFIGURE_TOTP, UPDATE_PASSWORD diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheKeycloakSession.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheKeycloakSession.java new file mode 100755 index 00000000000..9b0e421e75c --- /dev/null +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheKeycloakSession.java @@ -0,0 +1,176 @@ +package org.keycloak.models.cache; + +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakTransaction; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.cache.entities.CachedRealm; +import org.keycloak.provider.ProviderSession; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class CacheKeycloakSession implements KeycloakSession { + protected KeycloakCache cache; + protected ProviderSession providerSession; + protected KeycloakSession sessionDelegate; + protected KeycloakTransaction transactionDelegate; + protected boolean transactionActive; + protected boolean setRollbackOnly; + + protected Set realmInvalidations = new HashSet(); + protected boolean clearAll; + + protected KeycloakSession getDelegate() { + if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction"); + if (sessionDelegate != null) return sessionDelegate; + sessionDelegate = providerSession.getProvider(KeycloakSession.class); + transactionDelegate = sessionDelegate.getTransaction(); + if (!transactionDelegate.isActive()) { + transactionDelegate.begin(); + if (setRollbackOnly) { + transactionDelegate.setRollbackOnly(); + } + } + return sessionDelegate; + } + + public void registerInvalidation(RealmAdapter realm) { + realmInvalidations.add(realm.getId()); + } + + public void runInvalidations() { + for (String id : realmInvalidations) { + cache.invalidateCachedRealmById(id); + } + + } + + @Override + public KeycloakTransaction getTransaction() { + return new KeycloakTransaction() { + @Override + public void begin() { + transactionActive = true; + } + + @Override + public void commit() { + if (sessionDelegate == null) return; + try { + sessionDelegate.getTransaction().commit(); + } finally { + runInvalidations(); + } + } + + @Override + public void rollback() { + setRollbackOnly = true; + if (sessionDelegate == null) return; + try { + sessionDelegate.getTransaction().commit(); + } finally { + runInvalidations(); + } + } + + @Override + public void setRollbackOnly() { + setRollbackOnly = true; + if (sessionDelegate == null) return; + sessionDelegate.getTransaction().setRollbackOnly(); + setRollbackOnly = true; + } + + @Override + public boolean getRollbackOnly() { + return setRollbackOnly; + } + + @Override + public boolean isActive() { + return transactionActive; + } + }; + } + + @Override + public RealmModel createRealm(String name) { + return getDelegate().createRealm(name); + } + + @Override + public RealmModel createRealm(String id, String name) { + return getDelegate().createRealm(id, name); + } + + @Override + public RealmModel getRealm(String id) { + CachedRealm cached = cache.getCachedRealm(id); + if (cached == null) { + RealmModel model = getDelegate().getRealm(id); + if (model == null) return null; + cached = new CachedRealm(model); + } + return new RealmAdapter(cached, this); + } + + @Override + public RealmModel getRealmByName(String name) { + CachedRealm cached = cache.getCachedRealmByName(name); + if (cached == null) { + RealmModel model = getDelegate().getRealmByName(name); + if (model == null) return null; + cached = new CachedRealm(model); + } + return new RealmAdapter(cached, this); + } + + @Override + public UserModel getUserById(String id, String realmId) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UserModel getUserByUsername(String username, String realmId) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UserModel getUserByEmail(String email, String realmId) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List getRealms() { + // we don't cache this for now + return getDelegate().getRealms(); + } + + @Override + public boolean removeRealm(String id) { + cache.invalidateCachedRealmById(id); + boolean didIt = getDelegate().removeRealm(id); + realmInvalidations.add(id); + + return didIt; + } + + @Override + public void removeAllData() { + cache.clear(); + getDelegate().removeAllData(); + clearAll = true; + } + + @Override + public void close() { + if (sessionDelegate != null) sessionDelegate.close(); + } +} diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/KeycloakCache.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/KeycloakCache.java new file mode 100755 index 00000000000..fdf0897cb7a --- /dev/null +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/KeycloakCache.java @@ -0,0 +1,21 @@ +package org.keycloak.models.cache; + +import org.keycloak.models.cache.entities.CachedRealm; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface KeycloakCache { + CachedRealm getCachedRealm(String id); + + void invalidateCachedRealm(CachedRealm realm); + + void addCachedRealm(CachedRealm realm); + + CachedRealm getCachedRealmByName(String name); + + void clear(); + + void invalidateCachedRealmById(String id); +} diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java new file mode 100755 index 00000000000..735c108b32b --- /dev/null +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java @@ -0,0 +1,846 @@ +package org.keycloak.models.cache; + +import org.keycloak.models.ApplicationModel; +import org.keycloak.models.AuthenticationLinkModel; +import org.keycloak.models.AuthenticationProviderModel; +import org.keycloak.models.ClientModel; +import org.keycloak.models.OAuthClientModel; +import org.keycloak.models.PasswordPolicy; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RequiredCredentialModel; +import org.keycloak.models.RoleModel; +import org.keycloak.models.SocialLinkModel; +import org.keycloak.models.UserCredentialModel; +import org.keycloak.models.UserCredentialValueModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.UserSessionModel; +import org.keycloak.models.UsernameLoginFailureModel; +import org.keycloak.models.cache.entities.CachedRealm; +import org.keycloak.models.utils.KeycloakModelUtils; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class RealmAdapter implements RealmModel { + protected CachedRealm cached; + protected CacheKeycloakSession cacheSession; + protected RealmModel updated; + protected volatile transient PublicKey publicKey; + protected volatile transient PrivateKey privateKey; + + public RealmAdapter(CachedRealm cached, CacheKeycloakSession cacheSession) { + this.cached = cached; + this.cacheSession = cacheSession; + } + + @Override + public String getId() { + if (updated != null) return updated.getId(); + return cached.getId(); + } + + @Override + public String getName() { + if (updated != null) return updated.getName(); + return cached.getName(); + } + + @Override + public void setName(String name) { + getDelegateForUpdate(); + updated.setName(name); + } + + protected void getDelegateForUpdate() { + if (updated == null) { + updated = cacheSession.getRealm(getId()); + if (updated == null) throw new IllegalStateException("Not found in database"); + } + } + + @Override + public boolean isEnabled() { + if (updated != null) return updated.isEnabled(); + return cached.isEnabled(); + } + + @Override + public void setEnabled(boolean enabled) { + getDelegateForUpdate(); + updated.setEnabled(enabled); + } + + @Override + public boolean isSslNotRequired() { + if (updated != null) return updated.isSslNotRequired(); + return cached.isSslNotRequired(); + } + + @Override + public void setSslNotRequired(boolean sslNotRequired) { + getDelegateForUpdate(); + updated.setSslNotRequired(sslNotRequired); + } + + @Override + public boolean isRegistrationAllowed() { + if (updated != null) return updated.isRegistrationAllowed(); + return cached.isRegistrationAllowed(); + } + + @Override + public void setRegistrationAllowed(boolean registrationAllowed) { + getDelegateForUpdate(); + updated.setRegistrationAllowed(registrationAllowed); + } + + @Override + public boolean isPasswordCredentialGrantAllowed() { + if (updated != null) return updated.isPasswordCredentialGrantAllowed(); + return cached.isPasswordCredentialGrantAllowed(); + } + + @Override + public void setPasswordCredentialGrantAllowed(boolean passwordCredentialGrantAllowed) { + getDelegateForUpdate(); + updated.setPasswordCredentialGrantAllowed(passwordCredentialGrantAllowed); + } + + @Override + public boolean isRememberMe() { + if (updated != null) return updated.isRememberMe(); + return cached.isRememberMe(); + } + + @Override + public void setRememberMe(boolean rememberMe) { + getDelegateForUpdate(); + updated.setRememberMe(rememberMe); + } + + @Override + public boolean isBruteForceProtected() { + if (updated != null) return updated.isBruteForceProtected(); + return cached.isBruteForceProtected(); + } + + @Override + public void setBruteForceProtected(boolean value) { + getDelegateForUpdate(); + updated.setBruteForceProtected(value); + } + + @Override + public int getMaxFailureWaitSeconds() { + if (updated != null) return updated.getMaxFailureWaitSeconds(); + return cached.getMaxFailureWaitSeconds(); + } + + @Override + public void setMaxFailureWaitSeconds(int val) { + getDelegateForUpdate(); + updated.setMaxFailureWaitSeconds(val); + } + + @Override + public int getWaitIncrementSeconds() { + if (updated != null) return updated.getWaitIncrementSeconds(); + return cached.getWaitIncrementSeconds(); + } + + @Override + public void setWaitIncrementSeconds(int val) { + getDelegateForUpdate(); + updated.setWaitIncrementSeconds(val); + } + + @Override + public int getMinimumQuickLoginWaitSeconds() { + if (updated != null) return updated.getMinimumQuickLoginWaitSeconds(); + return cached.getMinimumQuickLoginWaitSeconds(); + } + + @Override + public void setMinimumQuickLoginWaitSeconds(int val) { + getDelegateForUpdate(); + updated.setMinimumQuickLoginWaitSeconds(val); + } + + @Override + public long getQuickLoginCheckMilliSeconds() { + if (updated != null) return updated.getQuickLoginCheckMilliSeconds(); + return cached.getQuickLoginCheckMilliSeconds(); + } + + @Override + public void setQuickLoginCheckMilliSeconds(long val) { + getDelegateForUpdate(); + updated.setQuickLoginCheckMilliSeconds(val); + } + + @Override + public int getMaxDeltaTimeSeconds() { + if (updated != null) return updated.getMaxDeltaTimeSeconds(); + return cached.getMaxDeltaTimeSeconds(); + } + + @Override + public void setMaxDeltaTimeSeconds(int val) { + getDelegateForUpdate(); + updated.setMaxDeltaTimeSeconds(val); + } + + @Override + public int getFailureFactor() { + if (updated != null) return updated.getFailureFactor(); + return cached.getFailureFactor(); + } + + @Override + public void setFailureFactor(int failureFactor) { + getDelegateForUpdate(); + updated.setFailureFactor(failureFactor); + } + + @Override + public boolean isVerifyEmail() { + if (updated != null) return updated.isVerifyEmail(); + return cached.isVerifyEmail(); + } + + @Override + public void setVerifyEmail(boolean verifyEmail) { + getDelegateForUpdate(); + updated.setVerifyEmail(verifyEmail); + } + + @Override + public boolean isResetPasswordAllowed() { + if (updated != null) return updated.isResetPasswordAllowed(); + return cached.isResetPasswordAllowed(); + } + + @Override + public void setResetPasswordAllowed(boolean resetPasswordAllowed) { + getDelegateForUpdate(); + updated.setResetPasswordAllowed(resetPasswordAllowed); + } + + @Override + public int getSsoSessionIdleTimeout() { + if (updated != null) return updated.getSsoSessionIdleTimeout(); + return cached.getSsoSessionIdleTimeout(); + } + + @Override + public void setSsoSessionIdleTimeout(int seconds) { + getDelegateForUpdate(); + updated.setSsoSessionIdleTimeout(seconds); + } + + @Override + public int getSsoSessionMaxLifespan() { + if (updated != null) return updated.getSsoSessionMaxLifespan(); + return cached.getSsoSessionMaxLifespan(); + } + + @Override + public void setSsoSessionMaxLifespan(int seconds) { + getDelegateForUpdate(); + updated.setSsoSessionMaxLifespan(seconds); + } + + @Override + public int getAccessTokenLifespan() { + if (updated != null) return updated.getAccessTokenLifespan(); + return cached.getAccessTokenLifespan(); + } + + @Override + public void setAccessTokenLifespan(int seconds) { + getDelegateForUpdate(); + updated.setAccessTokenLifespan(seconds); + } + + @Override + public int getAccessCodeLifespan() { + if (updated != null) return updated.getAccessCodeLifespan(); + return cached.getAccessCodeLifespan(); + } + + @Override + public void setAccessCodeLifespan(int seconds) { + getDelegateForUpdate(); + updated.setAccessCodeLifespan(seconds); + } + + @Override + public int getAccessCodeLifespanUserAction() { + if (updated != null) return updated.getAccessCodeLifespanUserAction(); + return cached.getAccessCodeLifespanUserAction(); + } + + @Override + public void setAccessCodeLifespanUserAction(int seconds) { + getDelegateForUpdate(); + updated.setAccessCodeLifespanUserAction(seconds); + } + + @Override + public String getPublicKeyPem() { + if (updated != null) return updated.getPublicKeyPem(); + return cached.getPublicKeyPem(); + } + + @Override + public void setPublicKeyPem(String publicKeyPem) { + getDelegateForUpdate(); + updated.setPublicKeyPem(publicKeyPem); + } + + @Override + public String getPrivateKeyPem() { + if (updated != null) return updated.getPrivateKeyPem(); + return cached.getPrivateKeyPem(); + } + + @Override + public void setPrivateKeyPem(String privateKeyPem) { + getDelegateForUpdate(); + updated.setPrivateKeyPem(privateKeyPem); + } + + @Override + public PublicKey getPublicKey() { + if (publicKey != null) return publicKey; + publicKey = KeycloakModelUtils.getPublicKey(getPublicKeyPem()); + return publicKey; + } + + @Override + public void setPublicKey(PublicKey publicKey) { + this.publicKey = publicKey; + String publicKeyPem = KeycloakModelUtils.getPemFromKey(publicKey); + setPublicKeyPem(publicKeyPem); + } + + @Override + public PrivateKey getPrivateKey() { + if (privateKey != null) return privateKey; + privateKey = KeycloakModelUtils.getPrivateKey(getPrivateKeyPem()); + return privateKey; + } + + @Override + public void setPrivateKey(PrivateKey privateKey) { + this.privateKey = privateKey; + String privateKeyPem = KeycloakModelUtils.getPemFromKey(privateKey); + setPrivateKeyPem(privateKeyPem); + } + + @Override + public List getRequiredCredentials() { + + List copy = new LinkedList(); + if (updated != null) copy.addAll(updated.getRequiredCredentials()); + else copy.addAll(cached.getRequiredCredentials()); + return copy; + } + + @Override + public void addRequiredCredential(String cred) { + getDelegateForUpdate(); + updated.addRequiredCredential(cred); + } + + @Override + public PasswordPolicy getPasswordPolicy() { + if (updated != null) return updated.getPasswordPolicy(); + return cached.getPasswordPolicy(); + } + + @Override + public void setPasswordPolicy(PasswordPolicy policy) { + getDelegateForUpdate(); + updated.setPasswordPolicy(policy); + } + + @Override + public boolean validatePassword(UserModel user, String password) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean validateTOTP(UserModel user, String password, String token) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UserModel getUser(String name) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UserModel getUserByEmail(String email) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UserModel getUserById(String name) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UserModel addUser(String id, String username) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UserModel addUser(String username) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean removeUser(String name) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public RoleModel getRoleById(String id) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List getDefaultRoles() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void addDefaultRole(String name) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void updateDefaultRoles(String[] defaultRoles) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public ClientModel findClient(String clientId) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Map getApplicationNameMap() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List getApplications() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public ApplicationModel addApplication(String name) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public ApplicationModel addApplication(String id, String name) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean removeApplication(String id) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public ApplicationModel getApplicationById(String id) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public ApplicationModel getApplicationByName(String name) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void updateRequiredCredentials(Set creds) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UserModel getUserBySocialLink(SocialLinkModel socialLink) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Set getSocialLinks(UserModel user) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public SocialLinkModel getSocialLink(UserModel user, String socialProvider) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void addSocialLink(UserModel user, SocialLinkModel socialLink) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean removeSocialLink(UserModel user, String socialProvider) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public AuthenticationLinkModel getAuthenticationLink(UserModel user) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setAuthenticationLink(UserModel user, AuthenticationLinkModel authenticationLink) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean isSocial() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setSocial(boolean social) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean isUpdateProfileOnInitialSocialLogin() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UsernameLoginFailureModel getUserLoginFailure(String username) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UsernameLoginFailureModel addUserLoginFailure(String username) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List getAllUserLoginFailures() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List getUsers() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List searchForUser(String search) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List searchForUserByAttributes(Map attributes) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public OAuthClientModel addOAuthClient(String name) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public OAuthClientModel addOAuthClient(String id, String name) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public OAuthClientModel getOAuthClient(String name) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public OAuthClientModel getOAuthClientById(String id) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean removeOAuthClient(String id) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List getOAuthClients() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Map getSmtpConfig() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setSmtpConfig(Map smtpConfig) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Map getSocialConfig() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setSocialConfig(Map socialConfig) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Map getLdapServerConfig() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setLdapServerConfig(Map ldapServerConfig) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List getAuthenticationProviders() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setAuthenticationProviders(List authenticationProviders) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Set getRealmRoleMappings(UserModel user) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Set getRealmScopeMappings(ClientModel client) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public String getLoginTheme() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setLoginTheme(String name) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public String getAccountTheme() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setAccountTheme(String name) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public String getAdminTheme() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setAdminTheme(String name) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public String getEmailTheme() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setEmailTheme(String name) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean hasScope(ClientModel client, RoleModel role) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public int getNotBefore() { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setNotBefore(int notBefore) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean removeRoleById(String id) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean isAuditEnabled() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setAuditEnabled(boolean enabled) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public long getAuditExpiration() { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setAuditExpiration(long expiration) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Set getAuditListeners() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setAuditListeners(Set listeners) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public ApplicationModel getMasterAdminApp() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void setMasterAdminApp(ApplicationModel app) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UserSessionModel createUserSession(UserModel user, String ipAddress) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public UserSessionModel getUserSession(String id) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List getUserSessions(UserModel user) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void removeUserSession(UserSessionModel session) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void removeUserSessions(UserModel user) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void removeExpiredUserSessions() { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public ClientModel findClientById(String id) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void removeUserSessions() { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public RoleModel getRole(String name) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public RoleModel addRole(String name) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public RoleModel addRole(String id, String name) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean removeRole(RoleModel role) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Set getRoles() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean hasRole(UserModel user, RoleModel role) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void grantRole(UserModel user, RoleModel role) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Set getRoleMappings(UserModel user) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void deleteRoleMapping(UserModel user, RoleModel role) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Set getScopeMappings(ClientModel client) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void addScopeMapping(ClientModel client, RoleModel role) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void deleteScopeMapping(ClientModel client, RoleModel role) { + //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java new file mode 100755 index 00000000000..1e7a17f68b8 --- /dev/null +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java @@ -0,0 +1,59 @@ +package org.keycloak.models.cache; + +import org.keycloak.Config; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.models.KeycloakTransaction; +import org.keycloak.models.RealmModel; +import org.keycloak.models.cache.entities.CachedRealm; +import org.keycloak.provider.ProviderSession; +import org.keycloak.provider.ProviderSessionFactory; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class SimpleCache implements KeycloakCache { + + protected ConcurrentHashMap realmCache = new ConcurrentHashMap(); + protected ConcurrentHashMap realmCacheByName = new ConcurrentHashMap(); + + @Override + public void clear() { + realmCache.clear(); + realmCacheByName.clear(); + } + + @Override + public CachedRealm getCachedRealm(String id) { + return realmCache.get(id); + } + + @Override + public void invalidateCachedRealm(CachedRealm realm) { + realmCache.remove(realm.getId()); + realmCacheByName.remove(realm.getName()); + } + + @Override + public void invalidateCachedRealmById(String id) { + CachedRealm cached = realmCache.remove(id); + if (cached != null) realmCacheByName.remove(cached.getName()); + } + + + @Override + public void addCachedRealm(CachedRealm realm) { + realmCache.put(realm.getId(), realm); + realmCache.put(realm.getName(), realm); + + } + + @Override + public CachedRealm getCachedRealmByName(String name) { + return realmCacheByName.get(name); + } +} diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java new file mode 100755 index 00000000000..10a89013315 --- /dev/null +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java @@ -0,0 +1,295 @@ +package org.keycloak.models.cache.entities; + +import org.keycloak.models.ApplicationModel; +import org.keycloak.models.AuthenticationLinkModel; +import org.keycloak.models.AuthenticationProviderModel; +import org.keycloak.models.ClientModel; +import org.keycloak.models.OAuthClientModel; +import org.keycloak.models.PasswordPolicy; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RequiredCredentialModel; +import org.keycloak.models.RoleModel; +import org.keycloak.models.SocialLinkModel; +import org.keycloak.models.UserCredentialModel; +import org.keycloak.models.UserCredentialValueModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.UserSessionModel; +import org.keycloak.models.UsernameLoginFailureModel; +import org.keycloak.models.entities.AuthenticationProviderEntity; +import org.keycloak.models.entities.RequiredCredentialEntity; + +import java.io.Serializable; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class CachedRealm { + + private String id; + private String name; + private boolean enabled; + private boolean sslNotRequired; + private boolean registrationAllowed; + private boolean rememberMe; + private boolean verifyEmail; + private boolean passwordCredentialGrantAllowed; + private boolean resetPasswordAllowed; + private boolean social; + private boolean updateProfileOnInitialSocialLogin; + //--- brute force settings + private boolean bruteForceProtected; + private int maxFailureWaitSeconds; + private int minimumQuickLoginWaitSeconds; + private int waitIncrementSeconds; + private long quickLoginCheckMilliSeconds; + private int maxDeltaTimeSeconds; + private int failureFactor; + //--- end brute force settings + + private int ssoSessionIdleTimeout; + private int ssoSessionMaxLifespan; + private int accessTokenLifespan; + private int accessCodeLifespan; + private int accessCodeLifespanUserAction; + private int notBefore; + private PasswordPolicy passwordPolicy; + + private String publicKeyPem; + private String privateKeyPem; + + private String loginTheme; + private String accountTheme; + private String adminTheme; + private String emailTheme; + + private List requiredCredentials = new ArrayList(); + private List authenticationProviders = new ArrayList(); + + private Map smtpConfig = new HashMap(); + private Map socialConfig = new HashMap(); + private Map ldapServerConfig = new HashMap(); + + private boolean auditEnabled; + private long auditExpiration; + private Set auditListeners = new HashSet(); + + public CachedRealm() { + } + + public CachedRealm(RealmModel model) { + id = model.getId(); + name = model.getName(); + enabled = model.isEnabled(); + sslNotRequired = model.isSslNotRequired(); + registrationAllowed = model.isRegistrationAllowed(); + rememberMe = model.isRememberMe(); + verifyEmail = model.isVerifyEmail(); + passwordCredentialGrantAllowed = model.isPasswordCredentialGrantAllowed(); + resetPasswordAllowed = model.isResetPasswordAllowed(); + social = model.isSocial(); + updateProfileOnInitialSocialLogin = model.isUpdateProfileOnInitialSocialLogin(); + //--- brute force settings + bruteForceProtected = model.isBruteForceProtected(); + maxFailureWaitSeconds = model.getMaxFailureWaitSeconds(); + minimumQuickLoginWaitSeconds = model.getMinimumQuickLoginWaitSeconds(); + waitIncrementSeconds = model.getWaitIncrementSeconds(); + quickLoginCheckMilliSeconds = model.getQuickLoginCheckMilliSeconds(); + maxDeltaTimeSeconds = model.getMaxDeltaTimeSeconds(); + failureFactor = model.getFailureFactor(); + //--- end brute force settings + + ssoSessionIdleTimeout = model.getSsoSessionIdleTimeout(); + ssoSessionMaxLifespan = model.getSsoSessionMaxLifespan(); + accessTokenLifespan = model.getAccessTokenLifespan(); + accessCodeLifespan = model.getAccessCodeLifespan(); + accessCodeLifespanUserAction = model.getAccessCodeLifespanUserAction(); + notBefore = model.getNotBefore(); + passwordPolicy = model.getPasswordPolicy(); + + publicKeyPem = model.getPublicKeyPem(); + privateKeyPem = model.getPrivateKeyPem(); + + loginTheme = model.getLoginTheme(); + accountTheme = model.getAccountTheme(); + adminTheme = model.getAdminTheme(); + emailTheme = model.getEmailTheme(); + + requiredCredentials = model.getRequiredCredentials(); + authenticationProviders = model.getAuthenticationProviders(); + + smtpConfig.putAll(model.getSmtpConfig()); + socialConfig.putAll(model.getSocialConfig()); + ldapServerConfig.putAll(model.getLdapServerConfig()); + + auditEnabled = model.isAuditEnabled(); + auditExpiration = model.getAuditExpiration(); + auditListeners.addAll(model.getAuditListeners()); + } + + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public boolean isEnabled() { + return enabled; + } + + public boolean isSslNotRequired() { + return sslNotRequired; + } + + public boolean isRegistrationAllowed() { + return registrationAllowed; + } + + public boolean isPasswordCredentialGrantAllowed() { + return passwordCredentialGrantAllowed; + } + + public boolean isRememberMe() { + return this.rememberMe; + } + + public boolean isBruteForceProtected() { + return bruteForceProtected; + } + + public int getMaxFailureWaitSeconds() { + return this.maxFailureWaitSeconds; + } + + public int getWaitIncrementSeconds() { + return this.waitIncrementSeconds; + } + + public int getMinimumQuickLoginWaitSeconds() { + return this.minimumQuickLoginWaitSeconds; + } + + public long getQuickLoginCheckMilliSeconds() { + return quickLoginCheckMilliSeconds; + } + + public int getMaxDeltaTimeSeconds() { + return maxDeltaTimeSeconds; + } + + public int getFailureFactor() { + return failureFactor; + } + + public boolean isVerifyEmail() { + return verifyEmail; + } + + public boolean isResetPasswordAllowed() { + return resetPasswordAllowed; + } + + public int getSsoSessionIdleTimeout() { + return ssoSessionIdleTimeout; + } + + public int getSsoSessionMaxLifespan() { + return ssoSessionMaxLifespan; + } + + public int getAccessTokenLifespan() { + return accessTokenLifespan; + } + + public int getAccessCodeLifespan() { + return accessCodeLifespan; + } + + public int getAccessCodeLifespanUserAction() { + return accessCodeLifespanUserAction; + } + + public String getPublicKeyPem() { + return publicKeyPem; + } + + public String getPrivateKeyPem() { + return privateKeyPem; + } + + public List getRequiredCredentials() { + return requiredCredentials; + } + + public PasswordPolicy getPasswordPolicy() { + return passwordPolicy; + } + + public boolean isSocial() { + return social; + } + + public boolean isUpdateProfileOnInitialSocialLogin() { + return updateProfileOnInitialSocialLogin; + } + + public Map getSmtpConfig() { + return smtpConfig; + } + + public Map getSocialConfig() { + return socialConfig; + } + + public Map getLdapServerConfig() { + return ldapServerConfig; + } + + public List getAuthenticationProviders() { + return authenticationProviders; + } + + public String getLoginTheme() { + return loginTheme; + } + + public String getAccountTheme() { + return accountTheme; + } + + public String getAdminTheme() { + return this.adminTheme; + } + + public String getEmailTheme() { + return emailTheme; + } + + public int getNotBefore() { + return notBefore; + } + + public boolean isAuditEnabled() { + return auditEnabled; + } + + public long getAuditExpiration() { + return auditExpiration; + } + + public Set getAuditListeners() { + return auditListeners; + } + +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java index 36aabd6a15e..98b0745c4b5 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java @@ -72,6 +72,38 @@ public class JpaKeycloakSession implements KeycloakSession { return new RealmAdapter(em, realm); } + @Override + public UserModel getUserById(String id, String realmId) { + TypedQuery query = em.createNamedQuery("getRealmUserById", UserEntity.class); + query.setParameter("id", id); + RealmEntity realm = em.getReference(RealmEntity.class, realmId); + query.setParameter("realm", realm); + List entities = query.getResultList(); + if (entities.size() == 0) return null; + return new UserAdapter(em, entities.get(0)); + } + + @Override + public UserModel getUserByUsername(String username, String realmId) { + TypedQuery query = em.createNamedQuery("getRealmUserByLoginName", UserEntity.class); + query.setParameter("loginName", username); + RealmEntity realm = em.getReference(RealmEntity.class, realmId); + query.setParameter("realm", realm); + List results = query.getResultList(); + if (results.size() == 0) return null; + return new UserAdapter(em, results.get(0)); + } + + @Override + public UserModel getUserByEmail(String email, String realmId) { + TypedQuery query = em.createNamedQuery("getRealmUserByEmail", UserEntity.class); + query.setParameter("email", email); + RealmEntity realm = em.getReference(RealmEntity.class, realmId); + query.setParameter("realm", realm); + List results = query.getResultList(); + return results.isEmpty() ? null : new UserAdapter(em, results.get(0)); + } + @Override public boolean removeRealm(String id) { RealmEntity realm = em.find(RealmEntity.class, id); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java index 1c4cae0d631..5af777d589c 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java @@ -429,7 +429,7 @@ public class RealmAdapter implements RealmModel { query.setParameter("realm", realm); List results = query.getResultList(); if (results.size() == 0) return null; - return new UserAdapter(results.get(0)); + return new UserAdapter(em, results.get(0)); } @Override @@ -470,7 +470,7 @@ public class RealmAdapter implements RealmModel { query.setParameter("email", email); query.setParameter("realm", realm); List results = query.getResultList(); - return results.isEmpty() ? null : new UserAdapter(results.get(0)); + return results.isEmpty() ? null : new UserAdapter(em, results.get(0)); } @Override @@ -479,7 +479,7 @@ public class RealmAdapter implements RealmModel { // Check if user belongs to this realm if (entity == null || !this.realm.equals(entity.getRealm())) return null; - return new UserAdapter(entity); + return new UserAdapter(em, entity); } @Override @@ -495,7 +495,7 @@ public class RealmAdapter implements RealmModel { entity.setRealm(realm); em.persist(entity); em.flush(); - UserModel userModel = new UserAdapter(entity); + UserModel userModel = new UserAdapter(em, entity); for (String r : getDefaultRoles()) { grantRole(userModel, getRole(r)); @@ -706,7 +706,7 @@ public class RealmAdapter implements RealmModel { ", socialUserId=" + socialLink.getSocialUserId() + ", results=" + results); } else { UserEntity user = results.get(0); - return new UserAdapter(user); + return new UserAdapter(em, user); } } @@ -808,7 +808,7 @@ public class RealmAdapter implements RealmModel { query.setParameter("realm", realm); List results = query.getResultList(); List users = new ArrayList(); - for (UserEntity entity : results) users.add(new UserAdapter(entity)); + for (UserEntity entity : results) users.add(new UserAdapter(em, entity)); return users; } @@ -819,7 +819,7 @@ public class RealmAdapter implements RealmModel { query.setParameter("search", "%" + search.toLowerCase() + "%"); List results = query.getResultList(); List users = new ArrayList(); - for (UserEntity entity : results) users.add(new UserAdapter(entity)); + for (UserEntity entity : results) users.add(new UserAdapter(em, entity)); return users; } @@ -851,7 +851,7 @@ public class RealmAdapter implements RealmModel { TypedQuery query = em.createQuery(q, UserEntity.class); List results = query.getResultList(); List users = new ArrayList(); - for (UserEntity entity : results) users.add(new UserAdapter(entity)); + for (UserEntity entity : results) users.add(new UserAdapter(em, entity)); return users; } @@ -1218,9 +1218,10 @@ public class RealmAdapter implements RealmModel { @Override public boolean validatePassword(UserModel user, String password) { - for (CredentialEntity cred : ((UserAdapter) user).getUser().getCredentials()) { + for (UserCredentialValueModel cred : user.getCredentialsDirectly()) { if (cred.getType().equals(UserCredentialModel.PASSWORD)) { return new Pbkdf2PasswordEncoder(cred.getSalt()).verify(password, cred.getValue()); + } } return false; @@ -1229,7 +1230,7 @@ public class RealmAdapter implements RealmModel { @Override public boolean validateTOTP(UserModel user, String password, String token) { if (!validatePassword(user, password)) return false; - for (CredentialEntity cred : ((UserAdapter) user).getUser().getCredentials()) { + for (UserCredentialValueModel cred : user.getCredentialsDirectly()) { if (cred.getType().equals(UserCredentialModel.TOTP)) { return new TimeBasedOTP().validate(token, cred.getValue().getBytes()); } @@ -1237,81 +1238,6 @@ public class RealmAdapter implements RealmModel { return false; } - @Override - public void updateCredential(UserModel user, UserCredentialModel cred) { - UserEntity userEntity = ((UserAdapter) user).getUser(); - CredentialEntity credentialEntity = getCredentialEntity(userEntity, cred.getType()); - - if (credentialEntity == null) { - credentialEntity = new CredentialEntity(); - credentialEntity.setType(cred.getType()); - credentialEntity.setDevice(cred.getDevice()); - credentialEntity.setUser(userEntity); - em.persist(credentialEntity); - userEntity.getCredentials().add(credentialEntity); - } - if (cred.getType().equals(UserCredentialModel.PASSWORD)) { - byte[] salt = getSalt(); - credentialEntity.setValue(new Pbkdf2PasswordEncoder(salt).encode(cred.getValue())); - credentialEntity.setSalt(salt); - } else { - credentialEntity.setValue(cred.getValue()); - } - credentialEntity.setDevice(cred.getDevice()); - em.flush(); - } - - private CredentialEntity getCredentialEntity(UserEntity userEntity, String credType) { - for (CredentialEntity entity : userEntity.getCredentials()) { - if (entity.getType().equals(credType)) { - return entity; - } - } - - return null; - } - - @Override - public List getCredentialsDirectly(UserModel user) { - UserEntity userEntity = ((UserAdapter) user).getUser(); - List credentials = new ArrayList(userEntity.getCredentials()); - List result = new ArrayList(); - - if (credentials != null) { - for (CredentialEntity credEntity : credentials) { - UserCredentialValueModel credModel = new UserCredentialValueModel(); - credModel.setType(credEntity.getType()); - credModel.setDevice(credEntity.getDevice()); - credModel.setValue(credEntity.getValue()); - credModel.setSalt(credEntity.getSalt()); - - result.add(credModel); - } - } - - return result; - } - - @Override - public void updateCredentialDirectly(UserModel user, UserCredentialValueModel credModel) { - UserEntity userEntity = ((UserAdapter) user).getUser(); - CredentialEntity credentialEntity = getCredentialEntity(userEntity, credModel.getType()); - - if (credentialEntity == null) { - credentialEntity = new CredentialEntity(); - credentialEntity.setType(credModel.getType()); - credentialEntity.setUser(userEntity); - em.persist(credentialEntity); - userEntity.getCredentials().add(credentialEntity); - } - - credentialEntity.setValue(credModel.getValue()); - credentialEntity.setSalt(credModel.getSalt()); - credentialEntity.setDevice(credModel.getDevice()); - - em.flush(); - } - @Override public PasswordPolicy getPasswordPolicy() { if (passwordPolicy == null) { diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java index 98570625c9e..1683cfd2bf8 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java @@ -1,13 +1,22 @@ package org.keycloak.models.jpa; +import org.keycloak.models.UserCredentialModel; +import org.keycloak.models.UserCredentialValueModel; import org.keycloak.models.UserModel; +import org.keycloak.models.jpa.entities.CredentialEntity; import org.keycloak.models.jpa.entities.UserEntity; +import org.keycloak.models.utils.Pbkdf2PasswordEncoder; +import javax.persistence.EntityManager; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; +import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt; + /** * @author Bill Burke * @version $Revision: 1 $ @@ -15,8 +24,10 @@ import java.util.Set; public class UserAdapter implements UserModel { protected UserEntity user; + protected EntityManager em; - public UserAdapter(UserEntity user) { + public UserAdapter(EntityManager em, UserEntity user) { + this.em = em; this.user = user; } @@ -160,6 +171,78 @@ public class UserAdapter implements UserModel { user.setNotBefore(notBefore); } + @Override + public void updateCredential(UserCredentialModel cred) { + CredentialEntity credentialEntity = getCredentialEntity(user, cred.getType()); + + if (credentialEntity == null) { + credentialEntity = new CredentialEntity(); + credentialEntity.setType(cred.getType()); + credentialEntity.setDevice(cred.getDevice()); + credentialEntity.setUser(user); + em.persist(credentialEntity); + user.getCredentials().add(credentialEntity); + } + if (cred.getType().equals(UserCredentialModel.PASSWORD)) { + byte[] salt = getSalt(); + credentialEntity.setValue(new Pbkdf2PasswordEncoder(salt).encode(cred.getValue())); + credentialEntity.setSalt(salt); + } else { + credentialEntity.setValue(cred.getValue()); + } + credentialEntity.setDevice(cred.getDevice()); + em.flush(); + } + + private CredentialEntity getCredentialEntity(UserEntity userEntity, String credType) { + for (CredentialEntity entity : userEntity.getCredentials()) { + if (entity.getType().equals(credType)) { + return entity; + } + } + + return null; + } + + @Override + public List getCredentialsDirectly() { + List credentials = new ArrayList(user.getCredentials()); + List result = new ArrayList(); + + if (credentials != null) { + for (CredentialEntity credEntity : credentials) { + UserCredentialValueModel credModel = new UserCredentialValueModel(); + credModel.setType(credEntity.getType()); + credModel.setDevice(credEntity.getDevice()); + credModel.setValue(credEntity.getValue()); + credModel.setSalt(credEntity.getSalt()); + + result.add(credModel); + } + } + + return result; + } + + @Override + public void updateCredentialDirectly(UserCredentialValueModel credModel) { + CredentialEntity credentialEntity = getCredentialEntity(user, credModel.getType()); + + if (credentialEntity == null) { + credentialEntity = new CredentialEntity(); + credentialEntity.setType(credModel.getType()); + credentialEntity.setUser(user); + em.persist(credentialEntity); + user.getCredentials().add(credentialEntity); + } + + credentialEntity.setValue(credModel.getValue()); + credentialEntity.setSalt(credModel.getSalt()); + credentialEntity.setDevice(credModel.getDevice()); + + em.flush(); + } + } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java index f51ed9435d1..39d03a43b93 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java @@ -32,6 +32,7 @@ import java.util.Set; * @version $Revision: 1 $ */ @NamedQueries({ + @NamedQuery(name="getRealmUserById", query="select u from UserEntity u where u.id = :id and u.realm = :realm"), @NamedQuery(name="getRealmUserByLoginName", query="select u from UserEntity u where u.loginName = :loginName and u.realm = :realm"), @NamedQuery(name="getRealmUserByEmail", query="select u from UserEntity u where u.email = :email and u.realm = :realm"), @NamedQuery(name="getRealmUserByLastName", query="select u from UserEntity u where u.lastName = :lastName and u.realm = :realm"), diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java index 0c13eb9c8e6..d16cdcb4722 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java @@ -6,10 +6,12 @@ import com.mongodb.QueryBuilder; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakTransaction; import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; import org.keycloak.models.mongo.api.MongoStore; import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext; import org.keycloak.models.mongo.impl.context.TransactionMongoStoreInvocationContext; import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity; +import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity; import org.keycloak.models.utils.KeycloakModelUtils; import java.util.ArrayList; @@ -89,6 +91,48 @@ public class MongoKeycloakSession implements KeycloakSession { return new RealmAdapter(realm, invocationContext); } + @Override + public UserModel getUserById(String id, String realmId) { + MongoUserEntity user = getMongoStore().loadEntity(MongoUserEntity.class, id, invocationContext); + + // Check that it's user from this realm + if (user == null || !realmId.equals(user.getRealmId())) { + return null; + } else { + return new UserAdapter(user, invocationContext); + } + } + + @Override + public UserModel getUserByUsername(String username, String realmId) { + DBObject query = new QueryBuilder() + .and("loginName").is(username) + .and("realmId").is(realmId) + .get(); + MongoUserEntity user = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext); + + if (user == null) { + return null; + } else { + return new UserAdapter(user, invocationContext); + } + } + + @Override + public UserModel getUserByEmail(String email, String realmId) { + DBObject query = new QueryBuilder() + .and("email").is(email) + .and("realmId").is(realmId) + .get(); + MongoUserEntity user = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext); + + if (user == null) { + return null; + } else { + return new UserAdapter(user, invocationContext); + } + } + @Override public boolean removeRealm(String id) { return getMongoStore().removeEntity(MongoRealmEntity.class, id, invocationContext); diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java index da20338ebc2..8a1d112a43c 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java @@ -994,7 +994,7 @@ public class RealmAdapter extends AbstractMongoAdapter impleme @Override public boolean validatePassword(UserModel user, String password) { - for (CredentialEntity cred : ((UserAdapter) user).getUser().getCredentials()) { + for (UserCredentialValueModel cred : user.getCredentialsDirectly()) { if (cred.getType().equals(UserCredentialModel.PASSWORD)) { return new Pbkdf2PasswordEncoder(cred.getSalt()).verify(password, cred.getValue()); } @@ -1005,7 +1005,7 @@ public class RealmAdapter extends AbstractMongoAdapter impleme @Override public boolean validateTOTP(UserModel user, String password, String token) { if (!validatePassword(user, password)) return false; - for (CredentialEntity cred : ((UserAdapter) user).getUser().getCredentials()) { + for (UserCredentialValueModel cred : user.getCredentialsDirectly()) { if (cred.getType().equals(UserCredentialModel.TOTP)) { return new TimeBasedOTP().validate(token, cred.getValue().getBytes()); } @@ -1014,74 +1014,7 @@ public class RealmAdapter extends AbstractMongoAdapter impleme } - @Override - public void updateCredential(UserModel user, UserCredentialModel cred) { - MongoUserEntity userEntity = ((UserAdapter) user).getUser(); - CredentialEntity credentialEntity = getCredentialEntity(userEntity, cred.getType()); - if (credentialEntity == null) { - credentialEntity = new CredentialEntity(); - credentialEntity.setType(cred.getType()); - credentialEntity.setDevice(cred.getDevice()); - userEntity.getCredentials().add(credentialEntity); - } - if (cred.getType().equals(UserCredentialModel.PASSWORD)) { - byte[] salt = Pbkdf2PasswordEncoder.getSalt(); - credentialEntity.setValue(new Pbkdf2PasswordEncoder(salt).encode(cred.getValue())); - credentialEntity.setSalt(salt); - } else { - credentialEntity.setValue(cred.getValue()); - } - credentialEntity.setDevice(cred.getDevice()); - - getMongoStore().updateEntity(userEntity, invocationContext); - } - - private CredentialEntity getCredentialEntity(MongoUserEntity userEntity, String credType) { - for (CredentialEntity entity : userEntity.getCredentials()) { - if (entity.getType().equals(credType)) { - return entity; - } - } - - return null; - } - - @Override - public List getCredentialsDirectly(UserModel user) { - MongoUserEntity userEntity = ((UserAdapter) user).getUser(); - List credentials = userEntity.getCredentials(); - List result = new ArrayList(); - for (CredentialEntity credEntity : credentials) { - UserCredentialValueModel credModel = new UserCredentialValueModel(); - credModel.setType(credEntity.getType()); - credModel.setDevice(credEntity.getDevice()); - credModel.setValue(credEntity.getValue()); - credModel.setSalt(credEntity.getSalt()); - - result.add(credModel); - } - - return result; - } - - @Override - public void updateCredentialDirectly(UserModel user, UserCredentialValueModel credModel) { - MongoUserEntity userEntity = ((UserAdapter) user).getUser(); - CredentialEntity credentialEntity = getCredentialEntity(userEntity, credModel.getType()); - - if (credentialEntity == null) { - credentialEntity = new CredentialEntity(); - credentialEntity.setType(credModel.getType()); - userEntity.getCredentials().add(credentialEntity); - } - - credentialEntity.setValue(credModel.getValue()); - credentialEntity.setSalt(credModel.getSalt()); - credentialEntity.setDevice(credModel.getDevice()); - - getMongoStore().updateEntity(userEntity, invocationContext); - } @Override public UserModel getUserBySocialLink(SocialLinkModel socialLink) { diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java index c713b9f3911..7cc178b7485 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java @@ -1,12 +1,18 @@ package org.keycloak.models.mongo.keycloak.adapters; +import org.keycloak.models.UserCredentialModel; +import org.keycloak.models.UserCredentialValueModel; import org.keycloak.models.UserModel; +import org.keycloak.models.entities.CredentialEntity; import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext; import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity; +import org.keycloak.models.utils.Pbkdf2PasswordEncoder; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -168,6 +174,72 @@ public class UserAdapter extends AbstractMongoAdapter implement updateUser(); } + @Override + public void updateCredential(UserCredentialModel cred) { + CredentialEntity credentialEntity = getCredentialEntity(user, cred.getType()); + + if (credentialEntity == null) { + credentialEntity = new CredentialEntity(); + credentialEntity.setType(cred.getType()); + credentialEntity.setDevice(cred.getDevice()); + user.getCredentials().add(credentialEntity); + } + if (cred.getType().equals(UserCredentialModel.PASSWORD)) { + byte[] salt = Pbkdf2PasswordEncoder.getSalt(); + credentialEntity.setValue(new Pbkdf2PasswordEncoder(salt).encode(cred.getValue())); + credentialEntity.setSalt(salt); + } else { + credentialEntity.setValue(cred.getValue()); + } + credentialEntity.setDevice(cred.getDevice()); + + getMongoStore().updateEntity(user, invocationContext); + } + + private CredentialEntity getCredentialEntity(MongoUserEntity userEntity, String credType) { + for (CredentialEntity entity : userEntity.getCredentials()) { + if (entity.getType().equals(credType)) { + return entity; + } + } + + return null; + } + + @Override + public List getCredentialsDirectly() { + List credentials = user.getCredentials(); + List result = new ArrayList(); + for (CredentialEntity credEntity : credentials) { + UserCredentialValueModel credModel = new UserCredentialValueModel(); + credModel.setType(credEntity.getType()); + credModel.setDevice(credEntity.getDevice()); + credModel.setValue(credEntity.getValue()); + credModel.setSalt(credEntity.getSalt()); + + result.add(credModel); + } + + return result; + } + + @Override + public void updateCredentialDirectly(UserCredentialValueModel credModel) { + CredentialEntity credentialEntity = getCredentialEntity(user, credModel.getType()); + + if (credentialEntity == null) { + credentialEntity = new CredentialEntity(); + credentialEntity.setType(credModel.getType()); + user.getCredentials().add(credentialEntity); + } + + credentialEntity.setValue(credModel.getValue()); + credentialEntity.setSalt(credModel.getSalt()); + credentialEntity.setDevice(credModel.getDevice()); + + getMongoStore().updateEntity(user, invocationContext); + } + protected void updateUser() { super.updateMongoEntity(); } diff --git a/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java b/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java index 84d4586d89b..d6d5e7bd19b 100755 --- a/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java +++ b/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java @@ -133,7 +133,7 @@ public class AdapterTest extends AbstractModelTest { UserCredentialModel cred = new UserCredentialModel(); cred.setType(CredentialRepresentation.PASSWORD); cred.setValue("geheim"); - realmModel.updateCredential(user, cred); + user.updateCredential(cred); Assert.assertTrue(realmModel.validatePassword(user, "geheim")); } @@ -166,7 +166,7 @@ public class AdapterTest extends AbstractModelTest { UserCredentialModel cred = new UserCredentialModel(); cred.setType(CredentialRepresentation.PASSWORD); cred.setValue("password"); - realmModel.updateCredential(user, cred); + user.updateCredential(cred); commit(); @@ -208,7 +208,7 @@ public class AdapterTest extends AbstractModelTest { UserCredentialModel cred = new UserCredentialModel(); cred.setType(CredentialRepresentation.PASSWORD); cred.setValue("password"); - realmModel.updateCredential(user, cred); + user.updateCredential(cred); OAuthClientModel client = realmModel.addOAuthClient("client"); diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java index 5d28b602826..961b6740dcb 100755 --- a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java +++ b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java @@ -63,7 +63,7 @@ public class AuthProvidersExternalModelTest extends AbstractModelTest { UserCredentialModel credential = new UserCredentialModel(); credential.setType(CredentialRepresentation.PASSWORD); credential.setValue("password"); - realm1.updateCredential(john, credential); + john.updateCredential(credential); am = new AuthenticationManager(providerSession); } diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java index 24317a8c51a..083a967c70e 100755 --- a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java +++ b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java @@ -112,7 +112,7 @@ public class AuthProvidersLDAPTest extends AbstractModelTest { UserCredentialModel credential = new UserCredentialModel(); credential.setType(CredentialRepresentation.PASSWORD); credential.setValue("pass"); - realm.updateCredential(realmUser, credential); + realmUser.updateCredential(credential); // User doesn't exists MultivaluedMap formData = AuthProvidersExternalModelTest.createFormData("invalid", "invalid"); diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java index a603226fdb8..24e894fc3de 100755 --- a/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java +++ b/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java @@ -107,7 +107,7 @@ public class AuthenticationManagerTest extends AbstractModelTest { credential.setType(CredentialRepresentation.TOTP); credential.setValue(totpSecret); - realm.updateCredential(user, credential); + user.updateCredential(credential); user.setTotp(true); @@ -175,7 +175,7 @@ public class AuthenticationManagerTest extends AbstractModelTest { credential.setType(CredentialRepresentation.PASSWORD); credential.setValue("password"); - realm.updateCredential(user, credential); + user.updateCredential(credential); formData = new MultivaluedMapImpl(); formData.add("username", "test"); diff --git a/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java b/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java index 35a09814f2f..26dff19e966 100755 --- a/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java +++ b/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java @@ -37,8 +37,8 @@ public class MultipleRealmsTest extends AbstractModelTest { Assert.assertNotEquals(r1user1.getId(), r2user1.getId()); // Test password - realm1.updateCredential(r1user1, UserCredentialModel.password("pass1")); - realm2.updateCredential(r2user1, UserCredentialModel.password("pass2")); + r1user1.updateCredential(UserCredentialModel.password("pass1")); + r2user1.updateCredential(UserCredentialModel.password("pass2")); Assert.assertTrue(realm1.validatePassword(r1user1, "pass1")); Assert.assertFalse(realm1.validatePassword(r1user1, "pass2")); diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java index 653cdc6f932..121dec70185 100755 --- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java +++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java @@ -71,7 +71,7 @@ public class ApplianceBootstrap { UserCredentialModel password = new UserCredentialModel(); password.setType(UserCredentialModel.PASSWORD); password.setValue("admin"); - realm.updateCredential(adminUser, password); + adminUser.updateCredential(password); adminUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); RoleModel adminRole = realm.getRole(AdminRoles.ADMIN); diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java index c897d779725..73634cf052a 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -569,7 +569,7 @@ public class RealmManager { if (userRep.getCredentials() != null) { for (CredentialRepresentation cred : userRep.getCredentials()) { UserCredentialModel credential = fromRepresentation(cred); - newRealm.updateCredential(user, credential); + user.updateCredential(credential); } } if (userRep.getAuthenticationLink() != null) { diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java index a9ee7748f3e..3ba8d1627bf 100755 --- a/services/src/main/java/org/keycloak/services/resources/AccountService.java +++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java @@ -402,7 +402,7 @@ public class AccountService { UserCredentialModel credentials = new UserCredentialModel(); credentials.setType(CredentialRepresentation.TOTP); credentials.setValue(totpSecret); - realm.updateCredential(user, credentials); + user.updateCredential(credentials); user.setTotp(true); diff --git a/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java b/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java index 335b10bce38..7132d6e59cc 100755 --- a/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java @@ -171,7 +171,7 @@ public class RequiredActionsService { UserCredentialModel credentials = new UserCredentialModel(); credentials.setType(CredentialRepresentation.TOTP); credentials.setValue(totpSecret); - realm.updateCredential(user, credentials); + user.updateCredential(credentials); user.setTotp(true); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java index 8297e7fcb2c..f26c8d77cf9 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java @@ -766,7 +766,7 @@ public class UsersResource { } UserCredentialModel cred = RealmManager.fromRepresentation(pass); - realm.updateCredential(user, cred); + user.updateCredential(cred); user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); } diff --git a/testsuite/integration/src/main/resources/log4j.properties b/testsuite/integration/src/main/resources/log4j.properties index bc2777323a4..5700df4ae3e 100755 --- a/testsuite/integration/src/main/resources/log4j.properties +++ b/testsuite/integration/src/main/resources/log4j.properties @@ -4,4 +4,4 @@ log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n -log4j.logger.org.keycloak=debug \ No newline at end of file +log4j.logger.org.keycloak=warn \ No newline at end of file diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java index 7bec7a7b74b..359b287c0f5 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java @@ -87,7 +87,7 @@ public class AccountTest { UserCredentialModel creds = new UserCredentialModel(); creds.setType(CredentialRepresentation.PASSWORD); creds.setValue("password"); - appRealm.updateCredential(user2, creds); + user2.updateCredential(creds); } }); @@ -153,7 +153,7 @@ public class AccountTest { cred.setType(CredentialRepresentation.PASSWORD); cred.setValue("password"); - appRealm.updateCredential(user, cred); + user.updateCredential(cred); } }); } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java index eee56e0c6e4..cf86b183b73 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java @@ -64,7 +64,7 @@ public class ProfileTest { UserCredentialModel creds = new UserCredentialModel(); creds.setType(CredentialRepresentation.PASSWORD); creds.setValue("password"); - appRealm.updateCredential(user2, creds); + user2.updateCredential(creds); ApplicationModel app = appRealm.getApplicationNameMap().get("test-app"); appRealm.addScopeMapping(app, accountApp.getRole(AccountRoles.VIEW_PROFILE)); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java index c354f0dd8b4..fb296133f0b 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java @@ -77,12 +77,12 @@ public class CompositeRoleTest { final UserModel realmComposite1User = realm.addUser("REALM_COMPOSITE_1_USER"); realmComposite1User.setEnabled(true); - realm.updateCredential(realmComposite1User, UserCredentialModel.password("password")); + realmComposite1User.updateCredential(UserCredentialModel.password("password")); realm.grantRole(realmComposite1User, realmComposite1); final UserModel realmRole1User = realm.addUser("REALM_ROLE_1_USER"); realmRole1User.setEnabled(true); - realm.updateCredential(realmRole1User, UserCredentialModel.password("password")); + realmRole1User.updateCredential(UserCredentialModel.password("password")); realm.grantRole(realmRole1User, realmRole1); final ApplicationModel realmComposite1Application = new ApplicationManager(manager).createApplication(realm, "REALM_COMPOSITE_1_APPLICATION"); @@ -116,12 +116,12 @@ public class CompositeRoleTest { final UserModel realmAppCompositeUser = realm.addUser("REALM_APP_COMPOSITE_USER"); realmAppCompositeUser.setEnabled(true); - realm.updateCredential(realmAppCompositeUser, UserCredentialModel.password("password")); + realmAppCompositeUser.updateCredential(UserCredentialModel.password("password")); realm.grantRole(realmAppCompositeUser, realmAppCompositeRole); final UserModel realmAppRoleUser = realm.addUser("REALM_APP_ROLE_USER"); realmAppRoleUser.setEnabled(true); - realm.updateCredential(realmAppRoleUser, UserCredentialModel.password("password")); + realmAppRoleUser.updateCredential(UserCredentialModel.password("password")); realm.grantRole(realmAppRoleUser, appRole2); final ApplicationModel appCompositeApplication = new ApplicationManager(manager).createApplication(realm, "APP_COMPOSITE_APPLICATION"); @@ -139,7 +139,7 @@ public class CompositeRoleTest { final UserModel appCompositeUser = realm.addUser("APP_COMPOSITE_USER"); appCompositeUser.setEnabled(true); - realm.updateCredential(appCompositeUser, UserCredentialModel.password("password")); + appCompositeUser.updateCredential(UserCredentialModel.password("password")); realm.grantRole(appCompositeUser, realmAppCompositeRole); realm.grantRole(appCompositeUser, realmComposite1); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java index cd367c9bbae..1ad65e44ee0 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java @@ -104,7 +104,7 @@ public class AuthProvidersIntegrationTest { creds.setType(CredentialRepresentation.PASSWORD); creds.setValue(password); - realm.updateCredential(user, creds); + user.updateCredential(creds); return user; } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java old mode 100644 new mode 100755 index af561d14c84..277bc7a64bb --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java @@ -61,7 +61,7 @@ public class LoginTest { creds.setType(CredentialRepresentation.PASSWORD); creds.setValue("password"); - appRealm.updateCredential(user, creds); + user.updateCredential(creds); } }); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java index 15710b17cf9..eadf367337e 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java @@ -63,7 +63,7 @@ public class LoginTotpTest { UserCredentialModel credentials = new UserCredentialModel(); credentials.setType(CredentialRepresentation.TOTP); credentials.setValue("totpSecret"); - appRealm.updateCredential(user, credentials); + user.updateCredential(credentials); user.setTotp(true); appRealm.setAuditListeners(Collections.singleton("dummy")); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java index ae5cfce6d9a..0946727728d 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java @@ -72,7 +72,7 @@ public class ResetPasswordTest { creds.setType(CredentialRepresentation.PASSWORD); creds.setValue("password"); - appRealm.updateCredential(user, creds); + user.updateCredential(creds); appRealm.setAuditListeners(Collections.singleton("dummy")); } })); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java index f0b93180a7f..c5d3a02aff8 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java @@ -22,14 +22,20 @@ package org.keycloak.testsuite.perf; import org.apache.http.NameValuePair; +import org.apache.http.client.CookieStore; +import org.apache.http.client.HttpClient; import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.cookie.Cookie; +import org.apache.http.impl.client.DefaultHttpClient; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; +import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine; import org.junit.Assert; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.keycloak.OAuth2Constants; +import org.keycloak.adapters.HttpClientBuilder; import org.keycloak.audit.Details; import org.keycloak.audit.Errors; import org.keycloak.audit.Event; @@ -53,6 +59,8 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import java.net.URI; +import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -72,15 +80,22 @@ public class AccessTokenPerfTest { public static class BrowserLogin implements Runnable { + + private WebDriver driver; + + public BrowserLogin() { + driver = WebRule.createWebDriver(); + } + @Override public void run() { - WebDriver driver = WebRule.createWebDriver(); + driver.manage().deleteAllCookies(); OAuthClient oauth = new OAuthClient(driver); oauth.doLogin("test-user@localhost", "password"); String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password"); Assert.assertEquals(200, response.getStatusCode()); - driver.close(); + count.incrementAndGet(); } } @@ -105,7 +120,30 @@ public class AccessTokenPerfTest { public JaxrsClientLogin() { - this.client = new ResteasyClientBuilder().build(); + DefaultHttpClient httpClient = (DefaultHttpClient) new HttpClientBuilder().build(); + httpClient.setCookieStore(new CookieStore() { + @Override + public void addCookie(Cookie cookie) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List getCookies() { + return Collections.emptyList(); + } + + @Override + public boolean clearExpired(Date date) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void clear() { + //To change body of implemented methods use File | Settings | File Templates. + } + }); + ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient); + this.client = new ResteasyClientBuilder().httpEngine(engine).build(); } public String getLoginFormUrl(String state) { @@ -142,7 +180,7 @@ public class AccessTokenPerfTest { @Override public void run() { - this.client = new ResteasyClientBuilder().build(); + //this.client = new ResteasyClientBuilder().build(); String state = "42"; Response response = client.target(getLoginFormUrl(state)).request().get(); URI uri = null; @@ -173,7 +211,7 @@ public class AccessTokenPerfTest { .header(HttpHeaders.AUTHORIZATION, authorization) .post(Entity.form(form), String.class); count.incrementAndGet(); - client.close(); + //client.close(); } public String getCode(URI uri) { @@ -196,7 +234,7 @@ public class AccessTokenPerfTest { @Test public void perfJaxrsClientLogin() { - long ITERATIONS = 1; + long ITERATIONS = 100; JaxrsClientLogin login = new JaxrsClientLogin(); long start = System.currentTimeMillis(); for (int i = 0; i < ITERATIONS; i++) { @@ -207,12 +245,13 @@ public class AccessTokenPerfTest { } @Test - public void perfBrowserLogin() throws Exception + public void perfBrowserLogin() { - long ITERATIONS = 1; + long ITERATIONS = 100; long start = System.currentTimeMillis(); + BrowserLogin login = new BrowserLogin(); for (int i = 0; i < ITERATIONS; i++) { - new BrowserLogin().run(); + login.run(); } long end = System.currentTimeMillis() - start; System.out.println("took: " + end); @@ -220,7 +259,7 @@ public class AccessTokenPerfTest { @Test public void multiThread() throws Exception { - int num_threads = 1; + int num_threads = 20; Thread[] threads = new Thread[num_threads]; for (int i = 0; i < num_threads; i++) { threads[i] = new Thread(new Runnable() { diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java index 62d22af157f..ae7795d99bb 100755 --- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java +++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java @@ -83,7 +83,7 @@ public class CreateUsersWorker implements Worker { UserCredentialModel password = new UserCredentialModel(); password.setType(CredentialRepresentation.PASSWORD); password.setValue(username); - realm.updateCredential(user, password); + user.updateCredential(password); } // Creating some socialLinks