diff --git a/uma-server/src/main/java/org/mitre/uma/web/ClaimsAPI.java b/uma-server/src/main/java/org/mitre/uma/web/ClaimsAPI.java deleted file mode 100644 index f7341b23d..000000000 --- a/uma-server/src/main/java/org/mitre/uma/web/ClaimsAPI.java +++ /dev/null @@ -1,162 +0,0 @@ -/******************************************************************************* - * 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.web; - -import java.util.Collection; -import java.util.Set; - -import org.mitre.oauth2.service.SystemScopeService; -import org.mitre.openid.connect.view.HttpCodeView; -import org.mitre.openid.connect.view.JsonEntityView; -import org.mitre.openid.connect.view.JsonErrorView; -import org.mitre.openid.connect.web.RootController; -import org.mitre.uma.model.Claim; -import org.mitre.uma.model.Policy; -import org.mitre.uma.model.ResourceSet; -import org.mitre.uma.service.ResourceSetService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -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.security.oauth2.provider.OAuth2Authentication; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.util.MimeTypeUtils; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; - -import static org.mitre.oauth2.web.AuthenticationUtilities.ensureOAuthScope; - -/** - * @author jricher - * - */ -@Controller -@RequestMapping("/" + ClaimsAPI.URL) -@PreAuthorize("hasRole('ROLE_USER')") -public class ClaimsAPI { - - // - // - // FIXME - // - // - - // Logger for this class - private static final Logger logger = LoggerFactory.getLogger(ClaimsAPI.class); - - public static final String URL = RootController.API_URL + "/claims"; - - @Autowired - private ResourceSetService resourceSetService; - - @RequestMapping(value = "", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) - public String getResourceSetsForCurrentUser(Model m, Authentication auth) { - - Collection resourceSets = resourceSetService.getAllForOwner(auth.getName()); - - m.addAttribute(JsonEntityView.ENTITY, resourceSets); - - return JsonEntityView.VIEWNAME; - } - - @RequestMapping(value = "/{rsid}", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) - public String getClaimsForResourceSet(@PathVariable (value = "rsid") Long rsid, Model m, Authentication auth) { - - ResourceSet rs = resourceSetService.getById(rsid); - - if (rs == null) { - m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND); - return HttpCodeView.VIEWNAME; - } - - if (!rs.getOwner().equals(auth.getName())) { - // authenticated user didn't match the owner of the resource set - m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); - return HttpCodeView.VIEWNAME; - } - - m.addAttribute(JsonEntityView.ENTITY, rs.getPolicies()); - - return JsonEntityView.VIEWNAME; - } - - @RequestMapping(value = "/{rsid}", method = RequestMethod.PUT, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) - public String setClaimsForResourceSet(@PathVariable (value = "rsid") Long rsid, @RequestBody String jsonString, Model m, Authentication auth) { - - ResourceSet rs = resourceSetService.getById(rsid); - - if (rs == null) { - m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND); - return HttpCodeView.VIEWNAME; - } - - if (!rs.getOwner().equals(auth.getName())) { - // authenticated user didn't match the owner of the resource set - m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); - return HttpCodeView.VIEWNAME; - } - - @SuppressWarnings("serial") - Set claims = (new Gson()).fromJson(jsonString, new TypeToken>() {}.getType()); - - //rs.setClaimsRequired(claims); - - resourceSetService.update(rs, rs); - - m.addAttribute(JsonEntityView.ENTITY, rs.getPolicies()); - - return JsonEntityView.VIEWNAME; - } - - @RequestMapping(value = "/{rsid}", method = RequestMethod.DELETE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) - public String deleteResourceSet(@PathVariable ("rsid") Long id, Model m, Authentication auth) { - - ResourceSet rs = resourceSetService.getById(id); - - if (rs == null) { - m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND); - m.addAttribute(JsonErrorView.ERROR, "not_found"); - return JsonErrorView.VIEWNAME; - } else { - if (!auth.getName().equals(rs.getOwner())) { - - logger.warn("Unauthorized resource set request from bad user; expected " + rs.getOwner() + " got " + auth.getName()); - - // it wasn't issued to this user - m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); - return JsonErrorView.VIEWNAME; - } else { - - resourceSetService.remove(rs); - - m.addAttribute(HttpCodeView.CODE, HttpStatus.NO_CONTENT); - return HttpCodeView.VIEWNAME; - } - - } - } - -} diff --git a/uma-server/src/main/java/org/mitre/uma/web/PolicyAPI.java b/uma-server/src/main/java/org/mitre/uma/web/PolicyAPI.java new file mode 100644 index 000000000..03862397e --- /dev/null +++ b/uma-server/src/main/java/org/mitre/uma/web/PolicyAPI.java @@ -0,0 +1,330 @@ +/******************************************************************************* + * 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.web; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.mitre.openid.connect.view.HttpCodeView; +import org.mitre.openid.connect.view.JsonEntityView; +import org.mitre.openid.connect.view.JsonErrorView; +import org.mitre.openid.connect.web.RootController; +import org.mitre.uma.model.Claim; +import org.mitre.uma.model.Policy; +import org.mitre.uma.model.ResourceSet; +import org.mitre.uma.service.ResourceSetService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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; +import org.springframework.ui.Model; +import org.springframework.util.MimeTypeUtils; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import com.google.common.collect.Sets; +import com.google.gson.Gson; + +/** + * API for managing policies on resource sets. + * + * @author jricher + * + */ +@Controller +@RequestMapping("/" + PolicyAPI.URL) +@PreAuthorize("hasRole('ROLE_USER')") +public class PolicyAPI { + + // Logger for this class + private static final Logger logger = LoggerFactory.getLogger(PolicyAPI.class); + + public static final String URL = RootController.API_URL + "/policy"; + + private Gson gson = new Gson(); + + @Autowired + private ResourceSetService resourceSetService; + + /** + * List all resource sets for the current user + * @param m + * @param auth + * @return + */ + @RequestMapping(value = "", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) + public String getResourceSetsForCurrentUser(Model m, Authentication auth) { + + Collection resourceSets = resourceSetService.getAllForOwner(auth.getName()); + + m.addAttribute(JsonEntityView.ENTITY, resourceSets); + + return JsonEntityView.VIEWNAME; + } + + /** + * List all the policies for the given resource set + * @param rsid + * @param m + * @param auth + * @return + */ + @RequestMapping(value = "/{rsid}", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) + public String getPoliciesForResourceSet(@PathVariable (value = "rsid") Long rsid, Model m, Authentication auth) { + + ResourceSet rs = resourceSetService.getById(rsid); + + if (rs == null) { + m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + } + + if (!rs.getOwner().equals(auth.getName())) { + logger.warn("Unauthorized resource set request from bad user; expected " + rs.getOwner() + " got " + auth.getName()); + + // authenticated user didn't match the owner of the resource set + m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); + return HttpCodeView.VIEWNAME; + } + + m.addAttribute(JsonEntityView.ENTITY, rs.getPolicies()); + + return JsonEntityView.VIEWNAME; + } + + /** + * Create a new policy on the given resource set + * @param rsid + * @param m + * @param auth + * @return + */ + @RequestMapping(value = "/{rsid}", method = RequestMethod.POST, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) + public String createNewPolicyForResourceSet(@PathVariable (value = "rsid") Long rsid, @RequestBody String jsonString, Model m, Authentication auth) { + ResourceSet rs = resourceSetService.getById(rsid); + + if (rs == null) { + m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + } + + if (!rs.getOwner().equals(auth.getName())) { + logger.warn("Unauthorized resource set request from bad user; expected " + rs.getOwner() + " got " + auth.getName()); + + // authenticated user didn't match the owner of the resource set + m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); + return HttpCodeView.VIEWNAME; + } + + Policy p = gson.fromJson(jsonString, Policy.class); + + if (p.getId() != null) { + logger.warn("Tried to add a policy with a non-null ID: " + p.getId()); + m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); + return HttpCodeView.VIEWNAME; + } + + for (Claim claim : p.getClaimsRequired()) { + if (claim.getId() != null) { + logger.warn("Tried to add a policy with a non-null claim ID: " + claim.getId()); + m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); + return HttpCodeView.VIEWNAME; + } + } + + rs.getPolicies().add(p); + ResourceSet saved = resourceSetService.update(rs, rs); + + // find the new policy object + Collection newPolicies = Sets.difference(new HashSet<>(saved.getPolicies()), new HashSet<>(rs.getPolicies())); + + if (newPolicies.size() == 1) { + Policy newPolicy = newPolicies.iterator().next(); + m.addAttribute(JsonEntityView.ENTITY, newPolicy); + return JsonEntityView.VIEWNAME; + } else { + logger.warn("Unexpected result trying to add a new policy object: " + newPolicies); + m.addAttribute(HttpCodeView.CODE, HttpStatus.INTERNAL_SERVER_ERROR); + return HttpCodeView.VIEWNAME; + } + + } + + /** + * Get a specific policy + * @param rsid + * @param pid + * @param m + * @param auth + * @return + */ + @RequestMapping(value = "/{rsid}/{pid}", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) + public String getPolicy(@PathVariable (value = "rsid") Long rsid, @PathVariable (value = "pid") Long pid, Model m, Authentication auth) { + + ResourceSet rs = resourceSetService.getById(rsid); + + if (rs == null) { + m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + } + + if (!rs.getOwner().equals(auth.getName())) { + logger.warn("Unauthorized resource set request from bad user; expected " + rs.getOwner() + " got " + auth.getName()); + + // authenticated user didn't match the owner of the resource set + m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); + return HttpCodeView.VIEWNAME; + } + + for (Policy policy : rs.getPolicies()) { + if (policy.getId().equals(pid)) { + // found it! + m.addAttribute(JsonEntityView.ENTITY, policy); + return JsonEntityView.VIEWNAME; + } + } + + // if we made it this far, we haven't found it + m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + } + + /** + * Update a specific policy + * @param rsid + * @param pid + * @param jsonString + * @param m + * @param auth + * @return + */ + @RequestMapping(value = "/{rsid}/{pid}", method = RequestMethod.PUT, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) + public String setClaimsForResourceSet(@PathVariable (value = "rsid") Long rsid, @PathVariable (value = "pid") Long pid, @RequestBody String jsonString, Model m, Authentication auth) { + + ResourceSet rs = resourceSetService.getById(rsid); + + if (rs == null) { + m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + } + + if (!rs.getOwner().equals(auth.getName())) { + logger.warn("Unauthorized resource set request from bad user; expected " + rs.getOwner() + " got " + auth.getName()); + + // authenticated user didn't match the owner of the resource set + m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); + return HttpCodeView.VIEWNAME; + } + + Policy p = gson.fromJson(jsonString, Policy.class); + + if (!pid.equals(p.getId())) { + logger.warn("Policy ID mismatch, expected " + pid + " got " + p.getId()); + + m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); + return HttpCodeView.VIEWNAME; + } + + for (Policy policy : rs.getPolicies()) { + if (policy.getId().equals(pid)) { + // found it! + + // find the existing claim IDs, make sure we're not overwriting anything from another policy + Set claimIds = new HashSet<>(); + for (Claim claim : policy.getClaimsRequired()) { + claimIds.add(claim.getId()); + } + + for (Claim claim : p.getClaimsRequired()) { + if (claim.getId() != null && !claimIds.contains(claim.getId())) { + logger.warn("Tried to add a policy with a an unmatched claim ID: got " + claim.getId() + " expected " + claimIds); + m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); + return HttpCodeView.VIEWNAME; + } + } + + // update the existing object with the new values + policy.setClaimsRequired(p.getClaimsRequired()); + policy.setName(p.getName()); + policy.setScopes(p.getScopes()); + + resourceSetService.update(rs, rs); + + m.addAttribute(JsonEntityView.ENTITY, policy); + return JsonEntityView.VIEWNAME; + } + } + + // if we made it this far, we haven't found it + m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + } + + /** + * Delete a specific policy + * @param rsid + * @param pid + * @param m + * @param auth + * @return + */ + @RequestMapping(value = "/{rsid}/{pid}", method = RequestMethod.DELETE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) + public String deleteResourceSet(@PathVariable ("rsid") Long rsid, @PathVariable (value = "pid") Long pid, Model m, Authentication auth) { + + ResourceSet rs = resourceSetService.getById(rsid); + + if (rs == null) { + m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + m.addAttribute(JsonErrorView.ERROR, "not_found"); + return JsonErrorView.VIEWNAME; + } + + if (!auth.getName().equals(rs.getOwner())) { + + logger.warn("Unauthorized resource set request from bad user; expected " + rs.getOwner() + " got " + auth.getName()); + + // it wasn't issued to this user + m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); + return JsonErrorView.VIEWNAME; + } + + + for (Policy policy : rs.getPolicies()) { + if (policy.getId().equals(pid)) { + // found it! + rs.getPolicies().remove(policy); + resourceSetService.update(rs, rs); + + m.addAttribute(HttpCodeView.CODE, HttpStatus.NO_CONTENT); + return HttpCodeView.VIEWNAME; + } + } + + // if we made it this far, we haven't found it + m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND); + return HttpCodeView.VIEWNAME; + + } + +}