Skip to content
Permalink
Browse files
CXF-8653 - Provide an easy way to require PKCE for the AuthorizationC…
…odeGrantHandler
  • Loading branch information
coheigea committed Feb 4, 2022
1 parent 574d284 commit 9eaf9c462f97402f5a7356db03d949f445f0b8ec
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 28 deletions.
@@ -42,6 +42,7 @@ public class AuthorizationCodeGrantHandler extends AbstractGrantHandler {

private List<CodeVerifierTransformer> codeVerifierTransformers = Collections.emptyList();
private boolean expectCodeVerifierForPublicClients;
private boolean requireCodeVerifier;

public AuthorizationCodeGrantHandler() {
super(OAuthConstants.AUTHORIZATION_CODE_GRANT);
@@ -153,9 +154,11 @@ private ServerAccessToken doCreateAccessToken(Client client,

private boolean compareCodeVerifierWithChallenge(Client c, String clientCodeVerifier,
String clientCodeChallenge, String clientCodeChallengeMethod) {
if (clientCodeChallenge == null && clientCodeVerifier == null
&& (c.isConfidential() || !expectCodeVerifierForPublicClients)) {
return true;
if (clientCodeChallenge == null && clientCodeVerifier == null) {
if (requireCodeVerifier) {
return false;
}
return c.isConfidential() || !expectCodeVerifierForPublicClients;
} else if (clientCodeChallenge != null && clientCodeVerifier == null
|| clientCodeChallenge == null && clientCodeVerifier != null) {
return false;
@@ -191,7 +194,19 @@ public void setCodeVerifierTransformers(List<CodeVerifierTransformer> codeVerifi
this.codeVerifierTransformers = new ArrayList<>(codeVerifierTransformers);
}

/**
* Require a code verifier for public clients only.
* @param expectCodeVerifierForPublicClients require a code verifier for public clients only.
*/
public void setExpectCodeVerifierForPublicClients(boolean expectCodeVerifierForPublicClients) {
this.expectCodeVerifierForPublicClients = expectCodeVerifierForPublicClients;
}

/**
* Require a code verifier (PKCE). This will override any value set for expectCodeVerifierForPublicClients
* @param requireCodeVerifier require a code verifier
*/
public void setRequireCodeVerifier(boolean requireCodeVerifier) {
this.requireCodeVerifier = requireCodeVerifier;
}
}
@@ -84,30 +84,6 @@ public static String[] data() {
JCACHE_PORT_SESSION};
}

@org.junit.Test
public void testAuthorizationCodeGrant() throws Exception {
URL busFile = PublicClientTest.class.getResource("publicclient.xml");

String address = "https://localhost:" + port + "/services/";
WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
"alice", "security", busFile.toString());
// Save the Cookie for the second request...
WebClient.getConfig(client).getRequestContext().put(
org.apache.cxf.message.Message.MAINTAIN_SESSION, Boolean.TRUE);

// Get Authorization Code
String code = OAuth2TestUtils.getAuthorizationCode(client);
assertNotNull(code);

// Now get the access token - note services2 doesn't require basic auth
String address2 = "https://localhost:" + port + "/services2/";
client = WebClient.create(address2, busFile.toString());

ClientAccessToken accessToken =
OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code);
assertNotNull(accessToken.getTokenKey());
}

@org.junit.Test
public void testAuthorizationCodeGrantNoRedirectURI() throws Exception {
URL busFile = PublicClientTest.class.getResource("publicclient.xml");
@@ -121,7 +97,17 @@ public void testAuthorizationCodeGrantNoRedirectURI() throws Exception {

// Get Authorization Code
try {
OAuth2TestUtils.getAuthorizationCode(client, null, "fredPublic");
// Get Authorization Code
AuthorizationCodeParameters parameters = new AuthorizationCodeParameters();
parameters.setConsumerId("fredPublic");
String codeVerifier = Base64UrlUtility.encode(CryptoUtils.generateSecureRandomBytes(32));
CodeVerifierTransformer transformer = new PlainCodeVerifier();
parameters.setCodeChallenge(transformer.transformCodeVerifier(codeVerifier));
parameters.setCodeChallengeMethod(transformer.getChallengeMethod());
parameters.setResponseType(OAuthConstants.CODE_RESPONSE_TYPE);
parameters.setPath("authorize/");

OAuth2TestUtils.getLocation(client, parameters);
fail("Failure expected on a missing (registered) redirectURI");
} catch (Exception ex) {
// expected
@@ -130,6 +130,7 @@ under the License.
<bean id="plainVerifier" class="org.apache.cxf.rs.security.oauth2.grants.code.PlainCodeVerifier" />
<bean id="codeGrantHandler" class="org.apache.cxf.rs.security.oauth2.grants.code.AuthorizationCodeGrantHandler">
<property name="dataProvider" ref="oauthProvider"/>
<property name="requireCodeVerifier" value="true"/>
<property name="codeVerifierTransformers">
<list>
<ref bean="digestVerifier"/>

0 comments on commit 9eaf9c4

Please sign in to comment.