org.springframework.vault.authentication.AwsEc2Authentication.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.vault.authentication.AwsEc2Authentication.java

Source

/*
 * Copyright 2016 the original author or authors.
 *
 * Licensed 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.springframework.vault.authentication;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.vault.client.VaultClient;
import org.springframework.vault.client.VaultException;
import org.springframework.vault.client.VaultResponseEntity;
import org.springframework.vault.support.VaultResponse;
import org.springframework.vault.support.VaultToken;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

/**
 * AWS-EC2 login implementation.
 * <p>
 * AWS-EC2 login uses the EC2 identity document and a nonce to login into Vault. AWS-EC2
 * login obtains the PKCS#7 signed EC2 identity document and generates a
 * {@link #createNonce() nonce}. Instances of this class are immutable once constructed.
 *
 * @author Mark Paluch
 * @see AwsEc2AuthenticationOptions
 * @see <a href="https://www.vaultproject.io/docs/auth/aws-ec2.html">Auth Backend:
 * aws-ec2</a>
 */
public class AwsEc2Authentication implements ClientAuthentication {

    private final static Log logger = LogFactory.getLog(AwsEc2Authentication.class);

    private final AwsEc2AuthenticationOptions options;

    private final VaultClient vaultClient;

    private final RestTemplate restTemplate;

    private final AtomicReference<char[]> nonce = new AtomicReference<char[]>();

    /**
     * Creates a new {@link AwsEc2Authentication}.
     * 
     * @param vaultClient must not be {@literal null}.
     */
    public AwsEc2Authentication(VaultClient vaultClient) {
        this(AwsEc2AuthenticationOptions.DEFAULT, vaultClient, vaultClient.getRestTemplate());
    }

    /**
     * Creates a new {@link AwsEc2Authentication} specifying
     * {@link AwsEc2AuthenticationOptions}, {@link VaultClient} and a {@link RestTemplate}
     * .
     * 
     * @param options must not be {@literal null}.
     * @param vaultClient must not be {@literal null}.
     * @param restTemplate must not be {@literal null}.
     */
    public AwsEc2Authentication(AwsEc2AuthenticationOptions options, VaultClient vaultClient,
            RestTemplate restTemplate) {

        Assert.notNull(options, "AwsEc2AuthenticationOptions must not be null");
        Assert.notNull(vaultClient, "VaultEndpoint must not be null");
        Assert.notNull(restTemplate, "RestTemplate must not be null");

        this.options = options;
        this.vaultClient = vaultClient;
        this.restTemplate = restTemplate;
    }

    @Override
    public VaultToken login() throws VaultException {
        return createTokenUsingAwsEc2();
    }

    @SuppressWarnings("unchecked")
    private VaultToken createTokenUsingAwsEc2() {

        String path = String.format("auth/%s/login", options.getPath());

        Map<String, String> login = getEc2Login();

        VaultResponseEntity<VaultResponse> entity = this.vaultClient.postForEntity(path, login,
                VaultResponse.class);

        if (!entity.isSuccessful()) {
            throw new VaultException(String.format("Cannot login using AWS-EC2: %s", entity.getMessage()));
        }

        VaultResponse body = entity.getBody();

        if (logger.isDebugEnabled()) {

            if (body.getAuth().get("metadata") instanceof Map) {
                Map<Object, Object> metadata = (Map<Object, Object>) body.getAuth().get("metadata");
                logger.debug(String.format("Login successful using AWS-EC2 authentication for instance %s, AMI %s",
                        metadata.get("instance_id"), metadata.get("instance_id")));
            } else {
                logger.debug("Login successful using AWS-EC2 authentication");
            }
        }

        return LoginTokenUtil.from(entity.getBody().getAuth());
    }

    protected Map<String, String> getEc2Login() {

        Map<String, String> login = new HashMap<String, String>();

        if (StringUtils.hasText(options.getRole())) {
            login.put("role", options.getRole());
        }

        if (this.nonce.get() == null) {
            this.nonce.compareAndSet(null, createNonce());
        }

        login.put("nonce", new String(this.nonce.get()));

        try {
            String pkcs7 = restTemplate.getForObject(options.getIdentityDocumentUri(), String.class);
            if (StringUtils.hasText(pkcs7)) {
                login.put("pkcs7", pkcs7.replaceAll("\\r", "").replace("\\n", ""));
            }

            return login;
        } catch (RestClientException e) {
            throw new VaultException(
                    String.format("Cannot obtain Identity Document from %s", options.getIdentityDocumentUri()), e);
        }
    }

    protected char[] createNonce() {
        return UUID.randomUUID().toString().toCharArray();
    }
}