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 2019/11/14 16:14:12 UTC

[cxf] branch master updated (6c137a5 -> 6852cd5)

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

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


    from 6c137a5  [CXF-8158] Fixing checkstyle (take 2)
     new 493eedd  Adding OIDC MetadataService test
     new 6852cd5  Some updates to the OIDC JWK Keys service

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../cxf/rs/security/jose/jwk/JsonWebKeys.java      |   8 +-
 .../apache/cxf/rs/security/jose/jwk/JwkUtils.java  |  32 ++++
 .../apache/cxf/rs/security/jose/jws/JwsUtils.java  |  37 ++--
 .../cxf/rs/security/jose/jws/JwsUtilsTest.java     |   6 +-
 .../cxf/rs/security/oidc/idp/OidcKeysService.java  |  18 +-
 .../jaxrs/security/oidc/OIDCKeysServiceTest.java   | 196 +++++++++++++++++++++
 .../security/oidc/OIDCMetadataServiceTest.java     |  73 ++++++++
 ...erver-dynreg.xml => metadata-server-jcache.xml} |  45 ++---
 .../{oidc-server-jpa.xml => oidc-keys-jcache.xml}  | 159 +++++++++--------
 9 files changed, 447 insertions(+), 127 deletions(-)
 create mode 100644 systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCKeysServiceTest.java
 create mode 100644 systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCMetadataServiceTest.java
 copy systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oidc/{oidc-server-dynreg.xml => metadata-server-jcache.xml} (71%)
 copy systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oidc/{oidc-server-jpa.xml => oidc-keys-jcache.xml} (52%)


[cxf] 01/02: Adding OIDC MetadataService test

Posted by co...@apache.org.
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 493eedd30634d763f7386b469444a5b6824f3a27
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Thu Nov 14 12:44:07 2019 +0000

    Adding OIDC MetadataService test
---
 .../security/oidc/OIDCMetadataServiceTest.java     | 73 +++++++++++++++++++
 .../jaxrs/security/oidc/metadata-server-jcache.xml | 84 ++++++++++++++++++++++
 2 files changed, 157 insertions(+)

diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCMetadataServiceTest.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCMetadataServiceTest.java
new file mode 100644
index 0000000..cac4f24
--- /dev/null
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCMetadataServiceTest.java
@@ -0,0 +1,73 @@
+/**
+ * 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.
+ */
+package org.apache.cxf.systest.jaxrs.security.oidc;
+
+import java.net.URL;
+import java.util.Map;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter;
+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.junit.AfterClass;
+import org.junit.BeforeClass;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Some unit tests for the OIDC/OAuth OidcConfigurationService
+ */
+public class OIDCMetadataServiceTest extends AbstractBusClientServerTestBase {
+
+    private static final SpringBusTestServer JCACHE_SERVER = new SpringBusTestServer("metadata-server-jcache");
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        assertTrue("Server failed to launch", launchServer(JCACHE_SERVER));
+    }
+
+    @AfterClass
+    public static void cleanup() throws Exception {
+        SecurityTestUtil.cleanup();
+    }
+
+    @org.junit.Test
+    public void testOIDCMetadataService() throws Exception {
+        URL busFile = OIDCMetadataServiceTest.class.getResource("client.xml");
+
+        String address = "https://localhost:" + JCACHE_SERVER.getPort() + "/services/.well-known/openid-configuration";
+        WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+                                            "alice", "security", busFile.toString());
+
+        Response response = client.get();
+        assertEquals(200, response.getStatus());
+        String responseStr = response.readEntity(String.class);
+
+        JsonMapObjectReaderWriter reader = new JsonMapObjectReaderWriter();
+        Map<String, Object> json = reader.fromJson(responseStr);
+        assertTrue(json.containsKey("issuer"));
+        assertTrue(json.containsKey("response_types_supported"));
+    }
+
+}
\ No newline at end of file
diff --git a/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oidc/metadata-server-jcache.xml b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oidc/metadata-server-jcache.xml
new file mode 100644
index 0000000..d75ee3e
--- /dev/null
+++ b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oidc/metadata-server-jcache.xml
@@ -0,0 +1,84 @@
+<?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.metadata-server-jcache}">
+            <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="false" required="false"/>
+            </httpj:tlsServerParameters>
+            <httpj:sessionSupport>true</httpj:sessionSupport>
+        </httpj:engine>
+    </httpj:engine-factory>
+    
+   <bean id="metadataService" class="org.apache.cxf.rs.security.oidc.idp.OidcConfigurationService"/>
+   
+   <jaxrs:server 
+       depends-on="tls-config" 
+       address="https://localhost:${testutil.ports.metadata-server-jcache}/services/.well-known">
+        <jaxrs:serviceBeans>
+            <ref bean="metadataService"/>
+        </jaxrs:serviceBeans>
+        <jaxrs: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>


[cxf] 02/02: Some updates to the OIDC JWK Keys service

Posted by co...@apache.org.
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 6852cd5e4927f8e651c0a0589b5ee3f61e753186
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Thu Nov 14 15:24:32 2019 +0000

    Some updates to the OIDC JWK Keys service
---
 .../cxf/rs/security/jose/jwk/JsonWebKeys.java      |   8 +-
 .../apache/cxf/rs/security/jose/jwk/JwkUtils.java  |  32 ++++
 .../apache/cxf/rs/security/jose/jws/JwsUtils.java  |  37 ++--
 .../cxf/rs/security/jose/jws/JwsUtilsTest.java     |   6 +-
 .../cxf/rs/security/oidc/idp/OidcKeysService.java  |  18 +-
 .../jaxrs/security/oidc/OIDCKeysServiceTest.java   | 196 +++++++++++++++++++++
 .../jaxrs/security/oidc/oidc-keys-jcache.xml       | 178 +++++++++++++++++++
 7 files changed, 453 insertions(+), 22 deletions(-)

diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java
index 0542adf..7be2e8a 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java
@@ -35,11 +35,13 @@ public class JsonWebKeys extends JsonMapObject {
 
     }
     public JsonWebKeys(JsonWebKey key) {
-        setInitKey(key);
-    }
-    private void setInitKey(JsonWebKey key) {
         setKey(key);
     }
+
+    public JsonWebKeys(List<JsonWebKey> keys) {
+        setKeys(keys);
+    }
+
     public List<JsonWebKey> getKeys() {
         List<?> list = (List<?>)super.getProperty(KEYS_PROPERTY);
         if (list != null && !list.isEmpty()) {
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java
index 888837e..8b051e6 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java
@@ -37,6 +37,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -319,10 +320,18 @@ public final class JwkUtils {
         }
         return null;
     }
+
     public static List<JsonWebKey> loadJsonWebKeys(Message m,
                                                    Properties props,
                                                    KeyOperation keyOper) {
         PrivateKeyPasswordProvider cb = KeyManagementUtils.loadPasswordProvider(m, props, keyOper);
+        return loadJsonWebKeys(m, props, keyOper, cb);
+    }
+
+    public static List<JsonWebKey> loadJsonWebKeys(Message m,
+                                                   Properties props,
+                                                   KeyOperation keyOper,
+                                                   PrivateKeyPasswordProvider cb) {
         JsonWebKeys jwkSet = loadJwkSet(m, props, cb);
         String kid = KeyManagementUtils.getKeyId(m, props, JoseConstants.RSSEC_KEY_STORE_ALIAS, keyOper);
         if (kid != null) {
@@ -567,4 +576,27 @@ public final class JwkUtils {
             headers.setJsonWebKey(jwkPublic);
         }
     }
+
+    public static List<JsonWebKey> stripPrivateParameters(List<JsonWebKey> keys) {
+        if (keys == null) {
+            return Collections.emptyList();
+        }
+
+        List<JsonWebKey> parsedKeys = new ArrayList<>(keys.size());
+        Iterator<JsonWebKey> iter = keys.iterator();
+        while (iter.hasNext()) {
+            JsonWebKey key = iter.next();
+            if (!(key.containsProperty("k") || key.getKeyType() == KeyType.OCTET)) {
+                // We don't allow secret keys in a public keyset
+                key.removeProperty(JsonWebKey.RSA_PRIVATE_EXP);
+                key.removeProperty(JsonWebKey.RSA_FIRST_PRIME_FACTOR);
+                key.removeProperty(JsonWebKey.RSA_SECOND_PRIME_FACTOR);
+                key.removeProperty(JsonWebKey.RSA_FIRST_PRIME_CRT);
+                key.removeProperty(JsonWebKey.RSA_SECOND_PRIME_CRT);
+                key.removeProperty(JsonWebKey.RSA_FIRST_CRT_COEFFICIENT);
+                parsedKeys.add(key);
+            }
+        }
+        return parsedKeys;
+    }
 }
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
index c571248..8e2d92f 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
@@ -41,6 +41,7 @@ import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageUtils;
 import org.apache.cxf.phase.PhaseInterceptorChain;
 import org.apache.cxf.rs.security.jose.common.JoseConstants;
+import org.apache.cxf.rs.security.jose.common.JoseException;
 import org.apache.cxf.rs.security.jose.common.JoseUtils;
 import org.apache.cxf.rs.security.jose.common.KeyManagementUtils;
 import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils;
@@ -160,8 +161,8 @@ public final class JwsUtils {
             if (algo == null) {
                 LOG.warning("No signature algorithm was defined");
                 throw new JwsException(JwsException.Error.ALGORITHM_NOT_SET);
-            }    
-            
+            }
+
             if (cert.getPublicKey() instanceof RSAPublicKey) {
                 return new PublicKeyJwsSignatureVerifier(cert, algo);
             } else if (cert.getPublicKey() instanceof ECPublicKey) {
@@ -267,8 +268,8 @@ public final class JwsUtils {
         Properties props = loadSignatureInProperties(required);
         return loadSignatureVerifier(props, headers);
     }
-    
-    
+
+
     public static boolean validateCriticalHeaders(JwsHeaders headers) {
         //TODO: validate JWS specific constraints
         return JoseUtils.validateCriticalHeaders(headers);
@@ -278,7 +279,7 @@ public final class JwsUtils {
         return loadSignatureProvider(PhaseInterceptorChain.getCurrentMessage(),
                                      props, headers);
     }
-    
+
     public static JwsSignatureProvider loadSignatureProvider(String propertiesLoc, Bus bus) {
         Properties props = loadSignatureProperties(propertiesLoc, bus);
         return loadSignatureProvider(props, null);
@@ -289,11 +290,11 @@ public final class JwsUtils {
                                                              JwsHeaders headers) {
         JwsSignatureProvider theSigProvider = null;
 
-        boolean includeCert = 
+        boolean includeCert =
             JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT);
-        boolean includeCertSha1 = 
+        boolean includeCertSha1 =
             JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT_SHA1);
-        boolean includeCertSha256 =  
+        boolean includeCertSha256 =
             JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT_SHA256);
         boolean includeKeyId =
             JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_KEY_ID);
@@ -307,8 +308,8 @@ public final class JwsUtils {
                                                              getDefaultKeyAlgorithm(jwk));
                 theSigProvider = JwsUtils.getSignatureProvider(jwk, signatureAlgo);
 
-                boolean includePublicKey = 
-                    JoseUtils.checkBooleanProperty(headers, props, m, 
+                boolean includePublicKey =
+                    JoseUtils.checkBooleanProperty(headers, props, m,
                                                    JoseConstants.RSSEC_SIGNATURE_INCLUDE_PUBLIC_KEY);
 
                 if (includeCert) {
@@ -335,7 +336,7 @@ public final class JwsUtils {
                 if (signatureAlgo == null) {
                     signatureAlgo = getDefaultPrivateKeyAlgorithm(pk);
                 }
-                
+
                 theSigProvider = getPrivateKeySignatureProvider(pk, signatureAlgo);
                 if (includeCert) {
                     headers.setX509Chain(KeyManagementUtils.loadAndEncodeX509CertificateOrChain(m, props));
@@ -344,7 +345,7 @@ public final class JwsUtils {
                     KeyManagementUtils.setSha1DigestHeader(headers, m, props);
                 } else if (includeCertSha256) {
                     KeyManagementUtils.setSha256DigestHeader(headers, m, props);
-                }  
+                }
                 if (includeKeyId && props.containsKey(JoseConstants.RSSEC_KEY_STORE_ALIAS)) {
                     headers.setKeyId(props.getProperty(JoseConstants.RSSEC_KEY_STORE_ALIAS));
                 }
@@ -521,10 +522,20 @@ public final class JwsUtils {
             throw new JwsException(JwsException.Error.INVALID_KEY);
         }
     }
+
+    @Deprecated
     public static JsonWebKeys loadPublicVerificationKeys(Message m, Properties props) {
+        return loadPublicVerificationKeys(m, props, true);
+    }
+
+    public static JsonWebKeys loadPublicVerificationKeys(Message m, Properties props, boolean stripPrivateParameters) {
         String storeType = props.getProperty(JoseConstants.RSSEC_KEY_STORE_TYPE);
         if ("jwk".equals(storeType)) {
-            return JwkUtils.loadPublicJwkSet(m, props);
+            List<JsonWebKey> jsonWebKeys = JwkUtils.loadJsonWebKeys(m, props, KeyOperation.SIGN, null);
+            if (jsonWebKeys == null || jsonWebKeys.isEmpty()) {
+                throw new JoseException("Error loading keys");
+            }
+            return new JsonWebKeys(stripPrivateParameters ? JwkUtils.stripPrivateParameters(jsonWebKeys) : jsonWebKeys);
         }
         X509Certificate[] certs = null;
         if (PropertyUtils.isTrue(props.get(JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT))) {
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsUtilsTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsUtilsTest.java
index c28fe43..4ba20f2 100644
--- a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsUtilsTest.java
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsUtilsTest.java
@@ -92,7 +92,7 @@ public class JwsUtilsTest {
             "org/apache/cxf/rs/security/jose/jws/alice.jks");
         p.put(JoseConstants.RSSEC_KEY_STORE_PSWD, "password");
         p.put(JoseConstants.RSSEC_KEY_STORE_ALIAS, "alice");
-        JsonWebKeys keySet = JwsUtils.loadPublicVerificationKeys(createMessage(), p);
+        JsonWebKeys keySet = JwsUtils.loadPublicVerificationKeys(createMessage(), p, true);
         assertEquals(1, keySet.asMap().size());
         List<JsonWebKey> keys = keySet.getRsaKeys();
         assertEquals(1, keys.size());
@@ -112,7 +112,7 @@ public class JwsUtilsTest {
         p.put(JoseConstants.RSSEC_KEY_STORE_PSWD, "password");
         p.put(JoseConstants.RSSEC_KEY_STORE_ALIAS, "alice");
         p.put(JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT, true);
-        JsonWebKeys keySet = JwsUtils.loadPublicVerificationKeys(createMessage(), p);
+        JsonWebKeys keySet = JwsUtils.loadPublicVerificationKeys(createMessage(), p, true);
         assertEquals(1, keySet.asMap().size());
         List<JsonWebKey> keys = keySet.getRsaKeys();
         assertEquals(1, keys.size());
@@ -136,4 +136,4 @@ public class JwsUtilsTest {
         e.setInMessage(m);
         return m;
     }
-}
\ No newline at end of file
+}
diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/OidcKeysService.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/OidcKeysService.java
index fc1f0c7..ea5ad91 100644
--- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/OidcKeysService.java
+++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/OidcKeysService.java
@@ -34,13 +34,14 @@ public class OidcKeysService {
 
     private volatile JsonWebKeys keySet;
     private WebClient keyServiceClient;
+    private boolean stripPrivateParameters = true;
 
     @GET
     @Produces("application/json")
     public JsonWebKeys getPublicVerificationKeys() {
         if (keySet == null) {
             if (keyServiceClient == null) {
-                keySet = getFromLocalStore();
+                keySet = getFromLocalStore(stripPrivateParameters);
             } else {
                 keySet = keyServiceClient.get(JsonWebKeys.class);
             }
@@ -49,13 +50,24 @@ public class OidcKeysService {
         return keySet;
     }
 
-    private static JsonWebKeys getFromLocalStore() {
+    private static JsonWebKeys getFromLocalStore(boolean stripPrivateParameters) {
         Properties props = JwsUtils.loadSignatureInProperties(true);
-        return JwsUtils.loadPublicVerificationKeys(JAXRSUtils.getCurrentMessage(), props);
+        return JwsUtils.loadPublicVerificationKeys(JAXRSUtils.getCurrentMessage(), props, stripPrivateParameters);
     }
 
     public void setKeyServiceClient(WebClient keyServiceClient) {
         this.keyServiceClient = keyServiceClient;
     }
 
+    public boolean isStripPrivateParameters() {
+        return stripPrivateParameters;
+    }
+
+    /**
+     * Whether to strip private parameters from the keys that are returned. The default is true.
+     */
+    public void setStripPrivateParameters(boolean stripPrivateParameters) {
+        this.stripPrivateParameters = stripPrivateParameters;
+    }
+
 }
diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCKeysServiceTest.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCKeysServiceTest.java
new file mode 100644
index 0000000..3144c4a
--- /dev/null
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCKeysServiceTest.java
@@ -0,0 +1,196 @@
+/**
+ * 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.
+ */
+package org.apache.cxf.systest.jaxrs.security.oidc;
+
+import java.net.URL;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKeys;
+import org.apache.cxf.rs.security.jose.jwk.KeyType;
+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.junit.AfterClass;
+import org.junit.BeforeClass;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Some tests for the OIDC Keys Service
+ */
+public class OIDCKeysServiceTest extends AbstractBusClientServerTestBase {
+
+    private static final SpringBusTestServer JCACHE_SERVER = new SpringBusTestServer("oidc-keys-jcache");
+
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        assertTrue("Server failed to launch", launchServer(JCACHE_SERVER));
+    }
+
+    @AfterClass
+    public static void cleanup() throws Exception {
+        SecurityTestUtil.cleanup();
+    }
+
+    @org.junit.Test
+    public void testGetRSAPublicKey() throws Exception {
+        URL busFile = OIDCFlowTest.class.getResource("client.xml");
+
+        String address = "https://localhost:" + JCACHE_SERVER.getPort() + "/services/";
+        WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+                                            "alice", "security", busFile.toString());
+        client.accept("application/json");
+
+        client.path("keys/");
+        Response response = client.get();
+        JsonWebKeys jsonWebKeys = response.readEntity(JsonWebKeys.class);
+
+        assertEquals(1, jsonWebKeys.getKeys().size());
+
+        JsonWebKey jsonWebKey = jsonWebKeys.getKeys().get(0);
+        assertEquals(KeyType.RSA, jsonWebKey.getKeyType());
+        assertEquals("alice", jsonWebKey.getKeyId());
+        assertNotNull(jsonWebKey.getProperty("n"));
+        assertNotNull(jsonWebKey.getProperty("e"));
+        // Check we don't send the private key back
+        checkPrivateKeyParametersNotPresent(jsonWebKeys);
+    }
+
+    @org.junit.Test
+    public void testGetJWKRSAPublicKey() throws Exception {
+        URL busFile = OIDCFlowTest.class.getResource("client.xml");
+
+        String address = "https://localhost:" + JCACHE_SERVER.getPort() + "/services2/";
+        WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+                                            "alice", "security", busFile.toString());
+        client.accept("application/json");
+
+        client.path("keys/");
+        Response response = client.get();
+        JsonWebKeys jsonWebKeys = response.readEntity(JsonWebKeys.class);
+
+        assertEquals(1, jsonWebKeys.getKeys().size());
+
+        JsonWebKey jsonWebKey = jsonWebKeys.getKeys().get(0);
+        assertEquals(KeyType.RSA, jsonWebKey.getKeyType());
+        assertEquals("2011-04-29", jsonWebKey.getKeyId());
+        assertNotNull(jsonWebKey.getProperty("n"));
+        assertNotNull(jsonWebKey.getProperty("e"));
+        // Check we don't send the private key back
+        checkPrivateKeyParametersNotPresent(jsonWebKeys);
+    }
+
+    @org.junit.Test
+    public void testGetJWKECPublicKey() throws Exception {
+        URL busFile = OIDCFlowTest.class.getResource("client.xml");
+
+        String address = "https://localhost:" + JCACHE_SERVER.getPort() + "/services3/";
+        WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+                                            "alice", "security", busFile.toString());
+        client.accept("application/json");
+
+        client.path("keys/");
+        Response response = client.get();
+        JsonWebKeys jsonWebKeys = response.readEntity(JsonWebKeys.class);
+
+        assertEquals(1, jsonWebKeys.getKeys().size());
+
+        JsonWebKey jsonWebKey = jsonWebKeys.getKeys().get(0);
+        assertEquals(KeyType.EC, jsonWebKey.getKeyType());
+        assertEquals("ECKey", jsonWebKey.getKeyId());
+        assertNotNull(jsonWebKey.getProperty("x"));
+        assertNotNull(jsonWebKey.getProperty("y"));
+        // Check we don't send the private key back
+        checkPrivateKeyParametersNotPresent(jsonWebKeys);
+    }
+
+    @org.junit.Test
+    public void testGetJWKHMAC() throws Exception {
+        URL busFile = OIDCFlowTest.class.getResource("client.xml");
+
+        String address = "https://localhost:" + JCACHE_SERVER.getPort() + "/services4/";
+        WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+                                            "alice", "security", busFile.toString());
+        client.accept("application/json");
+
+        client.path("keys/");
+        Response response = client.get();
+        JsonWebKeys jsonWebKeys = response.readEntity(JsonWebKeys.class);
+
+        // We don't allow sending secret keys back from the key service by default
+        assertNull(jsonWebKeys.getKeys());
+    }
+
+    @org.junit.Test
+    public void testGetJWKHMACExplicitlyAllowed() throws Exception {
+        URL busFile = OIDCFlowTest.class.getResource("client.xml");
+
+        String address = "https://localhost:" + JCACHE_SERVER.getPort() + "/services5/";
+        WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+                                            "alice", "security", busFile.toString());
+        client.accept("application/json");
+
+        client.path("keys/");
+        Response response = client.get();
+        JsonWebKeys jsonWebKeys = response.readEntity(JsonWebKeys.class);
+
+        // Here we explicitly allow sending back secret keys
+        assertEquals(1, jsonWebKeys.getKeys().size());
+    }
+
+    @org.junit.Test
+    public void testGetJWKMultipleKeys() throws Exception {
+        URL busFile = OIDCFlowTest.class.getResource("client.xml");
+
+        String address = "https://localhost:" + JCACHE_SERVER.getPort() + "/services6/";
+        WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+                                            "alice", "security", busFile.toString());
+        client.accept("application/json");
+
+        client.path("keys/");
+        Response response = client.get();
+        JsonWebKeys jsonWebKeys = response.readEntity(JsonWebKeys.class);
+
+        assertEquals(2, jsonWebKeys.getKeys().size());
+
+        // Check we don't send the private key back
+        checkPrivateKeyParametersNotPresent(jsonWebKeys);
+    }
+
+    private void checkPrivateKeyParametersNotPresent(JsonWebKeys jsonWebKeys) {
+        for (JsonWebKey jsonWebKey : jsonWebKeys.getKeys()) {
+            assertNull(jsonWebKey.getProperty("d"));
+            assertNull(jsonWebKey.getProperty("p"));
+            assertNull(jsonWebKey.getProperty("q"));
+            assertNull(jsonWebKey.getProperty("dp"));
+            assertNull(jsonWebKey.getProperty("dq"));
+            assertNull(jsonWebKey.getProperty("qi"));
+        }
+    }
+
+
+}
\ No newline at end of file
diff --git a/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oidc/oidc-keys-jcache.xml b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oidc/oidc-keys-jcache.xml
new file mode 100644
index 0000000..19647b7
--- /dev/null
+++ b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oidc/oidc-keys-jcache.xml
@@ -0,0 +1,178 @@
+<?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.oidc-keys-jcache}">
+            <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="false" required="false"/>
+            </httpj:tlsServerParameters>
+            <httpj:sessionSupport>true</httpj:sessionSupport>
+        </httpj:engine>
+    </httpj:engine-factory>
+    
+   <bean id="oidcKeysService" class="org.apache.cxf.rs.security.oidc.idp.OidcKeysService"/>
+   
+   <jaxrs:server 
+       depends-on="tls-config" 
+       address="https://localhost:${testutil.ports.oidc-keys-jcache}/services">
+       <jaxrs:serviceBeans>
+           <ref bean="oidcKeysService"/>
+       </jaxrs:serviceBeans>
+       <jaxrs:providers>
+           <bean class="org.apache.cxf.rs.security.jose.jaxrs.JsonWebKeysProvider"/>
+       </jaxrs:providers>
+       <jaxrs: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" />
+       </jaxrs:properties>
+   </jaxrs:server>
+   
+   <bean id="oidcKeysService2" class="org.apache.cxf.rs.security.oidc.idp.OidcKeysService"/>
+   
+   <jaxrs:server 
+       depends-on="tls-config" 
+       address="https://localhost:${testutil.ports.oidc-keys-jcache}/services2">
+       <jaxrs:serviceBeans>
+           <ref bean="oidcKeysService2"/>
+       </jaxrs:serviceBeans>
+       <jaxrs:providers>
+           <bean class="org.apache.cxf.rs.security.jose.jaxrs.JsonWebKeysProvider"/>
+       </jaxrs:providers>
+       <jaxrs:properties>
+            <entry key="rs.security.keystore.type" value="jwk" />
+            <entry key="rs.security.keystore.alias" value="2011-04-29"/>
+            <entry key="rs.security.keystore.file" value="org/apache/cxf/systest/jaxrs/security/certs/jwkPrivateSet.txt" />
+       </jaxrs:properties>
+   </jaxrs:server>
+   
+   <bean id="oidcKeysService3" class="org.apache.cxf.rs.security.oidc.idp.OidcKeysService"/>
+   
+   <jaxrs:server 
+       depends-on="tls-config" 
+       address="https://localhost:${testutil.ports.oidc-keys-jcache}/services3">
+       <jaxrs:serviceBeans>
+           <ref bean="oidcKeysService3"/>
+       </jaxrs:serviceBeans>
+       <jaxrs:providers>
+           <bean class="org.apache.cxf.rs.security.jose.jaxrs.JsonWebKeysProvider"/>
+       </jaxrs:providers>
+       <jaxrs:properties>
+            <entry key="rs.security.keystore.type" value="jwk" />
+            <entry key="rs.security.keystore.alias" value="ECKey"/>
+            <entry key="rs.security.keystore.file" value="org/apache/cxf/systest/jaxrs/security/certs/jwkPrivateSet.txt" />
+       </jaxrs:properties>
+   </jaxrs:server>
+   
+   <bean id="oidcKeysService4" class="org.apache.cxf.rs.security.oidc.idp.OidcKeysService"/>
+   
+   <jaxrs:server 
+       depends-on="tls-config" 
+       address="https://localhost:${testutil.ports.oidc-keys-jcache}/services4">
+       <jaxrs:serviceBeans>
+           <ref bean="oidcKeysService4"/>
+       </jaxrs:serviceBeans>
+       <jaxrs:providers>
+           <bean class="org.apache.cxf.rs.security.jose.jaxrs.JsonWebKeysProvider"/>
+       </jaxrs:providers>
+       <jaxrs:properties>
+            <entry key="rs.security.keystore.type" value="jwk" />
+            <entry key="rs.security.keystore.alias" value="HMAC512Key"/>
+            <entry key="rs.security.keystore.file" value="org/apache/cxf/systest/jaxrs/security/certs/jwkPrivateSet.txt" />
+       </jaxrs:properties>
+   </jaxrs:server>
+   
+   <bean id="oidcKeysService5" class="org.apache.cxf.rs.security.oidc.idp.OidcKeysService">
+       <property name="stripPrivateParameters" value="false"/>
+   </bean>
+   
+   <jaxrs:server 
+       depends-on="tls-config" 
+       address="https://localhost:${testutil.ports.oidc-keys-jcache}/services5">
+       <jaxrs:serviceBeans>
+           <ref bean="oidcKeysService5"/>
+       </jaxrs:serviceBeans>
+       <jaxrs:providers>
+           <bean class="org.apache.cxf.rs.security.jose.jaxrs.JsonWebKeysProvider"/>
+       </jaxrs:providers>
+       <jaxrs:properties>
+            <entry key="rs.security.keystore.type" value="jwk" />
+            <entry key="rs.security.keystore.alias" value="HMAC512Key"/>
+            <entry key="rs.security.keystore.file" value="org/apache/cxf/systest/jaxrs/security/certs/jwkPrivateSet.txt" />
+       </jaxrs:properties>
+   </jaxrs:server>
+   
+    
+   <bean id="oidcKeysService6" class="org.apache.cxf.rs.security.oidc.idp.OidcKeysService"/>
+   
+   <jaxrs:server 
+       depends-on="tls-config" 
+       address="https://localhost:${testutil.ports.oidc-keys-jcache}/services6">
+       <jaxrs:serviceBeans>
+           <ref bean="oidcKeysService6"/>
+       </jaxrs:serviceBeans>
+       <jaxrs:providers>
+           <bean class="org.apache.cxf.rs.security.jose.jaxrs.JsonWebKeysProvider"/>
+       </jaxrs:providers>
+        <jaxrs:properties>
+            <entry key="rs.security.keystore.type" value="jwk" />
+            <entry key="rs.security.keystore.aliases" value="2011-04-29,ECKey"/>
+            <entry key="rs.security.keystore.file" value="org/apache/cxf/systest/jaxrs/security/certs/jwkPrivateSet.txt" />
+       </jaxrs:properties>
+   </jaxrs:server>
+   
+</beans>