commit
c3681df76c
9 changed files with 75 additions and 67 deletions
4
pom.xml
4
pom.xml
|
@ -2,14 +2,14 @@
|
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<name>Identity Guardener</name>
|
||||
<name>Keycloak</name>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<version>1.0-alpha-1</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<resteasy.version>3.0.1.Final</resteasy.version>
|
||||
<resteasy.version>3.0.2.Final</resteasy.version>
|
||||
</properties>
|
||||
|
||||
<url>http://keycloak.org</url>
|
||||
|
|
|
@ -21,6 +21,8 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Stateless object that manages authentication
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
|
|
|
@ -13,17 +13,51 @@ import org.picketlink.idm.model.User;
|
|||
import javax.ws.rs.ForbiddenException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class TokenManager {
|
||||
|
||||
public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user) {
|
||||
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) {
|
||||
SkeletonKeyToken token = new SkeletonKeyToken();
|
||||
token.id(RealmManager.generateId());
|
||||
token.principal(user.getLoginName());
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
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.IdentitySession;
|
||||
import org.picketlink.idm.model.Realm;
|
||||
import org.picketlink.idm.model.Role;
|
||||
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;
|
||||
|
@ -26,10 +21,10 @@ public class RealmManager {
|
|||
return counter.getAndIncrement() + "-" + System.currentTimeMillis();
|
||||
}
|
||||
|
||||
protected IdentitySession IdentitySession;
|
||||
protected IdentitySession identitySession;
|
||||
|
||||
public RealmManager(IdentitySession IdentitySession) {
|
||||
this.IdentitySession = IdentitySession;
|
||||
this.identitySession = IdentitySession;
|
||||
}
|
||||
|
||||
public RealmModel defaultRealm() {
|
||||
|
@ -37,11 +32,11 @@ public class RealmManager {
|
|||
}
|
||||
|
||||
public RealmModel getRealm(String id) {
|
||||
Realm existing = IdentitySession.findRealm(id);
|
||||
Realm existing = identitySession.findRealm(id);
|
||||
if (existing == null) {
|
||||
return null;
|
||||
}
|
||||
return new RealmModel(existing, IdentitySession);
|
||||
return new RealmModel(existing, identitySession);
|
||||
}
|
||||
|
||||
public RealmModel createRealm(String name) {
|
||||
|
@ -49,11 +44,11 @@ public class RealmManager {
|
|||
}
|
||||
|
||||
public RealmModel createRealm(String id, String name) {
|
||||
Realm newRealm = IdentitySession.createRealm(id);
|
||||
IdentityManager idm = IdentitySession.createIdentityManager(newRealm);
|
||||
Realm newRealm = identitySession.createRealm(id);
|
||||
IdentityManager idm = identitySession.createIdentityManager(newRealm);
|
||||
SimpleAgent agent = new SimpleAgent(RealmModel.REALM_AGENT_ID);
|
||||
idm.add(agent);
|
||||
RealmModel realm = new RealmModel(newRealm, IdentitySession);
|
||||
RealmModel realm = new RealmModel(newRealm, identitySession);
|
||||
return realm;
|
||||
}
|
||||
|
||||
|
@ -68,4 +63,4 @@ public class RealmManager {
|
|||
realm.setPublicKey(keyPair.getPublic());
|
||||
realm.updateRealm();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import org.keycloak.services.models.relationships.ScopeRelationship;
|
|||
import org.picketlink.idm.IdentitySession;
|
||||
import org.picketlink.idm.IdentityManager;
|
||||
import org.picketlink.idm.model.Agent;
|
||||
import org.picketlink.idm.model.Attribute;
|
||||
import org.picketlink.idm.model.Grant;
|
||||
import org.picketlink.idm.model.Role;
|
||||
import org.picketlink.idm.model.Tier;
|
||||
|
@ -22,24 +21,20 @@ import java.util.Set;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
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 ResourceRelationship agent;
|
||||
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.agent = agent;
|
||||
this.realm = realm;
|
||||
this.IdentitySession = factory;
|
||||
this.identitySession = session;
|
||||
}
|
||||
|
||||
public IdentityManager getIdm() {
|
||||
return IdentitySession.createIdentityManager(tier);
|
||||
return identitySession.createIdentityManager(tier);
|
||||
}
|
||||
|
||||
public void updateResource() {
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.keycloak.services.resources;
|
|||
|
||||
import org.keycloak.SkeletonKeyContextResolver;
|
||||
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.ResourceRelationship;
|
||||
import org.keycloak.services.models.relationships.RequiredCredentialRelationship;
|
||||
|
@ -38,7 +39,7 @@ public class KeycloakApplication extends Application {
|
|||
public KeycloakApplication() {
|
||||
this.factory = createFactory();
|
||||
IdentitySessionFilter filter = new IdentitySessionFilter(factory);
|
||||
singletons.add(new RealmsResource());
|
||||
singletons.add(new RealmsResource(new TokenManager()));
|
||||
singletons.add(filter);
|
||||
classes.add(SkeletonKeyContextResolver.class);
|
||||
classes.add(RegistrationService.class);
|
||||
|
|
|
@ -24,7 +24,7 @@ public class RealmSubResource {
|
|||
protected UriInfo uriInfo;
|
||||
|
||||
@Context
|
||||
protected IdentitySession IdentitySession;
|
||||
protected IdentitySession identitySession;
|
||||
|
||||
protected RealmModel realm;
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ 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.managers.TokenManager;
|
||||
import org.keycloak.services.models.RealmManager;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.models.RequiredCredentialModel;
|
||||
|
@ -38,7 +38,6 @@ 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>
|
||||
|
@ -55,23 +54,26 @@ public class RealmsResource {
|
|||
protected HttpHeaders headers;
|
||||
|
||||
@Context
|
||||
protected
|
||||
IdentitySession IdentitySession;
|
||||
protected IdentitySession identitySession;
|
||||
|
||||
@Context
|
||||
ResourceContext resourceContext;
|
||||
|
||||
protected Map<String, AccessCodeEntry> accessCodes = new ConcurrentHashMap<String, AccessCodeEntry>();
|
||||
protected TokenManager tokenManager;
|
||||
|
||||
public RealmsResource(TokenManager tokenManager) {
|
||||
this.tokenManager = tokenManager;
|
||||
}
|
||||
|
||||
@Path("{realm}/tokens")
|
||||
public TokenService getTokenService(@PathParam("realm") String id) {
|
||||
RealmManager realmManager = new RealmManager(IdentitySession);
|
||||
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);
|
||||
TokenService tokenService = new TokenService(realm, tokenManager);
|
||||
resourceContext.initResource(tokenService);
|
||||
return tokenService;
|
||||
|
||||
|
@ -80,7 +82,7 @@ public class RealmsResource {
|
|||
|
||||
@Path("{realm}")
|
||||
public RealmSubResource getRealmResource(@PathParam("realm") String id) {
|
||||
RealmManager realmManager = new RealmManager(IdentitySession);
|
||||
RealmManager realmManager = new RealmManager(identitySession);
|
||||
RealmModel realm = realmManager.getRealm(id);
|
||||
if (realm == null) {
|
||||
logger.debug("realm not found");
|
||||
|
@ -96,13 +98,13 @@ public class RealmsResource {
|
|||
@POST
|
||||
@Consumes("application/json")
|
||||
public Response importRealm(RealmRepresentation rep) {
|
||||
IdentitySession.getTransaction().begin();
|
||||
identitySession.getTransaction().begin();
|
||||
RealmModel realm;
|
||||
try {
|
||||
realm = createRealm(rep);
|
||||
IdentitySession.getTransaction().commit();
|
||||
identitySession.getTransaction().commit();
|
||||
} catch (RuntimeException re) {
|
||||
IdentitySession.getTransaction().rollback();
|
||||
identitySession.getTransaction().rollback();
|
||||
throw re;
|
||||
}
|
||||
UriBuilder builder = uriInfo.getRequestUriBuilder().path(realm.getId());
|
||||
|
@ -112,7 +114,7 @@ public class RealmsResource {
|
|||
}
|
||||
|
||||
protected RealmModel createRealm(RealmRepresentation rep) {
|
||||
RealmManager realmManager = new RealmManager(IdentitySession);
|
||||
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);
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.keycloak.representations.SkeletonKeyToken;
|
|||
import org.keycloak.services.managers.AccessCodeEntry;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.models.RealmManager;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.models.RequiredCredentialModel;
|
||||
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.UriInfo;
|
||||
import javax.ws.rs.ext.Providers;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -50,7 +48,7 @@ public class TokenService {
|
|||
|
||||
|
||||
protected static final Logger logger = Logger.getLogger(TokenService.class);
|
||||
protected Map<String, AccessCodeEntry> accessCodeMap;
|
||||
//protected Map<String, AccessCodeEntry> accessCodeMap;
|
||||
|
||||
@Context
|
||||
protected UriInfo uriInfo;
|
||||
|
@ -65,12 +63,12 @@ public class TokenService {
|
|||
IdentitySession IdentitySession;
|
||||
|
||||
protected RealmModel realm;
|
||||
protected TokenManager tokenManager = new TokenManager();
|
||||
protected TokenManager tokenManager;
|
||||
protected AuthenticationManager authManager = new AuthenticationManager();
|
||||
|
||||
public TokenService(RealmModel realm, Map<String, AccessCodeEntry> accessCodeMap) {
|
||||
public TokenService(RealmModel realm, TokenManager tokenManager) {
|
||||
this.realm = realm;
|
||||
this.accessCodeMap = accessCodeMap;
|
||||
this.tokenManager = tokenManager;
|
||||
}
|
||||
|
||||
@Path("grants/identity-token")
|
||||
|
@ -163,23 +161,7 @@ public class TokenService {
|
|||
if (!authenticated)
|
||||
return loginForm("Unable to authenticate, try again", redirect, clientId, scopeParam, state, realm, client);
|
||||
|
||||
SkeletonKeyToken token = null;
|
||||
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);
|
||||
}
|
||||
String accessCode = tokenManager.createAccessCode(scopeParam, realm, client, user);
|
||||
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", accessCode);
|
||||
if (state != null) redirectUri.queryParam("state", state);
|
||||
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();
|
||||
}
|
||||
String key = input.readContent(String.class);
|
||||
AccessCodeEntry accessCode = null;
|
||||
synchronized (accessCodeMap) {
|
||||
accessCode = accessCodeMap.remove(key);
|
||||
}
|
||||
AccessCodeEntry accessCode = tokenManager.pullAccessCode(key);
|
||||
if (accessCode == null) {
|
||||
Map<String, String> res = new HashMap<String, String>();
|
||||
res.put("error", "invalid_grant");
|
||||
|
|
Loading…
Reference in a new issue