From 5ff9cd1bbba931ee9a75c7de08f6e8a32e488eef Mon Sep 17 00:00:00 2001 From: Justin Richer Date: Sat, 28 Feb 2015 17:59:37 -0500 Subject: [PATCH] implemented permission registration API --- .../java/org/mitre/uma/model/Permission.java | 80 +++++++++++++++- .../java/org/mitre/uma/model/ResourceSet.java | 6 +- ...ository.java => PermissionRepository.java} | 10 +- .../mitre/uma/service/PermissionService.java | 12 +++ .../db/tables/hsql_database_tables.sql | 24 ++++- .../webapp/WEB-INF/application-context.xml | 8 +- .../impl/JpaPermissionRepository.java | 45 +++++++++ .../impl/DefaultPermissionService.java | 54 +++++++++++ .../web/PermissionRegistrationEndpoint.java | 93 ++++++++++++++++++- .../web/ResourceSetRegistrationEndpoint.java | 2 +- 10 files changed, 317 insertions(+), 17 deletions(-) rename openid-connect-common/src/main/java/org/mitre/uma/repository/{PermissionRespository.java => PermissionRepository.java} (85%) create mode 100644 openid-connect-server/src/main/java/org/mitre/uma/repository/impl/JpaPermissionRepository.java create mode 100644 openid-connect-server/src/main/java/org/mitre/uma/service/impl/DefaultPermissionService.java diff --git a/openid-connect-common/src/main/java/org/mitre/uma/model/Permission.java b/openid-connect-common/src/main/java/org/mitre/uma/model/Permission.java index 635482941..43f321e46 100644 --- a/openid-connect-common/src/main/java/org/mitre/uma/model/Permission.java +++ b/openid-connect-common/src/main/java/org/mitre/uma/model/Permission.java @@ -17,10 +17,19 @@ package org.mitre.uma.model; -import java.util.Date; import java.util.Set; +import javax.persistence.Basic; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; import javax.persistence.Table; /** @@ -39,5 +48,74 @@ public class Permission { private Set scopes; private String ticket; + /** + * @return the id + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + public Long getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(Long id) { + this.id = id; + } + + /** + * @return the resourceSet + */ + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "resource_set_id") + public ResourceSet getResourceSet() { + return resourceSet; + } + + /** + * @param resourceSet the resourceSet to set + */ + public void setResourceSet(ResourceSet resourceSet) { + this.resourceSet = resourceSet; + } + + /** + * @return the scopes + */ + @ElementCollection(fetch = FetchType.EAGER) + @Column(name = "scope") + @CollectionTable( + name = "permission_scope", + joinColumns = @JoinColumn(name = "owner_id") + ) + public Set getScopes() { + return scopes; + } + + /** + * @param scopes the scopes to set + */ + public void setScopes(Set scopes) { + this.scopes = scopes; + } + + /** + * @return the ticket + */ + @Basic + @Column(name = "ticket") + public String getTicket() { + return ticket; + } + + /** + * @param ticket the ticket to set + */ + public void setTicket(String ticket) { + this.ticket = ticket; + } + } diff --git a/openid-connect-common/src/main/java/org/mitre/uma/model/ResourceSet.java b/openid-connect-common/src/main/java/org/mitre/uma/model/ResourceSet.java index 013e1f180..9f3a35934 100644 --- a/openid-connect-common/src/main/java/org/mitre/uma/model/ResourceSet.java +++ b/openid-connect-common/src/main/java/org/mitre/uma/model/ResourceSet.java @@ -118,11 +118,11 @@ public class ResourceSet { /** * @return the scopes */ - @ElementCollection(fetch=FetchType.EAGER) + @ElementCollection(fetch = FetchType.EAGER) @Column(name = "scope") @CollectionTable( - name="resource_set_scope", - joinColumns=@JoinColumn(name = "owner_id") + name = "resource_set_scope", + joinColumns = @JoinColumn(name = "owner_id") ) public Set getScopes() { return scopes; diff --git a/openid-connect-common/src/main/java/org/mitre/uma/repository/PermissionRespository.java b/openid-connect-common/src/main/java/org/mitre/uma/repository/PermissionRepository.java similarity index 85% rename from openid-connect-common/src/main/java/org/mitre/uma/repository/PermissionRespository.java rename to openid-connect-common/src/main/java/org/mitre/uma/repository/PermissionRepository.java index e0caf2fb4..f7ff56609 100644 --- a/openid-connect-common/src/main/java/org/mitre/uma/repository/PermissionRespository.java +++ b/openid-connect-common/src/main/java/org/mitre/uma/repository/PermissionRepository.java @@ -17,10 +17,18 @@ package org.mitre.uma.repository; +import org.mitre.uma.model.Permission; + /** * @author jricher * */ -public interface PermissionRespository { +public interface PermissionRepository { + + /** + * @param p + * @return + */ + public Permission save(Permission p); } diff --git a/openid-connect-common/src/main/java/org/mitre/uma/service/PermissionService.java b/openid-connect-common/src/main/java/org/mitre/uma/service/PermissionService.java index 334aa03f8..5e6afec17 100644 --- a/openid-connect-common/src/main/java/org/mitre/uma/service/PermissionService.java +++ b/openid-connect-common/src/main/java/org/mitre/uma/service/PermissionService.java @@ -17,6 +17,11 @@ package org.mitre.uma.service; +import java.util.Set; + +import org.mitre.uma.model.Permission; +import org.mitre.uma.model.ResourceSet; + /** * @author jricher @@ -24,4 +29,11 @@ package org.mitre.uma.service; */ public interface PermissionService { + /** + * @param resourceSet the resource set to create the permission on + * @param scopes the set of scopes that this permission is for + * @return the created (and stored) permission object, with ticket + */ + public Permission create(ResourceSet resourceSet, Set scopes); + } diff --git a/openid-connect-server-webapp/src/main/resources/db/tables/hsql_database_tables.sql b/openid-connect-server-webapp/src/main/resources/db/tables/hsql_database_tables.sql index 84d25d25c..1ec18d7b9 100644 --- a/openid-connect-server-webapp/src/main/resources/db/tables/hsql_database_tables.sql +++ b/openid-connect-server-webapp/src/main/resources/db/tables/hsql_database_tables.sql @@ -221,14 +221,28 @@ CREATE TABLE IF NOT EXISTS pairwise_identifier ( CREATE TABLE IF NOT EXISTS resource_set ( id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, - name VARCHAR(1024), + name VARCHAR(1024) NOT NULL, uri VARCHAR(1024), icon_uri VARCHAR(1024), rs_type VARCHAR(256), - owner VARCHAR(256) + owner VARCHAR(256) NOT NULL ); CREATE TABLE IF NOT EXISTS resource_set_scope ( - owner_id BIGINT, - scope VARCHAR(256) -); \ No newline at end of file + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS permission ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + resource_set_id BIGINT NOT NULL, + ticket VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS permission_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + + + \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml index fd234f069..a883d46c9 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml @@ -117,7 +117,13 @@ - + + + + + + + diff --git a/openid-connect-server/src/main/java/org/mitre/uma/repository/impl/JpaPermissionRepository.java b/openid-connect-server/src/main/java/org/mitre/uma/repository/impl/JpaPermissionRepository.java new file mode 100644 index 000000000..b2912f95b --- /dev/null +++ b/openid-connect-server/src/main/java/org/mitre/uma/repository/impl/JpaPermissionRepository.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright 2015 The MITRE Corporation + * and the MIT Kerberos and Internet Trust Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ + +package org.mitre.uma.repository.impl; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +import org.mitre.uma.model.Permission; +import org.mitre.uma.repository.PermissionRepository; +import org.mitre.util.jpa.JpaUtil; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author jricher + * + */ +@Repository +public class JpaPermissionRepository implements PermissionRepository { + + @PersistenceContext + private EntityManager em; + + @Override + @Transactional + public Permission save(Permission p) { + return JpaUtil.saveOrUpdate(p.getId(), em, p); + } + +} diff --git a/openid-connect-server/src/main/java/org/mitre/uma/service/impl/DefaultPermissionService.java b/openid-connect-server/src/main/java/org/mitre/uma/service/impl/DefaultPermissionService.java new file mode 100644 index 000000000..e8e6d4f67 --- /dev/null +++ b/openid-connect-server/src/main/java/org/mitre/uma/service/impl/DefaultPermissionService.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright 2015 The MITRE Corporation + * and the MIT Kerberos and Internet Trust Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ + +package org.mitre.uma.service.impl; + +import java.util.Set; +import java.util.UUID; + +import org.mitre.uma.model.Permission; +import org.mitre.uma.model.ResourceSet; +import org.mitre.uma.repository.PermissionRepository; +import org.mitre.uma.service.PermissionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author jricher + * + */ +@Service +public class DefaultPermissionService implements PermissionService { + + @Autowired + private PermissionRepository repository; + + /* (non-Javadoc) + * @see org.mitre.uma.service.PermissionService#create(org.mitre.uma.model.ResourceSet, java.util.Set) + */ + @Override + public Permission create(ResourceSet resourceSet, Set scopes) { + Permission p = new Permission(); + p.setResourceSet(resourceSet); + p.setScopes(scopes); + p.setTicket(UUID.randomUUID().toString()); + + return repository.save(p); + + } + +} diff --git a/openid-connect-server/src/main/java/org/mitre/uma/web/PermissionRegistrationEndpoint.java b/openid-connect-server/src/main/java/org/mitre/uma/web/PermissionRegistrationEndpoint.java index 7c197696e..32ecb0d04 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/web/PermissionRegistrationEndpoint.java +++ b/openid-connect-server/src/main/java/org/mitre/uma/web/PermissionRegistrationEndpoint.java @@ -18,11 +18,20 @@ package org.mitre.uma.web; import static org.mitre.uma.web.OAuthScopeEnforcementUtilities.ensureOAuthScope; +import static org.mitre.util.JsonUtils.getAsLong; +import static org.mitre.util.JsonUtils.getAsStringSet; + +import java.util.Set; import org.mitre.oauth2.service.SystemScopeService; import org.mitre.openid.connect.view.JsonEntityView; +import org.mitre.openid.connect.view.JsonErrorView; +import org.mitre.uma.model.Permission; +import org.mitre.uma.model.ResourceSet; import org.mitre.uma.service.PermissionService; +import org.mitre.uma.service.ResourceSetService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; @@ -32,6 +41,11 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; + /** * @author jricher * @@ -40,21 +54,90 @@ import org.springframework.web.bind.annotation.RequestMethod; @RequestMapping("/" + PermissionRegistrationEndpoint.URL) @PreAuthorize("hasRole('ROLE_USER')") public class PermissionRegistrationEndpoint { - + public static final String URL = "permission"; @Autowired private PermissionService permissionService; + @Autowired + private ResourceSetService resourceSetService; + + private JsonParser parser = new JsonParser(); + @RequestMapping(method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) public String getPermissionTicket(@RequestBody String jsonString, Model m, Authentication auth) { ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE); - - - return JsonEntityView.VIEWNAME; + try { + + // parse the permission request + + JsonElement el = parser.parse(jsonString); + if (el.isJsonObject()) { + JsonObject o = el.getAsJsonObject(); + + Long rsid = getAsLong(o, "resource_set_id"); + Set scopes = getAsStringSet(o, "scopes"); + + if (rsid == null || scopes == null || scopes.isEmpty()){ + // missing information + m.addAttribute("code", HttpStatus.BAD_REQUEST); + m.addAttribute("errorMessage", "Missing required component of resource registration request."); + return JsonErrorView.VIEWNAME; + } + + ResourceSet resourceSet = resourceSetService.getById(rsid); + + // requested resource set doesn't exist + if (resourceSet == null) { + m.addAttribute("code", HttpStatus.NOT_FOUND); + m.addAttribute("errorMessage", "Requested resource set not found: " + rsid); + return JsonErrorView.VIEWNAME; + } + + // authorized user of the token doesn't match owner of the resource set + if (!resourceSet.getOwner().equals(auth.getName())) { + m.addAttribute("code", HttpStatus.FORBIDDEN); + m.addAttribute("errorMessage", "Party requesting permission is not owner of resource set, expected " + resourceSet.getOwner() + " got " + auth.getName()); + return JsonErrorView.VIEWNAME; + } + + // create the permission + Permission permission = permissionService.create(resourceSet, scopes); + + if (permission != null) { + // we've created the permission, return the ticket + JsonObject out = new JsonObject(); + out.addProperty("ticket", permission.getTicket()); + m.addAttribute("entity", out); + + m.addAttribute("code", HttpStatus.CREATED); + + return JsonEntityView.VIEWNAME; + } else { + // there was a failure creating the permission object + + m.addAttribute("code", HttpStatus.INTERNAL_SERVER_ERROR); + m.addAttribute("errorMessage", "Unable to save permission and generate ticket."); + + return JsonErrorView.VIEWNAME; + } + + } else { + // malformed request + m.addAttribute("code", HttpStatus.BAD_REQUEST); + m.addAttribute("errorMessage", "Malformed JSON request."); + return JsonErrorView.VIEWNAME; + } + } catch (JsonParseException e) { + // malformed request + m.addAttribute("code", HttpStatus.BAD_REQUEST); + m.addAttribute("errorMessage", "Malformed JSON request."); + return JsonErrorView.VIEWNAME; + } } - + } diff --git a/openid-connect-server/src/main/java/org/mitre/uma/web/ResourceSetRegistrationEndpoint.java b/openid-connect-server/src/main/java/org/mitre/uma/web/ResourceSetRegistrationEndpoint.java index a46ad6f56..45c4440d6 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/web/ResourceSetRegistrationEndpoint.java +++ b/openid-connect-server/src/main/java/org/mitre/uma/web/ResourceSetRegistrationEndpoint.java @@ -116,7 +116,7 @@ public class ResourceSetRegistrationEndpoint { if (!auth.getName().equals(rs.getOwner())) { - logger.warn("Unauthorized resource set request from bad user; expected " + rs.getOwner() + " got " + auth.getName()); + logger.warn("Unauthorized resource set request from wrong user; expected " + rs.getOwner() + " got " + auth.getName()); // it wasn't issued to this user m.addAttribute("code", HttpStatus.FORBIDDEN);