-
-
Notifications
You must be signed in to change notification settings - Fork 70
Expand file tree
/
Copy pathBasicSSHUserPrivateKeyFIPSTest.java
More file actions
126 lines (113 loc) · 7.23 KB
/
BasicSSHUserPrivateKeyFIPSTest.java
File metadata and controls
126 lines (113 loc) · 7.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package com.cloudbees.jenkins.plugins.sshcredentials.impl;
import com.cloudbees.jenkins.plugins.sshcredentials.SSHUserPrivateKey;
import com.cloudbees.plugins.credentials.CredentialsMatchers;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.CredentialsStore;
import com.cloudbees.plugins.credentials.domains.Domain;
import hudson.ExtensionList;
import hudson.security.ACL;
import hudson.util.FormValidation;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RealJenkinsRule;
import org.jvnet.hudson.test.recipes.LocalData;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.util.Iterator;
import static org.junit.Assert.*;
public class BasicSSHUserPrivateKeyFIPSTest {
@Rule public RealJenkinsRule rule = new RealJenkinsRule().omitPlugins("eddsa-api", "trilead-api")
.javaOptions("-Djenkins.security.FIPS140.COMPLIANCE=true");
@Test
@Issue("JENKINS-73408")
public void nonCompliantKeysLaunchExceptionTest() throws Throwable {
rule.then(BasicSSHUserPrivateKeyFIPSTest::checkNonCompliantKeysLaunchException);
}
private static void checkNonCompliantKeysLaunchException(JenkinsRule r) throws Exception {
new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "no-key", "user",
null, null, "no key provided doesn't throw exceptions");
assertThrows(IllegalArgumentException.class, () -> new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "nopass-openssh-ed25519", "user",
getKey("openssh-ed25519-nopass"), null, "openssh ED25519 with no encryption is not compliant"));
assertThrows(IllegalArgumentException.class, () -> new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "rsa1024", "user",
getKey("rsa1024"), "fipsvalidpassword", "Invalid size key"));
assertThrows(IllegalArgumentException.class, () -> new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "openssh-rsa1024", "user",
getKey("openssh-rsa1024"), "fipsvalidpassword", "Invalid key format"));
new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "ed25519", "user",
getKey("ed25519"), "fipsvalidpassword", "Elliptic curve accepted key");
new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "rsa2048", "user",
getKey("rsa2048"), "fipsvalidpassword", "RSA 2048 accepted key");
assertThrows(IllegalArgumentException.class, () -> new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "rsa1024-short-pass", "user",
getKey("unencrypted-rsa1024"), "password", "password shorter than 14 chatacters is invalid"));
new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "unencrypted-rsa2048", "user",
getKey("unencrypted-rsa2048"), null, "RSA 2048 with no encryption is valid");
assertThrows(IllegalArgumentException.class, () -> new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "rsa2048-wrong-pass", "user",
getKey("rsa2048"), "NOT-fipsvalidpassword", "Wrong password avoids getting size or algorithm"));
assertThrows(IllegalArgumentException.class, () -> new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "dsa2048", "user",
getKey("dsa2048"), "fipsvalidpassword", "DSA is not accepted"));
assertThrows(IllegalArgumentException.class, () -> new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "not-a-key", "user",
getKey("not-a-key"), "fipsvalidpassword", "Provided data is not a key"));
}
@Test
@Issue("JENKINS-73408")
public void invalidKeyIsNotSavedInFIPSModeTest() throws Throwable {
rule.then(BasicSSHUserPrivateKeyFIPSTest::checkInvalidKeyIsNotSavedInFIPSMode);
}
private static void checkInvalidKeyIsNotSavedInFIPSMode(JenkinsRule r) throws Exception {
BasicSSHUserPrivateKey entry = new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "rsa2048", "user", getKey("rsa2048"), "fipsvalidpassword", "RSA 1024 accepted key");
Iterator<CredentialsStore> stores = CredentialsProvider.lookupStores(r.jenkins).iterator();
assertTrue(stores.hasNext());
CredentialsStore store = stores.next();
store.addCredentials(Domain.global(), entry);
store.save();
// Valid key is saved
SSHUserPrivateKey cred = CredentialsMatchers.firstOrNull(
CredentialsProvider.lookupCredentialsInItem(SSHUserPrivateKey.class, null, ACL.SYSTEM2),
CredentialsMatchers.withId("rsa2048"));
assertNotNull(cred);
assertThrows(IllegalArgumentException.class, () -> store.addCredentials(Domain.global(),
new BasicSSHUserPrivateKey(CredentialsScope.GLOBAL, "rsa1024", "user", getKey("rsa1024"), "fipsvalidpassword", "Invalid size key")));
store.save();
// Invalid key threw an exception, so it wasn't saved
cred = CredentialsMatchers.firstOrNull(
CredentialsProvider.lookupCredentialsInItem(SSHUserPrivateKey.class, null, ACL.SYSTEM2),
CredentialsMatchers.withId("rsa1024"));
assertNull(cred);
}
@Test
@LocalData
@Issue("JENKINS-73408")
public void invalidKeysAreRemovedOnStartupTest() throws Throwable {
rule.then(BasicSSHUserPrivateKeyFIPSTest::checkInvalidKeysAreRemovedOnStartup);
}
private static void checkInvalidKeysAreRemovedOnStartup(JenkinsRule r) {
SSHUserPrivateKey cred = CredentialsMatchers.firstOrNull(
CredentialsProvider.lookupCredentialsInItem(SSHUserPrivateKey.class, null, ACL.SYSTEM2),
CredentialsMatchers.withId("valid-rsa-key"));
assertNotNull(cred);
cred = CredentialsMatchers.firstOrNull(
CredentialsProvider.lookupCredentialsInItem(SSHUserPrivateKey.class, null, ACL.SYSTEM2),
CredentialsMatchers.withId("invalid-rsa-key"));
assertNull(cred);
}
@Test
@Issue("JENKINS-73408")
public void formValidationTest() throws Throwable {
rule.then(BasicSSHUserPrivateKeyFIPSTest::checkFormValidation);
}
private static void checkFormValidation(JenkinsRule r) throws Exception {
BasicSSHUserPrivateKey.DirectEntryPrivateKeySource.DescriptorImpl descriptor = ExtensionList.lookupSingleton(BasicSSHUserPrivateKey.DirectEntryPrivateKeySource.DescriptorImpl.class);
FormValidation result = descriptor.doCheckPrivateKey(getKey("rsa2048").getPrivateKey().getPlainText(), "fipsvalidpassword");
assertNull(result.getMessage());
result = descriptor.doCheckPrivateKey(getKey("rsa1024").getPrivateKey().getPlainText(), "fipsvalidpassword");
assertFalse(result.getMessage().isBlank());
}
private static BasicSSHUserPrivateKey.DirectEntryPrivateKeySource getKey(String file) throws Exception {
String keyText = FileUtils.readFileToString(Paths.get("src/test/resources/com/cloudbees/jenkins/plugins/sshcredentials/impl/BasicSSHUserPrivateKeyFIPSTest/nonCompliantKeysLaunchExceptionTest").resolve(file).toFile(), Charset.defaultCharset());
return new BasicSSHUserPrivateKey.DirectEntryPrivateKeySource(keyText);
}
}