Skip to content

Commit

Permalink
Merge pull request #296 from BorisYaoA/Do_not_allows_users_to_authent…
Browse files Browse the repository at this point in the history
…icate_with_short_passwords_in_fips_mode

[JENKINS-73806] Do not allows users to authenticate with short passwords in FIPS mode
  • Loading branch information
fcojfernandez authored Sep 30, 2024
2 parents d3700c2 + 2c10134 commit 387f5b3
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/main/java/hudson/security/LDAPSecurityRealm.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import hudson.util.Secret;
import jenkins.model.IdStrategy;
import jenkins.model.Jenkins;
import jenkins.security.FIPS140;
import jenkins.security.SecurityListener;
import jenkins.security.plugins.ldap.FromGroupSearchLDAPGroupMembershipStrategy;
import jenkins.security.plugins.ldap.LDAPConfiguration;
Expand Down Expand Up @@ -986,6 +987,12 @@ private void addDelegate(AuthenticationManager delegate, String configurationId,
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
try (SetContextClassLoader sccl = new SetContextClassLoader()) {
String password = authentication.getCredentials() instanceof String ? (String) authentication.getCredentials() : null;

Check warning on line 990 in src/main/java/hudson/security/LDAPSecurityRealm.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 990 is only partially covered, one branch is missing
if(FIPS140.useCompliantAlgorithms() && (StringUtils.isBlank(password) || password.length() < 14)) {

Check warning on line 991 in src/main/java/hudson/security/LDAPSecurityRealm.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 991 is only partially covered, one branch is missing
final String message = "When running in FIPS compliance mode, the password must be at least 14 characters long";
LOGGER.warning(message);
throw new org.springframework.ldap.AuthenticationException(new javax.naming.AuthenticationException(message));
}
AuthenticationException lastException = null;
for (ManagerEntry delegate : delegates) {
try {
Expand Down
75 changes: 75 additions & 0 deletions src/test/java/hudson/security/LDAPSecurityRealmWithFIPSTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package hudson.security;

import java.util.logging.Level;

import hudson.util.Secret;
import jenkins.model.IdStrategy;
import jenkins.security.FIPS140;
import jenkins.security.plugins.ldap.FromUserRecordLDAPGroupMembershipStrategy;

import org.htmlunit.FailingHttpStatusCodeException;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.FlagRule;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.LoggerRule;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThrows;

public class LDAPSecurityRealmWithFIPSTest {

@Rule
public JenkinsRule r = new JenkinsRule();
@Rule
public LoggerRule log = new LoggerRule();

@ClassRule
public static FlagRule<String> fipsFlag = FlagRule.systemProperty(FIPS140.class.getName() + ".COMPLIANCE", "true");

@Test
public void ldapAuthenticationWithFIPSTest() throws Exception {
final String server = "localhost";
final String rootDN = "ou=umich,dc=ou.edu";
final String userSearchBase = "cn=users,ou=umich,ou.edu";
final String managerDN = "cn=admin,ou=umich,ou.edu";
final String managerSecret = "secret";
final LDAPSecurityRealm realm = new LDAPSecurityRealm(
server,
rootDN,
userSearchBase,
null,
null,
null,
new FromUserRecordLDAPGroupMembershipStrategy("previousValue"),
managerDN,
Secret.fromString(managerSecret),
false,
false,
null,
null,
null,
null,
IdStrategy.CASE_INSENSITIVE,
IdStrategy.CASE_INSENSITIVE);
r.jenkins.setSecurityRealm(realm);

JenkinsRule.WebClient wc = r.createWebClient();

log.record(LDAPSecurityRealm.class, Level.WARNING).capture(10); // reset
FailingHttpStatusCodeException cannotLogin = assertThrows("Valid password, but expected to fail as there is no such user. Just 401",
FailingHttpStatusCodeException.class,
() -> wc.login("alice", "passwordLongEnoughToBeFIPScompliant"));
assertThat("Invalid user", cannotLogin.getStatusCode(), is(401));

log.record(LDAPSecurityRealm.class, Level.WARNING).capture(10); // reset
cannotLogin = assertThrows("Short password, so the error is different now",
FailingHttpStatusCodeException.class,
() -> wc.login("bob", "shortPassword"));
assertThat("Password invalid in FIPS, not even authenticated", cannotLogin.getStatusCode(), is(500));
assertThat("FIPS message is logged", log, LoggerRule.recorded(Level.WARNING, containsString("the password must be at least 14 characters long")));
}
}

0 comments on commit 387f5b3

Please sign in to comment.