com.joyent.manta.client.multipart.EncryptedMultipartManagerTest.java Source code

Java tutorial

Introduction

Here is the source code for com.joyent.manta.client.multipart.EncryptedMultipartManagerTest.java

Source

/*
 * Copyright (c) 2017, Joyent, Inc. All rights reserved.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package com.joyent.manta.client.multipart;

import com.joyent.manta.client.MantaMetadata;
import com.joyent.manta.client.MantaObjectInputStream;
import com.joyent.manta.client.MantaObjectMapper;
import com.joyent.manta.client.MantaObjectResponse;
import com.joyent.manta.client.crypto.AesCtrCipherDetails;
import com.joyent.manta.client.crypto.EncryptionContext;
import com.joyent.manta.client.crypto.MantaEncryptedObjectInputStream;
import com.joyent.manta.client.crypto.SecretKeyUtils;
import com.joyent.manta.client.crypto.SupportedCipherDetails;
import com.joyent.manta.client.crypto.SupportedHmacsLookupMap;
import com.joyent.manta.config.BaseChainedConfigContext;
import com.joyent.manta.config.ConfigContext;
import com.joyent.manta.config.SettableConfigContext;
import com.joyent.manta.config.StandardConfigContext;
import com.joyent.manta.config.TestConfigContext;
import com.joyent.manta.http.EncryptionHttpHelper;
import com.joyent.manta.http.MantaConnectionContext;
import com.joyent.manta.http.MantaHttpHeaders;
import com.joyent.manta.http.MantaHttpRequestFactory;
import com.joyent.manta.util.UnitTestConstants;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.conn.EofSensorInputStream;
import org.testng.Assert;
import org.testng.AssertJUnit;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.stream.Stream;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;

import static org.mockito.Mockito.mock;

@Test
public class EncryptedMultipartManagerTest {
    private SupportedCipherDetails cipherDetails = AesCtrCipherDetails.INSTANCE_128_BIT;
    private SecretKey secretKey = SecretKeyUtils.loadKey(Base64.getDecoder().decode("qAnCNUmmFjUTtImNGv241Q=="),
            cipherDetails);

    private TestMultipartManager testManager = new TestMultipartManager();
    private EncryptedMultipartManager<TestMultipartManager, TestMultipartUpload> manager;

    @BeforeClass
    public void setup() {
        this.manager = buildManager();
    }

    public void canDoMultipartUpload() throws Exception {
        MantaMetadata metadata = new MantaMetadata();
        metadata.put("m-my-key", "my value");
        metadata.put("e-my-key-1", "my value 1");
        metadata.put("e-my-key-2", "my value 2");

        MantaHttpHeaders headers = new MantaHttpHeaders();

        String path = "/user/stor/testobject";

        EncryptedMultipartUpload<TestMultipartUpload> upload = manager.initiateUpload(path, 35L, metadata, headers);

        ArrayList<String> lines = new ArrayList<>();
        lines.add("01234567890ABCDEF|}{");
        lines.add("ZYXWVUTSRQPONMLKJIHG");
        lines.add("!@#$%^&*()_+-=[]/,.<");
        lines.add(">~`?abcdefghijklmnop");
        lines.add("qrstuvxyz");

        String expected = StringUtils.join(lines, "");

        MantaMultipartUploadPart[] parts = new MantaMultipartUploadPart[5];

        for (int i = 0; i < lines.size(); i++) {
            parts[i] = manager.uploadPart(upload, i + 1, lines.get(i));
        }

        Stream<MantaMultipartUploadTuple> partsStream = Stream.of(parts);

        manager.complete(upload, partsStream);

        TestMultipartUpload actualUpload = upload.getWrapped();

        MantaMetadata actualMetadata = MantaObjectMapper.INSTANCE.readValue(actualUpload.getMetadata(),
                MantaMetadata.class);

        Assert.assertEquals(actualMetadata, metadata, "Metadata wasn't stored correctly");

        MantaHttpHeaders actualHeaders = MantaObjectMapper.INSTANCE.readValue(actualUpload.getHeaders(),
                MantaHttpHeaders.class);

        Assert.assertEquals(actualHeaders, headers, "Headers were stored correctly");

        {
            Cipher cipher = cipherDetails.getCipher();
            byte[] iv = upload.getEncryptionState().getEncryptionContext().getCipher().getIV();
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, cipherDetails.getEncryptionParameterSpec(iv));

            byte[] assumedCiphertext = cipher.doFinal(expected.getBytes(StandardCharsets.US_ASCII));
            byte[] contents = FileUtils.readFileToByteArray(upload.getWrapped().getContents());
            byte[] actualCiphertext = Arrays.copyOf(contents,
                    contents.length - cipherDetails.getAuthenticationTagOrHmacLengthInBytes());

            try {
                AssertJUnit.assertEquals(assumedCiphertext, actualCiphertext);
            } catch (AssertionError e) {
                System.err.println("expected: " + Hex.encodeHexString(assumedCiphertext));
                System.err.println("actual  : " + Hex.encodeHexString(actualCiphertext));
                throw e;
            }
        }

        EncryptionContext encryptionContext = upload.getEncryptionState().getEncryptionContext();

        MantaHttpHeaders responseHttpHeaders = new MantaHttpHeaders();
        responseHttpHeaders.setContentLength(actualUpload.getContents().length());

        final String hmacName = SupportedHmacsLookupMap
                .hmacNameFromInstance(encryptionContext.getCipherDetails().getAuthenticationHmac());

        responseHttpHeaders.put(MantaHttpHeaders.ENCRYPTION_HMAC_TYPE, hmacName);
        responseHttpHeaders.put(MantaHttpHeaders.ENCRYPTION_IV,
                Base64.getEncoder().encodeToString(encryptionContext.getCipher().getIV()));
        responseHttpHeaders.put(MantaHttpHeaders.ENCRYPTION_KEY_ID, cipherDetails.getCipherId());

        MantaObjectResponse response = new MantaObjectResponse(path, responseHttpHeaders, metadata);

        CloseableHttpResponse httpResponse = mock(CloseableHttpResponse.class);

        try (InputStream fin = new FileInputStream(actualUpload.getContents());
                EofSensorInputStream eofIn = new EofSensorInputStream(fin, null);
                MantaObjectInputStream objIn = new MantaObjectInputStream(response, httpResponse, eofIn);
                InputStream in = new MantaEncryptedObjectInputStream(objIn, cipherDetails, secretKey, true)) {
            String actual = IOUtils.toString(in, StandardCharsets.UTF_8);

            Assert.assertEquals(actual, expected);
        }
    }

    // TEST UTILITY METHODS

    private SettableConfigContext<BaseChainedConfigContext> testConfigContext(SecretKey key) {
        StandardConfigContext settable = new StandardConfigContext();
        settable.setMantaUser("test");
        settable.setPrivateKeyContent(UnitTestConstants.PRIVATE_KEY);
        settable.setMantaKeyId(UnitTestConstants.FINGERPRINT);

        settable.setEncryptionPrivateKeyBytes(key.getEncoded());

        return new TestConfigContext(settable);
    }

    private EncryptedMultipartManager<TestMultipartManager, TestMultipartUpload> buildManager() {
        ConfigContext config = testConfigContext(secretKey);

        final MantaConnectionContext connectionContext = mock(MantaConnectionContext.class);

        EncryptionHttpHelper httpHelper = new EncryptionHttpHelper(connectionContext,
                new MantaHttpRequestFactory(UnitTestConstants.UNIT_TEST_URL), config);

        return new EncryptedMultipartManager<>(secretKey, cipherDetails, httpHelper, testManager);
    }
}