Merge pull request #15 from patriot1burke/master

picketlink upgrade
This commit is contained in:
Bill Burke 2013-08-01 16:17:40 -07:00
commit 4f673117af
39 changed files with 1566 additions and 778 deletions

View file

@ -40,7 +40,7 @@
</dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-schema</artifactId>
<artifactId>picketlink-idm-simple-schema</artifactId>
</dependency>
<dependency>
<groupId>org.picketlink</groupId>

View file

@ -5,15 +5,23 @@
<persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>org.picketlink.idm.jpa.schema.IdentityObject</class>
<class>org.picketlink.idm.jpa.schema.PartitionObject</class>
<class>org.picketlink.idm.jpa.schema.RelationshipObject</class>
<class>org.picketlink.idm.jpa.schema.RelationshipIdentityObject</class>
<class>org.picketlink.idm.jpa.schema.RelationshipIdentityWeakObject</class>
<class>org.picketlink.idm.jpa.schema.RelationshipObjectAttribute</class>
<class>org.picketlink.idm.jpa.schema.IdentityObjectAttribute</class>
<class>org.picketlink.idm.jpa.schema.CredentialObject</class>
<class>org.picketlink.idm.jpa.schema.CredentialObjectAttribute</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity</class>
<class>org.keycloak.services.models.picketlink.mappings.RealmEntity</class>
<class>org.keycloak.services.models.picketlink.mappings.ResourceEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.connection.url" value="jdbc:h2:mem:test"/>

View file

@ -10,7 +10,7 @@
<properties>
<resteasy.version>3.0.2.Final</resteasy.version>
<picketlink.version>2.5.0.Keycloak-alpha-1</picketlink.version>
<picketlink.version>2.5.0.Beta6</picketlink.version>
</properties>
<url>http://keycloak.org</url>
@ -57,10 +57,11 @@
<module>services</module>
<module>integration</module>
<module>examples</module>
<!--
<module>sdk-html</module>
<module>social</module>
<module>server</module>
<module>ui</module>
<module>ui</module> -->
</modules>
<dependencyManagement>
@ -158,7 +159,7 @@
</dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-schema</artifactId>
<artifactId>picketlink-idm-simple-schema</artifactId>
<version>${picketlink.version}</version>
</dependency>
<dependency>

View file

@ -46,7 +46,7 @@
</dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-schema</artifactId>
<artifactId>picketlink-idm-simple-schema</artifactId>
<scope>provided</scope>
</dependency>
<dependency>

View file

@ -17,11 +17,11 @@ import java.io.IOException;
* @version $Revision: 1 $
*/
@PreMatching
public class KeycloakSessionFilter implements ContainerRequestFilter, ContainerResponseFilter {
protected static final Logger logger = Logger.getLogger(KeycloakSessionFilter.class);
public class KeycloakSessionRequestFilter implements ContainerRequestFilter, ContainerResponseFilter {
protected static final Logger logger = Logger.getLogger(KeycloakSessionRequestFilter.class);
protected KeycloakSessionFactory factory;
public KeycloakSessionFilter(KeycloakSessionFactory factory) {
public KeycloakSessionRequestFilter(KeycloakSessionFactory factory) {
this.factory = factory;
}

View file

@ -0,0 +1,27 @@
package org.keycloak.services.filters;
import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakSessionFactory;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.container.PreMatching;
import java.io.IOException;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakSessionResponseFilter implements ContainerResponseFilter {
protected static final Logger logger = Logger.getLogger(KeycloakSessionResponseFilter.class);
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
KeycloakSession ctx = (KeycloakSession)requestContext.getProperty(KeycloakSession.class.getName());
if (ctx != null) ctx.close();
}
}

View file

@ -0,0 +1,43 @@
package org.keycloak.services.models.jpa.entities;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import java.util.Collection;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class RealmEntity {
@Id
protected String id;
protected String realmName;
protected boolean enabled;
protected boolean sslNotRequired;
protected boolean cookieLoginAllowed;
protected boolean registrationAllowed;
protected int tokenLifespan;
protected int accessCodeLifespan;
@Column(length = 2048)
protected String publicKeyPem;
@Column(length = 2048)
protected String privateKeyPem;
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true)
Collection<RequiredCredentailEntity> requiredCredentials;
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true)
Collection<ResourceEntity> resources;
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
Collection<RoleEntity> roles;
}

View file

@ -0,0 +1,11 @@
package org.keycloak.services.models.jpa.entities;
import javax.persistence.Entity;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Entity
public class RequiredCredentailEntity {
}

View file

@ -0,0 +1,88 @@
package org.keycloak.services.models.jpa.entities;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import java.util.Collection;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Entity
public class ResourceEntity {
@Id
@GeneratedValue
private String id;
private String resourceName;
private boolean enabled;
private boolean surrogateAuthRequired;
private String managementUrl;
@ManyToOne
private UserEntity resourceUser;
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
Collection<RoleEntity> roles;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getResourceName() {
return resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isSurrogateAuthRequired() {
return surrogateAuthRequired;
}
public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
this.surrogateAuthRequired = surrogateAuthRequired;
}
public String getManagementUrl() {
return managementUrl;
}
public void setManagementUrl(String managementUrl) {
this.managementUrl = managementUrl;
}
public UserEntity getResourceUser() {
return resourceUser;
}
public void setResourceUser(UserEntity resourceUser) {
this.resourceUser = resourceUser;
}
public Collection<RoleEntity> getRoles() {
return roles;
}
public void setRoles(Collection<RoleEntity> roles) {
this.roles = roles;
}
}

View file

@ -0,0 +1,43 @@
package org.keycloak.services.models.jpa.entities;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Entity
public class RoleEntity {
@Id
@GeneratedValue
private String id;
private String name;
private String description;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View file

@ -0,0 +1,46 @@
package org.keycloak.services.models.jpa.entities;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Entity
public class ScopeMappingEntity {
@Id
@GeneratedValue
private long id;
@ManyToOne
private UserEntity user;
@ManyToOne
private RoleEntity role;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
public RoleEntity getRole() {
return role;
}
public void setRole(RoleEntity role) {
this.role = role;
}
}

View file

@ -0,0 +1,34 @@
package org.keycloak.services.models.jpa.entities;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Entity
public class UserEntity {
@Id
@GeneratedValue
private String id;
private String loginName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
}

View file

@ -0,0 +1,47 @@
package org.keycloak.services.models.jpa.entities;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Entity
public class UserRoleMappingEntity {
@Id
@GeneratedValue
private long id;
@ManyToOne
private UserEntity user;
@ManyToOne
private RoleEntity role;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
public RoleEntity getRole() {
return role;
}
public void setRole(RoleEntity role) {
this.role = role;
}
}

View file

@ -4,11 +4,10 @@ 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.picketlink.idm.IdentityManager;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.model.Realm;
import org.picketlink.idm.model.SimpleAgent;
import org.keycloak.services.models.picketlink.mappings.RealmData;
import org.picketlink.idm.PartitionManager;
import javax.persistence.EntityManager;
import java.util.concurrent.atomic.AtomicLong;
/**
@ -16,20 +15,31 @@ import java.util.concurrent.atomic.AtomicLong;
* @version $Revision: 1 $
*/
public class PicketlinkKeycloakSession implements KeycloakSession {
protected IdentitySession session;
public static ThreadLocal<EntityManager> currentEntityManager = new ThreadLocal<EntityManager>();
public static ThreadLocal<Exception> setWhere = new ThreadLocal<Exception>();
protected PartitionManager partitionManager;
protected EntityManager entityManager;
private static AtomicLong counter = new AtomicLong(1);
public static String generateId() {
return counter.getAndIncrement() + "-" + System.currentTimeMillis();
}
public PicketlinkKeycloakSession(IdentitySession session) {
this.session = session;
public PicketlinkKeycloakSession(PartitionManager partitionManager, EntityManager entityManager) {
this.partitionManager = partitionManager;
this.entityManager = entityManager;
if (currentEntityManager.get() != null)
{
setWhere.get().printStackTrace();
throw new IllegalStateException("Thread local was leaked!");
}
currentEntityManager.set(entityManager);
setWhere.set(new Exception());
}
@Override
public KeycloakTransaction getTransaction() {
return new PicketlinkKeycloakTransaction(session.getTransaction());
return new PicketlinkKeycloakTransaction(entityManager.getTransaction());
}
@Override
@ -39,21 +49,22 @@ public class PicketlinkKeycloakSession implements KeycloakSession {
@Override
public RealmAdapter createRealm(String id, String name) {
Realm newRealm = session.createRealm(id);
IdentityManager idm = session.createIdentityManager(newRealm);
SimpleAgent agent = new SimpleAgent(RealmAdapter.REALM_AGENT_ID);
idm.add(agent);
RealmAdapter realm = new RealmAdapter(newRealm, session);
// Picketlink beta 6 uses name attribute for getPartition()
RealmData newRealm = new RealmData(id);
newRealm.setId(id);
newRealm.setRealmName(name);
partitionManager.add(newRealm);
RealmAdapter realm = new RealmAdapter(this, newRealm, partitionManager);
return realm;
}
@Override
public RealmAdapter getRealm(String id) {
Realm existing = session.findRealm(id);
RealmData existing = partitionManager.getPartition(RealmData.class, id);
if (existing == null) {
return null;
}
return new RealmAdapter(existing, session);
return new RealmAdapter(this, existing, partitionManager);
}
@Override
@ -64,6 +75,9 @@ public class PicketlinkKeycloakSession implements KeycloakSession {
@Override
public void close() {
session.close();
if (entityManager.getTransaction().isActive()) entityManager.getTransaction().rollback();
setWhere.set(null);
currentEntityManager.set(null);
if (entityManager.isOpen()) entityManager.close();
}
}

View file

@ -2,22 +2,26 @@ package org.keycloak.services.models.picketlink;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakSessionFactory;
import org.picketlink.idm.IdentitySessionFactory;
import org.picketlink.idm.PartitionManager;
import javax.persistence.EntityManagerFactory;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class PicketlinkKeycloakSessionFactory implements KeycloakSessionFactory {
protected IdentitySessionFactory factory;
protected EntityManagerFactory factory;
protected PartitionManager partitionManager;
public PicketlinkKeycloakSessionFactory(IdentitySessionFactory factory) {
public PicketlinkKeycloakSessionFactory(EntityManagerFactory factory, PartitionManager partitionManager) {
this.factory = factory;
this.partitionManager = partitionManager;
}
@Override
public KeycloakSession createSession() {
return new PicketlinkKeycloakSession(factory.createIdentitySession());
return new PicketlinkKeycloakSession(partitionManager, factory.createEntityManager());
}
@Override

View file

@ -1,16 +1,17 @@
package org.keycloak.services.models.picketlink;
import org.keycloak.services.models.KeycloakTransaction;
import org.picketlink.idm.IdentityTransaction;
import javax.persistence.EntityTransaction;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class PicketlinkKeycloakTransaction implements KeycloakTransaction{
protected IdentityTransaction transaction;
public class PicketlinkKeycloakTransaction implements KeycloakTransaction {
protected EntityTransaction transaction;
public PicketlinkKeycloakTransaction(IdentityTransaction transaction) {
public PicketlinkKeycloakTransaction(EntityTransaction transaction) {
this.transaction = transaction;
}

View file

@ -4,33 +4,32 @@ import org.bouncycastle.openssl.PEMWriter;
import org.jboss.resteasy.security.PemUtils;
import org.keycloak.representations.idm.RequiredCredentialRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.ResourceModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserCredentialModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.models.picketlink.mappings.RealmData;
import org.keycloak.services.models.picketlink.mappings.ResourceData;
import org.keycloak.services.models.picketlink.relationships.RealmAdminRelationship;
import org.keycloak.services.models.picketlink.relationships.RequiredCredentialRelationship;
import org.keycloak.services.models.picketlink.relationships.ResourceRelationship;
import org.keycloak.services.models.picketlink.relationships.ScopeRelationship;
import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.PartitionManager;
import org.picketlink.idm.RelationshipManager;
import org.picketlink.idm.credential.Credentials;
import org.picketlink.idm.credential.Password;
import org.picketlink.idm.credential.TOTPCredential;
import org.picketlink.idm.credential.TOTPCredentials;
import org.picketlink.idm.credential.UsernamePasswordCredentials;
import org.picketlink.idm.credential.X509CertificateCredentials;
import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Grant;
import org.picketlink.idm.model.Realm;
import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.SimpleRole;
import org.picketlink.idm.model.SimpleUser;
import org.picketlink.idm.model.Tier;
import org.picketlink.idm.model.User;
import org.picketlink.idm.model.sample.Grant;
import org.picketlink.idm.model.sample.Role;
import org.picketlink.idm.model.sample.SampleModel;
import org.picketlink.idm.model.sample.User;
import org.picketlink.idm.query.IdentityQuery;
import org.picketlink.idm.query.RelationshipQuery;
@ -53,140 +52,138 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class RealmAdapter implements RealmModel {
public static final String REALM_AGENT_ID = "_realm_";
public static final String REALM_NAME = "name";
public static final String REALM_ACCESS_CODE_LIFESPAN = "accessCodeLifespan";
public static final String REALM_TOKEN_LIFESPAN = "tokenLifespan";
public static final String REALM_PRIVATE_KEY = "privateKey";
public static final String REALM_PUBLIC_KEY = "publicKey";
public static final String REALM_IS_SSL_NOT_REQUIRED = "isSSLNotRequired";
public static final String REALM_IS_COOKIE_LOGIN_ALLOWED = "isCookieLoginAllowed";
public static final String REALM_IS_REGISTRATION_ALLOWED = "isRegistrationAllowed";
protected Realm realm;
protected Agent realmAgent;
protected IdentitySession identitySession;
protected RealmData realm;
protected volatile transient PublicKey publicKey;
protected volatile transient PrivateKey privateKey;
protected IdentityManager idm;
protected PartitionManager partitionManager;
protected RelationshipManager relationshipManager;
protected KeycloakSession session;
public RealmAdapter(Realm realm, IdentitySession session) {
public RealmAdapter(KeycloakSession session, RealmData realm, PartitionManager partitionManager) {
this.session = session;
this.realm = realm;
this.identitySession = session;
realmAgent = getIdm().getAgent(REALM_AGENT_ID);
this.partitionManager = partitionManager;
}
protected IdentityManager getIdm() {
if (idm == null) idm = identitySession.createIdentityManager(realm);
if (idm == null) idm = partitionManager.createIdentityManager(realm);
return idm;
}
protected RelationshipManager getRelationshipManager() {
if (relationshipManager == null) relationshipManager = partitionManager.createRelationshipManager();
return relationshipManager;
}
protected void updateRealm() {
getIdm().update(realmAgent);
partitionManager.update(realm);
}
@Override
public String getId() {
return realm.getId();
// for some reason picketlink queries by name when finding partition, don't know what ID is used for now
return realm.getName();
}
@Override
public String getName() {
return (String) realmAgent.getAttribute(REALM_NAME).getValue();
return realm.getRealmName();
}
@Override
public void setName(String name) {
realmAgent.setAttribute(new Attribute<String>(REALM_NAME, name));
realm.setRealmName(name);
updateRealm();
}
@Override
public boolean isEnabled() {
return realmAgent.isEnabled();
return realm.isEnabled();
}
@Override
public void setEnabled(boolean enabled) {
realmAgent.setEnabled(enabled);
realm.setEnabled(enabled);
updateRealm();
}
@Override
public boolean isSslNotRequired() {
return (Boolean) realmAgent.getAttribute(REALM_IS_SSL_NOT_REQUIRED).getValue();
return realm.isSslNotRequired();
}
@Override
public void setSslNotRequired(boolean sslNotRequired) {
realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_SSL_NOT_REQUIRED, sslNotRequired));
realm.setSslNotRequired(sslNotRequired);
updateRealm();
}
@Override
public boolean isCookieLoginAllowed() {
return (Boolean) realmAgent.getAttribute(REALM_IS_COOKIE_LOGIN_ALLOWED).getValue();
return realm.isCookieLoginAllowed();
}
@Override
public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_COOKIE_LOGIN_ALLOWED, cookieLoginAllowed));
realm.setCookieLoginAllowed(cookieLoginAllowed);
updateRealm();
}
@Override
public boolean isRegistrationAllowed() {
return (Boolean) realmAgent.getAttribute(REALM_IS_REGISTRATION_ALLOWED).getValue();
return realm.isRegistrationAllowed();
}
@Override
public void setRegistrationAllowed(boolean registrationAllowed) {
realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_REGISTRATION_ALLOWED, registrationAllowed));
realm.setRegistrationAllowed(registrationAllowed);
updateRealm();
}
@Override
public int getTokenLifespan() {
return (Integer) realmAgent.getAttribute(REALM_TOKEN_LIFESPAN).getValue();
return realm.getTokenLifespan();
}
@Override
public void setTokenLifespan(int tokenLifespan) {
realmAgent.setAttribute(new Attribute<Integer>(REALM_TOKEN_LIFESPAN, tokenLifespan));
realm.setTokenLifespan(tokenLifespan);
updateRealm();
}
@Override
public int getAccessCodeLifespan() {
return (Integer) realmAgent.getAttribute(REALM_ACCESS_CODE_LIFESPAN).getValue();
return realm.getAccessCodeLifespan();
}
@Override
public void setAccessCodeLifespan(int accessCodeLifespan) {
realmAgent.setAttribute(new Attribute<Integer>(REALM_ACCESS_CODE_LIFESPAN, accessCodeLifespan));
realm.setAccessCodeLifespan(accessCodeLifespan);
updateRealm();
}
@Override
public String getPublicKeyPem() {
return (String) realmAgent.getAttribute(REALM_PUBLIC_KEY).getValue();
return realm.getPublicKeyPem();
}
@Override
public void setPublicKeyPem(String publicKeyPem) {
realmAgent.setAttribute(new Attribute<String>(REALM_PUBLIC_KEY, publicKeyPem));
realm.setPublicKeyPem(publicKeyPem);
this.publicKey = null;
updateRealm();
}
@Override
public String getPrivateKeyPem() {
return (String) realmAgent.getAttribute(REALM_PRIVATE_KEY).getValue();
return realm.getPrivateKeyPem();
}
@Override
public void setPrivateKeyPem(String privateKeyPem) {
realmAgent.setAttribute(new Attribute<String>(REALM_PRIVATE_KEY, privateKeyPem));
realm.setPrivateKeyPem(privateKeyPem);
this.privateKey = null;
updateRealm();
}
@ -251,10 +248,8 @@ public class RealmAdapter implements RealmModel {
@Override
public List<RequiredCredentialModel> getRequiredCredentials() {
IdentityManager idm = getIdm();
Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
RelationshipQuery<RequiredCredentialRelationship> query = idm.createRelationshipQuery(RequiredCredentialRelationship.class);
query.setParameter(RequiredCredentialRelationship.REALM_AGENT, realmAgent);
RelationshipQuery<RequiredCredentialRelationship> query = getRelationshipManager().createRelationshipQuery(RequiredCredentialRelationship.class);
query.setParameter(RequiredCredentialRelationship.REALM, realm.getName());
List<RequiredCredentialRelationship> results = query.getResultList();
List<RequiredCredentialModel> rtn = new ArrayList<RequiredCredentialModel>();
for (RequiredCredentialRelationship relationship : results) {
@ -269,16 +264,15 @@ public class RealmAdapter implements RealmModel {
@Override
public void addRequiredCredential(RequiredCredentialModel cred) {
IdentityManager idm = getIdm();
Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
RequiredCredentialRelationship relationship = new RequiredCredentialRelationship();
relationship.setCredentialType(cred.getType());
relationship.setInput(cred.isInput());
relationship.setSecret(cred.isSecret());
relationship.setRealmAgent(realmAgent);
idm.add(relationship);
relationship.setRealm(realm.getName());
getRelationshipManager().add(relationship);
}
@Override
public boolean validatePassword(UserModel user, String password) {
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(user.getLoginName(), new Password(password));
@ -319,30 +313,34 @@ public class RealmAdapter implements RealmModel {
@Override
public UserAdapter getUser(String name) {
User user = getIdm().getUser(name);
User user = findPicketlinkUser(name);
if (user == null) return null;
return new UserAdapter(user, getIdm());
}
protected User findPicketlinkUser(String name) {
return SampleModel.getUser(getIdm(), name);
}
@Override
public UserAdapter addUser(String username) {
User user = getIdm().getUser(username);
User user = findPicketlinkUser(username);
if (user != null) throw new IllegalStateException("User already exists");
user = new SimpleUser(username);
user = new User(username);
getIdm().add(user);
return new UserAdapter(user, getIdm());
}
@Override
public RoleAdapter getRole(String name) {
Role role = getIdm().getRole(name);
Role role = SampleModel.getRole(getIdm(), name);
if (role == null) return null;
return new RoleAdapter(role, getIdm());
}
@Override
public RoleAdapter addRole(String name) {
Role role = new SimpleRole(name);
Role role = new Role(name);
getIdm().add(role);
return new RoleAdapter(role, getIdm());
}
@ -377,14 +375,13 @@ public class RealmAdapter implements RealmModel {
@Override
public List<ResourceModel> getResources() {
IdentityManager idm = getIdm();
RelationshipQuery<ResourceRelationship> query = idm.createRelationshipQuery(ResourceRelationship.class);
query.setParameter(ResourceRelationship.REALM_AGENT, realmAgent);
RelationshipQuery<ResourceRelationship> query = getRelationshipManager().createRelationshipQuery(ResourceRelationship.class);
query.setParameter(ResourceRelationship.REALM, realm.getName());
List<ResourceRelationship> results = query.getResultList();
List<ResourceModel> resources = new ArrayList<ResourceModel>();
for (ResourceRelationship relationship : results) {
Tier resourceTier = identitySession.findTier(relationship.getResourceId());
ResourceModel model = new ResourceAdapter(resourceTier,relationship, this, identitySession);
ResourceData resource = partitionManager.getPartition(ResourceData.class, relationship.getResource());
ResourceModel model = new ResourceAdapter(resource, this, partitionManager);
resources.add(model);
}
@ -393,18 +390,12 @@ public class RealmAdapter implements RealmModel {
@Override
public ResourceModel addResource(String name) {
Tier newTier = identitySession.createTier(RealmManager.generateId());
IdentityManager idm = getIdm();
ResourceRelationship relationship = new ResourceRelationship();
relationship.setResourceName(name);
relationship.setRealmAgent(realmAgent);
relationship.setResourceId(newTier.getId());
relationship.setManagementUrl(""); // Picketlink doesn't like null attribute values
User resourceUser = new SimpleUser(name);
ResourceData resourceData = new ResourceData(name);
User resourceUser = new User(name);
idm.add(resourceUser);
relationship.setResourceUser(resourceUser);
idm.add(relationship);
ResourceModel resource = new ResourceAdapter(newTier, relationship, this, identitySession);
resourceData.setResourceUser(resourceUser);
partitionManager.add(resourceData);
ResourceModel resource = new ResourceAdapter(resourceData, this, partitionManager);
resource.addRole("*");
resource.addScope(new UserAdapter(resourceUser, idm), "*");
return resource;
@ -412,17 +403,17 @@ public class RealmAdapter implements RealmModel {
@Override
public boolean hasRole(UserModel user, RoleModel role) {
return getIdm().hasRole(((UserAdapter)user).getUser(), ((RoleAdapter)role).getRole());
return SampleModel.hasRole(getRelationshipManager(), ((UserAdapter) user).getUser(), ((RoleAdapter) role).getRole());
}
@Override
public void grantRole(UserModel user, RoleModel role) {
getIdm().grantRole(((UserAdapter)user).getUser(), ((RoleAdapter)role).getRole());
SampleModel.grantRole(getRelationshipManager(), ((UserAdapter) user).getUser(), ((RoleAdapter) role).getRole());
}
@Override
public Set<String> getRoleMappings(UserModel user) {
RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
RelationshipQuery<Grant> query = getRelationshipManager().createRelationshipQuery(Grant.class);
query.setParameter(Grant.ASSIGNEE, ((UserAdapter)user).getUser());
List<Grant> grants = query.getResultList();
HashSet<String> set = new HashSet<String>();
@ -435,19 +426,18 @@ public class RealmAdapter implements RealmModel {
@Override
public void addScope(UserModel agent, String roleName) {
IdentityManager idm = getIdm();
Role role = idm.getRole(roleName);
Role role = SampleModel.getRole(idm, roleName);
if (role == null) throw new RuntimeException("role not found");
ScopeRelationship scope = new ScopeRelationship();
scope.setClient(((UserAdapter)agent).getUser());
scope.setScope(role);
idm.add(scope);
getRelationshipManager().add(scope);
}
@Override
public Set<String> getScope(UserModel agent) {
RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
RelationshipQuery<ScopeRelationship> query = getRelationshipManager().createRelationshipQuery(ScopeRelationship.class);
query.setParameter(ScopeRelationship.CLIENT, ((UserAdapter)agent).getUser());
List<ScopeRelationship> scope = query.getResultList();
HashSet<String> set = new HashSet<String>();
@ -459,10 +449,9 @@ public class RealmAdapter implements RealmModel {
@Override
public boolean isRealmAdmin(UserModel agent) {
RealmAdapter realmModel = (RealmAdapter)new RealmManager(new PicketlinkKeycloakSession(identitySession)).defaultRealm();
IdentityManager idm = realmModel.getIdm();
RelationshipQuery<RealmAdminRelationship> query = idm.createRelationshipQuery(RealmAdminRelationship.class);
query.setParameter(RealmAdminRelationship.REALM, realm.getId());
RealmAdapter realmModel = (RealmAdapter)new RealmManager(session).defaultRealm();
RelationshipQuery<RealmAdminRelationship> query = getRelationshipManager().createRelationshipQuery(RealmAdminRelationship.class);
query.setParameter(RealmAdminRelationship.REALM, realm.getName());
query.setParameter(RealmAdminRelationship.ADMIN, ((UserAdapter)agent).getUser());
List<RealmAdminRelationship> results = query.getResultList();
return results.size() > 0;
@ -470,10 +459,9 @@ public class RealmAdapter implements RealmModel {
@Override
public void addRealmAdmin(UserModel agent) {
RealmAdapter realmModel = (RealmAdapter)new RealmManager(new PicketlinkKeycloakSession(identitySession)).defaultRealm();
RealmAdminRelationship relationship = new RealmAdminRelationship();
relationship.setAdmin(((UserAdapter)agent).getUser());
relationship.setRealm(realm.getId());
idm.add(relationship);
relationship.setRealm(realm.getName());
getRelationshipManager().add(relationship);
}
}

View file

@ -3,14 +3,15 @@ package org.keycloak.services.models.picketlink;
import org.keycloak.services.models.ResourceModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.models.picketlink.mappings.ResourceData;
import org.keycloak.services.models.picketlink.relationships.ResourceRelationship;
import org.keycloak.services.models.picketlink.relationships.ScopeRelationship;
import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.model.Grant;
import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.SimpleRole;
import org.picketlink.idm.model.Tier;
import org.picketlink.idm.PartitionManager;
import org.picketlink.idm.RelationshipManager;
import org.picketlink.idm.model.sample.Grant;
import org.picketlink.idm.model.sample.Role;
import org.picketlink.idm.model.sample.SampleModel;
import org.picketlink.idm.query.IdentityQuery;
import org.picketlink.idm.query.RelationshipQuery;
@ -24,89 +25,94 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class ResourceAdapter implements ResourceModel {
protected Tier tier;
protected ResourceRelationship agent;
protected ResourceData resource;
protected RealmAdapter realm;
protected IdentitySession identitySession;
protected IdentityManager idm;
protected PartitionManager partitionManager;
protected RelationshipManager relationshipManager;
public ResourceAdapter(Tier tier, ResourceRelationship agent, RealmAdapter realm, IdentitySession session) {
this.tier = tier;
this.agent = agent;
public ResourceAdapter(ResourceData resource, RealmAdapter realm, PartitionManager partitionManager) {
this.resource = resource;
this.realm = realm;
this.identitySession = session;
this.partitionManager = partitionManager;
}
protected IdentityManager getIdm() {
if (idm == null) idm = identitySession.createIdentityManager(tier);
if (idm == null) idm = partitionManager.createIdentityManager(resource);
return idm;
}
protected RelationshipManager getRelationshipManager() {
if (relationshipManager == null) relationshipManager = partitionManager.createRelationshipManager();
return relationshipManager;
}
@Override
public void updateResource() {
getIdm().update(agent);
partitionManager.update(resource);
}
@Override
public UserAdapter getResourceUser() {
return new UserAdapter(agent.getResourceUser(), realm.getIdm());
return new UserAdapter(resource.getResourceUser(), realm.getIdm());
}
@Override
public String getId() {
return tier.getId();
// for some reason picketlink queries by name when finding partition, don't know what ID is used for now
return resource.getName();
}
@Override
public String getName() {
return agent.getResourceName();
return resource.getResourceName();
}
@Override
public void setName(String name) {
agent.setResourceName(name);
resource.setResourceName(name);
}
@Override
public boolean isEnabled() {
return agent.getEnabled();
return resource.isEnabled();
}
@Override
public void setEnabled(boolean enabled) {
agent.setEnabled(enabled);
resource.setEnabled(enabled);
}
@Override
public boolean isSurrogateAuthRequired() {
return agent.getSurrogateAuthRequired();
return resource.isSurrogateAuthRequired();
}
@Override
public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
agent.setSurrogateAuthRequired(surrogateAuthRequired);
resource.setSurrogateAuthRequired(surrogateAuthRequired);
}
@Override
public String getManagementUrl() {
return agent.getManagementUrl();
return resource.getManagementUrl();
}
@Override
public void setManagementUrl(String url) {
agent.setManagementUrl(url);
resource.setManagementUrl(url);
}
@Override
public RoleAdapter getRole(String name) {
Role role = getIdm().getRole(name);
Role role = SampleModel.getRole(getIdm(), name);
if (role == null) return null;
return new RoleAdapter(role, getIdm());
}
@Override
public RoleAdapter addRole(String name) {
Role role = new SimpleRole(name);
Role role = new Role(name);
getIdm().add(role);
return new RoleAdapter(role, getIdm());
}
@ -114,7 +120,7 @@ public class ResourceAdapter implements ResourceModel {
@Override
public List<RoleModel> getRoles() {
IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class);
query.setParameter(Role.PARTITION, tier);
query.setParameter(Role.PARTITION, resource);
List<Role> roles = query.getResultList();
List<RoleModel> roleModels = new ArrayList<RoleModel>();
for (Role role : roles) {
@ -125,12 +131,12 @@ public class ResourceAdapter implements ResourceModel {
@Override
public Set<String> getRoleMappings(UserModel user) {
RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
RelationshipQuery<Grant> query = getRelationshipManager().createRelationshipQuery(Grant.class);
query.setParameter(Grant.ASSIGNEE, ((UserAdapter)user).getUser());
List<Grant> grants = query.getResultList();
HashSet<String> set = new HashSet<String>();
for (Grant grant : grants) {
if (grant.getRole().getPartition().getId().equals(tier.getId())) set.add(grant.getRole().getName());
if (grant.getRole().getPartition().getId().equals(resource.getId())) set.add(grant.getRole().getName());
}
return set;
}
@ -138,7 +144,7 @@ public class ResourceAdapter implements ResourceModel {
@Override
public void addScope(UserModel agent, String roleName) {
IdentityManager idm = getIdm();
Role role = idm.getRole(roleName);
Role role = SampleModel.getRole(idm,roleName);
if (role == null) throw new RuntimeException("role not found");
addScope(agent, new RoleAdapter(role, idm));
@ -153,12 +159,12 @@ public class ResourceAdapter implements ResourceModel {
@Override
public Set<String> getScope(UserModel agent) {
RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
RelationshipQuery<ScopeRelationship> query = getRelationshipManager().createRelationshipQuery(ScopeRelationship.class);
query.setParameter(ScopeRelationship.CLIENT, ((UserAdapter)agent).getUser());
List<ScopeRelationship> scope = query.getResultList();
HashSet<String> set = new HashSet<String>();
for (ScopeRelationship rel : scope) {
if (rel.getScope().getPartition().getId().equals(tier.getId())) set.add(rel.getScope().getName());
if (rel.getScope().getPartition().getId().equals(resource.getId())) set.add(rel.getScope().getName());
}
return set;
}

View file

@ -3,7 +3,7 @@ package org.keycloak.services.models.picketlink;
import org.keycloak.services.models.RoleModel;
import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.sample.Role;
import java.io.Serializable;

View file

@ -3,7 +3,7 @@ package org.keycloak.services.models.picketlink;
import org.keycloak.services.models.UserModel;
import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.User;
import org.picketlink.idm.model.sample.User;
import java.util.HashMap;
import java.util.Map;

View file

@ -0,0 +1,109 @@
package org.keycloak.services.models.picketlink.mappings;
import org.picketlink.idm.jpa.annotations.AttributeValue;
import org.picketlink.idm.model.AbstractPartition;
import org.picketlink.idm.model.annotation.AttributeProperty;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class RealmData extends AbstractPartition {
private String realmName;
private boolean enabled;
private boolean sslNotRequired;
private boolean cookieLoginAllowed;
private boolean registrationAllowed;
private int tokenLifespan;
private int accessCodeLifespan;
private String publicKeyPem;
private String privateKeyPem;
public RealmData() {
super(null);
}
public RealmData(String name) {
super(name);
}
@AttributeProperty
public String getRealmName() {
return realmName;
}
public void setRealmName(String realmName) {
this.realmName = realmName;
}
@AttributeProperty
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@AttributeProperty
public boolean isSslNotRequired() {
return sslNotRequired;
}
public void setSslNotRequired(boolean sslNotRequired) {
this.sslNotRequired = sslNotRequired;
}
@AttributeProperty
public boolean isCookieLoginAllowed() {
return cookieLoginAllowed;
}
public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
this.cookieLoginAllowed = cookieLoginAllowed;
}
@AttributeProperty
public boolean isRegistrationAllowed() {
return registrationAllowed;
}
public void setRegistrationAllowed(boolean registrationAllowed) {
this.registrationAllowed = registrationAllowed;
}
@AttributeProperty
public int getTokenLifespan() {
return tokenLifespan;
}
public void setTokenLifespan(int tokenLifespan) {
this.tokenLifespan = tokenLifespan;
}
@AttributeProperty
public int getAccessCodeLifespan() {
return accessCodeLifespan;
}
public void setAccessCodeLifespan(int accessCodeLifespan) {
this.accessCodeLifespan = accessCodeLifespan;
}
@AttributeProperty
public String getPublicKeyPem() {
return publicKeyPem;
}
public void setPublicKeyPem(String publicKeyPem) {
this.publicKeyPem = publicKeyPem;
}
@AttributeProperty
public String getPrivateKeyPem() {
return privateKeyPem;
}
public void setPrivateKeyPem(String privateKeyPem) {
this.privateKeyPem = privateKeyPem;
}
}

View file

@ -0,0 +1,128 @@
package org.keycloak.services.models.picketlink.mappings;
import org.picketlink.idm.jpa.annotations.AttributeValue;
import org.picketlink.idm.jpa.annotations.OwnerReference;
import org.picketlink.idm.jpa.annotations.entity.IdentityManaged;
import org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import java.io.Serializable;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@IdentityManaged(RealmData.class)
@Entity
public class RealmEntity implements Serializable {
@OneToOne
@Id
@OwnerReference
private PartitionTypeEntity partitionTypeEntity;
@AttributeValue
private String realmName;
@AttributeValue
private boolean enabled;
@AttributeValue
private boolean sslNotRequired;
@AttributeValue
private boolean cookieLoginAllowed;
@AttributeValue
private boolean registrationAllowed;
@AttributeValue
private int tokenLifespan;
@AttributeValue
private int accessCodeLifespan;
@AttributeValue
@Column(length = 2048)
private String publicKeyPem;
@AttributeValue
@Column(length = 2048)
private String privateKeyPem;
public PartitionTypeEntity getPartitionTypeEntity() {
return partitionTypeEntity;
}
public void setPartitionTypeEntity(PartitionTypeEntity partitionTypeEntity) {
this.partitionTypeEntity = partitionTypeEntity;
}
public String getRealmName() {
return realmName;
}
public void setRealmName(String realmName) {
this.realmName = realmName;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isSslNotRequired() {
return sslNotRequired;
}
public void setSslNotRequired(boolean sslNotRequired) {
this.sslNotRequired = sslNotRequired;
}
public boolean isCookieLoginAllowed() {
return cookieLoginAllowed;
}
public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
this.cookieLoginAllowed = cookieLoginAllowed;
}
public boolean isRegistrationAllowed() {
return registrationAllowed;
}
public void setRegistrationAllowed(boolean registrationAllowed) {
this.registrationAllowed = registrationAllowed;
}
public int getTokenLifespan() {
return tokenLifespan;
}
public void setTokenLifespan(int tokenLifespan) {
this.tokenLifespan = tokenLifespan;
}
public int getAccessCodeLifespan() {
return accessCodeLifespan;
}
public void setAccessCodeLifespan(int accessCodeLifespan) {
this.accessCodeLifespan = accessCodeLifespan;
}
public String getPublicKeyPem() {
return publicKeyPem;
}
public void setPublicKeyPem(String publicKeyPem) {
this.publicKeyPem = publicKeyPem;
}
public String getPrivateKeyPem() {
return privateKeyPem;
}
public void setPrivateKeyPem(String privateKeyPem) {
this.privateKeyPem = privateKeyPem;
}
}

View file

@ -0,0 +1,68 @@
package org.keycloak.services.models.picketlink.mappings;
import org.picketlink.idm.jpa.annotations.AttributeValue;
import org.picketlink.idm.model.AbstractPartition;
import org.picketlink.idm.model.annotation.AttributeProperty;
import org.picketlink.idm.model.sample.User;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceData extends AbstractPartition {
private String resourceName;
private boolean enabled;
private boolean surrogateAuthRequired;
private String managementUrl;
private User resourceUser;
public ResourceData() {
super(null);
}
public ResourceData(String name) {
super(name);
}
public String getResourceName() {
return resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
public User getResourceUser() {
return resourceUser;
}
public void setResourceUser(User resourceUser) {
this.resourceUser = resourceUser;
}
@AttributeProperty
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@AttributeProperty
public boolean isSurrogateAuthRequired() {
return surrogateAuthRequired;
}
public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
this.surrogateAuthRequired = surrogateAuthRequired;
}
@AttributeProperty
public String getManagementUrl() {
return managementUrl;
}
public void setManagementUrl(String managementUrl) {
this.managementUrl = managementUrl;
}
}

View file

@ -0,0 +1,87 @@
package org.keycloak.services.models.picketlink.mappings;
import org.picketlink.idm.jpa.annotations.AttributeValue;
import org.picketlink.idm.jpa.annotations.OwnerReference;
import org.picketlink.idm.jpa.annotations.entity.IdentityManaged;
import org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import java.io.Serializable;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@IdentityManaged(ResourceData.class)
@Entity
public class ResourceEntity implements Serializable {
@OneToOne
@Id
@OwnerReference
private PartitionTypeEntity partitionTypeEntity;
@AttributeValue
private String realmName;
@AttributeValue
private boolean enabled;
@AttributeValue
private boolean surrogateAuthRequired;
@AttributeValue
private String managementUrl;
@OneToOne
@AttributeValue
AccountTypeEntity resourceUser;
public PartitionTypeEntity getPartitionTypeEntity() {
return partitionTypeEntity;
}
public void setPartitionTypeEntity(PartitionTypeEntity partitionTypeEntity) {
this.partitionTypeEntity = partitionTypeEntity;
}
public String getRealmName() {
return realmName;
}
public void setRealmName(String realmName) {
this.realmName = realmName;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isSurrogateAuthRequired() {
return surrogateAuthRequired;
}
public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
this.surrogateAuthRequired = surrogateAuthRequired;
}
public String getManagementUrl() {
return managementUrl;
}
public void setManagementUrl(String managementUrl) {
this.managementUrl = managementUrl;
}
public AccountTypeEntity getResourceUser() {
return resourceUser;
}
public void setResourceUser(AccountTypeEntity resourceUser) {
this.resourceUser = resourceUser;
}
}

View file

@ -1,10 +1,12 @@
package org.keycloak.services.models.picketlink.relationships;
import org.keycloak.services.models.picketlink.mappings.RealmData;
import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Relationship;
import org.picketlink.idm.model.annotation.AttributeProperty;
import org.picketlink.idm.model.annotation.IdentityProperty;
import org.picketlink.idm.model.sample.User;
import org.picketlink.idm.query.AttributeParameter;
import org.picketlink.idm.query.RelationshipQueryParameter;
/**
@ -14,13 +16,7 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
public class RealmAdminRelationship extends AbstractAttributedType implements Relationship {
private static final long serialVersionUID = 1L;
public static final RelationshipQueryParameter REALM = new RelationshipQueryParameter() {
@Override
public String getName() {
return "realm";
}
};
public static final AttributeParameter REALM = new AttributeParameter("realm");
public static final RelationshipQueryParameter ADMIN = new RelationshipQueryParameter() {
@ -30,24 +26,22 @@ public class RealmAdminRelationship extends AbstractAttributedType implements Re
}
};
protected String realm;
protected Agent admin;
//protected String realm;
protected User admin;
@AttributeProperty
public String getRealm() {
return realm;
return (String)getAttribute("realm").getValue();
}
public void setRealm(String realm) {
this.realm = realm;
setAttribute(new Attribute<String>("realm", realm));
}
@IdentityProperty
public Agent getAdmin() {
public User getAdmin() {
return admin;
}
public void setAdmin(Agent admin) {
public void setAdmin(User admin) {
this.admin = admin;
}
}

View file

@ -1,10 +1,11 @@
package org.keycloak.services.models.picketlink.relationships;
import org.keycloak.services.models.picketlink.mappings.RealmData;
import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Relationship;
import org.picketlink.idm.model.annotation.AttributeProperty;
import org.picketlink.idm.model.annotation.IdentityProperty;
import org.picketlink.idm.query.AttributeParameter;
import org.picketlink.idm.query.RelationshipQueryParameter;
/**
@ -14,56 +15,59 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
public class RequiredCredentialRelationship extends AbstractAttributedType implements Relationship {
private static final long serialVersionUID = 1L;
public static final RelationshipQueryParameter REALM_AGENT = new RelationshipQueryParameter() {
@Override
public String getName() {
return "realmAgent";
}
};
public static final AttributeParameter REALM = new AttributeParameter("realm");
protected Agent realmAgent;
protected String credentialType;
protected boolean input;
protected boolean secret;
//protected String realm;
//protected String credentialType;
//protected boolean input;
//protected boolean secret;
public RequiredCredentialRelationship() {
}
@IdentityProperty
public Agent getRealmAgent() {
return realmAgent;
/*
@AttributeProperty
public String getRealm() {
return realm;
}
public void setRealmAgent(Agent realmAgent) {
this.realmAgent = realmAgent;
public void setRealm(String realm) {
this.realm = realm;
}*/
public String getRealm() {
return (String)getAttribute("realm").getValue();
}
public void setRealm(String realm) {
setAttribute(new Attribute<String>("realm", realm));
}
@AttributeProperty
public String getCredentialType() {
return credentialType;
return (String)getAttribute("credentialType").getValue();
}
public void setCredentialType(String credentialType) {
this.credentialType = credentialType;
setAttribute(new Attribute<String>("credentialType", credentialType));
}
@AttributeProperty
public boolean isInput() {
return input;
return (Boolean)getAttribute("input").getValue();
}
public void setInput(boolean input) {
this.input = input;
setAttribute(new Attribute<Boolean>("input", input));
}
@AttributeProperty
public boolean isSecret() {
return secret;
return (Boolean)getAttribute("secret").getValue();
}
public void setSecret(boolean secret) {
this.secret = secret;
setAttribute(new Attribute<Boolean>("secret", secret));
}
}

View file

@ -1,11 +1,14 @@
package org.keycloak.services.models.picketlink.relationships;
import org.keycloak.services.models.picketlink.mappings.RealmData;
import org.keycloak.services.models.picketlink.mappings.ResourceData;
import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Relationship;
import org.picketlink.idm.model.User;
import org.picketlink.idm.model.annotation.AttributeProperty;
import org.picketlink.idm.model.annotation.IdentityProperty;
import org.picketlink.idm.model.sample.Agent;
import org.picketlink.idm.model.sample.User;
import org.picketlink.idm.query.AttributeParameter;
import org.picketlink.idm.query.RelationshipQueryParameter;
/**
@ -15,84 +18,26 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
public class ResourceRelationship extends AbstractAttributedType implements Relationship {
private static final long serialVersionUID = 1L;
public static final RelationshipQueryParameter REALM_AGENT = new RelationshipQueryParameter() {
public static final AttributeParameter REALM = new AttributeParameter("realm");
@Override
public String getName() {
return "realmAgent";
}
};
protected String realm;
protected String resource;
protected Agent realmAgent;
protected User resourceUser;
protected String resourceId;
protected String resourceName;
protected String managementUrl = ""; // Picketlink doesn't like null attribute values
protected boolean surrogateAuthRequired;
protected boolean enabled;
@IdentityProperty
public Agent getRealmAgent() {
return realmAgent;
public String getRealm() {
return (String)getAttribute("realm").getValue();
}
public void setRealmAgent(Agent realmAgent) {
this.realmAgent = realmAgent;
public void setRealm(String realm) {
setAttribute(new Attribute<String>("realm", realm));
}
@IdentityProperty
public User getResourceUser() {
return resourceUser;
public String getResource() {
return (String)getAttribute("resource").getValue();
}
public void setResourceUser(User resourceUser) {
this.resourceUser = resourceUser;
public void setResource(String realm) {
setAttribute(new Attribute<String>("resource", realm));
}
@AttributeProperty
public String getResourceId() {
return resourceId;
}
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}
@AttributeProperty
public String getResourceName() {
return resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
@AttributeProperty
public boolean getSurrogateAuthRequired() {
return surrogateAuthRequired;
}
public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
this.surrogateAuthRequired = surrogateAuthRequired;
}
@AttributeProperty
public boolean getEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@AttributeProperty
public String getManagementUrl()
{
return managementUrl;
}
public void setManagementUrl(String managementUrl) {
if (managementUrl == null) managementUrl = ""; // Picketlink doesn't like NULL attribute values.
this.managementUrl = managementUrl;
}
}

View file

@ -1,10 +1,9 @@
package org.keycloak.services.models.picketlink.relationships;
import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Relationship;
import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.annotation.IdentityProperty;
import org.picketlink.idm.model.sample.Role;
import org.picketlink.idm.model.sample.User;
import org.picketlink.idm.query.RelationshipQueryParameter;
/**
@ -22,19 +21,17 @@ public class ScopeRelationship extends AbstractAttributedType implements Relatio
}
};
protected Agent client;
protected User client;
protected Role scope;
@IdentityProperty
public Agent getClient() {
public User getClient() {
return client;
}
public void setClient(Agent client) {
public void setClient(User client) {
this.client = client;
}
@IdentityProperty
public Role getScope() {
return scope;
}

View file

@ -1,29 +1,36 @@
package org.keycloak.services.resources;
import org.keycloak.SkeletonKeyContextResolver;
import org.keycloak.services.filters.KeycloakSessionFilter;
import org.keycloak.services.filters.KeycloakSessionRequestFilter;
import org.keycloak.services.filters.KeycloakSessionResponseFilter;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.picketlink.PicketlinkKeycloakSession;
import org.keycloak.services.models.picketlink.PicketlinkKeycloakSessionFactory;
import org.keycloak.services.models.picketlink.relationships.RealmAdminRelationship;
import org.keycloak.services.models.picketlink.relationships.RequiredCredentialRelationship;
import org.keycloak.services.models.picketlink.relationships.ResourceRelationship;
import org.keycloak.services.models.picketlink.relationships.ScopeRelationship;
import org.picketlink.idm.IdentitySessionFactory;
import org.picketlink.idm.config.IdentityConfiguration;
import org.keycloak.services.models.picketlink.mappings.RealmEntity;
import org.keycloak.services.models.picketlink.mappings.ResourceEntity;
import org.picketlink.idm.PartitionManager;
import org.picketlink.idm.config.IdentityConfigurationBuilder;
import org.picketlink.idm.internal.DefaultIdentitySessionFactory;
import org.picketlink.idm.jpa.internal.ResourceLocalJpaIdentitySessionHandler;
import org.picketlink.idm.jpa.schema.CredentialObject;
import org.picketlink.idm.jpa.schema.CredentialObjectAttribute;
import org.picketlink.idm.jpa.schema.IdentityObject;
import org.picketlink.idm.jpa.schema.IdentityObjectAttribute;
import org.picketlink.idm.jpa.schema.PartitionObject;
import org.picketlink.idm.jpa.schema.RelationshipIdentityObject;
import org.picketlink.idm.jpa.schema.RelationshipObject;
import org.picketlink.idm.jpa.schema.RelationshipObjectAttribute;
import org.picketlink.idm.internal.DefaultPartitionManager;
import org.picketlink.idm.jpa.internal.JPAContextInitializer;
import org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity;
import org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity;
import javax.annotation.PreDestroy;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
@ -39,14 +46,25 @@ public class KeycloakApplication extends Application {
protected KeycloakSessionFactory factory;
public KeycloakApplication() {
this.factory = new PicketlinkKeycloakSessionFactory(createFactory());
KeycloakSessionFilter filter = new KeycloakSessionFilter(factory);
KeycloakSessionFactory f = createSessionFactory();
this.factory = f;
KeycloakSessionRequestFilter filter = new KeycloakSessionRequestFilter(factory);
singletons.add(new RealmsResource(new TokenManager()));
singletons.add(filter);
classes.add(KeycloakSessionResponseFilter.class);
classes.add(SkeletonKeyContextResolver.class);
classes.add(RegistrationService.class);
}
protected KeycloakSessionFactory createSessionFactory() {
return buildSessionFactory();
}
public static KeycloakSessionFactory buildSessionFactory() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("keycloak-identity-store");
return new PicketlinkKeycloakSessionFactory(emf, buildPartitionManager());
}
public KeycloakSessionFactory getFactory() {
return factory;
}
@ -56,27 +74,45 @@ public class KeycloakApplication extends Application {
factory.close();
}
public IdentitySessionFactory createFactory() {
ResourceLocalJpaIdentitySessionHandler handler = new ResourceLocalJpaIdentitySessionHandler("keycloak-identity-store");
public PartitionManager createPartitionManager() {
return buildPartitionManager();
}
public static PartitionManager buildPartitionManager() {
IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
builder
.named("KEYCLOAK_JPA_CONFIG")
.stores()
.jpa()
.identityClass(IdentityObject.class)
.attributeClass(IdentityObjectAttribute.class)
.relationshipClass(RelationshipObject.class)
.relationshipIdentityClass(RelationshipIdentityObject.class)
.relationshipAttributeClass(RelationshipObjectAttribute.class)
.credentialClass(CredentialObject.class)
.credentialAttributeClass(CredentialObjectAttribute.class)
.partitionClass(PartitionObject.class)
.supportAllFeatures()
.supportRelationshipType(RealmAdminRelationship.class, ResourceRelationship.class, RequiredCredentialRelationship.class, ScopeRelationship.class)
.setIdentitySessionHandler(handler);
.mappedEntity(
AttributedTypeEntity.class,
AccountTypeEntity.class,
RoleTypeEntity.class,
GroupTypeEntity.class,
IdentityTypeEntity.class,
RelationshipTypeEntity.class,
RelationshipIdentityTypeEntity.class,
PartitionTypeEntity.class,
PasswordCredentialTypeEntity.class,
DigestCredentialTypeEntity.class,
X509CredentialTypeEntity.class,
OTPCredentialTypeEntity.class,
AttributeTypeEntity.class,
RealmEntity.class,
ResourceEntity.class
)
.supportGlobalRelationship(org.picketlink.idm.model.Relationship.class)
.addContextInitializer(new JPAContextInitializer(null) {
@Override
public EntityManager getEntityManager() {
return PicketlinkKeycloakSession.currentEntityManager.get();
}
})
.supportAllFeatures();
IdentityConfiguration build = builder.build();
return new DefaultIdentitySessionFactory(build);
DefaultPartitionManager partitionManager = new DefaultPartitionManager(builder.buildAll());
return partitionManager;
}

View file

@ -24,9 +24,6 @@ public class RealmSubResource {
@Context
protected UriInfo uriInfo;
@Context
protected KeycloakSession identitySession;
protected RealmModel realm;
public RealmSubResource(RealmModel realm) {
@ -42,13 +39,19 @@ public class RealmSubResource {
@GET
@Produces("application/json")
public PublishedRealmRepresentation getRealm(@PathParam("realm") String id) {
return new Transaction() {
protected PublishedRealmRepresentation callImpl() {
return realmRep(realm, uriInfo);
}
}.call();
}
@GET
@Path("html")
@Produces("text/html")
public String getRealmHtml(@PathParam("realm") String id) {
return new Transaction() {
protected String callImpl() {
StringBuffer html = new StringBuffer();
String authUri = TokenService.loginPageUrl(uriInfo).build(realm.getId()).toString();
@ -66,6 +69,8 @@ public class RealmSubResource {
return html.toString();
}
}.call();
}
public static PublishedRealmRepresentation realmRep(RealmModel realm, UriInfo uriInfo) {

View file

@ -6,6 +6,7 @@ import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel;
@ -38,9 +39,6 @@ public class RealmsResource {
@Context
protected HttpHeaders headers;
@Context
protected KeycloakSession identitySession;
@Context
ResourceContext resourceContext;
@ -55,8 +53,11 @@ public class RealmsResource {
}
@Path("{realm}/tokens")
public TokenService getTokenService(@PathParam("realm") String id) {
RealmManager realmManager = new RealmManager(identitySession);
public TokenService getTokenService(final @PathParam("realm") String id) {
return new Transaction(false) {
@Override
protected TokenService callImpl() {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.getRealm(id);
if (realm == null) {
logger.debug("realm not found");
@ -65,13 +66,18 @@ public class RealmsResource {
TokenService tokenService = new TokenService(realm, tokenManager);
resourceContext.initResource(tokenService);
return tokenService;
}
}.call();
}
@Path("{realm}")
public RealmSubResource getRealmResource(@PathParam("realm") String id) {
RealmManager realmManager = new RealmManager(identitySession);
public RealmSubResource getRealmResource(final @PathParam("realm") String id) {
return new Transaction(false) {
@Override
protected RealmSubResource callImpl() {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.getRealm(id);
if (realm == null) {
logger.debug("realm not found");
@ -80,17 +86,18 @@ public class RealmsResource {
RealmSubResource realmResource = new RealmSubResource(realm);
resourceContext.initResource(realmResource);
return realmResource;
}
}.call();
}
@POST
@Consumes("application/json")
public Response importRealm(RealmRepresentation rep) {
identitySession.getTransaction().begin();
RealmModel realm;
try {
RealmManager realmManager = new RealmManager(identitySession);
public Response importRealm(final RealmRepresentation rep) {
return new Transaction() {
@Override
protected Response callImpl() {
RealmManager realmManager = new RealmManager(session);
RealmModel defaultRealm = realmManager.getRealm(RealmModel.DEFAULT_REALM);
UserModel realmCreator = new AuthenticationManager().authenticateBearerToken(defaultRealm, headers);
RoleModel creatorRole = defaultRealm.getRole(RegistrationService.REALM_CREATOR_ROLE);
@ -98,15 +105,12 @@ public class RealmsResource {
logger.warn("not a realm creator");
throw new NotAuthorizedException("Bearer");
}
realm = realmManager.importRealm(rep, realmCreator);
identitySession.getTransaction().commit();
} catch (RuntimeException re) {
identitySession.getTransaction().rollback();
throw re;
}
RealmModel realm = realmManager.importRealm(rep, realmCreator);
UriBuilder builder = uriInfo.getRequestUriBuilder().path(realm.getId());
return Response.created(builder.build())
.entity(RealmSubResource.realmRep(realm, uriInfo))
.type(MediaType.APPLICATION_JSON_TYPE).build();
}
}.call();
}
}

View file

@ -4,7 +4,7 @@ import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel;
@ -32,15 +32,13 @@ public class RegistrationService {
@Context
protected UriInfo uriInfo;
@Context
protected KeycloakSession identitySession;
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response register(UserRepresentation newUser) {
identitySession.getTransaction().begin();
try {
RealmManager realmManager = new RealmManager(identitySession);
public Response register(final UserRepresentation newUser) {
return new Transaction() {
@Override
protected Response callImpl() {
RealmManager realmManager = new RealmManager(session);
RealmModel defaultRealm = realmManager.defaultRealm();
if (!defaultRealm.isEnabled()) {
throw new ForbiddenException();
@ -62,14 +60,10 @@ public class RegistrationService {
}
RoleModel realmCreator = defaultRealm.getRole(REALM_CREATOR_ROLE);
defaultRealm.grantRole(user, realmCreator);
identitySession.getTransaction().commit();
URI uri = uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(user.getLoginName()).build();
return Response.created(uri).build();
} catch (RuntimeException e) {
logger.error("Failed to register", e);
identitySession.getTransaction().rollback();
throw e;
}
}.call();
}

View file

@ -58,19 +58,17 @@ public class TokenService {
@Context
protected HttpHeaders headers;
@Context
protected KeycloakSession identitySession;
@Context
HttpRequest request;
@Context
HttpResponse response;
protected String securityFailurePath = "/securityFailure.jsp";
protected String loginFormPath = "/loginForm.jsp";
protected String oauthFormPath = "/oauthGrantForm.jsp";
protected RealmModel realm;
protected TokenManager tokenManager;
protected AuthenticationManager authManager = new AuthenticationManager();
private ResourceAdminManager resourceAdminManager = new ResourceAdminManager();
@ -117,7 +115,9 @@ public class TokenService {
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Response grantIdentityToken(MultivaluedMap<String, String> form) {
public Response grantIdentityToken(final MultivaluedMap<String, String> form) {
return new Transaction() {
protected Response callImpl() {
String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
if (username == null) {
throw new NotAuthorizedException("No user");
@ -141,12 +141,16 @@ public class TokenService {
AccessTokenResponse res = accessTokenResponse(token, encoded);
return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
}
}.call();
}
@Path("grants/access")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Response grantAccessToken(MultivaluedMap<String, String> form) {
public Response grantAccessToken(final MultivaluedMap<String, String> form) {
return new Transaction() {
protected Response callImpl() {
String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
if (username == null) {
throw new NotAuthorizedException("No user");
@ -169,11 +173,16 @@ public class TokenService {
AccessTokenResponse res = accessTokenResponse(token, encoded);
return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
}
}.call();
}
@Path("auth/request/login")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processLogin(MultivaluedMap<String, String> formData) {
public Response processLogin(final MultivaluedMap<String, String> formData) {
return new Transaction() {
protected Response callImpl() {
String clientId = formData.getFirst("client_id");
String scopeParam = formData.getFirst("scope");
String state = formData.getFirst("state");
@ -215,6 +224,8 @@ public class TokenService {
return processAccessCode(scopeParam, state, redirect, client, user);
}
}.call();
}
protected Response processAccessCode(String scopeParam, String state, String redirect, UserModel client, UserModel user) {
RoleModel resourceRole = realm.getRole(RealmManager.RESOURCE_ROLE);
@ -222,7 +233,6 @@ public class TokenService {
boolean isResource = realm.hasRole(client, resourceRole);
if (!isResource && !realm.hasRole(client, identityRequestRole)) {
securityFailureForward("Login requester not allowed to request login.");
identitySession.close();
return null;
}
AccessCodeEntry accessCode = tokenManager.createAccessCode(scopeParam, state, redirect, realm, client, user);
@ -230,7 +240,6 @@ public class TokenService {
logger.info("processAccessCode: go to oauth page?: " + (!isResource && (accessCode.getRealmRolesRequested().size() > 0 || accessCode.getResourceRolesRequested().size() > 0)));
if (!isResource && (accessCode.getRealmRolesRequested().size() > 0 || accessCode.getResourceRolesRequested().size() > 0)) {
oauthGrantPage(accessCode, client);
identitySession.close();
return null;
}
return redirectAccessCode(accessCode, state, redirect);
@ -251,7 +260,9 @@ public class TokenService {
@Path("access/codes")
@POST
@Produces("application/json")
public Response accessCodeToToken(MultivaluedMap<String, String> formData) {
public Response accessCodeToToken(final MultivaluedMap<String, String> formData) {
return new Transaction() {
protected Response callImpl() {
logger.info("accessRequest <---");
if (!realm.isEnabled()) {
throw new NotAuthorizedException("Realm not enabled");
@ -341,6 +352,8 @@ public class TokenService {
logger.info("accessRequest SUCCESS");
AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
return Response.ok(res).build();
}
}.call();
}
@ -373,7 +386,6 @@ public class TokenService {
logger.error(message);
request.setAttribute(JspRequestParameters.KEYCLOAK_SECURITY_FAILURE_MESSAGE, message);
request.forward(securityFailurePath);
identitySession.close();
}
protected void forwardToLoginForm(String redirect,
@ -389,16 +401,17 @@ public class TokenService {
request.setAttribute("scope", scopeParam);
request.setAttribute("state", state);
request.forward(loginFormPath);
identitySession.close();
}
@Path("login")
@GET
public Response loginPage(@QueryParam("response_type") String responseType,
@QueryParam("redirect_uri") String redirect,
@QueryParam("client_id") String clientId,
@QueryParam("scope") String scopeParam,
@QueryParam("state") String state) {
public Response loginPage(final @QueryParam("response_type") String responseType,
final @QueryParam("redirect_uri") String redirect,
final @QueryParam("client_id") String clientId,
final @QueryParam("scope") String scopeParam,
final @QueryParam("state") String state) {
return new Transaction() {
protected Response callImpl() {
if (!realm.isEnabled()) {
securityFailureForward("Realm not enabled");
return null;
@ -406,12 +419,14 @@ public class TokenService {
UserModel client = realm.getUser(clientId);
if (client == null) {
securityFailureForward("Unknown login requester.");
transaction.rollback();
return null;
}
if (!client.isEnabled()) {
securityFailureForward("Login requester not enabled.");
identitySession.close();
transaction.rollback();
session.close();
return null;
}
@ -420,7 +435,8 @@ public class TokenService {
boolean isResource = realm.hasRole(client, resourceRole);
if (!isResource && !realm.hasRole(client, identityRequestRole)) {
securityFailureForward("Login requester not allowed to request login.");
identitySession.close();
transaction.rollback();
session.close();
return null;
}
@ -433,10 +449,14 @@ public class TokenService {
forwardToLoginForm(redirect, clientId, scopeParam, state);
return null;
}
}.call();
}
@Path("logout")
@GET
public Response logout(@QueryParam("redirect_uri") String redirectUri) {
public Response logout(final @QueryParam("redirect_uri") String redirectUri) {
return new Transaction() {
protected Response callImpl() {
// todo do we care if anybody can trigger this?
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
@ -448,11 +468,15 @@ public class TokenService {
// todo manage legal redirects
return Response.status(302).location(UriBuilder.fromUri(redirectUri).build()).build();
}
}.call();
}
@Path("oauth/grant")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processOAuth(MultivaluedMap<String, String> formData) {
public Response processOAuth(final MultivaluedMap<String, String> formData) {
return new Transaction() {
protected Response callImpl() {
String code = formData.getFirst("code");
JWSInput input = new JWSInput(code, providers);
boolean verifiedCode = false;
@ -463,14 +487,14 @@ public class TokenService {
}
if (!verifiedCode) {
securityFailureForward("Illegal access code.");
identitySession.close();
session.close();
return null;
}
String key = input.readContent(String.class);
AccessCodeEntry accessCodeEntry = tokenManager.getAccessCode(key);
if (accessCodeEntry == null) {
securityFailureForward("Unknown access code.");
identitySession.close();
session.close();
return null;
}
@ -483,6 +507,8 @@ public class TokenService {
return redirectAccessCode(accessCodeEntry, state, redirect);
}
}.call();
}
protected Response redirectAccessDenied(String redirect, String state) {
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("error", "access_denied");

View file

@ -0,0 +1,96 @@
package org.keycloak.services.resources;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.KeycloakTransaction;
/**
* Meant to be used as an inner class wrapper (I forget the pattern name, its been awhile).
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Transaction {
protected KeycloakSession session;
protected KeycloakTransaction transaction;
protected boolean closeSession;
/**
* Pull KeycloakSession from @Context
*
* Will close session after finished
*
*/
public Transaction() {
this(true);
}
/**
* Pull KeycloakSession from @Context
*
* @param close whether to close the session or not after completion
*/
public Transaction(boolean close) {
this.session = ResteasyProviderFactory.getContextData(KeycloakSession.class);
transaction = session.getTransaction();
closeSession = close;
}
/**
* Creates and manages its own session.
*
* @param factory
*/
public Transaction(KeycloakSessionFactory factory) {
this.closeSession = true;
this.session = factory.createSession();
this.transaction = session.getTransaction();
}
protected void runImpl() {
}
/**
* Will not begin or end a transaction or close a session if the transaction was already active when called
*
*/
public void run() {
boolean wasActive = transaction.isActive();
if (!wasActive) transaction.begin();
try {
runImpl();
if (!wasActive && transaction.isActive()) transaction.commit();
} catch (RuntimeException e) {
if (!wasActive && transaction.isActive()) transaction.rollback();
throw e;
} finally {
if (!wasActive && closeSession) session.close();
}
}
protected <T> T callImpl() {
return null;
}
/**
* Will not begin or end a transaction or close a session if the transaction was already active when called
*
*/
public <T> T call() {
boolean wasActive = transaction.isActive();
if (!wasActive) transaction.begin();
try {
T rtn = callImpl();
if (!wasActive && transaction.isActive()) transaction.commit();
return rtn;
} catch (RuntimeException e) {
if (!wasActive && transaction.isActive()) transaction.rollback();
throw e;
} finally {
if (!wasActive && closeSession) session.close();
}
}
}

View file

@ -15,24 +15,8 @@ import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.models.UserCredentialModel;
import org.keycloak.services.models.picketlink.PicketlinkKeycloakSessionFactory;
import org.keycloak.services.models.picketlink.relationships.RealmAdminRelationship;
import org.keycloak.services.models.picketlink.relationships.RequiredCredentialRelationship;
import org.keycloak.services.models.picketlink.relationships.ResourceRelationship;
import org.keycloak.services.models.picketlink.relationships.ScopeRelationship;
import org.picketlink.idm.IdentitySessionFactory;
import org.picketlink.idm.config.IdentityConfiguration;
import org.picketlink.idm.config.IdentityConfigurationBuilder;
import org.picketlink.idm.internal.DefaultIdentitySessionFactory;
import org.picketlink.idm.jpa.internal.ResourceLocalJpaIdentitySessionHandler;
import org.picketlink.idm.jpa.schema.CredentialObject;
import org.picketlink.idm.jpa.schema.CredentialObjectAttribute;
import org.picketlink.idm.jpa.schema.IdentityObject;
import org.picketlink.idm.jpa.schema.IdentityObjectAttribute;
import org.picketlink.idm.jpa.schema.PartitionObject;
import org.picketlink.idm.jpa.schema.RelationshipIdentityObject;
import org.picketlink.idm.jpa.schema.RelationshipObject;
import org.picketlink.idm.jpa.schema.RelationshipObjectAttribute;
import org.keycloak.services.resources.KeycloakApplication;
import java.util.List;
@ -49,37 +33,15 @@ public class AdapterTest {
@Before
public void before() throws Exception {
factory = new PicketlinkKeycloakSessionFactory(createFactory());
factory = KeycloakApplication.buildSessionFactory();
identitySession = factory.createSession();
identitySession.getTransaction().begin();
adapter = new RealmManager(identitySession);
}
public static IdentitySessionFactory createFactory() {
ResourceLocalJpaIdentitySessionHandler handler = new ResourceLocalJpaIdentitySessionHandler("keycloak-identity-store");
IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
builder
.stores()
.jpa()
.identityClass(IdentityObject.class)
.attributeClass(IdentityObjectAttribute.class)
.relationshipClass(RelationshipObject.class)
.relationshipIdentityClass(RelationshipIdentityObject.class)
.relationshipAttributeClass(RelationshipObjectAttribute.class)
.credentialClass(CredentialObject.class)
.credentialAttributeClass(CredentialObjectAttribute.class)
.partitionClass(PartitionObject.class)
.supportAllFeatures()
.supportRelationshipType(RealmAdminRelationship.class, ResourceRelationship.class, RequiredCredentialRelationship.class, ScopeRelationship.class)
.setIdentitySessionHandler(handler);
IdentityConfiguration build = builder.build();
return new DefaultIdentitySessionFactory(build);
}
@After
public void after() throws Exception {
identitySession.getTransaction().commit();
identitySession.close();
factory.close();
}
@ -132,6 +94,8 @@ public class AdapterTest {
for (RequiredCredentialModel cred : storedCreds) {
if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD)) password = true;
else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP)) totp = true;
Assert.assertTrue(cred.isInput());
Assert.assertTrue(cred.isSecret());
}
Assert.assertTrue(totp);
Assert.assertTrue(password);

View file

@ -13,26 +13,8 @@ import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.models.picketlink.PicketlinkKeycloakSessionFactory;
import org.keycloak.services.models.picketlink.relationships.RealmAdminRelationship;
import org.keycloak.services.models.picketlink.relationships.RequiredCredentialRelationship;
import org.keycloak.services.models.picketlink.relationships.ResourceRelationship;
import org.keycloak.services.models.picketlink.relationships.ScopeRelationship;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.resources.RegistrationService;
import org.picketlink.idm.IdentitySessionFactory;
import org.picketlink.idm.config.IdentityConfiguration;
import org.picketlink.idm.config.IdentityConfigurationBuilder;
import org.picketlink.idm.internal.DefaultIdentitySessionFactory;
import org.picketlink.idm.jpa.internal.ResourceLocalJpaIdentitySessionHandler;
import org.picketlink.idm.jpa.schema.CredentialObject;
import org.picketlink.idm.jpa.schema.CredentialObjectAttribute;
import org.picketlink.idm.jpa.schema.IdentityObject;
import org.picketlink.idm.jpa.schema.IdentityObjectAttribute;
import org.picketlink.idm.jpa.schema.PartitionObject;
import org.picketlink.idm.jpa.schema.RelationshipIdentityObject;
import org.picketlink.idm.jpa.schema.RelationshipObject;
import org.picketlink.idm.jpa.schema.RelationshipObjectAttribute;
import org.picketlink.idm.model.Realm;
import java.util.Set;
@ -49,45 +31,23 @@ public class ImportTest {
@Before
public void before() throws Exception {
factory = new PicketlinkKeycloakSessionFactory(createFactory());
factory = KeycloakApplication.buildSessionFactory();
identitySession = factory.createSession();
identitySession.getTransaction().begin();
manager = new RealmManager(identitySession);
}
public static IdentitySessionFactory createFactory() {
ResourceLocalJpaIdentitySessionHandler handler = new ResourceLocalJpaIdentitySessionHandler("keycloak-identity-store");
IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
builder
.stores()
.jpa()
.identityClass(IdentityObject.class)
.attributeClass(IdentityObjectAttribute.class)
.relationshipClass(RelationshipObject.class)
.relationshipIdentityClass(RelationshipIdentityObject.class)
.relationshipAttributeClass(RelationshipObjectAttribute.class)
.credentialClass(CredentialObject.class)
.credentialAttributeClass(CredentialObjectAttribute.class)
.partitionClass(PartitionObject.class)
.supportAllFeatures()
.supportRelationshipType(RealmAdminRelationship.class, ResourceRelationship.class, RequiredCredentialRelationship.class, ScopeRelationship.class)
.setIdentitySessionHandler(handler);
IdentityConfiguration build = builder.build();
return new DefaultIdentitySessionFactory(build);
}
@After
public void after() throws Exception {
identitySession.getTransaction().commit();
identitySession.close();
factory.close();
}
@Test
public void install() throws Exception {
RealmModel defaultRealm = manager.createRealm(Realm.DEFAULT_REALM, Realm.DEFAULT_REALM);
defaultRealm.setName(Realm.DEFAULT_REALM);
RealmModel defaultRealm = manager.createRealm(RealmModel.DEFAULT_REALM, RealmModel.DEFAULT_REALM);
defaultRealm.setName(RealmModel.DEFAULT_REALM);
defaultRealm.setEnabled(true);
defaultRealm.setTokenLifespan(300);
defaultRealm.setAccessCodeLifespan(60);

View file

@ -4,7 +4,6 @@ import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.resources.RegistrationService;
import org.picketlink.idm.model.Realm;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -12,8 +11,8 @@ import org.picketlink.idm.model.Realm;
*/
public class InstallationManager {
public void install(RealmManager manager) {
RealmModel defaultRealm = manager.createRealm(Realm.DEFAULT_REALM, Realm.DEFAULT_REALM);
defaultRealm.setName(Realm.DEFAULT_REALM);
RealmModel defaultRealm = manager.createRealm(RealmModel.DEFAULT_REALM, RealmModel.DEFAULT_REALM);
defaultRealm.setName(RealmModel.DEFAULT_REALM);
defaultRealm.setEnabled(true);
defaultRealm.setTokenLifespan(300);
defaultRealm.setAccessCodeLifespan(60);

View file

@ -14,9 +14,8 @@ import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.resources.KeycloakApplication;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.model.Realm;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.client.Client;
@ -43,9 +42,12 @@ public class RealmCreationTest {
deployment.setApplicationClass(KeycloakApplication.class.getName());
EmbeddedContainer.start(deployment);
KeycloakApplication application = (KeycloakApplication) deployment.getApplication();
KeycloakSession IdentitySession = application.getFactory().createSession();
RealmManager manager = new RealmManager(IdentitySession);
KeycloakSession session = application.getFactory().createSession();
session.getTransaction().begin();
RealmManager manager = new RealmManager(session);
new InstallationManager().install(manager);
session.getTransaction().commit();
session.close();
client = new ResteasyClientBuilder().build();
client.register(SkeletonKeyContextResolver.class);
}
@ -72,14 +74,14 @@ public class RealmCreationTest {
Form form = new Form();
form.param(AuthenticationManager.FORM_USERNAME, "bburke");
form.param(RequiredCredentialRepresentation.PASSWORD, "badpassword");
tokenResponse = target.path("realms").path(Realm.DEFAULT_REALM).path("tokens/grants/identity-token").request().post(Entity.form(form), AccessTokenResponse.class);
tokenResponse = target.path("realms").path(RealmModel.DEFAULT_REALM).path("tokens/grants/identity-token").request().post(Entity.form(form), AccessTokenResponse.class);
Assert.fail();
} catch (NotAuthorizedException e) {
}
Form form = new Form();
form.param(AuthenticationManager.FORM_USERNAME, "bburke");
form.param(RequiredCredentialRepresentation.PASSWORD, "geheim");
tokenResponse = target.path("realms").path(Realm.DEFAULT_REALM).path("tokens/grants/identity-token").request().post(Entity.form(form), AccessTokenResponse.class);
tokenResponse = target.path("realms").path(RealmModel.DEFAULT_REALM).path("tokens/grants/identity-token").request().post(Entity.form(form), AccessTokenResponse.class);
Assert.assertNotNull(tokenResponse);
System.out.println(tokenResponse.getToken());
//

View file

@ -5,15 +5,23 @@
<persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>org.picketlink.idm.jpa.schema.IdentityObject</class>
<class>org.picketlink.idm.jpa.schema.PartitionObject</class>
<class>org.picketlink.idm.jpa.schema.RelationshipObject</class>
<class>org.picketlink.idm.jpa.schema.RelationshipIdentityObject</class>
<class>org.picketlink.idm.jpa.schema.RelationshipIdentityWeakObject</class>
<class>org.picketlink.idm.jpa.schema.RelationshipObjectAttribute</class>
<class>org.picketlink.idm.jpa.schema.IdentityObjectAttribute</class>
<class>org.picketlink.idm.jpa.schema.CredentialObject</class>
<class>org.picketlink.idm.jpa.schema.CredentialObjectAttribute</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity</class>
<class>org.keycloak.services.models.picketlink.mappings.RealmEntity</class>
<class>org.keycloak.services.models.picketlink.mappings.ResourceEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.connection.url" value="jdbc:h2:mem:test"/>
@ -22,8 +30,9 @@
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.format_sql" value="true" />
</properties>
</persistence-unit>
</persistence>