package org.jboss.resteasy.test.crypto;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.resteasy.category.NotForForwardCompatibility;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import org.jboss.resteasy.security.doseta.DKIMSignature;
import org.jboss.resteasy.security.doseta.DosetaKeyRepository;
import org.jboss.resteasy.security.doseta.KeyRepository;
import org.jboss.resteasy.security.doseta.UnauthorizedSignatureException;
import org.jboss.resteasy.security.doseta.Verification;
import org.jboss.resteasy.security.doseta.Verifier;
import org.jboss.resteasy.spi.MarshalledEntity;
import org.jboss.resteasy.test.crypto.resource.SigningResource;
import org.jboss.resteasy.test.crypto.resource.SigningProxy;
import org.jboss.resteasy.util.HttpResponseCodes;
import org.jboss.resteasy.utils.PortProviderUtil;
import org.jboss.resteasy.utils.TestUtil;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;

import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.ResponseProcessingException;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SignatureException;
import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.containsString;

/**
 * @tpSubChapter Crypto
 * @tpChapter Integration tests
 * @tpTestCaseDetails Signing test for RESTEasy-crypto
 * @tpSince RESTEasy 3.0.16
 */
@RunWith(Arquillian.class)
@RunAsClient
public class SigningTest {
    public static KeyPair keys;
    public static DosetaKeyRepository repository;
    public static PrivateKey badKey;
    private static ResteasyClient client;

    protected final Logger logger = LogManager.getLogger(PKCS7SignatureSmokeTest.class.getName());

    private static final String RESPONSE_ERROR_MSG = "Response contains wrong content";
    static final String testJksPath;

    static {
        testJksPath = TestUtil.getResourcePath(SigningTest.class, "SigningTest.jks");
    }

    @Before
    public void init() {
        client = new ResteasyClientBuilder().build();
    }

    @After
    public void close() {
        client.close();
    }

    @Deployment
    public static Archive<?> deploy() {
        WebArchive war = TestUtil.prepareArchive(SigningTest.class.getSimpleName());
        war.addClass(SigningProxy.class);
        war.addAsResource(SigningTest.class.getPackage(), "SigningTest.jks", "test.jks");
        Map<String, String> contextParams = new HashMap<>();
        contextParams.put("resteasy.doseta.keystore.classpath", "test.jks");
        contextParams.put("resteasy.doseta.keystore.password", "password");
        contextParams.put("resteasy.context.objects", "org.jboss.resteasy.security.doseta.KeyRepository : org.jboss.resteasy.security.doseta.ConfiguredDosetaKeyRepository");
        contextParams.put("resteasy.doseta.use.dns", "false");
        return TestUtil.finishContainerPrepare(war, contextParams, SigningResource.class);
    }

    private String generateURL(String path) {
        return PortProviderUtil.generateURL(path, SigningTest.class.getSimpleName());
    }

    @BeforeClass
    public static void setup() throws Exception {
        repository = new DosetaKeyRepository();
        repository.setKeyStoreFile(testJksPath);
        repository.setKeyStorePassword("password");
        repository.setUseDns(false);
        repository.start();

        PrivateKey privateKey = repository.getKeyStore().getPrivateKey("test._domainKey.samplezone.org");
        if (privateKey == null) {
            throw new Exception("Private Key is null!!!");
        }
        PublicKey publicKey = repository.getKeyStore().getPublicKey("test._domainKey.samplezone.org");
        keys = new KeyPair(publicKey, privateKey);

        KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
        badKey = keyPair.getPrivate();
    }

    @AfterClass
    public static void afterIt() throws Exception {
        client.close();
        client = null;
    }

    /**
     * @tpTestDetails Test for "DKIM-Signature" header attribute
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testRequestOnly() throws Exception {
        WebTarget target = client.target(generateURL("/signed/request-only"));
        DKIMSignature contentSignature = new DKIMSignature();
        contentSignature.setDomain("samplezone.org");
        contentSignature.setSelector("test");
        contentSignature.setPrivateKey(keys.getPrivate());
        contentSignature.setBodyHashRequired(false);
        contentSignature.setAttribute("method", "GET");
        contentSignature.setAttribute("uri", "/signed/request-only");
        contentSignature.setAttribute("token", "1122");
        Response response = target.request().header(DKIMSignature.DKIM_SIGNATURE, contentSignature).delete();

        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        String signatureHeader = response.getHeaderString(DKIMSignature.DKIM_SIGNATURE);
        contentSignature = new DKIMSignature(signatureHeader);
        Verification verification = new Verification(keys.getPublic());
        verification.setBodyHashRequired(false);
        verification.getRequiredAttributes().put("token", "1122");
        verification.verify(contentSignature, response.getStringHeaders(), null, keys.getPublic());
        response.close();
    }

    /**
     * @tpTestDetails Test for manual signing
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testSigningManual() throws Exception {
        WebTarget target = client.target(generateURL("/signed"));
        Response response = target.request().get();
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        MarshalledEntity<String> marshalledEntity = response.readEntity(new GenericType<MarshalledEntity<String>>() {
        });
        Assert.assertEquals(RESPONSE_ERROR_MSG, "hello world", marshalledEntity.getEntity());
        String signatureHeader = response.getHeaderString(DKIMSignature.DKIM_SIGNATURE);
        logger.info(DKIMSignature.DKIM_SIGNATURE + ":  " + signatureHeader);

        Assert.assertNotNull("Missing DKIM_SIGNATURE header", signatureHeader);

        DKIMSignature contentSignature = new DKIMSignature(signatureHeader);
        contentSignature.verify(response.getStringHeaders(), marshalledEntity.getMarshalledBytes(), keys.getPublic());
        response.close();
    }

    /**
     * @tpTestDetails Basic verification test
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBasicVerification() throws Exception {
        WebTarget target = client.target(generateURL("/signed"));
        DKIMSignature contentSignature = new DKIMSignature();
        contentSignature.setDomain("samplezone.org");
        contentSignature.setSelector("test");
        contentSignature.setPrivateKey(keys.getPrivate());
        Response response = target.request().header(DKIMSignature.DKIM_SIGNATURE, contentSignature)
                .post(Entity.text("hello world"));
        Assert.assertEquals(HttpResponseCodes.SC_NO_CONTENT, response.getStatus());
        response.close();
    }

    /**
     * @tpTestDetails Manual verification test
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testManualVerification() throws Exception {
        WebTarget target = client.target(generateURL("/signed/verify-manual"));
        DKIMSignature contentSignature = new DKIMSignature();
        contentSignature.setDomain("samplezone.org");
        contentSignature.setSelector("test");
        contentSignature.setAttribute("code", "hello");
        contentSignature.setPrivateKey(keys.getPrivate());
        Response response = target.request().header(DKIMSignature.DKIM_SIGNATURE, contentSignature)
                .post(Entity.text("hello world"));
        Assert.assertEquals(HttpResponseCodes.SC_NO_CONTENT, response.getStatus());
        response.close();
    }

    /**
     * @tpTestDetails Basic verification test with repository
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBasicVerificationRepository() throws Exception {
        WebTarget target = client.target(generateURL("/signed"));
        target.property(KeyRepository.class.getName(), repository);
        DKIMSignature contentSignature = new DKIMSignature();
        contentSignature.setSelector("test");
        contentSignature.setDomain("samplezone.org");
        Response response = target.request().header(DKIMSignature.DKIM_SIGNATURE, contentSignature)
                .post(Entity.text("hello world"));
        Assert.assertEquals(HttpResponseCodes.SC_NO_CONTENT, response.getStatus());
        response.close();
    }

    /**
     * @tpTestDetails Basic verification test with bad signature
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBasicVerificationBadSignature() throws Exception {
        WebTarget target = client.target(generateURL("/signed"));
        DKIMSignature contentSignature = new DKIMSignature();
        contentSignature.setSelector("test");
        contentSignature.setDomain("samplezone.org");
        contentSignature.setPrivateKey(badKey);
        Response response = target.request().header(DKIMSignature.DKIM_SIGNATURE, contentSignature)
                .post(Entity.text("hello world"));
        Assert.assertEquals(HttpResponseCodes.SC_UNAUTHORIZED, response.getStatus());
        response.close();
    }

    /**
     * @tpTestDetails Basic verification test with no signature
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBasicVerificationNoSignature() throws Exception {
        WebTarget target = client.target(generateURL("/signed"));
        Response response = target.request().post(Entity.text("hello world"));
        Assert.assertEquals(HttpResponseCodes.SC_UNAUTHORIZED, response.getStatus());
        response.close();
    }

    /**
     * @tpTestDetails Test for timestamp signature with set domain
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testTimestampSignature() throws Exception {
        DKIMSignature signature = new DKIMSignature();
        signature.setTimestamp();
        signature.setSelector("test");
        signature.setDomain("samplezone.org");
        signature.sign(new HashMap(), "hello world".getBytes(), keys.getPrivate());
        String sig = signature.toString();
        logger.info(DKIMSignature.DKIM_SIGNATURE + ": " + sig);
        new DKIMSignature(sig);
    }

    /**
     * @tpTestDetails Test for timestamp signature without set domain
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testTimestamp() throws Exception {
        Verifier verifier = new Verifier();
        Verification verification = verifier.addNew();
        verification.setRepository(repository);
        verification.setStaleCheck(true);
        verification.setStaleSeconds(100);
        WebTarget target = client.target(generateURL("/signed/stamped"));
        Invocation.Builder request = target.request();
        request.property(Verifier.class.getName(), verifier);
        Response response = request.get();
        logger.info(response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        try {
            response.readEntity(String.class);
        } catch (Exception e) {
            throw e;
        }
        response.close();
    }

    /**
     * @tpTestDetails Stale timestamp test
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testStaleTimestamp() throws Exception {
        Verifier verifier = new Verifier();
        Verification verification = verifier.addNew();
        verification.setRepository(repository);
        verification.setStaleCheck(true);
        verification.setStaleSeconds(1);
        WebTarget target = client.target(generateURL("/signed/stamped"));
        Invocation.Builder request = target.request();
        request.property(Verifier.class.getName(), verifier);
        Response response = request.get();
        logger.info(response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        Thread.sleep(1500);
        try {
            response.readEntity(String.class);
            Assert.fail("Validation error excepted.");
        } catch (ProcessingException pe) {
            UnauthorizedSignatureException e = (UnauthorizedSignatureException) pe.getCause();
            Assert.assertThat("Unexcepted error", e.getMessage(), containsString("Failed to verify signatures:\r\n"));
            Assert.assertThat("Unexcepted error", e.getMessage(), containsString("Signature is stale"));
        }
        response.close();
    }

    /**
     * @tpTestDetails Hour expiration test (expires attribute in Signed annotation in REST end-point is used).
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testExpiresHour() throws Exception {
        Verifier verifier = new Verifier();
        Verification verification = verifier.addNew();
        verification.setRepository(repository);
        WebTarget target = client.target(generateURL("/signed/expires-hour"));
        Invocation.Builder request = target.request();
        request.property(Verifier.class.getName(), verifier);
        Response response = request.get();
        logger.info(response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        response.readEntity(String.class);
        response.close();
    }

    /**
     * @tpTestDetails Minute expiration test (expires attribute in Signed annotation in REST end-point is used).
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testExpiresMinutes() throws Exception {
        Verifier verifier = new Verifier();
        Verification verification = verifier.addNew();
        verification.setRepository(repository);
        WebTarget target = client.target(generateURL("/signed/expires-minute"));
        Invocation.Builder request = target.request();
        request.property(Verifier.class.getName(), verifier);
        Response response = request.get();
        logger.info(response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        response.readEntity(String.class);
        response.close();
    }

    /**
     * @tpTestDetails Day expiration test (expires attribute in Signed annotation in REST end-point is used).
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testExpiresDays() throws Exception {
        Verifier verifier = new Verifier();
        Verification verification = verifier.addNew();
        verification.setRepository(repository);
        WebTarget target = client.target(generateURL("/signed/expires-day"));
        Invocation.Builder request = target.request();
        request.property(Verifier.class.getName(), verifier);
        Response response = request.get();
        logger.info(response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        response.readEntity(String.class);
        response.close();
    }

    /**
     * @tpTestDetails Month expiration test (expires attribute in Signed annotation in REST end-point is used).
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testExpiresMonths() throws Exception {
        Verifier verifier = new Verifier();
        Verification verification = verifier.addNew();
        verification.setRepository(repository);
        WebTarget target = client.target(generateURL("/signed/expires-month"));
        Invocation.Builder request = target.request();
        request.property(Verifier.class.getName(), verifier);
        Response response = request.get();
        logger.info(response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        response.readEntity(String.class);
        response.close();
    }

    /**
     * @tpTestDetails Year expiration test (expires attribute in Signed annotation in REST end-point is used).
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testExpiresYears() throws Exception {
        Verifier verifier = new Verifier();
        Verification verification = verifier.addNew();
        verification.setRepository(repository);
        WebTarget target = client.target(generateURL("/signed/expires-year"));
        Invocation.Builder request = target.request();
        request.property(Verifier.class.getName(), verifier);
        Response response = request.get();
        logger.info(response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        response.readEntity(String.class);
        response.close();
    }

    /**
     * @tpTestDetails Fail expiration test (expires attribute in Signed annotation in REST end-point is used).
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testExpiresFail() throws Exception {
        Verifier verifier = new Verifier();
        Verification verification = verifier.addNew();
        verification.setRepository(repository);
        WebTarget target = client.target(generateURL("/signed/expires-short"));
        Invocation.Builder request = target.request();
        request.property(Verifier.class.getName(), verifier);
        Response response = request.get();
        logger.info(response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        Thread.sleep(1500);
        try {
            response.readEntity(String.class);
            throw new Exception("Signing error excepted");
        } catch (ProcessingException pe) {
            UnauthorizedSignatureException e = (UnauthorizedSignatureException) pe.getCause();
            Assert.assertThat("Unexcepted error", e.getMessage(), containsString("Failed to verify signatures:\r\n"));
            Assert.assertThat("Unexcepted error", e.getMessage(), containsString("Signature expired"));
        }
        response.close();
    }

    /**
     * @tpTestDetails Manual fail test
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testManualFail() throws Exception {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(1024);
        KeyPair keyPair = kpg.genKeyPair();

        Verifier verifier = new Verifier();
        Verification verification = verifier.addNew();
        verification.setKey(keyPair.getPublic());
        WebTarget target = client.target(generateURL("/signed/manual"));
        Invocation.Builder request = target.request();
        request.property(Verifier.class.getName(), verifier);
        Response response = request.get();
        logger.info(response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertNotNull("DKIM_SIGNATURE header is missing", response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        try {
            response.readEntity(String.class);
            throw new Exception("unreachable!");
        } catch (ProcessingException pe) {
            UnauthorizedSignatureException e = (UnauthorizedSignatureException) pe.getCause();
            logger.info("UnauthorizedSignatureException message: " + e.getMessage());
            Assert.assertThat("Unexcepted error", e.getMessage(), containsString("Failed to verify signatures:\r\n"));
            Assert.assertThat("Unexcepted error", e.getMessage(), containsString("Failed to verify signature."));
        }
        response.close();
    }

    /**
     * @tpTestDetails Manual success test
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testManual() throws Exception {
        Verifier verifier = new Verifier();
        Verification verification = verifier.addNew();
        verification.setRepository(repository);
        WebTarget target = client.target(generateURL("/signed/manual"));
        Invocation.Builder request = target.request();
        request.property(Verifier.class.getName(), verifier);
        Response response = request.get();
        logger.info(response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertNotNull("Missing header DKIM_SIGNATURE", response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        String output = response.readEntity(String.class);
        Assert.assertEquals(RESPONSE_ERROR_MSG, "hello", output);
        response.close();
    }

    /**
     * @tpTestDetails Manual test with header
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testManualWithHeader() throws Exception {
        Verifier verifier = new Verifier();
        Verification verification = verifier.addNew();
        verification.setRepository(repository);
        WebTarget target = client.target(generateURL("/signed/header"));
        Invocation.Builder request = target.request();
        request.property(Verifier.class.getName(), verifier);
        Response response = request.get();
        logger.info(response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertNotNull("Missing header DKIM_SIGNATURE", response.getHeaderString(DKIMSignature.DKIM_SIGNATURE));
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        String output = response.readEntity(String.class);
        Assert.assertEquals(RESPONSE_ERROR_MSG, "hello world", output);
        response.close();
    }

    /**
     * @tpTestDetails Bad signature test
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBadSignature() throws Exception {
        WebTarget target = client.target(generateURL("/signed/bad-signature"));
        Response response = target.request().get();
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        String signatureHeader = response.getHeaderString(DKIMSignature.DKIM_SIGNATURE);
        Assert.assertNotNull("Missing header DKIM_SIGNATURE", signatureHeader);
        logger.info(DKIMSignature.DKIM_SIGNATURE + ":  " + signatureHeader);

        DKIMSignature contentSignature = new DKIMSignature(signatureHeader);

        MarshalledEntity<String> entity = response.readEntity(new GenericType<MarshalledEntity<String>>() {
        });

        try {
            contentSignature.verify(response.getStringHeaders(), entity.getMarshalledBytes(), keys.getPublic());
            Assert.fail("Signing error excepted");
        } catch (SignatureException e) {
            logger.info("SignatureException message: " + e.getMessage());
        }
        response.close();
    }

    /**
     * @tpTestDetails Bad hash test
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBadHash() throws Exception {
        WebTarget target = client.target(generateURL("/signed/bad-hash"));
        Response response = target.request().get();
        Assert.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
        String signatureHeader = response.getHeaderString(DKIMSignature.DKIM_SIGNATURE);
        Assert.assertNotNull(signatureHeader);
        logger.info(DKIMSignature.DKIM_SIGNATURE + ":  " + signatureHeader);

        DKIMSignature contentSignature = new DKIMSignature(signatureHeader);

        MarshalledEntity<String> entity = response.readEntity(new GenericType<MarshalledEntity<String>>() {
        });

        try {
            contentSignature.verify(response.getStringHeaders(), entity.getMarshalledBytes(), keys.getPublic());
            Assert.fail("Signing error excepted");
        } catch (SignatureException e) {
            logger.info("SignatureException message: " + e.getMessage());
        }
        response.close();
    }

    /**
     * @tpTestDetails Proxy test with correct signature
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testProxy() throws Exception {
        ResteasyWebTarget target = client.target(generateURL("/"));
        target.property(KeyRepository.class.getName(), repository);
        SigningProxy proxy = target.proxy(SigningProxy.class);
        proxy.hello();
        proxy.postSimple("hello world");
    }

    /**
     * @tpTestDetails Proxy test with bad signature
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBadSignatureProxy() throws Exception {
        ResteasyWebTarget target = client.target(generateURL("/"));
        target.property(KeyRepository.class.getName(), repository);
        SigningProxy proxy = target.proxy(SigningProxy.class);
        try {
            proxy.bad();
            Assert.fail("Signing error excepted");
        } catch (ResponseProcessingException e) {
            logger.info("ResponseProcessingException cause: " + e.getCause().getClass().getName());
        }
    }

    /**
     * @tpTestDetails Regression test for RESTEASY-1169
     * @tpSince RESTEasy 3.0.17
     */
    @Test
    @Category({NotForForwardCompatibility.class})
    public void testBasicVerificationBadSignatureNoBody() throws Exception {
        WebTarget target = client.target(generateURL("/signed/nobody"));
        DKIMSignature contentSignature = new DKIMSignature();
        contentSignature.setSelector("test");
        contentSignature.setDomain("samplezone.org");
        contentSignature.setPrivateKey(badKey);
        Response response = target.request().header(DKIMSignature.DKIM_SIGNATURE, contentSignature).get();
        Assert.assertEquals(HttpResponseCodes.SC_UNAUTHORIZED, response.getStatus());
        response.close();
    }
}
