updated error handling on introspection and revocation endpoints

pull/324/merge
Justin Richer 2013-04-12 16:34:51 -04:00
parent 35cb14a73f
commit 98fff8fe99
2 changed files with 69 additions and 111 deletions

View File

@ -31,6 +31,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@ -58,58 +59,26 @@ public class IntrospectionEndpoint {
this.tokenServices = tokenServices;
}
@ExceptionHandler(InvalidTokenException.class)
public ModelAndView tokenNotFound(InvalidTokenException ex) {
Map<String,Boolean> e = ImmutableMap.of("valid", Boolean.FALSE);
Map<String, Object> model = new HashMap<String, Object>();
model.put("entity", e);
logger.error("InvalidTokenException: " + ex.getStackTrace().toString());
model.put("code", HttpStatus.BAD_REQUEST);
return new ModelAndView("jsonEntityView", model);
}
@PreAuthorize("hasRole('ROLE_CLIENT')")
@RequestMapping("/introspect")
public ModelAndView verify(@RequestParam("token") String tokenValue, Principal p, ModelAndView modelAndView) {
/*
if (p != null && p instanceof OAuth2Authentication) {
OAuth2Authentication auth = (OAuth2Authentication)p;
if (auth.getDetails() != null && auth.getDetails() instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)auth.getDetails();
String tokenValue = details.getTokenValue();
OAuth2AccessTokenEntity token = tokenServices.readAccessToken(tokenValue);
if (token != null) {
// if it's a valid token, we'll print out the scope and expiration
modelAndView.setViewName("tokenIntrospection");
modelAndView.addObject("entity", token);
}
}
}*/
public String verify(@RequestParam("token") String tokenValue, Principal p, Model model) {
if (Strings.isNullOrEmpty(tokenValue)) {
logger.error("Verify failed; token value is null");
modelAndView.addObject("code", HttpStatus.BAD_REQUEST);
modelAndView.setViewName("httpCodeView");
return modelAndView;
Map<String,Boolean> entity = ImmutableMap.of("valid", Boolean.FALSE);
model.addAttribute("entity", entity);
return "jsonEntityView";
}
OAuth2AccessTokenEntity token = null;
try {
token = tokenServices.readAccessToken(tokenValue);
} catch (AuthenticationException e) {
} catch (InvalidTokenException e) {
logger.error("Verify failed; AuthenticationException: " + e.getStackTrace().toString());
modelAndView.addObject("code", HttpStatus.FORBIDDEN);
modelAndView.setViewName("httpCodeView");
return modelAndView;
Map<String,Boolean> entity = ImmutableMap.of("valid", Boolean.FALSE);
model.addAttribute("entity", entity);
return "jsonEntityView";
}
ClientDetailsEntity tokenClient = token.getClient();
@ -124,27 +93,23 @@ public class IntrospectionEndpoint {
if (authClient.equals(tokenClient) || authClient.getScope().containsAll(token.getScope())) {
// if it's a valid token, we'll print out information on it
modelAndView.setViewName("tokenIntrospection");
modelAndView.addObject("entity", token);
return modelAndView;
model.addAttribute("entity", token);
return "tokenIntrospection";
} else {
logger.error("Verify failed; client tried to introspect a token of an incorrect scope");
modelAndView.addObject("code", HttpStatus.BAD_REQUEST);
modelAndView.setViewName("httpCodeView");
return modelAndView;
model.addAttribute("code", HttpStatus.FORBIDDEN);
return "httpCodeView";
}
} else {
logger.error("Verify failed; client " + clientId + " is not allowed to call introspection endpoint");
modelAndView.addObject("code", HttpStatus.BAD_REQUEST);
modelAndView.setViewName("httpCodeView");
return modelAndView;
model.addAttribute("code", HttpStatus.FORBIDDEN);
return "httpCodeView";
}
} else {
//TODO: Log error client not found
// This is a bad error -- I think it means we have a token outstanding that doesn't map to a client?
logger.error("Verify failed; client " + clientId + " not found.");
modelAndView.addObject("code", HttpStatus.NOT_FOUND);
modelAndView.setViewName("httpCodeView");
return modelAndView;
model.addAttribute("code", HttpStatus.NOT_FOUND);
return "httpCodeView";
}
}

View File

@ -24,12 +24,14 @@ 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.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@ -45,75 +47,66 @@ public class RevocationEndpoint {
}
public RevocationEndpoint(OAuth2TokenEntityService tokenServices) {
this.tokenServices = tokenServices;
}
// TODO
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')")
@RequestMapping("/revoke")
public ModelAndView revoke(@RequestParam("token") String tokenValue, Principal principal,
ModelAndView modelAndView) {
public String revoke(@RequestParam("token") String tokenValue, Principal principal, Model model) {
// This is the token as passed in from OAuth (in case we need it some day)
//OAuth2AccessTokenEntity tok = tokenServices.getAccessToken((OAuth2Authentication) principal);
OAuth2RefreshTokenEntity refreshToken = null;
OAuth2AccessTokenEntity accessToken = null;
try {
refreshToken = tokenServices.getRefreshToken(tokenValue);
} catch (InvalidTokenException e) {
// it's OK if either of these tokens are bad
//TODO: Error Handling
}
try {
accessToken = tokenServices.readAccessToken(tokenValue);
} catch (InvalidTokenException e) {
// it's OK if either of these tokens are bad
//TODO: Error Handling
} catch (AuthenticationException e) {
//TODO: Error Handling
}
if (refreshToken == null && accessToken == null) {
//TODO: Error Handling
// TODO: this should throw a 400 with a JSON error code
throw new InvalidTokenException("Invalid OAuth token: " + tokenValue);
}
AuthorizationRequest clientAuth = null;
if (principal instanceof OAuth2Authentication) {
//TODO what is this variable for? It is unused. is it just a validation check?
OAuth2AccessTokenEntity tok = tokenServices.getAccessToken((OAuth2Authentication) principal);
// if the client is acting on its own behalf (the common case), pull out the client authorization request
clientAuth = ((OAuth2Authentication) principal).getAuthorizationRequest();
}
// we've got a client acting on its own behalf, not an admin
//ClientAuthentication clientAuth = (ClientAuthenticationToken) ((OAuth2Authentication) auth).getClientAuthentication();
AuthorizationRequest clientAuth = ((OAuth2Authentication) principal).getAuthorizationRequest();
if (refreshToken != null) {
if (!refreshToken.getClient().getClientId().equals(clientAuth.getClientId())) {
// trying to revoke a token we don't own, fail
// TODO: this should throw a 403
//TODO: Error Handling
throw new PermissionDeniedException("Client tried to revoke a token it doesn't own");
}
} else {
try {
// check and handle access tokens first
OAuth2AccessTokenEntity accessToken = tokenServices.readAccessToken(tokenValue);
if (clientAuth != null) {
// client acting on its own, make sure it owns the token
if (!accessToken.getClient().getClientId().equals(clientAuth.getClientId())) {
// trying to revoke a token we don't own, fail
// TODO: this should throw a 403
//TODO: Error Handling
throw new PermissionDeniedException("Client tried to revoke a token it doesn't own");
// trying to revoke a token we don't own, throw a 403
model.addAttribute("code", HttpStatus.FORBIDDEN);
return "httpCodeView";
}
}
// if we got this far, we're allowed to do this
tokenServices.revokeAccessToken(accessToken);
model.addAttribute("code", HttpStatus.OK);
return "httpCodeView";
} catch (InvalidTokenException e) {
// access token wasn't found, check the refresh token
try {
OAuth2RefreshTokenEntity refreshToken = tokenServices.getRefreshToken(tokenValue);
if (clientAuth != null) {
// client acting on its own, make sure it owns the token
if (!refreshToken.getClient().getClientId().equals(clientAuth.getClientId())) {
// trying to revoke a token we don't own, throw a 403
model.addAttribute("code", HttpStatus.FORBIDDEN);
return "httpCodeView";
}
}
// if we got this far, we're allowed to do this
tokenServices.revokeRefreshToken(refreshToken);
model.addAttribute("code", HttpStatus.OK);
return "httpCodeView";
} catch (InvalidTokenException e1) {
// neither token type was found, simply say "OK" and be on our way.
model.addAttribute("code", HttpStatus.OK);
return "httpCodeView";
}
}
// if we got this far, we're allowed to do this
if (refreshToken != null) {
tokenServices.revokeRefreshToken(refreshToken);
} else {
tokenServices.revokeAccessToken(accessToken);
}
// TODO: throw a 200 back (no content?)
return modelAndView;
}
}