implemented permission registration API

pull/708/merge
Justin Richer 2015-02-28 17:59:37 -05:00
parent eed8fb0b28
commit 5ff9cd1bbb
10 changed files with 317 additions and 17 deletions

View File

@ -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<String> 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<String> getScopes() {
return scopes;
}
/**
* @param scopes the scopes to set
*/
public void setScopes(Set<String> 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;
}
}

View File

@ -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<String> getScopes() {
return scopes;

View File

@ -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);
}

View File

@ -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<String> scopes);
}

View File

@ -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)
);
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
);

View File

@ -117,7 +117,13 @@
<security:intercept-url pattern="/resource/**" access="permitAll"/>
</security:http>
<security:http pattern="/#{T(org.mitre.openid.connect.web.ResourceSetRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="never">
<security:http pattern="/#{T(org.mitre.uma.web.ResourceSetRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="never">
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
<security:expression-handler ref="oauthWebExpressionHandler" />
</security:http>
<security:http pattern="/#{T(org.mitre.uma.web.PermissionRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="never">
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
<security:expression-handler ref="oauthWebExpressionHandler" />

View File

@ -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);
}
}

View File

@ -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<String> scopes) {
Permission p = new Permission();
p.setResourceSet(resourceSet);
p.setScopes(scopes);
p.setTicket(UUID.randomUUID().toString());
return repository.save(p);
}
}

View File

@ -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<String> 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;
}
}
}

View File

@ -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);