/** * Copyright (c) 2013-2016, The SeedStack authors <http://seedstack.org> * * 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 org.seedstack.seed.core.internal.crypto; import com.google.common.base.Strings; import com.google.inject.Key; import io.nuun.kernel.api.plugin.InitState; import io.nuun.kernel.api.plugin.context.InitContext; import org.seedstack.seed.SeedException; import org.seedstack.seed.core.internal.AbstractSeedPlugin; import org.seedstack.seed.crypto.CryptoConfig; import org.seedstack.seed.crypto.EncryptionService; import org.seedstack.seed.crypto.spi.SSLProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import java.security.KeyStore; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; public class CryptoPlugin extends AbstractSeedPlugin implements SSLProvider { private static final Logger LOGGER = LoggerFactory.getLogger(CryptoPlugin.class); private static final String ALIAS = "alias"; private final Map<Key<EncryptionService>, EncryptionService> encryptionServices = new HashMap<>(); private final Map<String, KeyStore> keyStores = new HashMap<>(); private final Map<String, CryptoConfig.KeyStoreConfig> keyStoreConfigs = new HashMap<>(); private final List<KeyPairConfig> keyPairConfigs = new ArrayList<>(); private CryptoConfig.SSLConfig sslConfig; private SSLContext sslContext; @Override public String name() { return "crypto"; } @Override public Object nativeUnitModule() { return new CryptoModule(encryptionServices, keyStores); } @Override public InitState initialize(InitContext initContext) { CryptoConfig cryptoConfig = getConfiguration(CryptoConfig.class); // Load key stores KeyStoreLoader keyStoreLoader = new KeyStoreLoader(); for (Map.Entry<String, CryptoConfig.KeyStoreConfig> entry : cryptoConfig.keyStores().entrySet()) { keyStores.put(entry.getKey(), keyStoreLoader.load(entry.getKey(), entry.getValue())); keyStoreConfigs.put(entry.getKey(), entry.getValue()); } // Retrieve key pair configurations KeyPairConfigFactory keyPairConfigFactory = new KeyPairConfigFactory(cryptoConfig); for (Map.Entry<String, KeyStore> entry : keyStores.entrySet()) { this.keyPairConfigs.addAll(keyPairConfigFactory.create(entry.getKey(), entry.getValue())); } // Prepare encryption service bindings encryptionServices.putAll(new EncryptionServiceBindingFactory().createBindings(cryptoConfig, this.keyPairConfigs, keyStores)); LOGGER.debug("Registered {} cryptographic key(s)", encryptionServices.size()); // init SSL context if possible this.sslConfig = cryptoConfig.ssl(); this.sslContext = configureSSL(this.sslConfig); return InitState.INITIALIZED; } private SSLContext configureSSL(CryptoConfig.SSLConfig sslConfig) { SSLLoader sslLoader = new SSLLoader(); TrustManager[] trustManagers; KeyStore trustStore = keyStores.get(sslConfig.getTrustStore()); if (trustStore == null) { return null; } else { trustManagers = sslLoader.getTrustManager(trustStore); } KeyManager[] keyManagers = configureKeyManagers(sslConfig); if (keyManagers != null) { return sslLoader.getSSLContext(this.sslConfig.getProtocol(), keyManagers, trustManagers); } else { return null; } } private KeyManager[] configureKeyManagers(CryptoConfig.SSLConfig sslConfig) { String keyStoreName = sslConfig.getKeyStore(); CryptoConfig.KeyStoreConfig keyStoreConfig = keyStoreConfigs.get(keyStoreName); if (keyStoreConfig == null) { return null; } String aliasName = sslConfig.getAlias(); CryptoConfig.KeyStoreConfig.AliasConfig aliasConfig = keyStoreConfig.getAliases().get(aliasName); if (aliasConfig == null) { return null; } if (Strings.isNullOrEmpty(aliasConfig.getPassword())) { throw SeedException.createNew(CryptoErrorCode.MISSING_ALIAS_PASSWORD) .put(ALIAS, aliasName) .put("ksName", keyStoreName); } return new SSLLoader().getKeyManagers(keyStores.get(keyStoreName), aliasConfig.getPassword().toCharArray()); } @Override public Optional<SSLContext> sslContext() { return Optional.ofNullable(sslContext); } @Override public CryptoConfig.SSLConfig sslConfig() { return sslConfig; } }