diff options
author | Piotr Jaszczyk <piotr.jaszczyk@nokia.com> | 2019-02-15 14:49:54 +0100 |
---|---|---|
committer | Piotr Jaszczyk <piotr.jaszczyk@nokia.com> | 2019-02-18 15:20:20 +0100 |
commit | 28a5b0d5b6c844ca78665bded229e67a429800b7 (patch) | |
tree | e3fad7c857de1a734027fa9ccc3e9dcbb3cc29a5 /security | |
parent | 244b070d680eaac727091193b0998c76c78cc230 (diff) |
Remove vavr from SSL API
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>
Diffstat (limited to 'security')
11 files changed, 370 insertions, 74 deletions
diff --git a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/Password.java b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/Password.java index 35fc7bbe..c2feb17e 100644 --- a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/Password.java +++ b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/Password.java @@ -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>"; + } } diff --git a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/Passwords.java b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/Passwords.java index 39828086..38dae0df 100644 --- a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/Passwords.java +++ b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/Passwords.java @@ -20,8 +20,12 @@ 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); + } } } } diff --git a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SecurityKeys.java b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SecurityKeys.java index 244e33c8..70cb6c02 100644 --- a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SecurityKeys.java +++ b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SecurityKeys.java @@ -28,7 +28,6 @@ import org.immutables.value.Value; */ @Value.Immutable public interface SecurityKeys { - SecurityKeysStore keyStore(); Password keyStorePassword(); diff --git a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SecurityKeysStore.java b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SecurityKeysStore.java index 0ebfc451..401055ca 100644 --- a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SecurityKeysStore.java +++ b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SecurityKeysStore.java @@ -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")); } } diff --git a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SslFactory.java b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SslFactory.java index 1f3f4cfd..076490a9 100644 --- a/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SslFactory.java +++ b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/SslFactory.java @@ -20,32 +20,46 @@ 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 index 00000000..508fc6e2 --- /dev/null +++ b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/PasswordEvictedException.java @@ -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 index 00000000..b39e01c9 --- /dev/null +++ b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/ReadingPasswordFromFileException.java @@ -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 index 00000000..f8e0cfd5 --- /dev/null +++ b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/ReadingSecurityKeysStoreException.java @@ -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 index 00000000..08c38df7 --- /dev/null +++ b/security/ssl/src/main/java/org/onap/dcaegen2/services/sdk/security/ssl/exceptions/SecurityConfigurationException.java @@ -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); + } +} diff --git a/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordTest.java b/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordTest.java index ede227eb..41143f61 100644 --- a/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordTest.java +++ b/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordTest.java @@ -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) { diff --git a/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordsTest.java b/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordsTest.java index 07c5afe8..13d7f213 100644 --- a/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordsTest.java +++ b/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordsTest.java @@ -21,15 +21,17 @@ 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> @@ -38,28 +40,62 @@ 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 |