Repository: cxf Updated Branches: refs/heads/3.1.x-fixes 6e89af732 -> 45ca76a25
[CXF-7366] Adding a negative test, updating JWE filters too Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/45ca76a2 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/45ca76a2 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/45ca76a2 Branch: refs/heads/3.1.x-fixes Commit: 45ca76a2502fe1a4f05e49c870035be0297d9142 Parents: 6e89af7 Author: Sergey Beryozkin <sberyoz...@gmail.com> Authored: Thu May 11 11:38:18 2017 +0100 Committer: Sergey Beryozkin <sberyoz...@gmail.com> Committed: Thu May 11 12:18:13 2017 +0100 ---------------------------------------------------------------------- .../jose/jaxrs/AbstractJweDecryptingFilter.java | 20 +++++ .../jaxrs/AbstractJweJsonDecryptingFilter.java | 22 ++++- .../jaxrs/AbstractJwsJsonReaderProvider.java | 32 +------ .../jose/jaxrs/AbstractJwsReaderProvider.java | 35 +------- .../rs/security/jose/jaxrs/JoseJaxrsUtils.java | 95 ++++++++++++++++++++ .../jose/jaxrs/JweClientResponseFilter.java | 5 +- .../jose/jaxrs/JweContainerRequestFilter.java | 3 + .../jose/jaxrs/JweJsonClientResponseFilter.java | 3 + .../jaxrs/JweJsonContainerRequestFilter.java | 3 + .../jose/jaxrs/JweJsonWriterInterceptor.java | 23 ++++- .../jose/jaxrs/JweWriterInterceptor.java | 23 ++++- .../jose/jaxrs/JwsJsonWriterInterceptor.java | 22 +---- .../jose/jaxrs/JwsWriterInterceptor.java | 16 +--- .../systest/jaxrs/security/jose/BookStore.java | 2 +- .../jose/jwejws/HttpHeaderModifyingFilter.java | 42 +++++++++ .../security/jose/jwejws/JAXRSJweJwsTest.java | 9 ++ .../jaxrs/security/jose/jwejws/server.xml | 2 + 17 files changed, 260 insertions(+), 97 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweDecryptingFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweDecryptingFilter.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweDecryptingFilter.java index d28b1b7..7e2f066 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweDecryptingFilter.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweDecryptingFilter.java @@ -21,6 +21,9 @@ package org.apache.cxf.rs.security.jose.jaxrs; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.util.Set; + +import javax.ws.rs.core.MultivaluedMap; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.rs.security.jose.common.JoseUtils; @@ -31,6 +34,8 @@ import org.apache.cxf.rs.security.jose.jwe.JweHeaders; import org.apache.cxf.rs.security.jose.jwe.JweUtils; public class AbstractJweDecryptingFilter { + private Set<String> protectedHttpHeaders; + private boolean validateHttpHeaders; private JweDecryptionProvider decryption; private String defaultMediaType; protected JweDecryptionOutput decrypt(InputStream is) throws IOException { @@ -63,4 +68,19 @@ public class AbstractJweDecryptingFilter { this.defaultMediaType = defaultMediaType; } + public void setValidateHttpHeaders(boolean validateHttpHeaders) { + this.validateHttpHeaders = validateHttpHeaders; + } + public boolean isValidateHttpHeaders() { + return validateHttpHeaders; + } + + protected void validateHttpHeadersIfNeeded(MultivaluedMap<String, String> httpHeaders, JweHeaders jweHeaders) { + JoseJaxrsUtils.validateHttpHeaders(httpHeaders, + jweHeaders, + protectedHttpHeaders); + } + public void setProtectedHttpHeaders(Set<String> protectedHttpHeaders) { + this.protectedHttpHeaders = protectedHttpHeaders; + } } http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweJsonDecryptingFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweJsonDecryptingFilter.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweJsonDecryptingFilter.java index 8bfc807..9180ad9 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweJsonDecryptingFilter.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweJsonDecryptingFilter.java @@ -22,6 +22,9 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Map; +import java.util.Set; + +import javax.ws.rs.core.MultivaluedMap; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.jaxrs.utils.JAXRSUtils; @@ -34,6 +37,8 @@ import org.apache.cxf.rs.security.jose.jwe.JweJsonEncryptionEntry; import org.apache.cxf.rs.security.jose.jwe.JweUtils; public class AbstractJweJsonDecryptingFilter { + private Set<String> protectedHttpHeaders; + private boolean validateHttpHeaders; private JweDecryptionProvider decryption; private String defaultMediaType; private Map<String, Object> recipientProperties; @@ -74,6 +79,21 @@ public class AbstractJweJsonDecryptingFilter { public void setRecipientProperties(Map<String, Object> recipientProperties) { this.recipientProperties = recipientProperties; - } + } + + public void setValidateHttpHeaders(boolean validateHttpHeaders) { + this.validateHttpHeaders = validateHttpHeaders; + } + public boolean isValidateHttpHeaders() { + return validateHttpHeaders; + } + protected void validateHttpHeadersIfNeeded(MultivaluedMap<String, String> httpHeaders, JweHeaders jweHeaders) { + JoseJaxrsUtils.validateHttpHeaders(httpHeaders, + jweHeaders, + protectedHttpHeaders); + } + public void setProtectedHttpHeaders(Set<String> protectedHttpHeaders) { + this.protectedHttpHeaders = protectedHttpHeaders; + } } http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsJsonReaderProvider.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsJsonReaderProvider.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsJsonReaderProvider.java index 8185bc7..8f2103b 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsJsonReaderProvider.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsJsonReaderProvider.java @@ -18,16 +18,12 @@ */ package org.apache.cxf.rs.security.jose.jaxrs; -import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; -import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MultivaluedMap; import org.apache.cxf.common.logging.LogUtils; @@ -41,9 +37,7 @@ import org.apache.cxf.rs.security.jose.jws.JwsUtils; public class AbstractJwsJsonReaderProvider { protected static final Logger LOG = LogUtils.getL7dLogger(AbstractJwsJsonReaderProvider.class); - private static final Set<String> DEFAULT_PROTECTED_HTTP_HEADERS = - new HashSet<String>(Arrays.asList(HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT)); - private Set<String> protectedHttpHeaders = DEFAULT_PROTECTED_HTTP_HEADERS; + private Set<String> protectedHttpHeaders; private boolean validateHttpHeaders; private JwsSignatureVerifier sigVerifier; private String defaultMediaType; @@ -95,27 +89,9 @@ public class AbstractJwsJsonReaderProvider { } protected void validateHttpHeadersIfNeeded(MultivaluedMap<String, String> httpHeaders, JwsHeaders jwsHeaders) { - Map<String, String> jwsHttpHeaders = new HashMap<String, String>(); - Map<String, String> updatedHttpHeaders = new HashMap<String, String>(); - final String prefix = "http."; - for (String headerName : protectedHttpHeaders) { - List<String> headerValues = httpHeaders.get(headerName); - if (headerValues != null) { - String headerValue = headerValues.size() > 1 ? headerValues.toString() - : headerValues.get(0).toString(); - String prefixedHeaderName = prefix + headerName; - updatedHttpHeaders.put(prefixedHeaderName, headerValue); - String jwsHeaderValue = jwsHeaders.getStringProperty(prefixedHeaderName); - if (jwsHeaderValue != null) { - jwsHttpHeaders.put(prefixedHeaderName, jwsHeaderValue); - } - } - - } - if (jwsHttpHeaders.size() != updatedHttpHeaders.size() - || !jwsHttpHeaders.entrySet().containsAll(updatedHttpHeaders.entrySet())) { - throw new JwsException(JwsException.Error.INVALID_SIGNATURE); - } + JoseJaxrsUtils.validateHttpHeaders(httpHeaders, + jwsHeaders, + protectedHttpHeaders); } public void setProtectedHttpHeaders(Set<String> protectedHttpHeaders) { this.protectedHttpHeaders = protectedHttpHeaders; http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsReaderProvider.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsReaderProvider.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsReaderProvider.java index 5a58a49..124333a 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsReaderProvider.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsReaderProvider.java @@ -18,26 +18,17 @@ */ package org.apache.cxf.rs.security.jose.jaxrs; -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.MultivaluedMap; import org.apache.cxf.rs.security.jose.common.JoseUtils; -import org.apache.cxf.rs.security.jose.jws.JwsException; import org.apache.cxf.rs.security.jose.jws.JwsHeaders; import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier; import org.apache.cxf.rs.security.jose.jws.JwsUtils; public class AbstractJwsReaderProvider { - private static final Set<String> DEFAULT_PROTECTED_HTTP_HEADERS = - new HashSet<String>(Arrays.asList(HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT)); - private Set<String> protectedHttpHeaders = DEFAULT_PROTECTED_HTTP_HEADERS; + private Set<String> protectedHttpHeaders; private boolean validateHttpHeaders; private JwsSignatureVerifier sigVerifier; @@ -71,27 +62,9 @@ public class AbstractJwsReaderProvider { } protected void validateHttpHeadersIfNeeded(MultivaluedMap<String, String> httpHeaders, JwsHeaders jwsHeaders) { - Map<String, String> jwsHttpHeaders = new HashMap<String, String>(); - Map<String, String> updatedHttpHeaders = new HashMap<String, String>(); - final String prefix = "http."; - for (String headerName : protectedHttpHeaders) { - List<String> headerValues = httpHeaders.get(headerName); - if (headerValues != null) { - String headerValue = headerValues.size() > 1 ? headerValues.toString() - : headerValues.get(0).toString(); - String prefixedHeaderName = prefix + headerName; - updatedHttpHeaders.put(prefixedHeaderName, headerValue); - String jwsHeaderValue = jwsHeaders.getStringProperty(prefixedHeaderName); - if (jwsHeaderValue != null) { - jwsHttpHeaders.put(prefixedHeaderName, jwsHeaderValue); - } - } - - } - if (jwsHttpHeaders.size() != updatedHttpHeaders.size() - || !jwsHttpHeaders.entrySet().containsAll(updatedHttpHeaders.entrySet())) { - throw new JwsException(JwsException.Error.INVALID_SIGNATURE); - } + JoseJaxrsUtils.validateHttpHeaders(httpHeaders, + jwsHeaders, + protectedHttpHeaders); } public void setProtectedHttpHeaders(Set<String> protectedHttpHeaders) { this.protectedHttpHeaders = protectedHttpHeaders; http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JoseJaxrsUtils.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..b1f1a38 --- /dev/null +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JoseJaxrsUtils.java @@ -0,0 +1,95 @@ +/** + * 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.rs.security.jose.jaxrs; + +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.MultivaluedMap; + +import org.apache.cxf.jaxrs.utils.ExceptionUtils; +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 = + 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) { + if (protectedHttpHeaders == null) { + protectedHttpHeaders = DEFAULT_PROTECTED_HTTP_HEADERS; + } + for (String headerName : protectedHttpHeaders) { + List<Object> headerValues = httpHeaders.get(headerName); + if (headerValues != null) { + String joseHeaderValue = getJoseHeaderValue(headerValues); + String prefixedHeaderName = HTTP_PREFIX + headerName; + joseHeaders.setHeader(prefixedHeaderName, joseHeaderValue); + } + } + } + private static String getJoseHeaderValue(List<? extends Object> headerValues) { + StringBuilder sb = new StringBuilder(); + for (Object o : headerValues) { + String[] parts = o.toString().split(","); + for (String part : parts) { + sb.append(part); + } + } + return sb.toString(); + } + + public static void validateHttpHeaders(MultivaluedMap<String, String> httpHeaders, + JoseHeaders joseHeaders, + Set<String> protectedHttpHeaders) { + if (protectedHttpHeaders == null) { + protectedHttpHeaders = DEFAULT_PROTECTED_HTTP_HEADERS; + } + Map<String, String> joseHttpHeaders = new HashMap<String, String>(); + Map<String, String> updatedHttpHeaders = new HashMap<String, String>(); + for (String headerName : protectedHttpHeaders) { + List<String> headerValues = httpHeaders.get(headerName); + if (headerValues != 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())) { + throw ExceptionUtils.toBadRequestException(null, null); + } + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweClientResponseFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweClientResponseFilter.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweClientResponseFilter.java index 176973b..4b02790 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweClientResponseFilter.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweClientResponseFilter.java @@ -41,6 +41,9 @@ public class JweClientResponseFilter extends AbstractJweDecryptingFilter impleme if (ct != null) { res.getHeaders().putSingle("Content-Type", ct); } + if (super.isValidateHttpHeaders()) { + super.validateHttpHeadersIfNeeded(res.getHeaders(), out.getHeaders()); + } } - + } http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweContainerRequestFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweContainerRequestFilter.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweContainerRequestFilter.java index 9f0d831..d22cc79 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweContainerRequestFilter.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweContainerRequestFilter.java @@ -46,5 +46,8 @@ public class JweContainerRequestFilter extends AbstractJweDecryptingFilter imple if (ct != null) { context.getHeaders().putSingle("Content-Type", ct); } + if (super.isValidateHttpHeaders()) { + super.validateHttpHeadersIfNeeded(context.getHeaders(), out.getHeaders()); + } } } http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonClientResponseFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonClientResponseFilter.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonClientResponseFilter.java index cb48b95..8503a70 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonClientResponseFilter.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonClientResponseFilter.java @@ -41,6 +41,9 @@ public class JweJsonClientResponseFilter extends AbstractJweJsonDecryptingFilter if (ct != null) { res.getHeaders().putSingle("Content-Type", ct); } + if (super.isValidateHttpHeaders()) { + super.validateHttpHeadersIfNeeded(res.getHeaders(), out.getHeaders()); + } } } http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonContainerRequestFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonContainerRequestFilter.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonContainerRequestFilter.java index d0bb31f..5980b77 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonContainerRequestFilter.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonContainerRequestFilter.java @@ -49,6 +49,9 @@ public class JweJsonContainerRequestFilter extends AbstractJweJsonDecryptingFilt if (ct != null) { context.getHeaders().putSingle("Content-Type", ct); } + if (super.isValidateHttpHeaders()) { + super.validateHttpHeadersIfNeeded(context.getHeaders(), out.getHeaders()); + } } catch (JweException ex) { context.abortWith(JAXRSUtils.toResponse(400)); return; http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonWriterInterceptor.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonWriterInterceptor.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonWriterInterceptor.java index 89ce053..192be97 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonWriterInterceptor.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonWriterInterceptor.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import java.util.Set; import javax.annotation.Priority; import javax.ws.rs.WebApplicationException; @@ -43,6 +44,8 @@ import org.apache.cxf.rs.security.jose.jwe.JweJsonProducer; @Priority(Priorities.JWE_WRITE_PRIORITY) public class JweJsonWriterInterceptor extends AbstractJweJsonWriterProvider implements WriterInterceptor { + private Set<String> protectedHttpHeaders; + private boolean protectHttpHeaders; private boolean contentTypeRequired = true; private boolean useJweOutputStream; @Override @@ -67,6 +70,7 @@ public class JweJsonWriterInterceptor extends AbstractJweJsonWriterProvider impl if (ctString != null) { protectedHeaders.setContentType(ctString); } + protectHttpHeadersIfNeeded(ctx, protectedHeaders); List<KeyAlgorithm> keyAlgos = new ArrayList<>(); for (JweEncryptionProvider p : providers) { if (!keyAlgos.contains(p.getKeyAlgorithm())) { @@ -114,6 +118,21 @@ public class JweJsonWriterInterceptor extends AbstractJweJsonWriterProvider impl this.useJweOutputStream = useJweOutputStream; } - - + protected void protectHttpHeadersIfNeeded(WriterInterceptorContext ctx, JweHeaders jweHeaders) { + if (protectHttpHeaders) { + JoseJaxrsUtils.protectHttpHeaders(ctx.getHeaders(), + jweHeaders, + protectedHttpHeaders); + } + + } + + public void setProtectHttpHeaders(boolean protectHttpHeaders) { + this.protectHttpHeaders = protectHttpHeaders; + } + + public void setProtectedHttpHeaders(Set<String> protectedHttpHeaders) { + this.protectedHttpHeaders = protectedHttpHeaders; + } + } http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweWriterInterceptor.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweWriterInterceptor.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweWriterInterceptor.java index 20bea16..beb12f1 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweWriterInterceptor.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweWriterInterceptor.java @@ -21,6 +21,7 @@ package org.apache.cxf.rs.security.jose.jaxrs; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.OutputStream; +import java.util.Set; import java.util.logging.Logger; import java.util.zip.DeflaterOutputStream; @@ -49,6 +50,8 @@ import org.apache.cxf.rs.security.jose.jwe.JweUtils; @Priority(Priorities.JWE_WRITE_PRIORITY) public class JweWriterInterceptor implements WriterInterceptor { protected static final Logger LOG = LogUtils.getL7dLogger(JweWriterInterceptor.class); + private Set<String> protectedHttpHeaders; + private boolean protectHttpHeaders; private JweEncryptionProvider encryptionProvider; private boolean contentTypeRequired = true; private boolean useJweOutputStream; @@ -74,7 +77,7 @@ public class JweWriterInterceptor implements WriterInterceptor { if (ctString != null) { jweHeaders.setContentType(ctString); } - + protectHttpHeadersIfNeeded(ctx, jweHeaders); if (useJweOutputStream) { JweEncryptionOutput encryption = theEncryptionProvider.getEncryptionOutput(new JweEncryptionInput(jweHeaders)); @@ -132,5 +135,21 @@ public class JweWriterInterceptor implements WriterInterceptor { public void setEncryptionProvider(JweEncryptionProvider encryptionProvider) { this.encryptionProvider = encryptionProvider; } - + + protected void protectHttpHeadersIfNeeded(WriterInterceptorContext ctx, JweHeaders jweHeaders) { + if (protectHttpHeaders) { + JoseJaxrsUtils.protectHttpHeaders(ctx.getHeaders(), + jweHeaders, + protectedHttpHeaders); + } + + } + + public void setProtectHttpHeaders(boolean protectHttpHeaders) { + this.protectHttpHeaders = protectHttpHeaders; + } + + public void setProtectedHttpHeaders(Set<String> protectedHttpHeaders) { + this.protectedHttpHeaders = protectedHttpHeaders; + } } http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonWriterInterceptor.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonWriterInterceptor.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonWriterInterceptor.java index 38e1529..54566db 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonWriterInterceptor.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonWriterInterceptor.java @@ -22,16 +22,12 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Set; import javax.annotation.Priority; import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.WriterInterceptor; import javax.ws.rs.ext.WriterInterceptorContext; @@ -51,9 +47,7 @@ import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider; @Priority(Priorities.JWS_WRITE_PRIORITY) public class JwsJsonWriterInterceptor extends AbstractJwsJsonWriterProvider implements WriterInterceptor { - private static final Set<String> DEFAULT_PROTECTED_HTTP_HEADERS = - new HashSet<String>(Arrays.asList(HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT)); - private Set<String> protectedHttpHeaders = DEFAULT_PROTECTED_HTTP_HEADERS; + private Set<String> protectedHttpHeaders; private boolean protectHttpHeaders; private JsonMapObjectReaderWriter writer = new JsonMapObjectReaderWriter(); private boolean contentTypeRequired = true; @@ -148,17 +142,9 @@ public class JwsJsonWriterInterceptor extends AbstractJwsJsonWriterProvider impl protected void protectHttpHeadersIfNeeded(WriterInterceptorContext ctx, JwsHeaders jwsHeaders) { if (protectHttpHeaders) { - final String prefix = "http."; - MultivaluedMap<String, Object> httpHeaders = ctx.getHeaders(); - for (String headerName : protectedHttpHeaders) { - List<Object> headerValues = httpHeaders.get(headerName); - if (headerValues != null) { - String jwsHeaderValue = headerValues.size() > 1 ? headerValues.toString() - : headerValues.get(0).toString(); - String prefixedHeaderName = prefix + headerName; - jwsHeaders.setHeader(prefixedHeaderName, jwsHeaderValue); - } - } + JoseJaxrsUtils.protectHttpHeaders(ctx.getHeaders(), + jwsHeaders, + protectedHttpHeaders); } } http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsWriterInterceptor.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsWriterInterceptor.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsWriterInterceptor.java index 9b9cd6d..7d5d40b 100644 --- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsWriterInterceptor.java +++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsWriterInterceptor.java @@ -23,14 +23,12 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.annotation.Priority; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.WriterInterceptor; import javax.ws.rs.ext.WriterInterceptorContext; @@ -136,17 +134,9 @@ public class JwsWriterInterceptor extends AbstractJwsWriterProvider implements W } protected void protectHttpHeadersIfNeeded(WriterInterceptorContext ctx, JwsHeaders jwsHeaders) { if (protectHttpHeaders) { - final String prefix = "http."; - MultivaluedMap<String, Object> httpHeaders = ctx.getHeaders(); - for (String headerName : protectedHttpHeaders) { - List<Object> headerValues = httpHeaders.get(headerName); - if (headerValues != null) { - String jwsHeaderValue = headerValues.size() > 1 ? headerValues.toString() - : headerValues.get(0).toString(); - String prefixedHeaderName = prefix + headerName; - jwsHeaders.setHeader(prefixedHeaderName, jwsHeaderValue); - } - } + JoseJaxrsUtils.protectHttpHeaders(ctx.getHeaders(), + jwsHeaders, + protectedHttpHeaders); } } http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/BookStore.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/BookStore.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/BookStore.java index 7d6a17e..e774c77 100644 --- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/BookStore.java +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/BookStore.java @@ -38,7 +38,7 @@ public class BookStore { @POST @Path("/books") - @Produces("text/plain") + @Produces({"text/plain", "application/json"}) @Consumes("text/plain") public String echoText(String text) { return text; http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/HttpHeaderModifyingFilter.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/HttpHeaderModifyingFilter.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/HttpHeaderModifyingFilter.java new file mode 100644 index 0000000..d04bc65 --- /dev/null +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/HttpHeaderModifyingFilter.java @@ -0,0 +1,42 @@ +/** + * 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.io.IOException; + +import javax.annotation.Priority; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; + +import org.apache.cxf.rs.security.jose.jaxrs.Priorities; + +@PreMatching +@Priority(Priorities.JWS_SERVER_READ_PRIORITY - 1) +public class HttpHeaderModifyingFilter implements ContainerRequestFilter { + + @Override + public void filter(ContainerRequestContext ctx) throws IOException { + if (ctx.getHeaderString("Modify") != null) { + ctx.getHeaders().putSingle("Accept", "text/plain;a=b"); + } + + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JAXRSJweJwsTest.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JAXRSJweJwsTest.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JAXRSJweJwsTest.java index 7d22c4a..9d15ee2 100644 --- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JAXRSJweJwsTest.java +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JAXRSJweJwsTest.java @@ -26,6 +26,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Properties; +import javax.ws.rs.BadRequestException; + import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; import org.apache.cxf.Bus; @@ -260,6 +262,13 @@ public class JAXRSJweJwsTest extends AbstractBusClientServerTestBase { String text = bs.echoText("book"); assertEquals("book", text); } + @Test(expected = BadRequestException.class) + public void testJwsJwkPlainTextHMacHttpHeadersModified() throws Exception { + String address = "https://localhost:" + PORT + "/jwsjwkhmacHttpHeaders"; + BookStore bs = createJwsBookStore(address, null, true, true); + WebClient.client(bs).header("Modify", "true"); + bs.echoText("book"); + } @Test public void testJwsJwkPlainTextHMacUnencoded() throws Exception { String address = "https://localhost:" + PORT + "/jwsjwkhmac"; http://git-wip-us.apache.org/repos/asf/cxf/blob/45ca76a2/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml index 8e99760..67a1c94 100644 --- a/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml +++ b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml @@ -75,6 +75,7 @@ under the License. <bean id="jwsInFilterHttpHeaders" class="org.apache.cxf.rs.security.jose.jaxrs.JwsContainerRequestFilter"> <property name="validateHttpHeaders" value="true"/> </bean> + <bean id="httpHeaderFilter" class="org.apache.cxf.systest.jaxrs.security.jose.jwejws.HttpHeaderModifyingFilter"/> <bean id="jwsOutFilter" class="org.apache.cxf.rs.security.jose.jaxrs.JwsWriterInterceptor"/> <bean id="keyPasswordProvider" class="org.apache.cxf.systest.jaxrs.security.jose.jwejws.PrivateKeyPasswordProviderImpl"/> <bean id="keyPasswordProvider2" class="org.apache.cxf.systest.jaxrs.security.jose.jwejws.PrivateKeyPasswordProviderImpl"> @@ -216,6 +217,7 @@ under the License. </jaxrs:serviceBeans> <jaxrs:providers> <ref bean="jwsInFilterHttpHeaders"/> + <ref bean="httpHeaderFilter"/> <ref bean="jwsOutFilter"/> <ref bean="jackson"/> </jaxrs:providers>