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/05/07 11:45:25 UTC

[cxf] branch 3.2.x-fixes updated (9d1905c -> 76cead0)

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

coheigea pushed a change to branch 3.2.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git.


    from 9d1905c  CXF-7983: added check for existing, but empty input stream
     new 8e432a2  CXF-8035 - Checking on null values in HTTP Header for protected JWS header
     new 76cead0  Recording .gitmergeinfo Changes

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:
 .gitmergeinfo                                      |   1 +
 .../cxf/rs/security/jose/jaxrs/JoseJaxrsUtils.java |  20 +-
 ...rverJwsJson.java => BookServerHTTPHeaders.java} |  10 +-
 .../security/jose/jwejws/JwsHTTPHeaderTest.java    | 268 +++++++++++++++++++++
 .../security/jose/jwejws/http-headers-server.xml   |  79 ++++++
 5 files changed, 363 insertions(+), 15 deletions(-)
 copy systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/{BookServerJwsJson.java => BookServerHTTPHeaders.java} (86%)
 create mode 100644 systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JwsHTTPHeaderTest.java
 create mode 100644 systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/http-headers-server.xml


[cxf] 02/02: Recording .gitmergeinfo Changes

Posted by co...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch 3.2.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 76cead0f7f38414dd9b603b9f9469011e0ca2d03
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Tue May 7 12:39:16 2019 +0100

    Recording .gitmergeinfo Changes
---
 .gitmergeinfo | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitmergeinfo b/.gitmergeinfo
index 93ff5cd..166f4b2 100644
--- a/.gitmergeinfo
+++ b/.gitmergeinfo
@@ -563,6 +563,7 @@ M ac561c4a2b27bd8b427ff1f91d19c7929a8222ab
 M ad5c6ad246f9155fec7096de7701de02d757c0f2
 M af6a95f5b7efc141cc55792e10d05d471905cf32
 M c13381d891b56fe5a2b56f6f9f6f6b2cc8a10d5d
+M c79d8ac83379b9f80e124823fbb569141cc5e608
 M cb2a360153c6670925f91fdfa9980594715d62e2
 M d1470dd0e14aa001dde1227bfb456a8b4cf0061e
 M d419ae389ab4b42bf57106db99758dd8d3b11bca


[cxf] 01/02: CXF-8035 - Checking on null values in HTTP Header for protected JWS header

Posted by co...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch 3.2.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 8e432a28ef8bbb4278cafb346b32ab1d9547b045
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Tue May 7 12:27:20 2019 +0100

    CXF-8035 - Checking on null values in HTTP Header for protected JWS header
    
    (cherry picked from commit c79d8ac83379b9f80e124823fbb569141cc5e608)
    
    # Conflicts:
    #	rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JoseJaxrsUtils.java
---
 .../cxf/rs/security/jose/jaxrs/JoseJaxrsUtils.java |  20 +-
 .../jose/jwejws/BookServerHTTPHeaders.java         |  59 +++++
 .../security/jose/jwejws/JwsHTTPHeaderTest.java    | 268 +++++++++++++++++++++
 .../security/jose/jwejws/http-headers-server.xml   |  79 ++++++
 4 files changed, 416 insertions(+), 10 deletions(-)

diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JoseJaxrsUtils.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JoseJaxrsUtils.java
index b1f1a38..1f2cc23 100644
--- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JoseJaxrsUtils.java
+++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JoseJaxrsUtils.java
@@ -33,13 +33,13 @@ import org.apache.cxf.rs.security.jose.common.JoseHeaders;
 
 public final class JoseJaxrsUtils {
     private static final String HTTP_PREFIX = "http.";
-    private static final Set<String> DEFAULT_PROTECTED_HTTP_HEADERS = 
+    private static final Set<String> DEFAULT_PROTECTED_HTTP_HEADERS =
         new HashSet<String>(Arrays.asList(HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT));
-    
+
     private JoseJaxrsUtils() {
 
     }
-    
+
     public static void protectHttpHeaders(MultivaluedMap<String, Object> httpHeaders,
                                           JoseHeaders joseHeaders,
                                           Set<String> protectedHttpHeaders) {
@@ -56,7 +56,7 @@ public final class JoseJaxrsUtils {
         }
     }
     private static String getJoseHeaderValue(List<? extends Object> headerValues) {
-        StringBuilder sb = new StringBuilder(); 
+        StringBuilder sb = new StringBuilder();
         for (Object o : headerValues) {
             String[] parts = o.toString().split(",");
             for (String part : parts) {
@@ -66,7 +66,7 @@ public final class JoseJaxrsUtils {
         return sb.toString();
     }
 
-    public static void validateHttpHeaders(MultivaluedMap<String, String> httpHeaders, 
+    public static void validateHttpHeaders(MultivaluedMap<String, String> httpHeaders,
                                            JoseHeaders joseHeaders,
                                            Set<String> protectedHttpHeaders) {
         if (protectedHttpHeaders == null) {
@@ -76,19 +76,19 @@ public final class JoseJaxrsUtils {
         Map<String, String> updatedHttpHeaders = new HashMap<String, String>();
         for (String headerName : protectedHttpHeaders) {
             List<String> headerValues = httpHeaders.get(headerName);
-            if (headerValues != null) {
+            if (headerValues != null && !headerValues.isEmpty() && headerValues.get(0) != null) {
                 String headerValue = getJoseHeaderValue(headerValues);
                 String prefixedHeaderName = HTTP_PREFIX + headerName;
                 updatedHttpHeaders.put(prefixedHeaderName, headerValue);
                 String joseHeaderValue = joseHeaders.getStringProperty(prefixedHeaderName);
                 if (joseHeaderValue != null) {
                     joseHttpHeaders.put(prefixedHeaderName, joseHeaderValue);
-                }    
+                }
             }
-            
+
         }
-        if (joseHttpHeaders.size() != updatedHttpHeaders.size() 
-            || !joseHttpHeaders.entrySet().containsAll(updatedHttpHeaders.entrySet())) { 
+        if (joseHttpHeaders.size() != updatedHttpHeaders.size()
+            || !joseHttpHeaders.entrySet().containsAll(updatedHttpHeaders.entrySet())) {
             throw ExceptionUtils.toBadRequestException(null, null);
         }
     }
diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/BookServerHTTPHeaders.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/BookServerHTTPHeaders.java
new file mode 100644
index 0000000..02462e4
--- /dev/null
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/BookServerHTTPHeaders.java
@@ -0,0 +1,59 @@
+/**
+ * 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.jose.jwejws;
+
+import java.net.URL;
+
+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 BookServerHTTPHeaders extends AbstractBusTestServerBase {
+    public static final String PORT = TestUtil.getPortNumber("jaxrs-jose-httpheaders");
+    private static final URL SERVER_CONFIG_FILE =
+        BookServerHTTPHeaders.class.getResource("http-headers-server.xml");
+
+    protected void run() {
+        SpringBusFactory bf = new SpringBusFactory();
+        Bus springBus = bf.createBus(SERVER_CONFIG_FILE);
+        BusFactory.setDefaultBus(springBus);
+        setBus(springBus);
+
+        try {
+            new BookServerHTTPHeaders();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void main(String[] args) {
+        try {
+            BookServerHTTPHeaders s = new BookServerHTTPHeaders();
+            s.start();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            System.exit(-1);
+        } finally {
+            System.out.println("done!");
+        }
+    }
+}
diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JwsHTTPHeaderTest.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JwsHTTPHeaderTest.java
new file mode 100644
index 0000000..a91411e
--- /dev/null
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JwsHTTPHeaderTest.java
@@ -0,0 +1,268 @@
+/**
+ * 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.jose.jwejws;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
+
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+import org.apache.cxf.phase.Phase;
+import org.apache.cxf.rs.security.jose.jaxrs.JwsWriterInterceptor;
+import org.apache.cxf.systest.jaxrs.security.Book;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+
+import org.junit.BeforeClass;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Some signature tests for signing HTTP Headers
+ */
+public class JwsHTTPHeaderTest extends AbstractBusClientServerTestBase {
+    public static final String PORT = BookServerHTTPHeaders.PORT;
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        assertTrue("server did not launch correctly",
+                   launchServer(BookServerHTTPHeaders.class, true));
+    }
+
+    @org.junit.Test
+    public void testSignHTTPHeaders() throws Exception {
+
+        URL busFile = JwsHTTPHeaderTest.class.getResource("client.xml");
+
+        List<Object> providers = new ArrayList<>();
+        providers.add(new JacksonJsonProvider());
+        JwsWriterInterceptor jwsWriterInterceptor = new JwsWriterInterceptor();
+        providers.add(jwsWriterInterceptor);
+
+        String address = "http://localhost:" + PORT + "/jwsheaderdefault/bookstore/books";
+        WebClient client =
+            WebClient.create(address, providers, busFile.toString());
+        client.type("application/json").accept("application/json");
+
+        Map<String, Object> properties = new HashMap<>();
+        properties.put("rs.security.keystore.type", "jwk");
+        properties.put("rs.security.keystore.alias", "2011-04-29");
+        properties.put("rs.security.keystore.file",
+                       "org/apache/cxf/systest/jaxrs/security/certs/jwkPrivateSet.txt");
+        properties.put("rs.security.signature.algorithm", "RS256");
+        WebClient.getConfig(client).getRequestContext().putAll(properties);
+
+        // Expect failure on not signing the default headers
+        Response response = client.post(new Book("book", 123L));
+        assertNotEquals(response.getStatus(), 200);
+
+        jwsWriterInterceptor.setProtectHttpHeaders(true);
+        response = client.post(new Book("book", 123L));
+        assertEquals(response.getStatus(), 200);
+    }
+
+    @org.junit.Test
+    public void testSpecifyHeadersToSign() throws Exception {
+
+        URL busFile = JwsHTTPHeaderTest.class.getResource("client.xml");
+
+        List<Object> providers = new ArrayList<>();
+        providers.add(new JacksonJsonProvider());
+        JwsWriterInterceptor jwsWriterInterceptor = new JwsWriterInterceptor();
+        jwsWriterInterceptor.setProtectHttpHeaders(true);
+        Set<String> headersToSign = new HashSet<>();
+        headersToSign.add(HttpHeaders.CONTENT_TYPE);
+        jwsWriterInterceptor.setProtectedHttpHeaders(headersToSign);
+        providers.add(jwsWriterInterceptor);
+
+        String address = "http://localhost:" + PORT + "/jwsheaderdefault/bookstore/books";
+        WebClient client =
+            WebClient.create(address, providers, busFile.toString());
+        client.type("application/json").accept("application/json");
+
+        Map<String, Object> properties = new HashMap<>();
+        properties.put("rs.security.keystore.type", "jwk");
+        properties.put("rs.security.keystore.alias", "2011-04-29");
+        properties.put("rs.security.keystore.file",
+                       "org/apache/cxf/systest/jaxrs/security/certs/jwkPrivateSet.txt");
+        properties.put("rs.security.signature.algorithm", "RS256");
+        WebClient.getConfig(client).getRequestContext().putAll(properties);
+
+        // Expect failure on not signing all of the default headers
+        Response response = client.post(new Book("book", 123L));
+        assertNotEquals(response.getStatus(), 200);
+
+        headersToSign.add(HttpHeaders.ACCEPT);
+        response = client.post(new Book("book", 123L));
+        assertEquals(response.getStatus(), 200);
+    }
+
+    @org.junit.Test
+    public void testSignAdditionalCustomHeader() throws Exception {
+
+        URL busFile = JwsHTTPHeaderTest.class.getResource("client.xml");
+
+        List<Object> providers = new ArrayList<>();
+        providers.add(new JacksonJsonProvider());
+        JwsWriterInterceptor jwsWriterInterceptor = new JwsWriterInterceptor();
+        jwsWriterInterceptor.setProtectHttpHeaders(true);
+        Set<String> headersToSign = new HashSet<>();
+        headersToSign.add(HttpHeaders.CONTENT_TYPE);
+        headersToSign.add(HttpHeaders.ACCEPT);
+        headersToSign.add("customheader");
+        jwsWriterInterceptor.setProtectedHttpHeaders(headersToSign);
+        providers.add(jwsWriterInterceptor);
+
+        String address = "http://localhost:" + PORT + "/jwsheaderdefault/bookstore/books";
+        WebClient client =
+            WebClient.create(address, providers, busFile.toString());
+        client.type("application/json").accept("application/json");
+
+        Map<String, Object> properties = new HashMap<>();
+        properties.put("rs.security.keystore.type", "jwk");
+        properties.put("rs.security.keystore.alias", "2011-04-29");
+        properties.put("rs.security.keystore.file",
+                       "org/apache/cxf/systest/jaxrs/security/certs/jwkPrivateSet.txt");
+        properties.put("rs.security.signature.algorithm", "RS256");
+        WebClient.getConfig(client).getRequestContext().putAll(properties);
+        WebClient.getConfig(client).getOutInterceptors().add(new CustomHeaderInterceptor(Phase.PRE_STREAM));
+
+        Response response = client.post(new Book("book", 123L));
+        response = client.post(new Book("book", 123L));
+        assertEquals(response.getStatus(), 200);
+    }
+
+    @org.junit.Test
+    public void testSignCustomHeaderRequired() throws Exception {
+
+        URL busFile = JwsHTTPHeaderTest.class.getResource("client.xml");
+
+        List<Object> providers = new ArrayList<>();
+        providers.add(new JacksonJsonProvider());
+        JwsWriterInterceptor jwsWriterInterceptor = new JwsWriterInterceptor();
+        jwsWriterInterceptor.setProtectHttpHeaders(true);
+        providers.add(jwsWriterInterceptor);
+
+        String address = "http://localhost:" + PORT + "/jwsheadercustom/bookstore/books";
+        WebClient client =
+            WebClient.create(address, providers, busFile.toString());
+        client.type("application/json").accept("application/json");
+
+        Map<String, Object> properties = new HashMap<>();
+        properties.put("rs.security.keystore.type", "jwk");
+        properties.put("rs.security.keystore.alias", "2011-04-29");
+        properties.put("rs.security.keystore.file",
+                       "org/apache/cxf/systest/jaxrs/security/certs/jwkPrivateSet.txt");
+        properties.put("rs.security.signature.algorithm", "RS256");
+        WebClient.getConfig(client).getRequestContext().putAll(properties);
+        WebClient.getConfig(client).getOutInterceptors().add(new CustomHeaderInterceptor(Phase.PRE_STREAM));
+
+        // Expect failure on not signing all of the required headers
+        Response response = client.post(new Book("book", 123L));
+        assertNotEquals(response.getStatus(), 200);
+
+        Set<String> headersToSign = new HashSet<>();
+        headersToSign.add(HttpHeaders.CONTENT_TYPE);
+        headersToSign.add(HttpHeaders.ACCEPT);
+        headersToSign.add("customheader");
+        jwsWriterInterceptor.setProtectedHttpHeaders(headersToSign);
+
+        response = client.post(new Book("book", 123L));
+        response = client.post(new Book("book", 123L));
+        assertEquals(response.getStatus(), 200);
+    }
+
+    @org.junit.Test
+    public void testSignEmptyCustomHeader() throws Exception {
+
+        URL busFile = JwsHTTPHeaderTest.class.getResource("client.xml");
+
+        List<Object> providers = new ArrayList<>();
+        providers.add(new JacksonJsonProvider());
+        JwsWriterInterceptor jwsWriterInterceptor = new JwsWriterInterceptor();
+        jwsWriterInterceptor.setProtectHttpHeaders(true);
+        Set<String> headersToSign = new HashSet<>();
+        headersToSign.add(HttpHeaders.CONTENT_TYPE);
+        headersToSign.add(HttpHeaders.ACCEPT);
+        headersToSign.add("customheader");
+        jwsWriterInterceptor.setProtectedHttpHeaders(headersToSign);
+        providers.add(jwsWriterInterceptor);
+
+        String address = "http://localhost:" + PORT + "/jwsheadercustom/bookstore/books";
+        WebClient client =
+            WebClient.create(address, providers, busFile.toString());
+        client.type("application/json").accept("application/json");
+
+        Map<String, Object> properties = new HashMap<>();
+        properties.put("rs.security.keystore.type", "jwk");
+        properties.put("rs.security.keystore.alias", "2011-04-29");
+        properties.put("rs.security.keystore.file",
+                       "org/apache/cxf/systest/jaxrs/security/certs/jwkPrivateSet.txt");
+        properties.put("rs.security.signature.algorithm", "RS256");
+        WebClient.getConfig(client).getRequestContext().putAll(properties);
+        CustomHeaderInterceptor customHeaderInterceptor = new CustomHeaderInterceptor(Phase.PRE_STREAM);
+        customHeaderInterceptor.setEmpty(true);
+        WebClient.getConfig(client).getOutInterceptors().add(customHeaderInterceptor);
+
+        Response response = client.post(new Book("book", 123L));
+        response = client.post(new Book("book", 123L));
+        assertEquals(response.getStatus(), 200);
+    }
+
+    private static class CustomHeaderInterceptor extends AbstractPhaseInterceptor<Message> {
+
+        private boolean empty;
+
+        CustomHeaderInterceptor(String phase) {
+            super(phase);
+        }
+
+        @Override
+        public void handleMessage(Message message) throws Fault {
+            @SuppressWarnings("unchecked")
+            Map<String, List<?>> headers = (Map<String, List<?>>) message.get(Message.PROTOCOL_HEADERS);
+            headers.put("customheader", empty ? Arrays.asList("") : Arrays.asList("value1", "value2"));
+        }
+
+        public boolean isEmpty() {
+            return empty;
+        }
+
+        public void setEmpty(boolean empty) {
+            this.empty = empty;
+        }
+
+    }
+
+}
diff --git a/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/http-headers-server.xml b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/http-headers-server.xml
new file mode 100644
index 0000000..311d990
--- /dev/null
+++ b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/http-headers-server.xml
@@ -0,0 +1,79 @@
+<?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"
+    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://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 ht [...]
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
+    <cxf:bus>
+        <cxf:features>
+            <cxf:logging/>
+        </cxf:features>
+    </cxf:bus>
+    
+    <bean id="serviceBean" class="org.apache.cxf.systest.jaxrs.security.jose.BookStore"/>
+    
+   <bean id="jwsInFilter" class="org.apache.cxf.rs.security.jose.jaxrs.JwsContainerRequestFilter">
+       <property name="validateHttpHeaders" value="true" />
+   </bean>
+    
+   <jaxrs:server address="http://localhost:${testutil.ports.jaxrs-jose-httpheaders}/jwsheaderdefault">
+       <jaxrs:serviceBeans>
+          <ref bean="serviceBean"/>
+       </jaxrs:serviceBeans>
+       <jaxrs:providers>
+          <ref bean="jwsInFilter"/>
+       </jaxrs:providers>
+       <jaxrs:properties>
+            <entry key="rs.security.signature.in.properties" 
+                   value="org/apache/cxf/systest/jaxrs/security/bob.jwk.properties"/>
+       </jaxrs:properties>
+   </jaxrs:server>
+   
+   <bean id="customHeaderJwsInFilter" class="org.apache.cxf.rs.security.jose.jaxrs.JwsContainerRequestFilter">
+       <property name="validateHttpHeaders" value="true" />
+       <property name="protectedHttpHeaders">
+           <set>
+               <value>Content-Type</value>
+               <value>Accept</value>
+               <value>customheader</value>
+           </set>
+       </property>
+   </bean>
+    
+   <jaxrs:server address="http://localhost:${testutil.ports.jaxrs-jose-httpheaders}/jwsheadercustom">
+       <jaxrs:serviceBeans>
+          <ref bean="serviceBean"/>
+       </jaxrs:serviceBeans>
+       <jaxrs:providers>
+          <ref bean="customHeaderJwsInFilter"/>
+       </jaxrs:providers>
+       <jaxrs:properties>
+            <entry key="rs.security.signature.in.properties" 
+                   value="org/apache/cxf/systest/jaxrs/security/bob.jwk.properties"/>
+       </jaxrs:properties>
+   </jaxrs:server>
+   
+   
+</beans>
\ No newline at end of file