Added NoSQLQueryBuilder API. Support for persistence of all objects. All unit tests are passing and UI is working with MongoDB

This commit is contained in:
mposolda 2013-09-02 11:43:43 +02:00
parent 815e466d43
commit 5b8908c822
27 changed files with 1823 additions and 699 deletions

View file

@ -1,43 +0,0 @@
package org.keycloak.services.models.nosql.adapters;
import java.net.UnknownHostException;
import com.mongodb.DB;
import com.mongodb.MongoClient;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.nosql.api.NoSQL;
import org.keycloak.services.models.nosql.impl.MongoDBImpl;
/**
* NoSQL implementation based on MongoDB
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class MongoDBSessionFactory implements KeycloakSessionFactory {
private final MongoClient mongoClient;
private final NoSQL mongoDB;
public MongoDBSessionFactory(String host, int port, String dbName) {
try {
// TODO: authentication support
mongoClient = new MongoClient(host, port);
DB db = mongoClient.getDB(dbName);
mongoDB = new MongoDBImpl(db);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
@Override
public KeycloakSession createSession() {
return new NoSQLSession(mongoDB);
}
@Override
public void close() {
mongoClient.close();
}
}

View file

@ -1,67 +0,0 @@
package org.keycloak.services.models.nosql.adapters;
import java.util.List;
import org.jboss.resteasy.spi.NotImplementedYetException;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakTransaction;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.models.nosql.data.RealmData;
import org.keycloak.services.models.nosql.api.NoSQL;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class NoSQLSession implements KeycloakSession {
private static final NoSQLTransaction PLACEHOLDER = new NoSQLTransaction();
private final NoSQL noSQL;
public NoSQLSession(NoSQL noSQL) {
this.noSQL = noSQL;
}
@Override
public KeycloakTransaction getTransaction() {
return PLACEHOLDER;
}
@Override
public void close() {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public RealmModel createRealm(String name) {
RealmData newRealm = new RealmData();
newRealm.setName(name);
noSQL.saveObject(newRealm);
RealmAdapter realm = new RealmAdapter(newRealm, noSQL);
return realm;
}
@Override
public RealmModel createRealm(String id, String name) {
// Ignore ID for now. It seems that it exists just for workaround picketlink
return createRealm(name);
}
@Override
public RealmModel getRealm(String id) {
RealmData realmData = noSQL.loadObject(RealmData.class, id);
return new RealmAdapter(realmData, noSQL);
}
@Override
public List<RealmModel> getRealms(UserModel admin) {
throw new NotImplementedYetException();
}
@Override
public void deleteRealm(RealmModel realm) {
noSQL.removeObject(RealmData.class, realm.getId());
}
}

View file

@ -1,46 +0,0 @@
package org.keycloak.services.models.nosql.adapters;
import org.keycloak.services.models.nosql.api.NoSQLCollection;
import org.keycloak.services.models.nosql.api.NoSQLField;
import org.keycloak.services.models.nosql.api.NoSQLId;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@NoSQLCollection(collectionName = "users")
public class NoSQLUser {
@NoSQLId
private String oid;
private String username;
private String realmId;
@NoSQLId
public String getOid() {
return oid;
}
public void setOid(String oid) {
this.oid = oid;
}
@NoSQLField
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@NoSQLField(fieldName = "realm_id")
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
}

View file

@ -1,492 +0,0 @@
package org.keycloak.services.models.nosql.adapters;
import java.io.IOException;
import java.io.StringWriter;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bouncycastle.openssl.PEMWriter;
import org.jboss.resteasy.security.PemUtils;
import org.keycloak.services.models.ApplicationModel;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.SocialLinkModel;
import org.keycloak.services.models.UserCredentialModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.models.nosql.api.NoSQL;
import org.keycloak.services.models.nosql.api.NoSQLQuery;
import org.keycloak.services.models.nosql.data.RealmData;
import org.keycloak.services.models.nosql.data.RoleData;
import org.keycloak.services.models.nosql.data.UserData;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class RealmAdapter implements RealmModel {
private final RealmData realm;
private final NoSQL noSQL;
protected volatile transient PublicKey publicKey;
protected volatile transient PrivateKey privateKey;
public RealmAdapter(RealmData realmData, NoSQL noSQL) {
this.realm = realmData;
this.noSQL = noSQL;
}
@Override
public String getId() {
return realm.getId();
}
@Override
public String getName() {
return realm.getName();
}
@Override
public void setName(String name) {
realm.setName(name);
updateRealm();
}
@Override
public boolean isEnabled() {
return realm.isEnabled();
}
@Override
public void setEnabled(boolean enabled) {
realm.setEnabled(enabled);
updateRealm();
}
@Override
public boolean isSocial() {
return realm.isSocial();
}
@Override
public void setSocial(boolean social) {
realm.setSocial(social);
updateRealm();
}
@Override
public boolean isAutomaticRegistrationAfterSocialLogin() {
return realm.isAutomaticRegistrationAfterSocialLogin();
}
@Override
public void setAutomaticRegistrationAfterSocialLogin(boolean automaticRegistrationAfterSocialLogin) {
realm.setAutomaticRegistrationAfterSocialLogin(automaticRegistrationAfterSocialLogin);
updateRealm();
}
@Override
public boolean isSslNotRequired() {
return realm.isSslNotRequired();
}
@Override
public void setSslNotRequired(boolean sslNotRequired) {
realm.setSslNotRequired(sslNotRequired);
updateRealm();
}
@Override
public boolean isCookieLoginAllowed() {
return realm.isCookieLoginAllowed();
}
@Override
public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
realm.setCookieLoginAllowed(cookieLoginAllowed);
updateRealm();
}
@Override
public boolean isRegistrationAllowed() {
return realm.isRegistrationAllowed();
}
@Override
public void setRegistrationAllowed(boolean registrationAllowed) {
realm.setRegistrationAllowed(registrationAllowed);
updateRealm();
}
@Override
public int getTokenLifespan() {
return realm.getTokenLifespan();
}
@Override
public void setTokenLifespan(int tokenLifespan) {
realm.setTokenLifespan(tokenLifespan);
updateRealm();
}
@Override
public int getAccessCodeLifespan() {
return realm.getAccessCodeLifespan();
}
@Override
public void setAccessCodeLifespan(int accessCodeLifespan) {
realm.setAccessCodeLifespan(accessCodeLifespan);
updateRealm();
}
@Override
public String getPublicKeyPem() {
return realm.getPublicKeyPem();
}
@Override
public void setPublicKeyPem(String publicKeyPem) {
realm.setPublicKeyPem(publicKeyPem);
this.publicKey = null;
updateRealm();
}
@Override
public String getPrivateKeyPem() {
return realm.getPrivateKeyPem();
}
@Override
public void setPrivateKeyPem(String privateKeyPem) {
realm.setPrivateKeyPem(privateKeyPem);
this.privateKey = null;
updateRealm();
}
@Override
public PublicKey getPublicKey() {
if (publicKey != null) return publicKey;
String pem = getPublicKeyPem();
if (pem != null) {
try {
publicKey = PemUtils.decodePublicKey(pem);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return publicKey;
}
@Override
public void setPublicKey(PublicKey publicKey) {
this.publicKey = publicKey;
StringWriter writer = new StringWriter();
PEMWriter pemWriter = new PEMWriter(writer);
try {
pemWriter.writeObject(publicKey);
pemWriter.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
String s = writer.toString();
setPublicKeyPem(PemUtils.removeBeginEnd(s));
}
@Override
public PrivateKey getPrivateKey() {
if (privateKey != null) return privateKey;
String pem = getPrivateKeyPem();
if (pem != null) {
try {
privateKey = PemUtils.decodePrivateKey(pem);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return privateKey;
}
@Override
public void setPrivateKey(PrivateKey privateKey) {
this.privateKey = privateKey;
StringWriter writer = new StringWriter();
PEMWriter pemWriter = new PEMWriter(writer);
try {
pemWriter.writeObject(privateKey);
pemWriter.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
String s = writer.toString();
setPrivateKeyPem(PemUtils.removeBeginEnd(s));
}
@Override
public List<RequiredCredentialModel> getRequiredCredentials() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void addRequiredCredential(String cred) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public boolean validatePassword(UserModel user, String password) {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public boolean validateTOTP(UserModel user, String password, String token) {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void updateCredential(UserModel user, UserCredentialModel cred) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public UserModel getUser(String name) {
NoSQLQuery query = NoSQLQuery.create().put("loginName", name).put("realmId", getId());
UserData user = noSQL.loadSingleObject(UserData.class, query);
if (user == null) {
return null;
} else {
return new UserAdapter(user, noSQL);
}
}
@Override
public UserModel addUser(String username) {
if (getUser(username) != null) {
throw new IllegalArgumentException("User " + username + " already exists");
}
UserData userData = new UserData();
userData.setLoginName(username);
userData.setEnabled(true);
userData.setRealmId(getId());
noSQL.saveObject(userData);
return new UserAdapter(userData, noSQL);
}
@Override
public RoleAdapter getRole(String name) {
NoSQLQuery query = NoSQLQuery.create().put("name", name).put("realmId", getId());
RoleData role = noSQL.loadSingleObject(RoleData.class, query);
if (role == null) {
return null;
} else {
return new RoleAdapter(role, noSQL);
}
}
@Override
public RoleModel addRole(String name) {
if (getRole(name) != null) {
throw new IllegalArgumentException("Role " + name + " already exists");
}
RoleData roleData = new RoleData();
roleData.setName(name);
roleData.setRealmId(getId());
noSQL.saveObject(roleData);
return new RoleAdapter(roleData, noSQL);
}
@Override
public List<RoleModel> getRoles() {
NoSQLQuery query = NoSQLQuery.create().put("realmId", getId());
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 List<RoleModel> getDefaultRoles() {
List<RoleModel> defaultRoleModels = new ArrayList<RoleModel>();
if (realm.getDefaultRoles() != null) {
for (String name : realm.getDefaultRoles()) {
RoleAdapter role = getRole(name);
if (role != null) {
defaultRoleModels.add(role);
}
}
}
return defaultRoleModels;
}
@Override
public void addDefaultRole(String name) {
if (getRole(name) == null) {
addRole(name);
}
String[] defaultRoles = realm.getDefaultRoles();
if (defaultRoles == null) {
defaultRoles = new String[1];
} else {
defaultRoles = Arrays.copyOf(defaultRoles, defaultRoles.length + 1);
}
defaultRoles[defaultRoles.length - 1] = name;
realm.setDefaultRoles(defaultRoles);
updateRealm();
}
@Override
public void updateDefaultRoles(String[] defaultRoles) {
for (String name : defaultRoles) {
if (getRole(name) == null) {
addRole(name);
}
}
realm.setDefaultRoles(defaultRoles);
updateRealm();
}
@Override
public Map<String, ApplicationModel> getResourceNameMap() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public List<ApplicationModel> getApplications() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public ApplicationModel addApplication(String name) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public boolean hasRole(UserModel user, RoleModel role) {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void grantRole(UserModel user, RoleModel role) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Set<String> getRoleMappings(UserModel user) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void addScope(UserModel agent, String roleName) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Set<String> getScope(UserModel agent) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public boolean isRealmAdmin(UserModel agent) {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void addRealmAdmin(UserModel agent) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public RoleModel getRoleById(String id) {
RoleData role = noSQL.loadObject(RoleData.class, id);
if (role == null) {
return null;
} else {
return new RoleAdapter(role, noSQL);
}
}
@Override
public List<RequiredCredentialModel> getRequiredApplicationCredentials() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public List<RequiredCredentialModel> getRequiredOAuthClientCredentials() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public boolean hasRole(UserModel user, String role) {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public ApplicationModel getApplicationById(String id) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void addRequiredOAuthClientCredential(String type) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void addRequiredResourceCredential(String type) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void updateRequiredCredentials(Set<String> creds) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void updateRequiredOAuthClientCredentials(Set<String> creds) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void updateRequiredApplicationCredentials(Set<String> creds) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public UserModel getUserBySocialLink(SocialLinkModel socialLink) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Set<SocialLinkModel> getSocialLinks(UserModel user) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void addSocialLink(UserModel user, SocialLinkModel socialLink) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void removeSocialLink(UserModel user, SocialLinkModel socialLink) {
//To change body of implemented methods use File | Settings | File Templates.
}
protected void updateRealm() {
noSQL.saveObject(realm);
}
}

View file

@ -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>

View file

@ -1,4 +1,4 @@
package org.keycloak.services.models.nosql.api;
package org.keycloak.services.models.nosql.api.query;
import java.util.Collections;
import java.util.HashMap;
@ -9,18 +9,11 @@ import java.util.Map;
*/
public class NoSQLQuery {
private Map<String, Object> queryAttributes = new HashMap<String, Object>();
private final Map<String, Object> queryAttributes;
private NoSQLQuery() {};
public static NoSQLQuery create() {
return new NoSQLQuery();
}
public NoSQLQuery put(String name, Object value) {
queryAttributes.put(name, value);
return this;
}
NoSQLQuery(Map<String, Object> queryAttributes) {
this.queryAttributes = queryAttributes;
};
public Map<String, Object> getQueryAttributes() {
return Collections.unmodifiableMap(queryAttributes);

View file

@ -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);
}
}

View file

@ -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();
DBCollection dbCollection = getDBCollectionForType(type);
BasicDBObject dbQuery = getDBQueryFromQuery(query);
ObjectInfo<T> objectInfo = getObjectInfo(type);
DBCollection dbCollection = database.getCollection(objectInfo.getDbCollectionName());
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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -0,0 +1,74 @@
package org.keycloak.services.models.nosql.keycloak.adapters;
import java.net.UnknownHostException;
import com.mongodb.DB;
import com.mongodb.MongoClient;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.nosql.api.NoSQL;
import org.keycloak.services.models.nosql.api.NoSQLObject;
import org.keycloak.services.models.nosql.api.query.NoSQLQuery;
import org.keycloak.services.models.nosql.api.query.NoSQLQueryBuilder;
import org.keycloak.services.models.nosql.keycloak.data.ApplicationData;
import org.keycloak.services.models.nosql.keycloak.data.RealmData;
import org.keycloak.services.models.nosql.keycloak.data.RequiredCredentialData;
import org.keycloak.services.models.nosql.keycloak.data.RoleData;
import org.keycloak.services.models.nosql.keycloak.data.SocialLinkData;
import org.keycloak.services.models.nosql.keycloak.data.UserData;
import org.keycloak.services.models.nosql.impl.MongoDBImpl;
import org.keycloak.services.models.nosql.impl.MongoDBQueryBuilder;
import org.keycloak.services.models.nosql.keycloak.data.credentials.PasswordData;
/**
* NoSQL implementation based on MongoDB
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class MongoDBSessionFactory implements KeycloakSessionFactory {
private static final Class<?>[] MANAGED_DATA_TYPES = {
RealmData.class,
UserData.class,
RoleData.class,
RequiredCredentialData.class,
PasswordData.class,
SocialLinkData.class,
ApplicationData.class
};
private final MongoClient mongoClient;
private final NoSQL mongoDB;
public MongoDBSessionFactory(String host, int port, String dbName, boolean removeAllObjectsAtStartup) {
try {
// TODO: authentication support
mongoClient = new MongoClient(host, port);
DB db = mongoClient.getDB(dbName);
mongoDB = new MongoDBImpl(db);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
if (removeAllObjectsAtStartup) {
NoSQLQuery emptyQuery = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class).build();
for (Class<?> type : MANAGED_DATA_TYPES) {
mongoDB.removeObjects((Class<? extends NoSQLObject>)type, emptyQuery);
}
// TODO: logging
System.out.println("All objects successfully removed from DB");
}
}
@Override
public KeycloakSession createSession() {
return new NoSQLSession(mongoDB);
}
@Override
public void close() {
mongoClient.close();
}
}

View file

@ -0,0 +1,85 @@
package org.keycloak.services.models.nosql.keycloak.adapters;
import java.util.ArrayList;
import java.util.List;
import org.jboss.resteasy.spi.NotImplementedYetException;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakTransaction;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.UserModel;
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.RealmData;
import org.keycloak.services.models.nosql.api.NoSQL;
import org.keycloak.services.models.picketlink.PicketlinkKeycloakSession;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class NoSQLSession implements KeycloakSession {
private static final NoSQLTransaction PLACEHOLDER = new NoSQLTransaction();
private final NoSQL noSQL;
public NoSQLSession(NoSQL noSQL) {
this.noSQL = noSQL;
}
@Override
public KeycloakTransaction getTransaction() {
return PLACEHOLDER;
}
@Override
public void close() {
}
@Override
public RealmModel createRealm(String name) {
return createRealm(PicketlinkKeycloakSession.generateId(), name);
}
@Override
public RealmModel createRealm(String id, String name) {
RealmData newRealm = new RealmData();
newRealm.setId(id);
newRealm.setName(name);
noSQL.saveObject(newRealm);
RealmAdapter realm = new RealmAdapter(newRealm, noSQL);
return realm;
}
@Override
public RealmModel getRealm(String id) {
NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
.andCondition("id", id)
.build();
RealmData realmData = noSQL.loadSingleObject(RealmData.class, query);
return realmData != null ? new RealmAdapter(realmData, noSQL) : null;
}
@Override
public List<RealmModel> getRealms(UserModel admin) {
String userId = ((UserAdapter)admin).getUser().getId();
NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
.andCondition("realmAdmins", userId)
.build();
List<RealmData> realms = noSQL.loadObjects(RealmData.class, query);
List<RealmModel> results = new ArrayList<RealmModel>();
for (RealmData realmData : realms) {
results.add(new RealmAdapter(realmData, noSQL));
}
return results;
}
@Override
public void deleteRealm(RealmModel realm) {
String oid = ((RealmAdapter)realm).getOid();
noSQL.removeObject(RealmData.class, oid);
}
}

View file

@ -1,4 +1,4 @@
package org.keycloak.services.models.nosql.adapters;
package org.keycloak.services.models.nosql.keycloak.adapters;
import org.keycloak.services.models.KeycloakTransaction;

View file

@ -0,0 +1,751 @@
package org.keycloak.services.models.nosql.keycloak.adapters;
import java.io.IOException;
import java.io.StringWriter;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bouncycastle.openssl.PEMWriter;
import org.jboss.resteasy.security.PemUtils;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.models.ApplicationModel;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.SocialLinkModel;
import org.keycloak.services.models.UserCredentialModel;
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.keycloak.credentials.PasswordCredentialHandler;
import org.keycloak.services.models.nosql.keycloak.credentials.TOTPCredentialHandler;
import org.keycloak.services.models.nosql.keycloak.data.ApplicationData;
import org.keycloak.services.models.nosql.keycloak.data.RealmData;
import org.keycloak.services.models.nosql.keycloak.data.RequiredCredentialData;
import org.keycloak.services.models.nosql.keycloak.data.RoleData;
import org.keycloak.services.models.nosql.keycloak.data.SocialLinkData;
import org.keycloak.services.models.nosql.keycloak.data.UserData;
import org.keycloak.services.models.nosql.impl.MongoDBQueryBuilder;
import org.keycloak.services.models.nosql.impl.Utils;
import org.keycloak.services.models.picketlink.relationships.ResourceRelationship;
import org.picketlink.idm.credential.Credentials;
import org.picketlink.idm.query.RelationshipQuery;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class RealmAdapter implements RealmModel {
private final RealmData realm;
private final NoSQL noSQL;
protected volatile transient PublicKey publicKey;
protected volatile transient PrivateKey privateKey;
// TODO: likely shouldn't be static. And setup is not called ATM, which means that it's not possible to configure stuff like PasswordEncoder etc.
private static PasswordCredentialHandler passwordCredentialHandler = new PasswordCredentialHandler();
private static TOTPCredentialHandler totpCredentialHandler = new TOTPCredentialHandler();
public RealmAdapter(RealmData realmData, NoSQL noSQL) {
this.realm = realmData;
this.noSQL = noSQL;
}
protected String getOid() {
return realm.getOid();
}
@Override
public String getId() {
return realm.getId();
}
@Override
public String getName() {
return realm.getName();
}
@Override
public void setName(String name) {
realm.setName(name);
updateRealm();
}
@Override
public boolean isEnabled() {
return realm.isEnabled();
}
@Override
public void setEnabled(boolean enabled) {
realm.setEnabled(enabled);
updateRealm();
}
@Override
public boolean isSocial() {
return realm.isSocial();
}
@Override
public void setSocial(boolean social) {
realm.setSocial(social);
updateRealm();
}
@Override
public boolean isAutomaticRegistrationAfterSocialLogin() {
return realm.isAutomaticRegistrationAfterSocialLogin();
}
@Override
public void setAutomaticRegistrationAfterSocialLogin(boolean automaticRegistrationAfterSocialLogin) {
realm.setAutomaticRegistrationAfterSocialLogin(automaticRegistrationAfterSocialLogin);
updateRealm();
}
@Override
public boolean isSslNotRequired() {
return realm.isSslNotRequired();
}
@Override
public void setSslNotRequired(boolean sslNotRequired) {
realm.setSslNotRequired(sslNotRequired);
updateRealm();
}
@Override
public boolean isCookieLoginAllowed() {
return realm.isCookieLoginAllowed();
}
@Override
public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
realm.setCookieLoginAllowed(cookieLoginAllowed);
updateRealm();
}
@Override
public boolean isRegistrationAllowed() {
return realm.isRegistrationAllowed();
}
@Override
public void setRegistrationAllowed(boolean registrationAllowed) {
realm.setRegistrationAllowed(registrationAllowed);
updateRealm();
}
@Override
public int getTokenLifespan() {
return realm.getTokenLifespan();
}
@Override
public void setTokenLifespan(int tokenLifespan) {
realm.setTokenLifespan(tokenLifespan);
updateRealm();
}
@Override
public int getAccessCodeLifespan() {
return realm.getAccessCodeLifespan();
}
@Override
public void setAccessCodeLifespan(int accessCodeLifespan) {
realm.setAccessCodeLifespan(accessCodeLifespan);
updateRealm();
}
@Override
public String getPublicKeyPem() {
return realm.getPublicKeyPem();
}
@Override
public void setPublicKeyPem(String publicKeyPem) {
realm.setPublicKeyPem(publicKeyPem);
this.publicKey = null;
updateRealm();
}
@Override
public String getPrivateKeyPem() {
return realm.getPrivateKeyPem();
}
@Override
public void setPrivateKeyPem(String privateKeyPem) {
realm.setPrivateKeyPem(privateKeyPem);
this.privateKey = null;
updateRealm();
}
@Override
public PublicKey getPublicKey() {
if (publicKey != null) return publicKey;
String pem = getPublicKeyPem();
if (pem != null) {
try {
publicKey = PemUtils.decodePublicKey(pem);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return publicKey;
}
@Override
public void setPublicKey(PublicKey publicKey) {
this.publicKey = publicKey;
StringWriter writer = new StringWriter();
PEMWriter pemWriter = new PEMWriter(writer);
try {
pemWriter.writeObject(publicKey);
pemWriter.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
String s = writer.toString();
setPublicKeyPem(PemUtils.removeBeginEnd(s));
}
@Override
public PrivateKey getPrivateKey() {
if (privateKey != null) return privateKey;
String pem = getPrivateKeyPem();
if (pem != null) {
try {
privateKey = PemUtils.decodePrivateKey(pem);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return privateKey;
}
@Override
public void setPrivateKey(PrivateKey privateKey) {
this.privateKey = privateKey;
StringWriter writer = new StringWriter();
PEMWriter pemWriter = new PEMWriter(writer);
try {
pemWriter.writeObject(privateKey);
pemWriter.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
String s = writer.toString();
setPrivateKeyPem(PemUtils.removeBeginEnd(s));
}
@Override
public UserAdapter getUser(String name) {
NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
.andCondition("loginName", name)
.andCondition("realmId", getOid())
.build();
UserData user = noSQL.loadSingleObject(UserData.class, query);
if (user == null) {
return null;
} else {
return new UserAdapter(user, noSQL);
}
}
@Override
public UserAdapter addUser(String username) {
if (getUser(username) != null) {
throw new IllegalArgumentException("User " + username + " already exists");
}
UserData userData = new UserData();
userData.setLoginName(username);
userData.setEnabled(true);
userData.setRealmId(getOid());
noSQL.saveObject(userData);
return new UserAdapter(userData, noSQL);
}
@Override
public RoleAdapter getRole(String name) {
NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
.andCondition("name", name)
.andCondition("realmId", getOid())
.build();
RoleData role = noSQL.loadSingleObject(RoleData.class, query);
if (role == null) {
return null;
} else {
return new RoleAdapter(role, noSQL);
}
}
@Override
public RoleModel addRole(String name) {
if (getRole(name) != null) {
throw new IllegalArgumentException("Role " + name + " already exists");
}
RoleData roleData = new RoleData();
roleData.setName(name);
roleData.setRealmId(getOid());
noSQL.saveObject(roleData);
return new RoleAdapter(roleData, noSQL);
}
@Override
public List<RoleModel> getRoles() {
NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
.andCondition("realmId", getOid())
.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 List<RoleModel> getDefaultRoles() {
String[] defaultRoles = realm.getDefaultRoles();
NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
.inCondition("_id", defaultRoles)
.build();
List<RoleData> defaultRolesData = noSQL.loadObjects(RoleData.class, query);
List<RoleModel> defaultRoleModels = new ArrayList<RoleModel>();
for (RoleData roleData : defaultRolesData) {
defaultRoleModels.add(new RoleAdapter(roleData, noSQL));
}
return defaultRoleModels;
}
@Override
public void addDefaultRole(String name) {
RoleModel role = getRole(name);
if (role == null) {
role = addRole(name);
}
String[] defaultRoles = realm.getDefaultRoles();
String[] roleIds = Utils.addItemToArray(defaultRoles, role.getId());
realm.setDefaultRoles(roleIds);
updateRealm();
}
@Override
public void updateDefaultRoles(String[] defaultRoles) {
// defaultRoles is array with names of roles. So we need to convert to array of ids
String[] roleIds = new String[defaultRoles.length];
for (int i=0 ; i<defaultRoles.length ; i++) {
String roleName = defaultRoles[i];
RoleModel role = getRole(roleName);
if (role == null) {
role = addRole(roleName);
}
roleIds[i] = role.getId();
}
realm.setDefaultRoles(roleIds);
updateRealm();
}
@Override
public ApplicationModel getApplicationById(String id) {
ApplicationData appData = noSQL.loadObject(ApplicationData.class, id);
// Check if application belongs to this realm
if (appData == null || !getOid().equals(appData.getRealmId())) {
return null;
}
ApplicationModel model = new ApplicationAdapter(appData, noSQL);
return model;
}
@Override
public Map<String, ApplicationModel> getResourceNameMap() {
Map<String, ApplicationModel> resourceMap = new HashMap<String, ApplicationModel>();
for (ApplicationModel resource : getApplications()) {
resourceMap.put(resource.getName(), resource);
}
return resourceMap;
}
@Override
public List<ApplicationModel> getApplications() {
NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
.andCondition("realmId", getOid())
.build();
List<ApplicationData> appDatas = noSQL.loadObjects(ApplicationData.class, query);
List<ApplicationModel> result = new ArrayList<ApplicationModel>();
for (ApplicationData appData : appDatas) {
result.add(new ApplicationAdapter(appData, noSQL));
}
return result;
}
@Override
public ApplicationModel addApplication(String name) {
UserAdapter resourceUser = addUser(name);
ApplicationData appData = new ApplicationData();
appData.setName(name);
appData.setRealmId(getOid());
appData.setResourceUserId(resourceUser.getUser().getId());
noSQL.saveObject(appData);
ApplicationModel resource = new ApplicationAdapter(appData, noSQL);
resource.addRole("*");
resource.addScope(resourceUser, "*");
return resource;
}
@Override
public boolean hasRole(UserModel user, RoleModel role) {
UserData userData = ((UserAdapter)user).getUser();
String[] roleIds = userData.getRoleIds();
String roleId = role.getId();
if (roleIds != null) {
for (String currentId : roleIds) {
if (roleId.equals(currentId)) {
return true;
}
}
}
return false;
}
@Override
public void grantRole(UserModel user, RoleModel role) {
UserData userData = ((UserAdapter)user).getUser();
RoleData roleData = ((RoleAdapter)role).getRole();
String[] roleIds = userData.getRoleIds();
roleIds = Utils.addItemToArray(roleIds, roleData.getId());
userData.setRoleIds(roleIds);
noSQL.saveObject(userData);
}
@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 (getOid().equals(role.getRealmId())) {
result.add(role.getName());
}
}
return result;
}
@Override
public void addScope(UserModel agent, String roleName) {
UserData userData = ((UserAdapter)agent).getUser();
RoleAdapter role = getRole(roleName);
if (role == null) {
throw new RuntimeException("Role not found");
}
RoleData roleData = 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 (getOid().equals(role.getRealmId())) {
result.add(role.getName());
}
}
return result;
}
@Override
public boolean isRealmAdmin(UserModel agent) {
String[] realmAdmins = realm.getRealmAdmins();
String userId = ((UserAdapter)agent).getUser().getId();
return Utils.contains(realmAdmins, userId);
}
@Override
public void addRealmAdmin(UserModel agent) {
UserData userData = ((UserAdapter)agent).getUser();
String[] currentAdmins = realm.getRealmAdmins();
String[] newAdmins = Utils.addItemToArray(currentAdmins, userData.getId());
realm.setRealmAdmins(newAdmins);
updateRealm();
}
@Override
public RoleModel getRoleById(String id) {
RoleData role = noSQL.loadObject(RoleData.class, id);
if (role == null) {
return null;
} else {
return new RoleAdapter(role, noSQL);
}
}
@Override
public boolean hasRole(UserModel user, String role) {
RoleModel roleModel = getRole(role);
return hasRole(user, roleModel);
}
@Override
public void addRequiredCredential(String cred) {
RequiredCredentialModel credentialModel = initRequiredCredentialModel(cred);
addRequiredCredential(credentialModel, RequiredCredentialData.CLIENT_TYPE_USER);
}
@Override
public void addRequiredResourceCredential(String type) {
RequiredCredentialModel credentialModel = initRequiredCredentialModel(type);
addRequiredCredential(credentialModel, RequiredCredentialData.CLIENT_TYPE_RESOURCE);
}
@Override
public void addRequiredOAuthClientCredential(String type) {
RequiredCredentialModel credentialModel = initRequiredCredentialModel(type);
addRequiredCredential(credentialModel, RequiredCredentialData.CLIENT_TYPE_OAUTH_RESOURCE);
}
protected void addRequiredCredential(RequiredCredentialModel credentialModel, int clientType) {
RequiredCredentialData credData = new RequiredCredentialData();
credData.setType(credentialModel.getType());
credData.setFormLabel(credentialModel.getFormLabel());
credData.setInput(credentialModel.isInput());
credData.setSecret(credentialModel.isSecret());
credData.setRealmId(getOid());
credData.setClientType(clientType);
noSQL.saveObject(credData);
}
@Override
public void updateRequiredCredentials(Set<String> creds) {
List<RequiredCredentialData> credsData = getRequiredCredentialsData(RequiredCredentialData.CLIENT_TYPE_USER);
updateRequiredCredentials(creds, credsData);
}
@Override
public void updateRequiredApplicationCredentials(Set<String> creds) {
List<RequiredCredentialData> credsData = getRequiredCredentialsData(RequiredCredentialData.CLIENT_TYPE_RESOURCE);
updateRequiredCredentials(creds, credsData);
}
@Override
public void updateRequiredOAuthClientCredentials(Set<String> creds) {
List<RequiredCredentialData> credsData = getRequiredCredentialsData(RequiredCredentialData.CLIENT_TYPE_OAUTH_RESOURCE);
updateRequiredCredentials(creds, credsData);
}
protected void updateRequiredCredentials(Set<String> creds, List<RequiredCredentialData> credsData) {
Set<String> already = new HashSet<String>();
for (RequiredCredentialData data : credsData) {
if (!creds.contains(data.getType())) {
noSQL.removeObject(data);
} else {
already.add(data.getType());
}
}
for (String cred : creds) {
// TODO
System.out.println("updating cred: " + cred);
// logger.info("updating cred: " + cred);
if (!already.contains(cred)) {
addRequiredCredential(cred);
}
}
}
@Override
public List<RequiredCredentialModel> getRequiredCredentials() {
return getRequiredCredentials(RequiredCredentialData.CLIENT_TYPE_USER);
}
@Override
public List<RequiredCredentialModel> getRequiredApplicationCredentials() {
return getRequiredCredentials(RequiredCredentialData.CLIENT_TYPE_RESOURCE);
}
@Override
public List<RequiredCredentialModel> getRequiredOAuthClientCredentials() {
return getRequiredCredentials(RequiredCredentialData.CLIENT_TYPE_OAUTH_RESOURCE);
}
protected List<RequiredCredentialModel> getRequiredCredentials(int credentialType) {
List<RequiredCredentialData> credsData = getRequiredCredentialsData(credentialType);
List<RequiredCredentialModel> result = new ArrayList<RequiredCredentialModel>();
for (RequiredCredentialData data : credsData) {
RequiredCredentialModel model = new RequiredCredentialModel();
model.setFormLabel(data.getFormLabel());
model.setInput(data.isInput());
model.setSecret(data.isSecret());
model.setType(data.getType());
result.add(model);
}
return result;
}
protected List<RequiredCredentialData> getRequiredCredentialsData(int credentialType) {
NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
.andCondition("realmId", getOid())
.andCondition("clientType", credentialType)
.build();
return noSQL.loadObjects(RequiredCredentialData.class, query);
}
@Override
public boolean validatePassword(UserModel user, String password) {
Credentials.Status status = passwordCredentialHandler.validate(noSQL, ((UserAdapter)user).getUser(), password);
return status == Credentials.Status.VALID;
}
@Override
public boolean validateTOTP(UserModel user, String password, String token) {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void updateCredential(UserModel user, UserCredentialModel cred) {
if (cred.getType().equals(CredentialRepresentation.PASSWORD)) {
passwordCredentialHandler.update(noSQL, ((UserAdapter)user).getUser(), cred.getValue(), null, null);
} else if (cred.getType().equals(CredentialRepresentation.TOTP)) {
// TODO
// TOTPCredential totp = new TOTPCredential(cred.getValue());
// totp.setDevice(cred.getDevice());
// idm.updateCredential(((UserAdapter)user).getUser(), totp);
} else if (cred.getType().equals(CredentialRepresentation.CLIENT_CERT)) {
// TODO
// X509Certificate cert = null;
// try {
// cert = org.keycloak.PemUtils.decodeCertificate(cred.getValue());
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
// X509CertificateCredentials creds = new X509CertificateCredentials(cert);
// idm.updateCredential(((UserAdapter)user).getUser(), creds);
}
}
@Override
public UserModel getUserBySocialLink(SocialLinkModel socialLink) {
NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
.andCondition("socialProvider", socialLink.getSocialProvider())
.andCondition("socialUsername", socialLink.getSocialUsername())
.build();
SocialLinkData socialLinkData = noSQL.loadSingleObject(SocialLinkData.class, query);
if (socialLinkData == null) {
return null;
} else {
UserData userData = noSQL.loadObject(UserData.class, socialLinkData.getUserId());
// TODO: Add some checking if userData exists and programmatically remove binding if it doesn't? (There are more similar places where this should be handled)
return new UserAdapter(userData, noSQL);
}
}
@Override
public Set<SocialLinkModel> getSocialLinks(UserModel user) {
UserData userData = ((UserAdapter)user).getUser();
String userId = userData.getId();
NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
.andCondition("userId", userId)
.build();
List<SocialLinkData> dbSocialLinks = noSQL.loadObjects(SocialLinkData.class, query);
Set<SocialLinkModel> result = new HashSet<SocialLinkModel>();
for (SocialLinkData socialLinkData : dbSocialLinks) {
SocialLinkModel model = new SocialLinkModel(socialLinkData.getSocialProvider(), socialLinkData.getSocialUsername());
result.add(model);
}
return result;
}
@Override
public void addSocialLink(UserModel user, SocialLinkModel socialLink) {
UserData userData = ((UserAdapter)user).getUser();
SocialLinkData socialLinkData = new SocialLinkData();
socialLinkData.setSocialProvider(socialLink.getSocialProvider());
socialLinkData.setSocialUsername(socialLink.getSocialUsername());
socialLinkData.setUserId(userData.getId());
noSQL.saveObject(socialLinkData);
}
@Override
public void removeSocialLink(UserModel user, SocialLinkModel socialLink) {
UserData userData = ((UserAdapter)user).getUser();
String userId = userData.getId();
NoSQLQuery query = NoSQLQueryBuilder.create(MongoDBQueryBuilder.class)
.andCondition("socialProvider", socialLink.getSocialProvider())
.andCondition("socialUsername", socialLink.getSocialUsername())
.andCondition("userId", userId)
.build();
noSQL.removeObjects(SocialLinkData.class, query);
}
protected void updateRealm() {
noSQL.saveObject(realm);
}
protected RequiredCredentialModel initRequiredCredentialModel(String type) {
RequiredCredentialModel model = RequiredCredentialModel.BUILT_IN.get(type);
if (model == null) {
throw new RuntimeException("Unknown credential type " + type);
}
return model;
}
}

View file

@ -1,9 +1,8 @@
package org.keycloak.services.models.nosql.adapters;
package org.keycloak.services.models.nosql.keycloak.adapters;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.nosql.api.NoSQL;
import org.keycloak.services.models.nosql.data.RoleData;
import org.keycloak.services.models.nosql.data.UserData;
import org.keycloak.services.models.nosql.keycloak.data.RoleData;
/**
* Wrapper around RoleData object, which will persist wrapped object after each set operation (compatibility with picketlink based impl)
@ -46,4 +45,8 @@ public class RoleAdapter implements RoleModel {
role.setName(name);
noSQL.saveObject(role);
}
public RoleData getRole() {
return role;
}
}

View file

@ -1,10 +1,10 @@
package org.keycloak.services.models.nosql.adapters;
package org.keycloak.services.models.nosql.keycloak.adapters;
import java.util.Map;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.models.nosql.api.NoSQL;
import org.keycloak.services.models.nosql.data.UserData;
import org.keycloak.services.models.nosql.keycloak.data.UserData;
/**
* Wrapper around UserData object, which will persist wrapped object after each set operation (compatibility with picketlink based impl)
@ -90,4 +90,8 @@ public class UserAdapter implements UserModel {
public Map<String, String> getAttributes() {
return user.getAttributes();
}
public UserData getUser() {
return user;
}
}

View file

@ -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;
}
}

View file

@ -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
}

View file

@ -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;
}
}

View file

@ -1,4 +1,8 @@
package org.keycloak.services.models.nosql.data;
package org.keycloak.services.models.nosql.keycloak.data;
import java.security.SecureRandom;
import java.util.Random;
import java.util.UUID;
import org.keycloak.services.models.nosql.api.NoSQLCollection;
import org.keycloak.services.models.nosql.api.NoSQLField;
@ -11,6 +15,8 @@ import org.keycloak.services.models.nosql.api.NoSQLObject;
@NoSQLCollection(collectionName = "realms")
public class RealmData implements NoSQLObject {
private String oid;
private String id;
private String name;
private boolean enabled;
@ -23,9 +29,21 @@ public class RealmData implements NoSQLObject {
private int accessCodeLifespan;
private String publicKeyPem;
private String privateKeyPem;
private String[] defaultRoles;
private String[] realmAdmins;
@NoSQLId
public String getOid() {
return oid;
}
public void setOid(String oid) {
this.oid = oid;
}
// TODO: Is ID really needed? It seems that it exists just to workaround picketlink...
@NoSQLField
public String getId() {
return id;
}
@ -141,4 +159,14 @@ public class RealmData implements NoSQLObject {
public void setDefaultRoles(String[] defaultRoles) {
this.defaultRoles = defaultRoles;
}
@NoSQLField
public String[] getRealmAdmins() {
return realmAdmins;
}
public void setRealmAdmins(String[] realmAdmins) {
this.realmAdmins = realmAdmins;
}
}

View file

@ -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;
}
}

View file

@ -1,4 +1,4 @@
package org.keycloak.services.models.nosql.data;
package org.keycloak.services.models.nosql.keycloak.data;
import org.keycloak.services.models.nosql.api.NoSQLCollection;
import org.keycloak.services.models.nosql.api.NoSQLField;

View file

@ -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;
}
}

View file

@ -1,4 +1,4 @@
package org.keycloak.services.models.nosql.data;
package org.keycloak.services.models.nosql.keycloak.data;
import org.keycloak.services.models.nosql.api.AbstractAttributedNoSQLObject;
import org.keycloak.services.models.nosql.api.NoSQLCollection;
@ -20,6 +20,9 @@ public class UserData extends AbstractAttributedNoSQLObject {
private String realmId;
private String[] roleIds;
private String[] scopeIds;
@NoSQLId
public String getId() {
return id;
@ -82,4 +85,22 @@ public class UserData extends AbstractAttributedNoSQLObject {
public void setRealmId(String realmId) {
this.realmId = realmId;
}
@NoSQLField
public String[] getRoleIds() {
return roleIds;
}
public void setRoleIds(String[] roleIds) {
this.roleIds = roleIds;
}
@NoSQLField
public String[] getScopeIds() {
return scopeIds;
}
public void setScopeIds(String[] scopeIds) {
this.scopeIds = scopeIds;
}
}

View file

@ -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;
}
}

View file

@ -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() {