You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2018/07/17 17:03:59 UTC

[cxf] 05/05: Adding parameterized OAuth 2.0 tests for the EhCache provider, where access tokens are in JWT format

This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 521c0203d22cf82f754c92b1cbe495ed0c73329b
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Tue Jul 17 17:15:50 2018 +0100

    Adding parameterized OAuth 2.0 tests for the EhCache provider, where access tokens are in JWT format
---
 .../systest/jaxrs/security/SecurityTestUtil.java   |  16 +++
 .../oauth2/common/OAuthDataProviderImpl.java       |  10 +-
 .../oauth2/grants/AuthorizationGrantTest.java      | 147 ++++++++++++++++++---
 .../oauth2/grants/BookServerOAuth2Grants.java      |   2 -
 ...2Grants.java => BookServerOAuth2GrantsJWT.java} |   8 +-
 .../security/oauth2/grants/grants-server-jwt.xml   | 145 ++++++++++++++++++++
 6 files changed, 304 insertions(+), 24 deletions(-)

diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/SecurityTestUtil.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/SecurityTestUtil.java
index 118a39f..e3d09b4 100644
--- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/SecurityTestUtil.java
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/SecurityTestUtil.java
@@ -18,6 +18,8 @@
  */
 package org.apache.cxf.systest.jaxrs.security;
 
+import java.io.File;
+
 import javax.crypto.Cipher;
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
@@ -56,4 +58,18 @@ public final class SecurityTestUtil {
         return UNRESTRICTED_POLICIES_INSTALLED;
     }
 
+    public static void cleanup() {
+        String tmpDir = System.getProperty("java.io.tmpdir");
+        if (tmpDir != null) {
+            File[] tmpFiles = new File(tmpDir).listFiles();
+            if (tmpFiles != null) {
+                for (File tmpFile : tmpFiles) {
+                    // Cleanup eh-caches
+                    if (tmpFile.exists() && tmpFile.getName().matches("cxf.*.data")) {
+                        tmpFile.delete();
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuthDataProviderImpl.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuthDataProviderImpl.java
index 67389ec..45901ab 100644
--- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuthDataProviderImpl.java
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuthDataProviderImpl.java
@@ -24,8 +24,10 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Random;
 import java.util.Set;
 
+import org.apache.cxf.BusFactory;
 import org.apache.cxf.common.util.Base64Utility;
 import org.apache.cxf.rs.security.oauth2.common.Client;
 import org.apache.cxf.rs.security.oauth2.common.OAuthPermission;
@@ -47,6 +49,12 @@ public class OAuthDataProviderImpl extends DefaultEHCacheCodeDataProvider {
     }
 
     public OAuthDataProviderImpl(String servicePort, String partnerPort) throws Exception {
+        // Create random cache files, as this provider could be called by several test implementations
+        super(DEFAULT_CONFIG_URL, BusFactory.getThreadDefaultBus(true),
+              CLIENT_CACHE_KEY + "_" + Math.abs(new Random().nextInt()),
+              CODE_GRANT_CACHE_KEY + "_" + Math.abs(new Random().nextInt()),
+              ACCESS_TOKEN_CACHE_KEY + "_" + Math.abs(new Random().nextInt()),
+              REFRESH_TOKEN_CACHE_KEY + "_" + Math.abs(new Random().nextInt()));
         // filters/grants test client
         Client client = new Client("consumer-id", "this-is-a-secret", true);
         List<String> redirectUris = new ArrayList<>();
@@ -152,7 +160,7 @@ public class OAuthDataProviderImpl extends DefaultEHCacheCodeDataProvider {
 
     private Certificate loadCert() throws Exception {
         try (InputStream is = ClassLoaderUtils.getResourceAsStream("keys/Truststore.jks", this.getClass())) {
-            return CryptoUtils.loadCertificate(is, new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}, "morpit", null);
+            return CryptoUtils.loadCertificate(is, "password".toCharArray(), "morpit", null);
         }
     }
 
diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/AuthorizationGrantTest.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/AuthorizationGrantTest.java
index 2fdf4a7..08bbbaa 100644
--- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/AuthorizationGrantTest.java
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/AuthorizationGrantTest.java
@@ -19,39 +19,83 @@
 
 package org.apache.cxf.systest.jaxrs.security.oauth2.grants;
 
+import java.io.IOException;
 import java.net.URL;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
 
 import javax.ws.rs.core.Form;
 import javax.ws.rs.core.Response;
 
 import org.apache.cxf.common.util.Base64UrlUtility;
 import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer;
+import org.apache.cxf.rs.security.jose.jwt.JwtConstants;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
 import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken;
 import org.apache.cxf.rs.security.oauth2.common.OAuthAuthorizationData;
+import org.apache.cxf.systest.jaxrs.security.SecurityTestUtil;
 import org.apache.cxf.systest.jaxrs.security.oauth2.common.OAuth2TestUtils;
 import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
 import org.apache.cxf.testutil.common.TestUtil;
+import org.apache.xml.security.utils.ClassLoaderUtils;
 
+import org.junit.AfterClass;
+import org.junit.Assert;
 import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized.Parameters;
 
 /**
- * Some tests for various authorization grants.
+ * Some tests for various authorization grants. The tests are run multiple times with different OAuthDataProvider
+ * implementations:
+ * a) PORT - EhCache
+ * b) JWT_PORT - EhCache with useJwtFormatForAccessTokens enabled
  */
+@RunWith(value = org.junit.runners.Parameterized.class)
 public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
-    public static final String PORT = BookServerOAuth2Grants.PORT;
+    public static final String PORT = TestUtil.getPortNumber("jaxrs-oauth2-grants");
     public static final String PORT2 = TestUtil.getPortNumber("jaxrs-oauth2-grants2");
+    public static final String JWT_PORT = TestUtil.getPortNumber("jaxrs-oauth2-grants-jwt");
+    public static final String JWT_PORT2 = TestUtil.getPortNumber("jaxrs-oauth2-grants2-jwt");
+
+    final String port;
+
+    public AuthorizationGrantTest(String port) {
+        this.port = port;
+    }
 
     @BeforeClass
     public static void startServers() throws Exception {
         assertTrue("server did not launch correctly",
                    launchServer(BookServerOAuth2Grants.class, true));
+        assertTrue("server did not launch correctly",
+                   launchServer(BookServerOAuth2GrantsJWT.class, true));
+    }
+
+    @AfterClass
+    public static void cleanup() throws Exception {
+        SecurityTestUtil.cleanup();
+    }
+
+    @Parameters(name = "{0}")
+    public static Collection<String> data() {
+
+        return Arrays.asList(PORT, JWT_PORT);
     }
 
     @org.junit.Test
     public void testAuthorizationCodeGrant() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "alice", "security", busFile.toString());
         // Save the Cookie for the second request...
@@ -72,6 +116,10 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
         ClientAccessToken accessToken =
             OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code);
         assertNotNull(accessToken.getTokenKey());
+
+        if (JWT_PORT.equals(port)) {
+            validateAccessToken(accessToken.getTokenKey());
+        }
     }
 
     // The authorization server MUST support the use of the HTTP "GET"
@@ -81,7 +129,7 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
     public void testAuthorizationCodeGrantPOST() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "alice", "security", busFile.toString());
         // Save the Cookie for the second request...
@@ -114,13 +162,17 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
         ClientAccessToken accessToken =
             OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code);
         assertNotNull(accessToken.getTokenKey());
+
+        if (JWT_PORT.equals(port)) {
+            validateAccessToken(accessToken.getTokenKey());
+        }
     }
 
     @org.junit.Test
     public void testAuthorizationCodeGrantRefresh() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "alice", "security", busFile.toString());
         // Save the Cookie for the second request...
@@ -155,13 +207,17 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
         accessToken = response.readEntity(ClientAccessToken.class);
         assertNotNull(accessToken.getTokenKey());
         assertNotNull(accessToken.getRefreshToken());
+
+        if (JWT_PORT.equals(port)) {
+            validateAccessToken(accessToken.getTokenKey());
+        }
     }
 
     @org.junit.Test
     public void testAuthorizationCodeGrantRefreshWithScope() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "alice", "security", busFile.toString());
         // Save the Cookie for the second request...
@@ -197,13 +253,17 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
         accessToken = response.readEntity(ClientAccessToken.class);
         assertNotNull(accessToken.getTokenKey());
         assertNotNull(accessToken.getRefreshToken());
+
+        if (JWT_PORT.equals(port)) {
+            validateAccessToken(accessToken.getTokenKey());
+        }
     }
 
     @org.junit.Test
     public void testAuthorizationCodeGrantWithScope() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "alice", "security", busFile.toString());
         // Save the Cookie for the second request...
@@ -230,7 +290,7 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
     public void testAuthorizationCodeGrantWithState() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "alice", "security", busFile.toString());
         // Save the Cookie for the second request...
@@ -259,7 +319,7 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
     public void testAuthorizationCodeGrantWithAudience() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "alice", "security", busFile.toString());
         // Save the Cookie for the second request...
@@ -277,7 +337,11 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
         WebClient.getConfig(client).getRequestContext().put(
             org.apache.cxf.message.Message.MAINTAIN_SESSION, Boolean.TRUE);
 
-        String audience = "https://localhost:" + PORT2 + "/secured/bookstore/books";
+        String audPort = PORT2;
+        if (JWT_PORT.equals(port)) {
+            audPort = JWT_PORT2;
+        }
+        String audience = "https://localhost:" + audPort + "/secured/bookstore/books";
         ClientAccessToken accessToken =
             OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code,
                                                                 "consumer-id-aud", audience);
@@ -288,7 +352,7 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
     public void testImplicitGrant() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "alice", "security", busFile.toString());
         // Save the Cookie for the second request...
@@ -320,13 +384,17 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
         String location = response.getHeaderString("Location");
         String accessToken = OAuth2TestUtils.getSubstring(location, "access_token");
         assertNotNull(accessToken);
+
+        if (JWT_PORT.equals(port)) {
+            validateAccessToken(accessToken);
+        }
     }
 
     @org.junit.Test
     public void testPasswordsCredentialsGrant() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "consumer-id", "this-is-a-secret",
                                             busFile.toString());
@@ -344,13 +412,17 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
         ClientAccessToken accessToken = response.readEntity(ClientAccessToken.class);
         assertNotNull(accessToken.getTokenKey());
         assertNotNull(accessToken.getRefreshToken());
+
+        if (JWT_PORT.equals(port)) {
+            validateAccessToken(accessToken.getTokenKey());
+        }
     }
 
     @org.junit.Test
     public void testClientCredentialsGrant() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "consumer-id", "this-is-a-secret",
                                             busFile.toString());
@@ -366,13 +438,28 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
         ClientAccessToken accessToken = response.readEntity(ClientAccessToken.class);
         assertNotNull(accessToken.getTokenKey());
         assertNotNull(accessToken.getRefreshToken());
+
+        if (JWT_PORT.equals(port)) {
+            // We don't have a Subject for the client credential grant,
+            // so validate manually here as opposed to calling validateAccessToken
+            JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(accessToken.getTokenKey());
+
+            KeyStore keystore = KeyStore.getInstance("JKS");
+            keystore.load(ClassLoaderUtils.getResourceAsStream("keys/alice.jks", this.getClass()),
+                          "password".toCharArray());
+            Certificate cert = keystore.getCertificate("alice");
+            Assert.assertNotNull(cert);
+
+            Assert.assertTrue(jwtConsumer.verifySignatureWith((X509Certificate)cert,
+                                                              SignatureAlgorithm.RS256));
+        }
     }
 
     @org.junit.Test
     public void testSAMLAuthorizationGrant() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "alice", "security", busFile.toString());
 
@@ -392,19 +479,23 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
         ClientAccessToken accessToken = response.readEntity(ClientAccessToken.class);
         assertNotNull(accessToken.getTokenKey());
         assertNotNull(accessToken.getRefreshToken());
+
+        if (JWT_PORT.equals(port)) {
+            validateAccessToken(accessToken.getTokenKey());
+        }
     }
 
     @org.junit.Test
     public void testJWTAuthorizationGrant() throws Exception {
         URL busFile = AuthorizationGrantTest.class.getResource("client.xml");
 
-        String address = "https://localhost:" + PORT + "/services/";
+        String address = "https://localhost:" + port + "/services/";
         WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
                                             "alice", "security", busFile.toString());
 
         // Create the JWT Token
         String token = OAuth2TestUtils.createToken("DoubleItSTSIssuer", "consumer-id",
-                                   "https://localhost:" + PORT + "/services/token", true, true);
+                                   "https://localhost:" + port + "/services/token", true, true);
 
         // Get Access Token
         client.type("application/x-www-form-urlencoded").accept("application/json");
@@ -419,6 +510,30 @@ public class AuthorizationGrantTest extends AbstractBusClientServerTestBase {
         ClientAccessToken accessToken = response.readEntity(ClientAccessToken.class);
         assertNotNull(accessToken.getTokenKey());
         assertNotNull(accessToken.getRefreshToken());
+
+        if (JWT_PORT.equals(port)) {
+            validateAccessToken(accessToken.getTokenKey());
+        }
+    }
+
+    private void validateAccessToken(String accessToken)
+        throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
+        JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(accessToken);
+        JwtToken jwt = jwtConsumer.getJwtToken();
+
+        // Validate claims
+        Assert.assertNotNull(jwt.getClaim(JwtConstants.CLAIM_SUBJECT));
+        Assert.assertNotNull(jwt.getClaim(JwtConstants.CLAIM_EXPIRY));
+        Assert.assertNotNull(jwt.getClaim(JwtConstants.CLAIM_ISSUED_AT));
+
+        KeyStore keystore = KeyStore.getInstance("JKS");
+        keystore.load(ClassLoaderUtils.getResourceAsStream("keys/alice.jks", this.getClass()),
+                      "password".toCharArray());
+        Certificate cert = keystore.getCertificate("alice");
+        Assert.assertNotNull(cert);
+
+        Assert.assertTrue(jwtConsumer.verifySignatureWith((X509Certificate)cert,
+                                                          SignatureAlgorithm.RS256));
     }
 
 }
diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/BookServerOAuth2Grants.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/BookServerOAuth2Grants.java
index b306c15..6eb4be2 100644
--- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/BookServerOAuth2Grants.java
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/BookServerOAuth2Grants.java
@@ -25,10 +25,8 @@ import org.apache.cxf.Bus;
 import org.apache.cxf.BusFactory;
 import org.apache.cxf.bus.spring.SpringBusFactory;
 import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
-import org.apache.cxf.testutil.common.TestUtil;
 
 public class BookServerOAuth2Grants extends AbstractBusTestServerBase {
-    public static final String PORT = TestUtil.getPortNumber("jaxrs-oauth2-grants");
     private static final URL SERVER_CONFIG_FILE =
         BookServerOAuth2Grants.class.getResource("grants-server.xml");
 
diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/BookServerOAuth2Grants.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/BookServerOAuth2GrantsJWT.java
similarity index 81%
copy from systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/BookServerOAuth2Grants.java
copy to systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/BookServerOAuth2GrantsJWT.java
index b306c15..7f53f8f 100644
--- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/BookServerOAuth2Grants.java
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/BookServerOAuth2GrantsJWT.java
@@ -25,12 +25,10 @@ import org.apache.cxf.Bus;
 import org.apache.cxf.BusFactory;
 import org.apache.cxf.bus.spring.SpringBusFactory;
 import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
-import org.apache.cxf.testutil.common.TestUtil;
 
-public class BookServerOAuth2Grants extends AbstractBusTestServerBase {
-    public static final String PORT = TestUtil.getPortNumber("jaxrs-oauth2-grants");
+public class BookServerOAuth2GrantsJWT extends AbstractBusTestServerBase {
     private static final URL SERVER_CONFIG_FILE =
-        BookServerOAuth2Grants.class.getResource("grants-server.xml");
+        BookServerOAuth2GrantsJWT.class.getResource("grants-server-jwt.xml");
 
     protected void run() {
         SpringBusFactory bf = new SpringBusFactory();
@@ -39,7 +37,7 @@ public class BookServerOAuth2Grants extends AbstractBusTestServerBase {
         setBus(springBus);
 
         try {
-            new BookServerOAuth2Grants();
+            new BookServerOAuth2GrantsJWT();
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
diff --git a/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oauth2/grants/grants-server-jwt.xml b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oauth2/grants/grants-server-jwt.xml
new file mode 100644
index 0000000..388b0eb
--- /dev/null
+++ b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oauth2/grants/grants-server-jwt.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans" 
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+    xmlns:http="http://cxf.apache.org/transports/http/configuration" 
+    xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration" 
+    xmlns:sec="http://cxf.apache.org/configuration/security" 
+    xmlns:cxf="http://cxf.apache.org/core" 
+    xmlns:jaxrs="http://cxf.apache.org/jaxrs" 
+    xmlns:util="http://www.springframework.org/schema/util"
+    xsi:schemaLocation="http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
+             http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
+             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+             http://www.springframework.org/schema/util  http://www.springframework.org/schema/util/spring-util-4.2.xsd
+             http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
+             http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd 
+             http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd">
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
+    <cxf:bus>
+        <cxf:features>
+            <cxf:logging/>
+        </cxf:features>
+        <cxf:properties> 
+          <entry key="org.apache.cxf.jaxrs.bus.providers" value-ref="busProviders"/> 
+        </cxf:properties>
+    </cxf:bus>
+    <!-- providers -->
+    <util:list id="busProviders"> 
+        <ref bean="oauthJson"/> 
+    </util:list> 
+    <bean id="oauthJson" class="org.apache.cxf.rs.security.oauth2.provider.OAuthJSONProvider"/>
+    
+    <httpj:engine-factory id="tls-config">
+        <httpj:engine port="${testutil.ports.jaxrs-oauth2-grants-jwt}">
+            <httpj:tlsServerParameters>
+                <sec:keyManagers keyPassword="password">
+                    <sec:keyStore type="JKS" password="password" resource="keys/Bethal.jks"/>
+                </sec:keyManagers>
+                <sec:trustManagers>
+                    <sec:keyStore type="JKS" password="password" resource="keys/Truststore.jks"/>
+                </sec:trustManagers>
+                <sec:clientAuthentication want="true" required="true"/>
+            </httpj:tlsServerParameters>
+            <httpj:sessionSupport>true</httpj:sessionSupport>
+        </httpj:engine>
+    </httpj:engine-factory>
+    
+   <bean id="oauthProvider" class="org.apache.cxf.systest.jaxrs.security.oauth2.common.OAuthDataProviderImpl">
+       <constructor-arg><value>${testutil.ports.jaxrs-oauth2-grants2-jwt}</value></constructor-arg>
+       <property name="useJwtFormatForAccessTokens" value="true"/>
+   </bean>
+   
+   <bean id="authorizationService" class="org.apache.cxf.rs.security.oauth2.services.AuthorizationCodeGrantService">
+      <property name="dataProvider" ref="oauthProvider"/>
+   </bean>
+   
+   <bean id="implicitService" class="org.apache.cxf.rs.security.oauth2.services.ImplicitGrantService">
+      <property name="dataProvider" ref="oauthProvider"/>
+   </bean>
+   
+   <bean id="refreshGrantHandler" class="org.apache.cxf.rs.security.oauth2.grants.refresh.RefreshTokenGrantHandler">
+      <property name="dataProvider" ref="oauthProvider"/>
+   </bean>
+   
+   <bean id="callbackHandlerLoginHandler" class="org.apache.cxf.systest.jaxrs.security.oauth2.grants.CallbackHandlerLoginHandler">
+      <property name="callbackHandler" ref="callbackHandler"/>
+   </bean>
+   
+   <bean id="passwordGrantHandler" class="org.apache.cxf.rs.security.oauth2.grants.owner.ResourceOwnerGrantHandler">
+      <property name="dataProvider" ref="oauthProvider"/>
+      <property name="loginHandler" ref="callbackHandlerLoginHandler"/>
+   </bean>
+   
+   <bean id="clientCredsGrantHandler" class="org.apache.cxf.rs.security.oauth2.grants.clientcred.ClientCredentialsGrantHandler">
+      <property name="dataProvider" ref="oauthProvider"/>
+   </bean>
+   
+   <bean id="samlGrantHandler" class="org.apache.cxf.rs.security.oauth2.grants.saml.Saml2BearerGrantHandler">
+      <property name="dataProvider" ref="oauthProvider"/>
+   </bean>
+   
+   <bean id="jwtGrantHandler" class="org.apache.cxf.rs.security.oauth2.grants.jwt.JwtBearerGrantHandler">
+      <property name="dataProvider" ref="oauthProvider"/>
+   </bean>
+   
+   <bean id="tokenService" class="org.apache.cxf.rs.security.oauth2.services.AccessTokenService">
+      <property name="dataProvider" ref="oauthProvider"/>
+      <property name="grantHandlers">
+         <list>
+             <ref bean="refreshGrantHandler"/>
+             <ref bean="passwordGrantHandler"/>
+             <ref bean="clientCredsGrantHandler"/>
+             <ref bean="samlGrantHandler"/>
+             <ref bean="jwtGrantHandler"/>
+         </list>
+      </property>
+   </bean>
+   
+   <bean id="callbackHandler" class="org.apache.cxf.systest.jaxrs.security.oauth2.common.CallbackHandlerImpl"/>
+   <bean id="basicAuthFilter" class="org.apache.cxf.systest.jaxrs.security.oauth2.common.WSS4JBasicAuthFilter">
+       <property name="callbackHandler" ref="callbackHandler"/>
+   </bean>
+   
+   <jaxrs:server 
+       depends-on="tls-config" 
+       address="https://localhost:${testutil.ports.jaxrs-oauth2-grants-jwt}/services">
+       <jaxrs:serviceBeans>
+           <ref bean="authorizationService"/>
+           <ref bean="implicitService"/>
+           <ref bean="tokenService"/>
+       </jaxrs:serviceBeans>
+       <jaxrs:providers>
+           <ref bean="basicAuthFilter"/>
+       </jaxrs:providers>
+       <jaxrs:properties>
+           <entry key="security.signature.properties" 
+                  value="org/apache/cxf/systest/jaxrs/security/bob.properties"/>
+           <entry key="rs.security.keystore.type" value="jks" />
+           <entry key="rs.security.keystore.alias" value="alice"/>
+           <entry key="rs.security.keystore.password" value="password"/>
+           <entry key="rs.security.key.password" value="password"/>
+           <entry key="rs.security.keystore.file" value="keys/alice.jks" />
+           <entry key="rs.security.signature.algorithm" value="RS256" />
+       </jaxrs:properties>
+   </jaxrs:server>
+   
+
+</beans>