keycloak-memoizeit
Changes
model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserGroupMembershipEntity.java 2(+1 -1)
model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserRequiredActionEntity.java 1(+1 -0)
server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java 15(+15 -0)
server-spi/src/main/java/org/keycloak/storage/federated/UserGroupMembershipFederatedStorage.java 4(+2 -2)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserFederationStorageTest.java 87(+87 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java 85(+84 -1)
Details
diff --git a/common/src/main/java/org/keycloak/common/util/reflections/Types.java b/common/src/main/java/org/keycloak/common/util/reflections/Types.java
index e6787be..adf8626 100644
--- a/common/src/main/java/org/keycloak/common/util/reflections/Types.java
+++ b/common/src/main/java/org/keycloak/common/util/reflections/Types.java
@@ -17,7 +17,14 @@
package org.keycloak.common.util.reflections;
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.HashMap;
+import java.util.Map;
/**
* Utility class for Types
@@ -68,4 +75,564 @@ public class Types {
return type;
}
}
+
+ /**
+ * Is the genericType of a certain class?
+ */
+ public static boolean isA(Class clazz, ParameterizedType pType)
+ {
+ return clazz.isAssignableFrom((Class) pType.getRawType());
+ }
+
+ /**
+ * Gets the index-th type argument.
+ */
+ public static Class getArgumentType(ParameterizedType pType, int index)
+ {
+ return (Class) pType.getActualTypeArguments()[index];
+ }
+
+ public static Class getTemplateParameterOfInterface(Class base, Class desiredInterface)
+ {
+ Object rtn = searchForInterfaceTemplateParameter(base, desiredInterface);
+ if (rtn != null && rtn instanceof Class) return (Class) rtn;
+ return null;
+ }
+
+
+ private static Object searchForInterfaceTemplateParameter(Class base, Class desiredInterface)
+ {
+ for (int i = 0; i < base.getInterfaces().length; i++)
+ {
+ Class intf = base.getInterfaces()[i];
+ if (intf.equals(desiredInterface))
+ {
+ Type generic = base.getGenericInterfaces()[i];
+ if (generic instanceof ParameterizedType)
+ {
+ ParameterizedType p = (ParameterizedType) generic;
+ Type type = p.getActualTypeArguments()[0];
+ Class rtn = getRawTypeNoException(type);
+ if (rtn != null) return rtn;
+ return type;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+ if (base.getSuperclass() == null || base.getSuperclass().equals(Object.class)) return null;
+ Object rtn = searchForInterfaceTemplateParameter(base.getSuperclass(), desiredInterface);
+ if (rtn == null || rtn instanceof Class) return rtn;
+ if (!(rtn instanceof TypeVariable)) return null;
+
+ String name = ((TypeVariable) rtn).getName();
+ int index = -1;
+ TypeVariable[] variables = base.getSuperclass().getTypeParameters();
+ if (variables == null || variables.length < 1) return null;
+
+ for (int i = 0; i < variables.length; i++)
+ {
+ if (variables[i].getName().equals(name)) index = i;
+ }
+ if (index == -1) return null;
+
+
+ Type genericSuperclass = base.getGenericSuperclass();
+ if (!(genericSuperclass instanceof ParameterizedType)) return null;
+
+ ParameterizedType pt = (ParameterizedType) genericSuperclass;
+ Type type = pt.getActualTypeArguments()[index];
+
+ Class clazz = getRawTypeNoException(type);
+ if (clazz != null) return clazz;
+ return type;
+ }
+
+
+ /**
+ * See if the two methods are compatible, that is they have the same relative signature
+ *
+ * @param method
+ * @param intfMethod
+ * @return
+ */
+ public static boolean isCompatible(Method method, Method intfMethod)
+ {
+ if (method == intfMethod) return true;
+
+ if (!method.getName().equals(intfMethod.getName())) return false;
+ if (method.getParameterTypes().length != intfMethod.getParameterTypes().length) return false;
+
+ for (int i = 0; i < method.getParameterTypes().length; i++)
+ {
+ Class rootParam = method.getParameterTypes()[i];
+ Class intfParam = intfMethod.getParameterTypes()[i];
+ if (!intfParam.isAssignableFrom(rootParam)) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Given a method and a root class, find the actual method declared in the root that implements the method.
+ *
+ * @param clazz
+ * @param intfMethod
+ * @return
+ */
+ public static Method getImplementingMethod(Class clazz, Method intfMethod)
+ {
+ Class<?> declaringClass = intfMethod.getDeclaringClass();
+ if (declaringClass.equals(clazz)) return intfMethod;
+
+ Class[] paramTypes = intfMethod.getParameterTypes();
+
+ if (declaringClass.getTypeParameters().length > 0 && paramTypes.length > 0)
+ {
+ Type[] intfTypes = findParameterizedTypes(clazz, declaringClass);
+ Map<String, Type> typeVarMap = new HashMap<String, Type>();
+ TypeVariable<? extends Class<?>>[] vars = declaringClass.getTypeParameters();
+ for (int i = 0; i < vars.length; i++)
+ {
+ if (intfTypes != null && i < intfTypes.length)
+ {
+ typeVarMap.put(vars[i].getName(), intfTypes[i]);
+ }
+ else
+ {
+ // Interface type parameters may not have been filled out
+ typeVarMap.put(vars[i].getName(), vars[i].getGenericDeclaration());
+ }
+ }
+ Type[] paramGenericTypes = intfMethod.getGenericParameterTypes();
+ paramTypes = new Class[paramTypes.length];
+
+ for (int i = 0; i < paramTypes.length; i++)
+ {
+ if (paramGenericTypes[i] instanceof TypeVariable)
+ {
+ TypeVariable tv = (TypeVariable)paramGenericTypes[i];
+ Type t = typeVarMap.get(tv.getName());
+ if (t == null)
+ {
+ throw new RuntimeException("Unable to resolve type variable");
+ }
+ paramTypes[i] = getRawType(t);
+ }
+ else
+ {
+ paramTypes[i] = getRawType(paramGenericTypes[i]);
+ }
+ }
+
+ }
+
+ try
+ {
+ return clazz.getMethod(intfMethod.getName(), paramTypes);
+ }
+ catch (NoSuchMethodException e)
+ {
+ }
+
+ try
+ {
+ Method tmp = clazz.getMethod(intfMethod.getName(), intfMethod.getParameterTypes());
+ return tmp;
+ }
+ catch (NoSuchMethodException e)
+ {
+
+ }
+ return intfMethod;
+ }
+
+
+ public static Class<?> getRawType(Type type)
+ {
+ if (type instanceof Class<?>)
+ {
+ // type is a normal class.
+ return (Class<?>) type;
+
+ }
+ else if (type instanceof ParameterizedType)
+ {
+ ParameterizedType parameterizedType = (ParameterizedType) type;
+ Type rawType = parameterizedType.getRawType();
+ return (Class<?>) rawType;
+ }
+ else if (type instanceof GenericArrayType)
+ {
+ final GenericArrayType genericArrayType = (GenericArrayType) type;
+ final Class<?> componentRawType = getRawType(genericArrayType.getGenericComponentType());
+ return Array.newInstance(componentRawType, 0).getClass();
+ }
+ else if (type instanceof TypeVariable)
+ {
+ final TypeVariable typeVar = (TypeVariable) type;
+ if (typeVar.getBounds() != null && typeVar.getBounds().length > 0)
+ {
+ return getRawType(typeVar.getBounds()[0]);
+ }
+ }
+ throw new RuntimeException("unable to determine base class");
+ }
+
+
+ public static Class<?> getRawTypeNoException(Type type)
+ {
+ if (type instanceof Class<?>)
+ {
+ // type is a normal class.
+ return (Class<?>) type;
+
+ }
+ else if (type instanceof ParameterizedType)
+ {
+ ParameterizedType parameterizedType = (ParameterizedType) type;
+ Type rawType = parameterizedType.getRawType();
+ return (Class<?>) rawType;
+ }
+ else if (type instanceof GenericArrayType)
+ {
+ final GenericArrayType genericArrayType = (GenericArrayType) type;
+ final Class<?> componentRawType = getRawType(genericArrayType.getGenericComponentType());
+ return Array.newInstance(componentRawType, 0).getClass();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the type argument from a parameterized type
+ *
+ * @param genericType
+ * @return null if there is no type parameter
+ */
+ public static Class<?> getTypeArgument(Type genericType)
+ {
+ if (!(genericType instanceof ParameterizedType)) return null;
+ ParameterizedType parameterizedType = (ParameterizedType) genericType;
+ Class<?> typeArg = (Class<?>) parameterizedType.getActualTypeArguments()[0];
+ return typeArg;
+ }
+
+
+ public static Class getCollectionBaseType(Class type, Type genericType)
+ {
+ if (genericType instanceof ParameterizedType)
+ {
+ ParameterizedType parameterizedType = (ParameterizedType) genericType;
+ Type componentGenericType = parameterizedType.getActualTypeArguments()[0];
+ return getRawType(componentGenericType);
+ }
+ else if (genericType instanceof GenericArrayType)
+ {
+ final GenericArrayType genericArrayType = (GenericArrayType) genericType;
+ Type componentGenericType = genericArrayType.getGenericComponentType();
+ return getRawType(componentGenericType);
+ }
+ else if (type.isArray())
+ {
+ return type.getComponentType();
+ }
+ return null;
+ }
+
+
+ public static Class getMapKeyType(Type genericType)
+ {
+ if (genericType instanceof ParameterizedType)
+ {
+ ParameterizedType parameterizedType = (ParameterizedType) genericType;
+ Type componentGenericType = parameterizedType.getActualTypeArguments()[0];
+ return getRawType(componentGenericType);
+ }
+ return null;
+ }
+
+ public static Class getMapValueType(Type genericType)
+ {
+ if (genericType instanceof ParameterizedType)
+ {
+ ParameterizedType parameterizedType = (ParameterizedType) genericType;
+ Type componentGenericType = parameterizedType.getActualTypeArguments()[1];
+ return getRawType(componentGenericType);
+ }
+ return null;
+ }
+
+ public static Type resolveTypeVariables(Class<?> root, Type type)
+ {
+ if (type instanceof TypeVariable)
+ {
+ Type newType = resolveTypeVariable(root, (TypeVariable)type);
+ return (newType == null) ? type : newType;
+ }
+ else if (type instanceof ParameterizedType)
+ {
+ final ParameterizedType param = (ParameterizedType)type;
+ final Type[] actuals = new Type[param.getActualTypeArguments().length];
+ for (int i = 0; i < actuals.length; i++)
+ {
+ Type newType = resolveTypeVariables(root, param.getActualTypeArguments()[i]);
+ actuals[i] = newType == null ? param.getActualTypeArguments()[i] : newType;
+ }
+ return new ParameterizedType() {
+ @Override
+ public Type[] getActualTypeArguments()
+ {
+ return actuals;
+ }
+
+ @Override
+ public Type getRawType()
+ {
+ return param.getRawType();
+ }
+
+ @Override
+ public Type getOwnerType()
+ {
+ return param.getOwnerType();
+ }
+ };
+ }
+ else if (type instanceof GenericArrayType)
+ {
+ GenericArrayType arrayType = (GenericArrayType)type;
+ final Type componentType = resolveTypeVariables(root, arrayType.getGenericComponentType());
+ if (componentType == null) return type;
+ return new GenericArrayType()
+ {
+ @Override
+ public Type getGenericComponentType()
+ {
+ return componentType;
+ }
+ };
+ }
+ else
+ {
+ return type;
+ }
+ }
+
+
+ /**
+ * Finds an actual value of a type variable. The method looks in a class hierarchy for a class defining the variable
+ * and returns the value if present.
+ *
+ * @param root
+ * @param typeVariable
+ * @return actual type of the type variable
+ */
+ public static Type resolveTypeVariable(Class<?> root, TypeVariable<?> typeVariable)
+ {
+ if (typeVariable.getGenericDeclaration() instanceof Class<?>)
+ {
+ Class<?> classDeclaringTypeVariable = (Class<?>) typeVariable.getGenericDeclaration();
+ Type[] types = findParameterizedTypes(root, classDeclaringTypeVariable);
+ if (types == null) return null;
+ for (int i = 0; i < types.length; i++)
+ {
+ TypeVariable<?> tv = classDeclaringTypeVariable.getTypeParameters()[i];
+ if (tv.equals(typeVariable))
+ {
+ return types[i];
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Given a class and an interfaces, go through the class hierarchy to find the interface and return its type arguments.
+ *
+ * @param classToSearch
+ * @param interfaceToFind
+ * @return type arguments of the interface
+ */
+ public static Type[] getActualTypeArgumentsOfAnInterface(Class<?> classToSearch, Class<?> interfaceToFind)
+ {
+ Type[] types = findParameterizedTypes(classToSearch, interfaceToFind);
+ if (types == null) throw new RuntimeException("Unable to find type arguments");
+ return types;
+ }
+
+ private static final Type[] EMPTY_TYPE_ARRAY = {};
+
+ /**
+ * Search for the given interface or class within the root's class/interface hierarchy.
+ * If the searched for class/interface is a generic return an array of real types that fill it out.
+ *
+ * @param root
+ * @param searchedFor
+ * @return
+ */
+ public static Type[] findParameterizedTypes(Class<?> root, Class<?> searchedFor)
+ {
+ if (searchedFor.isInterface())
+ {
+ return findInterfaceParameterizedTypes(root, null, searchedFor);
+ }
+ return findClassParameterizedTypes(root, null, searchedFor);
+ }
+
+ public static Type[] findClassParameterizedTypes(Class<?> root, ParameterizedType rootType, Class<?> searchedForClass)
+ {
+ if (Object.class.equals(root)) return null;
+
+ Map<String, Type> typeVarMap = populateParameterizedMap(root, rootType);
+
+ Class<?> superclass = root.getSuperclass();
+ Type genericSuper = root.getGenericSuperclass();
+
+ if (superclass.equals(searchedForClass))
+ {
+ return extractTypes(typeVarMap, genericSuper);
+ }
+
+
+ if (genericSuper instanceof ParameterizedType)
+ {
+ ParameterizedType intfParam = (ParameterizedType) genericSuper;
+ Type[] types = findClassParameterizedTypes(superclass, intfParam, searchedForClass);
+ if (types != null)
+ {
+ return extractTypeVariables(typeVarMap, types);
+ }
+ }
+ else
+ {
+ Type[] types = findClassParameterizedTypes(superclass, null, searchedForClass);
+ if (types != null)
+ {
+ return types;
+ }
+ }
+ return null;
+ }
+
+ private static Map<String, Type> populateParameterizedMap(Class<?> root, ParameterizedType rootType)
+ {
+ Map<String, Type> typeVarMap = new HashMap<String, Type>();
+ if (rootType != null)
+ {
+ TypeVariable<? extends Class<?>>[] vars = root.getTypeParameters();
+ for (int i = 0; i < vars.length; i++)
+ {
+ typeVarMap.put(vars[i].getName(), rootType.getActualTypeArguments()[i]);
+ }
+ }
+ return typeVarMap;
+ }
+
+
+ public static Type[] findInterfaceParameterizedTypes(Class<?> root, ParameterizedType rootType, Class<?> searchedForInterface)
+ {
+ Map<String, Type> typeVarMap = populateParameterizedMap(root, rootType);
+
+ for (int i = 0; i < root.getInterfaces().length; i++)
+ {
+ Class<?> sub = root.getInterfaces()[i];
+ Type genericSub = root.getGenericInterfaces()[i];
+ if (sub.equals(searchedForInterface))
+ {
+ return extractTypes(typeVarMap, genericSub);
+ }
+ }
+
+ for (int i = 0; i < root.getInterfaces().length; i++)
+ {
+ Type genericSub = root.getGenericInterfaces()[i];
+ Class<?> sub = root.getInterfaces()[i];
+
+ Type[] types = recurseSuperclassForInterface(searchedForInterface, typeVarMap, genericSub, sub);
+ if (types != null) return types;
+ }
+ if (root.isInterface()) return null;
+
+ Class<?> superclass = root.getSuperclass();
+ Type genericSuper = root.getGenericSuperclass();
+
+
+ return recurseSuperclassForInterface(searchedForInterface, typeVarMap, genericSuper, superclass);
+ }
+
+ private static Type[] recurseSuperclassForInterface(Class<?> searchedForInterface, Map<String, Type> typeVarMap, Type genericSub, Class<?> sub)
+ {
+ if (genericSub instanceof ParameterizedType)
+ {
+ ParameterizedType intfParam = (ParameterizedType) genericSub;
+ Type[] types = findInterfaceParameterizedTypes(sub, intfParam, searchedForInterface);
+ if (types != null)
+ {
+ return extractTypeVariables(typeVarMap, types);
+ }
+ }
+ else
+ {
+ Type[] types = findInterfaceParameterizedTypes(sub, null, searchedForInterface);
+ if (types != null)
+ {
+ return types;
+ }
+ }
+ return null;
+ }
+
+ private static Type[] extractTypeVariables(Map<String, Type> typeVarMap, Type[] types)
+ {
+ for (int j = 0; j < types.length; j++)
+ {
+ if (types[j] instanceof TypeVariable)
+ {
+ TypeVariable tv = (TypeVariable) types[j];
+ types[j] = typeVarMap.get(tv.getName());
+ }
+ else
+ {
+ types[j] = types[j];
+ }
+ }
+ return types;
+ }
+
+ private static Type[] extractTypes(Map<String, Type> typeVarMap, Type genericSub)
+ {
+ if (genericSub instanceof ParameterizedType)
+ {
+ ParameterizedType param = (ParameterizedType) genericSub;
+ Type[] types = param.getActualTypeArguments();
+ Type[] returnTypes = new Type[types.length];
+ System.arraycopy(types, 0, returnTypes, 0, types.length);
+ extractTypeVariables(typeVarMap, returnTypes);
+ return returnTypes;
+ }
+ else
+ {
+ return EMPTY_TYPE_ARRAY;
+ }
+ }
+
+ /**
+ * Grabs the parameterized type of fromInterface
+ * that object implements and sees if it is assignable from type.
+ *
+ * @param type
+ * @param object
+ * @param fromInterface
+ * @param <T>
+ * @return
+ */
+ public static <T> boolean supports(Class<T> type, Object object, Class<?> fromInterface) {
+ Type providerType = getActualTypeArgumentsOfAnInterface(object.getClass(), fromInterface)[0];
+ Class providerClass = getRawType(providerType);
+ return type.isAssignableFrom(providerClass);
+ }
+
+
}
\ No newline at end of file
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserAttributeEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserAttributeEntity.java
index 071eacd..c5e6193 100755
--- a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserAttributeEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserAttributeEntity.java
@@ -32,7 +32,7 @@ import javax.persistence.Table;
* @version $Revision: 1 $
*/
@NamedQueries({
- @NamedQuery(name="getFederatedAttributesByNameAndValue", query="select attr from FederatedUserAttributeEntity attr where attr.name = :name and attr.value = :value and attr.realmId=:realmId"),
+ @NamedQuery(name="getFederatedAttributesByNameAndValue", query="select attr.userId from FederatedUserAttributeEntity attr where attr.name = :name and attr.value = :value and attr.realmId=:realmId"),
@NamedQuery(name="getFederatedAttributesByUser", query="select attr from FederatedUserAttributeEntity attr where attr.userId = :userId and attr.realmId=:realmId"),
@NamedQuery(name="deleteUserFederatedAttributesByUser", query="delete from FederatedUserAttributeEntity attr where attr.userId = :userId and attr.realmId=:realmId"),
@NamedQuery(name="deleteUserFederatedAttributesByUserAndName", query="delete from FederatedUserAttributeEntity attr where attr.userId = :userId and attr.name=:name and attr.realmId=:realmId"),
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserGroupMembershipEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserGroupMembershipEntity.java
index ecfaa49..3116a0a 100755
--- a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserGroupMembershipEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserGroupMembershipEntity.java
@@ -35,7 +35,7 @@ import java.io.Serializable;
@NamedQueries({
@NamedQuery(name="feduserMemberOf", query="select m from FederatedUserGroupMembershipEntity m where m.userId = :userId and m.groupId = :groupId"),
@NamedQuery(name="feduserGroupMembership", query="select m from FederatedUserGroupMembershipEntity m where m.userId = :userId"),
- @NamedQuery(name="fedgroupMembership", query="select g.userId from FederatedUserGroupMembershipEntity g where g.groupId = :groupId"),
+ @NamedQuery(name="fedgroupMembership", query="select g.userId from FederatedUserGroupMembershipEntity g where g.groupId = :groupId and g.realmId = :realmId"),
@NamedQuery(name="feduserGroupIds", query="select m.groupId from FederatedUserGroupMembershipEntity m where m.userId = :userId"),
@NamedQuery(name="deleteFederatedUserGroupMembershipByRealm", query="delete from FederatedUserGroupMembershipEntity mapping where mapping.realmId=:realmId"),
@NamedQuery(name="deleteFederatedUserGroupMembershipByStorageProvider", query="delete from FederatedUserGroupMembershipEntity e where e.storageProviderId=:storageProviderId"),
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserRequiredActionEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserRequiredActionEntity.java
index f555628..f30aee6 100755
--- a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserRequiredActionEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserRequiredActionEntity.java
@@ -37,6 +37,7 @@ import java.io.Serializable;
*/
@NamedQueries({
@NamedQuery(name="getFederatedUserRequiredActionsByUser", query="select action from FederatedUserRequiredActionEntity action where action.userId = :userId and action.realmId=:realmId"),
+ @NamedQuery(name="deleteFederatedUserRequiredActionsByUser", query="delete from FederatedUserRequiredActionEntity action where action.realmId=:realmId and action.userId = :userId"),
@NamedQuery(name="deleteFederatedUserRequiredActionsByRealm", query="delete from FederatedUserRequiredActionEntity action where action.realmId=:realmId"),
@NamedQuery(name="deleteFederatedUserRequiredActionsByStorageProvider", query="delete from FederatedUserRequiredActionEntity e where e.storageProviderId=:storageProviderId"),
@NamedQuery(name="deleteFederatedUserRequiredActionsByRealmAndLink", query="delete from FederatedUserRequiredActionEntity action where action.userId IN (select u.id from UserEntity u where u.realmId=:realmId and u.federationLink=:link)")
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java
index 4ec58bd..d64a3ea 100644
--- a/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java
@@ -148,6 +148,15 @@ public class JpaUserFederatedStorageProvider implements
}
@Override
+ public List<String> getUsersByUserAttribute(RealmModel realm, String name, String value) {
+ TypedQuery<String> query = em.createNamedQuery("getFederatedAttributesByNameAndValue", String.class)
+ .setParameter("realmId", realm.getId())
+ .setParameter("name", name)
+ .setParameter("value", value);
+ return query.getResultList();
+ }
+
+ @Override
public String getUserByFederatedIdentity(FederatedIdentityModel link, RealmModel realm) {
TypedQuery<String> query = em.createNamedQuery("findUserByBrokerLinkAndRealm", String.class)
.setParameter("realmId", realm.getId())
@@ -508,6 +517,15 @@ public class JpaUserFederatedStorageProvider implements
}
+ @Override
+ public List<String> getMembership(RealmModel realm, GroupModel group, int firstResult, int max) {
+ TypedQuery<String> query = em.createNamedQuery("fedgroupMembership", String.class)
+ .setParameter("realmId", realm.getId())
+ .setParameter("groupId", group.getId());
+ query.setFirstResult(firstResult);
+ query.setMaxResults(max);
+ return query.getResultList();
+ }
@Override
public Set<String> getRequiredActions(RealmModel realm, UserModel user) {
@@ -689,7 +707,7 @@ public class JpaUserFederatedStorageProvider implements
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.executeUpdate();
- em.createNamedQuery("getFederatedUserRequiredActionsByUser")
+ em.createNamedQuery("deleteFederatedUserRequiredActionsByUser")
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.executeUpdate();
diff --git a/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapter.java b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapter.java
index 1d3ff73..45c6168 100644
--- a/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapter.java
+++ b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapter.java
@@ -402,4 +402,19 @@ public abstract class AbstractUserAdapter implements UserModel {
throw new ReadOnlyException("user is read only for this update");
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof UserModel)) return false;
+
+ UserModel that = (UserModel) o;
+ return that.getId().equals(getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
}
diff --git a/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java
index bcc2651..b09ceae 100644
--- a/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java
+++ b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java
@@ -416,4 +416,19 @@ public abstract class AbstractUserAdapterFederatedStorage implements UserModel {
getFederatedStorage().updateCredential(realm, this, cred);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof UserModel)) return false;
+
+ UserModel that = (UserModel) o;
+ return that.getId().equals(getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserAttributeFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserAttributeFederatedStorage.java
index 12bcabf..08755da 100644
--- a/server-spi/src/main/java/org/keycloak/storage/federated/UserAttributeFederatedStorage.java
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserAttributeFederatedStorage.java
@@ -22,6 +22,7 @@ import org.keycloak.models.UserModel;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -32,4 +33,5 @@ public interface UserAttributeFederatedStorage {
void setAttribute(RealmModel realm, UserModel user, String name, List<String> values);
void removeAttribute(RealmModel realm, UserModel user, String name);
MultivaluedHashMap<String, String> getAttributes(RealmModel realm, UserModel user);
+ List<String> getUsersByUserAttribute(RealmModel realm, String name, String value);
}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserGroupMembershipFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserGroupMembershipFederatedStorage.java
index fef3cee..dad2399 100644
--- a/server-spi/src/main/java/org/keycloak/storage/federated/UserGroupMembershipFederatedStorage.java
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserGroupMembershipFederatedStorage.java
@@ -20,6 +20,7 @@ import org.keycloak.models.GroupModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
+import java.util.List;
import java.util.Set;
/**
@@ -28,9 +29,8 @@ import java.util.Set;
*/
public interface UserGroupMembershipFederatedStorage {
Set<GroupModel> getGroups(RealmModel realm, UserModel user);
-
void joinGroup(RealmModel realm,UserModel user, GroupModel group);
-
void leaveGroup(RealmModel realm,UserModel user, GroupModel group);
+ List<String> getMembership(RealmModel realm, GroupModel group, int firstResult, int max);
}
diff --git a/server-spi/src/main/java/org/keycloak/storage/StorageProviderFactory.java b/server-spi/src/main/java/org/keycloak/storage/StorageProviderFactory.java
index 3369da2..e4f2717 100755
--- a/server-spi/src/main/java/org/keycloak/storage/StorageProviderFactory.java
+++ b/server-spi/src/main/java/org/keycloak/storage/StorageProviderFactory.java
@@ -26,8 +26,7 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public interface StorageProviderFactory extends ProviderFactory<StorageProvider> {
- boolean supports(Class<?> type);
+public interface StorageProviderFactory<T extends StorageProvider> extends ProviderFactory<StorageProvider> {
/**
* called per Keycloak transaction.
*
@@ -35,14 +34,7 @@ public interface StorageProviderFactory extends ProviderFactory<StorageProvider>
* @param model
* @return
*/
- StorageProvider getInstance(KeycloakSession session, StorageProviderModel model);
-
- /**
- * Config options to display in generic admin console page for federated
- *
- * @return
- */
- Set<String> getConfigurationOptions();
+ T getInstance(KeycloakSession session, StorageProviderModel model);
/**
* This is the name of the provider and will be showed in the admin console as an option.
diff --git a/server-spi/src/main/java/org/keycloak/storage/UserStorageManager.java b/server-spi/src/main/java/org/keycloak/storage/UserStorageManager.java
index 72e4280..db39190 100755
--- a/server-spi/src/main/java/org/keycloak/storage/UserStorageManager.java
+++ b/server-spi/src/main/java/org/keycloak/storage/UserStorageManager.java
@@ -18,6 +18,7 @@
package org.keycloak.storage;
import org.jboss.logging.Logger;
+import org.keycloak.common.util.reflections.Types;
import org.keycloak.models.ClientModel;
import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.FederatedIdentityModel;
@@ -42,6 +43,7 @@ import org.keycloak.models.utils.CredentialValidation;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -79,18 +81,20 @@ public class UserStorageManager implements UserProvider {
protected <T> T getFirstStorageProvider(RealmModel realm, Class<T> type) {
for (StorageProviderModel model : getStorageProviders(realm)) {
StorageProviderFactory factory = (StorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
- if (factory.supports(type)) {
+
+ if (Types.supports(type, factory, StorageProviderFactory.class)) {
return type.cast(factory.getInstance(session, model));
}
}
return null;
}
+
protected <T> List<T> getStorageProviders(RealmModel realm, Class<T> type) {
List<T> list = new LinkedList<>();
for (StorageProviderModel model : getStorageProviders(realm)) {
StorageProviderFactory factory = (StorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
- if (factory.supports(type)) {
+ if (Types.supports(type, factory, StorageProviderFactory.class)) {
list.add(type.cast(factory.getInstance(session, model)));
}
@@ -130,6 +134,7 @@ public class UserStorageManager implements UserProvider {
@Override
public boolean removeUser(RealmModel realm, UserModel user) {
+ getFederatedStorage().preRemove(realm, user);
StorageId storageId = new StorageId(user.getId());
if (storageId.getProviderId() == null) {
return localStorage().removeUser(realm, user);
@@ -299,29 +304,33 @@ public class UserStorageManager implements UserProvider {
return size;
}
+ @FunctionalInterface
interface PaginatedQuery {
- List<UserModel> query(UserQueryProvider provider, int first, int max);
+ List<UserModel> query(Object provider, int first, int max);
}
protected List<UserModel> query(PaginatedQuery pagedQuery, RealmModel realm, int firstResult, int maxResults) {
- List<UserModel> results = new LinkedList<UserModel>();
- if (maxResults == 0) return results;
+ if (maxResults == 0) return Collections.EMPTY_LIST;
+
List<UserQueryProvider> storageProviders = getStorageProviders(realm, UserQueryProvider.class);
- LinkedList<UserQueryProvider> providers = new LinkedList<>();
- if (providers.isEmpty()) {
+ // we can skip rest of method if there are no storage providers
+ if (storageProviders.isEmpty()) {
return pagedQuery.query(localStorage(), firstResult, maxResults);
}
+ LinkedList<Object> providers = new LinkedList<>();
+ List<UserModel> results = new LinkedList<UserModel>();
providers.add(localStorage());
providers.addAll(storageProviders);
+ providers.add(getFederatedStorage());
int leftToRead = maxResults;
int leftToFirstResult = firstResult;
- Iterator<UserQueryProvider> it = providers.iterator();
+ Iterator<Object> it = providers.iterator();
while (it.hasNext() && leftToRead != 0) {
- UserQueryProvider provider = it.next();
+ Object provider = it.next();
boolean exhausted = false;
int index = 0;
if (leftToFirstResult > 0) {
@@ -341,20 +350,22 @@ public class UserStorageManager implements UserProvider {
results.addAll(tmp);
if (leftToRead > 0) leftToRead -= tmp.size();
}
+
return results;
}
@Override
public List<UserModel> getUsers(final RealmModel realm, int firstResult, int maxResults, final boolean includeServiceAccounts) {
- return query(new PaginatedQuery() {
- @Override
- public List<UserModel> query(UserQueryProvider provider, int first, int max) {
- if (provider instanceof UserProvider) { // it is local storage
- return ((UserProvider)provider).getUsers(realm, first, max, includeServiceAccounts);
- }
- return provider.getUsers(realm, first, max);
+ return query((provider, first, max) -> {
+ if (provider instanceof UserProvider) { // it is local storage
+ return ((UserProvider) provider).getUsers(realm, first, max, includeServiceAccounts);
+ } else if (provider instanceof UserQueryProvider) {
+ return ((UserQueryProvider)provider).getUsers(realm, first, max);
+
}
- }, realm, firstResult, maxResults);
+ return Collections.EMPTY_LIST;
+ }
+ , realm, firstResult, maxResults);
}
@Override
@@ -363,12 +374,13 @@ public class UserStorageManager implements UserProvider {
}
@Override
- public List<UserModel> searchForUser(final String search, final RealmModel realm, int firstResult, int maxResults) {
- return query(new PaginatedQuery() {
- @Override
- public List<UserModel> query(UserQueryProvider provider, int first, int max) {
- return provider.searchForUser(search, realm, first, max);
+ public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
+ return query((provider, first, max) -> {
+ if (provider instanceof UserQueryProvider) {
+ return ((UserQueryProvider)provider).searchForUser(search, realm, first, max);
+
}
+ return Collections.EMPTY_LIST;
}, realm, firstResult, maxResults);
}
@@ -378,23 +390,36 @@ public class UserStorageManager implements UserProvider {
}
@Override
- public List<UserModel> searchForUserByAttributes(final Map<String, String> attributes, final RealmModel realm, int firstResult, int maxResults) {
- return query(new PaginatedQuery() {
- @Override
- public List<UserModel> query(UserQueryProvider provider, int first, int max) {
- return provider.searchForUserByAttributes(attributes, realm, first, max);
+ public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
+ return query((provider, first, max) -> {
+ if (provider instanceof UserQueryProvider) {
+ return ((UserQueryProvider)provider).searchForUserByAttributes(attributes, realm, first, max);
+
}
- }, realm, firstResult, maxResults);
+ return Collections.EMPTY_LIST;
+ }
+ , realm, firstResult, maxResults);
}
@Override
- public List<UserModel> searchForUserByUserAttribute(final String attrName, final String attrValue, RealmModel realm) {
- return query(new PaginatedQuery() {
- @Override
- public List<UserModel> query(UserQueryProvider provider, int first, int max) {
- return provider.searchForUserByUserAttribute(attrName, attrValue, realm);
+ public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
+ List<UserModel> results = query((provider, first, max) -> {
+ if (provider instanceof UserQueryProvider) {
+ return ((UserQueryProvider)provider).searchForUserByUserAttribute(attrName, attrValue, realm);
+
+ } else if (provider instanceof UserFederatedStorageProvider) {
+ List<String> ids = ((UserFederatedStorageProvider)provider).getUsersByUserAttribute(realm, attrName, attrValue);
+ List<UserModel> rs = new LinkedList<>();
+ for (String id : ids) {
+ UserModel user = getUserById(id, realm);
+ if (user != null) rs.add(user);
+ }
+ return rs;
+
}
+ return Collections.EMPTY_LIST;
}, realm,0, Integer.MAX_VALUE - 1);
+ return results;
}
@Override
@@ -432,12 +457,23 @@ public class UserStorageManager implements UserProvider {
@Override
public List<UserModel> getGroupMembers(final RealmModel realm, final GroupModel group, int firstResult, int maxResults) {
- return query(new PaginatedQuery() {
- @Override
- public List<UserModel> query(UserQueryProvider provider, int first, int max) {
- return provider.getGroupMembers(realm, group, first, max);
+ List<UserModel> results = query((provider, first, max) -> {
+ if (provider instanceof UserQueryProvider) {
+ return ((UserQueryProvider)provider).getGroupMembers(realm, group, first, max);
+
+ } else if (provider instanceof UserFederatedStorageProvider) {
+ List<String> ids = ((UserFederatedStorageProvider)provider).getMembership(realm, group, first, max);
+ List<UserModel> rs = new LinkedList<UserModel>();
+ for (String id : ids) {
+ UserModel user = getUserById(id, realm);
+ if (user != null) rs.add(user);
+ }
+ return rs;
+
}
+ return Collections.EMPTY_LIST;
}, realm, firstResult, maxResults);
+ return results;
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserFederationStorageTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserFederationStorageTest.java
index 6e546a3..2cbf1ba 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserFederationStorageTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserFederationStorageTest.java
@@ -38,6 +38,8 @@ import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.WebDriver;
+import java.util.HashSet;
+import java.util.List;
import java.util.Set;
/**
@@ -146,4 +148,89 @@ public class UserFederationStorageTest {
loginSuccessAndLogout("thor", "lightning");
}
+ @Test
+ public void testQuery() {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+
+ // Test paging
+ List<UserModel> localUsers = session.userLocalStorage().getUsers(realm, false);
+ Set<UserModel> queried = new HashSet<>();
+ // tests assumes that local storage is queried first
+ int first = localUsers.size();
+ while (queried.size() < 8) {
+ List<UserModel> results = session.users().getUsers(realm, first, 3);
+ if (results.size() == 0) break;
+ first += results.size();
+ queried.addAll(results);
+
+ }
+ Set<String> usernames = new HashSet<>();
+ for (UserModel user : queried) {
+ usernames.add(user.getUsername());
+ System.out.println(user.getUsername());
+
+ }
+ Assert.assertEquals(8, queried.size());
+ Assert.assertTrue(usernames.contains("thor"));
+ Assert.assertTrue(usernames.contains("zeus"));
+ Assert.assertTrue(usernames.contains("apollo"));
+ Assert.assertTrue(usernames.contains("perseus"));
+ Assert.assertTrue(usernames.contains("tbrady"));
+ Assert.assertTrue(usernames.contains("rob"));
+ Assert.assertTrue(usernames.contains("jules"));
+ Assert.assertTrue(usernames.contains("danny"));
+
+ // test searchForUser
+ List<UserModel> users = session.users().searchForUser("tbrady", realm);
+ Assert.assertTrue(users.size() == 1);
+ Assert.assertTrue(users.get(0).getUsername().equals("tbrady"));
+
+ // test getGroupMembers()
+ GroupModel gods = realm.createGroup("gods");
+ UserModel user = null;
+ user = session.users().getUserByUsername("apollo", realm);
+ user.joinGroup(gods);
+ user = session.users().getUserByUsername("zeus", realm);
+ user.joinGroup(gods);
+ user = session.users().getUserByUsername("thor", realm);
+ user.joinGroup(gods);
+ queried.clear();
+ usernames.clear();
+
+ first = 0;
+ while (queried.size() < 8) {
+ List<UserModel> results = session.users().getGroupMembers(realm, gods, first, 1);
+ if (results.size() == 0) break;
+ first += results.size();
+ queried.addAll(results);
+
+ }
+ for (UserModel u : queried) {
+ usernames.add(u.getUsername());
+ System.out.println(u.getUsername());
+
+ }
+ Assert.assertEquals(3, queried.size());
+ Assert.assertTrue(usernames.contains("apollo"));
+ Assert.assertTrue(usernames.contains("zeus"));
+ Assert.assertTrue(usernames.contains("thor"));
+
+ // search by single attribute
+ System.out.println("search by single attribute");
+ user = session.users().getUserByUsername("thor", realm);
+ user.setSingleAttribute("weapon", "hammer");
+
+ users = session.users().searchForUserByUserAttribute("weapon", "hammer", realm);
+ for (UserModel u : users) {
+ System.out.println(u.getUsername());
+
+ }
+ Assert.assertEquals(1, users.size());
+ Assert.assertEquals("thor", users.get(0).getUsername());
+
+
+ keycloakRule.stopSession(session, true);
+ }
+
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java
index 52a43ec..cf237e4 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java
@@ -30,15 +30,19 @@ import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.storage.user.UserCredentialValidatorProvider;
import org.keycloak.storage.user.UserLookupProvider;
+import org.keycloak.storage.user.UserQueryProvider;
+import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class UserPropertyFileStorage implements UserLookupProvider, StorageProvider, UserCredentialValidatorProvider {
+public class UserPropertyFileStorage implements UserLookupProvider, StorageProvider, UserCredentialValidatorProvider, UserQueryProvider {
protected Properties userPasswords;
protected StorageProviderModel model;
@@ -129,6 +133,85 @@ public class UserPropertyFileStorage implements UserLookupProvider, StorageProvi
}
@Override
+ public int getUsersCount(RealmModel realm) {
+ return userPasswords.size();
+ }
+
+ @Override
+ public List<UserModel> getUsers(RealmModel realm) {
+ List<UserModel> users = new LinkedList<>();
+ for (Object username : userPasswords.keySet()) {
+ users.add(createUser(realm, (String)username));
+ }
+ return users;
+ }
+
+ @Override
+ public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
+ return Collections.EMPTY_LIST;
+ }
+
+ @Override
+ public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
+ if (maxResults == 0) return Collections.EMPTY_LIST;
+ List<UserModel> users = new LinkedList<>();
+ int count = 0;
+ for (Object un : userPasswords.keySet()) {
+ if (count++ < firstResult) continue;
+ String username = (String)un;
+ users.add(createUser(realm, username));
+ if (users.size() + 1 > maxResults) break;
+ }
+ return users;
+ }
+
+ @Override
+ public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
+ if (maxResults == 0) return Collections.EMPTY_LIST;
+ List<UserModel> users = new LinkedList<>();
+ int count = 0;
+ for (Object un : userPasswords.keySet()) {
+ String username = (String)un;
+ if (username.contains(search)) {
+ if (count++ < firstResult) {
+ continue;
+ }
+ users.add(createUser(realm, username));
+ if (users.size() + 1 > maxResults) break;
+ }
+ }
+ return users;
+ }
+
+ @Override
+ public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
+ if (attributes.size() != 1) return Collections.EMPTY_LIST;
+ String username = attributes.get(UserModel.USERNAME);
+ if (username == null) return Collections.EMPTY_LIST;
+ return searchForUser(username, realm, firstResult, maxResults);
+ }
+
+ @Override
+ public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
+ return Collections.EMPTY_LIST;
+ }
+
+ @Override
+ public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
+ return Collections.EMPTY_LIST;
+ }
+
+ @Override
+ public List<UserModel> searchForUser(String search, RealmModel realm) {
+ return getUsers(realm, 0, Integer.MAX_VALUE - 1);
+ }
+
+ @Override
+ public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
+ return Collections.EMPTY_LIST;
+ }
+
+ @Override
public void close() {
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorageFactory.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorageFactory.java
index d08065c..82d91cf 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorageFactory.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorageFactory.java
@@ -34,18 +34,13 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class UserPropertyFileStorageFactory implements StorageProviderFactory {
+public class UserPropertyFileStorageFactory implements StorageProviderFactory<UserPropertyFileStorage> {
public static final String PROVIDER_ID = "user-password-props";
@Override
- public boolean supports(Class<?> type) {
- return type.isAssignableFrom(UserPropertyFileStorage.class);
- }
-
- @Override
- public StorageProvider getInstance(KeycloakSession session, StorageProviderModel model) {
+ public UserPropertyFileStorage getInstance(KeycloakSession session, StorageProviderModel model) {
Properties props = new Properties();
try {
props.load(getClass().getResourceAsStream(model.getConfig().get("property.file")));
@@ -56,11 +51,6 @@ public class UserPropertyFileStorageFactory implements StorageProviderFactory {
}
@Override
- public Set<String> getConfigurationOptions() {
- return null;
- }
-
- @Override
public String getId() {
return PROVIDER_ID;
}
diff --git a/testsuite/integration/src/test/resources/storage-test/read-only-user-password.properties b/testsuite/integration/src/test/resources/storage-test/read-only-user-password.properties
index 1672680..c0b76ab 100644
--- a/testsuite/integration/src/test/resources/storage-test/read-only-user-password.properties
+++ b/testsuite/integration/src/test/resources/storage-test/read-only-user-password.properties
@@ -1 +1,4 @@
-tbrady=goat
\ No newline at end of file
+tbrady=goat
+rob=pw
+jules=pw
+danny=pw
diff --git a/testsuite/integration/src/test/resources/storage-test/user-password.properties b/testsuite/integration/src/test/resources/storage-test/user-password.properties
index 9dd1c15..a6e28c1 100644
--- a/testsuite/integration/src/test/resources/storage-test/user-password.properties
+++ b/testsuite/integration/src/test/resources/storage-test/user-password.properties
@@ -1 +1,4 @@
-thor=hammer
\ No newline at end of file
+thor=hammer
+zeus=pw
+apollo=pw
+perseus=pw
\ No newline at end of file