Browse Source

OAuth 2.1 PKCE

Crystal.Sea 3 years ago
parent
commit
8b3c035102
13 changed files with 138 additions and 34 deletions
  1. 19 0
      maxkey-common/src/main/java/org/maxkey/crypto/DigestUtils.java
  2. 2 0
      maxkey-common/src/test/java/org/maxkey/crypto/Base64UtilsTest.java
  3. 4 1
      maxkey-core/src/main/java/org/maxkey/constants/ConstantsProtocols.java
  4. 4 2
      maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/endpoint/AuthorizeEndpoint.java
  5. 12 0
      maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/OAuth2Constants.java
  6. 1 1
      maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/AuthorizationRequest.java
  7. 9 5
      maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/OAuth2Request.java
  8. 1 1
      maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/TokenRequest.java
  9. 42 9
      maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/code/AuthorizationCodeTokenGranter.java
  10. 34 12
      maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/AuthorizationEndpoint.java
  11. 2 2
      maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/TokenEndpoint.java
  12. 1 1
      maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/token/DefaultAccessTokenConverter.java
  13. 7 0
      maxkey-webs/maxkey-web-mgt/src/main/java/org/maxkey/web/apps/contorller/OAuth20DetailsController.java

+ 19 - 0
maxkey-common/src/main/java/org/maxkey/crypto/DigestUtils.java

@@ -61,6 +61,25 @@ public final class DigestUtils {
 		}
 		return cipherBASE64;
 	}
+	
+	/**
+     * @param simple
+     * @param algorithm MD5,SHA,SHA-1|SHA-256|SHA-384|SHA-512 then encodeBase64
+     * @return cipher
+     */
+    public static String digestBase64Url(String simple,String algorithm) {
+        MessageDigest messageDigest;
+        String cipherBASE64="";
+        try {
+            messageDigest = MessageDigest.getInstance(algorithm.toUpperCase());
+            messageDigest.update(simple.getBytes());
+            byte[] bCipher=messageDigest.digest();
+            cipherBASE64=Base64Utils.base64UrlEncode(bCipher);
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        return cipherBASE64;
+    }
 
 	//B64
 	public static String md5B64(String simple) {

+ 2 - 0
maxkey-common/src/test/java/org/maxkey/crypto/Base64UtilsTest.java

@@ -42,7 +42,9 @@ public class Base64UtilsTest {
 		 System.out.println(Base64Utils.decode("AAMkADU2OWY1MGQ3LWEyNWQtNDFmOC04MWFiLTI5YTE2NGM5YTZmNABGAAAAAABPKgpqnlfYQ7BVC/BfH2XIBwCS0xhUjzMYSLVky9bw7LddAAAAjov5AACS0xhUjzMYSLVky9bw7LddAAADzoyxAAA="));
 		 
 		
+		 String b = "UsWdAIe4opTqcrX6~SrIMhBu5Gc9oZKEnnSDFRx9JwBINK8XTgnXUs2A3b7QmxDM9nRu8~mGsikVEoISLg.JTIHYRwv-Bp5ljIADLwUHv9iJAWo1delBOlW0Hd7nIVF0";
 		 
+		 System.out.println(DigestUtils.digestBase64Url(b,DigestUtils.Algorithm.SHA256));
 	}
 
 }

+ 4 - 1
maxkey-core/src/main/java/org/maxkey/constants/ConstantsProtocols.java

@@ -34,10 +34,13 @@ public final class ConstantsProtocols {
 
     // OAuth
     public static final String OAUTH20 = "OAuth_v2.0";
+    
+    public static final String OAUTH21 = "OAuth_v2.1";
+    
     // SAML
     public static final String SAML20 = "SAML_v2.0";
 
-    public static final String OPEN_ID_CONNECT = "OpenID_Connect";
+    public static final String OPEN_ID_CONNECT10 = "OpenID_Connect_v1.0";
 
     public static final String CAS = "CAS";
     

+ 4 - 2
maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/endpoint/AuthorizeEndpoint.java

@@ -64,8 +64,10 @@ public class AuthorizeEndpoint extends AuthorizeBaseEndpoint{
 			 modelAndView=WebContext.forward("/authz/formbased/"+id);
 		}else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.OAUTH20)){
 			 modelAndView=WebContext.forward("/authz/oauth/v20/"+application.getId());
-		}else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.OPEN_ID_CONNECT)){
-			// modelAndView=new ModelAndView("openid connect");
+		}else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.OAUTH21)){
+		    modelAndView=WebContext.redirect(application.getLoginUrl());
+        }else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.OPEN_ID_CONNECT10)){
+            modelAndView=WebContext.forward("/authz/oauth/v20/"+application.getId());
 		}else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.SAML20)){
 			 modelAndView=WebContext.forward("/authz/saml20/idpinit/"+application.getId());
 		}else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.TOKENBASED)){

+ 12 - 0
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/common/OAuth2Constants.java

@@ -89,9 +89,21 @@ public class OAuth2Constants {
 		public static final String CODE_CHALLENGE_METHOD  = "code_challenge_method" ;
 		
 		public static final String CODE_VERIFIER          = "code_verifier" ;
+		
+		
 		 
 	}
 	
+	public static class PKCE_TYPE{
+	    public static final String PKCE_TYPE_YES          = "YES" ;
+        public static final String PKCE_TYPE_NO           = "NO" ; 
+	}
+	
+	public static class CODE_CHALLENGE_METHOD_TYPE{
+        public static final String PLAIN          = "plain" ;
+        public static final String S256           = "S256" ; 
+    }
+	
 	public static class ENDPOINT{
 		
 		public final static String ENDPOINT_BASE                      = "/authz/oauth/v20";

+ 1 - 1
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/AuthorizationRequest.java

@@ -164,7 +164,7 @@ public class AuthorizationRequest extends BaseRequest implements Serializable {
 	}
 
 	public OAuth2Request createOAuth2Request() {
-		return new OAuth2Request(getRequestParameters(), getClientId(), getAuthorities(), isApproved(), getScope(), getResourceIds(), getRedirectUri(), getResponseTypes(), getExtensions());
+		return new OAuth2Request(getRequestParameters(), getClientId(), getAuthorities(), isApproved(), getScope(), getResourceIds(), getRedirectUri(), getResponseTypes(), getCodeChallenge(),getCodeChallengeMethod(),getExtensions());
 	}
 
 	/**

+ 9 - 5
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/OAuth2Request.java

@@ -102,6 +102,7 @@ public class OAuth2Request extends BaseRequest implements Serializable {
 	public OAuth2Request(Map<String, String> requestParameters, String clientId,
 			Collection<? extends GrantedAuthority> authorities, boolean approved, Set<String> scope,
 			Set<String> resourceIds, String redirectUri, Set<String> responseTypes,
+			String codeChallenge,String codeChallengeMethod,
 			Map<String, Serializable> extensionProperties) {
 		setClientId(clientId);
 		setRequestParameters(requestParameters);
@@ -117,6 +118,8 @@ public class OAuth2Request extends BaseRequest implements Serializable {
 		if (responseTypes != null) {
 			this.responseTypes = new HashSet<String>(responseTypes);
 		}
+		this.codeChallenge = codeChallenge;
+		this.codeChallengeMethod = codeChallengeMethod;
 		this.redirectUri = redirectUri;
 		if (extensionProperties != null) {
 			this.extensions = extensionProperties;
@@ -125,8 +128,9 @@ public class OAuth2Request extends BaseRequest implements Serializable {
 
 	protected OAuth2Request(OAuth2Request other) {
 		this(other.getRequestParameters(), other.getClientId(), other.getAuthorities(), other.isApproved(), other
-				.getScope(), other.getResourceIds(), other.getRedirectUri(), other.getResponseTypes(), other
-				.getExtensions());
+				.getScope(), other.getResourceIds(), other.getRedirectUri(), other.getResponseTypes(),
+				other.getCodeChallenge(),other.getCodeChallengeMethod(),
+				other.getExtensions());
 	}
 
 	protected OAuth2Request(String clientId) {
@@ -177,7 +181,7 @@ public class OAuth2Request extends BaseRequest implements Serializable {
 	 */
 	public OAuth2Request createOAuth2Request(Map<String, String> parameters) {
 		return new OAuth2Request(parameters, getClientId(), authorities, approved, getScope(), resourceIds,
-				redirectUri, responseTypes, extensions);
+				redirectUri, responseTypes,  codeChallenge, codeChallengeMethod,extensions);
 	}
 
 	/**
@@ -189,14 +193,14 @@ public class OAuth2Request extends BaseRequest implements Serializable {
 	 */
 	public OAuth2Request narrowScope(Set<String> scope) {
 		OAuth2Request request = new OAuth2Request(getRequestParameters(), getClientId(), authorities, approved, scope,
-				resourceIds, redirectUri, responseTypes, extensions);
+				resourceIds, redirectUri, responseTypes, codeChallenge, codeChallengeMethod, extensions);
 		request.refresh = this.refresh;
 		return request;
 	}
 
 	public OAuth2Request refresh(TokenRequest tokenRequest) {
 		OAuth2Request request = new OAuth2Request(getRequestParameters(), getClientId(), authorities, approved,
-				getScope(), resourceIds, redirectUri, responseTypes, extensions);
+				getScope(), resourceIds, redirectUri, responseTypes,  codeChallenge, codeChallengeMethod,extensions);
 		request.refresh = tokenRequest;
 		return request;
 	}

+ 1 - 1
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/TokenRequest.java

@@ -110,7 +110,7 @@ public class TokenRequest extends BaseRequest {
 		// Add grant type so it can be retrieved from OAuth2Request
 		 modifiable.put("grant_type", grantType);
 		return new OAuth2Request(modifiable, client.getClientId(), client.getAuthorities(), true, this.getScope(),
-					client.getResourceIds(), null, null, null);
+					client.getResourceIds(), null, null, null, null, null);
 	}
 
 }

+ 42 - 9
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/code/AuthorizationCodeTokenGranter.java

@@ -20,11 +20,14 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.commons.lang3.StringUtils;
+import org.maxkey.authz.oauth2.common.OAuth2Constants;
+import org.maxkey.authz.oauth2.common.OAuth2Constants.CODE_CHALLENGE_METHOD_TYPE;
 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.RedirectMismatchException;
-import org.maxkey.authz.oauth2.common.util.OAuth2Utils;
 import org.maxkey.authz.oauth2.provider.ClientDetailsService;
 import org.maxkey.authz.oauth2.provider.OAuth2Authentication;
 import org.maxkey.authz.oauth2.provider.OAuth2Request;
@@ -32,6 +35,8 @@ import org.maxkey.authz.oauth2.provider.OAuth2RequestFactory;
 import org.maxkey.authz.oauth2.provider.TokenRequest;
 import org.maxkey.authz.oauth2.provider.token.AbstractTokenGranter;
 import org.maxkey.authz.oauth2.provider.token.AuthorizationServerTokenServices;
+import org.maxkey.constants.ConstantsProtocols;
+import org.maxkey.crypto.DigestUtils;
 import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
 import org.springframework.security.core.Authentication;
 
@@ -57,13 +62,15 @@ public class AuthorizationCodeTokenGranter extends AbstractTokenGranter {
 	protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
 
 		Map<String, String> parameters = tokenRequest.getRequestParameters();
-		String authorizationCode = parameters.get("code");
-		String redirectUri = parameters.get(OAuth2Utils.REDIRECT_URI);
+		String authorizationCode = parameters.get(OAuth2Constants.PARAMETER.CODE);
+		String redirectUri = parameters.get(OAuth2Constants.PARAMETER.REDIRECT_URI);
+		String codeVerifier = parameters.get(OAuth2Constants.PARAMETER.CODE_VERIFIER);
 
 		if (authorizationCode == null) {
 			throw new InvalidRequestException("An authorization code must be supplied.");
 		}
-
+		//consume AuthorizationCode
+		logger.trace("consume AuthorizationCode...");
 		OAuth2Authentication storedAuth = authorizationCodeServices.consumeAuthorizationCode(authorizationCode);
 		if (storedAuth == null) {
 			throw new InvalidGrantException("Invalid authorization code: " + authorizationCode);
@@ -72,8 +79,9 @@ public class AuthorizationCodeTokenGranter extends AbstractTokenGranter {
 		OAuth2Request pendingOAuth2Request = storedAuth.getOAuth2Request();
 		// https://jira.springsource.org/browse/SECOAUTH-333
 		// This might be null, if the authorization was done without the redirect_uri parameter
-		String redirectUriApprovalParameter = pendingOAuth2Request.getRequestParameters().get(
-				OAuth2Utils.REDIRECT_URI);
+		String redirectUriApprovalParameter = 
+		        pendingOAuth2Request.getRequestParameters().get(
+		                OAuth2Constants.PARAMETER.REDIRECT_URI);
 
 		String pendingClientId = pendingOAuth2Request.getClientId();
 		String clientId = tokenRequest.getClientId();
@@ -85,7 +93,7 @@ public class AuthorizationCodeTokenGranter extends AbstractTokenGranter {
 		 */
 		Set<String> redirectUris = client.getRegisteredRedirectUri();
 		boolean redirectMismatch=false;
-		
+		//match the stored RedirectUri with request redirectUri parameter
 		for(String storedRedirectUri : redirectUris){
 			if(redirectUri.startsWith(storedRedirectUri)){
 				redirectMismatch=true;
@@ -95,8 +103,8 @@ public class AuthorizationCodeTokenGranter extends AbstractTokenGranter {
 		if ((redirectUri != null || redirectUriApprovalParameter != null)
 				&& !redirectMismatch) {
 			logger.info("storedAuth redirectUri "+pendingOAuth2Request.getRedirectUri());
-			logger.info("redirectUri "+ redirectUri);
-			logger.info("storedRedirectUri "+ redirectUris);
+			logger.info("redirectUri parameter "+ redirectUri);
+			logger.info("stored RedirectUri "+ redirectUris);
 			throw new RedirectMismatchException("Redirect URI mismatch.");
 		}
 		/*
@@ -112,6 +120,31 @@ public class AuthorizationCodeTokenGranter extends AbstractTokenGranter {
 			// just a sanity check.
 			throw new InvalidClientException("Client ID mismatch");
 		}
+		
+		//OAuth 2.1 and PKCE Support
+		logger.debug("client Protocol "+client.getProtocol()+", PKCE Support "+
+		        (client.getPkce().equalsIgnoreCase(OAuth2Constants.PKCE_TYPE.PKCE_TYPE_YES)));
+		if(client.getProtocol().equalsIgnoreCase(ConstantsProtocols.OAUTH21)
+		        || client.getPkce().equalsIgnoreCase(OAuth2Constants.PKCE_TYPE.PKCE_TYPE_YES)) {
+    		logger.trace("stored CodeChallengeMethod "+ pendingOAuth2Request.getCodeChallengeMethod());
+    		logger.trace("stored CodeChallenge "+ pendingOAuth2Request.getCodeChallenge());
+    		logger.trace("stored codeVerifier "+ codeVerifier);
+    		if(StringUtils.isBlank(codeVerifier)) {
+    		    throw new OAuth2Exception("code_verifier can not null.");
+    		}
+    		
+    		if(StringUtils.isBlank(pendingOAuth2Request.getCodeChallenge())) {
+                throw new OAuth2Exception("code_challenge can not null.");
+            }
+    		
+    		if(CODE_CHALLENGE_METHOD_TYPE.S256.equalsIgnoreCase(pendingOAuth2Request.getCodeChallengeMethod())) {
+    		    codeVerifier = DigestUtils.digestBase64Url(codeVerifier,DigestUtils.Algorithm.SHA256);
+    		}
+    		
+    		if(!codeVerifier.equals(pendingOAuth2Request.getCodeChallenge())) {
+                throw new OAuth2Exception("code_verifier not match.");
+            }
+		}
 
 		// Secret is not required in the authorization request, so it won't be available
 		// in the pendingAuthorizationRequest. We do want to check that a secret is provided

+ 34 - 12
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/AuthorizationEndpoint.java

@@ -123,8 +123,11 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
 
 	@ApiOperation(value = "OAuth 2.0 认证接口", notes = "传递参数client_id,response_type,redirect_uri等",httpMethod="GET")
 	@RequestMapping(value = OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE, method = RequestMethod.GET)
-	public ModelAndView authorize(Map<String, Object> model, @RequestParam Map<String, String> parameters,
-			SessionStatus sessionStatus) {
+	public ModelAndView authorize(
+	            Map<String, Object> model, 
+	            @RequestParam Map<String, String> parameters,
+	            SessionStatus sessionStatus) {
+	    
 		 Principal principal=(Principal)WebContext.getAuthentication();
 		// Pull out the authorization request first, using the OAuth2RequestFactory. All further logic should
 		// query off of the authorization request instead of referring back to the parameters map. The contents of the
@@ -152,7 +155,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
 
 			// The resolved redirect URI is either the redirect_uri from the parameters or the one from
 			// clientDetails. Either way we need to store it on the AuthorizationRequest.
-			String redirectUriParameter = authorizationRequest.getRequestParameters().get(OAuth2Utils.REDIRECT_URI);
+			String redirectUriParameter = authorizationRequest.getRequestParameters().get(OAuth2Constants.PARAMETER.REDIRECT_URI);
 			String resolvedRedirect = redirectResolver.resolveRedirect(redirectUriParameter, client);
 			if (!StringUtils.hasText(resolvedRedirect)) {
 				logger.info("Client redirectUri "+resolvedRedirect);
@@ -202,8 +205,11 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
 	}
 
 	@RequestMapping(value = OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE, method = RequestMethod.POST, params = OAuth2Utils.USER_OAUTH_APPROVAL)
-	public View approveOrDeny(@RequestParam Map<String, String> approvalParameters, Map<String, ?> model,
-			SessionStatus sessionStatus) {
+	public View approveOrDeny(
+	                @RequestParam Map<String, String> approvalParameters,
+	                Map<String, ?> model,
+	                SessionStatus sessionStatus) {
+	    
 		Principal principal=(Principal)WebContext.getAuthentication();
 		if (!(principal instanceof Authentication)) {
 			sessionStatus.setComplete();
@@ -233,8 +239,12 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
 			}
 
 			if (!authorizationRequest.isApproved()) {
-				return new RedirectView(getUnsuccessfulRedirect(authorizationRequest,
-						new UserDeniedAuthorizationException("User denied access"), responseTypes.contains(OAuth2Constants.PARAMETER.TOKEN)),
+				return new RedirectView(
+				        getUnsuccessfulRedirect(
+				            authorizationRequest,
+				            new UserDeniedAuthorizationException("User denied access"), 
+				            responseTypes.contains(OAuth2Constants.PARAMETER.TOKEN)
+				        ),
 						false, true, false);
 			}
 
@@ -268,12 +278,24 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
 			if (accessToken == null) {
 				throw new UnsupportedResponseTypeException("Unsupported response type: token");
 			}
-			return new ModelAndView(new RedirectView(appendAccessToken(authorizationRequest, accessToken), false, true,
-					false));
+			return new ModelAndView(
+			        new RedirectView(
+			                appendAccessToken(authorizationRequest, accessToken), 
+			                false, 
+			                true,
+			                false
+			         )
+			 );
 		}
 		catch (OAuth2Exception e) {
-			return new ModelAndView(new RedirectView(getUnsuccessfulRedirect(authorizationRequest, e, true), false,
-					true, false));
+			return new ModelAndView(
+			        new RedirectView(
+			                getUnsuccessfulRedirect(authorizationRequest, e, true), 
+			                false,
+			                true, 
+			                false
+			         )
+			 );
 		}
 	}
 
@@ -331,7 +353,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
 			url.append("&").append(templateUrlVar(OAuth2Constants.PARAMETER.EXPIRES_IN));
 			vars.put(OAuth2Constants.PARAMETER.EXPIRES_IN, expires_in);
 		}
-		String originalScope = authorizationRequest.getRequestParameters().get(OAuth2Utils.SCOPE);
+		String originalScope = authorizationRequest.getRequestParameters().get(OAuth2Constants.PARAMETER.SCOPE);
 		if (originalScope == null || !OAuth2Utils.parseParameterList(originalScope).equals(accessToken.getScope())) {
 			url.append("&").append(templateUrlVar(OAuth2Constants.PARAMETER.SCOPE));
 			vars.put(OAuth2Constants.PARAMETER.SCOPE, OAuth2Utils.formatParameterList(accessToken.getScope()));

+ 2 - 2
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/TokenEndpoint.java

@@ -157,9 +157,9 @@ public class TokenEndpoint extends AbstractEndpoint {
 			 
 			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)));
+				tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Constants.PARAMETER.SCOPE)));
 			}
-	
+			//granter grant access token
 			token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
 			if (token == null) {
 				throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());

+ 1 - 1
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/token/DefaultAccessTokenConverter.java

@@ -161,7 +161,7 @@ public class DefaultAccessTokenConverter implements AccessTokenConverter {
 			authorities = AuthorityUtils.createAuthorityList(roles);
 		}
 		OAuth2Request request = new OAuth2Request(parameters, clientId, authorities, true, scope, resourceIds, null, null,
-				null);
+				null, null, null);
 		return new OAuth2Authentication(request, user);
 	}
 

+ 7 - 0
maxkey-webs/maxkey-web-mgt/src/main/java/org/maxkey/web/apps/contorller/OAuth20DetailsController.java

@@ -17,6 +17,7 @@
 
 package org.maxkey.web.apps.contorller;
 
+import org.maxkey.authz.oauth2.common.OAuth2Constants;
 import org.maxkey.authz.oauth2.provider.client.JdbcClientDetailsService;
 import org.maxkey.constants.ConstantsOperateMessage;
 import org.maxkey.constants.ConstantsProtocols;
@@ -65,6 +66,9 @@ public class OAuth20DetailsController  extends BaseAppContorller {
 	public ModelAndView insert(@ModelAttribute("oauth20Details") AppsOAuth20Details oauth20Details ) {
 		_logger.debug("-Add  :" + oauth20Details);
 		
+		if(oauth20Details.getProtocol().equalsIgnoreCase(ConstantsProtocols.OAUTH21)) {
+		    oauth20Details.setPkce(OAuth2Constants.PKCE_TYPE.PKCE_TYPE_YES);
+		}
 		transform(oauth20Details);
 
 		oauth20Details.setClientSecret(oauth20Details.getSecret());
@@ -103,6 +107,9 @@ public class OAuth20DetailsController  extends BaseAppContorller {
 		//
 		_logger.debug("-update  application :" + oauth20Details);
 		_logger.debug("-update  oauth20Details use oauth20JdbcClientDetails" );
+		if(oauth20Details.getProtocol().equalsIgnoreCase(ConstantsProtocols.OAUTH21)) {
+            oauth20Details.setPkce(OAuth2Constants.PKCE_TYPE.PKCE_TYPE_YES);
+        }
 		oauth20Details.setClientSecret(oauth20Details.getSecret());
         oauth20JdbcClientDetailsService.updateClientDetails(oauth20Details.clientDetailsRowMapper());
         oauth20JdbcClientDetailsService.updateClientSecret(oauth20Details.getClientId(), oauth20Details.getClientSecret());