com.joyent.manta.client.UriSigner.java Source code

Java tutorial

Introduction

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

Source

/*
 * Copyright (c) 2016-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;

import com.joyent.http.signature.KeyFingerprinter;
import com.joyent.http.signature.ThreadLocalSigner;
import com.joyent.manta.config.AuthAwareConfigContext;
import com.joyent.manta.config.ConfigContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.bouncycastle.util.encoders.Base64;

import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;

/**
 * Class used to create signed URLs using the Manta-compatible HTTP signature
 * method.
 *
 * @author <a href="https://github.com/dekobon">Elijah Zupancic</a>
 * @since 3.0.0
 */
public class UriSigner {

    /**
     * Authentication Helper which provides objects needed for signing.
     */
    private final AuthAwareConfigContext authConfig;

    /**
     * DEPRECATED: Creates an instance based on a new authentication context.
     *
     * @param config Manta configuration context
     * @param keyPair cryptographic key pair used to sign URIs
     * @param signer Signer configured to work with the the given keyPair
     */
    @Deprecated
    public UriSigner(final ConfigContext config, final KeyPair keyPair, final ThreadLocalSigner signer) {
        this(new AuthAwareConfigContext(config));
    }

    /**
     * Creates a new instance. This constructor is package-private because this class is being made package private.
     *
     * @param authConfig Manta authentication context
     */
    UriSigner(final AuthAwareConfigContext authConfig) {
        this.authConfig = authConfig;
    }

    /**
     * Signs an arbitrary URL using the Manta-compatible HTTP signature
     * method.
     *
     * @param uri URI with no query pointing to a downloadable resource
     * @param method HTTP request method to be used in the signature
     * @param expires epoch time in seconds when the resource will no longer
     *                be available
     * @return a signed version of the input URI
     * @throws IOException thrown when we can't sign or read char data
     */
    public URI signURI(final URI uri, final String method, final long expires) throws IOException {
        Validate.notNull(method, "Method must not be null");
        Validate.notNull(uri, "URI must not be null");

        Validate.isTrue(StringUtils.isEmpty(uri.getQuery()), "Query must be null or empty. URI: %s", uri);

        final ThreadLocalSigner signer = authConfig.getSigner();

        final String charset = "UTF-8";
        final String algorithm = signer.get().getHttpHeaderAlgorithm().toUpperCase();
        final String keyId = String.format("/%s/keys/%s", authConfig.getMantaUser(),
                KeyFingerprinter.md5Fingerprint(authConfig.getKeyPair()));

        final String keyIdEncoded = URLEncoder.encode(keyId, charset);

        StringBuilder sigText = new StringBuilder();
        sigText.append(method).append(StringUtils.LF).append(uri.getHost()).append(StringUtils.LF)
                .append(uri.getRawPath()).append(StringUtils.LF).append("algorithm=").append(algorithm).append("&")
                .append("expires=").append(expires).append("&").append("keyId=").append(keyIdEncoded);

        StringBuilder request = new StringBuilder();
        final byte[] sigBytes = sigText.toString().getBytes(StandardCharsets.UTF_8);

        // first parameter isn't actually used for anything, just checked for nullness
        final byte[] signed = signer.get().sign("", authConfig.getKeyPair(), sigBytes);

        final String encoded = new String(Base64.encode(signed), charset);
        final String urlEncoded = URLEncoder.encode(encoded, charset);

        request.append(uri).append("?").append("algorithm=").append(algorithm).append("&").append("expires=")
                .append(expires).append("&").append("keyId=").append(keyIdEncoded).append("&").append("signature=")
                .append(urlEncoded);

        return URI.create(request.toString());
    }
}