All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lithium.flow.vault.AgentVault Maven / Gradle / Ivy

/*
 * Copyright 2015 Lithium Technologies, Inc.
 *
 * 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 com.lithium.flow.vault;

import static com.google.common.base.Preconditions.checkNotNull;

import com.lithium.flow.config.Configs;
import com.lithium.flow.store.MemoryStore;
import com.lithium.flow.store.Store;
import com.lithium.flow.util.Logs;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.slf4j.Logger;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * @author Matt Ayres
 */
public class AgentVault implements Vault {
	private static final Logger log = Logs.getLogger();

	private final ObjectMapper mapper = new ObjectMapper();
	private final Vault delegate;
	private final Store store;

	public AgentVault(@Nonnull Vault delegate, @Nonnull Store store) {
		this.delegate = checkNotNull(delegate);
		this.store = checkNotNull(store);
	}

	@Override
	@Nonnull
	public State getState() {
		autoUnlock();
		return delegate.getState();
	}

	@Override
	public void setup(@Nonnull String password) {
		checkNotNull(password);
		delegate.setup(password);
		startAgent(password);
	}

	@Override
	public boolean unlock(@Nonnull String password) {
		checkNotNull(password);

		if (!delegate.unlock(password)) {
			return false;
		}

		if (!password.equals(readAgent())) {
			startAgent(password);
		}

		return true;
	}

	@Override
	public void lock() {
		delegate.lock();
	}

	@Override
	public void putValue(@Nonnull String key, @Nullable String secret) {
		checkNotNull(key);
		autoUnlock();
		delegate.putValue(key, secret);
	}

	@Override
	@Nullable
	public String getValue(@Nonnull String key) {
		checkNotNull(key);
		autoUnlock();
		return delegate.getValue(key);
	}

	@Override
	@Nonnull
	public Set getKeys() {
		return delegate.getKeys();
	}

	private void autoUnlock() {
		if (delegate.getState() == State.LOCKED) {
			String password = readAgent();
			if (password != null) {
				delegate.unlock(password);
			}
		}
	}

	@Nullable
	private String readAgent() {
		String agentPort = store.getValue("vault.agent.port");
		String agentPassword = store.getValue("vault.agent.password");
		if (agentPort == null || agentPassword == null) {
			return null;
		}

		try {
			int port = Integer.parseInt(agentPort);
			Socket socket = new Socket();
			socket.connect(new InetSocketAddress("localhost", port), 5000);

			@SuppressWarnings("unchecked")
			Map map = mapper.readValue(socket.getInputStream(), Map.class);

			Store agentStore = new MemoryStore(map);
			Vault agentVault = new SecureVault(Configs.empty(), agentStore);
			agentVault.unlock(agentPassword);
			return agentVault.getValue("password");
		} catch (Exception e) {
			log.debug("failed to read from agent", e);
			return null;
		}
	}

	private void startAgent(@Nonnull String password) {
		try {
			int port = findFreePort();
			String agentPassword = Vaults.securePassword();

			Map map = new HashMap<>();
			Store agentStore = new MemoryStore(map);
			Vault agentVault = new SecureVault(Configs.empty(), agentStore);
			agentVault.setup(agentPassword);
			agentVault.putValue("password", password);

			ProcessBuilder builder = new ProcessBuilder();
			builder.command(System.getProperty("java.home") + "/bin/java",
					"-Dagent.port=" + port, AgentServer.class.getName());
			builder.environment().put("CLASSPATH", System.getProperty("java.class.path"));
			Process process = builder.start();

			OutputStream out = process.getOutputStream();
			mapper.writeValue(out, map);
			out.close();

			store.putValue("vault.agent.port", String.valueOf(port));
			store.putValue("vault.agent.password", agentPassword);
		} catch (IOException e) {
			throw new VaultException("failed to start agent", e);
		}
	}

	private int findFreePort() throws IOException {
		try (ServerSocket server = new ServerSocket(0)) {
			return server.getLocalPort();
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy