diff --git a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/DefaultOAuth2AccessToken.java b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/DefaultOAuth2AccessToken.java index 451529fc6..e2986fc92 100644 --- a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/DefaultOAuth2AccessToken.java +++ b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/DefaultOAuth2AccessToken.java @@ -26,6 +26,8 @@ import java.util.Set; import java.util.StringTokenizer; import java.util.TreeSet; +import org.maxkey.authz.oauth2.common.exceptions.OAuth2Exception; + /** * Basic access token for OAuth 2. * @@ -48,7 +50,9 @@ public class DefaultOAuth2AccessToken implements Serializable, OAuth2AccessToken private Set scope; private Map additionalInformation = Collections.emptyMap(); - + + private OAuth2Exception oauth2Exception; + /** * Create an access token from the value provided. */ @@ -78,6 +82,10 @@ public class DefaultOAuth2AccessToken implements Serializable, OAuth2AccessToken setTokenType(accessToken.getTokenType()); } + public DefaultOAuth2AccessToken(OAuth2Exception oauth2Exception) { + this.oauth2Exception = oauth2Exception; + } + public void setValue(String value) { this.value = value; } @@ -258,4 +266,10 @@ public class DefaultOAuth2AccessToken implements Serializable, OAuth2AccessToken this.additionalInformation = new LinkedHashMap(additionalInformation); } + @Override + public OAuth2Exception getOAuth2Exception() { + + return this.oauth2Exception; + } + } diff --git a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/OAuth2AccessToken.java b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/OAuth2AccessToken.java index 9069b12c3..d96246310 100644 --- a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/OAuth2AccessToken.java +++ b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/OAuth2AccessToken.java @@ -17,6 +17,8 @@ import java.util.Date; import java.util.Map; import java.util.Set; +import org.maxkey.authz.oauth2.common.exceptions.OAuth2Exception; + /** * @author Dave Syer * @@ -59,6 +61,11 @@ public interface OAuth2AccessToken extends Serializable { * href="http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.3">Section 3.3 */ public static String SCOPE = "scope"; + + public static String ERROR = "error"; + + public static String ERROR_DESCRIPTION = "error_description"; + /** * The additionalInformation map is used by the token serializers to export any fields used by extensions of OAuth. @@ -73,6 +80,8 @@ public interface OAuth2AccessToken extends Serializable { OAuth2RefreshToken getRefreshToken(); String getTokenType(); + + OAuth2Exception getOAuth2Exception(); boolean isExpired(); diff --git a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/OAuth2AccessTokenJackson2Serializer.java b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/OAuth2AccessTokenJackson2Serializer.java index a702e5c4e..5c9b6861a 100644 --- a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/OAuth2AccessTokenJackson2Serializer.java +++ b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/OAuth2AccessTokenJackson2Serializer.java @@ -34,6 +34,11 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer; */ public final class OAuth2AccessTokenJackson2Serializer extends StdSerializer { + /** + * + */ + private static final long serialVersionUID = -7323248504425950254L; + public OAuth2AccessTokenJackson2Serializer() { super(OAuth2AccessToken.class); } @@ -42,26 +47,31 @@ public final class OAuth2AccessTokenJackson2Serializer extends StdSerializer scope = token.getScope(); - if (scope != null && !scope.isEmpty()) { - StringBuffer scopes = new StringBuffer(); - for (String s : scope) { - Assert.hasLength(s, "Scopes cannot be null or empty. Got " + scope + ""); - scopes.append(s); - scopes.append(" "); + if(token.getOAuth2Exception()==null) { + jgen.writeStringField(OAuth2AccessToken.ACCESS_TOKEN, token.getValue()); + jgen.writeStringField(OAuth2AccessToken.TOKEN_TYPE, token.getTokenType()); + OAuth2RefreshToken refreshToken = token.getRefreshToken(); + if (refreshToken != null) { + jgen.writeStringField(OAuth2AccessToken.REFRESH_TOKEN, refreshToken.getValue()); } - jgen.writeStringField(OAuth2AccessToken.SCOPE, scopes.substring(0, scopes.length() - 1)); + Date expiration = token.getExpiration(); + if (expiration != null) { + long now = System.currentTimeMillis(); + jgen.writeNumberField(OAuth2AccessToken.EXPIRES_IN, (expiration.getTime() - now) / 1000); + } + Set scope = token.getScope(); + if (scope != null && !scope.isEmpty()) { + StringBuffer scopes = new StringBuffer(); + for (String s : scope) { + Assert.hasLength(s, "Scopes cannot be null or empty. Got " + scope + ""); + scopes.append(s); + scopes.append(" "); + } + jgen.writeStringField(OAuth2AccessToken.SCOPE, scopes.substring(0, scopes.length() - 1)); + } + }else { + jgen.writeStringField(OAuth2AccessToken.ERROR, token.getOAuth2Exception().getOAuth2ErrorCode()); + jgen.writeStringField(OAuth2AccessToken.ERROR_DESCRIPTION, token.getOAuth2Exception().getMessage()); } Map additionalInformation = token.getAdditionalInformation(); for (String key : additionalInformation.keySet()) { diff --git a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/TokenEndpoint.java b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/TokenEndpoint.java index f76868e96..e5ffdffb2 100644 --- a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/TokenEndpoint.java +++ b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/TokenEndpoint.java @@ -16,7 +16,6 @@ package org.maxkey.authz.oauth2.provider.endpoint; -import java.security.Principal; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; @@ -24,10 +23,12 @@ import java.util.Map; import java.util.Set; import org.maxkey.authn.SigninPrincipal; +import org.maxkey.authz.oauth2.common.DefaultOAuth2AccessToken; import org.maxkey.authz.oauth2.common.OAuth2AccessToken; import org.maxkey.authz.oauth2.common.exceptions.InvalidClientException; import org.maxkey.authz.oauth2.common.exceptions.InvalidGrantException; import org.maxkey.authz.oauth2.common.exceptions.InvalidRequestException; +import org.maxkey.authz.oauth2.common.exceptions.OAuth2Exception; import org.maxkey.authz.oauth2.common.exceptions.UnsupportedGrantTypeException; import org.maxkey.authz.oauth2.common.util.OAuth2Utils; import org.maxkey.authz.oauth2.provider.OAuth2Authentication; @@ -97,64 +98,69 @@ public class TokenEndpoint extends AbstractEndpoint { public ResponseEntity postAccessToken(@RequestParam Map parameters) throws HttpRequestMethodNotSupportedException { // TokenEndpointAuthenticationFilter - - Object principal = WebContext.getAuthentication(); - - if (!(principal instanceof Authentication)) { - throw new InsufficientAuthenticationException( - "There is no client authentication. Try adding an appropriate authentication filter."); - } - - String clientId = getClientId((Authentication)principal); - ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId); - - TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient); - - if (clientId != null && !clientId.equals("")) { - // Only validate the client details if a client authenticated during this - // request. - if (!clientId.equals(tokenRequest.getClientId())) { - // double check to make sure that the client ID in the token request is the same as that in the - // authenticated client - throw new InvalidClientException("Given client ID does not match authenticated client"); + OAuth2AccessToken token = null; + try { + Object principal = WebContext.getAuthentication(); + + if (!(principal instanceof Authentication)) { + throw new InsufficientAuthenticationException( + "There is no client authentication. Try adding an appropriate authentication."); } - } - if (authenticatedClient != null) { - oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient); - } - if (!StringUtils.hasText(tokenRequest.getGrantType())) { - throw new InvalidRequestException("Missing grant type"); - } - if (tokenRequest.getGrantType().equals("implicit")) { - throw new InvalidGrantException("Implicit grant type not supported from token endpoint"); - } - - if (isAuthCodeRequest(parameters)) { + + String clientId = getClientId((Authentication)principal); + ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId); + + TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient); + + if (clientId != null && !clientId.equals("")) { + // Only validate the client details if a client authenticated during this + // request. + if (!clientId.equals(tokenRequest.getClientId())) { + // double check to make sure that the client ID in the token request is the same as that in the + // authenticated client + throw new InvalidClientException("Given client ID does not match authenticated client"); + } + } + if (authenticatedClient != null) { + oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient); + } + if (!StringUtils.hasText(tokenRequest.getGrantType())) { + throw new InvalidRequestException("Missing grant type"); + } + if (tokenRequest.getGrantType().equals("implicit")) { + throw new InvalidGrantException("Implicit grant type not supported from token endpoint"); + } + + if (isAuthCodeRequest(parameters)) { + // The scope was requested or determined during the authorization step + if (!tokenRequest.getScope().isEmpty()) { + logger.debug("Clearing scope of incoming token request"); + tokenRequest.setScope(Collections. emptySet()); + } + } + // The scope was requested or determined during the authorization step - if (!tokenRequest.getScope().isEmpty()) { - logger.debug("Clearing scope of incoming token request"); - tokenRequest.setScope(Collections. emptySet()); + /**crystal.sea + * code must uuid format + */ + if (parameters.get("code") != null &&!StringGenerator.uuidMatches(parameters.get("code"))) { + throw new InvalidRequestException("The code is not valid format ."); } - } - - // The scope was requested or determined during the authorization step - /**crystal.sea - * code must uuid format - */ - if (parameters.get("code") != null &&!StringGenerator.uuidMatches(parameters.get("code"))) { - throw new InvalidRequestException("The code is not valid format ."); - } - - if (isRefreshTokenRequest(parameters)) { - // A refresh token has its own default scopes, so we should ignore any added by the factory here. - tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE))); - } - - OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest); - if (token == null) { - throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType()); - } - + + if (isRefreshTokenRequest(parameters)) { + // A refresh token has its own default scopes, so we should ignore any added by the factory here. + tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE))); + } + + token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest); + if (token == null) { + throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType()); + } + }catch(OAuth2Exception oauth2Exception) { + token = new DefaultOAuth2AccessToken(oauth2Exception); + }catch(InsufficientAuthenticationException authenticationException) { + token = new DefaultOAuth2AccessToken(new OAuth2Exception(authenticationException.getMessage())); + } return getResponse(token); }