keycloak-uncached
Changes
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-subsystem/main/module.xml 0(+0 -0)
forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_ca.properties 2(+1 -1)
forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_de.properties 2(+1 -1)
forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties 6(+3 -3)
forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_es.properties 2(+1 -1)
integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ServerInfoResource.java 20(+20 -0)
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java 2(+1 -1)
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java 113(+110 -3)
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java 2(+1 -1)
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java 24(+13 -11)
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java 7(+4 -3)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmCache.java 2(+2 -0)
services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java 3(+2 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java 4(+4 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java 31(+20 -11)
Details
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_ca.properties b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_ca.properties
index 31b9fe2..02a307a 100644
--- a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_ca.properties
+++ b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_ca.properties
@@ -235,7 +235,7 @@ credentials=Credencials
saml-keys=Claus SAML
roles=Rols
mappers=Assignadors
-mappers.tootip=Els assignadors de protocols realitzen transformacions en tokens i documents. Poden fer coses com assignar dades d''usuari en peticions de protocol, o simplement transformar qualsevol petici\u00F3 entre el client i el servidor d''autenticaci\u00F3.
+mappers.tooltip=Els assignadors de protocols realitzen transformacions en tokens i documents. Poden fer coses com assignar dades d''usuari en peticions de protocol, o simplement transformar qualsevol petici\u00F3 entre el client i el servidor d''autenticaci\u00F3.
scope=\u00C0mbit
scope.tooltip=Les assignacions d''\u00E0mbit et permeten restringir que assignacions de rols d''usuari s''inclouen en el testimoni d''acc\u00E9s sol\u00B7licitat pel client.
sessions.tooltip=Veure sessions actives per a aquest client. Permet veure quins usuaris estan actius i quan es van identificar.
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_de.properties b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_de.properties
index 295a8ce..bc463fc 100644
--- a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_de.properties
+++ b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_de.properties
@@ -232,7 +232,7 @@ credentials=de Credentials
saml-keys=de SAML Keys
roles=de Roles
mappers=de Mappers
-mappers.tootip=de Protocol mappers perform transformation on tokens and documents. They an do things like map user data into protocol claims, or just transform any requests going between the client and auth server.
+mappers.tooltip=de Protocol mappers perform transformation on tokens and documents. They an do things like map user data into protocol claims, or just transform any requests going between the client and auth server.
scope=de Scope
scope.tooltip=de Scope mappings allow you to restrict which user role mappings are included within the access token requested by the client.
sessions.tooltip=de View active sessions for this client. Allows you to see which users are active and when they logged in.
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index b92f65b..0dd5168 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -63,9 +63,9 @@ supported-locales=Supported Locales
supported-locales.placeholder=Type a locale and enter
default-locale=Default Locale
realm-cache-enabled=Realm Cache Enabled
-realm-cache-enabled.tooltip=Enable/disable cache for realm, client and role data.
+realm-cache-enabled.tooltip=Enable/disable cache for realms, clients and roles.
user-cache-enabled=User Cache Enabled
-user-cache-enabled.tooltip=Enable/disable user and user role mapping cache.
+user-cache-enabled.tooltip=Enable/disable cache for users and user role mappings.
revoke-refresh-token=Revoke Refresh Token
revoke-refresh-token.tooltip=If enabled refresh tokens can only be used once. Otherwise refresh tokens are not revoked when used and can be used multiple times.
sso-session-idle=SSO Session Idle
@@ -243,7 +243,7 @@ credentials=Credentials
saml-keys=SAML Keys
roles=Roles
mappers=Mappers
-mappers.tootip=Protocol mappers perform transformation on tokens and documents. They an do things like map user data into protocol claims, or just transform any requests going between the client and auth server.
+mappers.tooltip=Protocol mappers perform transformation on tokens and documents. They an do things like map user data into protocol claims, or just transform any requests going between the client and auth server.
scope=Scope
scope.tooltip=Scope mappings allow you to restrict which user role mappings are included within the access token requested by the client.
sessions.tooltip=View active sessions for this client. Allows you to see which users are active and when they logged in.
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_es.properties b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_es.properties
index 5a353ab..2a1807c 100644
--- a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_es.properties
+++ b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_es.properties
@@ -235,7 +235,7 @@ credentials=Credenciales
saml-keys=Claves SAML
roles=Roles
mappers=Asignadores
-mappers.tootip=Los asignadores de protocolos realizan transformaciones en tokens y documentos. Pueden hacer cosas como asignar datos de usuario en peticiones de protocolo, o simplemente transformar cualquier petici\u00F3n entre el cliente y el servidor de autenticaci\u00F3n.
+mappers.tooltip=Los asignadores de protocolos realizan transformaciones en tokens y documentos. Pueden hacer cosas como asignar datos de usuario en peticiones de protocolo, o simplemente transformar cualquier petici\u00F3n entre el cliente y el servidor de autenticaci\u00F3n.
scope=\u00C1mbito
scope.tooltip=Las asignaciones de \u00E1mbito te permiten restringir que asignaciones de roles de usuario se incluyen en el token de acceso solicitado por el cliente.
sessions.tooltip=Ver sesiones activas para este cliente. Permite ver qu\u00E9 usuarios est\u00E1n activos y cuando se identificaron.
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
index 431a646..bc75fa9 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
@@ -6,6 +6,7 @@ import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import org.keycloak.admin.client.resource.BearerAuthFilter;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.RealmsResource;
+import org.keycloak.admin.client.resource.ServerInfoResource;
import org.keycloak.admin.client.token.TokenManager;
/**
@@ -51,6 +52,10 @@ public class Keycloak {
return realms().realm(realmName);
}
+ public ServerInfoResource serverInfo(){
+ return target.proxy(ServerInfoResource.class);
+ }
+
public TokenManager tokenManager(){
return tokenManager;
}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ServerInfoResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ServerInfoResource.java
new file mode 100644
index 0000000..6ebd642
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ServerInfoResource.java
@@ -0,0 +1,20 @@
+package org.keycloak.admin.client.resource;
+
+import org.keycloak.representations.info.ServerInfoRepresentation;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+@Path("/admin/serverinfo")
+public interface ServerInfoResource {
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ ServerInfoRepresentation getInfo();
+
+}
diff --git a/model/api/src/main/java/org/keycloak/models/OTPPolicy.java b/model/api/src/main/java/org/keycloak/models/OTPPolicy.java
index 1c6665a..157842e 100755
--- a/model/api/src/main/java/org/keycloak/models/OTPPolicy.java
+++ b/model/api/src/main/java/org/keycloak/models/OTPPolicy.java
@@ -4,6 +4,7 @@ import org.jboss.logging.Logger;
import org.keycloak.models.utils.Base32;
import org.keycloak.models.utils.HmacOTP;
+import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
@@ -13,7 +14,7 @@ import java.util.Map;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class OTPPolicy {
+public class OTPPolicy implements Serializable {
protected static final Logger logger = Logger.getLogger(OTPPolicy.class);
diff --git a/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java b/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java
index e1c356b..0ecf878 100755
--- a/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java
@@ -1,5 +1,6 @@
package org.keycloak.models;
+import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
@@ -7,7 +8,7 @@ import java.util.Map;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class RequiredActionProviderModel {
+public class RequiredActionProviderModel implements Serializable {
private String id;
private String alias;
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index dfa2e46..87c13a3 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -1044,35 +1044,14 @@ public class RepresentationToModel {
user.addRequiredAction(UserModel.RequiredAction.valueOf(requiredAction));
}
}
- if (userRep.getCredentials() != null) {
- for (CredentialRepresentation cred : userRep.getCredentials()) {
- updateCredential(user, cred);
- }
- }
+ createCredentials(userRep, user);
if (userRep.getFederatedIdentities() != null) {
for (FederatedIdentityRepresentation identity : userRep.getFederatedIdentities()) {
FederatedIdentityModel mappingModel = new FederatedIdentityModel(identity.getIdentityProvider(), identity.getUserId(), identity.getUserName());
session.users().addFederatedIdentity(newRealm, user, mappingModel);
}
}
- if (userRep.getRealmRoles() != null) {
- for (String roleString : userRep.getRealmRoles()) {
- RoleModel role = newRealm.getRole(roleString.trim());
- if (role == null) {
- role = newRealm.addRole(roleString.trim());
- }
- user.grantRole(role);
- }
- }
- if (userRep.getClientRoles() != null) {
- for (Map.Entry<String, List<String>> entry : userRep.getClientRoles().entrySet()) {
- ClientModel client = clientMap.get(entry.getKey());
- if (client == null) {
- throw new RuntimeException("Unable to find client role mappings for client: " + entry.getKey());
- }
- createClientRoleMappings(client, user, entry.getValue());
- }
- }
+ createRoleMappings(userRep, user, newRealm);
if (userRep.getClientConsents() != null) {
for (UserConsentRepresentation consentRep : userRep.getClientConsents()) {
UserConsentModel consentModel = toModel(newRealm, consentRep);
@@ -1100,6 +1079,14 @@ public class RepresentationToModel {
return user;
}
+ public static void createCredentials(UserRepresentation userRep, UserModel user) {
+ if (userRep.getCredentials() != null) {
+ for (CredentialRepresentation cred : userRep.getCredentials()) {
+ updateCredential(user, cred);
+ }
+ }
+ }
+
// Detect if it is "plain-text" or "hashed" representation and update model according to it
private static void updateCredential(UserModel user, CredentialRepresentation cred) {
if (cred.getValue() != null) {
@@ -1142,6 +1129,28 @@ public class RepresentationToModel {
// Role mappings
+ public static void createRoleMappings(UserRepresentation userRep, UserModel user, RealmModel realm) {
+ if (userRep.getRealmRoles() != null) {
+ for (String roleString : userRep.getRealmRoles()) {
+ RoleModel role = realm.getRole(roleString.trim());
+ if (role == null) {
+ role = realm.addRole(roleString.trim());
+ }
+ user.grantRole(role);
+ }
+ }
+ if (userRep.getClientRoles() != null) {
+ Map<String, ClientModel> clientMap = realm.getClientNameMap();
+ for (Map.Entry<String, List<String>> entry : userRep.getClientRoles().entrySet()) {
+ ClientModel client = clientMap.get(entry.getKey());
+ if (client == null) {
+ throw new RuntimeException("Unable to find client role mappings for client: " + entry.getKey());
+ }
+ createClientRoleMappings(client, user, entry.getValue());
+ }
+ }
+ }
+
public static void createClientRoleMappings(ClientModel clientModel, UserModel user, List<String> roleNames) {
if (user == null) {
throw new RuntimeException("User not found");
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
index 20c8725..2f7e61f 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
@@ -29,7 +29,7 @@ public class ClientAdapter implements ClientModel {
private void getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerApplicationInvalidation(getId());
- updated = updated = cacheSession.getDelegate().getClientById(getId(), cachedRealm);
+ updated = cacheSession.getDelegate().getClientById(getId(), cachedRealm);
if (updated == null) throw new IllegalStateException("Not found in database");
}
}
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java
index 4b96241..5a76153 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java
@@ -1,6 +1,16 @@
package org.keycloak.models.cache.infinispan;
import org.infinispan.Cache;
+import org.infinispan.notifications.Listener;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
+import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryInvalidatedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
+import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.models.KeycloakSession;
@@ -8,6 +18,8 @@ import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.CacheRealmProviderFactory;
import org.keycloak.models.cache.RealmCache;
+import org.keycloak.models.cache.entities.CachedRealm;
+import org.keycloak.models.cache.entities.CachedUser;
import java.util.concurrent.ConcurrentHashMap;
@@ -17,15 +29,43 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFactory {
- protected final ConcurrentHashMap<String, String> realmLookup = new ConcurrentHashMap<String, String>();
+ private static final Logger log = Logger.getLogger(InfinispanCacheRealmProviderFactory.class);
+
+ protected volatile InfinispanRealmCache realmCache;
+
+ protected final ConcurrentHashMap<String, String> realmLookup = new ConcurrentHashMap<>();
+
+ private boolean isNewInfinispan;
@Override
public CacheRealmProvider create(KeycloakSession session) {
- Cache<String, Object> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
- RealmCache realmCache = new InfinispanRealmCache(cache, realmLookup);
+ lazyInit(session);
return new DefaultCacheRealmProvider(realmCache, session);
}
+ private void lazyInit(KeycloakSession session) {
+ if (realmCache == null) {
+ synchronized (this) {
+ if (realmCache == null) {
+ checkIspnVersion();
+
+ Cache<String, Object> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
+ cache.addListener(new CacheListener());
+ realmCache = new InfinispanRealmCache(cache, realmLookup);
+ }
+ }
+ }
+ }
+
+ protected void checkIspnVersion() {
+ try {
+ CacheEntryCreatedEvent.class.getMethod("getValue");
+ isNewInfinispan = true;
+ } catch (NoSuchMethodException nsme) {
+ isNewInfinispan = false;
+ }
+ }
+
@Override
public void init(Config.Scope config) {
}
@@ -44,4 +84,71 @@ public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFa
return "infinispan";
}
+ @Listener
+ public class CacheListener {
+
+ @CacheEntryCreated
+ public void created(CacheEntryCreatedEvent<String, Object> event) {
+ if (!event.isPre()) {
+ Object object;
+
+ // Try optimized version if available
+ if (isNewInfinispan) {
+ object = event.getValue();
+ } else {
+ String id = event.getKey();
+ object = event.getCache().get(id);
+ }
+
+ if (object != null) {
+ if (object instanceof CachedRealm) {
+ CachedRealm realm = (CachedRealm) object;
+ realmLookup.put(realm.getName(), realm.getId());
+ log.tracev("Realm added realm={0}", realm.getName());
+ }
+ }
+ }
+ }
+
+ @CacheEntryRemoved
+ public void removed(CacheEntryRemovedEvent<String, Object> event) {
+ if (event.isPre()) {
+ Object object = event.getValue();
+ if (object != null) {
+ remove(object);
+ }
+ }
+ }
+
+ @CacheEntryInvalidated
+ public void removed(CacheEntryInvalidatedEvent<String, Object> event) {
+ if (event.isPre()) {
+ Object object = event.getValue();
+ if (object != null) {
+ remove(object);
+ }
+ }
+ }
+
+ @CacheEntriesEvicted
+ public void userEvicted(CacheEntriesEvictedEvent<String, Object> event) {
+ for (Object object : event.getEntries().values()) {
+ remove(object);
+ }
+ }
+
+ private void remove(Object object) {
+ if (object instanceof CachedRealm) {
+ CachedRealm realm = (CachedRealm) object;
+
+ realmLookup.remove(realm.getName());
+
+ for (String c : realm.getClients().values()) {
+ realmCache.evictCachedApplicationById(c);
+ }
+
+ log.tracev("Realm removed realm={0}", realm.getName());
+ }
+ }
+ }
}
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
index 4eb0bdf..ec69912 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
@@ -26,7 +26,7 @@ public class InfinispanCacheUserProviderFactory implements CacheUserProviderFact
private static final Logger log = Logger.getLogger(InfinispanCacheUserProviderFactory.class);
- protected InfinispanUserCache userCache;
+ protected volatile InfinispanUserCache userCache;
protected final RealmLookup usernameLookup = new RealmLookup();
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java
index a5239fb..8155801 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java
@@ -38,9 +38,10 @@ public class InfinispanRealmCache implements RealmCache {
@Override
public void setEnabled(boolean enabled) {
- clear();
+ if (this.enabled && !enabled) {
+ clear();
+ }
this.enabled = enabled;
- clear();
}
@Override
@@ -66,7 +67,7 @@ public class InfinispanRealmCache implements RealmCache {
public void addCachedRealm(CachedRealm realm) {
if (!enabled) return;
logger.tracev("Adding realm {0}", realm.getId());
- cache.put(realm.getId(), realm);
+ cache.putForExternalRead(realm.getId(), realm);
realmLookup.put(realm.getName(), realm.getId());
}
@@ -93,7 +94,7 @@ public class InfinispanRealmCache implements RealmCache {
public void addCachedClient(CachedClient app) {
if (!enabled) return;
logger.tracev("Adding application {0}", app.getId());
- cache.put(app.getId(), app);
+ cache.putForExternalRead(app.getId(), app);
}
@Override
@@ -103,6 +104,12 @@ public class InfinispanRealmCache implements RealmCache {
}
@Override
+ public void evictCachedApplicationById(String id) {
+ logger.tracev("Evicting application {0}", id);
+ cache.evict(id);
+ }
+
+ @Override
public CachedGroup getGroup(String id) {
if (!enabled) return null;
return get(id, CachedGroup.class);
@@ -112,15 +119,13 @@ public class InfinispanRealmCache implements RealmCache {
public void invalidateGroup(CachedGroup role) {
logger.tracev("Removing group {0}", role.getId());
cache.remove(role.getId());
-
}
@Override
public void addCachedGroup(CachedGroup role) {
if (!enabled) return;
logger.tracev("Adding group {0}", role.getId());
- cache.put(role.getId(), role);
-
+ cache.putForExternalRead(role.getId(), role);
}
@Override
@@ -134,7 +139,6 @@ public class InfinispanRealmCache implements RealmCache {
public void invalidateGroupById(String id) {
logger.tracev("Removing group {0}", id);
cache.remove(id);
-
}
@Override
@@ -143,8 +147,6 @@ public class InfinispanRealmCache implements RealmCache {
return get(id, CachedRole.class);
}
-
-
@Override
public void invalidateRole(CachedRole role) {
logger.tracev("Removing role {0}", role.getId());
@@ -161,7 +163,7 @@ public class InfinispanRealmCache implements RealmCache {
public void addCachedRole(CachedRole role) {
if (!enabled) return;
logger.tracev("Adding role {0}", role.getId());
- cache.put(role.getId(), role);
+ cache.putForExternalRead(role.getId(), role);
}
@Override
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java
index fbb36c5..c5e960c 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java
@@ -35,9 +35,10 @@ public class InfinispanUserCache implements UserCache {
@Override
public void setEnabled(boolean enabled) {
- clear();
+ if (this.enabled && !enabled) {
+ clear();
+ }
this.enabled = enabled;
- clear();
}
@Override
@@ -62,7 +63,7 @@ public class InfinispanUserCache implements UserCache {
@Override
public void addCachedUser(String realmId, CachedUser user) {
logger.tracev("Adding user {0}", user.getId());
- cache.put(user.getId(), user);
+ cache.putForExternalRead(user.getId(), user);
}
@Override
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmCache.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmCache.java
index df74b53..007daac 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmCache.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmCache.java
@@ -26,6 +26,8 @@ public interface RealmCache {
void invalidateApplication(CachedClient app);
+ void evictCachedApplicationById(String id);
+
void addCachedClient(CachedClient app);
void invalidateCachedApplicationById(String id);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
index 660b1c4..672745c 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
@@ -31,6 +31,7 @@ import org.keycloak.provider.Spi;
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation;
+import org.keycloak.representations.info.*;
import org.keycloak.social.SocialIdentityProvider;
/**
@@ -51,7 +52,7 @@ public class ServerInfoAdminResource {
@GET
public ServerInfoRepresentation getInfo() {
ServerInfoRepresentation info = new ServerInfoRepresentation();
- info.setSystemInfo(SystemInfoRepresentation.create(session));
+ info.setSystemInfo(SystemInfoRepresentation.create(session.getKeycloakSessionFactory().getServerStartupTimestamp()));
info.setMemoryInfo(MemoryInfoRepresentation.create());
setSocialProviders(info);
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index c26e60c..88569b6 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -9,10 +9,7 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.Config;
import org.keycloak.exportimport.ExportImportManager;
import org.keycloak.migration.MigrationModelManager;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserModel;
+import org.keycloak.models.*;
import org.keycloak.models.utils.PostMigrationEvent;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.RealmRepresentation;
@@ -263,32 +260,46 @@ public class KeycloakApplication extends Application {
if (addUserFile.isFile()) {
log.info("Importing users from '" + addUserFile + "'");
- KeycloakSession session = sessionFactory.create();
+ List<RealmRepresentation> realms;
try {
- session.getTransaction().begin();
-
- List<RealmRepresentation> realms = JsonSerialization.readValue(new FileInputStream(addUserFile), new TypeReference<List<RealmRepresentation>>() {});
- for (RealmRepresentation r : realms) {
- RealmModel realm = session.realms().getRealmByName(r.getRealm());
- if (realm == null) {
- throw new Exception("Realm '" + r.getRealm() + "' not found");
- }
+ realms = JsonSerialization.readValue(new FileInputStream(addUserFile), new TypeReference<List<RealmRepresentation>>() {
+ });
+ } catch (IOException e) {
+ log.errorv("Failed to load 'keycloak-add-user.json': {0}", e.getMessage());
+ return;
+ }
- for (UserRepresentation u : r.getUsers()) {
- RepresentationToModel.createUser(session, realm, u, realm.getClientNameMap());
+ for (RealmRepresentation realmRep : realms) {
+ for (UserRepresentation userRep : realmRep.getUsers()) {
+ KeycloakSession session = sessionFactory.create();
+ try {
+ session.getTransaction().begin();
+
+ RealmModel realm = session.realms().getRealmByName(realmRep.getRealm());
+ if (realm == null) {
+ log.errorv("Failed to add user ''{0}'' to realm ''{1}'': realm not found", userRep.getUsername(), realmRep.getRealm());
+ } else {
+ UserModel user = session.users().addUser(realm, userRep.getUsername());
+ user.setEnabled(userRep.isEnabled());
+ RepresentationToModel.createCredentials(userRep, user);
+ RepresentationToModel.createRoleMappings(userRep, user, realm);
+ }
+
+ session.getTransaction().commit();
+ log.infov("Added user ''{0}'' to realm ''{1}''", userRep.getUsername(), realmRep.getRealm());
+ } catch (ModelDuplicateException e) {
+ log.errorv("Failed to add user ''{0}'' to realm ''{1}'': user with username exists", userRep.getUsername(), realmRep.getRealm());
+ } catch (Throwable t) {
+ session.getTransaction().rollback();
+ log.errorv("Failed to add user ''{0}'' to realm ''{1}'': {2}", userRep.getUsername(), realmRep.getRealm(), t.getMessage());
+ } finally {
+ session.close();
}
}
+ }
- session.getTransaction().commit();
-
- if (!addUserFile.delete()) {
- log.error("Failed to delete '" + addUserFile + "'");
- }
- } catch (Throwable t) {
- session.getTransaction().rollback();
- log.error("Failed to import users from '" + addUserFile + "'", t);
- } finally {
- session.close();
+ if (!addUserFile.delete()) {
+ log.errorv("Failed to delete '{0}'", addUserFile.getAbsolutePath());
}
}
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
index 17fa174..dea6ebc 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
@@ -1,15 +1,28 @@
package org.keycloak.testsuite.adduser;
+import org.codehaus.jackson.type.TypeReference;
import org.junit.*;
import org.junit.rules.TemporaryFolder;
import org.keycloak.admin.client.Keycloak;
+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.common.util.Base64Url;
import org.keycloak.models.Constants;
-import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
+import org.keycloak.representations.idm.*;
import org.keycloak.testsuite.KeycloakServer;
+import org.keycloak.util.JsonSerialization;
import org.keycloak.wildfly.adduser.AddUser;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.*;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -37,7 +50,16 @@ public class AddUserTest {
@Test
public void addUserTest() throws Throwable {
AddUser.main(new String[]{"-u", "addusertest-admin", "-p", "password"});
- Assert.assertEquals(1, dir.listFiles().length);
+ assertEquals(1, dir.listFiles().length);
+
+ List<RealmRepresentation> realms = JsonSerialization.readValue(new FileInputStream(new File(dir, "keycloak-add-user.json")), new TypeReference<List<RealmRepresentation>>() {});
+ assertEquals(1, realms.size());
+ assertEquals(1, realms.get(0).getUsers().size());
+
+ UserRepresentation user = realms.get(0).getUsers().get(0);
+ assertEquals(new Integer(100000), user.getCredentials().get(0).getHashIterations());
+ assertNull(user.getCredentials().get(0).getValue());
+ assertEquals(new Pbkdf2PasswordEncoder(Base64Url.decode(user.getCredentials().get(0).getSalt()), 100000).encode("password"), user.getCredentials().get(0).getHashedSaltedValue());
KeycloakServer server = new KeycloakServer();
try {
@@ -53,12 +75,54 @@ public class AddUserTest {
keycloak.realms().create(testRealm);
+ RealmResource realm = keycloak.realm("master");
+
+ List<UserRepresentation> users = realm.users().search("addusertest-admin", null, null, null, null, null);
+ assertEquals(1, users.size());
+
+ UserRepresentation created = users.get(0);
+ assertNotNull(created.getCreatedTimestamp());
+
+ UserResource userResource = realm.users().get(created.getId());
+
+ List<RoleRepresentation> realmRoles = userResource.roles().realmLevel().listAll();
+
+ assertRoles(realmRoles, "admin", "offline_access");
+
+ List<ClientRepresentation> clients = realm.clients().findAll();
+ String accountId = null;
+ for (ClientRepresentation c : clients) {
+ if (c.getClientId().equals("account")) {
+ accountId = c.getId();
+ }
+ }
+
+ List<RoleRepresentation> accountRoles = userResource.roles().clientLevel(accountId).listAll();
+
+ assertRoles(accountRoles, "view-profile", "manage-account");
+
keycloak.close();
- Assert.assertEquals(0, dir.listFiles().length);
+ assertEquals(0, dir.listFiles().length);
} finally {
server.stop();
}
}
+ public static void assertRoles(List<RoleRepresentation> actual, String... expected) {
+ assertEquals(expected.length, actual.size());
+
+ for (String e : expected) {
+ boolean found = false;
+ for (RoleRepresentation r : actual) {
+ if (r.getName().equals(e)) {
+ found = true;
+ }
+ }
+ if (!found) {
+ fail("Role " + e + " not found");
+ }
+ }
+ }
+
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
index dd575b1..31f88bc 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
@@ -1,24 +1,26 @@
package org.keycloak.testsuite.admin;
+import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ProtocolMappersResource;
import org.keycloak.models.Constants;
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
-import org.keycloak.representations.idm.ClientRepresentation;
-import org.keycloak.representations.idm.ProtocolMapperRepresentation;
-import org.keycloak.representations.idm.RoleRepresentation;
-import org.keycloak.representations.idm.UserSessionRepresentation;
+import org.keycloak.representations.idm.*;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.WebDriver;
import javax.ws.rs.NotFoundException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -46,19 +48,21 @@ public class ClientTest extends AbstractClientTest {
assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", Constants.ADMIN_CLI_CLIENT_ID);
}
- private String createClient() {
+ private ClientRepresentation createClient() {
ClientRepresentation rep = new ClientRepresentation();
rep.setClientId("my-app");
rep.setDescription("my-app description");
rep.setEnabled(true);
Response response = realm.clients().create(rep);
response.close();
- return ApiUtil.getCreatedId(response);
+ String id = ApiUtil.getCreatedId(response);
+ rep.setId(id);
+ return rep;
}
@Test
public void createClientVerify() {
- String id = createClient();
+ String id = createClient().getId();
assertNotNull(realm.clients().get(id));
assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "my-app", Constants.ADMIN_CLI_CLIENT_ID);
@@ -66,14 +70,14 @@ public class ClientTest extends AbstractClientTest {
@Test
public void removeClient() {
- String id = createClient();
+ String id = createClient().getId();
realm.clients().get(id).remove();
}
@Test
public void getClientRepresentation() {
- String id = createClient();
+ String id = createClient().getId();
ClientRepresentation rep = realm.clients().get(id).toRepresentation();
assertEquals(id, rep.getId());
@@ -86,8 +90,7 @@ public class ClientTest extends AbstractClientTest {
*/
@Test
public void getClientDescription() {
-
- String id = createClient();
+ String id = createClient().getId();
ClientRepresentation rep = realm.clients().get(id).toRepresentation();
assertEquals(id, rep.getId());
@@ -145,6 +148,28 @@ public class ClientTest extends AbstractClientTest {
protocolMappersTest(mappersResource);
}
+ @Test
+ public void updateClient() {
+ ClientRepresentation client = createClient();
+
+ ClientRepresentation newClient = new ClientRepresentation();
+ newClient.setId(client.getId());
+ newClient.setClientId(client.getClientId());
+ newClient.setBaseUrl("http://baseurl");
+
+ realm.clients().get(client.getId()).update(newClient);
+
+ ClientRepresentation storedClient = realm.clients().get(client.getId()).toRepresentation();
+
+ assertClient(client, storedClient);
+
+ newClient.setSecret("new-secret");
+
+ realm.clients().get(client.getId()).update(newClient);
+
+ storedClient = realm.clients().get(client.getId()).toRepresentation();
+ assertClient(client, storedClient);
+ }
public static void protocolMappersTest(ProtocolMappersResource mappersResource) {
// assert default mappers found
@@ -197,4 +222,62 @@ public class ClientTest extends AbstractClientTest {
}
}
+ public static void assertClient(ClientRepresentation client, ClientRepresentation storedClient) {
+ if (client.getClientId() != null) Assert.assertEquals(client.getClientId(), storedClient.getClientId());
+ if (client.getName() != null) Assert.assertEquals(client.getName(), storedClient.getName());
+ if (client.isEnabled() != null) Assert.assertEquals(client.isEnabled(), storedClient.isEnabled());
+ if (client.isBearerOnly() != null) Assert.assertEquals(client.isBearerOnly(), storedClient.isBearerOnly());
+ if (client.isPublicClient() != null) Assert.assertEquals(client.isPublicClient(), storedClient.isPublicClient());
+ if (client.isFullScopeAllowed() != null) Assert.assertEquals(client.isFullScopeAllowed(), storedClient.isFullScopeAllowed());
+ if (client.getRootUrl() != null) Assert.assertEquals(client.getRootUrl(), storedClient.getRootUrl());
+ if (client.getAdminUrl() != null) Assert.assertEquals(client.getAdminUrl(), storedClient.getAdminUrl());
+ if (client.getBaseUrl() != null) Assert.assertEquals(client.getBaseUrl(), storedClient.getBaseUrl());
+ if (client.isSurrogateAuthRequired() != null) Assert.assertEquals(client.isSurrogateAuthRequired(), storedClient.isSurrogateAuthRequired());
+ if (client.getClientAuthenticatorType() != null) Assert.assertEquals(client.getClientAuthenticatorType(), storedClient.getClientAuthenticatorType());
+
+ if (client.getNotBefore() != null) {
+ Assert.assertEquals(client.getNotBefore(), storedClient.getNotBefore());
+ }
+ if (client.getDefaultRoles() != null) {
+ Set<String> set = new HashSet<String>();
+ for (String val : client.getDefaultRoles()) {
+ set.add(val);
+ }
+ Set<String> storedSet = new HashSet<String>();
+ for (String val : storedClient.getDefaultRoles()) {
+ storedSet.add(val);
+ }
+
+ Assert.assertEquals(set, storedSet);
+ }
+
+ List<String> redirectUris = client.getRedirectUris();
+ if (redirectUris != null) {
+ Set<String> set = new HashSet<String>();
+ for (String val : client.getRedirectUris()) {
+ set.add(val);
+ }
+ Set<String> storedSet = new HashSet<String>();
+ for (String val : storedClient.getRedirectUris()) {
+ storedSet.add(val);
+ }
+
+ Assert.assertEquals(set, storedSet);
+ }
+
+ List<String> webOrigins = client.getWebOrigins();
+ if (webOrigins != null) {
+ Set<String> set = new HashSet<String>();
+ for (String val : client.getWebOrigins()) {
+ set.add(val);
+ }
+ Set<String> storedSet = new HashSet<String>();
+ for (String val : storedClient.getWebOrigins()) {
+ storedSet.add(val);
+ }
+
+ Assert.assertEquals(set, storedSet);
+ }
+ }
+
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
index 42870a6..604dcff 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
@@ -1,6 +1,7 @@
package org.keycloak.testsuite.admin;
import org.apache.commons.io.IOUtils;
+import org.junit.Assert;
import org.junit.Test;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@@ -8,6 +9,7 @@ import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.KeycloakServer;
import org.keycloak.util.JsonSerialization;
import javax.ws.rs.NotFoundException;
@@ -43,7 +45,7 @@ public class RealmTest extends AbstractClientTest {
}
@Test
- public void createRealm() {
+ public void createRealmEmpty() {
try {
RealmRepresentation rep = new RealmRepresentation();
rep.setRealm("new-realm");
@@ -63,6 +65,25 @@ public class RealmTest extends AbstractClientTest {
}
@Test
+ public void createRealm() {
+ try {
+ RealmRepresentation rep = KeycloakServer.loadJson(getClass().getResourceAsStream("/admin-test/testrealm.json"), RealmRepresentation.class);
+ keycloak.realms().create(rep);
+
+ RealmRepresentation created = keycloak.realms().realm("admin-test-1").toRepresentation();
+ assertRealm(rep, created);
+ } finally {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmManager manager = new RealmManager(session);
+ RealmModel newRealm = manager.getRealmByName("admin-test-1");
+ if (newRealm != null) {
+ manager.removeRealm(newRealm);
+ }
+ keycloakRule.stopSession(session, true);
+ }
+ }
+
+ @Test
public void removeRealm() {
realm.remove();
@@ -194,4 +215,64 @@ public class RealmTest extends AbstractClientTest {
assertEquals("https://LoadBalancer-9.siroe.com:3443/federation/Consumer/metaAlias/sp", converted.getRedirectUris().get(0));
}
+ public static void assertRealm(RealmRepresentation realm, RealmRepresentation storedRealm) {
+ if (realm.getId() != null) {
+ Assert.assertEquals(realm.getId(), storedRealm.getId());
+ }
+ if (realm.getRealm() != null) {
+ Assert.assertEquals(realm.getRealm(), storedRealm.getRealm());
+ }
+ if (realm.isEnabled() != null) Assert.assertEquals(realm.isEnabled(), storedRealm.isEnabled());
+ if (realm.isBruteForceProtected() != null) Assert.assertEquals(realm.isBruteForceProtected(), storedRealm.isBruteForceProtected());
+ if (realm.getMaxFailureWaitSeconds() != null) Assert.assertEquals(realm.getMaxFailureWaitSeconds(), storedRealm.getMaxFailureWaitSeconds());
+ if (realm.getMinimumQuickLoginWaitSeconds() != null) Assert.assertEquals(realm.getMinimumQuickLoginWaitSeconds(), storedRealm.getMinimumQuickLoginWaitSeconds());
+ if (realm.getWaitIncrementSeconds() != null) Assert.assertEquals(realm.getWaitIncrementSeconds(), storedRealm.getWaitIncrementSeconds());
+ if (realm.getQuickLoginCheckMilliSeconds() != null) Assert.assertEquals(realm.getQuickLoginCheckMilliSeconds(), storedRealm.getQuickLoginCheckMilliSeconds());
+ if (realm.getMaxDeltaTimeSeconds() != null) Assert.assertEquals(realm.getMaxDeltaTimeSeconds(), storedRealm.getMaxDeltaTimeSeconds());
+ if (realm.getFailureFactor() != null) Assert.assertEquals(realm.getFailureFactor(), storedRealm.getFailureFactor());
+ if (realm.isRegistrationAllowed() != null) Assert.assertEquals(realm.isRegistrationAllowed(), storedRealm.isRegistrationAllowed());
+ if (realm.isRegistrationEmailAsUsername() != null) Assert.assertEquals(realm.isRegistrationEmailAsUsername(), storedRealm.isRegistrationEmailAsUsername());
+ if (realm.isRememberMe() != null) Assert.assertEquals(realm.isRememberMe(), storedRealm.isRememberMe());
+ if (realm.isVerifyEmail() != null) Assert.assertEquals(realm.isVerifyEmail(), storedRealm.isVerifyEmail());
+ if (realm.isResetPasswordAllowed() != null) Assert.assertEquals(realm.isResetPasswordAllowed(), storedRealm.isResetPasswordAllowed());
+ if (realm.isEditUsernameAllowed() != null) Assert.assertEquals(realm.isEditUsernameAllowed(), storedRealm.isEditUsernameAllowed());
+ if (realm.getSslRequired() != null) Assert.assertEquals(realm.getSslRequired(), storedRealm.getSslRequired());
+ if (realm.getAccessCodeLifespan() != null) Assert.assertEquals(realm.getAccessCodeLifespan(), storedRealm.getAccessCodeLifespan());
+ if (realm.getAccessCodeLifespanUserAction() != null)
+ Assert.assertEquals(realm.getAccessCodeLifespanUserAction(), storedRealm.getAccessCodeLifespanUserAction());
+ if (realm.getNotBefore() != null) Assert.assertEquals(realm.getNotBefore(), storedRealm.getNotBefore());
+ if (realm.getAccessTokenLifespan() != null) Assert.assertEquals(realm.getAccessTokenLifespan(), storedRealm.getAccessTokenLifespan());
+ if (realm.getAccessTokenLifespanForImplicitFlow() != null) Assert.assertEquals(realm.getAccessTokenLifespanForImplicitFlow(), storedRealm.getAccessTokenLifespanForImplicitFlow());
+ if (realm.getSsoSessionIdleTimeout() != null) Assert.assertEquals(realm.getSsoSessionIdleTimeout(), storedRealm.getSsoSessionIdleTimeout());
+ if (realm.getSsoSessionMaxLifespan() != null) Assert.assertEquals(realm.getSsoSessionMaxLifespan(), storedRealm.getSsoSessionMaxLifespan());
+ if (realm.getRequiredCredentials() != null) {
+ Assert.assertNotNull(storedRealm.getRequiredCredentials());
+ for (String cred : realm.getRequiredCredentials()) {
+ Assert.assertTrue(storedRealm.getRequiredCredentials().contains(cred));
+ }
+ }
+ if (realm.getLoginTheme() != null) Assert.assertEquals(realm.getLoginTheme(), storedRealm.getLoginTheme());
+ if (realm.getAccountTheme() != null) Assert.assertEquals(realm.getAccountTheme(), storedRealm.getAccountTheme());
+ if (realm.getAdminTheme() != null) Assert.assertEquals(realm.getAdminTheme(), storedRealm.getAdminTheme());
+ if (realm.getEmailTheme() != null) Assert.assertEquals(realm.getEmailTheme(), storedRealm.getEmailTheme());
+
+ if (realm.getPasswordPolicy() != null) Assert.assertEquals(realm.getPasswordPolicy(), storedRealm.getPasswordPolicy());
+
+ if (realm.getDefaultRoles() != null) {
+ Assert.assertNotNull(storedRealm.getDefaultRoles());
+ for (String role : realm.getDefaultRoles()) {
+ Assert.assertTrue(storedRealm.getDefaultRoles().contains(role));
+ }
+ }
+
+ if (realm.getSmtpServer() != null) {
+ Assert.assertEquals(realm.getSmtpServer(), storedRealm.getSmtpServer());
+ }
+
+ if (realm.getBrowserSecurityHeaders() != null) {
+ Assert.assertEquals(realm.getBrowserSecurityHeaders(), storedRealm.getBrowserSecurityHeaders());
+ }
+
+ }
+
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ServerInfoTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ServerInfoTest.java
new file mode 100644
index 0000000..6c839c5
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ServerInfoTest.java
@@ -0,0 +1,44 @@
+package org.keycloak.testsuite.admin;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.common.Version;
+import org.keycloak.representations.info.ServerInfoRepresentation;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ServerInfoTest extends AbstractClientTest {
+
+ @Rule
+ public WebRule webRule = new WebRule(this);
+
+ @WebResource
+ protected WebDriver driver;
+
+ @WebResource
+ protected OAuthClient oauth;
+
+ @Test
+ public void testServerInfo() {
+ ServerInfoRepresentation info = keycloak.serverInfo().getInfo();
+
+ Assert.assertNotNull(info);
+ Assert.assertNotNull(info.getProviders());
+ Assert.assertNotNull(info.getThemes());
+ Assert.assertNotNull(info.getEnums());
+
+ Assert.assertNotNull(info.getMemoryInfo());
+ Assert.assertNotNull(info.getSystemInfo());
+
+ Assert.assertEquals(Version.VERSION, info.getSystemInfo().getVersion());
+ Assert.assertNotNull(info.getSystemInfo().getServerTime());
+ Assert.assertNotNull(info.getSystemInfo().getUptime());
+ }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
index 5248c38..7545a50 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -51,6 +51,7 @@ import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
import org.keycloak.testsuite.pages.OAuthGrantPage;
import org.keycloak.testsuite.pages.VerifyEmailPage;
import org.keycloak.testsuite.rule.GreenMailRule;
+import org.keycloak.testsuite.rule.LoggingRule;
import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.keycloak.util.JsonSerialization;
@@ -94,6 +95,9 @@ public abstract class AbstractIdentityProviderTest {
public static BrokerKeyCloakRule brokerServerRule = new BrokerKeyCloakRule();
@Rule
+ public LoggingRule loggingRule = new LoggingRule(this);
+
+ @Rule
public WebRule webRule = new WebRule(this);
@WebResource
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
index dbf761e..a2d4935 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
@@ -83,13 +83,15 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
*/
@Test
public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled() throws IOException, MessagingException {
- getRealm().setVerifyEmail(true);
+ RealmModel realm = getRealm();
+ realm.setVerifyEmail(true);
+ setUpdateProfileFirstLogin(realm, IdentityProviderRepresentation.UPFLM_OFF);
+
brokerServerRule.stopSession(this.session, true);
this.session = brokerServerRule.startSession();
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
try {
- setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
identityProviderModel.setTrustEmail(false);
UserModel federatedUser = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "test-user@localhost", false);
@@ -152,13 +154,15 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
*/
@Test
public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() {
- getRealm().setVerifyEmail(true);
+ RealmModel realm = getRealm();
+ realm.setVerifyEmail(true);
+ setUpdateProfileFirstLogin(realm, IdentityProviderRepresentation.UPFLM_OFF);
+
brokerServerRule.stopSession(this.session, true);
this.session = brokerServerRule.startSession();
try {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
- setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", null, false);
@@ -174,8 +178,10 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
*/
@Test
public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled_emailTrustEnabled() {
- getRealm().setVerifyEmail(true);
- setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
+ RealmModel realmWithBroker = getRealm();
+ realmWithBroker.setVerifyEmail(true);
+ setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_OFF);
+
brokerServerRule.stopSession(this.session, true);
this.session = brokerServerRule.startSession();
@@ -201,13 +207,15 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
*/
@Test
public void testSuccessfulAuthentication_emailTrustEnabled_emailVerifyEnabled_emailUpdatedOnFirstLogin() throws IOException, MessagingException {
- getRealm().setVerifyEmail(true);
+ RealmModel realm = getRealm();
+ realm.setVerifyEmail(true);
+ setUpdateProfileFirstLogin(realm, IdentityProviderRepresentation.UPFLM_ON);
+
brokerServerRule.stopSession(this.session, true);
this.session = brokerServerRule.startSession();
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
try {
- setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON);
identityProviderModel.setTrustEmail(true);
UserModel user = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "new@email.com", true);
@@ -220,14 +228,15 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
@Test
public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() {
+ RealmModel realm = getRealm();
+ realm.setRegistrationEmailAsUsername(true);
+ setUpdateProfileFirstLogin(realm, IdentityProviderRepresentation.UPFLM_OFF);
- getRealm().setRegistrationEmailAsUsername(true);
brokerServerRule.stopSession(this.session, true);
this.session = brokerServerRule.startSession();
try {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
- setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
authenticateWithIdentityProvider(identityProviderModel, "test-user", false);
@@ -238,7 +247,7 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
session = brokerServerRule.startSession();
// check correct user is created with email as username and bound to correct federated identity
- RealmModel realm = getRealm();
+ realm = getRealm();
UserModel federatedUser = session.users().getUserByUsername("test-user@localhost", realm);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
index 597e7dd..a9b907c 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
@@ -7,10 +7,12 @@ import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;
import org.keycloak.models.*;
+import org.keycloak.models.cache.infinispan.ClientAdapter;
import org.keycloak.models.cache.infinispan.RealmAdapter;
import org.keycloak.testsuite.rule.KeycloakRule;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -27,10 +29,12 @@ public class CacheTest {
// load up cache
KeycloakSession session = kc.startSession();
RealmModel realm = session.realms().getRealmByName("test");
+ assertTrue(realm instanceof RealmAdapter);
ClientModel testApp = realm.getClientByClientId("test-app");
+ assertTrue(testApp instanceof ClientAdapter);
assertNotNull(testApp);
appId = testApp.getId();
- Assert.assertTrue(testApp.isEnabled());
+ assertTrue(testApp.isEnabled());
kc.stopSession(session, true);
}
{
@@ -40,16 +44,18 @@ public class CacheTest {
// KEYCLOAK-1240 - obtain the realm via session.realms().getRealms()
RealmModel realm = null;
List<RealmModel> realms = session.realms().getRealms();
+
for (RealmModel current : realms) {
+ assertTrue(current instanceof RealmAdapter);
if ("test".equals(current.getName())) {
realm = current;
break;
}
}
- Assert.assertTrue(realm instanceof RealmAdapter);
realm.setAccessCodeLifespanLogin(200);
ClientModel testApp = realm.getClientByClientId("test-app");
+
assertNotNull(testApp);
testApp.setEnabled(false);
kc.stopSession(session, true);
@@ -62,10 +68,7 @@ public class CacheTest {
ClientModel testApp = session.realms().getClientById(appId, realm);
Assert.assertFalse(testApp.isEnabled());
kc.stopSession(session, true);
-
}
-
-
}
@Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
index 0d12caf..ab93b1c 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
@@ -11,6 +11,7 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
@@ -26,6 +27,7 @@ import org.keycloak.services.managers.UserManager;
import org.keycloak.services.managers.UserSessionManager;
import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.common.util.Time;
+import org.keycloak.testsuite.rule.LoggingRule;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -35,6 +37,9 @@ public class UserSessionProviderOfflineTest {
@ClassRule
public static KeycloakRule kc = new KeycloakRule();
+ @Rule
+ public LoggingRule loggingRule = new LoggingRule(this);
+
private KeycloakSession session;
private RealmModel realm;
private UserSessionManager sessionManager;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LoggingRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LoggingRule.java
new file mode 100644
index 0000000..fdcec66
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LoggingRule.java
@@ -0,0 +1,38 @@
+package org.keycloak.testsuite.rule;
+
+import org.jboss.logging.Logger;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class LoggingRule implements TestRule {
+
+ private final Logger log;
+
+ public LoggingRule(Object test) {
+ log = Logger.getLogger(test.getClass());
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ log.debugf("Before %s", description.getMethodName());
+
+ try {
+ base.evaluate();
+ } finally {
+ log.debugf("After %s", description.getMethodName());
+ }
+
+ }
+
+ };
+ }
+
+}
diff --git a/testsuite/integration/src/test/resources/log4j.properties b/testsuite/integration/src/test/resources/log4j.properties
index 5bccb0e..3a6fe1d 100755
--- a/testsuite/integration/src/test/resources/log4j.properties
+++ b/testsuite/integration/src/test/resources/log4j.properties
@@ -14,6 +14,10 @@ log4j.logger.org.keycloak=info
# log4j.logger.org.keycloak.provider.ProviderManager=debug
# log4j.logger.org.keycloak.provider.FileSystemProviderLoaderFactory=debug
+# Broker logging
+keycloak.testsuite.logging.level=info
+log4j.logger.org.keycloak.testsuite=${keycloak.testsuite.logging.level}
+
# Liquibase updates logged with "info" by default. Logging level can be changed by system property "keycloak.liquibase.logging.level"
keycloak.liquibase.logging.level=info
log4j.logger.org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider=${keycloak.liquibase.logging.level}
@@ -21,13 +25,16 @@ log4j.logger.org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterP
# Enable to view infinispan initialization
# log4j.logger.org.keycloak.models.sessions.infinispan.initializer=trace
+# Enable to view cache activity
+# log4j.logger.org.keycloak.models.cache=trace
+
# Enable to view database updates
# log4j.logger.org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider=debug
# log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug
# log4j.logger.org.keycloak.migration.MigrationModelManager=debug
# Enable to view kerberos/spnego logging
-# log4j.logger.org.keycloak.broker.kerberos=trace
+# log4j.logger.org.keycloak.federation.kerberos=trace
# Enable to view detailed AS REQ and TGS REQ requests to embedded Kerberos server
# log4j.logger.org.apache.directory.server.kerberos=debug
@@ -36,4 +43,5 @@ log4j.logger.org.xnio=off
log4j.logger.org.hibernate=off
log4j.logger.org.jboss.resteasy=warn
log4j.logger.org.apache.directory.api=warn
-log4j.logger.org.apache.directory.server.core=warn
\ No newline at end of file
+log4j.logger.org.apache.directory.server.core=warn
+log4j.logger.org.apache.directory.server.ldap.LdapProtocolHandler=error
\ No newline at end of file
diff --git a/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java b/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java
index ff4cf35..7be53c6 100644
--- a/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java
+++ b/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java
@@ -154,9 +154,9 @@ public class AddUser {
roles = rolesString.split(",");
} else {
if (realmName.equals("master")) {
- roles = new String[] { "admin", "account/manage-account" };
+ roles = new String[] { "admin" };
} else {
- roles = new String[] { "realm-management/realm-admin", "account/manage-account" };
+ roles = new String[] { "realm-management/realm-admin" };
}
}