Java tutorial
/******************************************************************************* * Copyright 2016 The MITRE Corporation * and the MIT 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.Collections; import java.util.HashSet; import java.util.Set; import org.mitre.oauth2.model.SystemScope; import org.mitre.oauth2.service.SystemScopeService; import org.mitre.openid.connect.config.ConfigurationPropertiesBean; import org.mitre.openid.connect.view.HttpCodeView; import org.mitre.openid.connect.view.JsonEntityView; import org.mitre.openid.connect.view.JsonErrorView; import org.mitre.uma.model.ResourceSet; import org.mitre.uma.service.ResourceSetService; import org.mitre.uma.view.ResourceSetEntityAbbreviatedView; import org.mitre.uma.view.ResourceSetEntityView; 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.base.Strings; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import static org.mitre.oauth2.web.AuthenticationUtilities.ensureOAuthScope; import static org.mitre.util.JsonUtils.getAsLong; import static org.mitre.util.JsonUtils.getAsString; import static org.mitre.util.JsonUtils.getAsStringSet; @Controller @RequestMapping("/" + ResourceSetRegistrationEndpoint.URL) @PreAuthorize("hasRole('ROLE_USER')") public class ResourceSetRegistrationEndpoint { private static final Logger logger = LoggerFactory.getLogger(ResourceSetRegistrationEndpoint.class); public static final String DISCOVERY_URL = "resource_set"; public static final String URL = DISCOVERY_URL + "/resource_set"; @Autowired private ResourceSetService resourceSetService; @Autowired private ConfigurationPropertiesBean config; @Autowired private SystemScopeService scopeService; private JsonParser parser = new JsonParser(); @RequestMapping(method = RequestMethod.POST, produces = MimeTypeUtils.APPLICATION_JSON_VALUE, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE) public String createResourceSet(@RequestBody String jsonString, Model m, Authentication auth) { ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE); ResourceSet rs = parseResourceSet(jsonString); if (rs == null) { // there was no resource set in the body logger.warn("Resource set registration missing body."); m.addAttribute("code", HttpStatus.BAD_REQUEST); m.addAttribute("error_description", "Resource request was missing body."); return JsonErrorView.VIEWNAME; } if (auth instanceof OAuth2Authentication) { // if it's an OAuth mediated call, it's on behalf of a client, so store that OAuth2Authentication o2a = (OAuth2Authentication) auth; rs.setClientId(o2a.getOAuth2Request().getClientId()); rs.setOwner(auth.getName()); // the username is going to be in the auth object } else { // this one shouldn't be called if it's not OAuth m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); m.addAttribute(JsonErrorView.ERROR_MESSAGE, "This call must be made with an OAuth token"); return JsonErrorView.VIEWNAME; } rs = validateScopes(rs); if (Strings.isNullOrEmpty(rs.getName()) // there was no name (required) || rs.getScopes() == null // there were no scopes (required) ) { logger.warn("Resource set registration missing one or more required fields."); m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Resource request was missing one or more required fields."); return JsonErrorView.VIEWNAME; } ResourceSet saved = resourceSetService.saveNew(rs); m.addAttribute(HttpCodeView.CODE, HttpStatus.CREATED); m.addAttribute(JsonEntityView.ENTITY, saved); m.addAttribute(ResourceSetEntityAbbreviatedView.LOCATION, config.getIssuer() + URL + "/" + saved.getId()); return ResourceSetEntityAbbreviatedView.VIEWNAME; } @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) public String readResourceSet(@PathVariable("id") Long id, Model m, Authentication auth) { ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE); ResourceSet rs = resourceSetService.getById(id); if (rs == null) { m.addAttribute("code", HttpStatus.NOT_FOUND); m.addAttribute("error", "not_found"); return JsonErrorView.VIEWNAME; } else { rs = validateScopes(rs); if (!auth.getName().equals(rs.getOwner())) { logger.warn("Unauthorized resource set request from wrong user; expected " + rs.getOwner() + " got " + auth.getName()); // it wasn't issued to this user m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); return JsonErrorView.VIEWNAME; } else { m.addAttribute(JsonEntityView.ENTITY, rs); return ResourceSetEntityView.VIEWNAME; } } } @RequestMapping(value = "/{id}", method = RequestMethod.PUT, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) public String updateResourceSet(@PathVariable("id") Long id, @RequestBody String jsonString, Model m, Authentication auth) { ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE); ResourceSet newRs = parseResourceSet(jsonString); if (newRs == null // there was no resource set in the body || Strings.isNullOrEmpty(newRs.getName()) // there was no name (required) || newRs.getScopes() == null // there were no scopes (required) || newRs.getId() == null || !newRs.getId().equals(id) // the IDs didn't match ) { logger.warn("Resource set registration missing one or more required fields."); m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Resource request was missing one or more required fields."); return JsonErrorView.VIEWNAME; } 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 { ResourceSet saved = resourceSetService.update(rs, newRs); m.addAttribute(JsonEntityView.ENTITY, saved); m.addAttribute(ResourceSetEntityAbbreviatedView.LOCATION, config.getIssuer() + URL + "/" + rs.getId()); return ResourceSetEntityAbbreviatedView.VIEWNAME; } } } @RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) public String deleteResourceSet(@PathVariable("id") Long id, Model m, Authentication auth) { ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE); 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 if (auth instanceof OAuth2Authentication && !((OAuth2Authentication) auth).getOAuth2Request().getClientId().equals(rs.getClientId())) { logger.warn("Unauthorized resource set request from bad client; expected " + rs.getClientId() + " got " + ((OAuth2Authentication) auth).getOAuth2Request().getClientId()); // it wasn't issued to this client m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); return JsonErrorView.VIEWNAME; } else { // user and client matched resourceSetService.remove(rs); m.addAttribute(HttpCodeView.CODE, HttpStatus.NO_CONTENT); return HttpCodeView.VIEWNAME; } } } @RequestMapping(method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) public String listResourceSets(Model m, Authentication auth) { ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE); String owner = auth.getName(); Collection<ResourceSet> resourceSets = Collections.emptySet(); if (auth instanceof OAuth2Authentication) { // if it's an OAuth mediated call, it's on behalf of a client, so look that up too OAuth2Authentication o2a = (OAuth2Authentication) auth; resourceSets = resourceSetService.getAllForOwnerAndClient(owner, o2a.getOAuth2Request().getClientId()); } else { // otherwise get everything for the current user resourceSets = resourceSetService.getAllForOwner(owner); } // build the entity here and send to the display Set<String> ids = new HashSet<>(); for (ResourceSet resourceSet : resourceSets) { ids.add(resourceSet.getId().toString()); // add them all as strings so that gson renders them properly } m.addAttribute(JsonEntityView.ENTITY, ids); return JsonEntityView.VIEWNAME; } private ResourceSet parseResourceSet(String jsonString) { try { JsonElement el = parser.parse(jsonString); if (el.isJsonObject()) { JsonObject o = el.getAsJsonObject(); ResourceSet rs = new ResourceSet(); rs.setId(getAsLong(o, "_id")); rs.setName(getAsString(o, "name")); rs.setIconUri(getAsString(o, "icon_uri")); rs.setType(getAsString(o, "type")); rs.setScopes(getAsStringSet(o, "scopes")); rs.setUri(getAsString(o, "uri")); return rs; } return null; } catch (JsonParseException e) { return null; } } /** * * Make sure the resource set doesn't have any restricted or reserved scopes. * * @param rs */ private ResourceSet validateScopes(ResourceSet rs) { // scopes that the client is asking for Set<SystemScope> requestedScopes = scopeService.fromStrings(rs.getScopes()); // the scopes that the resource set can have must be a subset of the dynamically allowed scopes Set<SystemScope> allowedScopes = scopeService.removeRestrictedAndReservedScopes(requestedScopes); rs.setScopes(scopeService.toStrings(allowedScopes)); return rs; } }