refactoring

This commit is contained in:
Bill Burke 2013-07-18 10:14:52 -04:00
parent 5ce263c2b5
commit f7b3f2998d
9 changed files with 75 additions and 67 deletions

View file

@ -2,14 +2,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<name>Identity Guardener</name> <name>Keycloak</name>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-parent</artifactId> <artifactId>keycloak-parent</artifactId>
<version>1.0-alpha-1</version> <version>1.0-alpha-1</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<properties> <properties>
<resteasy.version>3.0.1.Final</resteasy.version> <resteasy.version>3.0.2.Final</resteasy.version>
</properties> </properties>
<url>http://keycloak.org</url> <url>http://keycloak.org</url>

View file

@ -21,6 +21,8 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
/** /**
* Stateless object that manages authentication
*
* @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 $
*/ */

View file

@ -13,16 +13,50 @@ import org.picketlink.idm.model.User;
import javax.ws.rs.ForbiddenException; import javax.ws.rs.ForbiddenException;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
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.concurrent.ConcurrentHashMap;
/** /**
* Stateful object that creates tokens and manages oauth access codes
*
* @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 Map<String, AccessCodeEntry> accessCodeMap = new ConcurrentHashMap<String, AccessCodeEntry>();
public void clearAccessCodes() {
accessCodeMap.clear();
}
public AccessCodeEntry pullAccessCode(String key) {
return accessCodeMap.remove(key);
}
public String createAccessCode(String scopeParam, RealmModel realm, User client, User user)
{
SkeletonKeyToken token = null;
if (scopeParam != null) token = createScopedToken(scopeParam, realm, client, user);
else token = createLoginToken(realm, client, user);
AccessCodeEntry code = new AccessCodeEntry();
code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
code.setToken(token);
code.setClient(client);
accessCodeMap.put(code.getId(), code);
String accessCode = null;
try {
accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realm.getPrivateKey());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return accessCode;
}
public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user) { public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user) {
SkeletonKeyToken token = new SkeletonKeyToken(); SkeletonKeyToken token = new SkeletonKeyToken();
token.id(RealmManager.generateId()); token.id(RealmManager.generateId());

View file

@ -1,15 +1,10 @@
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.IdentitySession;
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.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -26,10 +21,10 @@ public class RealmManager {
return counter.getAndIncrement() + "-" + System.currentTimeMillis(); return counter.getAndIncrement() + "-" + System.currentTimeMillis();
} }
protected IdentitySession IdentitySession; protected IdentitySession identitySession;
public RealmManager(IdentitySession IdentitySession) { public RealmManager(IdentitySession IdentitySession) {
this.IdentitySession = IdentitySession; this.identitySession = IdentitySession;
} }
public RealmModel defaultRealm() { public RealmModel defaultRealm() {
@ -37,11 +32,11 @@ public class RealmManager {
} }
public RealmModel getRealm(String id) { public RealmModel getRealm(String id) {
Realm existing = IdentitySession.findRealm(id); Realm existing = identitySession.findRealm(id);
if (existing == null) { if (existing == null) {
return null; return null;
} }
return new RealmModel(existing, IdentitySession); return new RealmModel(existing, identitySession);
} }
public RealmModel createRealm(String name) { public RealmModel createRealm(String name) {
@ -49,11 +44,11 @@ public class RealmManager {
} }
public RealmModel createRealm(String id, String name) { public RealmModel createRealm(String id, String name) {
Realm newRealm = IdentitySession.createRealm(id); Realm newRealm = identitySession.createRealm(id);
IdentityManager idm = IdentitySession.createIdentityManager(newRealm); 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);
RealmModel realm = new RealmModel(newRealm, IdentitySession); RealmModel realm = new RealmModel(newRealm, identitySession);
return realm; return realm;
} }
@ -68,4 +63,4 @@ public class RealmManager {
realm.setPublicKey(keyPair.getPublic()); realm.setPublicKey(keyPair.getPublic());
realm.updateRealm(); realm.updateRealm();
} }
} }

View file

@ -5,7 +5,6 @@ import org.keycloak.services.models.relationships.ScopeRelationship;
import org.picketlink.idm.IdentitySession; import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.IdentityManager; import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.model.Agent; import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Grant; import org.picketlink.idm.model.Grant;
import org.picketlink.idm.model.Role; import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.Tier; import org.picketlink.idm.model.Tier;
@ -22,24 +21,20 @@ import java.util.Set;
* @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_NAME = "name";
public static final String RESOURCE_SURROGATE_AUTH = "surrogate_auth";
protected Tier tier; protected Tier tier;
protected ResourceRelationship agent; protected ResourceRelationship agent;
protected RealmModel realm; protected RealmModel realm;
protected IdentitySession IdentitySession; protected IdentitySession identitySession;
public ResourceModel(Tier tier, ResourceRelationship agent, RealmModel realm, IdentitySession factory) { public ResourceModel(Tier tier, ResourceRelationship agent, RealmModel realm, IdentitySession session) {
this.tier = tier; this.tier = tier;
this.agent = agent; this.agent = agent;
this.realm = realm; this.realm = realm;
this.IdentitySession = factory; this.identitySession = session;
} }
public IdentityManager getIdm() { public IdentityManager getIdm() {
return IdentitySession.createIdentityManager(tier); return identitySession.createIdentityManager(tier);
} }
public void updateResource() { public void updateResource() {

View file

@ -2,6 +2,7 @@ package org.keycloak.services.resources;
import org.keycloak.SkeletonKeyContextResolver; import org.keycloak.SkeletonKeyContextResolver;
import org.keycloak.services.filters.IdentitySessionFilter; import org.keycloak.services.filters.IdentitySessionFilter;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.models.relationships.RealmAdminRelationship; import org.keycloak.services.models.relationships.RealmAdminRelationship;
import org.keycloak.services.models.relationships.ResourceRelationship; import org.keycloak.services.models.relationships.ResourceRelationship;
import org.keycloak.services.models.relationships.RequiredCredentialRelationship; import org.keycloak.services.models.relationships.RequiredCredentialRelationship;
@ -38,7 +39,7 @@ public class KeycloakApplication extends Application {
public KeycloakApplication() { public KeycloakApplication() {
this.factory = createFactory(); this.factory = createFactory();
IdentitySessionFilter filter = new IdentitySessionFilter(factory); IdentitySessionFilter filter = new IdentitySessionFilter(factory);
singletons.add(new RealmsResource()); singletons.add(new RealmsResource(new TokenManager()));
singletons.add(filter); singletons.add(filter);
classes.add(SkeletonKeyContextResolver.class); classes.add(SkeletonKeyContextResolver.class);
classes.add(RegistrationService.class); classes.add(RegistrationService.class);

View file

@ -24,7 +24,7 @@ public class RealmSubResource {
protected UriInfo uriInfo; protected UriInfo uriInfo;
@Context @Context
protected IdentitySession IdentitySession; protected IdentitySession identitySession;
protected RealmModel realm; protected RealmModel realm;

View file

@ -7,8 +7,8 @@ import org.keycloak.representations.idm.ResourceRepresentation;
import org.keycloak.representations.idm.RoleMappingRepresentation; import org.keycloak.representations.idm.RoleMappingRepresentation;
import org.keycloak.representations.idm.ScopeMappingRepresentation; import org.keycloak.representations.idm.ScopeMappingRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
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.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;
@ -38,7 +38,6 @@ import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -55,23 +54,26 @@ public class RealmsResource {
protected HttpHeaders headers; protected HttpHeaders headers;
@Context @Context
protected protected IdentitySession identitySession;
IdentitySession IdentitySession;
@Context @Context
ResourceContext resourceContext; ResourceContext resourceContext;
protected Map<String, AccessCodeEntry> accessCodes = new ConcurrentHashMap<String, AccessCodeEntry>(); protected TokenManager tokenManager;
public RealmsResource(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
@Path("{realm}/tokens") @Path("{realm}/tokens")
public TokenService getTokenService(@PathParam("realm") String id) { public TokenService getTokenService(@PathParam("realm") String id) {
RealmManager realmManager = new RealmManager(IdentitySession); RealmManager realmManager = new RealmManager(identitySession);
RealmModel realm = realmManager.getRealm(id); RealmModel realm = realmManager.getRealm(id);
if (realm == null) { if (realm == null) {
logger.debug("realm not found"); logger.debug("realm not found");
throw new NotFoundException(); throw new NotFoundException();
} }
TokenService tokenService = new TokenService(realm, accessCodes); TokenService tokenService = new TokenService(realm, tokenManager);
resourceContext.initResource(tokenService); resourceContext.initResource(tokenService);
return tokenService; return tokenService;
@ -80,7 +82,7 @@ public class RealmsResource {
@Path("{realm}") @Path("{realm}")
public RealmSubResource getRealmResource(@PathParam("realm") String id) { public RealmSubResource getRealmResource(@PathParam("realm") String id) {
RealmManager realmManager = new RealmManager(IdentitySession); RealmManager realmManager = new RealmManager(identitySession);
RealmModel realm = realmManager.getRealm(id); RealmModel realm = realmManager.getRealm(id);
if (realm == null) { if (realm == null) {
logger.debug("realm not found"); logger.debug("realm not found");
@ -96,13 +98,13 @@ public class RealmsResource {
@POST @POST
@Consumes("application/json") @Consumes("application/json")
public Response importRealm(RealmRepresentation rep) { public Response importRealm(RealmRepresentation rep) {
IdentitySession.getTransaction().begin(); identitySession.getTransaction().begin();
RealmModel realm; RealmModel realm;
try { try {
realm = createRealm(rep); realm = createRealm(rep);
IdentitySession.getTransaction().commit(); identitySession.getTransaction().commit();
} catch (RuntimeException re) { } catch (RuntimeException re) {
IdentitySession.getTransaction().rollback(); identitySession.getTransaction().rollback();
throw re; throw re;
} }
UriBuilder builder = uriInfo.getRequestUriBuilder().path(realm.getId()); UriBuilder builder = uriInfo.getRequestUriBuilder().path(realm.getId());
@ -112,7 +114,7 @@ public class RealmsResource {
} }
protected RealmModel createRealm(RealmRepresentation rep) { protected RealmModel createRealm(RealmRepresentation rep) {
RealmManager realmManager = new RealmManager(IdentitySession); RealmManager realmManager = new RealmManager(identitySession);
RealmModel defaultRealm = realmManager.getRealm(Realm.DEFAULT_REALM); RealmModel defaultRealm = realmManager.getRealm(Realm.DEFAULT_REALM);
User realmCreator = new AuthenticationManager().authenticateToken(defaultRealm, headers); User realmCreator = new AuthenticationManager().authenticateToken(defaultRealm, headers);
Role creatorRole = defaultRealm.getIdm().getRole(RegistrationService.REALM_CREATOR_ROLE); Role creatorRole = defaultRealm.getIdm().getRole(RegistrationService.REALM_CREATOR_ROLE);

View file

@ -12,7 +12,6 @@ import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.services.managers.AccessCodeEntry; 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.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;
@ -35,7 +34,6 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers; import javax.ws.rs.ext.Providers;
import java.io.UnsupportedEncodingException;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -50,7 +48,7 @@ public class TokenService {
protected static final Logger logger = Logger.getLogger(TokenService.class); protected static final Logger logger = Logger.getLogger(TokenService.class);
protected Map<String, AccessCodeEntry> accessCodeMap; //protected Map<String, AccessCodeEntry> accessCodeMap;
@Context @Context
protected UriInfo uriInfo; protected UriInfo uriInfo;
@ -65,12 +63,12 @@ public class TokenService {
IdentitySession IdentitySession; IdentitySession IdentitySession;
protected RealmModel realm; protected RealmModel realm;
protected TokenManager tokenManager = new TokenManager(); protected TokenManager tokenManager;
protected AuthenticationManager authManager = new AuthenticationManager(); protected AuthenticationManager authManager = new AuthenticationManager();
public TokenService(RealmModel realm, Map<String, AccessCodeEntry> accessCodeMap) { public TokenService(RealmModel realm, TokenManager tokenManager) {
this.realm = realm; this.realm = realm;
this.accessCodeMap = accessCodeMap; this.tokenManager = tokenManager;
} }
@Path("grants/identity-token") @Path("grants/identity-token")
@ -163,23 +161,7 @@ public class TokenService {
if (!authenticated) if (!authenticated)
return loginForm("Unable to authenticate, try again", redirect, clientId, scopeParam, state, realm, client); return loginForm("Unable to authenticate, try again", redirect, clientId, scopeParam, state, realm, client);
SkeletonKeyToken token = null; String accessCode = tokenManager.createAccessCode(scopeParam, realm, client, user);
if (scopeParam != null) token = tokenManager.createScopedToken(scopeParam, realm, client, user);
else token = tokenManager.createLoginToken(realm, client, user);
AccessCodeEntry code = new AccessCodeEntry();
code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
code.setToken(token);
code.setClient(client);
synchronized (accessCodeMap) {
accessCodeMap.put(code.getId(), code);
}
String accessCode = null;
try {
accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realm.getPrivateKey());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", accessCode); UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", accessCode);
if (state != null) redirectUri.queryParam("state", state); if (state != null) redirectUri.queryParam("state", state);
return Response.status(302).location(redirectUri.build()).build(); return Response.status(302).location(redirectUri.build()).build();
@ -249,10 +231,7 @@ public class TokenService {
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);
AccessCodeEntry accessCode = null; AccessCodeEntry accessCode = tokenManager.pullAccessCode(key);
synchronized (accessCodeMap) {
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");