You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2018/09/06 16:03:43 UTC
[33/51] [abbrv] mina-sshd git commit: [SSHD-842] Split common
utilities code from sshd-core into sshd-common (new artifact)
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryTest.java b/sshd-common/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryTest.java
new file mode 100644
index 0000000..0c8f43c
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryTest.java
@@ -0,0 +1,325 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.client.config.hosts;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class HostConfigEntryTest extends JUnitTestSupport {
+ public HostConfigEntryTest() {
+ super();
+ }
+
+ @Test
+ public void testNegatingPatternOverridesAll() {
+ String testHost = "37.77.34.7";
+ String[] elements = GenericUtils.split(testHost, '.');
+ StringBuilder sb = new StringBuilder(testHost.length() + Byte.SIZE);
+ List<HostPatternValue> patterns = new ArrayList<>(elements.length + 1);
+ // all wildcard patterns are not negated - only the actual host
+ patterns.add(HostPatternsHolder.toPattern(Character.toString(HostPatternsHolder.NEGATION_CHAR_PATTERN) + testHost));
+
+ for (int i = 0; i < elements.length; i++) {
+ sb.setLength(0);
+
+ for (int j = 0; j < elements.length; j++) {
+ if (j > 0) {
+ sb.append('.');
+ }
+ if (i == j) {
+ sb.append(HostPatternsHolder.WILDCARD_PATTERN);
+ } else {
+ sb.append(elements[j]);
+ }
+ }
+
+ patterns.add(HostPatternsHolder.toPattern(sb));
+ }
+
+ for (int index = 0; index < patterns.size(); index++) {
+ assertFalse("Unexpected match for " + patterns, HostPatternsHolder.isHostMatch(testHost, 0, patterns));
+ Collections.shuffle(patterns);
+ }
+ }
+
+ @Test
+ public void testHostWildcardPatternMatching() {
+ String pkgName = getClass().getPackage().getName();
+ String[] elements = GenericUtils.split(pkgName, '.');
+ StringBuilder sb = new StringBuilder(pkgName.length() + Long.SIZE + 1).append(HostPatternsHolder.WILDCARD_PATTERN);
+ for (int index = elements.length - 1; index >= 0; index--) {
+ sb.append('.').append(elements[index]);
+ }
+
+ String value = sb.toString();
+ HostPatternValue pp = HostPatternsHolder.toPattern(value);
+ Pattern pattern = pp.getPattern();
+ String domain = value.substring(1); // chomp the wildcard prefix
+ for (String host : new String[] {
+ getClass().getSimpleName(),
+ getCurrentTestName(),
+ getClass().getSimpleName() + "-" + getCurrentTestName(),
+ getClass().getSimpleName() + "." + getCurrentTestName(),
+ }) {
+ sb.setLength(0); // start from scratch
+ sb.append(host).append(domain);
+
+ testCaseInsensitivePatternMatching(sb.toString(), pattern, true);
+ }
+ }
+
+ @Test
+ public void testIPAddressWildcardPatternMatching() {
+ StringBuilder sb = new StringBuilder().append("10.0.0.");
+ int sbLen = sb.length();
+
+ Pattern pattern = HostPatternsHolder.toPattern(sb.append(HostPatternsHolder.WILDCARD_PATTERN)).getPattern();
+ for (int v = 0; v <= 255; v++) {
+ sb.setLength(sbLen); // start from scratch
+ sb.append(v);
+
+ String address = sb.toString();
+ assertTrue("No match for " + address, HostPatternsHolder.isHostMatch(address, pattern));
+ }
+ }
+
+ @Test
+ public void testHostSingleCharPatternMatching() {
+ String value = getCurrentTestName();
+ StringBuilder sb = new StringBuilder(value);
+ for (boolean restoreOriginal : new boolean[] {true, false}) {
+ for (int index = 0; index < value.length(); index++) {
+ sb.setCharAt(index, HostPatternsHolder.SINGLE_CHAR_PATTERN);
+ testCaseInsensitivePatternMatching(value, HostPatternsHolder.toPattern(sb.toString()).getPattern(), true);
+ if (restoreOriginal) {
+ sb.setCharAt(index, value.charAt(index));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testIPAddressSingleCharPatternMatching() {
+ StringBuilder sb = new StringBuilder().append("10.0.0.");
+ int sbLen = sb.length();
+
+ for (int v = 0; v <= 255; v++) {
+ sb.setLength(sbLen); // start from scratch
+ sb.append(v);
+
+ String address = sb.toString();
+ // replace the added digits with single char pattern
+ for (int index = sbLen; index < sb.length(); index++) {
+ sb.setCharAt(index, HostPatternsHolder.SINGLE_CHAR_PATTERN);
+ }
+
+ String pattern = sb.toString();
+ HostPatternValue pp = HostPatternsHolder.toPattern(pattern);
+ assertTrue("No match for " + address + " on pattern=" + pattern, HostPatternsHolder.isHostMatch(address, 0, Collections.singletonList(pp)));
+ }
+ }
+
+ @Test
+ public void testIsValidPatternChar() {
+ for (char ch = '\0'; ch <= ' '; ch++) {
+ assertFalse("Unexpected valid character (0x" + Integer.toHexString(ch & 0xFF) + ")", HostPatternsHolder.isValidPatternChar(ch));
+ }
+
+ for (char ch = 'a'; ch <= 'z'; ch++) {
+ assertTrue("Valid character not recognized: " + Character.toString(ch), HostPatternsHolder.isValidPatternChar(ch));
+ }
+
+ for (char ch = 'A'; ch <= 'Z'; ch++) {
+ assertTrue("Valid character not recognized: " + Character.toString(ch), HostPatternsHolder.isValidPatternChar(ch));
+ }
+
+ for (char ch = '0'; ch <= '9'; ch++) {
+ assertTrue("Valid character not recognized: " + Character.toString(ch), HostPatternsHolder.isValidPatternChar(ch));
+ }
+
+ for (char ch : new char[] {'-', '_', '.', HostPatternsHolder.SINGLE_CHAR_PATTERN, HostPatternsHolder.WILDCARD_PATTERN}) {
+ assertTrue("Valid character not recognized: " + Character.toString(ch), HostPatternsHolder.isValidPatternChar(ch));
+ }
+
+ for (char ch : new char[] {
+ '(', ')', '{', '}', '[', ']', '@',
+ '#', '$', '^', '&', '%', '~', '<', '>',
+ ',', '/', '\\', '\'', '"', ':', ';'
+ }) {
+ assertFalse("Unexpected valid character: " + Character.toString(ch), HostPatternsHolder.isValidPatternChar(ch));
+ }
+
+ for (char ch = 0x7E; ch <= 0xFF; ch++) {
+ assertFalse("Unexpected valid character (0x" + Integer.toHexString(ch & 0xFF) + ")", HostPatternsHolder.isValidPatternChar(ch));
+ }
+ }
+
+ @Test
+ public void testResolvePort() {
+ final int originalPort = Short.MAX_VALUE;
+ final int preferredPort = 7365;
+ assertEquals("Mismatched entry port preference",
+ preferredPort, HostConfigEntry.resolvePort(originalPort, preferredPort));
+
+ for (int entryPort : new int[] {-1, 0}) {
+ assertEquals("Non-preferred original port for entry port=" + entryPort,
+ originalPort, HostConfigEntry.resolvePort(originalPort, entryPort));
+ }
+ }
+
+ @Test
+ public void testResolveUsername() {
+ final String originalUser = getCurrentTestName();
+ final String preferredUser = getClass().getSimpleName();
+ assertSame("Mismatched entry user preference",
+ preferredUser, HostConfigEntry.resolveUsername(originalUser, preferredUser));
+
+ for (String entryUser : new String[] {null, ""}) {
+ assertSame("Non-preferred original user for entry user='" + entryUser + "'",
+ originalUser, HostConfigEntry.resolveUsername(originalUser, entryUser));
+ }
+ }
+
+ @Test
+ public void testReadSimpleHostsConfigEntries() throws IOException {
+ validateHostConfigEntries(readHostConfigEntries());
+ }
+
+ @Test
+ public void testReadGlobalHostsConfigEntries() throws IOException {
+ List<HostConfigEntry> entries = validateHostConfigEntries(readHostConfigEntries());
+ assertTrue("Not enough entries read", GenericUtils.size(entries) > 1);
+
+ // global entry MUST be 1st one
+ HostConfigEntry globalEntry = entries.get(0);
+ assertEquals("Mismatched global entry pattern", HostPatternsHolder.ALL_HOSTS_PATTERN, globalEntry.getHost());
+
+ for (int index = 1; index < entries.size(); index++) {
+ HostConfigEntry entry = entries.get(index);
+ assertFalse("No target host for " + entry, GenericUtils.isEmpty(entry.getHostName()));
+ assertTrue("No target port for " + entry, entry.getPort() > 0);
+ assertFalse("No username for " + entry, GenericUtils.isEmpty(entry.getUsername()));
+ assertFalse("No identities for " + entry, GenericUtils.isEmpty(entry.getIdentities()));
+ assertFalse("No properties for " + entry, GenericUtils.isEmpty(entry.getProperties()));
+ }
+ }
+
+ @Test
+ public void testReadMultipleHostPatterns() throws IOException {
+ List<HostConfigEntry> entries = validateHostConfigEntries(readHostConfigEntries());
+ assertEquals("Mismatched number of entries", 1, GenericUtils.size(entries));
+ assertEquals("Mismatched number of patterns", 3, GenericUtils.size(entries.get(0).getPatterns()));
+ }
+
+ @Test
+ public void testResolveIdentityFilePath() throws Exception {
+ final String hostValue = getClass().getSimpleName();
+ final int portValue = 7365;
+ final String userValue = getCurrentTestName();
+
+ Exception err = null;
+ for (String pattern : new String[] {
+ "~/.ssh/%h.key",
+ "%d/.ssh/%h.key",
+ "/home/%u/.ssh/id_rsa_%p",
+ "/home/%u/.ssh/id_%r_rsa",
+ "/home/%u/.ssh/%h/%l.key"
+ }) {
+ try {
+ String result = HostConfigEntry.resolveIdentityFilePath(pattern, hostValue, portValue, userValue);
+ System.out.append('\t').append(pattern).append(" => ").println(result);
+ } catch (Exception e) {
+ System.err.append("Failed (").append(e.getClass().getSimpleName())
+ .append(") to process pattern=").append(pattern)
+ .append(": ").println(e.getMessage());
+ err = e;
+ }
+ }
+
+ if (err != null) {
+ throw err;
+ }
+ }
+
+ @Test
+ public void testFindBestMatch() {
+ final String hostValue = getCurrentTestName();
+ HostConfigEntry expected = new HostConfigEntry(hostValue, hostValue, 7365, hostValue);
+ List<HostConfigEntry> matches = new ArrayList<>();
+ matches.add(new HostConfigEntry(HostPatternsHolder.ALL_HOSTS_PATTERN,
+ getClass().getSimpleName(), Short.MAX_VALUE, getClass().getSimpleName()));
+ matches.add(new HostConfigEntry(hostValue + Character.toString(HostPatternsHolder.WILDCARD_PATTERN),
+ getClass().getSimpleName(), Byte.MAX_VALUE, getClass().getSimpleName()));
+ matches.add(expected);
+
+ for (int index = 0; index < matches.size(); index++) {
+ HostConfigEntry actual = HostConfigEntry.findBestMatch(matches);
+ assertSame("Mismatched best match for " + matches, expected, actual);
+ Collections.shuffle(matches);
+ }
+ }
+
+ private static <C extends Collection<HostConfigEntry>> C validateHostConfigEntries(C entries) {
+ assertFalse("No entries", GenericUtils.isEmpty(entries));
+
+ for (HostConfigEntry entry : entries) {
+ assertFalse("No pattern for " + entry, GenericUtils.isEmpty(entry.getHost()));
+ assertFalse("No extra properties for " + entry, GenericUtils.isEmpty(entry.getProperties()));
+ }
+
+ return entries;
+ }
+
+ private List<HostConfigEntry> readHostConfigEntries() throws IOException {
+ return readHostConfigEntries(getCurrentTestName() + ".config.txt");
+ }
+
+ private List<HostConfigEntry> readHostConfigEntries(String resourceName) throws IOException {
+ URL url = getClass().getResource(resourceName);
+ assertNotNull("Missing resource " + resourceName, url);
+ return HostConfigEntry.readHostConfigEntries(url);
+ }
+
+ private static void testCaseInsensitivePatternMatching(String value, Pattern pattern, boolean expected) {
+ for (int index = 0; index < value.length(); index++) {
+ boolean actual = HostPatternsHolder.isHostMatch(value, pattern);
+ assertEquals("Mismatched match result for " + value + " on pattern=" + pattern.pattern(), expected, actual);
+ value = shuffleCase(value);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/client/config/hosts/KnownHostHashValueTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/client/config/hosts/KnownHostHashValueTest.java b/sshd-common/src/test/java/org/apache/sshd/client/config/hosts/KnownHostHashValueTest.java
new file mode 100644
index 0000000..80d58d0
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/client/config/hosts/KnownHostHashValueTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.client.config.hosts;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+@Category({ NoIoTestCase.class })
+public class KnownHostHashValueTest extends JUnitTestSupport {
+ private final String hostName;
+ private final String hashValue;
+ private final KnownHostHashValue hash;
+
+ public KnownHostHashValueTest(String hostName, String hashValue) {
+ this.hostName = hostName;
+ this.hashValue = hashValue;
+ this.hash = KnownHostHashValue.parse(hashValue);
+ }
+
+ @Parameters(name = "host={0}, hash={1}")
+ public static Collection<Object[]> parameters() {
+ return Arrays.<Object[]>asList(
+ (Object[]) new String[]{"192.168.1.61", "|1|F1E1KeoE/eEWhi10WpGv4OdiO6Y=|3988QV0VE8wmZL7suNrYQLITLCg="});
+ }
+
+ @Test
+ public void testDecodeEncode() {
+ assertSame("Mismatched digester", KnownHostHashValue.DEFAULT_DIGEST, hash.getDigester());
+ assertEquals("Mismatched encoded form", hashValue, hash.toString());
+ }
+
+ @Test
+ public void testHostMatch() {
+ assertTrue("Specified host does not match", hash.isHostMatch(hostName));
+ assertFalse("Unexpected host match", hash.isHostMatch(getCurrentTestName()));
+ }
+
+ @Test
+ public void testCalculateHashValue() throws Exception {
+ byte[] expected = hash.getDigestValue();
+ byte[] actual = KnownHostHashValue.calculateHashValue(hostName, hash.getDigester(), hash.getSaltValue());
+ assertArrayEquals("Mismatched hash value", expected, actual);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java b/sshd-common/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
new file mode 100644
index 0000000..19375ec
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.client.config.keys;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.sshd.common.config.keys.BuiltinIdentities;
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.util.test.CommonTestSupportUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class BuiltinClientIdentitiesWatcherTest extends JUnitTestSupport {
+ public BuiltinClientIdentitiesWatcherTest() {
+ super();
+ }
+
+ @Test
+ public void testMultipleFilesWatch() throws Exception {
+ KeyPair identity = CommonTestSupportUtils.getFirstKeyPair(createTestHostKeyProvider());
+ String keyType = ValidateUtils.checkNotNullAndNotEmpty(KeyUtils.getKeyType(identity), "Cannot determine identity key type");
+
+ Path dir = assertHierarchyTargetFolderExists(getTempTargetRelativeFile(getClass().getSimpleName()));
+ Map<BuiltinIdentities, Path> locationsMap = new EnumMap<>(BuiltinIdentities.class);
+ Map<BuiltinIdentities, KeyPair> idsMap = new EnumMap<>(BuiltinIdentities.class);
+ for (BuiltinIdentities id : BuiltinIdentities.VALUES) {
+ Path idFile = dir.resolve(ClientIdentity.getIdentityFileName(id));
+ Files.deleteIfExists(idFile);
+ assertNull("Multiple file mappings for " + id, locationsMap.put(id, idFile));
+ assertNull("Multiple identity mappings for " + id, idsMap.put(id, KeyUtils.cloneKeyPair(keyType, identity)));
+ }
+
+ ClientIdentityLoader loader = new ClientIdentityLoader() {
+ @Override
+ public KeyPair loadClientIdentity(String location, FilePasswordProvider provider) throws IOException, GeneralSecurityException {
+ BuiltinIdentities id = findIdentity(location);
+ assertNotNull("Invalid location: " + location, id);
+ return idsMap.get(id);
+ }
+
+ @Override
+ public boolean isValidLocation(String location) throws IOException {
+ return findIdentity(location) != null;
+ }
+
+ private BuiltinIdentities findIdentity(String location) {
+ if (GenericUtils.isEmpty(location)) {
+ return null;
+ }
+
+ for (Map.Entry<BuiltinIdentities, Path> le : locationsMap.entrySet()) {
+ Path path = le.getValue();
+ if (String.CASE_INSENSITIVE_ORDER.compare(location, path.toString()) == 0) {
+ return le.getKey();
+ }
+ }
+
+ return null;
+ }
+ };
+
+ Map<BuiltinIdentities, KeyPair> existing = new EnumMap<>(BuiltinIdentities.class);
+ KeyPairProvider watcher = new BuiltinClientIdentitiesWatcher(dir, false, loader, FilePasswordProvider.EMPTY, false);
+ testMultipleFilesWatch("No files", watcher, existing.values());
+
+ for (BuiltinIdentities id : BuiltinIdentities.VALUES) {
+ String phase = id + " + " + Objects.toString(existing.keySet());
+ touchIdentityFile(locationsMap.get(id));
+ existing.put(id, idsMap.get(id));
+
+ for (int index = 0; index < Byte.SIZE; index++) {
+ testMultipleFilesWatch(phase + "[" + index + "]", watcher, existing.values());
+ }
+ }
+
+ testMultipleFilesWatch("All files", watcher, existing.values());
+
+ for (BuiltinIdentities id : BuiltinIdentities.VALUES) {
+ existing.remove(id);
+ Files.deleteIfExists(locationsMap.get(id));
+ String phase = Objects.toString(existing.keySet()) + " - " + id;
+
+ for (int index = 0; index < Byte.SIZE; index++) {
+ testMultipleFilesWatch(phase + "[" + index + "]", watcher, existing.values());
+ }
+ }
+ }
+
+ private static void touchIdentityFile(Path idFile) throws IOException {
+ OpenOption[] options = IoUtils.EMPTY_OPEN_OPTIONS;
+ if (Files.exists(idFile, IoUtils.EMPTY_LINK_OPTIONS)) {
+ options = new OpenOption[]{StandardOpenOption.WRITE, StandardOpenOption.APPEND};
+ }
+
+ try (OutputStream out = Files.newOutputStream(idFile, options)) {
+ out.write(new Date(System.currentTimeMillis()).toString().getBytes(StandardCharsets.UTF_8));
+ out.write('\n');
+ }
+ }
+
+ private static void testMultipleFilesWatch(String phase, KeyIdentityProvider watcher, Collection<? extends KeyPair> expected) {
+ Iterable<KeyPair> keys = watcher.loadKeys();
+ Collection<KeyPair> actual = new ArrayList<>();
+ for (KeyPair kp : keys) {
+ actual.add(kp);
+ }
+ assertEquals(phase + ": mismatched sizes", GenericUtils.size(expected), GenericUtils.size(actual));
+
+ if (!GenericUtils.isEmpty(expected)) {
+ for (KeyPair kp : expected) {
+ assertTrue(phase + ": missing key", actual.contains(kp));
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcherTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcherTest.java b/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcherTest.java
new file mode 100644
index 0000000..144a3b0
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcherTest.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.client.config.keys;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.util.Date;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.util.test.CommonTestSupportUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class ClientIdentityFileWatcherTest extends JUnitTestSupport {
+ public ClientIdentityFileWatcherTest() {
+ super();
+ }
+
+ @Test
+ public void testIdentityReload() throws Exception {
+ Path dir = assertHierarchyTargetFolderExists(getTempTargetRelativeFile(getClass().getSimpleName()));
+ Path idFile = dir.resolve(getCurrentTestName() + ".pem");
+ KeyPair identity = CommonTestSupportUtils.getFirstKeyPair(createTestHostKeyProvider());
+ ClientIdentityLoader loader = new ClientIdentityLoader() {
+ @Override
+ public KeyPair loadClientIdentity(String location, FilePasswordProvider provider) throws IOException, GeneralSecurityException {
+ assertTrue("Invalid location: " + location, isValidLocation(location));
+ return identity;
+ }
+
+ @Override
+ public boolean isValidLocation(String location) throws IOException {
+ return Objects.equals(location, toString());
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toString(idFile);
+ }
+ };
+
+ AtomicInteger reloadCount = new AtomicInteger(0);
+ ClientIdentityProvider idProvider = new ClientIdentityFileWatcher(idFile, loader, FilePasswordProvider.EMPTY, false) {
+ @Override
+ protected KeyPair reloadClientIdentity(Path path) throws IOException, GeneralSecurityException {
+ assertEquals("Mismatched client identity path", idFile, path);
+ reloadCount.incrementAndGet();
+ return super.reloadClientIdentity(path);
+ }
+ };
+ Files.deleteIfExists(idFile);
+
+ testIdentityReload("Non-existing", reloadCount, idProvider, null, 0);
+
+ touchIdentityFile(idFile);
+ for (int index = 1; index < Byte.SIZE; index++) {
+ testIdentityReload("Created iteration " + 1, reloadCount, idProvider, identity, 1);
+ }
+
+ touchIdentityFile(idFile);
+ for (int index = 1; index < Byte.SIZE; index++) {
+ testIdentityReload("Modified iteration " + 1, reloadCount, idProvider, identity, 2);
+ }
+ }
+
+ private static void touchIdentityFile(Path idFile) throws IOException {
+ OpenOption[] options = IoUtils.EMPTY_OPEN_OPTIONS;
+ if (Files.exists(idFile, IoUtils.EMPTY_LINK_OPTIONS)) {
+ options = new OpenOption[]{StandardOpenOption.WRITE, StandardOpenOption.APPEND};
+ }
+
+ try (OutputStream out = Files.newOutputStream(idFile, options)) {
+ out.write(new Date(System.currentTimeMillis()).toString().getBytes(StandardCharsets.UTF_8));
+ out.write('\n');
+ }
+ }
+
+ private static void testIdentityReload(
+ String phase, Number reloadCount, ClientIdentityProvider provider, KeyPair expectedIdentity, int expectedCount)
+ throws Exception {
+ KeyPair actualIdentity = provider.getClientIdentity();
+ assertSame(phase + ": mismatched identity", expectedIdentity, actualIdentity);
+ assertEquals(phase + ": mismatched re-load count", expectedCount, reloadCount.intValue());
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityTest.java b/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityTest.java
new file mode 100644
index 0000000..bc2f02c
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.client.config.keys;
+
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.security.KeyPair;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Map;
+
+import org.apache.sshd.common.config.keys.BuiltinIdentities;
+import org.apache.sshd.common.config.keys.IdentityUtils;
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class ClientIdentityTest extends JUnitTestSupport {
+ public ClientIdentityTest() {
+ super();
+ }
+
+ @Test
+ public void testLoadClientIdentities() throws Exception {
+ Path resFolder = getTestResourcesFolder();
+ LinkOption[] options = IoUtils.getLinkOptions(true);
+ Collection<BuiltinIdentities> expected = EnumSet.noneOf(BuiltinIdentities.class);
+ for (BuiltinIdentities type : BuiltinIdentities.VALUES) {
+ String fileName = ClientIdentity.getIdentityFileName(type);
+ Path file = resFolder.resolve(fileName);
+ if (!Files.exists(file, options)) {
+ System.out.println("Skip non-existing identity file " + file);
+ continue;
+ }
+
+ if (!type.isSupported()) {
+ System.out.println("Skip unsupported identity file " + file);
+ continue;
+ }
+
+ expected.add(type);
+ }
+
+ Map<String, KeyPair> ids = ClientIdentity.loadDefaultIdentities(
+ resFolder,
+ false, // don't be strict
+ null, // none of the files is password protected
+ options);
+ assertEquals("Mismatched loaded ids count", GenericUtils.size(expected), GenericUtils.size(ids));
+
+ Collection<KeyPair> pairs = new ArrayList<>(ids.size());
+ for (BuiltinIdentities type : BuiltinIdentities.VALUES) {
+ if (expected.contains(type)) {
+ KeyPair kp = ids.get(type.getName());
+ assertNotNull("No key pair loaded for " + type, kp);
+ pairs.add(kp);
+ }
+ }
+
+ KeyIdentityProvider provider = IdentityUtils.createKeyPairProvider(ids, true /* supported only */);
+ assertNotNull("No provider generated", provider);
+
+ Iterable<KeyPair> keys = provider.loadKeys();
+ for (KeyPair kp : keys) {
+ assertTrue("Unexpected loaded key: " + kp, pairs.remove(kp));
+ }
+
+ assertEquals("Not all pairs listed", 0, pairs.size());
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/SshConstantsTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/SshConstantsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/SshConstantsTest.java
new file mode 100644
index 0000000..1d123d3
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/SshConstantsTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import java.util.Collection;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class SshConstantsTest extends JUnitTestSupport {
+ public SshConstantsTest() {
+ super();
+ }
+
+ @Test
+ public void testGetDisconnectReason() {
+ for (int reason = SshConstants.SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT; reason <= SshConstants.SSH2_DISCONNECT_ILLEGAL_USER_NAME; reason++) {
+ String name = SshConstants.getDisconnectReasonName(reason);
+ assertTrue("Mismatched name for reason=" + reason + ": " + name, name.startsWith("SSH2_DISCONNECT_"));
+ }
+ }
+
+ @Test
+ public void testGetOpenErrorName() {
+ for (int code = SshConstants.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; code <= SshConstants.SSH_OPEN_RESOURCE_SHORTAGE; code++) {
+ String name = SshConstants.getOpenErrorCodeName(code);
+ assertTrue("Mismatched name for code=" + code + ": " + name, name.startsWith("SSH_OPEN_"));
+ }
+ }
+
+ @Test
+ public void testAmbiguousOpcodes() throws Exception {
+ int[] knownAmbiguities = {30, 31, 60};
+ Collection<Integer> opcodes = SshConstants.getAmbiguousOpcodes();
+ assertTrue("Not enough ambiguities found", GenericUtils.size(opcodes) >= knownAmbiguities.length);
+
+ for (int cmd : knownAmbiguities) {
+ assertEquals("Mismatched mnemonic for known ambiguity=" + cmd, Integer.toString(cmd), SshConstants.getCommandMessageName(cmd));
+ assertTrue("Known ambiguity not reported as such: " + cmd, SshConstants.isAmbiguousOpcode(cmd));
+ assertTrue("Known ambiguity=" + cmd + " not listed: " + opcodes, opcodes.contains(cmd));
+ }
+
+ for (Integer cmd : opcodes) {
+ assertEquals("Mismatched mnemonic for " + cmd, cmd.toString(), SshConstants.getCommandMessageName(cmd));
+ assertTrue("Opcode not detected as ambiguous: " + cmd, SshConstants.isAmbiguousOpcode(cmd));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/VersionPropertiesTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/VersionPropertiesTest.java b/sshd-common/src/test/java/org/apache/sshd/common/VersionPropertiesTest.java
new file mode 100644
index 0000000..c0978d4
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/VersionPropertiesTest.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import java.util.Map;
+
+import org.apache.sshd.common.config.VersionProperties;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class VersionPropertiesTest extends JUnitTestSupport {
+ public VersionPropertiesTest() {
+ super();
+ }
+
+ @Test
+ public void testNonEmptyProperties() {
+ Map<?, ?> props = VersionProperties.getVersionProperties();
+ assertTrue(GenericUtils.isNotEmpty(props));
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/cipher/AES192CTRTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/cipher/AES192CTRTest.java b/sshd-common/src/test/java/org/apache/sshd/common/cipher/AES192CTRTest.java
new file mode 100644
index 0000000..6611702
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/cipher/AES192CTRTest.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.cipher;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class AES192CTRTest extends BaseCipherTest {
+ public AES192CTRTest() {
+ super();
+ }
+
+ @Test
+ public void testEncryptDecrypt() throws Exception {
+ // for AES 256 bits we need the JCE unlimited strength policy
+ ensureKeySizeSupported(16, 24, "AES", "AES/CTR/NoPadding");
+ testEncryptDecrypt(BuiltinCiphers.aes192ctr);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/cipher/AES256CBCTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/cipher/AES256CBCTest.java b/sshd-common/src/test/java/org/apache/sshd/common/cipher/AES256CBCTest.java
new file mode 100644
index 0000000..dd39fd4
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/cipher/AES256CBCTest.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.cipher;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class AES256CBCTest extends BaseCipherTest {
+ public AES256CBCTest() {
+ super();
+ }
+
+ @Test
+ public void testEncryptDecrypt() throws Exception {
+ // for AES 256 bits we need the JCE unlimited strength policy
+ ensureKeySizeSupported(16, 32, "AES", "AES/CBC/NoPadding");
+ testEncryptDecrypt(BuiltinCiphers.aes256cbc);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/cipher/ARCFOUR128Test.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/cipher/ARCFOUR128Test.java b/sshd-common/src/test/java/org/apache/sshd/common/cipher/ARCFOUR128Test.java
new file mode 100644
index 0000000..1c37449
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/cipher/ARCFOUR128Test.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.cipher;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ARCFOUR128Test extends BaseCipherTest {
+ public ARCFOUR128Test() {
+ super();
+ }
+
+ @Test
+ public void testEncryptDecrypt() throws Exception {
+ testEncryptDecrypt(BuiltinCiphers.arcfour128);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/cipher/ARCFOUR256Test.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/cipher/ARCFOUR256Test.java b/sshd-common/src/test/java/org/apache/sshd/common/cipher/ARCFOUR256Test.java
new file mode 100644
index 0000000..5511e0f
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/cipher/ARCFOUR256Test.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.cipher;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ARCFOUR256Test extends BaseCipherTest {
+ public ARCFOUR256Test() {
+ super();
+ }
+
+ @Test
+ public void testEncryptDecrypt() throws Exception {
+ // for RC4 256 bits we need the JCE unlimited strength policy
+ ensureKeySizeSupported(32, "ARCFOUR", "RC4");
+ testEncryptDecrypt(BuiltinCiphers.arcfour256);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/cipher/BaseCipherTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/cipher/BaseCipherTest.java b/sshd-common/src/test/java/org/apache/sshd/common/cipher/BaseCipherTest.java
new file mode 100644
index 0000000..514cba4
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/cipher/BaseCipherTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.cipher;
+
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.cipher.Cipher.Mode;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.Assume;
+import org.junit.experimental.categories.Category;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@Category({ NoIoTestCase.class })
+public abstract class BaseCipherTest extends JUnitTestSupport {
+ protected BaseCipherTest() {
+ super();
+ }
+
+ protected void ensureKeySizeSupported(int bsize, String algorithm, String transformation) throws GeneralSecurityException {
+ try {
+ javax.crypto.Cipher cipher = SecurityUtils.getCipher(transformation);
+ byte[] key = new byte[bsize];
+ cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, new SecretKeySpec(key, algorithm));
+ } catch (GeneralSecurityException e) {
+ if (e instanceof InvalidKeyException) { // NOTE: assumption violations are NOT test failures...
+ Assume.assumeTrue(algorithm + "/" + transformation + "[" + bsize + "] N/A", false);
+ }
+
+ throw e;
+ }
+ }
+
+ protected void ensureKeySizeSupported(int ivsize, int bsize, String algorithm, String transformation) throws GeneralSecurityException {
+ try {
+ javax.crypto.Cipher cipher = SecurityUtils.getCipher(transformation);
+ byte[] key = new byte[bsize];
+ byte[] iv = new byte[ivsize];
+ cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, new SecretKeySpec(key, algorithm), new IvParameterSpec(iv));
+ } catch (GeneralSecurityException e) {
+ if (e instanceof InvalidKeyException) {
+ Assume.assumeTrue(algorithm + "/" + transformation + "[" + bsize + "/" + ivsize + "]", false /* force exception */);
+ }
+
+ throw e;
+ }
+ }
+
+ protected void testEncryptDecrypt(NamedFactory<Cipher> factory) throws Exception {
+ String facName = factory.getName();
+ Cipher enc = factory.create();
+ int keySize = enc.getBlockSize();
+ int ivSize = enc.getIVSize();
+ byte[] key = new byte[keySize];
+ byte[] iv = new byte[ivSize];
+ enc.init(Mode.Encrypt, key, iv);
+
+ byte[] expected = facName.getBytes(StandardCharsets.UTF_8);
+ byte[] workBuf = expected.clone(); // need to clone since the cipher works in-line
+ enc.update(workBuf, 0, workBuf.length);
+
+ Cipher dec = factory.create();
+ dec.init(Mode.Decrypt, key, iv);
+ byte[] actual = workBuf.clone();
+ dec.update(actual, 0, actual.length);
+
+ assertArrayEquals(facName, expected, actual);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/cipher/ECCurvesTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/cipher/ECCurvesTest.java b/sshd-common/src/test/java/org/apache/sshd/common/cipher/ECCurvesTest.java
new file mode 100644
index 0000000..2294606
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/cipher/ECCurvesTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.cipher;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class ECCurvesTest extends JUnitTestSupport {
+ public ECCurvesTest() {
+ super();
+ }
+
+ @Test
+ public void testFromName() {
+ for (ECCurves expected : ECCurves.VALUES) {
+ String name = expected.getName();
+ for (int index = 0; index < name.length(); index++) {
+ ECCurves actual = ECCurves.fromCurveName(name);
+ assertSame(name, expected, actual);
+ name = shuffleCase(name);
+ }
+ }
+ }
+
+ @Test
+ public void testAllNamesListed() {
+ Set<ECCurves> listed = EnumSet.noneOf(ECCurves.class);
+ for (String name : ECCurves.NAMES) {
+ ECCurves c = ECCurves.fromCurveName(name);
+ assertNotNull("No curve for listed name=" + name, c);
+ assertTrue("Duplicated listed name: " + name, listed.add(c));
+ }
+
+ assertEquals("Mismatched listed vs. values", ECCurves.VALUES, listed);
+ }
+
+ @Test
+ public void testFromKeySize() {
+ for (ECCurves expected : ECCurves.VALUES) {
+ String name = expected.getName();
+ ECCurves actual = ECCurves.fromCurveSize(expected.getKeySize());
+ assertSame(name, expected, actual);
+ }
+ }
+
+ @Test
+ public void testFromCurveParameters() {
+ for (ECCurves expected : ECCurves.VALUES) {
+ String name = expected.getName();
+ ECCurves actual = ECCurves.fromCurveParameters(expected.getParameters());
+ assertSame(name, expected, actual);
+ }
+ }
+
+ @Test
+ public void testFromKeyType() {
+ for (ECCurves expected : ECCurves.VALUES) {
+ String keyType = expected.getKeyType();
+ for (int index = 0; index < keyType.length(); index++) {
+ ECCurves actual = ECCurves.fromKeyType(keyType);
+ assertSame(keyType, expected, actual);
+ keyType = shuffleCase(keyType);
+ }
+ }
+ }
+
+ @Test
+ public void testAllKeyTypesListed() {
+ Set<ECCurves> listed = EnumSet.noneOf(ECCurves.class);
+ for (String name : ECCurves.KEY_TYPES) {
+ ECCurves c = ECCurves.fromKeyType(name);
+ assertNotNull("No curve for listed key type=" + name, c);
+ assertTrue("Duplicated listed key type: " + name, listed.add(c));
+ }
+
+ assertEquals("Mismatched listed vs. values", ECCurves.VALUES, listed);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/compression/BuiltinCompressionsTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/compression/BuiltinCompressionsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/compression/BuiltinCompressionsTest.java
new file mode 100644
index 0000000..3d1ed00
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/compression/BuiltinCompressionsTest.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.compression;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.compression.BuiltinCompressions.ParseResult;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+import org.mockito.Mockito;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class BuiltinCompressionsTest extends JUnitTestSupport {
+ public BuiltinCompressionsTest() {
+ super();
+ }
+
+ @Test
+ public void testFromFactoryName() {
+ for (BuiltinCompressions expected : BuiltinCompressions.VALUES) {
+ String name = expected.getName();
+
+ for (int index = 0; index < name.length(); index++) {
+ BuiltinCompressions actual = BuiltinCompressions.fromFactoryName(name);
+ assertSame(name, expected, actual);
+ name = shuffleCase(name);
+ }
+ }
+ }
+
+ @Test
+ public void testAllConstantsCovered() throws Exception {
+ Set<BuiltinCompressions> avail = EnumSet.noneOf(BuiltinCompressions.class);
+ Field[] fields = BuiltinCompressions.Constants.class.getFields();
+ for (Field f : fields) {
+ String name = (String) f.get(null);
+ BuiltinCompressions value = BuiltinCompressions.fromFactoryName(name);
+ assertNotNull("No match found for " + name, value);
+ assertTrue(name + " re-specified", avail.add(value));
+ }
+
+ assertEquals("Incomplete coverage", BuiltinCompressions.VALUES, avail);
+ }
+
+ @Test
+ public void testParseCompressionsList() {
+ List<String> builtin = NamedResource.getNameList(BuiltinCompressions.VALUES);
+ List<String> unknown = Arrays.asList(getClass().getPackage().getName(), getClass().getSimpleName(), getCurrentTestName());
+ Random rnd = new Random();
+ for (int index = 0; index < (builtin.size() + unknown.size()); index++) {
+ Collections.shuffle(builtin, rnd);
+ Collections.shuffle(unknown, rnd);
+
+ List<String> weavedList = new ArrayList<>(builtin.size() + unknown.size());
+ for (int bIndex = 0, uIndex = 0; (bIndex < builtin.size()) || (uIndex < unknown.size());) {
+ boolean useBuiltin = false;
+ if (bIndex < builtin.size()) {
+ useBuiltin = uIndex >= unknown.size() || rnd.nextBoolean();
+ }
+
+ if (useBuiltin) {
+ weavedList.add(builtin.get(bIndex));
+ bIndex++;
+ } else if (uIndex < unknown.size()) {
+ weavedList.add(unknown.get(uIndex));
+ uIndex++;
+ }
+ }
+
+ String fullList = GenericUtils.join(weavedList, ',');
+ ParseResult result = BuiltinCompressions.parseCompressionsList(fullList);
+ List<String> parsed = NamedResource.getNameList(result.getParsedFactories());
+ List<String> missing = result.getUnsupportedFactories();
+
+ // makes sure not only that the contents are the same but also the order
+ assertListEquals(fullList + "[parsed]", builtin, parsed);
+ assertListEquals(fullList + "[unsupported]", unknown, missing);
+ }
+ }
+
+ @Test
+ public void testResolveFactoryOnBuiltinValues() {
+ for (NamedFactory<Compression> expected : BuiltinCompressions.VALUES) {
+ String name = expected.getName();
+ NamedFactory<Compression> actual = BuiltinCompressions.resolveFactory(name);
+ assertSame(name, expected, actual);
+ }
+ }
+
+ @Test
+ public void testNotAllowedToRegisterBuiltinFactories() {
+ for (CompressionFactory expected : BuiltinCompressions.VALUES) {
+ try {
+ BuiltinCompressions.registerExtension(expected);
+ fail("Unexpected success for " + expected.getName());
+ } catch (IllegalArgumentException e) {
+ // expected - ignored
+ }
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNotAllowedToOverrideRegisteredFactories() {
+ CompressionFactory expected = Mockito.mock(CompressionFactory.class);
+ Mockito.when(expected.getName()).thenReturn(getCurrentTestName());
+
+ String name = expected.getName();
+ try {
+ for (int index = 1; index <= Byte.SIZE; index++) {
+ BuiltinCompressions.registerExtension(expected);
+ assertEquals("Unexpected success at attempt #" + index, 1, index);
+ }
+ } finally {
+ BuiltinCompressions.unregisterExtension(name);
+ }
+ }
+
+ @Test
+ public void testResolveFactoryOnRegisteredExtension() {
+ CompressionFactory expected = Mockito.mock(CompressionFactory.class);
+ Mockito.when(expected.getName()).thenReturn(getCurrentTestName());
+
+ String name = expected.getName();
+ try {
+ assertNull("Extension already registered", BuiltinCompressions.resolveFactory(name));
+ BuiltinCompressions.registerExtension(expected);
+
+ NamedFactory<Compression> actual = BuiltinCompressions.resolveFactory(name);
+ assertSame("Mismatched resolved instance", expected, actual);
+ } finally {
+ NamedFactory<Compression> actual = BuiltinCompressions.unregisterExtension(name);
+ assertSame("Mismatched unregistered instance", expected, actual);
+ assertNull("Extension not un-registered", BuiltinCompressions.resolveFactory(name));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/TimeValueConfigTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/TimeValueConfigTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/TimeValueConfigTest.java
new file mode 100644
index 0000000..0466d95
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/TimeValueConfigTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.config;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class TimeValueConfigTest extends JUnitTestSupport {
+ public TimeValueConfigTest() {
+ super();
+ }
+
+ @Test
+ public void testDurationOf() {
+ Object[] values = {
+ "600", TimeUnit.SECONDS.toMillis(600L),
+ "10m", TimeUnit.MINUTES.toMillis(10L),
+ "1h30m", TimeUnit.MINUTES.toMillis(90L),
+ "2d", TimeUnit.DAYS.toMillis(2L),
+ "3w", TimeUnit.DAYS.toMillis(3L * 7L)
+ };
+ for (int index = 0; index < values.length; index += 2) {
+ String s = (String) values[index];
+ Number expected = (Number) values[index + 1];
+ long actual = TimeValueConfig.durationOf(s);
+ assertEquals(s, expected.longValue(), actual);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/AuthorizedKeyEntryLoginOptionsParseTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/AuthorizedKeyEntryLoginOptionsParseTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/AuthorizedKeyEntryLoginOptionsParseTest.java
new file mode 100644
index 0000000..d912998
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/AuthorizedKeyEntryLoginOptionsParseTest.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.config.keys;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+public class AuthorizedKeyEntryLoginOptionsParseTest extends JUnitTestSupport {
+ private final String value;
+ private final String loginPart;
+ private final String keyPart;
+ private final Map<String, String> options;
+
+ public AuthorizedKeyEntryLoginOptionsParseTest(String value, String loginPart, String keyPart, Map<String, String> options) {
+ this.value = value;
+ this.loginPart = loginPart;
+ this.keyPart = keyPart;
+ this.options = options;
+ }
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> parameters() {
+ List<Object[]> params = new ArrayList<>();
+ addData(params, "ssh-rsa AAAAB2...19Q==", "john@example.net", "from=\"*.sales.example.net,!pc.sales.example.net\"");
+ addData(params, "ssh-dss AAAAC3...51R==", "example.net", "command=\"dump /home\"", "no-pty", "no-port-forwarding");
+ addData(params, "ssh-dss AAAAB5...21S==", "", "permitopen=\"192.0.2.1:80\"", "permitopen=\"192.0.2.2:25\"");
+ addData(params, "ssh-rsa AAAA...==", "jane@example.net", "tunnel=\"0\"", "command=\"sh /etc/netstart tun0\"");
+ addData(params, "ssh-rsa AAAA1C8...32Tv==", "user@example.net", "!restrict", "command=\"uptime\"");
+ addData(params, "ssh-rsa AAAA1f8...IrrC5==", "user@example.net", "restrict", "!pty", "command=\"nethack\"");
+ return params;
+ }
+
+ private static void addData(List<Object[]> params, String keyData, String comment, String... comps) {
+ StringBuilder sb = new StringBuilder();
+
+ Map<String, String> optionsMap = new HashMap<>();
+ for (String c : comps) {
+ if (sb.length() > 0) {
+ sb.append(',');
+ }
+ sb.append(c);
+
+ int pos = c.indexOf('=');
+ if (pos > 0) {
+ String name = c.substring(0, pos);
+ String value = GenericUtils.stripQuotes(c.substring(pos + 1)).toString();
+ String prev = optionsMap.put(name, value);
+ if (prev != null) {
+ optionsMap.put(name, prev + "," + value);
+ }
+ } else {
+ optionsMap.put(c, Boolean.toString(c.charAt(0) != AuthorizedKeyEntry.BOOLEAN_OPTION_NEGATION_INDICATOR));
+ }
+ }
+
+ int pos = sb.length();
+
+ sb.append(' ').append(keyData);
+ if (GenericUtils.isNotEmpty(comment)) {
+ sb.append(' ').append(comment);
+ }
+
+ String value = sb.toString();
+ params.add(new Object[] {value, value.substring(0, pos), value.substring(pos + 1), optionsMap});
+ }
+
+ @Test
+ public void testResolveEntryComponents() {
+ Map.Entry<String, String> actual = AuthorizedKeyEntry.resolveEntryComponents(value);
+ assertNotNull(value, actual);
+ assertEquals("login(" + value + ")", loginPart, actual.getKey());
+ assertEquals("remainder(" + value + ")", keyPart, actual.getValue());
+ }
+
+ @Test
+ public void testParseLoginOptions() {
+ Map<String, String> parsed = AuthorizedKeyEntry.parseLoginOptions(loginPart);
+ options.forEach((key, expected) -> {
+ String actual = parsed.get(key);
+ assertEquals(key, expected, actual);
+ });
+ assertEquals("Mismatched size", options.size(), parsed.size());
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + value + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java
new file mode 100644
index 0000000..4735846
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.config.keys;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.util.List;
+
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+@Category({ NoIoTestCase.class })
+public class BuiltinIdentitiesTest extends JUnitTestSupport {
+ private final BuiltinIdentities expected;
+
+ public BuiltinIdentitiesTest(BuiltinIdentities expected) {
+ this.expected = expected;
+ }
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> parameters() {
+ return parameterize(BuiltinIdentities.VALUES);
+ }
+
+ @BeforeClass // Dirty hack around the parameterized run
+ public static void testAllConstantsCovered() throws Exception {
+ Field[] fields = BuiltinIdentities.Constants.class.getFields();
+ for (Field f : fields) {
+ int mods = f.getModifiers();
+ if (!Modifier.isStatic(mods)) {
+ continue;
+ }
+
+ if (!Modifier.isFinal(mods)) {
+ continue;
+ }
+
+ Class<?> type = f.getType();
+ if (!String.class.isAssignableFrom(type)) {
+ continue;
+ }
+
+ String name = f.getName();
+ String value = (String) f.get(null);
+ BuiltinIdentities id = BuiltinIdentities.fromName(value);
+ assertNotNull("No match found for field " + name + "=" + value, id);
+ }
+ }
+
+ @Test
+ public void testFromName() {
+ String name = expected.getName();
+ for (int index = 0, count = name.length(); index < count; index++) {
+ assertSame(name, expected, BuiltinIdentities.fromName(name));
+ name = shuffleCase(name);
+ }
+ }
+
+ @Test
+ public void testFromAlgorithm() {
+ String algorithm = expected.getAlgorithm();
+ for (int index = 0, count = algorithm.length(); index < count; index++) {
+ assertSame(algorithm, expected, BuiltinIdentities.fromAlgorithm(algorithm));
+ algorithm = shuffleCase(algorithm);
+ }
+ }
+
+ @Test
+ public void testFromKey() throws GeneralSecurityException {
+ Assume.assumeTrue("Unsupported built-in identity", expected.isSupported());
+ KeyPairGenerator gen = SecurityUtils.getKeyPairGenerator(expected.getAlgorithm());
+ KeyPair kp = gen.generateKeyPair();
+ outputDebugMessage("Checking built-in identity: %s", expected);
+ assertSame(expected + "[pair]", expected, BuiltinIdentities.fromKeyPair(kp));
+ assertSame(expected + "[public]", expected, BuiltinIdentities.fromKey(kp.getPublic()));
+ assertSame(expected + "[private]", expected, BuiltinIdentities.fromKey(kp.getPrivate()));
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyRandomArtTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyRandomArtTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyRandomArtTest.java
new file mode 100644
index 0000000..eedbfe7
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyRandomArtTest.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.config.keys;
+
+import java.security.KeyPair;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.apache.sshd.util.test.CommonTestSupportUtils;
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.AfterClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+@Category({ NoIoTestCase.class })
+public class KeyRandomArtTest extends JUnitTestSupport {
+ private static final Collection<KeyPair> KEYS = new LinkedList<>();
+
+ private final String algorithm;
+ private final int keySize;
+ private final KeyPair keyPair;
+
+ public KeyRandomArtTest(String algorithm, int keySize) throws Exception {
+ this.algorithm = algorithm;
+ this.keySize = keySize;
+ this.keyPair = CommonTestSupportUtils.generateKeyPair(algorithm, keySize);
+ KEYS.add(this.keyPair);
+ }
+
+ @Parameters(name = "algorithm={0}, key-size={1}")
+ public static List<Object[]> parameters() {
+ List<Object[]> params = new ArrayList<>();
+ for (int keySize : RSA_SIZES) {
+ params.add(new Object[]{KeyUtils.RSA_ALGORITHM, keySize});
+ }
+
+ for (int keySize : DSS_SIZES) {
+ params.add(new Object[]{KeyUtils.DSS_ALGORITHM, keySize});
+ }
+
+ if (SecurityUtils.isECCSupported()) {
+ for (ECCurves curve : ECCurves.VALUES) {
+ params.add(new Object[]{KeyUtils.EC_ALGORITHM, curve.getKeySize()});
+ }
+ }
+
+ if (SecurityUtils.isEDDSACurveSupported()) {
+ for (int keySize : ED25519_SIZES) {
+ params.add(new Object[]{SecurityUtils.EDDSA, keySize});
+ }
+ }
+ return params;
+ }
+
+ @AfterClass
+ public static void dumpAllArts() throws Exception {
+ KeyRandomArt.combine(System.out, ' ', () -> KEYS);
+ }
+
+ @Test
+ public void testRandomArtString() throws Exception {
+ KeyRandomArt art = new KeyRandomArt(keyPair.getPublic());
+ assertEquals("Mismatched algorithm", algorithm, art.getAlgorithm());
+ assertEquals("Mismatched key size", keySize, art.getKeySize());
+
+ String s = art.toString();
+ String[] lines = GenericUtils.split(s, '\n');
+ assertEquals("Mismatched lines count", KeyRandomArt.FLDSIZE_Y + 2, lines.length);
+
+ for (int index = 0; index < lines.length; index++) {
+ String l = lines[index];
+ if ((l.length() > 0) && (l.charAt(l.length() - 1) == '\r')) {
+ l = l.substring(0, l.length() - 1);
+ lines[index] = l;
+ }
+ System.out.append('\t').println(l);
+
+ assertTrue("Mismatched line length #" + (index + 1) + ": " + l.length(), l.length() >= (KeyRandomArt.FLDSIZE_X + 2));
+ }
+ }
+}