more stuff

This commit is contained in:
Bill Burke 2013-07-11 17:56:15 -04:00
parent 1586f461be
commit 1548065b7f
30 changed files with 2118 additions and 2123 deletions

View file

@ -36,7 +36,7 @@ public class SkeletonKeyContextResolver implements ContextResolver<ObjectMapper>
@Override @Override
public ObjectMapper getContext(Class<?> type) public ObjectMapper getContext(Class<?> type)
{ {
if (type.getPackage().getName().startsWith("org.jboss.resteasy.skeleton.key")) return mapper; if (type.getPackage().getName().startsWith(getClass().getPackage().getName())) return mapper;
return null; return null;
} }
} }

11
pom.xml
View file

@ -108,6 +108,12 @@
<artifactId>jose-jwt</artifactId> <artifactId>jose-jwt</artifactId>
<version>${resteasy.version}</version> <version>${resteasy.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>tjws</artifactId>
<version>${resteasy.version}</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.codehaus.jackson</groupId> <groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId> <artifactId>jackson-core-asl</artifactId>
@ -163,6 +169,11 @@
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.11</version> <version>4.11</version>
</dependency> </dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

View file

@ -43,6 +43,25 @@
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId> <artifactId>resteasy-jaxrs</artifactId>
<scope>provided</scope> <scope>provided</scope>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>tjws</artifactId>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
@ -94,6 +113,23 @@
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.161</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.6.6.Final</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>

View file

@ -0,0 +1,38 @@
package org.keycloak.services.filters;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.IdentitySessionFactory;
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 $
*/
@PreMatching
public class IdentitySessionFilter implements ContainerRequestFilter, ContainerResponseFilter {
protected IdentitySessionFactory factory;
public IdentitySessionFilter(IdentitySessionFactory factory) {
this.factory = factory;
}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
IdentitySession ctx = factory.createIdentitySession();
requestContext.setProperty(IdentitySession.class.getName(), ctx);
ResteasyProviderFactory.pushContext(IdentitySession.class, ctx);
}
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
IdentitySession ctx = (IdentitySession)requestContext.getProperty(IdentitySession.class.getName());
if (ctx != null) ctx.close();
}
}

View file

@ -0,0 +1,49 @@
package org.keycloak.services.managers;
import org.keycloak.representations.SkeletonKeyToken;
import org.picketlink.idm.model.User;
import java.util.UUID;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AccessCodeEntry {
protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
protected long expiration;
protected SkeletonKeyToken token;
protected User client;
public boolean isExpired() {
return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration;
}
public String getId() {
return id;
}
public long getExpiration() {
return expiration;
}
public void setExpiration(long expiration) {
this.expiration = expiration;
}
public SkeletonKeyToken getToken() {
return token;
}
public void setToken(SkeletonKeyToken token) {
this.token = token;
}
public User getClient() {
return client;
}
public void setClient(User client) {
this.client = client;
}
}

View file

@ -24,27 +24,28 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class AuthenticationManager public class AuthenticationManager {
{
protected Logger logger = Logger.getLogger(AuthenticationManager.class); protected Logger logger = Logger.getLogger(AuthenticationManager.class);
public static final String FORM_USERNAME = "username"; public static final String FORM_USERNAME = "username";
protected RealmManager adapter;
public AuthenticationManager(RealmManager adapter) /**
{ * Grabs token from headers, authenticates, authorizes
this.adapter = adapter; *
* @param realm
* @param headers
* @return
*/
public boolean isRealmAdmin(RealmModel realm, HttpHeaders headers) {
User user = authenticateToken(realm, headers);
return realm.isRealmAdmin(user);
} }
public User authenticateToken(RealmModel realm, HttpHeaders headers) public User authenticateToken(RealmModel realm, HttpHeaders headers) {
{
String tokenString = null; String tokenString = null;
String authHeader = headers.getHeaderString(HttpHeaders.AUTHORIZATION); String authHeader = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
if (authHeader == null) if (authHeader == null) {
{
throw new NotAuthorizedException("Bearer"); throw new NotAuthorizedException("Bearer");
} } else {
else
{
String[] split = authHeader.trim().split("\\s+"); String[] split = authHeader.trim().split("\\s+");
if (split == null || split.length != 2) throw new NotAuthorizedException("Bearer"); if (split == null || split.length != 2) throw new NotAuthorizedException("Bearer");
if (!split[0].equalsIgnoreCase("Bearer")) throw new NotAuthorizedException("Bearer"); if (!split[0].equalsIgnoreCase("Bearer")) throw new NotAuthorizedException("Bearer");
@ -52,51 +53,40 @@ public class AuthenticationManager
} }
try try {
{
SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId()); SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId());
if (!token.isActive()) if (!token.isActive()) {
{
throw new NotAuthorizedException("token_expired"); throw new NotAuthorizedException("token_expired");
} }
User user = realm.getIdm().getUser(token.getPrincipal()); User user = realm.getIdm().getUser(token.getPrincipal());
if (user == null || !user.isEnabled()) if (user == null || !user.isEnabled()) {
{
throw new NotAuthorizedException("invalid_user"); throw new NotAuthorizedException("invalid_user");
} }
return user; return user;
} } catch (VerificationException e) {
catch (VerificationException e)
{
logger.error("Failed to verify token", e); logger.error("Failed to verify token", e);
throw new NotAuthorizedException("invalid_token"); throw new NotAuthorizedException("invalid_token");
} }
} }
public boolean authenticateForm(RealmModel realm, User user, MultivaluedMap<String, String> formData) public boolean authenticateForm(RealmModel realm, User user, MultivaluedMap<String, String> formData) {
{
String username = user.getLoginName(); String username = user.getLoginName();
Set<String> types = new HashSet<String>(); Set<String> types = new HashSet<String>();
for (RequiredCredentialModel credential : realm.getRequiredCredentials()) for (RequiredCredentialModel credential : realm.getRequiredCredentials()) {
{
types.add(credential.getType()); types.add(credential.getType());
} }
if (types.contains(RequiredCredentialRepresentation.PASSWORD)) if (types.contains(RequiredCredentialRepresentation.PASSWORD)) {
{
String password = formData.getFirst(RequiredCredentialRepresentation.PASSWORD); String password = formData.getFirst(RequiredCredentialRepresentation.PASSWORD);
if (password == null) if (password == null) {
{
logger.warn("Password not provided"); logger.warn("Password not provided");
return false; return false;
} }
if (types.contains(RequiredCredentialRepresentation.TOTP)) if (types.contains(RequiredCredentialRepresentation.TOTP)) {
{
String token = formData.getFirst(RequiredCredentialRepresentation.TOTP); String token = formData.getFirst(RequiredCredentialRepresentation.TOTP);
if (token == null) if (token == null) {
{
logger.warn("TOTP token not provided"); logger.warn("TOTP token not provided");
return false; return false;
} }
@ -105,23 +95,17 @@ public class AuthenticationManager
creds.setUsername(username); creds.setUsername(username);
creds.setPassword(new Password(password)); creds.setPassword(new Password(password));
realm.getIdm().validateCredentials(creds); realm.getIdm().validateCredentials(creds);
if (creds.getStatus() != Credentials.Status.VALID) if (creds.getStatus() != Credentials.Status.VALID) {
{
return false; return false;
} }
} } else {
else
{
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, new Password(password)); UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, new Password(password));
realm.getIdm().validateCredentials(creds); realm.getIdm().validateCredentials(creds);
if (creds.getStatus() != Credentials.Status.VALID) if (creds.getStatus() != Credentials.Status.VALID) {
{
return false; return false;
} }
} }
} } else {
else
{
logger.warn("Do not know how to authenticate user"); logger.warn("Do not know how to authenticate user");
return false; return false;
} }

View file

@ -0,0 +1,29 @@
package org.keycloak.services.managers;
import org.keycloak.services.models.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;
import org.picketlink.idm.model.SimpleRole;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class InstallationManager {
public void install(RealmManager manager) {
RealmModel defaultRealm = manager.createRealm(Realm.DEFAULT_REALM, Realm.DEFAULT_REALM);
defaultRealm.setName(Realm.DEFAULT_REALM);
defaultRealm.setEnabled(true);
defaultRealm.setTokenLifespan(300);
defaultRealm.setAccessCodeLifespan(60);
defaultRealm.setSslNotRequired(false);
defaultRealm.setCookieLoginAllowed(true);
manager.generateRealmKeys(defaultRealm);
defaultRealm.updateRealm();
defaultRealm.addRequiredCredential(RequiredCredentialModel.PASSWORD);
defaultRealm.getIdm().add(new SimpleRole(RegistrationService.REALM_CREATOR_ROLE));
}
}

View file

@ -21,43 +21,30 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class TokenManager public class TokenManager {
{
protected RealmManager adapter;
public TokenManager(RealmManager adapter) public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user) {
{
this.adapter = adapter;
}
public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user)
{
SkeletonKeyToken token = new SkeletonKeyToken(); SkeletonKeyToken token = new SkeletonKeyToken();
token.id(adapter.generateId()); token.id(RealmManager.generateId());
token.principal(user.getLoginName()); token.principal(user.getLoginName());
token.audience(realm.getName()); token.audience(realm.getName());
token.issuedNow(); token.issuedNow();
token.issuedFor(client.getLoginName()); token.issuedFor(client.getLoginName());
if (realm.getTokenLifespan() > 0) if (realm.getTokenLifespan() > 0) {
{
token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan()); token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
} }
Map<String, ResourceModel> resourceMap = realm.getResourceMap(); Map<String, ResourceModel> resourceMap = realm.getResourceMap();
for (String res : scope.keySet()) for (String res : scope.keySet()) {
{
ResourceModel resource = resourceMap.get(res); ResourceModel resource = resourceMap.get(res);
Set<String> scopeMapping = resource.getScope(client); Set<String> scopeMapping = resource.getScope(client);
Set<String> roleMapping = resource.getRoleMappings(user); Set<String> roleMapping = resource.getRoleMappings(user);
SkeletonKeyToken.Access access = token.addAccess(resource.getName()); SkeletonKeyToken.Access access = token.addAccess(resource.getName());
for (String role : scope.get(res)) for (String role : scope.get(res)) {
{ if (!scopeMapping.contains("*") && !scopeMapping.contains(role)) {
if (!scopeMapping.contains("*") && !scopeMapping.contains(role))
{
throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build()); throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
} }
if (!roleMapping.contains(role)) if (!roleMapping.contains(role)) {
{
throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build()); throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
} }
@ -67,17 +54,14 @@ public class TokenManager
return token; return token;
} }
public SkeletonKeyToken createScopedToken(String scopeParam, RealmModel realm, User client, User user) public SkeletonKeyToken createScopedToken(String scopeParam, RealmModel realm, User client, User user) {
{
SkeletonKeyScope scope = decodeScope(scopeParam); SkeletonKeyScope scope = decodeScope(scopeParam);
return createScopedToken(scope, realm, client, user); return createScopedToken(scope, realm, client, user);
} }
public SkeletonKeyToken createLoginToken(RealmModel realm, User client, User user) public SkeletonKeyToken createLoginToken(RealmModel realm, User client, User user) {
{
Set<String> mapping = realm.getScope(client); Set<String> mapping = realm.getScope(client);
if (!mapping.contains("*")) if (!mapping.contains("*")) {
{
throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized to request a user login.</p>").type("text/html").build()); throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized to request a user login.</p>").type("text/html").build());
} }
SkeletonKeyToken token = createAccessToken(realm, user); SkeletonKeyToken token = createAccessToken(realm, user);
@ -86,56 +70,45 @@ public class TokenManager
} }
public SkeletonKeyScope decodeScope(String scopeParam) public SkeletonKeyScope decodeScope(String scopeParam) {
{
SkeletonKeyScope scope = null; SkeletonKeyScope scope = null;
byte[] bytes = Base64Url.decode(scopeParam); byte[] bytes = Base64Url.decode(scopeParam);
try try {
{
scope = JsonSerialization.fromBytes(SkeletonKeyScope.class, bytes); scope = JsonSerialization.fromBytes(SkeletonKeyScope.class, bytes);
} } catch (IOException e) {
catch (IOException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return scope; return scope;
} }
public SkeletonKeyToken createAccessToken(RealmModel realm, User user) public SkeletonKeyToken createAccessToken(RealmModel realm, User user) {
{
List<ResourceModel> resources = realm.getResources(); List<ResourceModel> resources = realm.getResources();
SkeletonKeyToken token = new SkeletonKeyToken(); SkeletonKeyToken token = new SkeletonKeyToken();
token.id(adapter.generateId()); token.id(RealmManager.generateId());
token.issuedNow(); token.issuedNow();
token.principal(user.getLoginName()); token.principal(user.getLoginName());
token.audience(realm.getId()); token.audience(realm.getId());
if (realm.getTokenLifespan() > 0) if (realm.getTokenLifespan() > 0) {
{
token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan()); token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
} }
Set<String> realmMapping = realm.getRoleMappings(user); Set<String> realmMapping = realm.getRoleMappings(user);
if (realmMapping != null && realmMapping.size() > 0) if (realmMapping != null && realmMapping.size() > 0) {
{
SkeletonKeyToken.Access access = new SkeletonKeyToken.Access(); SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
for (String role : realmMapping) for (String role : realmMapping) {
{
access.addRole(role); access.addRole(role);
} }
token.setRealmAccess(access); token.setRealmAccess(access);
} }
if (resources != null) if (resources != null) {
{ for (ResourceModel resource : resources) {
for (ResourceModel resource : resources)
{
Set<String> mapping = resource.getRoleMappings(user); Set<String> mapping = resource.getRoleMappings(user);
if (mapping == null) continue; if (mapping == null) continue;
SkeletonKeyToken.Access access = token.addAccess(resource.getName()) SkeletonKeyToken.Access access = token.addAccess(resource.getName())
.verifyCaller(resource.isSurrogateAuthRequired()); .verifyCaller(resource.isSurrogateAuthRequired());
for (String role : mapping) for (String role : mapping) {
{
access.addRole(role); access.addRole(role);
} }
} }
@ -143,29 +116,23 @@ public class TokenManager
return token; return token;
} }
public SkeletonKeyToken createIdentityToken(RealmModel realm, String username) public SkeletonKeyToken createIdentityToken(RealmModel realm, String username) {
{
SkeletonKeyToken token = new SkeletonKeyToken(); SkeletonKeyToken token = new SkeletonKeyToken();
token.id(adapter.generateId()); token.id(RealmManager.generateId());
token.issuedNow(); token.issuedNow();
token.principal(username); token.principal(username);
token.audience(realm.getId()); token.audience(realm.getId());
if (realm.getTokenLifespan() > 0) if (realm.getTokenLifespan() > 0) {
{
token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan()); token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
} }
return token; return token;
} }
public String encodeToken(RealmModel realm, SkeletonKeyToken token) public String encodeToken(RealmModel realm, SkeletonKeyToken token) {
{
byte[] tokenBytes = null; byte[] tokenBytes = null;
try try {
{
tokenBytes = JsonSerialization.toByteArray(token, false); tokenBytes = JsonSerialization.toByteArray(token, false);
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
String encodedToken = new JWSBuilder() String encodedToken = new JWSBuilder()

View file

@ -1,49 +1,71 @@
package org.keycloak.services.models; package org.keycloak.services.models;
import org.keycloak.representations.idm.UserRepresentation;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.IdentityManager; import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.internal.IdentityManagerFactory;
import org.picketlink.idm.model.Realm; import org.picketlink.idm.model.Realm;
import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.SimpleAgent; import org.picketlink.idm.model.SimpleAgent;
import org.picketlink.idm.model.SimpleUser;
import org.picketlink.idm.model.User;
import javax.ws.rs.core.Response;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RealmManager public class RealmManager {
{
private static AtomicLong counter = new AtomicLong(1); private static AtomicLong counter = new AtomicLong(1);
public static String generateId() public static String generateId() {
{
return counter.getAndIncrement() + "-" + System.currentTimeMillis(); return counter.getAndIncrement() + "-" + System.currentTimeMillis();
} }
protected IdentityManagerFactory factory; protected IdentitySession IdentitySession;
public RealmManager(IdentityManagerFactory factory) public RealmManager(IdentitySession IdentitySession) {
{ this.IdentitySession = IdentitySession;
this.factory = factory;
} }
public RealmModel getRealm(String id) public RealmModel defaultRealm() {
{ return getRealm(Realm.DEFAULT_REALM);
Realm existing = factory.findRealm(id); }
if (existing == null)
{ public RealmModel getRealm(String id) {
Realm existing = IdentitySession.findRealm(id);
if (existing == null) {
return null; return null;
} }
return new RealmModel(existing, factory); return new RealmModel(existing, IdentitySession);
} }
public RealmModel create(String name) public RealmModel createRealm(String name) {
{ return createRealm(generateId(), name);
Realm newRealm = factory.createRealm(generateId()); }
IdentityManager idm = factory.createIdentityManager(newRealm);
public RealmModel createRealm(String id, String name) {
Realm newRealm = IdentitySession.createRealm(id);
IdentityManager idm = IdentitySession.createIdentityManager(newRealm);
SimpleAgent agent = new SimpleAgent(RealmModel.REALM_AGENT_ID); SimpleAgent agent = new SimpleAgent(RealmModel.REALM_AGENT_ID);
idm.add(agent); idm.add(agent);
return new RealmModel(newRealm, factory); RealmModel realm = new RealmModel(newRealm, IdentitySession);
return realm;
} }
public void generateRealmKeys(RealmModel realm) {
KeyPair keyPair = null;
try {
keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
realm.setPrivateKey(keyPair.getPrivate());
realm.setPublicKey(keyPair.getPublic());
realm.updateRealm();
}
} }

View file

@ -4,14 +4,14 @@ import org.bouncycastle.openssl.PEMWriter;
import org.jboss.resteasy.security.PemUtils; import org.jboss.resteasy.security.PemUtils;
import org.keycloak.representations.idm.RequiredCredentialRepresentation; import org.keycloak.representations.idm.RequiredCredentialRepresentation;
import org.keycloak.services.models.relationships.RealmAdminRelationship; import org.keycloak.services.models.relationships.RealmAdminRelationship;
import org.keycloak.services.models.relationships.RealmResourceRelationship; import org.keycloak.services.models.relationships.ResourceRelationship;
import org.keycloak.services.models.relationships.RequiredCredentialRelationship; import org.keycloak.services.models.relationships.RequiredCredentialRelationship;
import org.keycloak.services.models.relationships.ScopeRelationship; import org.keycloak.services.models.relationships.ScopeRelationship;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.IdentityManager; import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.credential.Password; import org.picketlink.idm.credential.Password;
import org.picketlink.idm.credential.TOTPCredential; import org.picketlink.idm.credential.TOTPCredential;
import org.picketlink.idm.credential.X509CertificateCredentials; import org.picketlink.idm.credential.X509CertificateCredentials;
import org.picketlink.idm.internal.IdentityManagerFactory;
import org.picketlink.idm.model.Agent; import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Attribute; import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Grant; import org.picketlink.idm.model.Grant;
@ -39,8 +39,7 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RealmModel public class RealmModel {
{
public static final String REALM_AGENT_ID = "_realm_"; public static final String REALM_AGENT_ID = "_realm_";
public static final String REALM_NAME = "name"; public static final String REALM_NAME = "name";
public static final String REALM_ACCESS_CODE_LIFESPAN = "accessCodeLifespan"; public static final String REALM_ACCESS_CODE_LIFESPAN = "accessCodeLifespan";
@ -52,196 +51,156 @@ public class RealmModel
protected Realm realm; protected Realm realm;
protected Agent realmAgent; protected Agent realmAgent;
protected IdentityManagerFactory factory; protected IdentitySession IdentitySession;
protected volatile transient PublicKey publicKey; protected volatile transient PublicKey publicKey;
protected volatile transient PrivateKey privateKey; protected volatile transient PrivateKey privateKey;
public RealmModel(Realm realm, IdentityManagerFactory factory) public RealmModel(Realm realm, IdentitySession factory) {
{
this.realm = realm; this.realm = realm;
this.factory = factory; this.IdentitySession = factory;
realmAgent = getIdm().getAgent(REALM_AGENT_ID); realmAgent = getIdm().getAgent(REALM_AGENT_ID);
} }
public IdentityManager getIdm() public IdentityManager getIdm() {
{ return IdentitySession.createIdentityManager(realm);
return factory.createIdentityManager(realm);
} }
public void updateRealm() public void updateRealm() {
{
getIdm().update(realmAgent); getIdm().update(realmAgent);
} }
public String getId() public String getId() {
{
return realm.getId(); return realm.getId();
} }
public String getName() public String getName() {
{
return (String) realmAgent.getAttribute(REALM_NAME).getValue(); return (String) realmAgent.getAttribute(REALM_NAME).getValue();
} }
public void setName(String name) public void setName(String name) {
{
realmAgent.setAttribute(new Attribute<String>(REALM_NAME, name)); realmAgent.setAttribute(new Attribute<String>(REALM_NAME, name));
} }
public boolean isEnabled() public boolean isEnabled() {
{
return realmAgent.isEnabled(); return realmAgent.isEnabled();
} }
public void setEnabled(boolean enabled) public void setEnabled(boolean enabled) {
{
realmAgent.setEnabled(enabled); realmAgent.setEnabled(enabled);
} }
public boolean isSslNotRequired() public boolean isSslNotRequired() {
{
return (Boolean) realmAgent.getAttribute(REALM_IS_SSL_NOT_REQUIRED).getValue(); return (Boolean) realmAgent.getAttribute(REALM_IS_SSL_NOT_REQUIRED).getValue();
} }
public void setSslNotRequired(boolean sslNotRequired) public void setSslNotRequired(boolean sslNotRequired) {
{
realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_SSL_NOT_REQUIRED, sslNotRequired)); realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_SSL_NOT_REQUIRED, sslNotRequired));
} }
public boolean isCookieLoginAllowed() public boolean isCookieLoginAllowed() {
{
return (Boolean) realmAgent.getAttribute(REALM_IS_COOKIE_LOGIN_ALLOWED).getValue(); return (Boolean) realmAgent.getAttribute(REALM_IS_COOKIE_LOGIN_ALLOWED).getValue();
} }
public void setCookieLoginAllowed(boolean cookieLoginAllowed) public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
{
realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_COOKIE_LOGIN_ALLOWED, cookieLoginAllowed)); realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_COOKIE_LOGIN_ALLOWED, cookieLoginAllowed));
} }
public long getTokenLifespan() public long getTokenLifespan() {
{
return (Long) realmAgent.getAttribute(REALM_TOKEN_LIFESPAN).getValue(); return (Long) realmAgent.getAttribute(REALM_TOKEN_LIFESPAN).getValue();
} }
public void setTokenLifespan(long tokenLifespan) public void setTokenLifespan(long tokenLifespan) {
{
realmAgent.setAttribute(new Attribute<Long>(REALM_TOKEN_LIFESPAN, tokenLifespan)); realmAgent.setAttribute(new Attribute<Long>(REALM_TOKEN_LIFESPAN, tokenLifespan));
} }
public long getAccessCodeLifespan() public long getAccessCodeLifespan() {
{
return (Long) realmAgent.getAttribute(REALM_ACCESS_CODE_LIFESPAN).getValue(); return (Long) realmAgent.getAttribute(REALM_ACCESS_CODE_LIFESPAN).getValue();
} }
public void setAccessCodeLifespan(long accessCodeLifespan) public void setAccessCodeLifespan(long accessCodeLifespan) {
{
realmAgent.setAttribute(new Attribute<Long>(REALM_ACCESS_CODE_LIFESPAN, accessCodeLifespan)); realmAgent.setAttribute(new Attribute<Long>(REALM_ACCESS_CODE_LIFESPAN, accessCodeLifespan));
} }
public String getPublicKeyPem() public String getPublicKeyPem() {
{
return (String) realmAgent.getAttribute(REALM_PUBLIC_KEY).getValue(); return (String) realmAgent.getAttribute(REALM_PUBLIC_KEY).getValue();
} }
public void setPublicKeyPem(String publicKeyPem) public void setPublicKeyPem(String publicKeyPem) {
{
realmAgent.setAttribute(new Attribute<String>(REALM_PUBLIC_KEY, publicKeyPem)); realmAgent.setAttribute(new Attribute<String>(REALM_PUBLIC_KEY, publicKeyPem));
this.publicKey = null; this.publicKey = null;
} }
public String getPrivateKeyPem() public String getPrivateKeyPem() {
{
return (String) realmAgent.getAttribute(REALM_PRIVATE_KEY).getValue(); return (String) realmAgent.getAttribute(REALM_PRIVATE_KEY).getValue();
} }
public void setPrivateKeyPem(String privateKeyPem) public void setPrivateKeyPem(String privateKeyPem) {
{
realmAgent.setAttribute(new Attribute<String>(REALM_PRIVATE_KEY, privateKeyPem)); realmAgent.setAttribute(new Attribute<String>(REALM_PRIVATE_KEY, privateKeyPem));
this.privateKey = null; this.privateKey = null;
} }
public PublicKey getPublicKey() public PublicKey getPublicKey() {
{
if (publicKey != null) return publicKey; if (publicKey != null) return publicKey;
String pem = getPublicKeyPem(); String pem = getPublicKeyPem();
if (pem != null) if (pem != null) {
{ try {
try
{
publicKey = PemUtils.decodePublicKey(pem); publicKey = PemUtils.decodePublicKey(pem);
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
return publicKey; return publicKey;
} }
public void setPublicKey(PublicKey publicKey) public void setPublicKey(PublicKey publicKey) {
{
this.publicKey = publicKey; this.publicKey = publicKey;
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
PEMWriter pemWriter = new PEMWriter(writer); PEMWriter pemWriter = new PEMWriter(writer);
try try {
{
pemWriter.writeObject(publicKey); pemWriter.writeObject(publicKey);
pemWriter.flush(); pemWriter.flush();
} } catch (IOException e) {
catch (IOException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
String s = writer.toString(); String s = writer.toString();
setPublicKeyPem(PemUtils.removeBeginEnd(s)); setPublicKeyPem(PemUtils.removeBeginEnd(s));
} }
public PrivateKey getPrivateKey() public PrivateKey getPrivateKey() {
{
if (privateKey != null) return privateKey; if (privateKey != null) return privateKey;
String pem = getPrivateKeyPem(); String pem = getPrivateKeyPem();
if (pem != null) if (pem != null) {
{ try {
try
{
privateKey = PemUtils.decodePrivateKey(pem); privateKey = PemUtils.decodePrivateKey(pem);
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
return privateKey; return privateKey;
} }
public void setPrivateKey(PrivateKey privateKey) public void setPrivateKey(PrivateKey privateKey) {
{
this.privateKey = privateKey; this.privateKey = privateKey;
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
PEMWriter pemWriter = new PEMWriter(writer); PEMWriter pemWriter = new PEMWriter(writer);
try try {
{
pemWriter.writeObject(privateKey); pemWriter.writeObject(privateKey);
pemWriter.flush(); pemWriter.flush();
} } catch (IOException e) {
catch (IOException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
String s = writer.toString(); String s = writer.toString();
setPrivateKeyPem(PemUtils.removeBeginEnd(s)); setPrivateKeyPem(PemUtils.removeBeginEnd(s));
} }
public List<RequiredCredentialModel> getRequiredCredentials() public List<RequiredCredentialModel> getRequiredCredentials() {
{
IdentityManager idm = getIdm(); IdentityManager idm = getIdm();
Agent realmAgent = idm.getAgent(REALM_AGENT_ID); Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
RelationshipQuery<RequiredCredentialRelationship> query = idm.createRelationshipQuery(RequiredCredentialRelationship.class); RelationshipQuery<RequiredCredentialRelationship> query = idm.createRelationshipQuery(RequiredCredentialRelationship.class);
query.setParameter(RequiredCredentialRelationship.REALM_AGENT, realmAgent); query.setParameter(RequiredCredentialRelationship.REALM_AGENT, realmAgent);
List<RequiredCredentialRelationship> results = query.getResultList(); List<RequiredCredentialRelationship> results = query.getResultList();
List<RequiredCredentialModel> rtn = new ArrayList<RequiredCredentialModel>(); List<RequiredCredentialModel> rtn = new ArrayList<RequiredCredentialModel>();
for (RequiredCredentialRelationship relationship : results) for (RequiredCredentialRelationship relationship : results) {
{
RequiredCredentialModel model = new RequiredCredentialModel(); RequiredCredentialModel model = new RequiredCredentialModel();
model.setInput(relationship.isInput()); model.setInput(relationship.isInput());
model.setSecret(relationship.isSecret()); model.setSecret(relationship.isSecret());
@ -251,8 +210,7 @@ public class RealmModel
return rtn; return rtn;
} }
public void addRequiredCredential(RequiredCredentialModel cred) public void addRequiredCredential(RequiredCredentialModel cred) {
{
IdentityManager idm = getIdm(); IdentityManager idm = getIdm();
Agent realmAgent = idm.getAgent(REALM_AGENT_ID); Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
RequiredCredentialRelationship relationship = new RequiredCredentialRelationship(); RequiredCredentialRelationship relationship = new RequiredCredentialRelationship();
@ -263,28 +221,19 @@ public class RealmModel
idm.add(relationship); idm.add(relationship);
} }
public void updateCredential(User user, UserCredentialModel cred) public void updateCredential(User user, UserCredentialModel cred) {
{
IdentityManager idm = getIdm(); IdentityManager idm = getIdm();
if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD)) if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD)) {
{
Password password = new Password(cred.getValue()); Password password = new Password(cred.getValue());
idm.updateCredential(user, password); idm.updateCredential(user, password);
} } else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP)) {
else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP))
{
TOTPCredential totp = new TOTPCredential(cred.getValue()); TOTPCredential totp = new TOTPCredential(cred.getValue());
idm.updateCredential(user, totp); idm.updateCredential(user, totp);
} } else if (cred.getType().equals(RequiredCredentialRepresentation.CLIENT_CERT)) {
else if (cred.getType().equals(RequiredCredentialRepresentation.CLIENT_CERT))
{
X509Certificate cert = null; X509Certificate cert = null;
try try {
{
cert = org.keycloak.PemUtils.decodeCertificate(cred.getValue()); cert = org.keycloak.PemUtils.decodeCertificate(cred.getValue());
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
X509CertificateCredentials creds = new X509CertificateCredentials(cert); X509CertificateCredentials creds = new X509CertificateCredentials(cert);
@ -292,8 +241,7 @@ public class RealmModel
} }
} }
public List<Role> getRoles() public List<Role> getRoles() {
{
IdentityManager idm = getIdm(); IdentityManager idm = getIdm();
IdentityQuery<Role> query = idm.createIdentityQuery(Role.class); IdentityQuery<Role> query = idm.createIdentityQuery(Role.class);
query.setParameter(Role.PARTITION, realm); query.setParameter(Role.PARTITION, realm);
@ -301,73 +249,57 @@ public class RealmModel
} }
protected ResourceModel loadResource(Agent resource)
{
Tier tier = factory.findTier(resource.getPartition().getId());
return new ResourceModel(tier, resource, this, factory);
}
/** /**
* Key name, value resource * Key name, value resource
* *
* @return * @return
*/ */
public Map<String, ResourceModel> getResourceMap() public Map<String, ResourceModel> getResourceMap() {
{
Map<String, ResourceModel> resourceMap = new HashMap<String, ResourceModel>(); Map<String, ResourceModel> resourceMap = new HashMap<String, ResourceModel>();
for (ResourceModel resource : getResources()) for (ResourceModel resource : getResources()) {
{
resourceMap.put(resource.getName(), resource); resourceMap.put(resource.getName(), resource);
} }
return resourceMap; return resourceMap;
} }
public List<ResourceModel> getResources() public List<ResourceModel> getResources() {
{
IdentityManager idm = getIdm(); IdentityManager idm = getIdm();
RelationshipQuery<RealmResourceRelationship> query = idm.createRelationshipQuery(RealmResourceRelationship.class); RelationshipQuery<ResourceRelationship> query = idm.createRelationshipQuery(ResourceRelationship.class);
query.setParameter(RealmResourceRelationship.REALM_AGENT, realmAgent); query.setParameter(ResourceRelationship.REALM_AGENT, realmAgent);
List<RealmResourceRelationship> results = query.getResultList(); List<ResourceRelationship> results = query.getResultList();
List<ResourceModel> resources = new ArrayList<ResourceModel>(); List<ResourceModel> resources = new ArrayList<ResourceModel>();
for (RealmResourceRelationship relationship : results) for (ResourceRelationship relationship : results) {
{ Tier resourceTier = IdentitySession.findTier(relationship.getResourceId());
ResourceModel model = loadResource(relationship.getResourceAgent()); ResourceModel model = new ResourceModel(resourceTier,relationship, this, IdentitySession);
resources.add(model); resources.add(model);
} }
return resources; return resources;
} }
public ResourceModel addResource(String name) public ResourceModel addResource(String name) {
{ Tier newTier = IdentitySession.createTier(RealmManager.generateId());
Tier newTier = factory.createTier(RealmManager.generateId()); IdentityManager idm = getIdm();
IdentityManager idm = factory.createIdentityManager(newTier); ResourceRelationship relationship = new ResourceRelationship();
SimpleAgent resourceAgent = new SimpleAgent(ResourceModel.RESOURCE_AGENT_ID); relationship.setResourceName(name);
resourceAgent.setAttribute(new Attribute<String>(ResourceModel.RESOURCE_NAME, name));
idm.add(resourceAgent);
idm = getIdm();
RealmResourceRelationship relationship = new RealmResourceRelationship();
relationship.setRealmAgent(realmAgent); relationship.setRealmAgent(realmAgent);
relationship.setResourceAgent(resourceAgent); relationship.setResourceId(newTier.getId());
idm.add(relationship); idm.add(relationship);
return new ResourceModel(newTier, resourceAgent, this, factory); return new ResourceModel(newTier, relationship, this, IdentitySession);
} }
public Set<String> getRoleMappings(User user) public Set<String> getRoleMappings(User user) {
{
RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class); RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
query.setParameter(Grant.ASSIGNEE, user); query.setParameter(Grant.ASSIGNEE, user);
List<Grant> grants = query.getResultList(); List<Grant> grants = query.getResultList();
HashSet<String> set = new HashSet<String>(); HashSet<String> set = new HashSet<String>();
for (Grant grant : grants) for (Grant grant : grants) {
{
if (grant.getRole().getPartition().getId().equals(realm.getId())) set.add(grant.getRole().getName()); if (grant.getRole().getPartition().getId().equals(realm.getId())) set.add(grant.getRole().getName());
} }
return set; return set;
} }
public void addScope(Agent agent, String roleName) public void addScope(Agent agent, String roleName) {
{
IdentityManager idm = getIdm(); IdentityManager idm = getIdm();
Role role = idm.getRole(roleName); Role role = idm.getRole(roleName);
if (role == null) throw new RuntimeException("role not found"); if (role == null) throw new RuntimeException("role not found");
@ -378,35 +310,31 @@ public class RealmModel
} }
public Set<String> getScope(Agent agent) public Set<String> getScope(Agent agent) {
{
RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class); RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
query.setParameter(ScopeRelationship.CLIENT, agent); query.setParameter(ScopeRelationship.CLIENT, agent);
List<ScopeRelationship> scope = query.getResultList(); List<ScopeRelationship> scope = query.getResultList();
HashSet<String> set = new HashSet<String>(); HashSet<String> set = new HashSet<String>();
for (ScopeRelationship rel : scope) for (ScopeRelationship rel : scope) {
{
if (rel.getScope().getPartition().getId().equals(realm.getId())) set.add(rel.getScope().getName()); if (rel.getScope().getPartition().getId().equals(realm.getId())) set.add(rel.getScope().getName());
} }
return set; return set;
} }
public boolean isRealmAdmin(Agent agent) public boolean isRealmAdmin(Agent agent) {
{ IdentityManager idm = new RealmManager(IdentitySession).defaultRealm().getIdm();
IdentityManager idm = getIdm();
RelationshipQuery<RealmAdminRelationship> query = idm.createRelationshipQuery(RealmAdminRelationship.class); RelationshipQuery<RealmAdminRelationship> query = idm.createRelationshipQuery(RealmAdminRelationship.class);
query.setParameter(RealmAdminRelationship.REALM, realm); query.setParameter(RealmAdminRelationship.REALM, realm.getId());
query.setParameter(RealmAdminRelationship.ADMIN, agent); query.setParameter(RealmAdminRelationship.ADMIN, agent);
List<RealmAdminRelationship> results = query.getResultList(); List<RealmAdminRelationship> results = query.getResultList();
return results.size() > 0; return results.size() > 0;
} }
public void addRealmAdmin(Agent agent) public void addRealmAdmin(Agent agent) {
{ IdentityManager idm = new RealmManager(IdentitySession).defaultRealm().getIdm();
IdentityManager idm = getIdm();
RealmAdminRelationship relationship = new RealmAdminRelationship(); RealmAdminRelationship relationship = new RealmAdminRelationship();
relationship.setAdmin(agent); relationship.setAdmin(agent);
relationship.setRealm(realm); relationship.setRealm(realm.getId());
idm.add(relationship); idm.add(relationship);
} }
} }

View file

@ -1,42 +1,48 @@
package org.keycloak.services.models; package org.keycloak.services.models;
import org.keycloak.representations.idm.RequiredCredentialRepresentation;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RequiredCredentialModel public class RequiredCredentialModel {
{
protected String type; protected String type;
protected boolean input; protected boolean input;
protected boolean secret; protected boolean secret;
public String getType() public RequiredCredentialModel() {
{ }
public RequiredCredentialModel(String type, boolean input, boolean secret) {
this.type = type;
this.input = input;
this.secret = secret;
}
public String getType() {
return type; return type;
} }
public void setType(String type) public void setType(String type) {
{
this.type = type; this.type = type;
} }
public boolean isInput() public boolean isInput() {
{
return input; return input;
} }
public void setInput(boolean input) public void setInput(boolean input) {
{
this.input = input; this.input = input;
} }
public boolean isSecret() public boolean isSecret() {
{
return secret; return secret;
} }
public void setSecret(boolean secret) public void setSecret(boolean secret) {
{
this.secret = secret; this.secret = secret;
} }
public static final RequiredCredentialModel PASSWORD = new RequiredCredentialModel(RequiredCredentialRepresentation.PASSWORD, true, true);
} }

View file

@ -1,8 +1,9 @@
package org.keycloak.services.models; package org.keycloak.services.models;
import org.keycloak.services.models.relationships.ResourceRelationship;
import org.keycloak.services.models.relationships.ScopeRelationship; import org.keycloak.services.models.relationships.ScopeRelationship;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.IdentityManager; import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.internal.IdentityManagerFactory;
import org.picketlink.idm.model.Agent; import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Attribute; import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Grant; import org.picketlink.idm.model.Grant;
@ -20,93 +21,77 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class ResourceModel public class ResourceModel {
{
public static final String RESOURCE_AGENT_ID = "_resource_"; public static final String RESOURCE_AGENT_ID = "_resource_";
public static final String RESOURCE_NAME = "name"; public static final String RESOURCE_NAME = "name";
public static final String RESOURCE_SURROGATE_AUTH = "surrogate_auth"; public static final String RESOURCE_SURROGATE_AUTH = "surrogate_auth";
protected Tier tier; protected Tier tier;
protected Agent agent; protected ResourceRelationship agent;
protected RealmModel realm; protected RealmModel realm;
protected IdentityManagerFactory factory; protected IdentitySession IdentitySession;
public ResourceModel(Tier tier, Agent agent, RealmModel realm, IdentityManagerFactory factory) public ResourceModel(Tier tier, ResourceRelationship agent, RealmModel realm, IdentitySession factory) {
{
this.tier = tier; this.tier = tier;
this.agent = agent; this.agent = agent;
this.realm = realm; this.realm = realm;
this.factory = factory; this.IdentitySession = factory;
} }
public IdentityManager getIdm() public IdentityManager getIdm() {
{ return IdentitySession.createIdentityManager(tier);
return factory.createIdentityManager(tier);
} }
public void updateResource() public void updateResource() {
{
getIdm().update(agent); getIdm().update(agent);
} }
public String getId() public String getId() {
{
return tier.getId(); return tier.getId();
} }
public String getName() public String getName() {
{ return agent.getResourceName();
return (String)agent.getAttribute(RESOURCE_NAME).getValue();
} }
public void setName(String name) public void setName(String name) {
{ agent.setResourceName(name);
agent.setAttribute(new Attribute<String>(RESOURCE_NAME, name));
getIdm().update(agent);
} }
public boolean isEnabled() public boolean isEnabled() {
{ return agent.getEnabled();
return agent.isEnabled();
} }
public void setEnabled(boolean enabled) public void setEnabled(boolean enabled) {
{
agent.setEnabled(enabled); agent.setEnabled(enabled);
} }
public boolean isSurrogateAuthRequired() public boolean isSurrogateAuthRequired() {
{ return agent.getSurrogateAuthRequired();
return (Boolean)agent.getAttribute(RESOURCE_SURROGATE_AUTH).getValue();
} }
public void setSurrogateAuthRequired(boolean surrogateAuthRequired) public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
{ agent.setSurrogateAuthRequired(surrogateAuthRequired);
agent.setAttribute(new Attribute<Boolean>(RESOURCE_SURROGATE_AUTH, surrogateAuthRequired));
} }
public List<Role> getRoles() public List<Role> getRoles() {
{
IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class); IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class);
query.setParameter(Role.PARTITION, tier); query.setParameter(Role.PARTITION, tier);
return query.getResultList(); return query.getResultList();
} }
public Set<String> getRoleMappings(User user) public Set<String> getRoleMappings(User user) {
{
RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class); RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
query.setParameter(Grant.ASSIGNEE, user); query.setParameter(Grant.ASSIGNEE, user);
List<Grant> grants = query.getResultList(); List<Grant> grants = query.getResultList();
HashSet<String> set = new HashSet<String>(); HashSet<String> set = new HashSet<String>();
for (Grant grant : grants) for (Grant grant : grants) {
{
if (grant.getRole().getPartition().getId().equals(tier.getId())) set.add(grant.getRole().getName()); if (grant.getRole().getPartition().getId().equals(tier.getId())) set.add(grant.getRole().getName());
} }
return set; return set;
} }
public void addScope(Agent agent, String roleName) public void addScope(Agent agent, String roleName) {
{
IdentityManager idm = getIdm(); IdentityManager idm = getIdm();
Role role = idm.getRole(roleName); Role role = idm.getRole(roleName);
if (role == null) throw new RuntimeException("role not found"); if (role == null) throw new RuntimeException("role not found");
@ -116,14 +101,12 @@ public class ResourceModel
} }
public Set<String> getScope(Agent agent) public Set<String> getScope(Agent agent) {
{
RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class); RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
query.setParameter(ScopeRelationship.CLIENT, agent); query.setParameter(ScopeRelationship.CLIENT, agent);
List<ScopeRelationship> scope = query.getResultList(); List<ScopeRelationship> scope = query.getResultList();
HashSet<String> set = new HashSet<String>(); HashSet<String> set = new HashSet<String>();
for (ScopeRelationship rel : scope) for (ScopeRelationship rel : scope) {
{
if (rel.getScope().getPartition().getId().equals(tier.getId())) set.add(rel.getScope().getName()); if (rel.getScope().getPartition().getId().equals(tier.getId())) set.add(rel.getScope().getName());
} }
return set; return set;

View file

@ -4,29 +4,24 @@ package org.keycloak.services.models;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class UserCredentialModel public class UserCredentialModel {
{
protected String type; protected String type;
protected String value; protected String value;
public String getType() public String getType() {
{
return type; return type;
} }
public void setType(String type) public void setType(String type) {
{
this.type = type; this.type = type;
} }
public String getValue() public String getValue() {
{
return value; return value;
} }
public void setValue(String value) public void setValue(String value) {
{
this.value = value; this.value = value;
} }
} }

View file

@ -4,6 +4,7 @@ import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Agent; import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Realm; import org.picketlink.idm.model.Realm;
import org.picketlink.idm.model.Relationship; 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.annotation.IdentityProperty;
import org.picketlink.idm.query.RelationshipQueryParameter; import org.picketlink.idm.query.RelationshipQueryParameter;
@ -11,8 +12,7 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RealmAdminRelationship extends AbstractAttributedType implements Relationship public class RealmAdminRelationship extends AbstractAttributedType implements Relationship {
{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public static final RelationshipQueryParameter REALM = new RelationshipQueryParameter() { public static final RelationshipQueryParameter REALM = new RelationshipQueryParameter() {
@ -31,28 +31,24 @@ public class RealmAdminRelationship extends AbstractAttributedType implements Re
} }
}; };
protected Realm realm; protected String realm;
protected Agent admin; protected Agent admin;
@IdentityProperty @AttributeProperty
public Realm getRealm() public String getRealm() {
{
return realm; return realm;
} }
public void setRealm(Realm realm) public void setRealm(String realm) {
{
this.realm = realm; this.realm = realm;
} }
@IdentityProperty @IdentityProperty
public Agent getAdmin() public Agent getAdmin() {
{
return admin; return admin;
} }
public void setAdmin(Agent admin) public void setAdmin(Agent admin) {
{
this.admin = admin; this.admin = admin;
} }
} }

View file

@ -1,57 +0,0 @@
package org.keycloak.services.models.relationships;
import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Relationship;
import org.picketlink.idm.model.annotation.IdentityProperty;
import org.picketlink.idm.query.RelationshipQueryParameter;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class RealmResourceRelationship 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 RelationshipQueryParameter RESOURCE_AGENT = new RelationshipQueryParameter() {
@Override
public String getName() {
return "resourceAgent";
}
};
protected Agent realmAgent;
protected Agent resourceAgent;
@IdentityProperty
public Agent getRealmAgent()
{
return realmAgent;
}
public void setRealmAgent(Agent realmAgent)
{
this.realmAgent = realmAgent;
}
@IdentityProperty
public Agent getResourceAgent()
{
return resourceAgent;
}
public void setResourceAgent(Agent resourceAgent)
{
this.resourceAgent = resourceAgent;
}
}

View file

@ -11,8 +11,7 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RequiredCredentialRelationship extends AbstractAttributedType implements Relationship public class RequiredCredentialRelationship extends AbstractAttributedType implements Relationship {
{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public static final RelationshipQueryParameter REALM_AGENT = new RelationshipQueryParameter() { public static final RelationshipQueryParameter REALM_AGENT = new RelationshipQueryParameter() {
@ -29,51 +28,42 @@ public class RequiredCredentialRelationship extends AbstractAttributedType imple
protected boolean input; protected boolean input;
protected boolean secret; protected boolean secret;
public RequiredCredentialRelationship() public RequiredCredentialRelationship() {
{
} }
@IdentityProperty @IdentityProperty
public Agent getRealmAgent() public Agent getRealmAgent() {
{
return realmAgent; return realmAgent;
} }
public void setRealmAgent(Agent realmAgent) public void setRealmAgent(Agent realmAgent) {
{
this.realmAgent = realmAgent; this.realmAgent = realmAgent;
} }
@AttributeProperty @AttributeProperty
public String getCredentialType() public String getCredentialType() {
{
return credentialType; return credentialType;
} }
public void setCredentialType(String credentialType) public void setCredentialType(String credentialType) {
{
this.credentialType = credentialType; this.credentialType = credentialType;
} }
@AttributeProperty @AttributeProperty
public boolean isInput() public boolean isInput() {
{
return input; return input;
} }
public void setInput(boolean input) public void setInput(boolean input) {
{
this.input = input; this.input = input;
} }
@AttributeProperty @AttributeProperty
public boolean isSecret() public boolean isSecret() {
{
return secret; return secret;
} }
public void setSecret(boolean secret) public void setSecret(boolean secret) {
{
this.secret = secret; this.secret = secret;
} }
} }

View file

@ -0,0 +1,75 @@
package org.keycloak.services.models.relationships;
import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Agent;
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.RelationshipQueryParameter;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceRelationship extends AbstractAttributedType implements Relationship {
private static final long serialVersionUID = 1L;
public static final RelationshipQueryParameter REALM_AGENT = new RelationshipQueryParameter() {
@Override
public String getName() {
return "realmAgent";
}
};
protected Agent realmAgent;
protected String resourceId;
protected String resourceName;
protected boolean surrogateAuthRequired;
protected boolean enabled;
@IdentityProperty
public Agent getRealmAgent() {
return realmAgent;
}
public void setRealmAgent(Agent realmAgent) {
this.realmAgent = realmAgent;
}
@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;
}
}

View file

@ -11,8 +11,7 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class ScopeRelationship extends AbstractAttributedType implements Relationship public class ScopeRelationship extends AbstractAttributedType implements Relationship {
{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public static final RelationshipQueryParameter CLIENT = new RelationshipQueryParameter() { public static final RelationshipQueryParameter CLIENT = new RelationshipQueryParameter() {
@ -27,24 +26,20 @@ public class ScopeRelationship extends AbstractAttributedType implements Relatio
protected Role scope; protected Role scope;
@IdentityProperty @IdentityProperty
public Agent getClient() public Agent getClient() {
{
return client; return client;
} }
public void setClient(Agent client) public void setClient(Agent client) {
{
this.client = client; this.client = client;
} }
@IdentityProperty @IdentityProperty
public Role getScope() public Role getScope() {
{
return scope; return scope;
} }
public void setScope(Role scope) public void setScope(Role scope) {
{
this.scope = scope; this.scope = scope;
} }
} }

View file

@ -0,0 +1,90 @@
package org.keycloak.services.resources;
import org.keycloak.SkeletonKeyContextResolver;
import org.keycloak.services.filters.IdentitySessionFilter;
import org.keycloak.services.models.relationships.RealmAdminRelationship;
import org.keycloak.services.models.relationships.ResourceRelationship;
import org.keycloak.services.models.relationships.RequiredCredentialRelationship;
import org.keycloak.services.models.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 javax.annotation.PreDestroy;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakApplication extends Application {
protected Set<Object> singletons = new HashSet<Object>();
protected Set<Class<?>> classes = new HashSet<Class<?>>();
protected IdentitySessionFactory factory;
public KeycloakApplication() {
this.factory = createFactory();
IdentitySessionFilter filter = new IdentitySessionFilter(factory);
singletons.add(new RealmsResource());
singletons.add(filter);
classes.add(SkeletonKeyContextResolver.class);
classes.add(RegistrationService.class);
}
public IdentitySessionFactory getFactory() {
return factory;
}
@PreDestroy
public void destroy() {
factory.close();
}
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);
}
@Override
public Set<Class<?>> getClasses() {
return classes;
}
@Override
public Set<Object> getSingletons() {
return singletons;
}
}

View file

@ -1,343 +0,0 @@
package org.keycloak.services.resources;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.RequiredCredentialRepresentation;
import org.keycloak.representations.idm.ResourceRepresentation;
import org.keycloak.representations.idm.RoleMappingRepresentation;
import org.keycloak.representations.idm.ScopeMappingRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.models.RealmManager;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.ResourceModel;
import org.keycloak.services.models.UserCredentialModel;
import org.picketlink.idm.model.Attribute;
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.User;
import javax.ws.rs.Consumes;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Path("/realmfactory")
public class RealmFactory
{
protected Logger logger = Logger.getLogger(RealmFactory.class);
protected RealmManager adapter;
protected AuthenticationManager authenticationManager;
protected RealmModel defaultRealm;
@Context
protected UriInfo uriInfo;
@Context
protected HttpHeaders headers;
public RealmFactory(RealmManager adapter)
{
this.adapter = adapter;
defaultRealm = adapter.getRealm(Realm.DEFAULT_REALM);
}
@POST
@Consumes("application/json")
public Response importDomain(RealmRepresentation rep)
{
RealmModel realm = createRealm(rep);
UriBuilder builder = uriInfo.getRequestUriBuilder().path(realm.getId());
return Response.created(builder.build())
.entity(RealmResource.realmRep(realm, uriInfo))
.type(MediaType.APPLICATION_JSON_TYPE).build();
}
protected RealmModel createRealm(RealmRepresentation rep)
{
User realmCreator = authenticationManager.authenticateToken(defaultRealm, headers);
Role creatorRole = defaultRealm.getIdm().getRole(RegistrationService.REALM_CREATOR_ROLE);
if (!defaultRealm.getIdm().hasRole(realmCreator, creatorRole))
{
logger.warn("not a realm creator");
throw new NotAuthorizedException("Bearer");
}
verifyRealmRepresentation(rep);
RealmModel realm = adapter.create(rep.getRealm());
realm.addRealmAdmin(realmCreator);
KeyPair keyPair = null;
try
{
keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(e);
}
realm.setPrivateKey(keyPair.getPrivate());
realm.setPublicKey(keyPair.getPublic());
realm.setName(rep.getRealm());
realm.setEnabled(rep.isEnabled());
realm.setTokenLifespan(rep.getTokenLifespan());
realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
realm.setSslNotRequired(rep.isSslNotRequired());
realm.setCookieLoginAllowed(rep.isCookieLoginAllowed());
realm.updateRealm();
Map<String, User> userMap = new HashMap<String, User>();
for (RequiredCredentialRepresentation requiredCred : rep.getRequiredCredentials())
{
RequiredCredentialModel credential = new RequiredCredentialModel();
credential.setType(requiredCred.getType());
credential.setInput(requiredCred.isInput());
credential.setSecret(requiredCred.isSecret());
realm.addRequiredCredential(credential);
}
for (UserRepresentation userRep : rep.getUsers())
{
User user = new SimpleUser(userRep.getUsername());
user.setEnabled(userRep.isEnabled());
if (userRep.getAttributes() != null)
{
for (Map.Entry<String, String> entry : userRep.getAttributes().entrySet())
{
user.setAttribute(new Attribute<String>(entry.getKey(), entry.getValue()));
}
}
realm.getIdm().add(user);
if (userRep.getCredentials() != null)
{
for (UserRepresentation.Credential cred : userRep.getCredentials())
{
UserCredentialModel credential = new UserCredentialModel();
credential.setType(cred.getType());
credential.setValue(cred.getValue());
realm.updateCredential(user, credential);
}
}
userMap.put(user.getLoginName(), user);
}
Map<String, Role> roles = new HashMap<String, Role>();
if (rep.getRoles() != null)
{
for (String roleString : rep.getRoles())
{
SimpleRole role = new SimpleRole(roleString.trim());
realm.getIdm().add(role);
roles.put(role.getName(), role);
}
}
if (rep.getRoleMappings() != null)
{
for (RoleMappingRepresentation mapping : rep.getRoleMappings())
{
User user = userMap.get(mapping.getUsername());
for (String roleString : mapping.getRoles())
{
Role role = roles.get(roleString.trim());
if (role == null)
{
role = new SimpleRole(roleString.trim());
realm.getIdm().add(role);
roles.put(role.getName(), role);
}
realm.getIdm().grantRole(user, role);
}
}
}
if (rep.getScopeMappings() != null)
{
for (ScopeMappingRepresentation scope : rep.getScopeMappings())
{
for (String roleString : scope.getRoles())
{
Role role = roles.get(roleString.trim());
if (role == null)
{
role = new SimpleRole(roleString.trim());
realm.getIdm().add(role);
roles.put(role.getName(), role);
}
User user = userMap.get(scope.getUsername());
realm.addScope(user, role.getName());
}
}
}
if (!roles.containsKey("*"))
{
SimpleRole wildcard = new SimpleRole("*");
realm.getIdm().add(wildcard);
roles.put("*", wildcard);
}
if (rep.getResources() != null)
{
createResources(rep, realm, userMap);
}
return realm;
}
protected void createResources(RealmRepresentation rep, RealmModel realm, Map<String, User> userMap)
{
for (ResourceRepresentation resourceRep : rep.getResources())
{
ResourceModel resource = realm.addResource(resourceRep.getName());
resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
resource.updateResource();
Map<String, Role> roles = new HashMap<String, Role>();
if (resourceRep.getRoles() != null)
{
for (String roleString : rep.getRoles())
{
SimpleRole role = new SimpleRole(roleString.trim());
resource.getIdm().add(role);
roles.put(role.getName(), role);
}
}
if (resourceRep.getRoleMappings() != null)
{
for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings())
{
User user = userMap.get(mapping.getUsername());
for (String roleString : mapping.getRoles())
{
Role role = roles.get(roleString.trim());
if (role == null)
{
role = new SimpleRole(roleString.trim());
resource.getIdm().add(role);
roles.put(role.getName(), role);
}
resource.getIdm().grantRole(user, role);
}
}
}
if (resourceRep.getScopeMappings() != null)
{
for (ScopeMappingRepresentation mapping : resourceRep.getScopeMappings())
{
User user = userMap.get(mapping.getUsername());
for (String roleString : mapping.getRoles())
{
Role role = roles.get(roleString.trim());
if (role == null)
{
role = new SimpleRole(roleString.trim());
resource.getIdm().add(role);
roles.put(role.getName(), role);
}
resource.addScope(user, role.getName());
}
}
}
if (!roles.containsKey("*"))
{
SimpleRole wildcard = new SimpleRole("*");
resource.getIdm().add(wildcard);
roles.put("*", wildcard);
}
}
}
protected void verifyRealmRepresentation(RealmRepresentation rep)
{
if (rep.getRequiredCredentials() == null)
{
throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
.entity("Realm credential requirements not defined").type("text/plain").build());
}
HashMap<String, UserRepresentation> userReps = new HashMap<String, UserRepresentation>();
for (UserRepresentation userRep : rep.getUsers()) userReps.put(userRep.getUsername(), userRep);
// override enabled to false if user does not have at least all of browser or client credentials
for (UserRepresentation userRep : rep.getUsers())
{
if (userRep.getCredentials() == null)
{
userRep.setEnabled(false);
}
else
{
boolean hasBrowserCredentials = true;
for (RequiredCredentialRepresentation credential : rep.getRequiredCredentials())
{
boolean hasCredential = false;
for (UserRepresentation.Credential cred : userRep.getCredentials())
{
if (cred.getType().equals(credential.getType()))
{
hasCredential = true;
break;
}
}
if (!hasCredential)
{
hasBrowserCredentials = false;
break;
}
}
if (!hasBrowserCredentials)
{
userRep.setEnabled(false);
}
}
}
if (rep.getResources() != null)
{
// check mappings
for (ResourceRepresentation resourceRep : rep.getResources())
{
if (resourceRep.getRoleMappings() != null)
{
for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings())
{
if (!userReps.containsKey(mapping.getUsername()))
{
throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
.entity("No users declared for role mapping").type("text/plain").build());
}
}
}
}
}
}
}

View file

@ -1,122 +0,0 @@
package org.keycloak.services.resources;
import org.keycloak.services.models.RealmManager;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.PublishedRealmRepresentation;
import org.keycloak.services.models.RealmModel;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Path("/realms")
public class RealmResource
{
protected Logger logger = Logger.getLogger(RealmResource.class);
protected RealmManager adapter;
@Context
protected UriInfo uriInfo;
public RealmResource(RealmManager adapter)
{
this.adapter = adapter;
}
@GET
@Path("{realm}")
@Produces("application/json")
public PublishedRealmRepresentation getRealm(@PathParam("realm") String id)
{
RealmModel realm = adapter.getRealm(id);
if (realm == null)
{
logger.debug("realm not found");
throw new NotFoundException();
}
return realmRep(realm, uriInfo);
}
@GET
@Path("{realm}.html")
@Produces("text/html")
public String getRealmHtml(@PathParam("realm") String id)
{
RealmModel realm = adapter.getRealm(id);
if (realm == null)
{
logger.debug("realm not found");
throw new NotFoundException();
}
return realmHtml(realm);
}
private String realmHtml(RealmModel realm)
{
StringBuffer html = new StringBuffer();
UriBuilder auth = uriInfo.getBaseUriBuilder();
auth.path(TokenService.class)
.path(TokenService.class, "requestAccessCode");
String authUri = auth.build(realm.getId()).toString();
UriBuilder code = uriInfo.getBaseUriBuilder();
code.path(TokenService.class).path(TokenService.class, "accessRequest");
String codeUri = code.build(realm.getId()).toString();
UriBuilder grant = uriInfo.getBaseUriBuilder();
grant.path(TokenService.class).path(TokenService.class, "accessTokenGrant");
String grantUrl = grant.build(realm.getId()).toString();
UriBuilder idGrant = uriInfo.getBaseUriBuilder();
grant.path(TokenService.class).path(TokenService.class, "identityTokenGrant");
String idGrantUrl = idGrant.build(realm.getId()).toString();
html.append("<html><body><h1>Realm: ").append(realm.getName()).append("</h1>");
html.append("<p>auth: ").append(authUri).append("</p>");
html.append("<p>code: ").append(codeUri).append("</p>");
html.append("<p>grant: ").append(grantUrl).append("</p>");
html.append("<p>identity grant: ").append(idGrantUrl).append("</p>");
html.append("<p>public key: ").append(realm.getPublicKeyPem()).append("</p>");
html.append("</body></html>");
return html.toString();
}
public static PublishedRealmRepresentation realmRep(RealmModel realm, UriInfo uriInfo)
{
PublishedRealmRepresentation rep = new PublishedRealmRepresentation();
rep.setRealm(realm.getName());
rep.setSelf(uriInfo.getRequestUri().toString());
rep.setPublicKeyPem(realm.getPublicKeyPem());
UriBuilder auth = uriInfo.getBaseUriBuilder();
auth.path(TokenService.class)
.path(TokenService.class, "requestAccessCode");
rep.setAuthorizationUrl(auth.build(realm.getId()).toString());
UriBuilder code = uriInfo.getBaseUriBuilder();
code.path(TokenService.class).path(TokenService.class, "accessRequest");
rep.setCodeUrl(code.build(realm.getId()).toString());
UriBuilder grant = uriInfo.getBaseUriBuilder();
grant.path(TokenService.class).path(TokenService.class, "accessTokenGrant");
String grantUrl = grant.build(realm.getId()).toString();
rep.setGrantUrl(grantUrl);
UriBuilder idGrant = uriInfo.getBaseUriBuilder();
grant.path(TokenService.class).path(TokenService.class, "identityTokenGrant");
String idGrantUrl = idGrant.build(realm.getId()).toString();
rep.setIdentityGrantUrl(idGrantUrl);
return rep;
}
}

View file

@ -0,0 +1,105 @@
package org.keycloak.services.resources;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.PublishedRealmRepresentation;
import org.keycloak.services.models.RealmModel;
import org.picketlink.idm.IdentitySession;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class RealmSubResource {
protected static final Logger logger = Logger.getLogger(RealmSubResource.class);
@Context
protected UriInfo uriInfo;
@Context
protected IdentitySession IdentitySession;
protected RealmModel realm;
public RealmSubResource(RealmModel realm) {
this.realm = realm;
}
@GET
@Path("json")
@Produces("application/json")
public PublishedRealmRepresentation getRealm(@PathParam("realm") String id) {
return realmRep(realm, uriInfo);
}
@GET
@Path("html")
@Produces("text/html")
public String getRealmHtml(@PathParam("realm") String id) {
StringBuffer html = new StringBuffer();
UriBuilder auth = uriInfo.getBaseUriBuilder();
auth.path(TokenService.class)
.path(TokenService.class, "requestAccessCode");
String authUri = auth.build(realm.getId()).toString();
UriBuilder code = uriInfo.getBaseUriBuilder();
code.path(TokenService.class).path(TokenService.class, "accessRequest");
String codeUri = code.build(realm.getId()).toString();
UriBuilder grant = uriInfo.getBaseUriBuilder();
grant.path(TokenService.class).path(TokenService.class, "accessTokenGrant");
String grantUrl = grant.build(realm.getId()).toString();
UriBuilder idGrant = uriInfo.getBaseUriBuilder();
grant.path(TokenService.class).path(TokenService.class, "identityTokenGrant");
String idGrantUrl = idGrant.build(realm.getId()).toString();
html.append("<html><body><h1>Realm: ").append(realm.getName()).append("</h1>");
html.append("<p>auth: ").append(authUri).append("</p>");
html.append("<p>code: ").append(codeUri).append("</p>");
html.append("<p>grant: ").append(grantUrl).append("</p>");
html.append("<p>identity grant: ").append(idGrantUrl).append("</p>");
html.append("<p>public key: ").append(realm.getPublicKeyPem()).append("</p>");
html.append("</body></html>");
return html.toString();
}
public static PublishedRealmRepresentation realmRep(RealmModel realm, UriInfo uriInfo) {
PublishedRealmRepresentation rep = new PublishedRealmRepresentation();
rep.setRealm(realm.getName());
rep.setSelf(uriInfo.getRequestUri().toString());
rep.setPublicKeyPem(realm.getPublicKeyPem());
UriBuilder auth = uriInfo.getBaseUriBuilder();
auth.path(RealmsResource.class).path(RealmsResource.class, "getTokenService")
.path(TokenService.class, "requestAccessCode");
rep.setAuthorizationUrl(auth.build(realm.getId()).toString());
UriBuilder code = uriInfo.getBaseUriBuilder();
code.path(RealmsResource.class).path(RealmsResource.class, "getTokenService").path(TokenService.class, "accessRequest");
rep.setCodeUrl(code.build(realm.getId()).toString());
UriBuilder grant = uriInfo.getBaseUriBuilder();
grant.path(RealmsResource.class).path(RealmsResource.class, "getTokenService").path(TokenService.class, "accessTokenGrant");
String grantUrl = grant.build(realm.getId()).toString();
rep.setGrantUrl(grantUrl);
UriBuilder idGrant = uriInfo.getBaseUriBuilder();
grant.path(RealmsResource.class).path(RealmsResource.class, "getTokenService").path(TokenService.class, "identityTokenGrant");
String idGrantUrl = idGrant.build(realm.getId()).toString();
rep.setIdentityGrantUrl(idGrantUrl);
return rep;
}
}

View file

@ -0,0 +1,323 @@
package org.keycloak.services.resources;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RequiredCredentialRepresentation;
import org.keycloak.representations.idm.ResourceRepresentation;
import org.keycloak.representations.idm.RoleMappingRepresentation;
import org.keycloak.representations.idm.ScopeMappingRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.AccessCodeEntry;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.models.RealmManager;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.ResourceModel;
import org.keycloak.services.models.UserCredentialModel;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.model.Attribute;
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.User;
import javax.ws.rs.Consumes;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Path("/realms")
public class RealmsResource {
protected static Logger logger = Logger.getLogger(RealmsResource.class);
@Context
protected UriInfo uriInfo;
@Context
protected HttpHeaders headers;
@Context
protected
IdentitySession IdentitySession;
@Context
ResourceContext resourceContext;
protected Map<String, AccessCodeEntry> accessCodes = new ConcurrentHashMap<String, AccessCodeEntry>();
@Path("{realm}/tokens")
public TokenService getTokenService(@PathParam("realm") String id) {
RealmManager realmManager = new RealmManager(IdentitySession);
RealmModel realm = realmManager.getRealm(id);
if (realm == null) {
logger.debug("realm not found");
throw new NotFoundException();
}
TokenService tokenService = new TokenService(realm, accessCodes);
resourceContext.initResource(tokenService);
return tokenService;
}
@Path("{realm}")
public RealmSubResource getRealmResource(@PathParam("realm") String id) {
RealmManager realmManager = new RealmManager(IdentitySession);
RealmModel realm = realmManager.getRealm(id);
if (realm == null) {
logger.debug("realm not found");
throw new NotFoundException();
}
RealmSubResource realmResource = new RealmSubResource(realm);
resourceContext.initResource(realmResource);
return realmResource;
}
@POST
@Consumes("application/json")
public Response importRealm(RealmRepresentation rep) {
IdentitySession.getTransaction().begin();
RealmModel realm;
try {
realm = createRealm(rep);
IdentitySession.getTransaction().commit();
} catch (RuntimeException re) {
IdentitySession.getTransaction().rollback();
throw re;
}
UriBuilder builder = uriInfo.getRequestUriBuilder().path(realm.getId());
return Response.created(builder.build())
.entity(RealmSubResource.realmRep(realm, uriInfo))
.type(MediaType.APPLICATION_JSON_TYPE).build();
}
protected RealmModel createRealm(RealmRepresentation rep) {
RealmManager realmManager = new RealmManager(IdentitySession);
RealmModel defaultRealm = realmManager.getRealm(Realm.DEFAULT_REALM);
User realmCreator = new AuthenticationManager().authenticateToken(defaultRealm, headers);
Role creatorRole = defaultRealm.getIdm().getRole(RegistrationService.REALM_CREATOR_ROLE);
if (!defaultRealm.getIdm().hasRole(realmCreator, creatorRole)) {
logger.warn("not a realm creator");
throw new NotAuthorizedException("Bearer");
}
verifyRealmRepresentation(rep);
RealmModel realm = realmManager.createRealm(rep.getRealm());
realmManager.generateRealmKeys(realm);
realm.addRealmAdmin(realmCreator);
realm.setName(rep.getRealm());
realm.setEnabled(rep.isEnabled());
realm.setTokenLifespan(rep.getTokenLifespan());
realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
realm.setSslNotRequired(rep.isSslNotRequired());
realm.setCookieLoginAllowed(rep.isCookieLoginAllowed());
realm.updateRealm();
Map<String, User> userMap = new HashMap<String, User>();
for (RequiredCredentialRepresentation requiredCred : rep.getRequiredCredentials()) {
RequiredCredentialModel credential = new RequiredCredentialModel();
credential.setType(requiredCred.getType());
credential.setInput(requiredCred.isInput());
credential.setSecret(requiredCred.isSecret());
realm.addRequiredCredential(credential);
}
for (UserRepresentation userRep : rep.getUsers()) {
User user = new SimpleUser(userRep.getUsername());
user.setEnabled(userRep.isEnabled());
if (userRep.getAttributes() != null) {
for (Map.Entry<String, String> entry : userRep.getAttributes().entrySet()) {
user.setAttribute(new Attribute<String>(entry.getKey(), entry.getValue()));
}
}
realm.getIdm().add(user);
if (userRep.getCredentials() != null) {
for (UserRepresentation.Credential cred : userRep.getCredentials()) {
UserCredentialModel credential = new UserCredentialModel();
credential.setType(cred.getType());
credential.setValue(cred.getValue());
realm.updateCredential(user, credential);
}
}
userMap.put(user.getLoginName(), user);
}
Map<String, Role> roles = new HashMap<String, Role>();
if (rep.getRoles() != null) {
for (String roleString : rep.getRoles()) {
SimpleRole role = new SimpleRole(roleString.trim());
realm.getIdm().add(role);
roles.put(role.getName(), role);
}
}
if (rep.getRoleMappings() != null) {
for (RoleMappingRepresentation mapping : rep.getRoleMappings()) {
User user = userMap.get(mapping.getUsername());
for (String roleString : mapping.getRoles()) {
Role role = roles.get(roleString.trim());
if (role == null) {
role = new SimpleRole(roleString.trim());
realm.getIdm().add(role);
roles.put(role.getName(), role);
}
realm.getIdm().grantRole(user, role);
}
}
}
if (rep.getScopeMappings() != null) {
for (ScopeMappingRepresentation scope : rep.getScopeMappings()) {
for (String roleString : scope.getRoles()) {
Role role = roles.get(roleString.trim());
if (role == null) {
role = new SimpleRole(roleString.trim());
realm.getIdm().add(role);
roles.put(role.getName(), role);
}
User user = userMap.get(scope.getUsername());
realm.addScope(user, role.getName());
}
}
}
if (!roles.containsKey("*")) {
SimpleRole wildcard = new SimpleRole("*");
realm.getIdm().add(wildcard);
roles.put("*", wildcard);
}
if (rep.getResources() != null) {
createResources(rep, realm, userMap);
}
return realm;
}
protected void createResources(RealmRepresentation rep, RealmModel realm, Map<String, User> userMap) {
for (ResourceRepresentation resourceRep : rep.getResources()) {
ResourceModel resource = realm.addResource(resourceRep.getName());
resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
resource.updateResource();
Map<String, Role> roles = new HashMap<String, Role>();
if (resourceRep.getRoles() != null) {
for (String roleString : resourceRep.getRoles()) {
SimpleRole role = new SimpleRole(roleString.trim());
resource.getIdm().add(role);
roles.put(role.getName(), role);
}
}
if (resourceRep.getRoleMappings() != null) {
for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) {
User user = userMap.get(mapping.getUsername());
for (String roleString : mapping.getRoles()) {
Role role = roles.get(roleString.trim());
if (role == null) {
role = new SimpleRole(roleString.trim());
resource.getIdm().add(role);
roles.put(role.getName(), role);
}
Role role1 = resource.getIdm().getRole(role.getName());
realm.getIdm().grantRole(user, role1);
}
}
}
if (resourceRep.getScopeMappings() != null) {
for (ScopeMappingRepresentation mapping : resourceRep.getScopeMappings()) {
User user = userMap.get(mapping.getUsername());
for (String roleString : mapping.getRoles()) {
Role role = roles.get(roleString.trim());
if (role == null) {
role = new SimpleRole(roleString.trim());
resource.getIdm().add(role);
roles.put(role.getName(), role);
}
resource.addScope(user, role.getName());
}
}
}
if (!roles.containsKey("*")) {
SimpleRole wildcard = new SimpleRole("*");
resource.getIdm().add(wildcard);
roles.put("*", wildcard);
}
}
}
protected void verifyRealmRepresentation(RealmRepresentation rep) {
if (rep.getRequiredCredentials() == null) {
throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
.entity("Realm credential requirements not defined").type("text/plain").build());
}
HashMap<String, UserRepresentation> userReps = new HashMap<String, UserRepresentation>();
for (UserRepresentation userRep : rep.getUsers()) userReps.put(userRep.getUsername(), userRep);
// override enabled to false if user does not have at least all of browser or client credentials
for (UserRepresentation userRep : rep.getUsers()) {
if (userRep.getCredentials() == null) {
userRep.setEnabled(false);
} else {
boolean hasBrowserCredentials = true;
for (RequiredCredentialRepresentation credential : rep.getRequiredCredentials()) {
boolean hasCredential = false;
for (UserRepresentation.Credential cred : userRep.getCredentials()) {
if (cred.getType().equals(credential.getType())) {
hasCredential = true;
break;
}
}
if (!hasCredential) {
hasBrowserCredentials = false;
break;
}
}
if (!hasBrowserCredentials) {
userRep.setEnabled(false);
}
}
}
if (rep.getResources() != null) {
// check mappings
for (ResourceRepresentation resourceRep : rep.getResources()) {
if (resourceRep.getRoleMappings() != null) {
for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) {
if (!userReps.containsKey(mapping.getUsername())) {
throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
.entity("No users declared for role mapping").type("text/plain").build());
}
}
}
}
}
}
}

View file

@ -1,10 +1,11 @@
package org.keycloak.services.resources; package org.keycloak.services.resources;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.models.RealmManager; import org.keycloak.services.models.RealmManager;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.UserCredentialModel; import org.keycloak.services.models.UserCredentialModel;
import org.picketlink.idm.model.Realm; import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.model.Role; import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.SimpleUser; import org.picketlink.idm.model.SimpleUser;
import org.picketlink.idm.model.User; import org.picketlink.idm.model.User;
@ -23,37 +24,31 @@ import java.net.URI;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@Path("/registrations") @Path("/registrations")
public class RegistrationService public class RegistrationService {
{ protected static final Logger logger = Logger.getLogger(RegistrationService.class);
public static final String REALM_CREATOR_ROLE = "realm-creator"; public static final String REALM_CREATOR_ROLE = "realm-creator";
protected RealmManager adapter;
protected RealmModel defaultRealm;
@Context @Context
protected UriInfo uriInfo; protected UriInfo uriInfo;
public RegistrationService(RealmManager adapter) @Context
{ protected IdentitySession IdentitySession;
this.adapter = adapter;
defaultRealm = adapter.getRealm(Realm.DEFAULT_REALM);
}
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response register(UserRepresentation newUser) public Response register(UserRepresentation newUser) {
{ IdentitySession.getTransaction().begin();
try {
RealmManager realmManager = new RealmManager(IdentitySession);
RealmModel defaultRealm = realmManager.defaultRealm();
User user = defaultRealm.getIdm().getUser(newUser.getUsername()); User user = defaultRealm.getIdm().getUser(newUser.getUsername());
if (user != null) if (user != null) {
{
return Response.status(400).type("text/plain").entity("user exists").build(); return Response.status(400).type("text/plain").entity("user exists").build();
} }
user = new SimpleUser(newUser.getUsername()); user = new SimpleUser(newUser.getUsername());
defaultRealm.getIdm().add(user); defaultRealm.getIdm().add(user);
for (UserRepresentation.Credential cred : newUser.getCredentials()) for (UserRepresentation.Credential cred : newUser.getCredentials()) {
{
UserCredentialModel credModel = new UserCredentialModel(); UserCredentialModel credModel = new UserCredentialModel();
credModel.setType(cred.getType()); credModel.setType(cred.getType());
credModel.setValue(cred.getValue()); credModel.setValue(cred.getValue());
@ -61,8 +56,14 @@ public class RegistrationService
} }
Role realmCreator = defaultRealm.getIdm().getRole(REALM_CREATOR_ROLE); Role realmCreator = defaultRealm.getIdm().getRole(REALM_CREATOR_ROLE);
defaultRealm.getIdm().grantRole(user, realmCreator); defaultRealm.getIdm().grantRole(user, realmCreator);
URI uri = uriInfo.getBaseUriBuilder().path(RealmFactory.class).path(user.getLoginName()).build(); IdentitySession.getTransaction().commit();
URI uri = uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(user.getLoginName()).build();
return Response.created(uri).build(); return Response.created(uri).build();
} catch (RuntimeException e) {
logger.error("Failed to register", e);
IdentitySession.getTransaction().rollback();
throw e;
}
} }

View file

@ -1,55 +0,0 @@
package org.keycloak.services.resources;
import org.infinispan.Cache;
import org.infinispan.manager.DefaultCacheManager;
import org.keycloak.SkeletonKeyContextResolver;
import javax.ws.rs.core.Application;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SkeletonKeyApplication extends Application
{
protected Set<Object> singletons = new HashSet<Object>();
protected Set<Class<?>> classes = new HashSet<Class<?>>();
public SkeletonKeyApplication()
{
Cache cache = getCache();
singletons.add(new TokenService(null));
singletons.add(new RealmFactory(null));
singletons.add(new RealmResource(null));
classes.add(SkeletonKeyContextResolver.class);
}
@Override
public Set<Class<?>> getClasses()
{
return classes;
}
@Override
public Set<Object> getSingletons()
{
return singletons;
}
protected Cache getCache()
{
try
{
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("skeleton-key.xml");
return new DefaultCacheManager(is).getCache("skeleton-key");
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
}

View file

@ -9,21 +9,21 @@ import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.SkeletonKeyScope; import org.keycloak.representations.SkeletonKeyScope;
import org.keycloak.representations.SkeletonKeyToken; import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.services.managers.AccessCodeEntry;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.TokenManager; import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.models.RealmManager; import org.keycloak.services.models.RealmManager;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel; import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.ResourceModel; import org.keycloak.services.models.ResourceModel;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.model.User; import org.picketlink.idm.model.User;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.NotAuthorizedException; import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
@ -41,69 +41,17 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@Path("/realms") public class TokenService {
public class TokenService
{
public static class AccessCode
{
protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
protected long expiration;
protected SkeletonKeyToken token;
protected User client;
public boolean isExpired()
{
return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration;
}
public String getId() protected static final Logger logger = Logger.getLogger(TokenService.class);
{ protected Map<String, AccessCodeEntry> accessCodeMap;
return id;
}
public long getExpiration()
{
return expiration;
}
public void setExpiration(long expiration)
{
this.expiration = expiration;
}
public SkeletonKeyToken getToken()
{
return token;
}
public void setToken(SkeletonKeyToken token)
{
this.token = token;
}
public User getClient()
{
return client;
}
public void setClient(User client)
{
this.client = client;
}
}
protected RealmManager adapter;
protected TokenManager tokenManager;
protected AuthenticationManager authManager;
protected Logger logger = Logger.getLogger(TokenService.class);
protected Map<String, AccessCode> accessCodeMap = new HashMap<String, AccessCode>();
@Context @Context
protected UriInfo uriInfo; protected UriInfo uriInfo;
@Context @Context
@ -112,86 +60,68 @@ public class TokenService
protected SecurityContext securityContext; protected SecurityContext securityContext;
@Context @Context
protected HttpHeaders headers; protected HttpHeaders headers;
@Context
protected
IdentitySession IdentitySession;
private static AtomicLong counter = new AtomicLong(1); protected RealmModel realm;
private static String generateId() protected TokenManager tokenManager = new TokenManager();
{ protected AuthenticationManager authManager = new AuthenticationManager();
return counter.getAndIncrement() + "." + UUID.randomUUID().toString();
public TokenService(RealmModel realm, Map<String, AccessCodeEntry> accessCodeMap) {
this.realm = realm;
this.accessCodeMap = accessCodeMap;
} }
public TokenService(RealmManager adapter) @Path("grants/identity-token")
{
this.adapter = adapter;
this.tokenManager = new TokenManager(adapter);
this.authManager = new AuthenticationManager(adapter);
}
@Path("{realm}/grants/identity-token")
@POST @POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response identityTokenGrant(@PathParam("realm") String realmId, MultivaluedMap<String, String> form) public Response identityTokenGrant(MultivaluedMap<String, String> form) {
{
String username = form.getFirst(AuthenticationManager.FORM_USERNAME); String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
if (username == null) if (username == null) {
{
throw new NotAuthorizedException("No user"); throw new NotAuthorizedException("No user");
} }
RealmModel realm = adapter.getRealm(realmId); if (!realm.isEnabled()) {
if (realm == null)
{
throw new NotFoundException("Realm not found");
}
if (!realm.isEnabled())
{
throw new NotAuthorizedException("Disabled realm"); throw new NotAuthorizedException("Disabled realm");
} }
User user = realm.getIdm().getUser(username); User user = realm.getIdm().getUser(username);
if (user == null) if (user == null) {
{
throw new NotAuthorizedException("No user"); throw new NotAuthorizedException("No user");
} }
if (!user.isEnabled()) if (!user.isEnabled()) {
{
throw new NotAuthorizedException("Disabled user."); throw new NotAuthorizedException("Disabled user.");
} }
if (!authManager.authenticateForm(realm, user, form)) {
throw new NotAuthorizedException("FORM");
}
tokenManager = new TokenManager();
SkeletonKeyToken token = tokenManager.createIdentityToken(realm, username); SkeletonKeyToken token = tokenManager.createIdentityToken(realm, username);
String encoded = tokenManager.encodeToken(realm, token); String encoded = tokenManager.encodeToken(realm, token);
AccessTokenResponse res = accessTokenResponse(token, encoded); AccessTokenResponse res = accessTokenResponse(token, encoded);
return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build(); return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
} }
@Path("{realm}/grants/access") @Path("grants/access")
@POST @POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response accessTokenGrant(@PathParam("realm") String realmId, MultivaluedMap<String, String> form) public Response accessTokenGrant(MultivaluedMap<String, String> form) {
{
String username = form.getFirst(AuthenticationManager.FORM_USERNAME); String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
if (username == null) if (username == null) {
{
throw new NotAuthorizedException("No user"); throw new NotAuthorizedException("No user");
} }
RealmModel realm = adapter.getRealm(realmId); if (!realm.isEnabled()) {
if (realm == null)
{
throw new NotFoundException("Realm not found");
}
if (!realm.isEnabled())
{
throw new NotAuthorizedException("Disabled realm"); throw new NotAuthorizedException("Disabled realm");
} }
User user = realm.getIdm().getUser(username); User user = realm.getIdm().getUser(username);
if (user == null) if (user == null) {
{
throw new NotAuthorizedException("No user"); throw new NotAuthorizedException("No user");
} }
if (!user.isEnabled()) if (!user.isEnabled()) {
{
throw new NotAuthorizedException("Disabled user."); throw new NotAuthorizedException("Disabled user.");
} }
if (authManager.authenticateForm(realm, user, form)) if (authManager.authenticateForm(realm, user, form)) {
{
throw new NotAuthorizedException("Auth failed"); throw new NotAuthorizedException("Auth failed");
} }
SkeletonKeyToken token = tokenManager.createAccessToken(realm, user); SkeletonKeyToken token = tokenManager.createAccessToken(realm, user);
@ -200,69 +130,54 @@ public class TokenService
return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build(); return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
} }
@Path("{realm}/auth/request/login") @Path("auth/request/login")
@POST @POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response login(@PathParam("realm") String realmId, public Response login(MultivaluedMap<String, String> formData) {
MultivaluedMap<String, String> formData)
{
String clientId = formData.getFirst("client_id"); String clientId = formData.getFirst("client_id");
String scopeParam = formData.getFirst("scope"); String scopeParam = formData.getFirst("scope");
String state = formData.getFirst("state"); String state = formData.getFirst("state");
String redirect = formData.getFirst("redirect_uri"); String redirect = formData.getFirst("redirect_uri");
RealmModel realm = adapter.getRealm(realmId); if (!realm.isEnabled()) {
if (realm == null)
{
throw new NotFoundException("Realm not found");
}
if (!realm.isEnabled())
{
return Response.ok("Realm not enabled").type("text/html").build(); return Response.ok("Realm not enabled").type("text/html").build();
} }
User client = realm.getIdm().getUser(clientId); User client = realm.getIdm().getUser(clientId);
if (client == null) if (client == null) {
{
throw new NotAuthorizedException("No client"); throw new NotAuthorizedException("No client");
} }
if (!client.isEnabled()) if (!client.isEnabled()) {
{
return Response.ok("Requester not enabled").type("text/html").build(); return Response.ok("Requester not enabled").type("text/html").build();
} }
String username = formData.getFirst("username"); String username = formData.getFirst("username");
User user = realm.getIdm().getUser(username); User user = realm.getIdm().getUser(username);
if (user == null) if (user == null) {
{
logger.debug("user not found"); logger.debug("user not found");
return loginForm("Not valid user", redirect, clientId, scopeParam, state, realm, client); return loginForm("Not valid user", redirect, clientId, scopeParam, state, realm, client);
} }
if (!user.isEnabled()) if (!user.isEnabled()) {
{
return Response.ok("Your account is not enabled").type("text/html").build(); return Response.ok("Your account is not enabled").type("text/html").build();
} }
boolean authenticated = authManager.authenticateForm(realm, user, formData); boolean authenticated = authManager.authenticateForm(realm, user, formData);
if (!authenticated) return loginForm("Unable to authenticate, try again", redirect, clientId, scopeParam, state, realm, client); if (!authenticated)
return loginForm("Unable to authenticate, try again", redirect, clientId, scopeParam, state, realm, client);
SkeletonKeyToken token = null; SkeletonKeyToken token = null;
if (scopeParam != null) token = tokenManager.createScopedToken(scopeParam, realm, client, user); if (scopeParam != null) token = tokenManager.createScopedToken(scopeParam, realm, client, user);
else token = tokenManager.createLoginToken(realm, client, user); else token = tokenManager.createLoginToken(realm, client, user);
AccessCode code = new AccessCode(); AccessCodeEntry code = new AccessCodeEntry();
code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan()); code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
code.setToken(token); code.setToken(token);
code.setClient(client); code.setClient(client);
synchronized (accessCodeMap) synchronized (accessCodeMap) {
{
accessCodeMap.put(code.getId(), code); accessCodeMap.put(code.getId(), code);
} }
String accessCode = null; String accessCode = null;
try try {
{
accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realm.getPrivateKey()); accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realm.getPrivateKey());
} } catch (UnsupportedEncodingException e) {
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", accessCode); UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", accessCode);
@ -270,25 +185,16 @@ public class TokenService
return Response.status(302).location(redirectUri.build()).build(); return Response.status(302).location(redirectUri.build()).build();
} }
@Path("{realm}/access/codes") @Path("access/codes")
@POST @POST
@Produces("application/json") @Produces("application/json")
public Response accessRequest(@PathParam("realm") String realmId, public Response accessRequest(MultivaluedMap<String, String> formData) {
MultivaluedMap<String, String> formData) if (!realm.isEnabled()) {
{
RealmModel realm = adapter.getRealm(realmId);
if (realm == null)
{
throw new NotFoundException("Realm not found");
}
if (!realm.isEnabled())
{
throw new NotAuthorizedException("Realm not enabled"); throw new NotAuthorizedException("Realm not enabled");
} }
String code = formData.getFirst("code"); String code = formData.getFirst("code");
if (code == null) if (code == null) {
{
logger.debug("code not specified"); logger.debug("code not specified");
Map<String, String> error = new HashMap<String, String>(); Map<String, String> error = new HashMap<String, String>();
error.put("error", "invalid_request"); error.put("error", "invalid_request");
@ -297,8 +203,7 @@ public class TokenService
} }
String client_id = formData.getFirst("client_id"); String client_id = formData.getFirst("client_id");
if (client_id == null) if (client_id == null) {
{
logger.debug("client_id not specified"); logger.debug("client_id not specified");
Map<String, String> error = new HashMap<String, String>(); Map<String, String> error = new HashMap<String, String>();
error.put("error", "invalid_request"); error.put("error", "invalid_request");
@ -306,8 +211,7 @@ public class TokenService
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build(); return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
} }
User client = realm.getIdm().getUser(client_id); User client = realm.getIdm().getUser(client_id);
if (client == null) if (client == null) {
{
logger.debug("Could not find user"); logger.debug("Could not find user");
Map<String, String> error = new HashMap<String, String>(); Map<String, String> error = new HashMap<String, String>();
error.put("error", "invalid_client"); error.put("error", "invalid_client");
@ -315,8 +219,7 @@ public class TokenService
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build(); return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
} }
if (!client.isEnabled()) if (!client.isEnabled()) {
{
logger.debug("user is not enabled"); logger.debug("user is not enabled");
Map<String, String> error = new HashMap<String, String>(); Map<String, String> error = new HashMap<String, String>();
error.put("error", "invalid_client"); error.put("error", "invalid_client");
@ -325,61 +228,50 @@ public class TokenService
} }
boolean authenticated = authManager.authenticateForm(realm, client, formData); boolean authenticated = authManager.authenticateForm(realm, client, formData);
if (!authenticated) if (!authenticated) {
{
Map<String, String> error = new HashMap<String, String>(); Map<String, String> error = new HashMap<String, String>();
error.put("error", "unauthorized_client"); error.put("error", "unauthorized_client");
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build(); return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
} }
JWSInput input = new JWSInput(code, providers); JWSInput input = new JWSInput(code, providers);
boolean verifiedCode = false; boolean verifiedCode = false;
try try {
{
verifiedCode = RSAProvider.verify(input, realm.getPublicKey()); verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
} } catch (Exception ignored) {
catch (Exception ignored)
{
logger.debug("Failed to verify signature", ignored); logger.debug("Failed to verify signature", ignored);
} }
if (!verifiedCode) if (!verifiedCode) {
{
Map<String, String> res = new HashMap<String, String>(); Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant"); res.put("error", "invalid_grant");
res.put("error_description", "Unable to verify code signature"); res.put("error_description", "Unable to verify code signature");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build(); return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
} }
String key = input.readContent(String.class); String key = input.readContent(String.class);
AccessCode accessCode = null; AccessCodeEntry accessCode = null;
synchronized (accessCodeMap) synchronized (accessCodeMap) {
{
accessCode = accessCodeMap.remove(key); accessCode = accessCodeMap.remove(key);
} }
if (accessCode == null) if (accessCode == null) {
{
Map<String, String> res = new HashMap<String, String>(); Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant"); res.put("error", "invalid_grant");
res.put("error_description", "Code not found"); res.put("error_description", "Code not found");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build(); return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
} }
if (accessCode.isExpired()) if (accessCode.isExpired()) {
{
Map<String, String> res = new HashMap<String, String>(); Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant"); res.put("error", "invalid_grant");
res.put("error_description", "Code is expired"); res.put("error_description", "Code is expired");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build(); return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
} }
if (!accessCode.getToken().isActive()) if (!accessCode.getToken().isActive()) {
{
Map<String, String> res = new HashMap<String, String>(); Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant"); res.put("error", "invalid_grant");
res.put("error_description", "Token expired"); res.put("error_description", "Token expired");
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build(); return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
} }
if (!client.getId().equals(accessCode.getClient().getId())) if (!client.getId().equals(accessCode.getClient().getId())) {
{
Map<String, String> res = new HashMap<String, String>(); Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant"); res.put("error", "invalid_grant");
res.put("error_description", "Auth error"); res.put("error_description", "Auth error");
@ -390,15 +282,11 @@ public class TokenService
} }
protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) {
{
byte[] tokenBytes = null; byte[] tokenBytes = null;
try try {
{
tokenBytes = JsonSerialization.toByteArray(token, false); tokenBytes = JsonSerialization.toByteArray(token, false);
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
String encodedToken = new JWSBuilder() String encodedToken = new JWSBuilder()
@ -408,35 +296,25 @@ public class TokenService
return accessTokenResponse(token, encodedToken); return accessTokenResponse(token, encodedToken);
} }
protected AccessTokenResponse accessTokenResponse(SkeletonKeyToken token, String encodedToken) protected AccessTokenResponse accessTokenResponse(SkeletonKeyToken token, String encodedToken) {
{
AccessTokenResponse res = new AccessTokenResponse(); AccessTokenResponse res = new AccessTokenResponse();
res.setToken(encodedToken); res.setToken(encodedToken);
res.setTokenType("bearer"); res.setTokenType("bearer");
if (token.getExpiration() != 0) if (token.getExpiration() != 0) {
{
long time = token.getExpiration() - (System.currentTimeMillis() / 1000); long time = token.getExpiration() - (System.currentTimeMillis() / 1000);
res.setExpiresIn(time); res.setExpiresIn(time);
} }
return res; return res;
} }
@Path("{realm}/auth/request") @Path("auth/request")
@GET @GET
public Response requestAccessCode(@PathParam("realm") String realmId, public Response requestAccessCode(@QueryParam("response_type") String responseType,
@QueryParam("response_type") String responseType,
@QueryParam("redirect_uri") String redirect, @QueryParam("redirect_uri") String redirect,
@QueryParam("client_id") String clientId, @QueryParam("client_id") String clientId,
@QueryParam("scope") String scopeParam, @QueryParam("scope") String scopeParam,
@QueryParam("state") String state) @QueryParam("state") String state) {
{ if (!realm.isEnabled()) {
RealmModel realm = adapter.getRealm(realmId);
if (realm == null)
{
throw new NotFoundException("Realm not found");
}
if (!realm.isEnabled())
{
throw new NotAuthorizedException("Realm not enabled"); throw new NotAuthorizedException("Realm not enabled");
} }
User client = realm.getIdm().getUser(clientId); User client = realm.getIdm().getUser(clientId);
@ -446,20 +324,14 @@ public class TokenService
return loginForm(null, redirect, clientId, scopeParam, state, realm, client); return loginForm(null, redirect, clientId, scopeParam, state, realm, client);
} }
private Response loginForm(String validationError, String redirect, String clientId, String scopeParam, String state, RealmModel realm, User client) private Response loginForm(String validationError, String redirect, String clientId, String scopeParam, String state, RealmModel realm, User client) {
{
StringBuffer html = new StringBuffer(); StringBuffer html = new StringBuffer();
if (scopeParam != null) if (scopeParam != null) {
{
html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>"); html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>");
if (validationError != null) if (validationError != null) {
{ try {
try
{
Thread.sleep(1000); // put in a delay Thread.sleep(1000); // put in a delay
} } catch (InterruptedException e) {
catch (InterruptedException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
html.append("<p/><p><b>").append(validationError).append("</b></p>"); html.append("<p/><p><b>").append(validationError).append("</b></p>");
@ -469,53 +341,37 @@ public class TokenService
SkeletonKeyScope scope = tokenManager.decodeScope(scopeParam); SkeletonKeyScope scope = tokenManager.decodeScope(scopeParam);
Map<String, ResourceModel> resourceMap = realm.getResourceMap(); Map<String, ResourceModel> resourceMap = realm.getResourceMap();
for (String res : scope.keySet()) for (String res : scope.keySet()) {
{
ResourceModel resource = resourceMap.get(res); ResourceModel resource = resourceMap.get(res);
html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>"); html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
Set<String> scopeMapping = resource.getScope(client); Set<String> scopeMapping = resource.getScope(client);
for (String role : scope.get(res)) for (String role : scope.get(res)) {
{
html.append(" ").append(role); html.append(" ").append(role);
if (!scopeMapping.contains("*") && !scopeMapping.contains(role)) if (!scopeMapping.contains("*") && !scopeMapping.contains(role)) {
{
return Response.ok("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build(); return Response.ok("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build();
} }
} }
html.append("</td></tr>"); html.append("</td></tr>");
} }
html.append("</table><p>To Authorize, please login below</p>"); html.append("</table><p>To Authorize, please login below</p>");
} } else {
else
{
Set<String> scopeMapping = realm.getScope(client); Set<String> scopeMapping = realm.getScope(client);
if (scopeMapping.contains("*")) if (scopeMapping.contains("*")) {
{
html.append("<h1>Login For ").append(realm.getName()).append(" Realm</h1>"); html.append("<h1>Login For ").append(realm.getName()).append(" Realm</h1>");
if (validationError != null) if (validationError != null) {
{ try {
try
{
Thread.sleep(1000); // put in a delay Thread.sleep(1000); // put in a delay
} } catch (InterruptedException e) {
catch (InterruptedException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
html.append("<p/><p><b>").append(validationError).append("</b></p>"); html.append("<p/><p><b>").append(validationError).append("</b></p>");
} }
} } else {
else
{
html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>"); html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>");
if (validationError != null) if (validationError != null) {
{ try {
try
{
Thread.sleep(1000); // put in a delay Thread.sleep(1000); // put in a delay
} } catch (InterruptedException e) {
catch (InterruptedException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
html.append("<p/><p><b>").append(validationError).append("</b></p>"); html.append("<p/><p><b>").append(validationError).append("</b></p>");
@ -523,37 +379,30 @@ public class TokenService
SkeletonKeyScope scope = new SkeletonKeyScope(); SkeletonKeyScope scope = new SkeletonKeyScope();
List<ResourceModel> resources = realm.getResources(); List<ResourceModel> resources = realm.getResources();
boolean found = false; boolean found = false;
for (ResourceModel resource : resources) for (ResourceModel resource : resources) {
{
Set<String> resourceScope = resource.getScope(client); Set<String> resourceScope = resource.getScope(client);
if (resourceScope == null) continue; if (resourceScope == null) continue;
if (resourceScope.size() == 0) continue; if (resourceScope.size() == 0) continue;
if (!found) if (!found) {
{
found = true; found = true;
html.append("<p>A Third Party is requesting access to the following resources</p>"); html.append("<p>A Third Party is requesting access to the following resources</p>");
html.append("<table>"); html.append("<table>");
} }
html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>"); html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
// todo add description of role // todo add description of role
for (String role : resourceScope) for (String role : resourceScope) {
{
html.append(" ").append(role); html.append(" ").append(role);
scope.add(resource.getName(), role); scope.add(resource.getName(), role);
} }
} }
if (!found) if (!found) {
{
return Response.ok("<h1>Security Alert</h1><p>Known client not authorized to access this realm.</p>").type("text/html").build(); return Response.ok("<h1>Security Alert</h1><p>Known client not authorized to access this realm.</p>").type("text/html").build();
} }
html.append("</table>"); html.append("</table>");
try try {
{
String json = JsonSerialization.toString(scope, false); String json = JsonSerialization.toString(scope, false);
scopeParam = Base64Url.encode(json.getBytes("UTF-8")); scopeParam = Base64Url.encode(json.getBytes("UTF-8"));
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -565,22 +414,18 @@ public class TokenService
html.append("<form action=\"").append(action).append("\" method=\"POST\">"); html.append("<form action=\"").append(action).append("\" method=\"POST\">");
html.append("Username: <input type=\"text\" name=\"username\" size=\"20\"><br>"); html.append("Username: <input type=\"text\" name=\"username\" size=\"20\"><br>");
for (RequiredCredentialModel credential : realm.getRequiredCredentials()) for (RequiredCredentialModel credential : realm.getRequiredCredentials()) {
{
if (!credential.isInput()) continue; if (!credential.isInput()) continue;
html.append(credential.getType()).append(": "); html.append(credential.getType()).append(": ");
if (credential.isSecret()) if (credential.isSecret()) {
{
html.append("<input type=\"password\" name=\"").append(credential.getType()).append("\" size=\"20\"><br>"); html.append("<input type=\"password\" name=\"").append(credential.getType()).append("\" size=\"20\"><br>");
} else } else {
{
html.append("<input type=\"text\" name=\"").append(credential.getType()).append("\" size=\"20\"><br>"); html.append("<input type=\"text\" name=\"").append(credential.getType()).append("\" size=\"20\"><br>");
} }
} }
html.append("<input type=\"hidden\" name=\"client_id\" value=\"").append(clientId).append("\">"); html.append("<input type=\"hidden\" name=\"client_id\" value=\"").append(clientId).append("\">");
if (scopeParam != null) if (scopeParam != null) {
{
html.append("<input type=\"hidden\" name=\"scope\" value=\"").append(scopeParam).append("\">"); html.append("<input type=\"hidden\" name=\"scope\" value=\"").append(scopeParam).append("\">");
} }
if (state != null) html.append("<input type=\"hidden\" name=\"state\" value=\"").append(state).append("\">"); if (state != null) html.append("<input type=\"hidden\" name=\"state\" value=\"").append(state).append("\">");

View file

@ -7,27 +7,23 @@ import org.junit.FixMethodOrder;
import org.junit.Test; import org.junit.Test;
import org.junit.runners.MethodSorters; import org.junit.runners.MethodSorters;
import org.keycloak.representations.idm.RequiredCredentialRepresentation; import org.keycloak.representations.idm.RequiredCredentialRepresentation;
import org.keycloak.services.managers.InstallationManager;
import org.keycloak.services.models.RealmManager; import org.keycloak.services.models.RealmManager;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.relationships.RealmResourceRelationship;
import org.keycloak.services.models.RequiredCredentialModel; import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.relationships.RequiredCredentialRelationship;
import org.keycloak.services.models.relationships.ScopeRelationship;
import org.keycloak.services.models.UserCredentialModel; import org.keycloak.services.models.UserCredentialModel;
import org.keycloak.services.resources.KeycloakApplication;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.IdentitySessionFactory;
import org.picketlink.idm.IdentityManager; import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.config.IdentityConfigurationBuilder;
import org.picketlink.idm.credential.Credentials; import org.picketlink.idm.credential.Credentials;
import org.picketlink.idm.credential.Password; import org.picketlink.idm.credential.Password;
import org.picketlink.idm.credential.UsernamePasswordCredentials; import org.picketlink.idm.credential.UsernamePasswordCredentials;
import org.picketlink.idm.file.internal.FileUtils;
import org.picketlink.idm.internal.IdentityManagerFactory;
import org.picketlink.idm.model.Realm;
import org.picketlink.idm.model.Role; import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.SimpleRole; import org.picketlink.idm.model.SimpleRole;
import org.picketlink.idm.model.SimpleUser; import org.picketlink.idm.model.SimpleUser;
import org.picketlink.idm.model.User; import org.picketlink.idm.model.User;
import java.io.File;
import java.util.List; import java.util.List;
/** /**
@ -35,47 +31,34 @@ import java.util.List;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@FixMethodOrder(MethodSorters.NAME_ASCENDING) @FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class AdapterTest public class AdapterTest {
{ private IdentitySessionFactory factory;
private static IdentityManagerFactory factory; private IdentitySession IdentitySession;
public static final String WORKING_DIRECTORY = "/tmp/keycloak"; private RealmManager adapter;
public RealmManager adapter; private RealmModel realmModel;
public RealmModel realmModel;
@Before @Before
public void before() throws Exception public void before() throws Exception {
{ factory = KeycloakApplication.createFactory();
after(); IdentitySession = factory.createIdentitySession();
factory = createFactory(); adapter = new RealmManager(IdentitySession);
adapter = new RealmManager(factory);
}
private static IdentityManagerFactory createFactory() {
IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
builder
.stores()
.file()
.addRealm(Realm.DEFAULT_REALM)
.workingDirectory(WORKING_DIRECTORY)
.preserveState(true)
.supportAllFeatures()
.supportRelationshipType(RealmResourceRelationship.class, RequiredCredentialRelationship.class, ScopeRelationship.class);
return new IdentityManagerFactory(builder.build());
} }
@After @After
public void after() throws Exception public void after() throws Exception {
{ IdentitySession.close();
File file = new File(WORKING_DIRECTORY); factory.close();
FileUtils.delete(file);
Thread.sleep(10); // my windows machine seems to have delays on deleting files sometimes
} }
@Test @Test
public void test1CreateRealm() throws Exception public void installTest() throws Exception {
{ new InstallationManager().install(adapter);
realmModel = adapter.create("JUGGLER");
}
@Test
public void test1CreateRealm() throws Exception {
realmModel = adapter.createRealm("JUGGLER");
realmModel.setAccessCodeLifespan(100); realmModel.setAccessCodeLifespan(100);
realmModel.setCookieLoginAllowed(true); realmModel.setCookieLoginAllowed(true);
realmModel.setEnabled(true); realmModel.setEnabled(true);
@ -97,8 +80,7 @@ public class AdapterTest
} }
@Test @Test
public void test2RequiredCredential() throws Exception public void test2RequiredCredential() throws Exception {
{
test1CreateRealm(); test1CreateRealm();
RequiredCredentialModel creds = new RequiredCredentialModel(); RequiredCredentialModel creds = new RequiredCredentialModel();
creds.setSecret(true); creds.setSecret(true);
@ -114,8 +96,7 @@ public class AdapterTest
Assert.assertEquals(2, storedCreds.size()); Assert.assertEquals(2, storedCreds.size());
boolean totp = false; boolean totp = false;
boolean password = false; boolean password = false;
for (RequiredCredentialModel cred : storedCreds) for (RequiredCredentialModel cred : storedCreds) {
{
if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD)) password = true; if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD)) password = true;
else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP)) totp = true; else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP)) totp = true;
} }
@ -124,8 +105,7 @@ public class AdapterTest
} }
@Test @Test
public void testCredentialValidation() throws Exception public void testCredentialValidation() throws Exception {
{
test1CreateRealm(); test1CreateRealm();
User user = new SimpleUser("bburke"); User user = new SimpleUser("bburke");
realmModel.getIdm().add(user); realmModel.getIdm().add(user);
@ -140,8 +120,7 @@ public class AdapterTest
} }
@Test @Test
public void testRoles() throws Exception public void testRoles() throws Exception {
{
test1CreateRealm(); test1CreateRealm();
IdentityManager idm = realmModel.getIdm(); IdentityManager idm = realmModel.getIdm();
idm.add(new SimpleRole("admin")); idm.add(new SimpleRole("admin"));

View file

@ -0,0 +1,31 @@
package org.keycloak.test;
import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.test.BaseResourceTest;
import org.keycloak.representations.idm.RealmRepresentation;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakTestBase extends BaseResourceTest
{
public static RealmRepresentation loadJson(String path) throws IOException
{
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
ByteArrayOutputStream os = new ByteArrayOutputStream();
int c;
while ( (c = is.read()) != -1)
{
os.write(c);
}
byte[] bytes = os.toByteArray();
System.out.println(new String(bytes));
return JsonSerialization.fromBytes(RealmRepresentation.class, bytes);
}
}

View file

@ -0,0 +1,94 @@
package org.keycloak.test;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.jboss.resteasy.test.EmbeddedContainer;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.SkeletonKeyContextResolver;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RequiredCredentialRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.InstallationManager;
import org.keycloak.services.models.RealmManager;
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;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import static org.jboss.resteasy.test.TestPortProvider.generateURL;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class RealmCreationTest {
private static ResteasyDeployment deployment;
private static Client client;
@BeforeClass
public static void before() throws Exception {
deployment = new ResteasyDeployment();
deployment.setApplicationClass(KeycloakApplication.class.getName());
EmbeddedContainer.start(deployment);
KeycloakApplication application = (KeycloakApplication) deployment.getApplication();
IdentitySession IdentitySession = application.getFactory().createIdentitySession();
RealmManager manager = new RealmManager(IdentitySession);
new InstallationManager().install(manager);
client = new ResteasyClientBuilder().build();
client.register(SkeletonKeyContextResolver.class);
}
public static void after() throws Exception {
client.close();
EmbeddedContainer.stop();
}
@Test
public void testRegisterLoginAndCreate() throws Exception {
UserRepresentation user = new UserRepresentation();
user.setUsername("bburke");
user.credential(RequiredCredentialRepresentation.PASSWORD, "geheim", false);
WebTarget target = client.target(generateURL("/"));
Response response = target.path("registrations").request().post(Entity.json(user));
Assert.assertEquals(201, response.getStatus());
response.close();
AccessTokenResponse tokenResponse = null;
try {
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);
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);
Assert.assertNotNull(tokenResponse);
System.out.println(tokenResponse.getToken());
//
RealmRepresentation realm = KeycloakTestBase.loadJson("testrealm.json");
response = target.path("realms").request().header(HttpHeaders.AUTHORIZATION, "Bearer " + tokenResponse.getToken()).post(Entity.json(realm));
Assert.assertEquals(201, response.getStatus());
response.close();
}
}

View file

@ -2,7 +2,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0"> version="1.0">
<persistence-unit name="identitydb" transaction-type="RESOURCE_LOCAL"> <persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider> <provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>org.picketlink.idm.jpa.schema.IdentityObject</class> <class>org.picketlink.idm.jpa.schema.IdentityObject</class>