Adding TypeConverters. AdapterTest.test1CreateRealm() is passing for MongoDB
This commit is contained in:
parent
0acc9e978a
commit
815e466d43
20 changed files with 1356 additions and 115 deletions
|
@ -0,0 +1,43 @@
|
|||
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();
|
||||
}
|
||||
}
|
|
@ -1,49 +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;
|
||||
import org.keycloak.services.models.nosql.api.NoSQLObject;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
@NoSQLCollection(collectionName = "realms")
|
||||
public class NoSQLRealm implements NoSQLObject {
|
||||
|
||||
private String oid;
|
||||
private String prop1;
|
||||
private Integer prop2;
|
||||
|
||||
@NoSQLId
|
||||
public String getOid() {
|
||||
return oid;
|
||||
}
|
||||
|
||||
public void setOid(String oid) {
|
||||
this.oid = oid;
|
||||
}
|
||||
|
||||
@NoSQLField(fieldName = "property1")
|
||||
public String getProp1() {
|
||||
return prop1;
|
||||
}
|
||||
|
||||
public void setProp1(String prop1) {
|
||||
this.prop1 = prop1;
|
||||
}
|
||||
|
||||
@NoSQLField(fieldName = "property2")
|
||||
public Integer getProp2() {
|
||||
return prop2;
|
||||
}
|
||||
|
||||
public void setProp2(Integer prop2) {
|
||||
this.prop2 = prop2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NoSQLRealm [ oid=" + oid + ", prop1=" + prop1 + ", prop2=" + prop2 + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package org.keycloak.services.models.nosql.adapters;
|
||||
|
||||
import org.keycloak.services.models.KeycloakTransaction;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class NoSQLTransaction implements KeycloakTransaction {
|
||||
|
||||
@Override
|
||||
public void begin() {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRollbackOnly() {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRollbackOnly() {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,492 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package org.keycloak.services.models.nosql.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;
|
||||
|
||||
/**
|
||||
* Wrapper around RoleData object, which will persist wrapped object after each set operation (compatibility with picketlink based impl)
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class RoleAdapter implements RoleModel {
|
||||
|
||||
private final RoleData role;
|
||||
private final NoSQL noSQL;
|
||||
|
||||
public RoleAdapter(RoleData roleData, NoSQL noSQL) {
|
||||
this.role = roleData;
|
||||
this.noSQL = noSQL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return role.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return role.getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDescription(String description) {
|
||||
role.setDescription(description);
|
||||
noSQL.saveObject(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return role.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
role.setName(name);
|
||||
noSQL.saveObject(role);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package org.keycloak.services.models.nosql.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;
|
||||
|
||||
/**
|
||||
* Wrapper around UserData object, which will persist wrapped object after each set operation (compatibility with picketlink based impl)
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class UserAdapter implements UserModel {
|
||||
|
||||
private final UserData user;
|
||||
private final NoSQL noSQL;
|
||||
|
||||
public UserAdapter(UserData userData, NoSQL noSQL) {
|
||||
this.user = userData;
|
||||
this.noSQL = noSQL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoginName() {
|
||||
return user.getLoginName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return user.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
user.setEnabled(enabled);
|
||||
noSQL.saveObject(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFirstName() {
|
||||
return user.getFirstName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFirstName(String firstName) {
|
||||
user.setFirstName(firstName);
|
||||
noSQL.saveObject(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLastName() {
|
||||
return user.getLastName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastName(String lastName) {
|
||||
user.setLastName(lastName);
|
||||
noSQL.saveObject(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
return user.getEmail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmail(String email) {
|
||||
user.setEmail(email);
|
||||
noSQL.saveObject(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, String value) {
|
||||
user.setAttribute(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
user.removeAttribute(name);
|
||||
noSQL.saveObject(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttribute(String name) {
|
||||
return user.getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttributes() {
|
||||
return user.getAttributes();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package org.keycloak.services.models.nosql.api;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class AbstractAttributedNoSQLObject implements AttributedNoSQLObject {
|
||||
|
||||
// Simple hashMap for now (no thread-safe)
|
||||
private Map<String, String> attributes = new HashMap<String, String>();
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, String value) {
|
||||
attributes.put(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
// attributes.remove(name);
|
||||
|
||||
// ensure that particular attribute has null value, so it will be deleted in DB. TODO: needs to be improved
|
||||
attributes.put(name, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttribute(String name) {
|
||||
return attributes.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttributes() {
|
||||
return Collections.unmodifiableMap(attributes);
|
||||
}
|
||||
}
|
|
@ -15,12 +15,14 @@ public interface NoSQL {
|
|||
|
||||
<T extends NoSQLObject> T loadObject(Class<T> type, String oid);
|
||||
|
||||
<T extends NoSQLObject> List<T> loadObjects(Class<T> type, Map<String, Object> queryAttributes);
|
||||
<T extends NoSQLObject> T loadSingleObject(Class<T> type, NoSQLQuery query);
|
||||
|
||||
<T extends NoSQLObject> List<T> loadObjects(Class<T> type, NoSQLQuery query);
|
||||
|
||||
// Object must have filled oid
|
||||
void removeObject(NoSQLObject object);
|
||||
|
||||
void removeObject(Class<? extends NoSQLObject> type, String oid);
|
||||
|
||||
void removeObjects(Class<? extends NoSQLObject> type, Map<String, Object> queryAttributes);
|
||||
void removeObjects(Class<? extends NoSQLObject> type, NoSQLQuery query);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package org.keycloak.services.models.nosql.api;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class NoSQLQuery {
|
||||
|
||||
private Map<String, Object> queryAttributes = new HashMap<String, Object>();
|
||||
|
||||
private NoSQLQuery() {};
|
||||
|
||||
public static NoSQLQuery create() {
|
||||
return new NoSQLQuery();
|
||||
}
|
||||
|
||||
public NoSQLQuery put(String name, Object value) {
|
||||
queryAttributes.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, Object> getQueryAttributes() {
|
||||
return Collections.unmodifiableMap(queryAttributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NoSQLQuery [" + queryAttributes + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package org.keycloak.services.models.nosql.api.types;
|
||||
|
||||
/**
|
||||
* SPI object to convert object from application type to database type and vice versa. Shouldn't be directly used by application.
|
||||
* Various converters should be registered in TypeConverter, which is main entry point to be used by application
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface Converter<T, S> {
|
||||
|
||||
T convertDBObjectToApplicationObject(S dbObject);
|
||||
|
||||
S convertApplicationObjectToDBObject(T applicationObject);
|
||||
|
||||
Class<? extends T> getApplicationObjectType();
|
||||
|
||||
Class<S> getDBObjectType();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package org.keycloak.services.models.nosql.api.types;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
class ConverterKey {
|
||||
|
||||
private final Class<?> applicationObjectType;
|
||||
private final Class<?> dbObjectType;
|
||||
|
||||
public ConverterKey(Class<?> applicationObjectType, Class<?> dbObjectType) {
|
||||
this.applicationObjectType = applicationObjectType;
|
||||
this.dbObjectType = dbObjectType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return applicationObjectType.hashCode() * 13 + dbObjectType.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !obj.getClass().equals(this.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ConverterKey tc = (ConverterKey)obj;
|
||||
return tc.applicationObjectType.equals(this.applicationObjectType) && tc.dbObjectType.equals(this.dbObjectType);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package org.keycloak.services.models.nosql.api.types;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Registry of converters, which allow to convert application object to database objects. TypeConverter is main entry point to be used by application.
|
||||
* Application can create instance of TypeConverter and then register required Converter objects.
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class TypeConverter {
|
||||
|
||||
private Map<ConverterKey, Converter<?, ?>> converterRegistry = new HashMap<ConverterKey, Converter<?, ?>>();
|
||||
|
||||
public <T, S> void addConverter(Converter<T, S> converter) {
|
||||
ConverterKey converterKey = new ConverterKey(converter.getApplicationObjectType(), converter.getDBObjectType());
|
||||
converterRegistry.put(converterKey, converter);
|
||||
}
|
||||
|
||||
public <T, S> T convertDBObjectToApplicationObject(S dbObject, Class<T> expectedApplicationObjectType, Class<S> expectedDBObjectType) {
|
||||
Converter<T, S> converter = getConverter(expectedApplicationObjectType, expectedDBObjectType);
|
||||
return converter.convertDBObjectToApplicationObject(dbObject);
|
||||
}
|
||||
|
||||
public <T, S> S convertApplicationObjectToDBObject(T applicationobject, Class<T> expectedApplicationObjectType, Class<S> expectedDBObjectType) {
|
||||
Converter<T, S> converter = getConverter(expectedApplicationObjectType, expectedDBObjectType);
|
||||
return converter.convertApplicationObjectToDBObject(applicationobject);
|
||||
}
|
||||
|
||||
private <T, S> Converter<T, S> getConverter( Class<T> expectedApplicationObjectType, Class<S> expectedDBObjectType) {
|
||||
ConverterKey key = new ConverterKey(expectedApplicationObjectType, expectedDBObjectType);
|
||||
Converter<T, S> converter = (Converter<T, S>)converterRegistry.get(key);
|
||||
|
||||
if (converter == null) {
|
||||
throw new IllegalStateException("Can't found converter for expectedApplicationObject=" + expectedApplicationObjectType + ", expectedDBObjectType=" + expectedDBObjectType);
|
||||
}
|
||||
|
||||
return converter;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
package org.keycloak.services.models.nosql.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 = "realms")
|
||||
public class RealmData implements NoSQLObject {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private boolean enabled;
|
||||
private boolean sslNotRequired;
|
||||
private boolean cookieLoginAllowed;
|
||||
private boolean registrationAllowed;
|
||||
private boolean social;
|
||||
private boolean automaticRegistrationAfterSocialLogin;
|
||||
private int tokenLifespan;
|
||||
private int accessCodeLifespan;
|
||||
private String publicKeyPem;
|
||||
private String privateKeyPem;
|
||||
private String[] defaultRoles;
|
||||
|
||||
@NoSQLId
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String realmName) {
|
||||
this.name = realmName;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public boolean isSslNotRequired() {
|
||||
return sslNotRequired;
|
||||
}
|
||||
|
||||
public void setSslNotRequired(boolean sslNotRequired) {
|
||||
this.sslNotRequired = sslNotRequired;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public boolean isCookieLoginAllowed() {
|
||||
return cookieLoginAllowed;
|
||||
}
|
||||
|
||||
public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
|
||||
this.cookieLoginAllowed = cookieLoginAllowed;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public boolean isRegistrationAllowed() {
|
||||
return registrationAllowed;
|
||||
}
|
||||
|
||||
public void setRegistrationAllowed(boolean registrationAllowed) {
|
||||
this.registrationAllowed = registrationAllowed;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public boolean isSocial() {
|
||||
return social;
|
||||
}
|
||||
|
||||
public void setSocial(boolean social) {
|
||||
this.social = social;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public boolean isAutomaticRegistrationAfterSocialLogin() {
|
||||
return automaticRegistrationAfterSocialLogin;
|
||||
}
|
||||
|
||||
public void setAutomaticRegistrationAfterSocialLogin(boolean automaticRegistrationAfterSocialLogin) {
|
||||
this.automaticRegistrationAfterSocialLogin = automaticRegistrationAfterSocialLogin;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public int getTokenLifespan() {
|
||||
return tokenLifespan;
|
||||
}
|
||||
|
||||
public void setTokenLifespan(int tokenLifespan) {
|
||||
this.tokenLifespan = tokenLifespan;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public int getAccessCodeLifespan() {
|
||||
return accessCodeLifespan;
|
||||
}
|
||||
|
||||
public void setAccessCodeLifespan(int accessCodeLifespan) {
|
||||
this.accessCodeLifespan = accessCodeLifespan;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String getPublicKeyPem() {
|
||||
return publicKeyPem;
|
||||
}
|
||||
|
||||
public void setPublicKeyPem(String publicKeyPem) {
|
||||
this.publicKeyPem = publicKeyPem;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String getPrivateKeyPem() {
|
||||
return privateKeyPem;
|
||||
}
|
||||
|
||||
public void setPrivateKeyPem(String privateKeyPem) {
|
||||
this.privateKeyPem = privateKeyPem;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String[] getDefaultRoles() {
|
||||
return defaultRoles;
|
||||
}
|
||||
|
||||
public void setDefaultRoles(String[] defaultRoles) {
|
||||
this.defaultRoles = defaultRoles;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package org.keycloak.services.models.nosql.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 = "roles")
|
||||
public class RoleData implements NoSQLObject {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
|
||||
private String realmId;
|
||||
private String applicationId;
|
||||
|
||||
@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 String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String getRealmId() {
|
||||
return realmId;
|
||||
}
|
||||
|
||||
public void setRealmId(String realmId) {
|
||||
this.realmId = realmId;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String getApplicationId() {
|
||||
return applicationId;
|
||||
}
|
||||
|
||||
public void setApplicationId(String applicationId) {
|
||||
this.applicationId = applicationId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package org.keycloak.services.models.nosql.data;
|
||||
|
||||
import org.keycloak.services.models.nosql.api.AbstractAttributedNoSQLObject;
|
||||
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 UserData extends AbstractAttributedNoSQLObject {
|
||||
|
||||
private String id;
|
||||
private String loginName;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private String email;
|
||||
private boolean enabled;
|
||||
|
||||
private String realmId;
|
||||
|
||||
@NoSQLId
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String getLoginName() {
|
||||
return loginName;
|
||||
}
|
||||
|
||||
public void setLoginName(String loginName) {
|
||||
this.loginName = loginName;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String getRealmId() {
|
||||
return realmId;
|
||||
}
|
||||
|
||||
public void setRealmId(String realmId) {
|
||||
this.realmId = realmId;
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ 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;
|
||||
|
@ -20,9 +21,14 @@ 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.types.Converter;
|
||||
import org.keycloak.services.models.nosql.api.types.TypeConverter;
|
||||
import org.keycloak.services.models.nosql.impl.types.BasicDBListToStringArrayConverter;
|
||||
import org.picketlink.common.properties.Property;
|
||||
import org.picketlink.common.properties.query.AnnotatedPropertyCriteria;
|
||||
import org.picketlink.common.properties.query.PropertyQueries;
|
||||
import org.picketlink.common.reflection.Types;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
|
@ -32,14 +38,20 @@ public class MongoDBImpl implements NoSQL {
|
|||
private final DB database;
|
||||
// private static final Logger logger = Logger.getLogger(MongoDBImpl.class);
|
||||
|
||||
private final TypeConverter typeConverter;
|
||||
|
||||
public MongoDBImpl(DB database) {
|
||||
this.database = database;
|
||||
|
||||
typeConverter = new TypeConverter();
|
||||
typeConverter.addConverter(new BasicDBListToStringArrayConverter());
|
||||
}
|
||||
|
||||
private ConcurrentMap<Class<? extends NoSQLObject>, ObjectInfo<? extends NoSQLObject>> objectInfoCache =
|
||||
new ConcurrentHashMap<Class<? extends NoSQLObject>, ObjectInfo<? extends NoSQLObject>>();
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void saveObject(NoSQLObject object) {
|
||||
Class<?> clazz = object.getClass();
|
||||
|
@ -96,32 +108,62 @@ public class MongoDBImpl implements NoSQL {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T extends NoSQLObject> List<T> loadObjects(Class<T> type, Map<String, Object> queryAttributes) {
|
||||
public <T extends NoSQLObject> T loadSingleObject(Class<T> type, NoSQLQuery query) {
|
||||
List<T> result = loadObjects(type, query);
|
||||
if (result.size() > 1) {
|
||||
throw new IllegalStateException("There are " + result.size() + " results for type=" + type + ", query=" + query + ". We expect just one");
|
||||
} else if (result.size() == 1) {
|
||||
return result.get(0);
|
||||
} else {
|
||||
// 0 results
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@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());
|
||||
|
||||
BasicDBObject query = new BasicDBObject();
|
||||
BasicDBObject dbQuery = new BasicDBObject();
|
||||
for (Map.Entry<String, Object> queryAttr : queryAttributes.entrySet()) {
|
||||
query.append(queryAttr.getKey(), queryAttr.getValue());
|
||||
dbQuery.append(queryAttr.getKey(), queryAttr.getValue());
|
||||
}
|
||||
DBCursor cursor = dbCollection.find(query);
|
||||
DBCursor cursor = dbCollection.find(dbQuery);
|
||||
|
||||
return convertCursor(type, cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeObject(NoSQLObject object) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
Class<? extends NoSQLObject> type = object.getClass();
|
||||
ObjectInfo<?> objectInfo = getObjectInfo(type);
|
||||
|
||||
Property<String> idProperty = objectInfo.getOidProperty();
|
||||
String oid = idProperty.getValue(object);
|
||||
|
||||
removeObject(type, oid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeObject(Class<? extends NoSQLObject> type, String oid) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
ObjectInfo<?> objectInfo = getObjectInfo(type);
|
||||
DBCollection dbCollection = database.getCollection(objectInfo.getDbCollectionName());
|
||||
|
||||
BasicDBObject query = new BasicDBObject("_id", new ObjectId(oid));
|
||||
dbCollection.remove(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeObjects(Class<? extends NoSQLObject> type, Map<String, Object> queryAttributes) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
public void removeObjects(Class<? extends NoSQLObject> type, NoSQLQuery query) {
|
||||
throw new NotImplementedYetException();
|
||||
}
|
||||
|
||||
// Possibility to add converters
|
||||
public void addConverter(Converter<?, ?> converter) {
|
||||
typeConverter.addConverter(converter);
|
||||
}
|
||||
|
||||
private <T extends NoSQLObject> ObjectInfo<T> getObjectInfo(Class<?> objectClass) {
|
||||
|
@ -173,7 +215,20 @@ public class MongoDBImpl implements NoSQL {
|
|||
|
||||
} else if ((property = objectInfo.getPropertyByName(key)) != null) {
|
||||
// It's declared property with @DBField annotation
|
||||
property.setValue(object, value);
|
||||
Class<?> expectedType = property.getJavaClass();
|
||||
Class actualType = value != null ? value.getClass() : expectedType;
|
||||
|
||||
// handle primitives
|
||||
expectedType = Types.boxedClass(expectedType);
|
||||
actualType = Types.boxedClass(actualType);
|
||||
|
||||
if (actualType.isAssignableFrom(expectedType)) {
|
||||
property.setValue(object, value);
|
||||
} else {
|
||||
// we need to convert
|
||||
Object convertedValue = typeConverter.convertDBObjectToApplicationObject(value, expectedType, actualType);
|
||||
property.setValue(object, convertedValue);
|
||||
}
|
||||
|
||||
} else if (object instanceof AttributedNoSQLObject) {
|
||||
// It's attributed object and property is not declared, so we will call setAttribute
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
package org.keycloak.services.models.nosql.impl;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.MongoClient;
|
||||
import org.keycloak.services.models.nosql.adapters.NoSQLRealm;
|
||||
|
||||
/**
|
||||
* TODO: delete
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) throws UnknownHostException {
|
||||
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
|
||||
DB javaDB = mongoClient.getDB("java");
|
||||
|
||||
MongoDBImpl test = new MongoDBImpl(javaDB);
|
||||
NoSQLRealm realm = new NoSQLRealm();
|
||||
realm.setOid("522085fc31dab908ec31c0cb");
|
||||
realm.setProp1("something1");
|
||||
realm.setProp2(12);
|
||||
test.saveObject(realm);
|
||||
System.out.println(realm.getOid());
|
||||
|
||||
realm = test.loadObject(NoSQLRealm.class, "522085fc31dab908ec31c0cb");
|
||||
System.out.println("Loaded realm: " + realm);
|
||||
|
||||
Map<String, Object> query = new HashMap<String, Object>();
|
||||
query.put("prop1", "sm");
|
||||
List<NoSQLRealm> queryResults = test.loadObjects(NoSQLRealm.class, query);
|
||||
System.out.println("results1: " + queryResults);
|
||||
|
||||
query.put("prop1", "something2");
|
||||
queryResults = test.loadObjects(NoSQLRealm.class, query);
|
||||
System.out.println("results2: " + queryResults);
|
||||
|
||||
query.put("prop2", 12);
|
||||
queryResults = test.loadObjects(NoSQLRealm.class, query);
|
||||
System.out.println("results3: " + queryResults);
|
||||
|
||||
query.put("prop1", "something1");
|
||||
queryResults = test.loadObjects(NoSQLRealm.class, query);
|
||||
System.out.println("results4: " + queryResults);
|
||||
|
||||
mongoClient.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package org.keycloak.services.models.nosql.impl.types;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import org.keycloak.services.models.nosql.api.types.Converter;
|
||||
|
||||
/**
|
||||
* Convert BasicDBList to String[] and viceversa (T needs to be declared as Object as Array is not possible here :/ )
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class BasicDBListToStringArrayConverter implements Converter<Object, BasicDBList> {
|
||||
|
||||
private static final String[] PLACEHOLDER = new String[] {};
|
||||
|
||||
@Override
|
||||
public Object convertDBObjectToApplicationObject(BasicDBList dbObject) {
|
||||
return dbObject.toArray(PLACEHOLDER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDBList convertApplicationObjectToDBObject(Object applicationObject) {
|
||||
BasicDBList list = new BasicDBList();
|
||||
|
||||
String[] array = (String[])applicationObject;
|
||||
for (String key : array) {
|
||||
list.add(key);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getApplicationObjectType() {
|
||||
return PLACEHOLDER.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<BasicDBList> getDBObjectType() {
|
||||
return BasicDBList.class;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,11 @@ import org.keycloak.models.picketlink.PicketlinkKeycloakSession;
|
|||
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.picketlink.PicketlinkKeycloakSession;
|
||||
import org.keycloak.services.models.picketlink.mappings.ApplicationEntity;
|
||||
import org.keycloak.services.models.picketlink.mappings.RealmEntity;
|
||||
import org.keycloak.social.SocialRequestManager;
|
||||
import org.picketlink.idm.PartitionManager;
|
||||
import org.picketlink.idm.config.IdentityConfigurationBuilder;
|
||||
|
@ -54,8 +59,9 @@ public class KeycloakApplication extends Application {
|
|||
}
|
||||
|
||||
public static KeycloakSessionFactory buildSessionFactory() {
|
||||
EntityManagerFactory emf = Persistence.createEntityManagerFactory("keycloak-identity-store");
|
||||
return new PicketlinkKeycloakSessionFactory(emf, buildPartitionManager());
|
||||
// EntityManagerFactory emf = Persistence.createEntityManagerFactory("keycloak-identity-store");
|
||||
// return new PicketlinkKeycloakSessionFactory(emf, buildPartitionManager());
|
||||
return new MongoDBSessionFactory("localhost", 27017, "keycloak");
|
||||
}
|
||||
|
||||
public KeycloakSessionFactory getFactory() {
|
||||
|
|
Loading…
Reference in a new issue