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 2015/10/21 15:27:52 UTC
[12/18] cxf git commit: Renaming jose module
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonOutputStream.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonOutputStream.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonOutputStream.java
new file mode 100644
index 0000000..7fe6059
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonOutputStream.java
@@ -0,0 +1,100 @@
+/**
+ * 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 java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.StringUtils;
+
+public class JwsJsonOutputStream extends FilterOutputStream {
+ private boolean flushed;
+ private List<String> protectedHeaders;
+ private List<JwsSignature> signatures;
+ private ExecutorService executor;
+ public JwsJsonOutputStream(OutputStream out,
+ List<String> protectedHeaders,
+ List<JwsSignature> signatures) {
+ super(out);
+ this.protectedHeaders = protectedHeaders;
+ this.signatures = signatures;
+ // This can be further optimized by having a dedicated thread per signature,
+ // can make a difference if a number of signatures to be created is > 2
+ this.executor = Executors.newSingleThreadExecutor();
+ }
+
+ @Override
+ public void write(int value) throws IOException {
+ byte[] bytes = ByteBuffer.allocate(Integer.SIZE / 8).putInt(value).array();
+ write(bytes, 0, bytes.length);
+ }
+
+ @Override
+ public void write(final byte b[], final int off, final int len) throws IOException {
+ //TODO: Review if it is at least theoretically possible that a given b[] region
+ // can be modified in a subsequent write which might affect the signature calculation
+ executor.execute(new Runnable() {
+ public void run() {
+ for (JwsSignature signature : signatures) {
+ signature.update(b, off, len);
+ }
+ }
+ });
+ out.write(b, off, len);
+ out.flush();
+ }
+ @Override
+ public void flush() throws IOException {
+ if (flushed) {
+ return;
+ }
+ out.write(StringUtils.toBytesUTF8("\",\"signatures\":["));
+ shutdownExecutor();
+ for (int i = 0; i < signatures.size(); i++) {
+ if (i > 0) {
+ out.write(new byte[]{','});
+ }
+ out.write(StringUtils.toBytesUTF8("{\"protected\":\""
+ + protectedHeaders.get(i)
+ + "\",\"signature\":\""));
+ byte[] sign = signatures.get(i).sign();
+ Base64UrlUtility.encodeAndStream(sign, 0, sign.length, out);
+ out.write(StringUtils.toBytesUTF8("\"}"));
+ }
+ out.write(StringUtils.toBytesUTF8("]}"));
+ flushed = true;
+ }
+ private void shutdownExecutor() {
+ executor.shutdown();
+ while (!executor.isTerminated()) {
+ try {
+ executor.awaitTermination(1, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProducer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProducer.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProducer.java
new file mode 100644
index 0000000..e96a630
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProducer.java
@@ -0,0 +1,212 @@
+/**
+ * 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 java.security.PrivateKey;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter;
+import org.apache.cxf.rs.security.jose.common.JoseConstants;
+import org.apache.cxf.rs.security.jose.common.JoseHeaders;
+import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+
+public class JwsJsonProducer {
+ protected static final Logger LOG = LogUtils.getL7dLogger(JwsJsonProducer.class);
+ private boolean supportFlattened;
+ private String plainPayload;
+ private String encodedPayload;
+ private List<JwsJsonSignatureEntry> signatures = new LinkedList<JwsJsonSignatureEntry>();
+ private JsonMapObjectReaderWriter writer = new JsonMapObjectReaderWriter();
+ public JwsJsonProducer(String tbsDocument) {
+ this(tbsDocument, false);
+ }
+ public JwsJsonProducer(String tbsDocument, boolean supportFlattened) {
+ this.supportFlattened = supportFlattened;
+ this.plainPayload = tbsDocument;
+ }
+
+ public String getPlainPayload() {
+ return plainPayload;
+ }
+ public String getUnsignedEncodedPayload() {
+ if (encodedPayload == null) {
+ encodedPayload = Base64UrlUtility.encode(getPlainPayload());
+ }
+ return encodedPayload;
+ }
+ public String getJwsJsonSignedDocument() {
+ return getJwsJsonSignedDocument(false);
+ }
+ public String getJwsJsonSignedDocument(boolean detached) {
+ if (signatures.isEmpty()) {
+ return null;
+ }
+
+ Boolean b64Status = validateB64Status(signatures);
+ StringBuilder sb = new StringBuilder();
+ sb.append("{");
+ if (!detached) {
+ sb.append("\"payload\":\"" + getActualPayload(b64Status) + "\"");
+ sb.append(",");
+ }
+ if (!supportFlattened || signatures.size() > 1) {
+ sb.append("\"signatures\":[");
+ for (int i = 0; i < signatures.size(); i++) {
+ JwsJsonSignatureEntry signature = signatures.get(i);
+ if (i > 0) {
+ sb.append(",");
+ }
+ sb.append(signature.toJson());
+ }
+ sb.append("]");
+ } else {
+ sb.append(signatures.get(0).toJson(true));
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+ public List<JwsJsonSignatureEntry> getSignatureEntries() {
+ return signatures;
+ }
+
+ /*
+ * TODO
+ public MultivaluedMap<SignatureAlgorithm, JwsJsonSignatureEntry> getSignatureEntryMap() {
+ return JwsUtils.getJwsJsonSignatureMap(signatures);
+ }
+ */
+ public String signWith(List<JwsSignatureProvider> signers) {
+ for (JwsSignatureProvider signer : signers) {
+ signWith(signer);
+ }
+ return getJwsJsonSignedDocument();
+ }
+ public String signWith(JwsSignatureProvider signer) {
+ JwsHeaders headers = new JwsHeaders();
+ headers.setSignatureAlgorithm(signer.getAlgorithm());
+ return signWith(signer, headers);
+ }
+ public String signWith(JwsSignatureProvider signer,
+ JwsHeaders protectedHeader) {
+ return signWith(signer, protectedHeader, null);
+ }
+ public String signWith(JsonWebKey jwk) {
+ return signWith(JwsUtils.getSignatureProvider(jwk));
+ }
+ public String signWith(PrivateKey key, SignatureAlgorithm algo) {
+ return signWith(JwsUtils.getPrivateKeySignatureProvider(key, algo));
+ }
+ public String signWith(byte[] key, SignatureAlgorithm algo) {
+ return signWith(JwsUtils.getHmacSignatureProvider(key, algo));
+ }
+ public String signWith(JwsSignatureProvider signer,
+ JwsHeaders protectedHeader,
+ JwsHeaders unprotectedHeader) {
+ JwsHeaders unionHeaders = new JwsHeaders();
+
+ if (protectedHeader != null) {
+ unionHeaders.asMap().putAll(protectedHeader.asMap());
+ }
+ if (unprotectedHeader != null) {
+ checkUnprotectedHeaders(unprotectedHeader,
+ JoseConstants.HEADER_CRITICAL,
+ JoseConstants.JWS_HEADER_B64_STATUS_HEADER);
+ if (!Collections.disjoint(unionHeaders.asMap().keySet(),
+ unprotectedHeader.asMap().keySet())) {
+ LOG.warning("Protected and unprotected headers have duplicate values");
+ throw new JwsException(JwsException.Error.INVALID_JSON_JWS);
+ }
+ unionHeaders.asMap().putAll(unprotectedHeader.asMap());
+ }
+ if (unionHeaders.getSignatureAlgorithm() == null) {
+ LOG.warning("Algorithm header is not set");
+ throw new JwsException(JwsException.Error.INVALID_JSON_JWS);
+ }
+ String sequenceToBeSigned;
+ String actualPayload = protectedHeader != null
+ ? getActualPayload(protectedHeader.getPayloadEncodingStatus())
+ : getUnsignedEncodedPayload();
+ if (protectedHeader != null) {
+ sequenceToBeSigned = Base64UrlUtility.encode(writer.toJson(protectedHeader))
+ + "." + actualPayload;
+ } else {
+ sequenceToBeSigned = "." + getUnsignedEncodedPayload();
+ }
+ byte[] bytesToBeSigned = StringUtils.toBytesUTF8(sequenceToBeSigned);
+
+ byte[] signatureBytes = signer.sign(unionHeaders, bytesToBeSigned);
+
+ String encodedSignatureBytes = Base64UrlUtility.encode(signatureBytes);
+ JwsJsonSignatureEntry signature;
+ if (protectedHeader != null) {
+ signature = new JwsJsonSignatureEntry(actualPayload,
+ Base64UrlUtility.encode(writer.toJson(protectedHeader)),
+ encodedSignatureBytes,
+ unprotectedHeader);
+ } else {
+ signature = new JwsJsonSignatureEntry(getUnsignedEncodedPayload(),
+ null,
+ encodedSignatureBytes,
+ unprotectedHeader);
+ }
+ return updateJwsJsonSignedDocument(signature);
+ }
+ private String getActualPayload(Boolean payloadEncodingStatus) {
+ return Boolean.FALSE == payloadEncodingStatus
+ ? getPlainPayload() : this.getUnsignedEncodedPayload();
+ }
+ private String updateJwsJsonSignedDocument(JwsJsonSignatureEntry signature) {
+ signatures.add(signature);
+ return getJwsJsonSignedDocument();
+ }
+ private static void checkUnprotectedHeaders(JoseHeaders unprotected, String... headerNames) {
+ for (String headerName : headerNames) {
+ if (unprotected.containsHeader(headerName)) {
+ LOG.warning("Unprotected headers contain a header \""
+ + headerName + "\" which must be protected");
+ throw new JwsException(JwsException.Error.INVALID_JSON_JWS);
+ }
+ }
+ }
+ static Boolean validateB64Status(List<JwsJsonSignatureEntry> signatures) {
+ Set<Boolean> b64Set = new LinkedHashSet<Boolean>();
+ for (JwsJsonSignatureEntry entry : signatures) {
+ JwsHeaders headers = entry.getProtectedHeader();
+ Boolean status = headers != null ? headers.getPayloadEncodingStatus() : null;
+ if (status == null) {
+ status = Boolean.TRUE;
+ }
+ b64Set.add(status);
+ }
+ if (b64Set.size() > 1) {
+ LOG.warning("Each signature entry can sign only encoded or only unencoded payload");
+ throw new JwsException(JwsException.Error.INVALID_JSON_JWS);
+ }
+ return b64Set.iterator().next();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonSignatureEntry.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonSignatureEntry.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonSignatureEntry.java
new file mode 100644
index 0000000..85f89df
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonSignatureEntry.java
@@ -0,0 +1,163 @@
+/**
+ * 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 java.util.Collections;
+import java.util.logging.Logger;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter;
+import org.apache.cxf.rs.security.jose.common.JoseConstants;
+import org.apache.cxf.rs.security.jose.common.JoseUtils;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+
+
+public class JwsJsonSignatureEntry {
+ protected static final Logger LOG = LogUtils.getL7dLogger(JwsJsonSignatureEntry.class);
+ private String jwsPayload;
+ private String encodedProtectedHeader;
+ private String encodedSignature;
+ private JwsHeaders protectedHeader;
+ private JwsHeaders unprotectedHeader;
+ private JwsHeaders unionHeaders;
+ private JsonMapObjectReaderWriter writer = new JsonMapObjectReaderWriter();
+
+ public JwsJsonSignatureEntry(String jwsPayload,
+ String encodedProtectedHeader,
+ String encodedSignature,
+ JwsHeaders unprotectedHeader) {
+ if (encodedProtectedHeader == null && unprotectedHeader == null || encodedSignature == null) {
+ LOG.warning("Invalid Signature entry");
+ throw new JwsException(JwsException.Error.INVALID_JSON_JWS);
+ }
+
+ this.jwsPayload = jwsPayload;
+ this.encodedProtectedHeader = encodedProtectedHeader;
+ this.encodedSignature = encodedSignature;
+ this.unprotectedHeader = unprotectedHeader;
+ if (encodedProtectedHeader != null) {
+ this.protectedHeader = new JwsHeaders(writer.fromJson(JoseUtils.decodeToString(encodedProtectedHeader)));
+ }
+ prepare();
+ }
+ private void prepare() {
+ unionHeaders = new JwsHeaders();
+
+ if (protectedHeader != null) {
+ unionHeaders.asMap().putAll(protectedHeader.asMap());
+ }
+ if (unprotectedHeader != null) {
+ if (!Collections.disjoint(unionHeaders.asMap().keySet(),
+ unprotectedHeader.asMap().keySet())) {
+ LOG.warning("Protected and unprotected headers have duplicate values");
+ throw new JwsException(JwsException.Error.INVALID_JSON_JWS);
+ }
+ unionHeaders.asMap().putAll(unprotectedHeader.asMap());
+ }
+ }
+ public String getJwsPayload() {
+ return jwsPayload;
+ }
+ public String getDecodedJwsPayload() {
+ if (protectedHeader == null || !JwsUtils.isPayloadUnencoded(protectedHeader)) {
+ return JoseUtils.decodeToString(jwsPayload);
+ } else {
+ return jwsPayload;
+ }
+ }
+ public byte[] getDecodedJwsPayloadBytes() {
+ return StringUtils.toBytesUTF8(getDecodedJwsPayload());
+ }
+ public String getEncodedProtectedHeader() {
+ return encodedProtectedHeader;
+ }
+ public JwsHeaders getProtectedHeader() {
+ return protectedHeader;
+ }
+ public JwsHeaders getUnprotectedHeader() {
+ return unprotectedHeader;
+ }
+ public JwsHeaders getUnionHeader() {
+ return unionHeaders;
+ }
+ public String getEncodedSignature() {
+ return encodedSignature;
+ }
+ public byte[] getDecodedSignature() {
+ return JoseUtils.decode(getEncodedSignature());
+ }
+ public String getUnsignedSequence() {
+ if (getEncodedProtectedHeader() != null) {
+ return getEncodedProtectedHeader() + "." + getJwsPayload();
+ } else {
+ return "." + getJwsPayload();
+ }
+ }
+ public String getKeyId() {
+ return getUnionHeader().getKeyId();
+ }
+ public boolean verifySignatureWith(JwsSignatureVerifier validator) {
+ try {
+ if (validator.verify(getUnionHeader(),
+ getUnsignedSequence(),
+ getDecodedSignature())) {
+ return true;
+ }
+ } catch (JwsException ex) {
+ // ignore
+ }
+ LOG.warning("Invalid Signature Entry");
+ return false;
+ }
+ public boolean verifySignatureWith(JsonWebKey key) {
+ return verifySignatureWith(JwsUtils.getSignatureVerifier(key));
+ }
+ public boolean validateCriticalHeaders() {
+ if (this.getUnprotectedHeader().getHeader(JoseConstants.HEADER_CRITICAL) != null) {
+ return false;
+ }
+ return JwsUtils.validateCriticalHeaders(getUnionHeader());
+ }
+ public String toJson() {
+ return toJson(false);
+ }
+ public String toJson(boolean flattenedMode) {
+ StringBuilder sb = new StringBuilder();
+ if (!flattenedMode) {
+ sb.append("{");
+ }
+ if (protectedHeader != null) {
+ sb.append("\"protected\":\"" + Base64UrlUtility.encode(writer.toJson(protectedHeader)) + "\"");
+ }
+ if (unprotectedHeader != null) {
+ if (protectedHeader != null) {
+ sb.append(",");
+ }
+ sb.append("\"header\":" + writer.toJson(unprotectedHeader));
+ }
+ sb.append(",");
+ sb.append("\"signature\":\"" + encodedSignature + "\"");
+ if (!flattenedMode) {
+ sb.append("}");
+ }
+ return sb.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactConsumer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactConsumer.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactConsumer.java
new file mode 100644
index 0000000..e2bcfa8
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactConsumer.java
@@ -0,0 +1,43 @@
+/**
+ * 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.jwt.JwtClaims;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.cxf.rs.security.jose.jwt.JwtTokenReaderWriter;
+
+public class JwsJwtCompactConsumer extends JwsCompactConsumer {
+ private JwtToken token;
+ public JwsJwtCompactConsumer(String encodedJws) {
+ super(encodedJws, null, new JwtTokenReaderWriter());
+ }
+ public JwtClaims getJwtClaims() {
+ return getJwtToken().getClaims();
+ }
+ public JwtToken getJwtToken() {
+ if (token == null) {
+ JwsHeaders theHeaders = super.getJwsHeaders();
+ JwtClaims theClaims =
+ ((JwtTokenReaderWriter)getReader()).fromJsonClaims(getDecodedJwsPayload());
+ token = new JwtToken(theHeaders, theClaims);
+ }
+ return token;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactProducer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactProducer.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactProducer.java
new file mode 100644
index 0000000..beaa598
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactProducer.java
@@ -0,0 +1,44 @@
+/**
+ * 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.common.JoseHeaders;
+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.JwtTokenReaderWriter;
+import org.apache.cxf.rs.security.jose.jwt.JwtUtils;
+
+
+public class JwsJwtCompactProducer extends JwsCompactProducer {
+
+ public JwsJwtCompactProducer(JwtToken token) {
+ this(token, null);
+ }
+ public JwsJwtCompactProducer(JwtClaims claims) {
+ this(new JwtToken(null, claims), null);
+ }
+ public JwsJwtCompactProducer(JoseHeaders headers, JwtClaims claims) {
+ this(new JwtToken(headers, claims), null);
+ }
+ protected JwsJwtCompactProducer(JwtToken token, JwtTokenReaderWriter w) {
+ super(new JwsHeaders(token.getHeaders()), w,
+ JwtUtils.claimsToJson(token.getClaims(), w));
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsOutputStream.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsOutputStream.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsOutputStream.java
new file mode 100644
index 0000000..53b592f
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsOutputStream.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.rs.security.jose.jws;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+import org.apache.cxf.common.util.Base64UrlUtility;
+
+public class JwsOutputStream extends FilterOutputStream {
+ private boolean flushed;
+ private JwsSignature signature;
+ public JwsOutputStream(OutputStream out, JwsSignature signature) {
+ super(out);
+ this.signature = signature;
+ }
+
+ @Override
+ public void write(int value) throws IOException {
+ byte[] bytes = ByteBuffer.allocate(Integer.SIZE / 8).putInt(value).array();
+ write(bytes, 0, bytes.length);
+ }
+
+ @Override
+ public void write(byte b[], int off, int len) throws IOException {
+ signature.update(b, off, len);
+ out.write(b, off, len);
+ out.flush();
+ }
+ @Override
+ public void flush() throws IOException {
+ if (flushed) {
+ return;
+ }
+ byte[] finalBytes = signature.sign();
+ out.write(new byte[]{'.'});
+ Base64UrlUtility.encodeAndStream(finalBytes, 0, finalBytes.length, out);
+ flushed = true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignature.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignature.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignature.java
new file mode 100644
index 0000000..778b5cb
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignature.java
@@ -0,0 +1,25 @@
+/**
+ * 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;
+
+
+public interface JwsSignature {
+ void update(byte[] src, int off, int len);
+ byte[] sign();
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureProvider.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureProvider.java
new file mode 100644
index 0000000..00f0c2a
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureProvider.java
@@ -0,0 +1,31 @@
+/**
+ * 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.jwa.SignatureAlgorithm;
+
+
+public interface JwsSignatureProvider {
+ SignatureAlgorithm getAlgorithm();
+ byte[] sign(JwsHeaders headers, byte[] content);
+ /**
+ * Create a signature handler capable of updating the signature input (optional operation)
+ */
+ JwsSignature createJwsSignature(JwsHeaders headers);
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureVerifier.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureVerifier.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureVerifier.java
new file mode 100644
index 0000000..c44a678
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureVerifier.java
@@ -0,0 +1,26 @@
+/**
+ * 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.jwa.SignatureAlgorithm;
+
+public interface JwsSignatureVerifier {
+ SignatureAlgorithm getAlgorithm();
+ boolean verify(JwsHeaders headers, String unsignedText, byte[] signature);
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
new file mode 100644
index 0000000..27e2e0f
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
@@ -0,0 +1,425 @@
+/**
+ * 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 java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
+import org.apache.cxf.phase.PhaseInterceptorChain;
+import org.apache.cxf.rs.security.jose.common.JoseConstants;
+import org.apache.cxf.rs.security.jose.common.JoseHeaders;
+import org.apache.cxf.rs.security.jose.common.JoseUtils;
+import org.apache.cxf.rs.security.jose.common.KeyManagementUtils;
+import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils;
+import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+import org.apache.cxf.rs.security.jose.jwk.JwkUtils;
+import org.apache.cxf.rs.security.jose.jwk.KeyOperation;
+import org.apache.cxf.rs.security.jose.jwk.KeyType;
+
+public final class JwsUtils {
+ private static final Logger LOG = LogUtils.getL7dLogger(JwsUtils.class);
+
+ private JwsUtils() {
+
+ }
+ public static String sign(PrivateKey key, SignatureAlgorithm algo, String content) {
+ return sign(key, algo, content, null);
+ }
+
+
+ public static String sign(PrivateKey key, SignatureAlgorithm algo, String content, String ct) {
+ return sign(getPrivateKeySignatureProvider(key, algo), content, ct);
+ }
+ public static String sign(byte[] key, SignatureAlgorithm algo, String content) {
+ return sign(key, algo, content, null);
+ }
+ public static String sign(byte[] key, SignatureAlgorithm algo, String content, String ct) {
+ return sign(getHmacSignatureProvider(key, algo), content, ct);
+ }
+ public static String verify(PublicKey key, SignatureAlgorithm algo, String content) {
+ JwsCompactConsumer jws = verify(getPublicKeySignatureVerifier(key, algo), content);
+ return jws.getDecodedJwsPayload();
+ }
+ public static String verify(byte[] key, SignatureAlgorithm algo, String content) {
+ JwsCompactConsumer jws = verify(getHmacSignatureVerifier(key, algo), content);
+ return jws.getDecodedJwsPayload();
+ }
+ public static JwsSignatureProvider getSignatureProvider(JsonWebKey jwk) {
+ return getSignatureProvider(jwk, null);
+ }
+ public static JwsSignatureProvider getSignatureProvider(JsonWebKey jwk,
+ SignatureAlgorithm defaultAlgorithm) {
+ SignatureAlgorithm sigAlgo = jwk.getAlgorithm() == null ? defaultAlgorithm
+ : SignatureAlgorithm.getAlgorithm(jwk.getAlgorithm());
+ JwsSignatureProvider theSigProvider = null;
+ KeyType keyType = jwk.getKeyType();
+ if (KeyType.RSA == keyType) {
+ theSigProvider = getPrivateKeySignatureProvider(JwkUtils.toRSAPrivateKey(jwk),
+ sigAlgo);
+ } else if (KeyType.OCTET == keyType) {
+ byte[] key = JoseUtils.decode((String)jwk.getProperty(JsonWebKey.OCTET_KEY_VALUE));
+ theSigProvider = getHmacSignatureProvider(key, sigAlgo);
+ } else if (KeyType.EC == jwk.getKeyType()) {
+ theSigProvider = getPrivateKeySignatureProvider(JwkUtils.toECPrivateKey(jwk),
+ sigAlgo);
+ }
+ return theSigProvider;
+ }
+ public static JwsSignatureProvider getPrivateKeySignatureProvider(PrivateKey key, SignatureAlgorithm algo) {
+ if (algo == null) {
+ LOG.warning("No signature algorithm was defined");
+ throw new JwsException(JwsException.Error.ALGORITHM_NOT_SET);
+ }
+ if (key instanceof ECPrivateKey) {
+ return new EcDsaJwsSignatureProvider((ECPrivateKey)key, algo);
+ } else if (key instanceof RSAPrivateKey) {
+ return new PrivateKeyJwsSignatureProvider(key, algo);
+ }
+
+ return null;
+ }
+ public static JwsSignatureProvider getHmacSignatureProvider(byte[] key, SignatureAlgorithm algo) {
+ if (algo == null) {
+ LOG.warning("No signature algorithm was defined");
+ throw new JwsException(JwsException.Error.ALGORITHM_NOT_SET);
+ }
+ if (AlgorithmUtils.isHmacSign(algo.getJwaName())) {
+ return new HmacJwsSignatureProvider(key, algo);
+ }
+ return null;
+ }
+ public static JwsSignatureVerifier getSignatureVerifier(JsonWebKey jwk) {
+ return getSignatureVerifier(jwk, null);
+ }
+ public static JwsSignatureVerifier getSignatureVerifier(JsonWebKey jwk, SignatureAlgorithm defaultAlgorithm) {
+ SignatureAlgorithm sigAlgo = jwk.getAlgorithm() == null ? defaultAlgorithm
+ : SignatureAlgorithm.getAlgorithm(jwk.getAlgorithm());
+ JwsSignatureVerifier theVerifier = null;
+ KeyType keyType = jwk.getKeyType();
+ if (KeyType.RSA == keyType) {
+ theVerifier = getPublicKeySignatureVerifier(JwkUtils.toRSAPublicKey(jwk, true), sigAlgo);
+ } else if (KeyType.OCTET == keyType) {
+ byte[] key = JoseUtils.decode((String)jwk.getProperty(JsonWebKey.OCTET_KEY_VALUE));
+ theVerifier = getHmacSignatureVerifier(key, sigAlgo);
+ } else if (KeyType.EC == keyType) {
+ theVerifier = getPublicKeySignatureVerifier(JwkUtils.toECPublicKey(jwk), sigAlgo);
+ }
+ return theVerifier;
+ }
+ public static JwsSignatureVerifier getPublicKeySignatureVerifier(X509Certificate cert, SignatureAlgorithm algo) {
+ return getPublicKeySignatureVerifier(cert.getPublicKey(), algo);
+ }
+ public static JwsSignatureVerifier getPublicKeySignatureVerifier(PublicKey key, SignatureAlgorithm algo) {
+ if (algo == null) {
+ LOG.warning("No signature algorithm was defined");
+ throw new JwsException(JwsException.Error.ALGORITHM_NOT_SET);
+ }
+
+ if (key instanceof RSAPublicKey) {
+ return new PublicKeyJwsSignatureVerifier(key, algo);
+ } else if (key instanceof ECPublicKey) {
+ return new EcDsaJwsSignatureVerifier(key, algo);
+ }
+
+ return null;
+ }
+ public static JwsSignatureVerifier getHmacSignatureVerifier(byte[] key, SignatureAlgorithm algo) {
+ if (algo == null) {
+ LOG.warning("No signature algorithm was defined");
+ throw new JwsException(JwsException.Error.ALGORITHM_NOT_SET);
+ }
+
+ if (AlgorithmUtils.isHmacSign(algo.getJwaName())) {
+ return new HmacJwsSignatureVerifier(key, algo);
+ }
+ return null;
+ }
+
+ public static Map<SignatureAlgorithm, List<JwsJsonSignatureEntry>> getJwsJsonSignatureMap(
+ List<JwsJsonSignatureEntry> signatures) {
+ Map<SignatureAlgorithm, List<JwsJsonSignatureEntry>> map = new HashMap<>();
+ for (JwsJsonSignatureEntry entry : signatures) {
+ SignatureAlgorithm sigAlgorithm = entry.getUnionHeader().getSignatureAlgorithm();
+ List<JwsJsonSignatureEntry> entries = map.get(sigAlgorithm);
+ if (entries == null) {
+ entries = new ArrayList<>();
+ }
+ entries.add(entry);
+ map.put(sigAlgorithm, entries);
+ }
+ return map;
+ }
+
+ public static JwsSignatureProvider loadSignatureProvider(boolean required) {
+ return loadSignatureProvider(null, required);
+ }
+ public static JwsSignatureProvider loadSignatureProvider(JwsHeaders headers, boolean required) {
+ Message m = PhaseInterceptorChain.getCurrentMessage();
+ Properties props = KeyManagementUtils.loadStoreProperties(m, required,
+ JoseConstants.RSSEC_SIGNATURE_OUT_PROPS,
+ JoseConstants.RSSEC_SIGNATURE_PROPS);
+ if (props == null) {
+ return null;
+ }
+ JwsSignatureProvider theSigProvider = loadSignatureProvider(m, props, headers, false);
+ if (headers != null) {
+ headers.setSignatureAlgorithm(theSigProvider.getAlgorithm());
+ }
+ return theSigProvider;
+ }
+ public static JwsSignatureVerifier loadSignatureVerifier(boolean required) {
+ return loadSignatureVerifier(null, required);
+ }
+ public static JwsSignatureVerifier loadSignatureVerifier(JwsHeaders headers, boolean required) {
+ Message m = PhaseInterceptorChain.getCurrentMessage();
+ Properties props = KeyManagementUtils.loadStoreProperties(m, required,
+ JoseConstants.RSSEC_SIGNATURE_IN_PROPS,
+ JoseConstants.RSSEC_SIGNATURE_PROPS);
+ return loadSignatureVerifier(m, props, headers, false);
+ }
+ public static List<JwsSignatureProvider> loadSignatureProviders(String propLoc, Message m) {
+ Properties props = loadJwsProperties(m, propLoc);
+ JwsSignatureProvider theSigProvider = loadSignatureProvider(m, props, null, true);
+ if (theSigProvider != null) {
+ return Collections.singletonList(theSigProvider);
+ }
+ List<JwsSignatureProvider> theSigProviders = null;
+ if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
+ List<JsonWebKey> jwks = JwkUtils.loadJsonWebKeys(m, props, KeyOperation.SIGN);
+ if (jwks != null) {
+ theSigProviders = new ArrayList<JwsSignatureProvider>(jwks.size());
+ for (JsonWebKey jwk : jwks) {
+ theSigProviders.add(JwsUtils.getSignatureProvider(jwk));
+ }
+ }
+ }
+ if (theSigProviders == null) {
+ LOG.warning("Providers are not available");
+ throw new JwsException(JwsException.Error.NO_PROVIDER);
+ }
+ return theSigProviders;
+ }
+
+ public static List<JwsSignatureVerifier> loadSignatureVerifiers(String propLoc, Message m) {
+ Properties props = loadJwsProperties(m, propLoc);
+ JwsSignatureVerifier theVerifier = loadSignatureVerifier(m, props, null, true);
+ if (theVerifier != null) {
+ return Collections.singletonList(theVerifier);
+ }
+ List<JwsSignatureVerifier> theVerifiers = null;
+ if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
+ List<JsonWebKey> jwks = JwkUtils.loadJsonWebKeys(m, props, KeyOperation.VERIFY);
+ if (jwks != null) {
+ theVerifiers = new ArrayList<JwsSignatureVerifier>(jwks.size());
+ for (JsonWebKey jwk : jwks) {
+ theVerifiers.add(JwsUtils.getSignatureVerifier(jwk));
+ }
+ }
+ }
+ if (theVerifiers == null) {
+ LOG.warning("Verifiers are not available");
+ throw new JwsException(JwsException.Error.NO_VERIFIER);
+ }
+ return theVerifiers;
+ }
+ public static boolean validateCriticalHeaders(JoseHeaders headers) {
+ //TODO: validate JWS specific constraints
+ return JoseUtils.validateCriticalHeaders(headers);
+ }
+ private static JwsSignatureProvider loadSignatureProvider(Message m,
+ Properties props,
+ JoseHeaders headers,
+ boolean ignoreNullProvider) {
+ JwsSignatureProvider theSigProvider = null;
+
+ boolean reportPublicKey = headers != null && MessageUtils.isTrue(
+ MessageUtils.getContextualProperty(m, JoseConstants.RSSEC_REPORT_KEY_PROP,
+ JoseConstants.RSSEC_REPORT_KEY_PROP));
+ boolean reportPublicKeyId =
+ headers != null && MessageUtils.isTrue(
+ MessageUtils.getContextualProperty(m, JoseConstants.RSSEC_REPORT_KEY_ID_PROP,
+ JoseConstants.RSSEC_REPORT_KEY_ID_PROP));
+ if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
+ JsonWebKey jwk = JwkUtils.loadJsonWebKey(m, props, KeyOperation.SIGN);
+ if (jwk != null) {
+ String signatureAlgo = getSignatureAlgo(m, props, jwk.getAlgorithm(), getDefaultKeyAlgo(jwk));
+ theSigProvider = JwsUtils.getSignatureProvider(jwk, SignatureAlgorithm.getAlgorithm(signatureAlgo));
+ if (reportPublicKey || reportPublicKeyId) {
+ JwkUtils.setPublicKeyInfo(jwk, headers, signatureAlgo, reportPublicKey, reportPublicKeyId);
+ }
+ }
+ } else {
+ String signatureAlgo = getSignatureAlgo(m, props, null, null);
+ PrivateKey pk = KeyManagementUtils.loadPrivateKey(m, props, KeyOperation.SIGN);
+ theSigProvider = getPrivateKeySignatureProvider(pk,
+ SignatureAlgorithm.getAlgorithm(signatureAlgo));
+ if (reportPublicKey) {
+ headers.setX509Chain(KeyManagementUtils.loadAndEncodeX509CertificateOrChain(m, props));
+ }
+ }
+ if (theSigProvider == null && !ignoreNullProvider) {
+ LOG.warning("Provider is not available");
+ throw new JwsException(JwsException.Error.NO_PROVIDER);
+ }
+ return theSigProvider;
+ }
+ private static JwsSignatureVerifier loadSignatureVerifier(Message m,
+ Properties props,
+ JwsHeaders inHeaders,
+ boolean ignoreNullVerifier) {
+ JwsSignatureVerifier theVerifier = null;
+ String inHeaderKid = null;
+ if (inHeaders != null) {
+ inHeaderKid = inHeaders.getKeyId();
+ //TODO: optionally validate inHeaders.getAlgorithm against a property in props
+ if (inHeaders.getHeader(JoseConstants.HEADER_JSON_WEB_KEY) != null) {
+ JsonWebKey publicJwk = inHeaders.getJsonWebKey();
+ if (inHeaderKid != null && !inHeaderKid.equals(publicJwk.getKeyId())
+ || !MessageUtils.getContextualBoolean(m, JoseConstants.RSSEC_ACCEPT_PUBLIC_KEY_PROP, true)) {
+ throw new JwsException(JwsException.Error.INVALID_KEY);
+ }
+ return getSignatureVerifier(publicJwk,
+ inHeaders.getSignatureAlgorithm());
+ } else if (inHeaders.getHeader(JoseConstants.HEADER_X509_CHAIN) != null) {
+ List<X509Certificate> chain = KeyManagementUtils.toX509CertificateChain(inHeaders.getX509Chain());
+ KeyManagementUtils.validateCertificateChain(props, chain);
+ return getPublicKeySignatureVerifier(chain.get(0).getPublicKey(),
+ inHeaders.getSignatureAlgorithm());
+ }
+ }
+
+ if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
+ JsonWebKey jwk = JwkUtils.loadJsonWebKey(m, props, KeyOperation.VERIFY, inHeaderKid);
+ if (jwk != null) {
+ String signatureAlgo = getSignatureAlgo(m, props, jwk.getAlgorithm(), getDefaultKeyAlgo(jwk));
+ theVerifier = getSignatureVerifier(jwk, SignatureAlgorithm.getAlgorithm(signatureAlgo));
+ }
+
+ } else {
+ String signatureAlgo = getSignatureAlgo(m, props, null, null);
+ if (SignatureAlgorithm.getAlgorithm(signatureAlgo) == SignatureAlgorithm.NONE
+ && SignatureAlgorithm.NONE.getJwaName().equals(inHeaders.getAlgorithm())) {
+ theVerifier = new NoneJwsSignatureVerifier();
+ } else {
+ theVerifier = getPublicKeySignatureVerifier(
+ KeyManagementUtils.loadPublicKey(m, props),
+ SignatureAlgorithm.getAlgorithm(signatureAlgo));
+ }
+ }
+ if (theVerifier == null && !ignoreNullVerifier) {
+ LOG.warning("Verifier is not available");
+ throw new JwsException(JwsException.Error.NO_VERIFIER);
+ }
+ return theVerifier;
+ }
+ private static Properties loadJwsProperties(Message m, String propLoc) {
+ try {
+ return JoseUtils.loadProperties(propLoc, m.getExchange().getBus());
+ } catch (Exception ex) {
+ LOG.warning("JWS init properties are not available");
+ throw new JwsException(JwsException.Error.NO_INIT_PROPERTIES);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public static String getSignatureAlgo(Message m, Properties props, String algo, String defaultAlgo) {
+ if (algo == null) {
+ if (defaultAlgo == null) {
+ defaultAlgo = AlgorithmUtils.RS_SHA_256_ALGO;
+ }
+
+ // Check for deprecated identifier first
+ String sigAlgo = props.getProperty(JoseConstants.DEPR_RSSEC_SIGNATURE_ALGORITHM);
+ if (sigAlgo == null) {
+ sigAlgo = (String)m.getContextualProperty(JoseConstants.DEPR_RSSEC_SIGNATURE_ALGORITHM);
+ }
+ if (sigAlgo != null) {
+ return sigAlgo;
+ }
+
+ // Otherwise check newer identifier
+ return KeyManagementUtils.getKeyAlgorithm(m, props,
+ JoseConstants.RSSEC_SIGNATURE_ALGORITHM, defaultAlgo);
+ }
+ return algo;
+ }
+ private static String getDefaultKeyAlgo(JsonWebKey jwk) {
+ KeyType keyType = jwk.getKeyType();
+ if (KeyType.OCTET == keyType) {
+ return AlgorithmUtils.HMAC_SHA_256_ALGO;
+ } else if (KeyType.EC == keyType) {
+ return AlgorithmUtils.ES_SHA_256_ALGO;
+ } else {
+ return AlgorithmUtils.RS_SHA_256_ALGO;
+ }
+ }
+ public static JwsCompactConsumer verify(JwsSignatureVerifier v, String content) {
+ JwsCompactConsumer jws = new JwsCompactConsumer(content);
+ if (!jws.verifySignatureWith(v)) {
+ throw new JwsException(JwsException.Error.INVALID_SIGNATURE);
+ }
+ return jws;
+ }
+ public static String sign(JwsSignatureProvider jwsSig, String content, String ct) {
+ JwsHeaders headers = new JwsHeaders();
+ if (ct != null) {
+ headers.setContentType(ct);
+ }
+ JwsCompactProducer jws = new JwsCompactProducer(headers, content);
+ jws.signWith(jwsSig);
+ return jws.getSignedEncodedJws();
+ }
+ public static void validateJwsCertificateChain(List<X509Certificate> certs) {
+
+ Message m = PhaseInterceptorChain.getCurrentMessage();
+ Properties props = KeyManagementUtils.loadStoreProperties(m, true,
+ JoseConstants.RSSEC_SIGNATURE_IN_PROPS,
+ JoseConstants.RSSEC_SIGNATURE_PROPS);
+ KeyManagementUtils.validateCertificateChain(props, certs);
+ }
+ public static boolean isPayloadUnencoded(JwsHeaders jwsHeaders) {
+ return jwsHeaders.getPayloadEncodingStatus() == Boolean.FALSE;
+ }
+
+ public static void checkSignatureKeySize(Key key) {
+ if (key instanceof RSAKey && ((RSAKey)key).getModulus().bitLength() < 2048) {
+ LOG.fine("A key of size: " + ((RSAKey)key).getModulus().bitLength()
+ + " was used with an RSA signature algorithm. 2048 is the minimum size that is accepted");
+ throw new JwsException(JwsException.Error.INVALID_KEY);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/NoneJwsSignatureProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/NoneJwsSignatureProvider.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/NoneJwsSignatureProvider.java
new file mode 100644
index 0000000..6ed31fd
--- /dev/null
+++ b/rt/rs/security/jose-parent/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.jwa.SignatureAlgorithm;
+
+public class NoneJwsSignatureProvider implements JwsSignatureProvider {
+
+ @Override
+ public SignatureAlgorithm getAlgorithm() {
+ return SignatureAlgorithm.NONE;
+ }
+
+ @Override
+ public JwsSignature createJwsSignature(JwsHeaders headers) {
+ return new NoneJwsSignature();
+ }
+
+ @Override
+ public byte[] sign(JwsHeaders 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/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/NoneJwsSignatureVerifier.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/NoneJwsSignatureVerifier.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/NoneJwsSignatureVerifier.java
new file mode 100644
index 0000000..441261b
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/NoneJwsSignatureVerifier.java
@@ -0,0 +1,36 @@
+/**
+ * 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.jwa.SignatureAlgorithm;
+
+public class NoneJwsSignatureVerifier implements JwsSignatureVerifier {
+
+ @Override
+ public boolean verify(JwsHeaders headers, String unsignedText, byte[] signature) {
+ return headers.getSignatureAlgorithm() == getAlgorithm()
+ && signature.length == 0;
+ }
+
+ @Override
+ public SignatureAlgorithm getAlgorithm() {
+ return SignatureAlgorithm.NONE;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PrivateKeyJwsSignatureProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PrivateKeyJwsSignatureProvider.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PrivateKeyJwsSignatureProvider.java
new file mode 100644
index 0000000..476d90f
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PrivateKeyJwsSignatureProvider.java
@@ -0,0 +1,91 @@
+/**
+ * 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 java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils;
+import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+import org.apache.cxf.rt.security.crypto.CryptoUtils;
+
+public class PrivateKeyJwsSignatureProvider extends AbstractJwsSignatureProvider {
+ private PrivateKey key;
+ private SecureRandom random;
+ private AlgorithmParameterSpec signatureSpec;
+
+ public PrivateKeyJwsSignatureProvider(PrivateKey key, SignatureAlgorithm algo) {
+ this(key, null, algo);
+ }
+ public PrivateKeyJwsSignatureProvider(PrivateKey key, AlgorithmParameterSpec spec, SignatureAlgorithm algo) {
+ this(key, null, spec, algo);
+ }
+ public PrivateKeyJwsSignatureProvider(PrivateKey key, SecureRandom random,
+ AlgorithmParameterSpec spec, SignatureAlgorithm algo) {
+ super(algo);
+ this.key = key;
+ this.random = random;
+ this.signatureSpec = spec;
+ }
+ protected JwsSignature doCreateJwsSignature(JwsHeaders headers) {
+ final String sigAlgo = headers.getSignatureAlgorithm().getJwaName();
+ final Signature s = CryptoUtils.getSignature(key,
+ AlgorithmUtils.toJavaName(sigAlgo),
+ random,
+ signatureSpec);
+ return doCreateJwsSignature(s);
+ }
+ protected JwsSignature doCreateJwsSignature(Signature s) {
+ return new PrivateKeyJwsSignature(s);
+ }
+
+ @Override
+ protected boolean isValidAlgorithmFamily(String algo) {
+ return AlgorithmUtils.isRsaSign(algo);
+ }
+
+ protected static class PrivateKeyJwsSignature implements JwsSignature {
+ private Signature s;
+ public PrivateKeyJwsSignature(Signature s) {
+ this.s = s;
+ }
+ @Override
+ public void update(byte[] src, int off, int len) {
+ try {
+ s.update(src, off, len);
+ } catch (SignatureException ex) {
+ throw new JwsException(JwsException.Error.SIGNATURE_FAILURE, ex);
+ }
+ }
+
+ @Override
+ public byte[] sign() {
+ try {
+ return s.sign();
+ } catch (SignatureException ex) {
+ throw new JwsException(JwsException.Error.SIGNATURE_FAILURE, ex);
+ }
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PublicKeyJwsSignatureVerifier.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PublicKeyJwsSignatureVerifier.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PublicKeyJwsSignatureVerifier.java
new file mode 100644
index 0000000..65a2a15
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PublicKeyJwsSignatureVerifier.java
@@ -0,0 +1,81 @@
+/**
+ * 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 java.security.PublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.logging.Logger;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils;
+import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+import org.apache.cxf.rt.security.crypto.CryptoUtils;
+
+public class PublicKeyJwsSignatureVerifier implements JwsSignatureVerifier {
+ protected static final Logger LOG = LogUtils.getL7dLogger(PublicKeyJwsSignatureVerifier.class);
+ private PublicKey key;
+ private AlgorithmParameterSpec signatureSpec;
+ private SignatureAlgorithm supportedAlgo;
+
+ public PublicKeyJwsSignatureVerifier(PublicKey key, SignatureAlgorithm supportedAlgorithm) {
+ this(key, null, supportedAlgorithm);
+ }
+ public PublicKeyJwsSignatureVerifier(PublicKey key, AlgorithmParameterSpec spec, SignatureAlgorithm supportedAlgo) {
+ this.key = key;
+ this.signatureSpec = spec;
+ this.supportedAlgo = supportedAlgo;
+ JwsUtils.checkSignatureKeySize(key);
+ }
+ @Override
+ public boolean verify(JwsHeaders headers, String unsignedText, byte[] signature) {
+ try {
+ return CryptoUtils.verifySignature(StringUtils.toBytesUTF8(unsignedText),
+ signature,
+ key,
+ AlgorithmUtils.toJavaName(checkAlgorithm(
+ headers.getSignatureAlgorithm())),
+ signatureSpec);
+ } catch (Exception ex) {
+ LOG.warning("Invalid signature: " + ex.getMessage());
+ throw new JwsException(JwsException.Error.INVALID_SIGNATURE, ex);
+ }
+ }
+ protected String checkAlgorithm(SignatureAlgorithm sigAlgo) {
+ String algo = sigAlgo.getJwaName();
+ if (algo == null) {
+ LOG.warning("Signature algorithm is not set");
+ throw new JwsException(JwsException.Error.ALGORITHM_NOT_SET);
+ }
+ if (!isValidAlgorithmFamily(algo)
+ || !algo.equals(supportedAlgo.getJwaName())) {
+ LOG.warning("Invalid signature algorithm: " + algo);
+ throw new JwsException(JwsException.Error.INVALID_ALGORITHM);
+ }
+ return algo;
+ }
+ protected boolean isValidAlgorithmFamily(String algo) {
+ return AlgorithmUtils.isRsaSign(algo);
+ }
+ @Override
+ public SignatureAlgorithm getAlgorithm() {
+ return supportedAlgo;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java
new file mode 100644
index 0000000..daea97b
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java
@@ -0,0 +1,106 @@
+/**
+ * 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.common.AbstractJoseConsumer;
+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.jws.JwsHeaders;
+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 extends AbstractJoseConsumer {
+ private boolean jwsRequired = true;
+ private boolean jweRequired;
+
+
+ protected JwtToken getJwtToken(String wrappedJwtToken) {
+ return getJwtToken(wrappedJwtToken, null, null);
+ }
+ protected JwtToken getJwtToken(String wrappedJwtToken,
+ JweDecryptionProvider jweDecryptor,
+ JwsSignatureVerifier theSigVerifier) {
+ if (!isJwsRequired() && !isJweRequired()) {
+ throw new JwtException("Unable to process JWT");
+ }
+
+ if (isJweRequired()) {
+ if (jweDecryptor == null) {
+ jweDecryptor = getInitializedDecryptionProvider();
+ }
+ if (jweDecryptor == null) {
+ throw new JwtException("Unable to decrypt JWT");
+ }
+
+ if (!isJwsRequired()) {
+ return new JweJwtCompactConsumer(wrappedJwtToken).decryptWith(jweDecryptor);
+ }
+ wrappedJwtToken = jweDecryptor.decrypt(wrappedJwtToken).getContentText();
+ }
+
+
+ JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(wrappedJwtToken);
+ JwtToken jwt = jwtConsumer.getJwtToken();
+ if (isJwsRequired()) {
+ if (theSigVerifier == null) {
+ theSigVerifier = getInitializedSignatureVerifier(jwt);
+ }
+ if (theSigVerifier == null) {
+ throw new JwtException("Unable to validate JWT");
+ }
+
+ if (!jwtConsumer.verifySignatureWith(theSigVerifier)) {
+ throw new JwtException("Invalid Signature");
+ }
+ }
+
+ validateToken(jwt);
+ return jwt;
+ }
+ protected JwsSignatureVerifier getInitializedSignatureVerifier(JwtToken jwt) {
+ if (super.getJwsVerifier() != null) {
+ return super.getJwsVerifier();
+ }
+
+ if (jwt.getHeaders() instanceof JwsHeaders) {
+ return JwsUtils.loadSignatureVerifier((JwsHeaders)jwt.getHeaders(), false);
+ }
+
+ return super.getInitializedSignatureVerifier();
+ }
+ protected void validateToken(JwtToken jwt) {
+ }
+ public boolean isJwsRequired() {
+ return jwsRequired;
+ }
+
+ public void setJwsRequired(boolean jwsRequired) {
+ this.jwsRequired = jwsRequired;
+ }
+
+ public boolean isJweRequired() {
+ return jweRequired;
+ }
+
+ public void setJweRequired(boolean jweRequired) {
+ this.jweRequired = jweRequired;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java
new file mode 100644
index 0000000..a5f5c37
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java
@@ -0,0 +1,90 @@
+/**
+ * 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.common.AbstractJoseProducer;
+import org.apache.cxf.rs.security.jose.jwe.JweEncryptionProvider;
+import org.apache.cxf.rs.security.jose.jwe.JweJwtCompactProducer;
+import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactProducer;
+import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider;
+
+public abstract class AbstractJoseJwtProducer extends AbstractJoseProducer {
+ private boolean jwsRequired = true;
+ private boolean jweRequired;
+
+ protected String processJwt(JwtToken jwt) {
+ return processJwt(jwt, null, null);
+ }
+ protected String processJwt(JwtToken jwt,
+ JweEncryptionProvider theEncProvider,
+ JwsSignatureProvider theSigProvider) {
+ if (!isJwsRequired() && !isJweRequired()) {
+ throw new JwtException("Unable to secure JWT");
+ }
+ String data = null;
+
+ if (isJweRequired() && theEncProvider == null) {
+ theEncProvider = getInitializedEncryptionProvider();
+ if (theEncProvider == null) {
+ throw new JwtException("Unable to encrypt JWT");
+ }
+ }
+
+ if (isJwsRequired()) {
+ JwsJwtCompactProducer jws = new JwsJwtCompactProducer(jwt);
+ if (jws.isPlainText()) {
+ data = jws.getSignedEncodedJws();
+ } else {
+ if (theSigProvider == null) {
+ theSigProvider = getInitializedSignatureProvider();
+ }
+
+ if (theSigProvider == null) {
+ throw new JwtException("Unable to sign JWT");
+ }
+
+ data = jws.signWith(theSigProvider);
+ }
+ if (theEncProvider != null) {
+ data = theEncProvider.encrypt(StringUtils.toBytesUTF8(data), null);
+ }
+ } else {
+ JweJwtCompactProducer jwe = new JweJwtCompactProducer(jwt);
+ data = jwe.encryptWith(theEncProvider);
+ }
+ return data;
+ }
+
+ public boolean isJwsRequired() {
+ return jwsRequired;
+ }
+
+ public void setJwsRequired(boolean jwsRequired) {
+ this.jwsRequired = jwsRequired;
+ }
+
+ public boolean isJweRequired() {
+ return jweRequired;
+ }
+
+ public void setJweRequired(boolean jweRequired) {
+ this.jweRequired = jweRequired;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtClaims.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtClaims.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtClaims.java
new file mode 100644
index 0000000..6fcc85d
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtClaims.java
@@ -0,0 +1,102 @@
+/**
+ * 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 java.util.Map;
+
+import org.apache.cxf.jaxrs.json.basic.JsonMapObject;
+
+
+
+
+public class JwtClaims extends JsonMapObject {
+
+ public JwtClaims() {
+ }
+
+ public JwtClaims(Map<String, Object> values) {
+ super(values);
+ }
+
+ public void setIssuer(String issuer) {
+ setClaim(JwtConstants.CLAIM_ISSUER, issuer);
+ }
+
+ public String getIssuer() {
+ return (String)getClaim(JwtConstants.CLAIM_ISSUER);
+ }
+
+ public void setSubject(String subject) {
+ setClaim(JwtConstants.CLAIM_SUBJECT, subject);
+ }
+
+ public String getSubject() {
+ return (String)getClaim(JwtConstants.CLAIM_SUBJECT);
+ }
+
+ public void setAudience(String audience) {
+ setClaim(JwtConstants.CLAIM_AUDIENCE, audience);
+ }
+
+ public String getAudience() {
+ return (String)getClaim(JwtConstants.CLAIM_AUDIENCE);
+ }
+
+ public void setExpiryTime(Long expiresIn) {
+ setClaim(JwtConstants.CLAIM_EXPIRY, expiresIn);
+ }
+
+ public Long getExpiryTime() {
+ return getLongProperty(JwtConstants.CLAIM_EXPIRY);
+ }
+
+ public void setNotBefore(Long notBefore) {
+ setClaim(JwtConstants.CLAIM_NOT_BEFORE, notBefore);
+ }
+
+ public Long getNotBefore() {
+ return getLongProperty(JwtConstants.CLAIM_NOT_BEFORE);
+ }
+
+ public void setIssuedAt(Long issuedAt) {
+ setClaim(JwtConstants.CLAIM_ISSUED_AT, issuedAt);
+ }
+
+ public Long getIssuedAt() {
+ return getLongProperty(JwtConstants.CLAIM_ISSUED_AT);
+ }
+
+ public void setTokenId(String id) {
+ setClaim(JwtConstants.CLAIM_JWT_ID, id);
+ }
+
+ public String getTokenId() {
+ return (String)getClaim(JwtConstants.CLAIM_JWT_ID);
+ }
+
+ public JwtClaims setClaim(String name, Object value) {
+ setProperty(name, value);
+ return this;
+ }
+
+ public Object getClaim(String name) {
+ return getProperty(name);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtConstants.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtConstants.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtConstants.java
new file mode 100644
index 0000000..d0a663d
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtConstants.java
@@ -0,0 +1,39 @@
+/**
+ * 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;
+
+public final class JwtConstants {
+
+ public static final String CLAIM_ISSUER = "iss";
+ public static final String CLAIM_SUBJECT = "sub";
+ public static final String CLAIM_AUDIENCE = "aud";
+ public static final String CLAIM_EXPIRY = "exp";
+ public static final String CLAIM_NOT_BEFORE = "nbf";
+ public static final String CLAIM_ISSUED_AT = "iat";
+ public static final String CLAIM_JWT_ID = "jti";
+
+ public static final String JWT_TOKEN = "jwt.token";
+ public static final String JWT_CLAIMS = "jwt.claims";
+
+
+ private JwtConstants() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtException.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtException.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtException.java
new file mode 100644
index 0000000..5b8db17
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtException.java
@@ -0,0 +1,35 @@
+/**
+ * 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.common.JoseException;
+
+public class JwtException extends JoseException {
+
+ private static final long serialVersionUID = 4118589816228511524L;
+ public JwtException() {
+
+ }
+ public JwtException(String error) {
+ super(error);
+ }
+ public JwtException(Throwable cause) {
+ super(cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtToken.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtToken.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtToken.java
new file mode 100644
index 0000000..069b8f2
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtToken.java
@@ -0,0 +1,56 @@
+/**
+ * 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.common.JoseHeaders;
+
+
+
+public class JwtToken {
+ private JoseHeaders headers;
+ private JwtClaims claims;
+ public JwtToken(JwtClaims claims) {
+ this(new JoseHeaders() { }, claims);
+ }
+ public JwtToken(JoseHeaders headers, JwtClaims claims) {
+ this.headers = headers;
+ this.claims = claims;
+ }
+ public JoseHeaders getHeaders() {
+ return headers;
+ }
+ public JwtClaims getClaims() {
+ return claims;
+ }
+ public Object getHeader(String name) {
+ return headers.getHeader(name);
+ }
+ public Object getClaim(String name) {
+ return claims.getClaim(name);
+ }
+ public int hashCode() {
+ return headers.hashCode() + 37 * claims.hashCode();
+ }
+
+ public boolean equals(Object obj) {
+ return obj instanceof JwtToken
+ && ((JwtToken)obj).headers.equals(this.headers)
+ && ((JwtToken)obj).claims.equals(this.claims);
+ }
+}