keycloak-memoizeit

Added NoSQLQueryBuilder API. Support for persistence of all

9/2/2013 6:43:43 AM

Changes

services/src/main/java/org/keycloak/services/models/nosql/adapters/NoSQLUser.java 46(+0 -46)

Details

diff --git a/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQL.java b/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQL.java
index 9da8166..c3081b0 100644
--- a/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQL.java
+++ b/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQL.java
@@ -1,7 +1,8 @@
 package org.keycloak.services.models.nosql.api;
 
 import java.util.List;
-import java.util.Map;
+
+import org.keycloak.services.models.nosql.api.query.NoSQLQuery;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/api/query/NoSQLQueryBuilder.java b/services/src/main/java/org/keycloak/services/models/nosql/api/query/NoSQLQueryBuilder.java
new file mode 100644
index 0000000..aa4eb48
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/models/nosql/api/query/NoSQLQueryBuilder.java
@@ -0,0 +1,38 @@
+package org.keycloak.services.models.nosql.api.query;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class NoSQLQueryBuilder {
+
+    private Map<String, Object> queryAttributes = new HashMap<String, Object>();
+
+    protected NoSQLQueryBuilder() {};
+
+    public static NoSQLQueryBuilder create(Class<? extends NoSQLQueryBuilder> builderClass) {
+        try {
+            return builderClass.newInstance();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public NoSQLQuery build() {
+        return new NoSQLQuery(queryAttributes);
+    }
+
+    public NoSQLQueryBuilder andCondition(String name, Object value) {
+        this.put(name, value);
+        return this;
+    }
+
+    public abstract NoSQLQueryBuilder inCondition(String name, Object[] values);
+
+    protected void put(String name, Object value) {
+        queryAttributes.put(name, value);
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/impl/MongoDBImpl.java b/services/src/main/java/org/keycloak/services/models/nosql/impl/MongoDBImpl.java
index 7d61b85..fd6efa7 100644
--- a/services/src/main/java/org/keycloak/services/models/nosql/impl/MongoDBImpl.java
+++ b/services/src/main/java/org/keycloak/services/models/nosql/impl/MongoDBImpl.java
@@ -12,16 +12,13 @@ import com.mongodb.DBCollection;
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
 import org.bson.types.ObjectId;
-import org.jboss.resteasy.logging.Logger;
-import org.jboss.resteasy.spi.NotImplementedYetException;
-import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.models.nosql.api.AttributedNoSQLObject;
 import org.keycloak.services.models.nosql.api.NoSQL;
 import org.keycloak.services.models.nosql.api.NoSQLCollection;
 import org.keycloak.services.models.nosql.api.NoSQLField;
 import org.keycloak.services.models.nosql.api.NoSQLId;
 import org.keycloak.services.models.nosql.api.NoSQLObject;
-import org.keycloak.services.models.nosql.api.NoSQLQuery;
+import org.keycloak.services.models.nosql.api.query.NoSQLQuery;
 import org.keycloak.services.models.nosql.api.types.Converter;
 import org.keycloak.services.models.nosql.api.types.TypeConverter;
 import org.keycloak.services.models.nosql.impl.types.BasicDBListToStringArrayConverter;
@@ -68,14 +65,14 @@ public class MongoDBImpl implements NoSQL {
 
 
             dbObject.append(propName, propValue);
+        }
 
-            // Adding attributes
-            if (object instanceof AttributedNoSQLObject) {
-                AttributedNoSQLObject attributedObject = (AttributedNoSQLObject)object;
-                Map<String, String> attributes = attributedObject.getAttributes();
-                for (Map.Entry<String, String> attribute : attributes.entrySet()) {
-                    dbObject.append(attribute.getKey(), attribute.getValue());
-                }
+        // Adding attributes
+        if (object instanceof AttributedNoSQLObject) {
+            AttributedNoSQLObject attributedObject = (AttributedNoSQLObject)object;
+            Map<String, String> attributes = attributedObject.getAttributes();
+            for (Map.Entry<String, String> attribute : attributes.entrySet()) {
+                dbObject.append(attribute.getKey(), attribute.getValue());
             }
         }
 
@@ -98,8 +95,7 @@ public class MongoDBImpl implements NoSQL {
 
     @Override
     public <T extends NoSQLObject> T loadObject(Class<T> type, String oid) {
-        ObjectInfo<T> objectInfo = getObjectInfo(type);
-        DBCollection dbCollection = database.getCollection(objectInfo.getDbCollectionName());
+        DBCollection dbCollection = getDBCollectionForType(type);
 
         BasicDBObject idQuery = new BasicDBObject("_id", new ObjectId(oid));
         DBObject dbObject = dbCollection.findOne(idQuery);
@@ -122,15 +118,9 @@ public class MongoDBImpl implements NoSQL {
 
     @Override
     public <T extends NoSQLObject> List<T> loadObjects(Class<T> type, NoSQLQuery query) {
-        Map<String, Object> queryAttributes = query.getQueryAttributes();
-
-        ObjectInfo<T> objectInfo = getObjectInfo(type);
-        DBCollection dbCollection = database.getCollection(objectInfo.getDbCollectionName());
+        DBCollection dbCollection = getDBCollectionForType(type);
+        BasicDBObject dbQuery = getDBQueryFromQuery(query);
 
-        BasicDBObject dbQuery = new BasicDBObject();
-        for (Map.Entry<String, Object> queryAttr : queryAttributes.entrySet()) {
-            dbQuery.append(queryAttr.getKey(), queryAttr.getValue());
-        }
         DBCursor cursor = dbCollection.find(dbQuery);
 
         return convertCursor(type, cursor);
@@ -149,19 +139,21 @@ public class MongoDBImpl implements NoSQL {
 
     @Override
     public void removeObject(Class<? extends NoSQLObject> type, String oid) {
-        ObjectInfo<?> objectInfo = getObjectInfo(type);
-        DBCollection dbCollection = database.getCollection(objectInfo.getDbCollectionName());
+        DBCollection dbCollection = getDBCollectionForType(type);
 
-        BasicDBObject query = new BasicDBObject("_id", new ObjectId(oid));
-        dbCollection.remove(query);
+        BasicDBObject dbQuery = new BasicDBObject("_id", new ObjectId(oid));
+        dbCollection.remove(dbQuery);
     }
 
     @Override
     public void removeObjects(Class<? extends NoSQLObject> type, NoSQLQuery query) {
-        throw new NotImplementedYetException();
+        DBCollection dbCollection = getDBCollectionForType(type);
+        BasicDBObject dbQuery = getDBQueryFromQuery(query);
+
+        dbCollection.remove(dbQuery);
     }
 
-    // Possibility to add converters
+    // Possibility to add user-defined converters
     public void addConverter(Converter<?, ?> converter) {
         typeConverter.addConverter(converter);
     }
@@ -171,6 +163,7 @@ public class MongoDBImpl implements NoSQL {
         if (objectInfo == null) {
             Property<String> idProperty = PropertyQueries.<String>createQuery(objectClass).addCriteria(new AnnotatedPropertyCriteria(NoSQLId.class)).getFirstResult();
             if (idProperty == null) {
+                // TODO: should be allowed to have NoSQLObject classes without declared NoSQLId annotation?
                 throw new IllegalStateException("Class " + objectClass + " doesn't have property with declared annotation " + NoSQLId.class);
             }
 
@@ -195,6 +188,10 @@ public class MongoDBImpl implements NoSQL {
 
 
     private <T extends NoSQLObject> T convertObject(Class<T> type, DBObject dbObject) {
+        if (dbObject == null) {
+            return null;
+        }
+
         ObjectInfo<T> objectInfo = getObjectInfo(type);
 
         T object;
@@ -255,4 +252,18 @@ public class MongoDBImpl implements NoSQL {
 
         return result;
     }
+
+    private DBCollection getDBCollectionForType(Class<? extends NoSQLObject> type) {
+        ObjectInfo<?> objectInfo = getObjectInfo(type);
+        return database.getCollection(objectInfo.getDbCollectionName());
+    }
+
+    private BasicDBObject getDBQueryFromQuery(NoSQLQuery query) {
+        Map<String, Object> queryAttributes = query.getQueryAttributes();
+        BasicDBObject dbQuery = new BasicDBObject();
+        for (Map.Entry<String, Object> queryAttr : queryAttributes.entrySet()) {
+            dbQuery.append(queryAttr.getKey(), queryAttr.getValue());
+        }
+        return dbQuery;
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/impl/MongoDBQueryBuilder.java b/services/src/main/java/org/keycloak/services/models/nosql/impl/MongoDBQueryBuilder.java
new file mode 100644
index 0000000..b3af732
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/models/nosql/impl/MongoDBQueryBuilder.java
@@ -0,0 +1,33 @@
+package org.keycloak.services.models.nosql.impl;
+
+import com.mongodb.BasicDBObject;
+import org.bson.types.ObjectId;
+import org.keycloak.services.models.nosql.api.query.NoSQLQueryBuilder;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class MongoDBQueryBuilder extends NoSQLQueryBuilder {
+
+    @Override
+    public NoSQLQueryBuilder inCondition(String name, Object[] values) {
+        if (values == null) {
+            values = new Object[0];
+        }
+
+        if ("_id".equals(name)) {
+            // we need to convert Strings to ObjectID
+            ObjectId[] objIds = new ObjectId[values.length];
+            for (int i=0 ; i<values.length ; i++) {
+                String id = values[i].toString();
+                ObjectId objectId = new ObjectId(id);
+                objIds[i] = objectId;
+            }
+            values = objIds;
+        }
+
+        BasicDBObject inObject = new BasicDBObject("$in", values);
+        put(name, inObject);
+        return this;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/impl/Utils.java b/services/src/main/java/org/keycloak/services/models/nosql/impl/Utils.java
new file mode 100644
index 0000000..1398e27
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/models/nosql/impl/Utils.java
@@ -0,0 +1,56 @@
+package org.keycloak.services.models.nosql.impl;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class Utils {
+
+    private Utils() {};
+
+    /**
+     * Add item to the end of array
+     *
+     * @param inputArray could be null. In this case, method will return array of length 1 with added item
+     * @param item must be not-null
+     * @return array with added item to the end
+     */
+    public static <T> T[] addItemToArray(T[] inputArray, T item) {
+        if (item == null) {
+            throw new IllegalArgumentException("item must be non-null");
+        }
+
+        T[] outputArray;
+        if (inputArray == null) {
+            outputArray = (T[])Array.newInstance(item.getClass(), 1);
+        } else {
+            outputArray = Arrays.copyOf(inputArray, inputArray.length + 1);
+        }
+        outputArray[outputArray.length - 1] = item;
+        return outputArray;
+    }
+
+    /**
+     * Return true if array contains specified item
+     * @param array could be null (In this case method always return false)
+     * @param item can't be null
+     * @return
+     */
+    public static boolean contains(Object[] array, Object item) {
+        if (item == null) {
+            throw new IllegalArgumentException("item must be non-null");
+        }
+
+        if (array != null) {
+            for (Object current : array) {
+                if (item.equals(current)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/keycloak/adapters/ApplicationAdapter.java b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/adapters/ApplicationAdapter.java
new file mode 100644
index 0000000..fc8a6e1
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/adapters/ApplicationAdapter.java
@@ -0,0 +1,199 @@
+package org.keycloak.services.models.nosql.keycloak.adapters;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.keycloak.services.models.ApplicationModel;
+import org.keycloak.services.models.RoleModel;
+import org.keycloak.services.models.UserModel;
+import org.keycloak.services.models.nosql.api.NoSQL;
+import org.keycloak.services.models.nosql.api.query.NoSQLQuery;
+import org.keycloak.services.models.nosql.api.query.NoSQLQueryBuilder;
+import org.keycloak.services.models.nosql.impl.MongoDBQueryBuilder;
+import org.keycloak.services.models.nosql.impl.Utils;
+import org.keycloak.services.models.nosql.keycloak.data.ApplicationData;
+import org.keycloak.services.models.nosql.keycloak.data.RoleData;
+import org.keycloak.services.models.nosql.keycloak.data.UserData;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ApplicationAdapter implements ApplicationModel {
+
+    private final ApplicationData application;
+    private final NoSQL noSQL;
+
+    private UserData resourceUser;
+
+    public ApplicationAdapter(ApplicationData applicationData, NoSQL noSQL) {
+        this.application = applicationData;
+        this.noSQL = noSQL;
+    }
+
+    @Override
+    public void updateResource() {
+        noSQL.saveObject(application);
+    }
+
+    @Override
+    public UserModel getResourceUser() {
+        // This is not thread-safe. Assumption is that ApplicationAdapter instance is per-client object
+        if (resourceUser == null) {
+            resourceUser = noSQL.loadObject(UserData.class, application.getResourceUserId());
+        }
+
+        return resourceUser != null ? new UserAdapter(resourceUser, noSQL) : null;
+    }
+
+    @Override
+    public String getId() {
+        return application.getId();
+    }
+
+    @Override
+    public String getName() {
+        return application.getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        application.setName(name);
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return application.isEnabled();
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        application.setEnabled(enabled);
+    }
+
+    @Override
+    public boolean isSurrogateAuthRequired() {
+        return application.isSurrogateAuthRequired();
+    }
+
+    @Override
+    public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
+        application.setSurrogateAuthRequired(surrogateAuthRequired);
+    }
+
+    @Override
+    public String getManagementUrl() {
+        return application.getManagementUrl();
+    }
+
+    @Override
+    public void setManagementUrl(String url) {
+        application.setManagementUrl(url);
+    }
+
+    @Override
+    public RoleAdapter getRole(String name) {
+        NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
+                .andCondition("name", name)
+                .andCondition("applicationId", getId())
+                .build();
+        RoleData role = noSQL.loadSingleObject(RoleData.class, query);
+        if (role == null) {
+            return null;
+        } else {
+            return new RoleAdapter(role, noSQL);
+        }
+    }
+
+    @Override
+    public RoleAdapter addRole(String name) {
+        if (getRole(name) != null) {
+            throw new IllegalArgumentException("Role " + name + " already exists");
+        }
+
+        RoleData roleData = new RoleData();
+        roleData.setName(name);
+        roleData.setApplicationId(getId());
+
+        noSQL.saveObject(roleData);
+        return new RoleAdapter(roleData, noSQL);
+    }
+
+    @Override
+    public List<RoleModel> getRoles() {
+        NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
+                .andCondition("applicationId", getId())
+                .build();
+        List<RoleData> roles = noSQL.loadObjects(RoleData.class, query);
+
+        List<RoleModel> result = new ArrayList<RoleModel>();
+        for (RoleData role : roles) {
+            result.add(new RoleAdapter(role, noSQL));
+        }
+
+        return result;
+    }
+
+    @Override
+    public Set<String> getRoleMappings(UserModel user) {
+        UserData userData = ((UserAdapter)user).getUser();
+        String[] roleIds = userData.getRoleIds();
+
+        Set<String> result = new HashSet<String>();
+
+        NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
+                .inCondition("_id", roleIds)
+                .build();
+        List<RoleData> roles = noSQL.loadObjects(RoleData.class, query);
+        // TODO: Maybe improve to have roles and scopes in separate table? As actually we need to obtain all roles and then filter programmatically...
+        for (RoleData role : roles) {
+            if (getId().equals(role.getApplicationId())) {
+                result.add(role.getName());
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void addScope(UserModel agent, String roleName) {
+        RoleAdapter role = getRole(roleName);
+        if (role == null) {
+            throw new RuntimeException("Role not found");
+        }
+
+        addScope(agent, role);
+    }
+
+    @Override
+    public void addScope(UserModel agent, RoleModel role) {
+        UserData userData = ((UserAdapter)agent).getUser();
+        RoleData roleData = ((RoleAdapter)role).getRole();
+
+        String[] scopeIds = userData.getScopeIds();
+        scopeIds = Utils.addItemToArray(scopeIds, roleData.getId());
+        userData.setScopeIds(scopeIds);
+
+        noSQL.saveObject(userData);
+    }
+
+    @Override
+    public Set<String> getScope(UserModel agent) {
+        UserData userData = ((UserAdapter)agent).getUser();
+        String[] scopeIds = userData.getScopeIds();
+
+        Set<String> result = new HashSet<String>();
+
+        NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
+                .inCondition("_id", scopeIds)
+                .build();
+        List<RoleData> roles = noSQL.loadObjects(RoleData.class, query);
+        // TODO: Maybe improve to have roles and scopes in separate table? As actually we need to obtain all roles and then filter programmatically...
+        for (RoleData role : roles) {
+            if (getId().equals(role.getApplicationId())) {
+                result.add(role.getName());
+            }
+        }
+        return result;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/keycloak/credentials/PasswordCredentialHandler.java b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/credentials/PasswordCredentialHandler.java
new file mode 100644
index 0000000..32a84d7
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/credentials/PasswordCredentialHandler.java
@@ -0,0 +1,155 @@
+package org.keycloak.services.models.nosql.keycloak.credentials;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Date;
+import java.util.Map;
+import java.util.UUID;
+
+import org.keycloak.services.models.nosql.api.NoSQL;
+import org.keycloak.services.models.nosql.api.query.NoSQLQuery;
+import org.keycloak.services.models.nosql.api.query.NoSQLQueryBuilder;
+import org.keycloak.services.models.nosql.impl.MongoDBQueryBuilder;
+import org.keycloak.services.models.nosql.keycloak.data.UserData;
+import org.keycloak.services.models.nosql.keycloak.data.credentials.PasswordData;
+import org.picketlink.idm.credential.Credentials;
+import org.picketlink.idm.credential.encoder.PasswordEncoder;
+import org.picketlink.idm.credential.encoder.SHAPasswordEncoder;
+
+/**
+ * Defacto forked from {@link org.picketlink.idm.credential.handler.PasswordCredentialHandler}
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class PasswordCredentialHandler {
+
+    private static final String DEFAULT_SALT_ALGORITHM = "SHA1PRNG";
+
+    /**
+     * <p>
+     * Stores a <b>stateless</b> instance of {@link org.picketlink.idm.credential.encoder.PasswordEncoder} that should be used to encode passwords.
+     * </p>
+     */
+    public static final String PASSWORD_ENCODER = "PASSWORD_ENCODER";
+
+    private PasswordEncoder passwordEncoder = new SHAPasswordEncoder(512);;
+
+    public void setup(Map<String, Object> options) {
+        if (options != null) {
+            Object providedEncoder = options.get(PASSWORD_ENCODER);
+
+            if (providedEncoder != null) {
+                if (PasswordEncoder.class.isInstance(providedEncoder)) {
+                    this.passwordEncoder = (PasswordEncoder) providedEncoder;
+                } else {
+                    throw new IllegalArgumentException("The password encoder [" + providedEncoder
+                            + "] must be an instance of " + PasswordEncoder.class.getName());
+                }
+            }
+        }
+    }
+
+    public Credentials.Status validate(NoSQL noSQL, UserData user, String passwordToValidate) {
+        Credentials.Status status = Credentials.Status.INVALID;
+
+        user = noSQL.loadObject(UserData.class, user.getId());
+
+        // If the user for the provided username cannot be found we fail validation
+        if (user != null) {
+            if (user.isEnabled()) {
+                NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
+                        .andCondition("userId", user.getId())
+                        .build();
+                PasswordData passwordData = noSQL.loadSingleObject(PasswordData.class, query);
+
+                // If the stored hash is null we automatically fail validation
+                if (passwordData != null) {
+                    if (!isCredentialExpired(passwordData.getExpiryDate())) {
+
+                        boolean matches = this.passwordEncoder.verify(saltPassword(passwordToValidate, passwordData.getSalt()), passwordData.getEncodedHash());
+
+                        if (matches) {
+                            status = Credentials.Status.VALID;
+                        }
+                    } else {
+                        status = Credentials.Status.EXPIRED;
+                    }
+                }
+            } else {
+                status = Credentials.Status.ACCOUNT_DISABLED;
+            }
+        }
+
+        return status;
+    }
+
+    public void update(NoSQL noSQL, UserData user, String password,
+                       Date effectiveDate, Date expiryDate) {
+
+        // Try to look if user already has password
+        NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
+                .andCondition("userId", user.getId())
+                .build();
+
+        PasswordData passwordData = noSQL.loadSingleObject(PasswordData.class, query);
+        if (passwordData == null) {
+            passwordData = new PasswordData();
+        }
+
+        String passwordSalt = generateSalt();
+
+        passwordData.setSalt(passwordSalt);
+        passwordData.setEncodedHash(this.passwordEncoder.encode(saltPassword(password, passwordSalt)));
+
+        if (effectiveDate != null) {
+            passwordData.setEffectiveDate(effectiveDate);
+        }
+
+        passwordData.setExpiryDate(expiryDate);
+
+        passwordData.setUserId(user.getId());
+
+        noSQL.saveObject(passwordData);
+    }
+
+    /**
+     * <p>
+     * Salt the give <code>rawPassword</code> with the specified <code>salt</code> value.
+     * </p>
+     *
+     * @param rawPassword
+     * @param salt
+     * @return
+     */
+    private String saltPassword(String rawPassword, String salt) {
+        return salt + rawPassword;
+    }
+
+    /**
+     * <p>
+     * Generates a random string to be used as a salt for passwords.
+     * </p>
+     *
+     * @return
+     */
+    private String generateSalt() {
+        // TODO: always returns same salt (See https://issues.jboss.org/browse/PLINK-258)
+        /*SecureRandom pseudoRandom = null;
+
+        try {
+            pseudoRandom = SecureRandom.getInstance(DEFAULT_SALT_ALGORITHM);
+            pseudoRandom.setSeed(1024);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("Error getting SecureRandom instance: " + DEFAULT_SALT_ALGORITHM, e);
+        }
+
+        return String.valueOf(pseudoRandom.nextLong());*/
+        return UUID.randomUUID().toString();
+    }
+
+    public static boolean isCredentialExpired(Date expiryDate) {
+        return expiryDate != null && new Date().compareTo(expiryDate) > 0;
+    }
+
+
+}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/keycloak/credentials/TOTPCredentialHandler.java b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/credentials/TOTPCredentialHandler.java
new file mode 100644
index 0000000..a5dc8d2
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/credentials/TOTPCredentialHandler.java
@@ -0,0 +1,11 @@
+package org.keycloak.services.models.nosql.keycloak.credentials;
+
+/**
+ * Defacto forked from {@link org.picketlink.idm.credential.handler.TOTPCredentialHandler}
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class TOTPCredentialHandler extends PasswordCredentialHandler {
+
+    // TODO: implement
+}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/ApplicationData.java b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/ApplicationData.java
new file mode 100644
index 0000000..7035f9a
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/ApplicationData.java
@@ -0,0 +1,85 @@
+package org.keycloak.services.models.nosql.keycloak.data;
+
+import org.keycloak.services.models.nosql.api.NoSQLCollection;
+import org.keycloak.services.models.nosql.api.NoSQLField;
+import org.keycloak.services.models.nosql.api.NoSQLId;
+import org.keycloak.services.models.nosql.api.NoSQLObject;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@NoSQLCollection(collectionName = "applications")
+public class ApplicationData implements NoSQLObject {
+
+    private String id;
+    private String name;
+    private boolean enabled;
+    private boolean surrogateAuthRequired;
+    private String managementUrl;
+
+    private String resourceUserId;
+    private String realmId;
+
+    @NoSQLId
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @NoSQLField
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @NoSQLField
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    @NoSQLField
+    public boolean isSurrogateAuthRequired() {
+        return surrogateAuthRequired;
+    }
+
+    public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
+        this.surrogateAuthRequired = surrogateAuthRequired;
+    }
+
+    @NoSQLField
+    public String getManagementUrl() {
+        return managementUrl;
+    }
+
+    public void setManagementUrl(String managementUrl) {
+        this.managementUrl = managementUrl;
+    }
+
+    @NoSQLField
+    public String getResourceUserId() {
+        return resourceUserId;
+    }
+
+    public void setResourceUserId(String resourceUserId) {
+        this.resourceUserId = resourceUserId;
+    }
+
+    @NoSQLField
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/credentials/PasswordData.java b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/credentials/PasswordData.java
new file mode 100644
index 0000000..a5ffad4
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/credentials/PasswordData.java
@@ -0,0 +1,77 @@
+package org.keycloak.services.models.nosql.keycloak.data.credentials;
+
+import java.util.Date;
+
+import org.keycloak.services.models.nosql.api.NoSQLCollection;
+import org.keycloak.services.models.nosql.api.NoSQLField;
+import org.keycloak.services.models.nosql.api.NoSQLId;
+import org.keycloak.services.models.nosql.api.NoSQLObject;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@NoSQLCollection(collectionName = "passwordCredentials")
+public class PasswordData implements NoSQLObject {
+
+    private String id;
+    private Date effectiveDate = new Date();
+    private Date expiryDate;
+    private String encodedHash;
+    private String salt;
+
+    private String userId;
+
+    @NoSQLId
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @NoSQLField
+    public Date getEffectiveDate() {
+        return effectiveDate;
+    }
+
+    public void setEffectiveDate(Date effectiveDate) {
+        this.effectiveDate = effectiveDate;
+    }
+
+    @NoSQLField
+    public Date getExpiryDate() {
+        return expiryDate;
+    }
+
+    public void setExpiryDate(Date expiryDate) {
+        this.expiryDate = expiryDate;
+    }
+
+    @NoSQLField
+    public String getEncodedHash() {
+        return encodedHash;
+    }
+
+    public void setEncodedHash(String encodedHash) {
+        this.encodedHash = encodedHash;
+    }
+
+    @NoSQLField
+    public String getSalt() {
+        return salt;
+    }
+
+    public void setSalt(String salt) {
+        this.salt = salt;
+    }
+
+    @NoSQLField
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/RequiredCredentialData.java b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/RequiredCredentialData.java
new file mode 100644
index 0000000..d20b595
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/RequiredCredentialData.java
@@ -0,0 +1,90 @@
+package org.keycloak.services.models.nosql.keycloak.data;
+
+import org.keycloak.services.models.nosql.api.NoSQLCollection;
+import org.keycloak.services.models.nosql.api.NoSQLField;
+import org.keycloak.services.models.nosql.api.NoSQLId;
+import org.keycloak.services.models.nosql.api.NoSQLObject;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@NoSQLCollection(collectionName = "requiredCredentials")
+public class RequiredCredentialData implements NoSQLObject {
+
+    public static final int CLIENT_TYPE_USER = 1;
+    public static final int CLIENT_TYPE_RESOURCE = 2;
+    public static final int CLIENT_TYPE_OAUTH_RESOURCE = 3;
+
+    private String id;
+
+    private String type;
+    private boolean input;
+    private boolean secret;
+    private String formLabel;
+
+    private String realmId;
+    private int clientType;
+
+    @NoSQLId
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @NoSQLField
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    @NoSQLField
+    public boolean isInput() {
+        return input;
+    }
+
+    public void setInput(boolean input) {
+        this.input = input;
+    }
+
+    @NoSQLField
+    public boolean isSecret() {
+        return secret;
+    }
+
+    public void setSecret(boolean secret) {
+        this.secret = secret;
+    }
+
+    @NoSQLField
+    public String getFormLabel() {
+        return formLabel;
+    }
+
+    public void setFormLabel(String formLabel) {
+        this.formLabel = formLabel;
+    }
+
+    @NoSQLField
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    @NoSQLField
+    public int getClientType() {
+        return clientType;
+    }
+
+    public void setClientType(int clientType) {
+        this.clientType = clientType;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/SocialLinkData.java b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/SocialLinkData.java
new file mode 100644
index 0000000..0ed96a4
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/models/nosql/keycloak/data/SocialLinkData.java
@@ -0,0 +1,54 @@
+package org.keycloak.services.models.nosql.keycloak.data;
+
+import org.keycloak.services.models.nosql.api.NoSQLCollection;
+import org.keycloak.services.models.nosql.api.NoSQLField;
+import org.keycloak.services.models.nosql.api.NoSQLId;
+import org.keycloak.services.models.nosql.api.NoSQLObject;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@NoSQLCollection(collectionName = "socialLinks")
+public class SocialLinkData implements NoSQLObject {
+
+    private String id;
+    private String socialUsername;
+    private String socialProvider;
+    private String userId;
+
+    @NoSQLId
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @NoSQLField
+    public String getSocialUsername() {
+        return socialUsername;
+    }
+
+    public void setSocialUsername(String socialUsername) {
+        this.socialUsername = socialUsername;
+    }
+
+    @NoSQLField
+    public String getSocialProvider() {
+        return socialProvider;
+    }
+
+    public void setSocialProvider(String socialProvider) {
+        this.socialProvider = socialProvider;
+    }
+
+    @NoSQLField
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+}
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 089ab39..dc8d711 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -8,8 +8,9 @@ import org.keycloak.models.picketlink.PicketlinkKeycloakSessionFactory;
 import org.keycloak.models.picketlink.mappings.ApplicationEntity;
 import org.keycloak.models.picketlink.mappings.RealmEntity;
 import org.keycloak.services.models.KeycloakSessionFactory;
-import org.keycloak.services.models.nosql.adapters.MongoDBSessionFactory;
+import org.keycloak.services.models.nosql.keycloak.adapters.MongoDBSessionFactory;
 import org.keycloak.services.models.picketlink.PicketlinkKeycloakSession;
+import org.keycloak.services.models.picketlink.PicketlinkKeycloakSessionFactory;
 import org.keycloak.services.models.picketlink.mappings.ApplicationEntity;
 import org.keycloak.services.models.picketlink.mappings.RealmEntity;
 import org.keycloak.social.SocialRequestManager;
@@ -24,6 +25,8 @@ import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.Persistence;
 import javax.servlet.ServletContext;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.Context;
 import java.util.HashSet;
@@ -61,7 +64,7 @@ public class KeycloakApplication extends Application {
     public static KeycloakSessionFactory buildSessionFactory() {
         // EntityManagerFactory emf = Persistence.createEntityManagerFactory("keycloak-identity-store");
         // return new PicketlinkKeycloakSessionFactory(emf, buildPartitionManager());
-        return new MongoDBSessionFactory("localhost", 27017, "keycloak");
+        return new MongoDBSessionFactory("localhost", 27017, "keycloak", true);
     }
 
     public KeycloakSessionFactory getFactory() {