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; package org.mitre.uma.model;
import java.util.Date;
import java.util.Set; 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.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; import javax.persistence.Table;
/** /**
@ -39,5 +48,74 @@ public class Permission {
private Set<String> scopes; private Set<String> scopes;
private String ticket; 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 * @return the scopes
*/ */
@ElementCollection(fetch=FetchType.EAGER) @ElementCollection(fetch = FetchType.EAGER)
@Column(name = "scope") @Column(name = "scope")
@CollectionTable( @CollectionTable(
name="resource_set_scope", name = "resource_set_scope",
joinColumns=@JoinColumn(name = "owner_id") joinColumns = @JoinColumn(name = "owner_id")
) )
public Set<String> getScopes() { public Set<String> getScopes() {
return scopes; return scopes;

View File

@ -17,10 +17,18 @@
package org.mitre.uma.repository; package org.mitre.uma.repository;
import org.mitre.uma.model.Permission;
/** /**
* @author jricher * @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; package org.mitre.uma.service;
import java.util.Set;
import org.mitre.uma.model.Permission;
import org.mitre.uma.model.ResourceSet;
/** /**
* @author jricher * @author jricher
@ -24,4 +29,11 @@ package org.mitre.uma.service;
*/ */
public interface PermissionService { 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 ( CREATE TABLE IF NOT EXISTS resource_set (
id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY,
name VARCHAR(1024), name VARCHAR(1024) NOT NULL,
uri VARCHAR(1024), uri VARCHAR(1024),
icon_uri VARCHAR(1024), icon_uri VARCHAR(1024),
rs_type VARCHAR(256), rs_type VARCHAR(256),
owner VARCHAR(256) owner VARCHAR(256) NOT NULL
); );
CREATE TABLE IF NOT EXISTS resource_set_scope ( CREATE TABLE IF NOT EXISTS resource_set_scope (
owner_id BIGINT, owner_id BIGINT NOT NULL,
scope VARCHAR(256) 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:intercept-url pattern="/resource/**" access="permitAll"/>
</security:http> </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="resourceServerFilter" before="PRE_AUTH_FILTER" />
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" /> <security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
<security:expression-handler ref="oauthWebExpressionHandler" /> <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; package org.mitre.uma.web;
import static org.mitre.uma.web.OAuthScopeEnforcementUtilities.ensureOAuthScope; 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.oauth2.service.SystemScopeService;
import org.mitre.openid.connect.view.JsonEntityView; 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.PermissionService;
import org.mitre.uma.service.ResourceSetService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller; 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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; 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 * @author jricher
* *
@ -46,14 +60,83 @@ public class PermissionRegistrationEndpoint {
@Autowired @Autowired
private PermissionService permissionService; 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) @RequestMapping(method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
public String getPermissionTicket(@RequestBody String jsonString, Model m, Authentication auth) { public String getPermissionTicket(@RequestBody String jsonString, Model m, Authentication auth) {
ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE); ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE);
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; 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())) { 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 // it wasn't issued to this user
m.addAttribute("code", HttpStatus.FORBIDDEN); m.addAttribute("code", HttpStatus.FORBIDDEN);