resource rest api

This commit is contained in:
Bill Burke 2013-08-04 12:57:12 -04:00
parent 4e61981b69
commit d11876f58e
14 changed files with 146 additions and 16 deletions

View file

@ -11,6 +11,7 @@ import java.util.Set;
*/ */
public class ResourceRepresentation { public class ResourceRepresentation {
protected String self; // link protected String self; // link
protected String id;
protected String name; protected String name;
protected String adminUrl; protected String adminUrl;
protected boolean surrogateAuthRequired; protected boolean surrogateAuthRequired;
@ -29,6 +30,14 @@ public class ResourceRepresentation {
this.self = self; this.self = self;
} }
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() { public String getName() {
return name; return name;
} }

View file

@ -72,6 +72,7 @@
"resources" : [ "resources" : [
{ {
"name" : "customer-portal", "name" : "customer-portal",
"enabled" : true,
"adminUrl" : "http://localhost:8080/customer-portal/j_admin_request", "adminUrl" : "http://localhost:8080/customer-portal/j_admin_request",
"useRealmMappings" : true, "useRealmMappings" : true,
"credentials" : [ "credentials" : [
@ -81,6 +82,7 @@
}, },
{ {
"name" : "product-portal", "name" : "product-portal",
"enabled" : true,
"adminUrl" : "http://localhost:8080/product-portal/j_admin_request", "adminUrl" : "http://localhost:8080/product-portal/j_admin_request",
"useRealmMappings" : true, "useRealmMappings" : true,
"credentials" : [ "credentials" : [

View file

@ -67,7 +67,7 @@
</section> </section>
<section class="info-area"> <section class="info-area">
<h3>Info area</h3> <h3>Info area</h3>
<p>Does not have an account? <a href="<%=application.getContextPath()%>/saas/saas-register.html">Register</a>.</p> <p>Does not have an account? <a href="<%=application.getContextPath()%>/saas/saas-register.jsp">Register</a>.</p>
<ul> <ul>
<li><strong>Domain:</strong> 10.0.0.1</li> <li><strong>Domain:</strong> 10.0.0.1</li>
<li><strong>Zone:</strong> Live</li> <li><strong>Zone:</strong> Live</li>

View file

@ -27,6 +27,7 @@ public class ResourceManager {
public ResourceModel createResource(RealmModel realm, RoleModel loginRole, ResourceRepresentation resourceRep) { public ResourceModel createResource(RealmModel realm, RoleModel loginRole, ResourceRepresentation resourceRep) {
ResourceModel resource = realm.addResource(resourceRep.getName()); ResourceModel resource = realm.addResource(resourceRep.getName());
resource.setEnabled(resourceRep.isEnabled());
resource.setManagementUrl(resourceRep.getAdminUrl()); resource.setManagementUrl(resourceRep.getAdminUrl());
resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired()); resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
resource.updateResource(); resource.updateResource();
@ -82,16 +83,22 @@ public class ResourceManager {
return createResource(realm, loginRole, resourceRep); return createResource(realm, loginRole, resourceRep);
} }
public ResourceRepresentation getResource(ResourceModel resourceModel, boolean bulk) { public void updateResource(ResourceRepresentation rep, ResourceModel resource) {
resource.setName(rep.getName());
resource.setEnabled(rep.isEnabled());
resource.setManagementUrl(rep.getAdminUrl());
resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
resource.updateResource();
}
public ResourceRepresentation toRepresentation(ResourceModel resourceModel) {
ResourceRepresentation rep = new ResourceRepresentation(); ResourceRepresentation rep = new ResourceRepresentation();
rep.setId(resourceModel.getId());
rep.setName(resourceModel.getName()); rep.setName(resourceModel.getName());
rep.setEnabled(resourceModel.isEnabled()); rep.setEnabled(resourceModel.isEnabled());
rep.setAdminUrl(resourceModel.getManagementUrl()); rep.setAdminUrl(resourceModel.getManagementUrl());
rep.setSurrogateAuthRequired(resourceModel.isSurrogateAuthRequired()); rep.setSurrogateAuthRequired(resourceModel.isSurrogateAuthRequired());
List<RoleModel> roles = resourceModel.getRoles();
for (RoleModel role : roles) {
rep.role(realmManager.toRepresentation(role));
}
return rep; return rep;
} }

View file

@ -9,14 +9,10 @@ import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.ResourceModel; import org.keycloak.services.models.ResourceModel;
import org.keycloak.services.models.RoleModel; import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel; import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.RealmsResource;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.UriInfo;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -135,7 +131,7 @@ public class TokenManager {
} }
if (accessCodeEntry.getResourceRolesRequested().size() > 0) { if (accessCodeEntry.getResourceRolesRequested().size() > 0) {
Map<String, ResourceModel> resourceMap = realm.getResourceMap(); Map<String, ResourceModel> resourceMap = realm.getResourceNameMap();
for (String resourceName : accessCodeEntry.getResourceRolesRequested().keySet()) { for (String resourceName : accessCodeEntry.getResourceRolesRequested().keySet()) {
ResourceModel resource = resourceMap.get(resourceName); ResourceModel resource = resourceMap.get(resourceName);
SkeletonKeyToken.Access access = token.addAccess(resourceName).verifyCaller(resource.isSurrogateAuthRequired()); SkeletonKeyToken.Access access = token.addAccess(resourceName).verifyCaller(resource.isSurrogateAuthRequired());

View file

@ -79,7 +79,7 @@ public interface RealmModel {
List<RoleModel> getRoles(); List<RoleModel> getRoles();
Map<String, ResourceModel> getResourceMap(); Map<String, ResourceModel> getResourceNameMap();
List<ResourceModel> getResources(); List<ResourceModel> getResources();
@ -110,4 +110,6 @@ public interface RealmModel {
List<RequiredCredentialModel> getOAuthClientRequiredCredentials(); List<RequiredCredentialModel> getOAuthClientRequiredCredentials();
boolean hasRole(UserModel user, String role); boolean hasRole(UserModel user, String role);
ResourceModel getResourceById(String id);
} }

View file

@ -416,7 +416,7 @@ public class RealmAdapter implements RealmModel {
* @return * @return
*/ */
@Override @Override
public Map<String, ResourceModel> getResourceMap() { public Map<String, ResourceModel> getResourceNameMap() {
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);
@ -424,6 +424,24 @@ public class RealmAdapter implements RealmModel {
return resourceMap; return resourceMap;
} }
/**
* Makes sure that the resource returned is owned by the realm
*
* @return
*/
@Override
public ResourceModel getResourceById(String id) {
RelationshipQuery<ResourceRelationship> query = getRelationshipManager().createRelationshipQuery(ResourceRelationship.class);
query.setParameter(ResourceRelationship.REALM, realm.getName());
query.setParameter(ResourceRelationship.RESOURCE, id);
List<ResourceRelationship> results = query.getResultList();
if (results.size() == 0) return null;
ResourceData resource = partitionManager.getPartition(ResourceData.class, id);
ResourceModel model = new ResourceAdapter(resource, this, partitionManager);
return model;
}
@Override @Override
public List<ResourceModel> getResources() { public List<ResourceModel> getResources() {
RelationshipQuery<ResourceRelationship> query = getRelationshipManager().createRelationshipQuery(ResourceRelationship.class); RelationshipQuery<ResourceRelationship> query = getRelationshipManager().createRelationshipQuery(ResourceRelationship.class);

View file

@ -14,6 +14,7 @@ public class ResourceRelationship extends AbstractAttributedType implements Rela
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public static final AttributeParameter REALM = new AttributeParameter("realm"); public static final AttributeParameter REALM = new AttributeParameter("realm");
public static final AttributeParameter RESOURCE = new AttributeParameter("resource");
public ResourceRelationship() { public ResourceRelationship() {
} }

View file

@ -1,5 +1,6 @@
package org.keycloak.services.resources; package org.keycloak.services.resources;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.PublishedRealmRepresentation; import org.keycloak.representations.idm.PublishedRealmRepresentation;
import org.keycloak.services.models.KeycloakSession; import org.keycloak.services.models.KeycloakSession;
@ -37,6 +38,7 @@ public class PublicRealmResource {
} }
@GET @GET
@NoCache
@Produces("application/json") @Produces("application/json")
public PublishedRealmRepresentation getRealm(@PathParam("realm") String id) { public PublishedRealmRepresentation getRealm(@PathParam("realm") String id) {
return new Transaction() { return new Transaction() {
@ -47,6 +49,7 @@ public class PublicRealmResource {
} }
@GET @GET
@NoCache
@Path("html") @Path("html")
@Produces("text/html") @Produces("text/html")
public String getRealmHtml(@PathParam("realm") String id) { public String getRealmHtml(@PathParam("realm") String id) {

View file

@ -1,5 +1,6 @@
package org.keycloak.services.resources; package org.keycloak.services.resources;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.jose.jws.JWSBuilder; import org.jboss.resteasy.jose.jws.JWSBuilder;
import org.jboss.resteasy.jose.jws.JWSInput; import org.jboss.resteasy.jose.jws.JWSInput;
import org.jboss.resteasy.jose.jws.crypto.RSAProvider; import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
@ -381,6 +382,7 @@ public class TokenService extends AbstractLoginService {
@Path("logout") @Path("logout")
@GET @GET
@NoCache
public Response logout(final @QueryParam("redirect_uri") String redirectUri) { public Response logout(final @QueryParam("redirect_uri") String redirectUri) {
return new Transaction() { return new Transaction() {
protected Response callImpl() { protected Response callImpl() {

View file

@ -1,5 +1,6 @@
package org.keycloak.services.resources.admin; package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
@ -47,7 +48,13 @@ public class RealmAdminResource {
this.realm = realm; this.realm = realm;
} }
@Path("resources")
public RealmResourcesResource getResources() {
return new RealmResourcesResource(admin, realm);
}
@GET @GET
@NoCache
@Produces("application/json") @Produces("application/json")
public RealmRepresentation getRealm() { public RealmRepresentation getRealm() {
return new Transaction() { return new Transaction() {
@ -70,6 +77,7 @@ public class RealmAdminResource {
@Path("roles") @Path("roles")
@GET @GET
@NoCache
@Produces("application/json") @Produces("application/json")
public List<RoleRepresentation> getRoles() { public List<RoleRepresentation> getRoles() {
return new Transaction() { return new Transaction() {
@ -88,6 +96,7 @@ public class RealmAdminResource {
@Path("roles/{id}") @Path("roles/{id}")
@GET @GET
@NoCache
@Produces("application/json") @Produces("application/json")
public RoleRepresentation getRole(final @PathParam("id") String id) { public RoleRepresentation getRole(final @PathParam("id") String id) {
return new Transaction() { return new Transaction() {
@ -147,6 +156,7 @@ public class RealmAdminResource {
@Path("users") @Path("users")
@GET @GET
@NoCache
@Produces("application/json") @Produces("application/json")
public List<UserRepresentation> getUsers() { public List<UserRepresentation> getUsers() {
return null; return null;

View file

@ -1,13 +1,28 @@
package org.keycloak.services.resources.admin; package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.ResourceRepresentation; import org.keycloak.representations.idm.ResourceRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceManager;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.ResourceModel;
import org.keycloak.services.models.UserModel; import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.Transaction;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@ -26,7 +41,68 @@ public class RealmResourcesResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
List<ResourceRepresentation> getResources() { @NoCache
return null; public List<ResourceRepresentation> getResources() {
return new Transaction() {
@Override
protected List<ResourceRepresentation> callImpl() {
List<ResourceRepresentation> rep = new ArrayList<ResourceRepresentation>();
List<ResourceModel> resourceModels = realm.getResources();
ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
for (ResourceModel resourceModel : resourceModels) {
rep.add(resourceManager.toRepresentation(resourceModel));
}
return rep;
}
}.call();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createResource(final @Context UriInfo uriInfo, final ResourceRepresentation rep) {
return new Transaction() {
@Override
protected Response callImpl() {
ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
ResourceModel resourceModel = resourceManager.createResource(realm, rep);
return Response.created(uriInfo.getAbsolutePathBuilder().path(resourceModel.getId()).build()).build();
}
}.call();
}
@Path("{id}")
@PUT
@Consumes(MediaType.APPLICATION_JSON)
public void update(final @PathParam("id") String id, final ResourceRepresentation rep) {
new Transaction() {
@Override
protected void runImpl() {
ResourceModel resourceModel = realm.getResourceById(id);
if (resourceModel == null) {
throw new NotFoundException();
}
ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
resourceManager.updateResource(rep, resourceModel);
}
}.run();
}
@Path("{id}")
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public ResourceRepresentation getResource(final @PathParam("id") String id) {
return new Transaction() {
@Override
protected ResourceRepresentation callImpl() {
ResourceModel resourceModel = realm.getResourceById(id);
if (resourceModel == null) {
throw new NotFoundException();
}
ResourceManager resourceManager = new ResourceManager(new RealmManager(session));
return resourceManager.toRepresentation(resourceModel);
}
}.call();
} }
} }

View file

@ -1,5 +1,6 @@
package org.keycloak.services.resources.admin; package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
@ -49,6 +50,7 @@ public class RealmsAdminResource {
} }
@GET @GET
@NoCache
@Produces("application/json") @Produces("application/json")
public Response getRealms() { public Response getRealms() {
return new Transaction() { return new Transaction() {

View file

@ -76,6 +76,7 @@
"resources" : [ "resources" : [
{ {
"name" : "Application", "name" : "Application",
"enabled" : true,
"roles" : [ "roles" : [
{ "name" : "admin" }, { "name" : "admin" },
{ "name" : "user" } { "name" : "user" }
@ -97,8 +98,9 @@
} }
] ]
}, },
{ {
"name" : "OtherApp", "name" : "OtherApp",
"enabled" : true,
"roles" : [ "roles" : [
{ "name" : "admin" }, { "name" : "admin" },
{ "name" : "user" } { "name" : "user" }