public void put(String namespace, String name, String data, @Nullable String description, Map<String, String> properties) throws Exception { checkNamespaceExists(namespace); String keyName = getKeyName(namespace, name); SecureStoreMetadata meta = new SecureStoreMetadata(name, description, System.currentTimeMillis(), properties); SecureStoreData secureStoreData = new SecureStoreData(meta, data.getBytes(Charsets.UTF_8)); writeLock.lock(); try { keyStore.setKeyEntry(keyName, new SecretKeySpec(serialize(secureStoreData), "none"), password, null); flush(); LOG.debug(String.format("Successfully stored %s in namespace %s", name, namespace)); } catch (KeyStoreException e) {
/** * Persist the keystore on the file system. * * During the flush the steps are * 1. Delete the _NEW file if it exists, it will exist only if something had failed in the last run. * 2. Try to write the current keystore in a _NEW file. * 3. If something fails then revert the key store to the old state and throw IOException. * 4. If everything is OK then rename the _NEW to the main file. * */ private void flush() throws IOException { Path newPath = constructNewPath(path); writeLock.lock(); try { // Might exist if a backup has been restored etc. Files.deleteIfExists(newPath); // Flush the keystore, write the _NEW file first writeToKeyStore(newPath); // Do Atomic rename _NEW to CURRENT Files.move(newPath, path, ATOMIC_MOVE, REPLACE_EXISTING); } finally { writeLock.unlock(); } }
/** * Returns the data stored in the secure store. * @param namespace The namespace this key belongs to. * @param name Name of the data element. * @return An object representing the securely stored data associated with the name. * @throws NamespaceNotFoundException If the specified namespace does not exist. * @throws NotFoundException If the key is not found in the store. * @throws IOException If there was a problem reading from the store. */ @Override public SecureStoreData get(String namespace, String name) throws Exception { checkNamespaceExists(namespace); String keyName = getKeyName(namespace, name); readLock.lock(); try { if (!keyStore.containsAlias(keyName)) { throw new NotFoundException(name + " not found in the secure store."); } Key key = keyStore.getKey(keyName, password); return deserialize(key.getEncoded()); } catch (NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException e) { throw new IOException("Unable to retrieve the key " + name, e); } finally { readLock.unlock(); } }
/** * Initialize the keyStore. * * @throws IOException If there is a problem reading or creating the keystore. */ private static KeyStore locateKeystore(Path path, final char[] password) throws IOException { Path newPath = constructNewPath(path); KeyStore ks; try { ks = KeyStore.getInstance(SCHEME_NAME); Files.deleteIfExists(newPath); if (Files.exists(path)) { loadFromPath(ks, path, password); } else { Path parent = path.getParent(); if (!Files.exists(parent)) { Files.createDirectories(parent); } // We were not able to load an existing key store. Create a new one. ks.load(null, password); LOG.info("New Secure Store initialized successfully."); } } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException e) { throw new IOException("Can't create Secure Store. ", e); } return ks; }
/** * List of all the entries in the secure store belonging to the specified namespace. No filtering or authentication * is done here. * @return A list of {@link SecureStoreMetadata} objects representing the data stored in the store. * @param namespace The namespace this key belongs to. * @throws NamespaceNotFoundException If the specified namespace does not exist. * @throws IOException If there was a problem reading from the keystore. */ @Override public List<SecureStoreMetadata> list(String namespace) throws Exception { checkNamespaceExists(namespace); readLock.lock(); try { Enumeration<String> aliases = keyStore.aliases(); List<SecureStoreMetadata> metadataList = new ArrayList<>(); String prefix = namespace + NAME_SEPARATOR; while (aliases.hasMoreElements()) { String alias = aliases.nextElement(); // Filter out elements not in this namespace. if (alias.startsWith(prefix)) { metadataList.add(getSecureStoreMetadata(alias)); } } return metadataList; } catch (KeyStoreException e) { throw new IOException("Failed to get the list of elements from the secure store.", e); } finally { readLock.unlock(); } }
checkNamespaceExists(namespace); String keyName = getKeyName(namespace, name); Key key = null; writeLock.lock(); throw new NotFoundException(new SecureKeyId(namespace, name)); key = deleteFromStore(keyName, password); flush(); LOG.debug(String.format("Successfully deleted key %s from namespace %s", name, namespace)); } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e) {
@Before public void setUp() throws Exception { CConfiguration conf = CConfiguration.create(); conf.set(Constants.Security.Store.FILE_PATH, TEMP_FOLDER.newFolder().getAbsolutePath()); SConfiguration sConf = SConfiguration.create(); sConf.set(Constants.Security.Store.FILE_PASSWORD, "secret"); InMemoryNamespaceAdmin namespaceClient = new InMemoryNamespaceAdmin(); NamespaceMeta namespaceMeta = new NamespaceMeta.Builder() .setName(NAMESPACE1) .build(); namespaceClient.create(namespaceMeta); namespaceMeta = new NamespaceMeta.Builder() .setName(NAMESPACE2) .build(); namespaceClient.create(namespaceMeta); FileSecureStoreService fileSecureStoreService = new FileSecureStoreService(conf, sConf, namespaceClient); secureStoreManager = fileSecureStoreService; secureStore = fileSecureStoreService; }
@Inject public FileSecureStoreService(CConfiguration cConf, SConfiguration sConf, NamespaceQueryAdmin namespaceQueryAdmin) throws IOException { // Get the path to the keystore file String pathString = cConf.get(Constants.Security.Store.FILE_PATH); Path dir = Paths.get(pathString); path = dir.resolve(cConf.get(Constants.Security.Store.FILE_NAME)); // Get the keystore password password = sConf.get(Constants.Security.Store.FILE_PASSWORD).toCharArray(); this.namespaceQueryAdmin = namespaceQueryAdmin; keyStore = locateKeystore(path, password); ReadWriteLock lock = new ReentrantReadWriteLock(true); readLock = lock.readLock(); writeLock = lock.writeLock(); }
/** * Returns the metadata for the element identified by the given name. * The name must be of the format namespace + NAME_SEPARATOR + key name. * @param keyName Name of the element * @return An object representing the metadata associated with the element * @throws NotFoundException If the key was not found in the store. * @throws IOException If there was a problem in getting the key from the store */ private SecureStoreMetadata getSecureStoreMetadata(String keyName) throws Exception { String[] namespaceAndName = keyName.split(NAME_SEPARATOR); Preconditions.checkArgument(namespaceAndName.length == 2); String namespace = namespaceAndName[0]; String name = namespaceAndName[1]; readLock.lock(); try { if (!keyStore.containsAlias(keyName)) { throw new NotFoundException(new SecureKeyId(namespace, name)); } Key key = keyStore.getKey(keyName, password); return deserialize(key.getEncoded()).getMetadata(); } catch (NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException e) { throw new IOException("Unable to retrieve the metadata for " + name + " in namespace " + namespace, e); } finally { readLock.unlock(); } }
@BeforeClass public static void setUp() throws Exception { CConfiguration conf = CConfiguration.create(); conf.set(Constants.Security.Store.FILE_PATH, TEMP_FOLDER.newFolder().getAbsolutePath()); SConfiguration sConf = SConfiguration.create(); sConf.set(Constants.Security.Store.FILE_PASSWORD, "secret"); InMemoryNamespaceAdmin namespaceClient = new InMemoryNamespaceAdmin(); NamespaceMeta namespaceMeta = new NamespaceMeta.Builder() .setName(NAMESPACE1) .build(); namespaceClient.create(namespaceMeta); FileSecureStoreService fileSecureStoreService = new FileSecureStoreService(conf, sConf, namespaceClient); // Starts a mock server to handle remote secure store requests httpService = NettyHttpService.builder("remoteSecureStoreTest") .setHttpHandlers(new SecureStoreHandler(fileSecureStoreService, fileSecureStoreService)) .setExceptionHandler(new HttpExceptionHandler()) .build(); httpService.start(); InMemoryDiscoveryService discoveryService = new InMemoryDiscoveryService(); discoveryService.register(new Discoverable(Constants.Service.SECURE_STORE_SERVICE, httpService.getBindAddress())); remoteSecureStore = new RemoteSecureStore(discoveryService); }