Skip to content
Permalink
Browse files
add a PrivateKeyProvider
Signed-off-by: David J. M. Karlsen <david@davidkarlsen.com>
  • Loading branch information
davidkarlsen committed Apr 1, 2019
1 parent 1391543 commit 776ffeb07d046c6e3e52e9234218f87be789d348
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 27 deletions.
@@ -19,12 +19,12 @@
package org.apache.cxf.rs.security.httpsignature;

import java.io.IOException;
import java.security.PrivateKey;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.apache.cxf.rs.security.httpsignature.provider.PrivateKeyProvider;
import org.apache.cxf.rs.security.httpsignature.utils.DefaultSignatureConstants;
import org.apache.cxf.rs.security.httpsignature.utils.SignatureHeaderUtils;

@@ -34,35 +34,35 @@ public class MessageSigner {

public MessageSigner(String signatureAlgorithmName,
String digestAlgorithmName,
PrivateKey privateKey,
PrivateKeyProvider privateKeyProvider,
String keyId) {
this(signatureAlgorithmName, digestAlgorithmName, privateKey, keyId, Collections.emptyList());
this(signatureAlgorithmName, digestAlgorithmName, privateKeyProvider, keyId, Collections.emptyList());
}

public MessageSigner(String signatureAlgorithmName,
String digestAlgorithmName,
PrivateKey privateKey,
PrivateKeyProvider privateKeyProvider,
String keyId,
List<String> headersToSign) {
this.digestAlgorithmName = Objects.requireNonNull(digestAlgorithmName);
this.signatureCreator = new TomitribeSignatureCreator(
Objects.requireNonNull(signatureAlgorithmName),
Objects.requireNonNull(privateKey),
Objects.requireNonNull(privateKeyProvider),
Objects.requireNonNull(keyId),
headersToSign);
}

public MessageSigner(PrivateKey privateKey,
public MessageSigner(PrivateKeyProvider privateKeyProvider,
String keyId) {
this(privateKey, keyId, Collections.emptyList());
this(privateKeyProvider, keyId, Collections.emptyList());
}

public MessageSigner(PrivateKey privateKey,
public MessageSigner(PrivateKeyProvider privateKeyProvider,
String keyId,
List<String> headersToSign) {
this(DefaultSignatureConstants.SIGNING_ALGORITHM,
DefaultSignatureConstants.DIGEST_ALGORITHM,
privateKey,
privateKeyProvider,
keyId,
headersToSign);
}
@@ -19,7 +19,6 @@
package org.apache.cxf.rs.security.httpsignature;

import java.io.IOException;
import java.security.PrivateKey;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -28,24 +27,26 @@
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageUtils;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.rs.security.httpsignature.provider.PrivateKeyProvider;
import org.apache.cxf.rs.security.httpsignature.utils.SignatureHeaderUtils;
import org.tomitribe.auth.signatures.Join;
import org.tomitribe.auth.signatures.Signature;

public class TomitribeSignatureCreator implements SignatureCreator {
private final String signatureAlgorithmName;
private final PrivateKey privateKey;
private final PrivateKeyProvider privateKeyProvider;
private final String keyId;
private final List<String> headersToSign;

public TomitribeSignatureCreator(String signatureAlgorithmName, PrivateKey privateKey, String keyId) {
this(signatureAlgorithmName, privateKey, keyId, Collections.emptyList());
public TomitribeSignatureCreator(String signatureAlgorithmName, PrivateKeyProvider privateKeyProvider,
String keyId) {
this(signatureAlgorithmName, privateKeyProvider, keyId, Collections.emptyList());
}

public TomitribeSignatureCreator(String signatureAlgorithmName, PrivateKey privateKey,
public TomitribeSignatureCreator(String signatureAlgorithmName, PrivateKeyProvider privateKeyProvider,
String keyId, List<String> headersToSign) {
this.signatureAlgorithmName = signatureAlgorithmName;
this.privateKey = privateKey;
this.privateKeyProvider = privateKeyProvider;
this.keyId = keyId;
this.headersToSign = headersToSign;
}
@@ -76,7 +77,7 @@ public String createSignature(Map<String, List<String>> messageHeaders, String u

final Signature signature = new Signature(keyId, signatureAlgorithmName, null, headers);
final org.tomitribe.auth.signatures.Signer signer =
new org.tomitribe.auth.signatures.Signer(privateKey, signature);
new org.tomitribe.auth.signatures.Signer(privateKeyProvider.getKey(keyId), signature);
Signature outputSignature = signer.sign(method, uri, SignatureHeaderUtils.mapHeaders(messageHeaders));

return "keyId=\"" + outputSignature.getKeyId() + '\"'
@@ -19,7 +19,6 @@
package org.apache.cxf.rs.security.httpsignature.filters;

import java.io.IOException;
import java.security.PrivateKey;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -38,6 +37,7 @@
import org.apache.cxf.rs.security.httpsignature.HTTPSignatureConstants;
import org.apache.cxf.rs.security.httpsignature.MessageSigner;
import org.apache.cxf.rs.security.httpsignature.exception.SignatureException;
import org.apache.cxf.rs.security.httpsignature.provider.PrivateKeyProvider;
import org.apache.cxf.rs.security.httpsignature.utils.DefaultSignatureConstants;
import org.apache.cxf.rs.security.httpsignature.utils.KeyManagementUtils;

@@ -114,7 +114,7 @@ private MessageSigner createMessageSigner() {
}

Message m = PhaseInterceptorChain.getCurrentMessage();
PrivateKey privateKey = KeyManagementUtils.loadPrivateKey(m, props);
PrivateKeyProvider privateKeyProvider = keyId -> KeyManagementUtils.loadPrivateKey(m, props);

String signatureAlgorithm = (String)m.getContextualProperty(HTTPSignatureConstants.RSSEC_SIGNATURE_ALGORITHM);
if (signatureAlgorithm == null) {
@@ -135,7 +135,7 @@ private MessageSigner createMessageSigner() {
signedHeaders = Collections.emptyList();
}

return new MessageSigner(signatureAlgorithm, DefaultSignatureConstants.DIGEST_ALGORITHM, privateKey,
return new MessageSigner(signatureAlgorithm, DefaultSignatureConstants.DIGEST_ALGORITHM, privateKeyProvider,
keyId, signedHeaders);
}

@@ -0,0 +1,33 @@
/**
* 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.httpsignature.provider;

import java.security.PrivateKey;

@FunctionalInterface
public interface PrivateKeyProvider {
/**
* @param keyId is used as lookup to find the correct configured private key for this keyId
* The keyId is sent in the message together with the signature
* @throws IllegalArgumentException if it can't provide a private key based on keyId
* @return the private key (which is never {@code null})
*/
PrivateKey getKey(String keyId);

}
@@ -64,7 +64,7 @@ public static void setUp() {
messageVerifier.setSecurityProvider(new MockSecurityProvider());
messageVerifier.setAlgorithmProvider(new MockAlgorithmProvider());

messageSigner = new MessageSigner(keyPair.getPrivate(), KEY_ID);
messageSigner = new MessageSigner(keyId -> keyPair.getPrivate(), KEY_ID);

} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
@@ -39,6 +39,7 @@
import org.apache.cxf.rs.security.httpsignature.provider.MockAlgorithmProvider;
import org.apache.cxf.rs.security.httpsignature.provider.MockPublicKeyProvider;
import org.apache.cxf.rs.security.httpsignature.provider.MockSecurityProvider;
import org.apache.cxf.rs.security.httpsignature.provider.PrivateKeyProvider;

import org.junit.BeforeClass;
import org.junit.Test;
@@ -50,7 +51,7 @@
*/
public class SpecExamplesTest {

private static PrivateKey privateKey;
private static PrivateKeyProvider privateKeyProvider;
private static PublicKey publicKey;

@BeforeClass
@@ -67,7 +68,8 @@ public static void setUp() throws IOException, InvalidKeySpecException {
byte[] keyBytes = Files.readAllBytes(privateKeyPath);

PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyBytes);
privateKey = KeyFactory.getInstance("RSA").generatePrivate(privateKeySpec);
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(privateKeySpec);
privateKeyProvider = keyId -> privateKey;

Path publicKeyPath = FileSystems.getDefault().getPath(basedir, "/src/test/resources/public_key.der");
byte[] publicKeyBytes = Files.readAllBytes(publicKeyPath);
@@ -84,7 +86,7 @@ public static void setUp() throws IOException, InvalidKeySpecException {
public void defaultTest() throws IOException {
Map<String, List<String>> headers = createMockHeaders();

MessageSigner messageSigner = new MessageSigner(privateKey, "Test", Collections.singletonList("Date"));
MessageSigner messageSigner = new MessageSigner(privateKeyProvider, "Test", Collections.singletonList("Date"));
messageSigner.sign(headers, "/foo?param=value&pet=dog", "POST");
String signatureHeader = headers.get("Signature").get(0);

@@ -108,7 +110,7 @@ public void defaultTest() throws IOException {
public void basicTest() throws IOException {
Map<String, List<String>> headers = createMockHeaders();

MessageSigner messageSigner = new MessageSigner(privateKey, "Test",
MessageSigner messageSigner = new MessageSigner(privateKeyProvider, "Test",
Arrays.asList("(request-target)", "host", "Date"));
messageSigner.sign(headers, "/foo?param=value&pet=dog", "POST");
String signatureHeader = headers.get("Signature").get(0);
@@ -131,9 +133,9 @@ public void basicTest() throws IOException {
public void allHeadersTest() throws IOException {
Map<String, List<String>> headers = createMockHeaders();

MessageSigner messageSigner = new MessageSigner(privateKey, "Test",
Arrays.asList("(request-target)", "host", "date",
"content-type", "digest", "content-length"));
MessageSigner messageSigner = new MessageSigner(privateKeyProvider, "Test",
Arrays.asList("(request-target)", "host", "date",
"content-type", "digest", "content-length"));
messageSigner.sign(headers, "/foo?param=value&pet=dog", "POST");
String signatureHeader = headers.get("Signature").get(0);

0 comments on commit 776ffeb

Please sign in to comment.