Repository: cxf Updated Branches: refs/heads/master 4fb4de764 -> 2ef6f5840
Adding JWT token related utility code Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/2ef6f584 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/2ef6f584 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/2ef6f584 Branch: refs/heads/master Commit: 2ef6f584022b7672df00a883525dc58807ffe7d7 Parents: 4fb4de7 Author: Sergey Beryozkin <sberyoz...@talend.com> Authored: Wed Dec 10 17:04:30 2014 +0000 Committer: Sergey Beryozkin <sberyoz...@talend.com> Committed: Wed Dec 10 17:04:30 2014 +0000 ---------------------------------------------------------------------- .../cxf/rs/security/jose/JoseConstants.java | 2 + .../apache/cxf/rs/security/jose/JoseUtils.java | 31 ++++++++ .../jose/jaxrs/AbstractJwsWriterProvider.java | 11 ++- .../jose/jaxrs/JwsContainerRequestFilter.java | 18 +---- .../jaxrs/JwtAuthenticationClientFilter.java | 75 ++++++++++++++++++++ .../jose/jaxrs/JwtAuthenticationFilter.java | 70 ++++++++++++++++++ .../cxf/rs/security/jose/jaxrs/Priorities.java | 15 ++-- .../jose/jws/NoneJwsSignatureProvider.java | 55 ++++++++++++++ .../jose/jwt/AbstractJoseJwtConsumer.java | 73 +++++++++++++++++++ .../jose/jwt/AbstractJoseJwtProducer.java | 58 +++++++++++++++ .../jwt/AbstactJwtAccessTokenValidator.java | 63 ++++++++++++++++ .../oauth2/tokens/jwt/JwtAccessTokenUtils.java | 38 +--------- .../oidc/rp/AbstractTokenValidator.java | 64 +++++++++-------- 13 files changed, 478 insertions(+), 95 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseConstants.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseConstants.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseConstants.java index 6d95234..b268129 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseConstants.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseConstants.java @@ -76,6 +76,8 @@ public final class JoseConstants { public static final String A192GCM_ALGO = "A192GCM"; public static final String A256GCM_ALGO = "A256GCM"; + public static final String JOSE_CONTEXT_PROPERTY = "org.apache.cxf.jose.context"; + private JoseConstants() { } http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseUtils.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseUtils.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseUtils.java index 23f9936..122c3eb 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseUtils.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseUtils.java @@ -24,12 +24,43 @@ import java.util.List; import java.util.Set; import org.apache.cxf.common.util.crypto.CryptoUtils; +import org.apache.cxf.jaxrs.utils.JAXRSUtils; public final class JoseUtils { + private JoseUtils() { } + public static void setJoseContextProperty(JoseHeaders headers) { + String context = (String)JAXRSUtils.getCurrentMessage().get(JoseConstants.JOSE_CONTEXT_PROPERTY); + if (context != null) { + headers.setHeader(JoseConstants.JOSE_CONTEXT_PROPERTY, context); + } + } + public static void setJoseMessageContextProperty(JoseHeaders headers, String value) { + headers.setHeader(JoseConstants.JOSE_CONTEXT_PROPERTY, value); + JAXRSUtils.getCurrentMessage().put(JoseConstants.JOSE_CONTEXT_PROPERTY, value); + } + public static void setMessageContextProperty(JoseHeaders headers) { + String context = (String)headers.getHeader(JoseConstants.JOSE_CONTEXT_PROPERTY); + if (context != null) { + JAXRSUtils.getCurrentMessage().put(JoseConstants.JOSE_CONTEXT_PROPERTY, context); + } + } + public static void validateRequestContextProperty(JoseHeaders headers) { + Object requestContext = JAXRSUtils.getCurrentMessage().get(JoseConstants.JOSE_CONTEXT_PROPERTY); + Object headerContext = headers.getHeader(JoseConstants.JOSE_CONTEXT_PROPERTY); + if (requestContext == null && headerContext == null) { + return; + } + if (requestContext == null && headerContext != null + || requestContext != null && headerContext == null + || !requestContext.equals(headerContext)) { + throw new SecurityException(); + } + } + public static String checkContentType(String contentType, String defaultType) { if (contentType != null) { int paramIndex = contentType.indexOf(';'); http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsWriterProvider.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsWriterProvider.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsWriterProvider.java index d281b2e..1fc5bdc 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsWriterProvider.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsWriterProvider.java @@ -24,14 +24,13 @@ import java.io.OutputStream; import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.helpers.IOUtils; -import org.apache.cxf.message.Message; import org.apache.cxf.rs.security.jose.JoseHeaders; +import org.apache.cxf.rs.security.jose.JoseUtils; import org.apache.cxf.rs.security.jose.jws.JwsCompactProducer; import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider; import org.apache.cxf.rs.security.jose.jws.JwsUtils; public class AbstractJwsWriterProvider { - private static final String JWS_CONTEXT_PROPERTY = "org.apache.cxf.jws.context"; private JwsSignatureProvider sigProvider; public void setSignatureProvider(JwsSignatureProvider signatureProvider) { @@ -39,6 +38,7 @@ public class AbstractJwsWriterProvider { } protected JwsSignatureProvider getInitializedSigProvider(JoseHeaders headers) { + setRequestContextProperty(headers); if (sigProvider != null) { return sigProvider; } @@ -46,11 +46,8 @@ public class AbstractJwsWriterProvider { headers.setAlgorithm(theSigProvider.getAlgorithm()); return theSigProvider; } - protected void setRequestContextProperty(Message m, JoseHeaders headers) { - String context = (String)m.getContextualProperty(JWS_CONTEXT_PROPERTY); - if (context != null) { - headers.setHeader(JWS_CONTEXT_PROPERTY, context); - } + protected void setRequestContextProperty(JoseHeaders headers) { + JoseUtils.setJoseContextProperty(headers); } protected void writeJws(JwsCompactProducer p, JwsSignatureProvider theSigProvider, OutputStream os) throws IOException { http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsContainerRequestFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsContainerRequestFilter.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsContainerRequestFilter.java index 1b5f5d2..6164b8f 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsContainerRequestFilter.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsContainerRequestFilter.java @@ -36,7 +36,6 @@ import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier; @PreMatching @Priority(Priorities.JWS_SERVER_READ_PRIORITY) public class JwsContainerRequestFilter extends AbstractJwsReaderProvider implements ContainerRequestFilter { - private static final String JWS_CONTEXT_PROPERTY = "org.apache.cxf.jws.context"; @Override public void filter(ContainerRequestContext context) throws IOException { if (HttpMethod.GET.equals(context.getMethod())) { @@ -48,7 +47,7 @@ public class JwsContainerRequestFilter extends AbstractJwsReaderProvider impleme context.abortWith(JAXRSUtils.toResponse(400)); return; } - validateRequestContextProperty(p); + JoseUtils.validateRequestContextProperty(p.getJoseHeaders()); byte[] bytes = p.getDecodedJwsPayloadBytes(); context.setEntityStream(new ByteArrayInputStream(bytes)); context.getHeaders().putSingle("Content-Length", Integer.toString(bytes.length)); @@ -58,18 +57,5 @@ public class JwsContainerRequestFilter extends AbstractJwsReaderProvider impleme context.getHeaders().putSingle("Content-Type", ct); } } - protected void validateRequestContextProperty(JwsCompactConsumer c) { - Object requestContext = JAXRSUtils.getCurrentMessage().get(JWS_CONTEXT_PROPERTY); - Object headerContext = c.getJoseHeaders().getHeader(JWS_CONTEXT_PROPERTY); - if (requestContext == null && headerContext == null) { - return; - } - if (requestContext == null && headerContext != null - || requestContext != null && headerContext == null - || !requestContext.equals(headerContext)) { - throw new SecurityException(); - } - - - } + } http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwtAuthenticationClientFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwtAuthenticationClientFilter.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwtAuthenticationClientFilter.java new file mode 100644 index 0000000..d8bd8c2 --- /dev/null +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwtAuthenticationClientFilter.java @@ -0,0 +1,75 @@ +/** + * 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.io.IOException; + +import javax.annotation.Priority; +import javax.ws.rs.Priorities; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientRequestFilter; +import javax.ws.rs.core.HttpHeaders; + +import org.apache.cxf.common.util.Base64UrlUtility; +import org.apache.cxf.common.util.crypto.CryptoUtils; +import org.apache.cxf.configuration.security.AuthorizationPolicy; +import org.apache.cxf.endpoint.Endpoint; +import org.apache.cxf.jaxrs.utils.JAXRSUtils; +import org.apache.cxf.rs.security.jose.JoseHeaders; +import org.apache.cxf.rs.security.jose.JoseUtils; +import org.apache.cxf.rs.security.jose.jwt.AbstractJoseJwtProducer; +import org.apache.cxf.rs.security.jose.jwt.JwtClaims; +import org.apache.cxf.rs.security.jose.jwt.JwtToken; + +@Priority(Priorities.AUTHENTICATION) +public class JwtAuthenticationClientFilter extends AbstractJoseJwtProducer + implements ClientRequestFilter { + + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + JwtToken jwt = getJwtToken(requestContext); + boolean jweRequired = false; + if (jwt == null) { + AuthorizationPolicy ap = JAXRSUtils.getCurrentMessage().getExchange() + .get(Endpoint.class).getEndpointInfo().getExtensor(AuthorizationPolicy.class); + if (ap != null && ap.getUserName() != null) { + JwtClaims claims = new JwtClaims(); + claims.setSubject(ap.getUserName()); + claims.setClaim("password", ap.getPassword()); + claims.setIssuedAt(System.currentTimeMillis() / 1000); + jwt = new JwtToken(new JoseHeaders(), claims); + jweRequired = true; + } + } + if (jwt == null) { + throw new SecurityException(); + } + JoseUtils.setJoseMessageContextProperty(jwt.getHeaders(), + getContextPropertyValue()); + String data = super.processJwt(jwt, true, jweRequired); + requestContext.getHeaders().putSingle(HttpHeaders.AUTHORIZATION, + "JWT " + data); + } + protected JwtToken getJwtToken(ClientRequestContext requestContext) { + return (JwtToken)requestContext.getProperty("jwt.token"); + } + protected String getContextPropertyValue() { + return Base64UrlUtility.encode(CryptoUtils.generateSecureRandomBytes(16)); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwtAuthenticationFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwtAuthenticationFilter.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwtAuthenticationFilter.java new file mode 100644 index 0000000..32de426 --- /dev/null +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwtAuthenticationFilter.java @@ -0,0 +1,70 @@ +/** + * 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.io.IOException; + +import javax.annotation.Priority; +import javax.ws.rs.Priorities; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.HttpHeaders; + +import org.apache.cxf.common.security.SimplePrincipal; +import org.apache.cxf.common.security.SimpleSecurityContext; +import org.apache.cxf.jaxrs.utils.JAXRSUtils; +import org.apache.cxf.rs.security.jose.JoseUtils; +import org.apache.cxf.rs.security.jose.jwt.AbstractJoseJwtConsumer; +import org.apache.cxf.rs.security.jose.jwt.JwtToken; +import org.apache.cxf.security.SecurityContext; + +@PreMatching +@Priority(Priorities.AUTHENTICATION) +public class JwtAuthenticationFilter extends AbstractJoseJwtConsumer implements ContainerRequestFilter { + + private boolean jweOnly; + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + String auth = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); + String[] parts = auth == null ? null : auth.split(" "); + if (parts == null || !"JWT".equals(parts[0]) || parts.length != 2) { + throw new SecurityException(); + } + JwtToken jwt = super.getJwtToken(parts[1], jweOnly); + JoseUtils.setMessageContextProperty(jwt.getHeaders()); + JAXRSUtils.getCurrentMessage().put(SecurityContext.class, + new SimpleSecurityContext(new JwtPrincipal(jwt))); + } + + public void setJweOnly(boolean jweOnly) { + this.jweOnly = jweOnly; + } + public static class JwtPrincipal extends SimplePrincipal { + private JwtToken jwt; + public JwtPrincipal(JwtToken jwt) { + super(jwt.getClaims().getSubject()); + this.jwt = jwt; + } + public JwtToken getJwt() { + return jwt; + } + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/Priorities.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/Priorities.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/Priorities.java index fc48ebc..877ff0c 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/Priorities.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/Priorities.java @@ -19,12 +19,15 @@ package org.apache.cxf.rs.security.jose.jaxrs; public final class Priorities { - public static final int JWE_SERVER_READ_PRIORITY = 1000; - public static final int JWE_WRITE_PRIORITY = 1000; - public static final int JWE_CLIENT_READ_PRIORITY = 1001; - public static final int JWS_SERVER_READ_PRIORITY = 1001; - public static final int JWS_WRITE_PRIORITY = 1001; - public static final int JWS_CLIENT_READ_PRIORITY = 1000; + public static final int JWE_SERVER_READ_PRIORITY = 1001; + public static final int JWS_SERVER_READ_PRIORITY = 1002; + + public static final int JWE_WRITE_PRIORITY = 1001; + public static final int JWS_WRITE_PRIORITY = 1002; + + public static final int JWE_CLIENT_READ_PRIORITY = 1002; + public static final int JWS_CLIENT_READ_PRIORITY = 1001; + private Priorities() { } http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/NoneJwsSignatureProvider.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/NoneJwsSignatureProvider.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/NoneJwsSignatureProvider.java new file mode 100644 index 0000000..6226102 --- /dev/null +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/NoneJwsSignatureProvider.java @@ -0,0 +1,55 @@ +/** + * 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.jws; + +import org.apache.cxf.rs.security.jose.JoseHeaders; + +public class NoneJwsSignatureProvider implements JwsSignatureProvider { + + @Override + public String getAlgorithm() { + return "none"; + } + + @Override + public JwsSignature createJwsSignature(JoseHeaders headers) { + return new NoneJwsSignature(); + } + + @Override + public byte[] sign(JoseHeaders headers, byte[] content) { + JwsSignature sig = createJwsSignature(headers); + sig.update(content, 0, content.length); + return sig.sign(); + } + private static class NoneJwsSignature implements JwsSignature { + + @Override + public void update(byte[] src, int off, int len) { + // complete + } + + @Override + public byte[] sign() { + return new byte[]{}; + } + + } +} + http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java new file mode 100644 index 0000000..34dd60c --- /dev/null +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.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.rs.security.jose.jwt; + +import org.apache.cxf.rs.security.jose.jwe.JweDecryptionProvider; +import org.apache.cxf.rs.security.jose.jwe.JweJwtCompactConsumer; +import org.apache.cxf.rs.security.jose.jwe.JweUtils; +import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer; +import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier; +import org.apache.cxf.rs.security.jose.jws.JwsUtils; + +public abstract class AbstractJoseJwtConsumer { + private JweDecryptionProvider jweDecryptor; + private JwsSignatureVerifier jwsVerifier; + protected JwtToken getJwtToken(String wrappedJwtToken, boolean jweOnly) { + JweDecryptionProvider theJweDecryptor = getInitializedDecryptionProvider(jweOnly); + if (theJweDecryptor != null) { + if (jweOnly) { + return new JweJwtCompactConsumer(wrappedJwtToken).decryptWith(jweDecryptor); + } + wrappedJwtToken = jweDecryptor.decrypt(wrappedJwtToken).getContentText(); + } else if (jweOnly) { + throw new SecurityException(); + } + + JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(wrappedJwtToken); + JwtToken jwt = jwtConsumer.getJwtToken(); + JwsSignatureVerifier theSigVerifier = getInitializedSigVerifier(); + return validateToken(jwtConsumer, jwt, theSigVerifier); + } + protected JwtToken validateToken(JwsJwtCompactConsumer consumer, JwtToken jwt, JwsSignatureVerifier jws) { + if (!consumer.verifySignatureWith(jws)) { + throw new SecurityException("Invalid Signature"); + } + return jwt; + } + public void setJweDecryptor(JweDecryptionProvider jweDecryptor) { + this.jweDecryptor = jweDecryptor; + } + + public void setJweVerifier(JwsSignatureVerifier theJwsVerifier) { + this.jwsVerifier = theJwsVerifier; + } + + protected JweDecryptionProvider getInitializedDecryptionProvider(boolean jweOnly) { + if (jweDecryptor != null) { + return jweDecryptor; + } + return JweUtils.loadDecryptionProvider(jweOnly); + } + protected JwsSignatureVerifier getInitializedSigVerifier() { + if (jwsVerifier != null) { + return jwsVerifier; + } + return JwsUtils.loadSignatureVerifier(true); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java new file mode 100644 index 0000000..80318fb --- /dev/null +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java @@ -0,0 +1,58 @@ +/** + * 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.jwt; + +import org.apache.cxf.common.util.StringUtils; +import org.apache.cxf.rs.security.jose.jwe.JweEncryptionProvider; +import org.apache.cxf.rs.security.jose.jwe.JweUtils; +import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactProducer; +import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider; +import org.apache.cxf.rs.security.jose.jws.JwsUtils; +import org.apache.cxf.rs.security.jose.jws.NoneJwsSignatureProvider; + +public abstract class AbstractJoseJwtProducer { + private JwsSignatureProvider sigProvider; + private JweEncryptionProvider encryptionProvider; + protected String processJwt(JwtToken jwt, boolean jwsRequired, boolean jweRequired) { + JwsJwtCompactProducer jws = new JwsJwtCompactProducer(jwt); + JwsSignatureProvider theSigProvider = getInitializedSigProvider(jweRequired, jwsRequired); + String data = jws.signWith(theSigProvider); + JweEncryptionProvider theEncProvider = getInitializedEncryptionProvider(jweRequired); + if (theEncProvider != null) { + data = theEncProvider.encrypt(StringUtils.toBytesUTF8(data), null); + } + return data; + } + protected JwsSignatureProvider getInitializedSigProvider(boolean jwsRequired, boolean jweRequired) { + if (sigProvider != null) { + return sigProvider; + } + JwsSignatureProvider theSigProvider = JwsUtils.loadSignatureProvider(jwsRequired); + if (theSigProvider == null && jweRequired) { + return new NoneJwsSignatureProvider(); + } + throw new SecurityException(); + } + protected JweEncryptionProvider getInitializedEncryptionProvider(boolean required) { + if (encryptionProvider != null) { + return encryptionProvider; + } + return JweUtils.loadEncryptionProvider(required); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/jwt/AbstactJwtAccessTokenValidator.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/jwt/AbstactJwtAccessTokenValidator.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/jwt/AbstactJwtAccessTokenValidator.java new file mode 100644 index 0000000..c0caa7c --- /dev/null +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/jwt/AbstactJwtAccessTokenValidator.java @@ -0,0 +1,63 @@ +/** + * 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.oauth2.tokens.jwt; + +import java.util.Collections; +import java.util.List; + +import javax.ws.rs.core.MultivaluedMap; + +import org.apache.cxf.jaxrs.ext.MessageContext; +import org.apache.cxf.rs.security.jose.jwt.AbstractJoseJwtConsumer; +import org.apache.cxf.rs.security.jose.jwt.JwtToken; +import org.apache.cxf.rs.security.oauth2.common.AccessTokenValidation; +import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken; +import org.apache.cxf.rs.security.oauth2.provider.AccessTokenValidator; +import org.apache.cxf.rs.security.oauth2.provider.OAuthDataProvider; +import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException; + +public abstract class AbstactJwtAccessTokenValidator extends AbstractJoseJwtConsumer + implements AccessTokenValidator { + private OAuthDataProvider dataProvider; + + @Override + public List<String> getSupportedAuthorizationSchemes() { + return Collections.singletonList("*"); + } + + @Override + public AccessTokenValidation validateAccessToken(MessageContext mc, + String authScheme, + String authSchemeData, + MultivaluedMap<String, String> extraProps) + throws OAuthServiceException { + ServerAccessToken at = dataProvider.getAccessToken(authSchemeData); + JwtToken token = super.getJwtToken(at.getTokenKey(), false); + validateToken(token); + return new AccessTokenValidation(at); + } + + public void setDataProvider(OAuthDataProvider dataProvider) { + this.dataProvider = dataProvider; + } + + protected void validateToken(JwtToken jwt) { + + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/jwt/JwtAccessTokenUtils.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/jwt/JwtAccessTokenUtils.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/jwt/JwtAccessTokenUtils.java index 33e74e4..ddd3c51 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/jwt/JwtAccessTokenUtils.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/tokens/jwt/JwtAccessTokenUtils.java @@ -25,7 +25,6 @@ import javax.crypto.SecretKey; import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.rs.security.jose.JoseConstants; -import org.apache.cxf.rs.security.jose.JoseHeaders; import org.apache.cxf.rs.security.jose.jwa.Algorithm; import org.apache.cxf.rs.security.jose.jwe.DirectKeyJweDecryption; import org.apache.cxf.rs.security.jose.jwe.JweDecryptionProvider; @@ -33,10 +32,10 @@ import org.apache.cxf.rs.security.jose.jwe.JweEncryptionProvider; import org.apache.cxf.rs.security.jose.jwe.JweUtils; import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer; import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactProducer; -import org.apache.cxf.rs.security.jose.jws.JwsSignature; import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider; import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier; import org.apache.cxf.rs.security.jose.jws.JwsUtils; +import org.apache.cxf.rs.security.jose.jws.NoneJwsSignatureProvider; import org.apache.cxf.rs.security.jose.jwt.JwtClaims; import org.apache.cxf.rs.security.jose.jwt.JwtToken; import org.apache.cxf.rs.security.jose.jwt.JwtUtils; @@ -60,7 +59,7 @@ public final class JwtAccessTokenUtils { Client client, JweEncryptionProvider jweEncryption) { String jwtString = new JwsJwtCompactProducer(jwt) - .signWith(new NoneSignatureProvider()); + .signWith(new NoneJwsSignatureProvider()); String tokenId = jweEncryption.encrypt(getBytes(jwtString), null); return toAccessToken(jwt, client, tokenId); } @@ -128,38 +127,7 @@ public final class JwtAccessTokenUtils { // TODO: the issuer is indirectly validated by validating the signature // but an extra check can be done } - private static class NoneSignatureProvider implements JwsSignatureProvider { - - @Override - public String getAlgorithm() { - return "none"; - } - - @Override - public JwsSignature createJwsSignature(JoseHeaders headers) { - return new NoneJwsSignature(); - } - - @Override - public byte[] sign(JoseHeaders headers, byte[] content) { - // TODO Auto-generated method stub - return null; - } - - } - private static class NoneJwsSignature implements JwsSignature { - - @Override - public void update(byte[] src, int off, int len) { - // complete - } - - @Override - public byte[] sign() { - return new byte[]{}; - } - - } + private static byte[] getBytes(String str) { return StringUtils.toBytesUTF8(str); } http://git-wip-us.apache.org/repos/asf/cxf/blob/2ef6f584/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/AbstractTokenValidator.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/AbstractTokenValidator.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/AbstractTokenValidator.java index 69c54a4..f6e95c6 100644 --- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/AbstractTokenValidator.java +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/AbstractTokenValidator.java @@ -56,8 +56,11 @@ public abstract class AbstractTokenValidator { wrappedJwtToken = jweDecryptor.decrypt(wrappedJwtToken).getContentText(); } - // validate token signature - return getTokenValidateSignature(wrappedJwtToken, idTokenKid); + JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(wrappedJwtToken); + JwtToken jwt = jwtConsumer.getJwtToken(); + JwsSignatureVerifier theSigVerifier = getInitializedSigVerifier(jwt, idTokenKid); + return validateToken(jwtConsumer, jwt, theSigVerifier); + } protected void validateJwtClaims(JwtClaims claims, String clientId, boolean validateClaimsAlways) { @@ -79,33 +82,7 @@ public abstract class AbstractTokenValidator { JwtUtils.validateJwtTimeClaims(claims, issuedAtRange, validateClaimsAlways); } - protected JwtToken getTokenValidateSignature(String wrappedJwtToken, String idTokenKid) { - // read id_token into JwtToken - JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(wrappedJwtToken); - JwtToken jwt = jwtConsumer.getJwtToken(); - JwsSignatureVerifier theSigVerifier = getInitializedSigVerifier(); - if (theSigVerifier != null) { - return validateToken(jwtConsumer, jwt, theSigVerifier); - } - if (jwkSetClient == null) { - throw new SecurityException("Provider Jwk Set Client is not available"); - } - String keyId = idTokenKid != null ? idTokenKid : jwtConsumer.getJwtToken().getHeaders().getKeyId(); - JsonWebKey key = keyId != null ? keyMap.get(keyId) : null; - if (key == null) { - JsonWebKeys keys = jwkSetClient.get(JsonWebKeys.class); - if (keyId != null) { - key = keys.getKey(keyId); - } else if (keys.getKeys().size() == 1) { - key = keys.getKeys().get(0); - } - keyMap.putAll(keys.getKeyIdMap()); - } - if (key == null) { - throw new SecurityException("JWK key with the key id: \"" + keyId + "\" is not available"); - } - return validateToken(jwtConsumer, jwt, JwsUtils.getSignatureVerifier(key)); - } + protected JwtToken validateToken(JwsJwtCompactConsumer consumer, JwtToken jwt, JwsSignatureVerifier jws) { if (!consumer.verifySignatureWith(jws)) { throw new SecurityException("Invalid Signature"); @@ -138,10 +115,35 @@ public abstract class AbstractTokenValidator { } return JweUtils.loadDecryptionProvider(jweOnly); } - protected JwsSignatureVerifier getInitializedSigVerifier() { + protected JwsSignatureVerifier getInitializedSigVerifier(JwtToken jwt, String idTokenKid) { if (jwsVerifier != null) { return jwsVerifier; } - return JwsUtils.loadSignatureVerifier(false); + JwsSignatureVerifier theJwsVerifier = JwsUtils.loadSignatureVerifier(false); + if (theJwsVerifier != null) { + return theJwsVerifier; + } + if (jwkSetClient == null) { + throw new SecurityException("Provider Jwk Set Client is not available"); + } + String keyId = idTokenKid != null ? idTokenKid : jwt.getHeaders().getKeyId(); + JsonWebKey key = keyId != null ? keyMap.get(keyId) : null; + if (key == null) { + JsonWebKeys keys = jwkSetClient.get(JsonWebKeys.class); + if (keyId != null) { + key = keys.getKey(keyId); + } else if (keys.getKeys().size() == 1) { + key = keys.getKeys().get(0); + } + keyMap.putAll(keys.getKeyIdMap()); + } + if (key == null) { + throw new SecurityException("JWK key with the key id: \"" + keyId + "\" is not available"); + } + theJwsVerifier = JwsUtils.getSignatureVerifier(key); + if (jwkSetClient == null) { + throw new SecurityException(); + } + return theJwsVerifier; } }