OAuth2Exception

This commit is contained in:
MaxKey 2020-12-19 15:59:26 +08:00
parent 3497aa5d26
commit 924cff9872
4 changed files with 115 additions and 76 deletions

View File

@ -26,6 +26,8 @@ import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.TreeSet; import java.util.TreeSet;
import org.maxkey.authz.oauth2.common.exceptions.OAuth2Exception;
/** /**
* Basic access token for OAuth 2. * Basic access token for OAuth 2.
* *
@ -48,7 +50,9 @@ public class DefaultOAuth2AccessToken implements Serializable, OAuth2AccessToken
private Set<String> scope; private Set<String> scope;
private Map<String, Object> additionalInformation = Collections.emptyMap(); private Map<String, Object> additionalInformation = Collections.emptyMap();
private OAuth2Exception oauth2Exception;
/** /**
* Create an access token from the value provided. * Create an access token from the value provided.
*/ */
@ -78,6 +82,10 @@ public class DefaultOAuth2AccessToken implements Serializable, OAuth2AccessToken
setTokenType(accessToken.getTokenType()); setTokenType(accessToken.getTokenType());
} }
public DefaultOAuth2AccessToken(OAuth2Exception oauth2Exception) {
this.oauth2Exception = oauth2Exception;
}
public void setValue(String value) { public void setValue(String value) {
this.value = value; this.value = value;
} }
@ -258,4 +266,10 @@ public class DefaultOAuth2AccessToken implements Serializable, OAuth2AccessToken
this.additionalInformation = new LinkedHashMap<String, Object>(additionalInformation); this.additionalInformation = new LinkedHashMap<String, Object>(additionalInformation);
} }
@Override
public OAuth2Exception getOAuth2Exception() {
return this.oauth2Exception;
}
} }

View File

@ -17,6 +17,8 @@ import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.maxkey.authz.oauth2.common.exceptions.OAuth2Exception;
/** /**
* @author Dave Syer * @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</a> * href="http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.3">Section 3.3</a>
*/ */
public static String SCOPE = "scope"; 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. * 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(); OAuth2RefreshToken getRefreshToken();
String getTokenType(); String getTokenType();
OAuth2Exception getOAuth2Exception();
boolean isExpired(); boolean isExpired();

View File

@ -34,6 +34,11 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer;
*/ */
public final class OAuth2AccessTokenJackson2Serializer extends StdSerializer<OAuth2AccessToken> { public final class OAuth2AccessTokenJackson2Serializer extends StdSerializer<OAuth2AccessToken> {
/**
*
*/
private static final long serialVersionUID = -7323248504425950254L;
public OAuth2AccessTokenJackson2Serializer() { public OAuth2AccessTokenJackson2Serializer() {
super(OAuth2AccessToken.class); super(OAuth2AccessToken.class);
} }
@ -42,26 +47,31 @@ public final class OAuth2AccessTokenJackson2Serializer extends StdSerializer<OAu
public void serialize(OAuth2AccessToken token, JsonGenerator jgen, SerializerProvider provider) throws IOException, public void serialize(OAuth2AccessToken token, JsonGenerator jgen, SerializerProvider provider) throws IOException,
JsonGenerationException { JsonGenerationException {
jgen.writeStartObject(); jgen.writeStartObject();
jgen.writeStringField(OAuth2AccessToken.ACCESS_TOKEN, token.getValue()); if(token.getOAuth2Exception()==null) {
jgen.writeStringField(OAuth2AccessToken.TOKEN_TYPE, token.getTokenType()); jgen.writeStringField(OAuth2AccessToken.ACCESS_TOKEN, token.getValue());
OAuth2RefreshToken refreshToken = token.getRefreshToken(); jgen.writeStringField(OAuth2AccessToken.TOKEN_TYPE, token.getTokenType());
if (refreshToken != null) { OAuth2RefreshToken refreshToken = token.getRefreshToken();
jgen.writeStringField(OAuth2AccessToken.REFRESH_TOKEN, refreshToken.getValue()); if (refreshToken != null) {
} jgen.writeStringField(OAuth2AccessToken.REFRESH_TOKEN, refreshToken.getValue());
Date expiration = token.getExpiration();
if (expiration != null) {
long now = System.currentTimeMillis();
jgen.writeNumberField(OAuth2AccessToken.EXPIRES_IN, (expiration.getTime() - now) / 1000);
}
Set<String> 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)); Date expiration = token.getExpiration();
if (expiration != null) {
long now = System.currentTimeMillis();
jgen.writeNumberField(OAuth2AccessToken.EXPIRES_IN, (expiration.getTime() - now) / 1000);
}
Set<String> 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<String, Object> additionalInformation = token.getAdditionalInformation(); Map<String, Object> additionalInformation = token.getAdditionalInformation();
for (String key : additionalInformation.keySet()) { for (String key : additionalInformation.keySet()) {

View File

@ -16,7 +16,6 @@
package org.maxkey.authz.oauth2.provider.endpoint; package org.maxkey.authz.oauth2.provider.endpoint;
import java.security.Principal;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
@ -24,10 +23,12 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.maxkey.authn.SigninPrincipal; 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.OAuth2AccessToken;
import org.maxkey.authz.oauth2.common.exceptions.InvalidClientException; import org.maxkey.authz.oauth2.common.exceptions.InvalidClientException;
import org.maxkey.authz.oauth2.common.exceptions.InvalidGrantException; import org.maxkey.authz.oauth2.common.exceptions.InvalidGrantException;
import org.maxkey.authz.oauth2.common.exceptions.InvalidRequestException; 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.exceptions.UnsupportedGrantTypeException;
import org.maxkey.authz.oauth2.common.util.OAuth2Utils; import org.maxkey.authz.oauth2.common.util.OAuth2Utils;
import org.maxkey.authz.oauth2.provider.OAuth2Authentication; import org.maxkey.authz.oauth2.provider.OAuth2Authentication;
@ -97,64 +98,69 @@ public class TokenEndpoint extends AbstractEndpoint {
public ResponseEntity<OAuth2AccessToken> postAccessToken(@RequestParam public ResponseEntity<OAuth2AccessToken> postAccessToken(@RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException { Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
// TokenEndpointAuthenticationFilter // TokenEndpointAuthenticationFilter
OAuth2AccessToken token = null;
Object principal = WebContext.getAuthentication(); try {
Object principal = WebContext.getAuthentication();
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException( if (!(principal instanceof Authentication)) {
"There is no client authentication. Try adding an appropriate authentication filter."); throw new InsufficientAuthenticationException(
} "There is no client authentication. Try adding an appropriate authentication.");
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) { String clientId = getClientId((Authentication)principal);
oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient); ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
}
if (!StringUtils.hasText(tokenRequest.getGrantType())) { TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
throw new InvalidRequestException("Missing grant type");
} if (clientId != null && !clientId.equals("")) {
if (tokenRequest.getGrantType().equals("implicit")) { // Only validate the client details if a client authenticated during this
throw new InvalidGrantException("Implicit grant type not supported from token endpoint"); // 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
if (isAuthCodeRequest(parameters)) { // 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.<String> emptySet());
}
}
// The scope was requested or determined during the authorization step // The scope was requested or determined during the authorization step
if (!tokenRequest.getScope().isEmpty()) { /**crystal.sea
logger.debug("Clearing scope of incoming token request"); * code must uuid format
tokenRequest.setScope(Collections.<String> emptySet()); */
if (parameters.get("code") != null &&!StringGenerator.uuidMatches(parameters.get("code"))) {
throw new InvalidRequestException("The code is not valid format .");
} }
}
if (isRefreshTokenRequest(parameters)) {
// The scope was requested or determined during the authorization step // A refresh token has its own default scopes, so we should ignore any added by the factory here.
/**crystal.sea tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
* code must uuid format }
*/
if (parameters.get("code") != null &&!StringGenerator.uuidMatches(parameters.get("code"))) { token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
throw new InvalidRequestException("The code is not valid format ."); if (token == null) {
} throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
}
if (isRefreshTokenRequest(parameters)) { }catch(OAuth2Exception oauth2Exception) {
// A refresh token has its own default scopes, so we should ignore any added by the factory here. token = new DefaultOAuth2AccessToken(oauth2Exception);
tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE))); }catch(InsufficientAuthenticationException authenticationException) {
} token = new DefaultOAuth2AccessToken(new OAuth2Exception(authenticationException.getMessage()));
}
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
if (token == null) {
throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
}
return getResponse(token); return getResponse(token);
} }