diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/view/TokenApiView.java b/openid-connect-server/src/main/java/org/mitre/oauth2/view/TokenApiView.java new file mode 100644 index 000000000..3ce1900cc --- /dev/null +++ b/openid-connect-server/src/main/java/org/mitre/oauth2/view/TokenApiView.java @@ -0,0 +1,129 @@ +package org.mitre.oauth2.view; + +import java.io.IOException; +import java.io.Writer; +import java.lang.reflect.Type; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.mitre.oauth2.model.OAuth2AccessTokenEntity; +import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; +import org.mitre.openid.connect.view.JsonEntityView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.web.servlet.view.AbstractView; + +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +@Component("tokenApiView") +public class TokenApiView extends AbstractView { + + private static Logger logger = LoggerFactory.getLogger(JsonEntityView.class); + + private Gson gson = new GsonBuilder() + .setExclusionStrategies(new ExclusionStrategy() { + + @Override + public boolean shouldSkipField(FieldAttributes f) { + return false; + } + + @Override + public boolean shouldSkipClass(Class clazz) { + // skip the JPA binding wrapper + if (clazz.equals(BeanPropertyBindingResult.class)) { + return true; + } + return false; + } + + }) + .registerTypeAdapter(OAuth2AccessTokenEntity.class, new JsonSerializer() { + + @Override + public JsonElement serialize(OAuth2AccessTokenEntity src, + Type typeOfSrc, JsonSerializationContext context) { + + + JsonObject o = new JsonObject(); + + o.addProperty("value", src.getValue()); + o.addProperty("id", src.getId()); + o.addProperty("idTokenId", src.getIdToken() != null ? src.getIdToken().getId() : null); + o.addProperty("refreshTokenId", src.getRefreshToken() != null ? src.getRefreshToken().getId() : null); + + o.add("scopes", context.serialize(src.getScope())); + + o.addProperty("clientId", src.getClient().getClientId()); + o.addProperty("userId", src.getAuthenticationHolder().getAuthentication().getName()); + + o.add("expiration", context.serialize(src.getExpiration())); + + return o; + } + + }) + .registerTypeAdapter(OAuth2RefreshTokenEntity.class, new JsonSerializer() { + + @Override + public JsonElement serialize(OAuth2RefreshTokenEntity src, + Type typeOfSrc, JsonSerializationContext context) { + JsonObject o = new JsonObject(); + + o.addProperty("value", src.getValue()); + o.addProperty("id", src.getId()); + + o.add("scopes", context.serialize(src.getAuthenticationHolder().getAuthentication().getOAuth2Request().getScope())); + + o.addProperty("clientId", src.getClient().getClientId()); + o.addProperty("userId", src.getAuthenticationHolder().getAuthentication().getName()); + + o.add("expiration", context.serialize(src.getExpiration())); + + return o; + } + + }) + .serializeNulls() + .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") + .create(); + + @Override + protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) { + + response.setContentType("application/json"); + + + HttpStatus code = (HttpStatus) model.get("code"); + if (code == null) { + code = HttpStatus.OK; // default to 200 + } + + response.setStatus(code.value()); + + try { + + Writer out = response.getWriter(); + Object obj = model.get("entity"); + gson.toJson(obj, out); + + } catch (IOException e) { + + logger.error("IOException in JsonEntityView.java: ", e); + + } + } + +} diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/AccessTokenAPI.java b/openid-connect-server/src/main/java/org/mitre/oauth2/web/AccessTokenAPI.java deleted file mode 100644 index 0dada026c..000000000 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/AccessTokenAPI.java +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************************* - * Copyright 2014 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.oauth2.web; - -import java.security.Principal; -import java.util.Set; - -import org.mitre.oauth2.model.OAuth2AccessTokenEntity; -import org.mitre.oauth2.service.OAuth2TokenEntityService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -/** - * REST-ish API for managing access tokens (no PUT; tokens cannot be updated and creation = OAuth). - * @author Amanda Anganes - * - */ -//@Controller -//@RequestMapping("/api/tokens/at") -//@PreAuthorize("hasRole('ROLE_USER')") -public class AccessTokenAPI { - - @Autowired - private OAuth2TokenEntityService tokenService; - - private static Logger logger = LoggerFactory.getLogger(AccessTokenAPI.class); - - @RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json") - public String getAll(ModelMap m, Principal p) { - - Set allTokens = tokenService.getAllAccessTokensForUser(p.getName()); - m.put("entity", allTokens); - return "jsonEntityView"; - } - - @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "application/json") - public String getById(@PathVariable("id") Long id, ModelMap m, Principal p) { - - OAuth2AccessTokenEntity token = tokenService.getAccessTokenById(id); - - if (token == null) { - logger.error("getToken failed; token not found: " + id); - m.put("code", HttpStatus.NOT_FOUND); - m.put("errorMessage", "The requested token with id " + id + " could not be found."); - return "jsonErrorView"; - } else if (!token.getAuthenticationHolder().getAuthentication().getName().equals(p.getName())) { - logger.error("getToken failed; token does not belong to principal " + p.getName()); - m.put("code", HttpStatus.FORBIDDEN); - m.put("errorMessage", "You do not have permission to view this token"); - return "jsonErrorView"; - } else { - m.put("entity", token); - return "jsonEntityView"; - } - } - -} diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/RefreshTokenAPI.java b/openid-connect-server/src/main/java/org/mitre/oauth2/web/TokenAPI.java similarity index 53% rename from openid-connect-server/src/main/java/org/mitre/oauth2/web/RefreshTokenAPI.java rename to openid-connect-server/src/main/java/org/mitre/oauth2/web/TokenAPI.java index 89b1f4b05..cb0b52361 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/RefreshTokenAPI.java +++ b/openid-connect-server/src/main/java/org/mitre/oauth2/web/TokenAPI.java @@ -19,47 +19,47 @@ package org.mitre.oauth2.web; import java.security.Principal; import java.util.Set; +import org.mitre.oauth2.model.OAuth2AccessTokenEntity; import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; import org.mitre.oauth2.service.OAuth2TokenEntityService; 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.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** - * REST-ish API for managing refresh tokens (no PUT; tokens cannot be updated and creation = OAuth). - * + * REST-ish API for managing access tokens (GET/read only) * @author Amanda Anganes * */ -//@Controller -//@RequestMapping("/api/tokens/rt") -//@PreAuthorize("hasRole('ROLE_USER')") -public class RefreshTokenAPI { +@Controller +@RequestMapping("/api/tokens") +@PreAuthorize("hasRole('ROLE_USER')") +public class TokenAPI { @Autowired private OAuth2TokenEntityService tokenService; - private static Logger logger = LoggerFactory.getLogger(RefreshTokenAPI.class); + private static Logger logger = LoggerFactory.getLogger(TokenAPI.class); - @RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json") - public String getAll(ModelMap m, Principal p) { - - Set allTokens = tokenService.getAllRefreshTokensForUser(p.getName()); + @RequestMapping(value = "/access", method = RequestMethod.GET, produces = "application/json") + public String getAllAccessTokens(ModelMap m, Principal p) { + Set allTokens = tokenService.getAllAccessTokensForUser(p.getName()); m.put("entity", allTokens); - - return "jsonEntityView"; + return "tokenApiView"; } - @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "application/json") - public String getById(@PathVariable("id") Long id, ModelMap m, Principal p) { + @RequestMapping(value = "/access/{id}", method = RequestMethod.GET, produces = "application/json") + public String getAccessTokenById(@PathVariable("id") Long id, ModelMap m, Principal p) { - OAuth2RefreshTokenEntity token = tokenService.getRefreshTokenById(id); + OAuth2AccessTokenEntity token = tokenService.getAccessTokenById(id); if (token == null) { logger.error("getToken failed; token not found: " + id); @@ -73,8 +73,39 @@ public class RefreshTokenAPI { return "jsonErrorView"; } else { m.put("entity", token); - return "jsonEntityView"; + return "tokenApiView"; } } + + @RequestMapping(value = "/refresh", method = RequestMethod.GET, produces = "application/json") + public String getAllRefreshTokens(ModelMap m, Principal p) { + + Set allTokens = tokenService.getAllRefreshTokensForUser(p.getName()); + m.put("entity", allTokens); + return "tokenApiView"; + + + } + @RequestMapping(value = "/refresh/{id}", method = RequestMethod.GET, produces = "application/json") + public String getRefreshTokenById(@PathVariable("id") Long id, ModelMap m, Principal p) { + + OAuth2RefreshTokenEntity token = tokenService.getRefreshTokenById(id); + + if (token == null) { + logger.error("refresh token not found: " + id); + m.put("code", HttpStatus.NOT_FOUND); + m.put("errorMessage", "The requested token with id " + id + " could not be found."); + return "jsonErrorView"; + } else if (!token.getAuthenticationHolder().getAuthentication().getName().equals(p.getName())) { + logger.error("refresh token " + id + " does not belong to principal " + p.getName()); + m.put("code", HttpStatus.FORBIDDEN); + m.put("errorMessage", "You do not have permission to view this token"); + return "jsonErrorView"; + } else { + m.put("entity", token); + return "tokenApiView"; + } + } + }