Remove vavr from SSL API 57/78557/5
authorPiotr Jaszczyk <piotr.jaszczyk@nokia.com>
Fri, 15 Feb 2019 13:49:54 +0000 (14:49 +0100)
committerPiotr Jaszczyk <piotr.jaszczyk@nokia.com>
Mon, 18 Feb 2019 14:20:20 +0000 (15:20 +0100)
It is still used internally, but methods does not depend on it. The goal
was to support clean integration with any JVM app, ie. apps using Kotlin
are rather using Arrow or nothing at all.

Issue-ID: DCAEGEN2-1069
Change-Id: I1a9151bacd287d65ca8c84057de2f3c174cf8145
Signed-off-by: Piotr Jaszczyk <piotr.jaszczyk@nokia.com>
13 files changed:
security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/Password.java
security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/Passwords.java
security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SecurityKeys.java
security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SecurityKeysStore.java
security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SslFactory.java
security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/PasswordEvictedException.java [new file with mode: 0644]
security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/ReadingPasswordFromFileException.java [new file with mode: 0644]
security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/ReadingSecurityKeysStoreException.java [new file with mode: 0644]
security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/SecurityConfigurationException.java [new file with mode: 0644]
security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordTest.java
security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordsTest.java
services/hv-ves-client/producer/ct/src/test/java/org/onap/dcaegen2/services/sdk/services/hvves/client/producer/ct/SystemUnderTestWrapper.java
services/hv-ves-client/producer/impl/src/main/java/org/onap/dcaegen2/services/sdk/services/hvves/client/producer/impl/HvVesProducerFactoryImpl.java

index 35fc7bb..c2feb17 100644 (file)
@@ -26,6 +26,7 @@ import io.vavr.control.Try;
 import java.security.GeneralSecurityException;
 import java.util.Arrays;
 import org.jetbrains.annotations.NotNull;
+import org.onap.dcaegen2.services.sdk.security.ssl.exceptions.PasswordEvictedException;
 
 /**
  * Simple password representation.
@@ -50,9 +51,10 @@ public class Password {
      *
      * @param user of the password
      */
-    public <T> Try<T> use(Function1<char[], Try<T>> user) {
-        if (value == null)
-            return Try.failure(new GeneralSecurityException("Password had been already used so it is in cleared state"));
+    public <T> T use(Function1<char[], T> user) {
+        if (value == null) {
+            throw new PasswordEvictedException("Password had been already used so it is in cleared state");
+        }
 
         try {
             return user.apply(value);
@@ -69,4 +71,14 @@ public class Password {
         Arrays.fill(value, (char) 0);
         value = null;
     }
+
+    /**
+     * For security reasons this will return a constant value.
+     *
+     * @return some predefined string not containing the actual password
+     */
+    @Override
+    public String toString() {
+        return "<password>";
+    }
 }
index 3982808..38dae0d 100644 (file)
 
 package org.onap.dcaegen2.services.sdk.security.ssl;
 
-import io.vavr.control.Try;
+import static io.vavr.Function0.constant;
+
 import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.Charset;
@@ -30,6 +34,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Arrays;
 import org.jetbrains.annotations.NotNull;
+import org.onap.dcaegen2.services.sdk.security.ssl.exceptions.ReadingPasswordFromFileException;
 
 /**
  * Utility functions for loading passwords.
@@ -42,22 +47,97 @@ public final class Passwords {
     private Passwords() {
     }
 
-    public static @NotNull Try<Password> fromFile(File file) {
-        return fromPath(file.toPath());
+    /**
+     * Creates password from given char array.
+     *
+     * Will directly used the provided array, ie. it will be cleared after password was used.
+     *
+     * @param passwd array containing password
+     * @return Password instance wrapping the provided array
+     */
+    public static @NotNull Password wrap(char[] passwd) {
+        return new Password(passwd);
+    }
+
+    /**
+     * Creates password from given CharSequence.
+     *
+     * <em>WARNING</em>: Avoid using this method. It will be impossible to clear memory containing the password.
+     *
+     *
+     * @param passwd the password as CharSequence
+     * @return Password instance
+     */
+    public static @NotNull Password fromString(CharSequence passwd) {
+        return constant(passwd)
+                .andThen(CharBuffer::wrap)
+                .andThen(Passwords::convertToCharArray)
+                .andThen(Passwords::wrap)
+                .apply();
+    }
+
+    /**
+     * Reads password from file.
+     *
+     * @param file to read
+     * @return Password instance with contents of the file
+     * @throws ReadingPasswordFromFileException when file could not be read
+     */
+    public static @NotNull Password fromFile(File file) {
+        return constant(file)
+                .andThen(File::toPath)
+                .andThen(Passwords::fromPath)
+                .apply();
+    }
+
+    /**
+     * Reads password from file.
+     *
+     * @param path of the file to read
+     * @return Password instance with contents of the file
+     * @throws ReadingPasswordFromFileException when file could not be read
+     */
+    public static @NotNull Password fromPath(Path path) {
+        try {
+            return constant(Files.readAllBytes(path))
+                    .andThen(Passwords::decodeChars)
+                    .andThen(Passwords::convertToCharArray)
+                    .andThen(Passwords::wrap)
+                    .apply();
+        } catch (IOException e) {
+            throw new ReadingPasswordFromFileException("Could not read password from " + path, e);
+        }
     }
 
-    public static @NotNull Try<Password> fromPath(Path path) {
-        return Try.of(() -> {
-            final byte[] bytes = Files.readAllBytes(path);
-            final CharBuffer password = decodeChars(bytes);
-            final char[] result = convertToCharArray(password);
-            return new Password(result);
-        });
+    /**
+     * Reads password from resource.
+     *
+     * @param resource URL starting with slash
+     * @return Password instance with contents of the resource
+     * @throws ReadingPasswordFromFileException when resource could not be read
+     */
+    public static @NotNull Password fromResource(String resource) {
+        return constant(resource)
+                .andThen(Passwords::resourceAsUrl)
+                .andThen(Passwords::asPath)
+                .andThen(Passwords::fromPath)
+                .apply();
     }
 
-    public static @NotNull Try<Password> fromResource(String resource) {
-        return Try.of(() -> Paths.get(Passwords.class.getResource(resource).toURI()))
-                .flatMap(Passwords::fromPath);
+    private static @NotNull URL resourceAsUrl(String resource) {
+        final URL resourceUrl = Passwords.class.getResource(resource);
+        if (resourceUrl == null) {
+            throw new ReadingPasswordFromFileException("Could not find resource " + resource);
+        }
+        return resourceUrl;
+    }
+
+    private static Path asPath(URL resourceUrl) {
+        try {
+            return Paths.get(resourceUrl.toURI());
+        } catch (URISyntaxException e) {
+            throw new ReadingPasswordFromFileException("Could not read password", e);
+        }
     }
 
     private static @NotNull CharBuffer decodeChars(byte[] bytes) {
@@ -80,8 +160,10 @@ public final class Passwords {
     }
 
     private static void clearBuffer(CharBuffer password) {
-        while (password.remaining() > 0) {
-            password.put((char) 0);
+        if(!password.isReadOnly()) {
+            while (password.remaining() > 0) {
+                password.put((char) 0);
+            }
         }
     }
 }
index 0ebfc45..401055c 100644 (file)
@@ -22,6 +22,7 @@ package org.onap.dcaegen2.services.sdk.security.ssl;
 
 import java.nio.file.Path;
 import org.immutables.value.Value;
+import org.onap.dcaegen2.services.sdk.security.ssl.exceptions.SecurityConfigurationException;
 
 /**
  * @author <a href="mailto:piotr.jaszczyk@nokia.com">Piotr Jaszczyk</a>
@@ -44,10 +45,11 @@ public interface SecurityKeysStore {
      * not be possible.
      *
      * @return key store type
+     * @throws org.onap.dcaegen2.services.sdk.security.ssl.exceptions.SecurityConfigurationException when file type is unknown
      */
     @Value.Default
     default String type() {
         return KeyStoreTypes.inferTypeFromExtension(path())
-                .getOrElseThrow(() -> new IllegalStateException("Could not determine key store type by file name"));
+                .getOrElseThrow(() -> new SecurityConfigurationException("Could not determine key store type by file name"));
     }
 }
index 1f3f4cf..076490a 100644 (file)
 
 package org.onap.dcaegen2.services.sdk.security.ssl;
 
+import io.netty.handler.ssl.ClientAuth;
 import io.netty.handler.ssl.SslContext;
 import io.netty.handler.ssl.SslContextBuilder;
 import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
-import io.vavr.control.Try;
 import java.io.IOException;
 import java.nio.file.Files;
-import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 import java.security.GeneralSecurityException;
 import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
 import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLException;
 import javax.net.ssl.TrustManagerFactory;
+import org.onap.dcaegen2.services.sdk.security.ssl.exceptions.ReadingSecurityKeysStoreException;
+import org.onap.dcaegen2.services.sdk.security.ssl.exceptions.SecurityConfigurationException;
 
+/**
+ * @since 1.1.1
+ */
 public class SslFactory {
 
+    private static final String EXCEPTION_MESSAGE = "Could not create SSL context";
+
     /**
      * Creates Netty SSL <em>client</em> context using provided security keys.
      *
      * @param keys - Security keys to be used
      * @return configured SSL context
      */
-    public Try<SslContext> createSecureClientContext(final SecurityKeys keys) {
-        return Try.success(SslContextBuilder.forClient())
-                .flatMap(ctx -> keyManagerFactory(keys).map(ctx::keyManager))
-                .flatMap(ctx -> trustManagerFactory(keys).map(ctx::trustManager))
-                .mapTry(SslContextBuilder::build);
+    public SslContext createSecureClientContext(final SecurityKeys keys) {
+        try {
+            return SslContextBuilder.forClient()
+                    .keyManager(keyManagerFactory(keys))
+                    .trustManager(trustManagerFactory(keys))
+                    .build();
+        } catch (SSLException e) {
+            throw new SecurityConfigurationException(EXCEPTION_MESSAGE, e);
+        }
     }
 
     /**
@@ -54,11 +68,15 @@ public class SslFactory {
      * @param keys - Security keys to be used
      * @return configured SSL context
      */
-    public Try<SslContext> createSecureServerContext(final SecurityKeys keys) {
-        return keyManagerFactory(keys)
-                .map(SslContextBuilder::forServer)
-                .flatMap(ctx -> trustManagerFactory(keys).map(ctx::trustManager))
-                .mapTry(SslContextBuilder::build);
+    public SslContext createSecureServerContext(final SecurityKeys keys) {
+        try {
+            return SslContextBuilder.forServer(keyManagerFactory(keys))
+                    .trustManager(trustManagerFactory(keys))
+                    .clientAuth(ClientAuth.REQUIRE)
+                    .build();
+        } catch (SSLException e) {
+            throw new SecurityConfigurationException(EXCEPTION_MESSAGE, e);
+        }
     }
 
     /**
@@ -68,40 +86,53 @@ public class SslFactory {
      * @deprecated Do not use in production. Will trust anyone.
      */
     @Deprecated
-    public Try<SslContext> createInsecureClientContext() {
-        return Try.success(SslContextBuilder.forClient())
-                .map(ctx -> ctx.trustManager(InsecureTrustManagerFactory.INSTANCE))
-                .mapTry(SslContextBuilder::build);
+    public SslContext createInsecureClientContext() {
+        try {
+            return SslContextBuilder.forClient()
+                    .trustManager(InsecureTrustManagerFactory.INSTANCE)
+                    .build();
+        } catch (SSLException e) {
+            throw new SecurityConfigurationException(EXCEPTION_MESSAGE, e);
+        }
     }
 
-    private Try<TrustManagerFactory> trustManagerFactory(SecurityKeys keys) {
+    private TrustManagerFactory trustManagerFactory(SecurityKeys keys) {
         return trustManagerFactory(keys.trustStore(), keys.trustStorePassword());
     }
 
-    private Try<KeyManagerFactory> keyManagerFactory(SecurityKeys keys) {
+    private KeyManagerFactory keyManagerFactory(SecurityKeys keys) {
         return keyManagerFactory(keys.keyStore(), keys.keyStorePassword());
     }
 
-    private Try<KeyManagerFactory> keyManagerFactory(SecurityKeysStore store, Password password) {
-        return password.useChecked(passwordChars -> {
-            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-            kmf.init(loadKeyStoreFromFile(store, passwordChars), passwordChars);
-            return kmf;
+    private KeyManagerFactory keyManagerFactory(SecurityKeysStore store, Password password) {
+        return password.use(passwordChars -> {
+            try {
+                KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+                kmf.init(loadKeyStoreFromFile(store, passwordChars), passwordChars);
+                return kmf;
+            } catch (GeneralSecurityException | IOException ex) {
+                throw new ReadingSecurityKeysStoreException("Could not read private keys from store", ex);
+            }
         });
     }
 
-    private Try<TrustManagerFactory> trustManagerFactory(SecurityKeysStore store, Password password) {
-        return password.useChecked(passwordChars -> {
-            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-            tmf.init(loadKeyStoreFromFile(store, passwordChars));
-            return tmf;
+    private TrustManagerFactory trustManagerFactory(SecurityKeysStore store, Password password) {
+        return password.use(passwordChars -> {
+            try {
+                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+                tmf.init(loadKeyStoreFromFile(store, passwordChars));
+                return tmf;
+            } catch (GeneralSecurityException | IOException ex) {
+                throw new ReadingSecurityKeysStoreException("Could not read trusted keys from store", ex);
+            }
         });
     }
 
     private KeyStore loadKeyStoreFromFile(SecurityKeysStore store, char[] keyStorePassword)
-            throws GeneralSecurityException, IOException {
+            throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
         KeyStore ks = KeyStore.getInstance(store.type());
         ks.load(Files.newInputStream(store.path(), StandardOpenOption.READ), keyStorePassword);
         return ks;
+
     }
 }
diff --git a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/PasswordEvictedException.java b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/PasswordEvictedException.java
new file mode 100644 (file)
index 0000000..508fc6e
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * ============LICENSE_START====================================
+ * DCAEGEN2-SERVICES-SDK
+ * =========================================================
+ * Copyright (C) 2019 Nokia. All rights reserved.
+ * =========================================================
+ * 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.
+ * ============LICENSE_END=====================================
+ */
+
+package org.onap.dcaegen2.services.sdk.security.ssl.exceptions;
+
+/**
+ * @author <a href="mailto:piotr.jaszczyk@nokia.com">Piotr Jaszczyk</a>
+ * @since 1.1.2
+ */
+public class PasswordEvictedException extends RuntimeException {
+
+    public PasswordEvictedException(String message) {
+        super(message);
+    }
+}
diff --git a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/ReadingPasswordFromFileException.java b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/ReadingPasswordFromFileException.java
new file mode 100644 (file)
index 0000000..b39e01c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * ============LICENSE_START====================================
+ * DCAEGEN2-SERVICES-SDK
+ * =========================================================
+ * Copyright (C) 2019 Nokia. All rights reserved.
+ * =========================================================
+ * 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.
+ * ============LICENSE_END=====================================
+ */
+
+package org.onap.dcaegen2.services.sdk.security.ssl.exceptions;
+
+/**
+ * @author <a href="mailto:piotr.jaszczyk@nokia.com">Piotr Jaszczyk</a>
+ * @since 1.1.2
+ */
+public class ReadingPasswordFromFileException extends SecurityConfigurationException {
+
+    public ReadingPasswordFromFileException(String message) {
+        super(message);
+    }
+
+    public ReadingPasswordFromFileException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/ReadingSecurityKeysStoreException.java b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/ReadingSecurityKeysStoreException.java
new file mode 100644 (file)
index 0000000..f8e0cfd
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * ============LICENSE_START====================================
+ * DCAEGEN2-SERVICES-SDK
+ * =========================================================
+ * Copyright (C) 2019 Nokia. All rights reserved.
+ * =========================================================
+ * 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.
+ * ============LICENSE_END=====================================
+ */
+
+package org.onap.dcaegen2.services.sdk.security.ssl.exceptions;
+
+/**
+ * @author <a href="mailto:piotr.jaszczyk@nokia.com">Piotr Jaszczyk</a>
+ * @since 1.1.2
+ */
+public class ReadingSecurityKeysStoreException extends SecurityConfigurationException {
+
+    public ReadingSecurityKeysStoreException(String message) {
+        super(message);
+    }
+
+    public ReadingSecurityKeysStoreException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/SecurityConfigurationException.java b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/SecurityConfigurationException.java
new file mode 100644 (file)
index 0000000..08c38df
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * ============LICENSE_START====================================
+ * DCAEGEN2-SERVICES-SDK
+ * =========================================================
+ * Copyright (C) 2019 Nokia. All rights reserved.
+ * =========================================================
+ * 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.
+ * ============LICENSE_END=====================================
+ */
+
+package org.onap.dcaegen2.services.sdk.security.ssl.exceptions;
+
+/**
+ * @author <a href="mailto:piotr.jaszczyk@nokia.com">Piotr Jaszczyk</a>
+ * @since 1.1.2
+ */
+public class SecurityConfigurationException extends RuntimeException {
+
+    public SecurityConfigurationException(String message) {
+        super(message);
+    }
+
+    public SecurityConfigurationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
index ede227e..41143f6 100644 (file)
@@ -24,10 +24,10 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 
 import io.vavr.collection.Array;
-import io.vavr.control.Try;
 import java.security.GeneralSecurityException;
 import java.util.Arrays;
 import org.junit.jupiter.api.Test;
+import org.onap.dcaegen2.services.sdk.security.ssl.exceptions.PasswordEvictedException;
 
 /**
  * @author <a href="mailto:piotr.jaszczyk@nokia.com">Piotr Jaszczyk</a>
@@ -66,10 +66,10 @@ class PasswordTest {
         final Password cut = new Password("ala ma kota".toCharArray());
 
         // when & then
-        useThePassword(cut).get();
+        useThePassword(cut);
 
-        assertThatExceptionOfType(GeneralSecurityException.class).isThrownBy(() ->
-                useThePassword(cut).get());
+        assertThatExceptionOfType(PasswordEvictedException.class).isThrownBy(() ->
+                useThePassword(cut));
     }
 
     @Test
@@ -80,8 +80,8 @@ class PasswordTest {
         // when & then
         cut.clear();
 
-        assertThatExceptionOfType(GeneralSecurityException.class).isThrownBy(() ->
-                useThePassword(cut).get());
+        assertThatExceptionOfType(PasswordEvictedException.class).isThrownBy(() ->
+                useThePassword(cut));
     }
 
     @Test
@@ -97,8 +97,8 @@ class PasswordTest {
         assertAllCharsAreNull(passwordChars);
     }
 
-    private Try<Object> useThePassword(Password cut) {
-        return cut.use((pass) -> Try.success(42));
+    private void useThePassword(Password cut) {
+        cut.use((pass) -> null);
     }
 
     private void assertAllCharsAreNull(char[] passwordChars) {
index 07c5afe..13d7f21 100644 (file)
 package org.onap.dcaegen2.services.sdk.security.ssl;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import io.vavr.control.Try;
 import java.io.File;
 import java.net.URISyntaxException;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.UUID;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
+import org.onap.dcaegen2.services.sdk.security.ssl.exceptions.ReadingPasswordFromFileException;
 
 /**
  * @author <a href="mailto:piotr.jaszczyk@nokia.com">Piotr Jaszczyk</a>
@@ -37,29 +39,63 @@ import org.junit.jupiter.api.Test;
  */
 class PasswordsTest {
 
+    @Test
+    void wrap() {
+        // given
+        final char[] passwd = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
+
+        // when
+        final Password result = Passwords.wrap(passwd);
+
+        // then
+        assertThat(extractPassword(result)).isEqualTo("password");
+        assertThat(passwd).containsOnly('\0');
+    }
+
+    @Test
+    void fromString() {
+        // given
+        final String passwd = "password";
+
+        // when
+        final Password result = Passwords.fromString(passwd);
+
+        // then
+        assertThat(extractPassword(result)).isEqualTo("password");
+    }
+
     @Test
     void fromFile() {
         // given
         final File file = new File("./src/test/resources/password.txt");
 
         // when
-        final Try<Password> result = Passwords.fromFile(file);
+        final Password result = Passwords.fromFile(file);
 
         // then
-        assertSuccessful(result);
         assertThat(extractPassword(result)).isEqualTo("ja baczewski\n2nd line");
     }
 
+    @Test
+    void fromFileWhenNotExisting() {
+        // given
+        final File file = new File("./not existing file");
+
+        // when & then
+        assertThatThrownBy(() -> Passwords.fromFile(file))
+                .isInstanceOf(ReadingPasswordFromFileException.class)
+                .hasCauseInstanceOf(NoSuchFileException.class);
+    }
+
     @Test
     void fromPath() throws URISyntaxException {
         // given
         final Path path = Paths.get(PasswordsTest.class.getResource("/password.txt").toURI());
 
         // when
-        final Try<Password> result = Passwords.fromPath(path);
+        final Password result = Passwords.fromPath(path);
 
         // then
-        assertSuccessful(result);
         assertThat(extractPassword(result)).isEqualTo("ja baczewski\n2nd line");
     }
 
@@ -69,11 +105,10 @@ class PasswordsTest {
         final Path path = Paths.get("/", UUID.randomUUID().toString());
 
         // when
-        final Try<Password> result = Passwords.fromPath(path);
+        Assertions.assertThrows(ReadingPasswordFromFileException.class, () -> {
+            Passwords.fromPath(path);
+        });
 
-        // then
-        assertThat(result.isFailure()).describedAs("Try.failure?").isTrue();
-        assertThat(result.getCause()).isInstanceOf(NoSuchFileException.class);
     }
 
     @Test
@@ -82,18 +117,13 @@ class PasswordsTest {
         final String resource = "/password.txt";
 
         // when
-        final Try<Password> result = Passwords.fromResource(resource);
+        final Password result = Passwords.fromResource(resource);
 
         // then
-        assertSuccessful(result);
         assertThat(extractPassword(result)).isEqualTo("ja baczewski\n2nd line");
     }
 
-    private void assertSuccessful(Try<Password> result) {
-        assertThat(result.isSuccess()).describedAs("Try.success?").isTrue();
-    }
-
-    private String extractPassword(Try<Password> result) {
-        return result.flatMap(pass -> pass.useChecked(String::new)).get();
+    private String extractPassword(Password pass) {
+        return pass.use(String::new);
     }
 }
\ No newline at end of file
index 87cf9fe..ec16e9e 100644 (file)
@@ -62,9 +62,9 @@ public class SystemUnderTestWrapper {
         start(ImmutableProducerOptions.builder()
                 .securityKeys(ImmutableSecurityKeys.builder()
                         .keyStore(ImmutableSecurityKeysStore.of(resource("/client.p12").get()))
-                        .keyStorePassword(Passwords.fromResource("/client.pass").get())
+                        .keyStorePassword(Passwords.fromResource("/client.pass"))
                         .trustStore(ImmutableSecurityKeysStore.of(resource("/trust.p12").get()))
-                        .trustStorePassword(Passwords.fromResource("/trust.pass").get())
+                        .trustStorePassword(Passwords.fromResource("/trust.pass"))
                         .build()));
     }
 
index e135445..185fca7 100644 (file)
@@ -48,7 +48,7 @@ public class HvVesProducerFactoryImpl extends HvVesProducerFactory {
             LOGGER.warn("Using insecure connection");
         } else {
             LOGGER.info("Using secure tunnel");
-            final SslContext ctx = sslFactory.createSecureClientContext(options.securityKeys()).get();
+            final SslContext ctx = sslFactory.createSecureClientContext(options.securityKeys());
             tcpClient = tcpClient.secure(ssl -> ssl.sslContext(ctx));
         }