Updated Token API to be less leaky
parent
f559673090
commit
89f015cf1c
|
@ -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<OAuth2AccessTokenEntity>() {
|
||||
|
||||
@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<OAuth2RefreshTokenEntity>() {
|
||||
|
||||
@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<String, Object> 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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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<OAuth2AccessTokenEntity> 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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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<OAuth2RefreshTokenEntity> allTokens = tokenService.getAllRefreshTokensForUser(p.getName());
|
||||
@RequestMapping(value = "/access", method = RequestMethod.GET, produces = "application/json")
|
||||
public String getAllAccessTokens(ModelMap m, Principal p) {
|
||||
|
||||
Set<OAuth2AccessTokenEntity> 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<OAuth2RefreshTokenEntity> 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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue