brought introspection endpoint and introspection token services into compliance with draft, addresses #376

pull/419/head
Justin Richer 2013-07-08 13:56:08 -04:00
parent 2d16b8d458
commit a9da88fb79
4 changed files with 76 additions and 33 deletions

View File

@ -101,7 +101,7 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
// create a default authentication object with authority ROLE_API
private Authentication createAuthentication(JsonObject token){
// TODO: make role/authority configurable somehow
return new PreAuthenticatedAuthenticationToken(token.get("subject").getAsString(), null, AuthorityUtils.createAuthorityList("ROLE_API"));
return new PreAuthenticatedAuthenticationToken(token.get("sub").getAsString(), null, AuthorityUtils.createAuthorityList("ROLE_API"));
}
private OAuth2AccessToken createAccessToken(final JsonObject token, final String tokenString){
@ -142,7 +142,7 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
return false;
}
if (!tokenResponse.get("valid").getAsBoolean()){
if (!tokenResponse.get("active").getAsBoolean()){
// non-valid token
return false;
}

View File

@ -25,12 +25,14 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.web.servlet.view.AbstractView;
import com.google.common.base.Joiner;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
@ -89,19 +91,38 @@ public class TokenIntrospectionView extends AbstractView {
public JsonElement serialize(OAuth2AccessTokenEntity src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject token = new JsonObject();
token.addProperty("valid", true);
token.addProperty("active", true);
JsonArray scopes = new JsonArray();
for (String scope : src.getScope()) {
scopes.add(new JsonPrimitive(scope));
}
token.add("scope", scopes);
token.add("expires_at", context.serialize(src.getExpiration()));
token.addProperty("scope", Joiner.on(" ").join(src.getScope()));
token.add("exp", context.serialize(src.getExpiration()));
//token.addProperty("audience", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());
token.addProperty("subject", src.getAuthenticationHolder().getAuthentication().getName());
token.addProperty("sub", src.getAuthenticationHolder().getAuthentication().getName());
token.addProperty("client_id", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());
token.addProperty("token_type", src.getTokenType());
return token;
}
})
.registerTypeAdapter(OAuth2RefreshTokenEntity.class, new JsonSerializer<OAuth2RefreshTokenEntity>() {
@Override
public JsonElement serialize(OAuth2RefreshTokenEntity src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject token = new JsonObject();
token.addProperty("active", true);
token.addProperty("scope", Joiner.on(" ").join(src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getScope()));
token.add("exp", context.serialize(src.getExpiration()));
//token.addProperty("audience", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());
token.addProperty("sub", src.getAuthenticationHolder().getAuthentication().getName());
token.addProperty("client_id", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());

View File

@ -17,10 +17,13 @@
package org.mitre.oauth2.web;
import java.security.Principal;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
import org.mitre.oauth2.service.ClientDetailsEntityService;
import org.mitre.oauth2.service.OAuth2TokenEntityService;
import org.slf4j.Logger;
@ -58,27 +61,51 @@ public class IntrospectionEndpoint {
@PreAuthorize("hasRole('ROLE_CLIENT')")
@RequestMapping("/introspect")
public String verify(@RequestParam("token") String tokenValue, Principal p, Model model) {
public String verify(@RequestParam("token") String tokenValue, @RequestParam("resource_id") String resourceId, @RequestParam("token_type_hint") String tokenType,
Principal p, Model model) {
if (Strings.isNullOrEmpty(tokenValue)) {
logger.error("Verify failed; token value is null");
Map<String,Boolean> entity = ImmutableMap.of("valid", Boolean.FALSE);
Map<String,Boolean> entity = ImmutableMap.of("active", Boolean.FALSE);
model.addAttribute("entity", entity);
return "jsonEntityView";
}
OAuth2AccessTokenEntity token = null;
ClientDetailsEntity tokenClient = null;
Set<String> scopes = null;
Object token = null;
try {
token = tokenServices.readAccessToken(tokenValue);
// check access tokens first (includes ID tokens)
OAuth2AccessTokenEntity access = tokenServices.readAccessToken(tokenValue);
tokenClient = access.getClient();
scopes = access.getScope();
token = access;
} catch (InvalidTokenException e) {
logger.error("Verify failed; AuthenticationException", e);
Map<String,Boolean> entity = ImmutableMap.of("valid", Boolean.FALSE);
model.addAttribute("entity", entity);
return "jsonEntityView";
logger.error("Verify failed; Invalid access token. Checking refresh token.", e);
try {
// check refresh tokens next
OAuth2RefreshTokenEntity refresh = tokenServices.getRefreshToken(tokenValue);
tokenClient = refresh.getClient();
scopes = refresh.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getScope();
token = refresh;
} catch (InvalidTokenException e2) {
logger.error("Verify failed; Invalid refresh token", e2);
Map<String,Boolean> entity = ImmutableMap.of("active", Boolean.FALSE);
model.addAttribute("entity", entity);
return "jsonEntityView";
}
}
ClientDetailsEntity tokenClient = token.getClient();
// clientID is the principal name in the authentication
String clientId = p.getName();
ClientDetailsEntity authClient = clientService.loadClientByClientId(clientId);
@ -87,7 +114,7 @@ public class IntrospectionEndpoint {
if (authClient.isAllowIntrospection()) {
// if it's the same client that the token was issued to, or it at least has all the scopes the token was issued with
if (authClient.equals(tokenClient) || authClient.getScope().containsAll(token.getScope())) {
if (authClient.equals(tokenClient) || authClient.getScope().containsAll(scopes)) {
// if it's a valid token, we'll print out information on it
model.addAttribute("entity", token);

View File

@ -41,31 +41,26 @@ public class RevocationEndpoint {
private static Logger logger = LoggerFactory.getLogger(RevocationEndpoint.class);
public RevocationEndpoint() {
}
// TODO
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')")
@RequestMapping("/revoke")
public String revoke(@RequestParam("token") String tokenValue, Principal principal, Model model) {
public String revoke(@RequestParam("token") String tokenValue, @RequestParam("token_type_hint") String tokenType, 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);
AuthorizationRequest clientAuth = null;
AuthorizationRequest authRequest = null;
if (principal instanceof OAuth2Authentication) {
// if the client is acting on its own behalf (the common case), pull out the client authorization request
clientAuth = ((OAuth2Authentication) principal).getAuthorizationRequest();
authRequest = ((OAuth2Authentication) principal).getAuthorizationRequest();
}
try {
// check and handle access tokens first
OAuth2AccessTokenEntity accessToken = tokenServices.readAccessToken(tokenValue);
if (clientAuth != null) {
if (authRequest != null) {
// client acting on its own, make sure it owns the token
if (!accessToken.getClient().getClientId().equals(clientAuth.getClientId())) {
if (!accessToken.getClient().getClientId().equals(authRequest.getClientId())) {
// trying to revoke a token we don't own, throw a 403
model.addAttribute("code", HttpStatus.FORBIDDEN);
return "httpCodeView";
@ -83,9 +78,9 @@ public class RevocationEndpoint {
try {
OAuth2RefreshTokenEntity refreshToken = tokenServices.getRefreshToken(tokenValue);
if (clientAuth != null) {
if (authRequest != null) {
// client acting on its own, make sure it owns the token
if (!refreshToken.getClient().getClientId().equals(clientAuth.getClientId())) {
if (!refreshToken.getClient().getClientId().equals(authRequest.getClientId())) {
// trying to revoke a token we don't own, throw a 403
model.addAttribute("code", HttpStatus.FORBIDDEN);
return "httpCodeView";