Medium severity5.9NVD Advisory· Published Apr 24, 2017· Updated May 13, 2026
CVE-2016-5016
CVE-2016-5016
Description
Pivotal Cloud Foundry 239 and earlier, UAA (aka User Account and Authentication Server) 3.4.1 and earlier, UAA release 12.2 and earlier, PCF (aka Pivotal Cloud Foundry) Elastic Runtime 1.6.x before 1.6.35, and PCF Elastic Runtime 1.7.x before 1.7.13 does not validate if a certificate is expired.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.cloudfoundry.identity:cloudfoundry-identity-serverMaven | >= 3.0.0, < 3.3.0.3 | 3.3.0.3 |
org.cloudfoundry.identity:cloudfoundry-identity-serverMaven | >= 3.4.0, < 3.4.2 | 3.4.2 |
Patches
30a78612f981cWrap trustmanager in custom trustmanager
11 files changed · +423 −7
scripts/ldap/truststore-with-ldap-certs.jks+0 −0 addedserver.jks+0 −0 addedserver/src/main/java/org/cloudfoundry/identity/uaa/provider/ldap/ProcessLdapProperties.java+10 −3 modified@@ -14,13 +14,16 @@ package org.cloudfoundry.identity.uaa.provider.ldap; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; import java.util.LinkedHashMap; import java.util.Map; public class ProcessLdapProperties { public static final String LDAP_SOCKET_FACTORY = "java.naming.ldap.factory.socket"; public static final String SKIP_SSL_VERIFICATION_SOCKET_FACTORY = "org.apache.directory.api.util.DummySSLSocketFactory"; + public static final String EXPIRY_CHECKING_SOCKET_FACTORY = "org.cloudfoundry.identity.uaa.security.LdapSocketFactory"; private boolean disableSslVerification; private String baseUrl; @@ -30,10 +33,14 @@ public ProcessLdapProperties(String baseUrl, boolean disableSslVerification) { this.disableSslVerification = disableSslVerification; } - public Map process(Map map) { + public Map process(Map map) throws KeyManagementException, NoSuchAlgorithmException { Map result = new LinkedHashMap(map); - if (isDisableSslVerification() && isLdapsUrl()) { - result.put(LDAP_SOCKET_FACTORY, SKIP_SSL_VERIFICATION_SOCKET_FACTORY); + if(isLdapsUrl()) { + if (isDisableSslVerification()) { + result.put(LDAP_SOCKET_FACTORY, SKIP_SSL_VERIFICATION_SOCKET_FACTORY); + } else { + result.put(LDAP_SOCKET_FACTORY, EXPIRY_CHECKING_SOCKET_FACTORY); + } } return result; }
server/src/main/java/org/cloudfoundry/identity/uaa/security/LdapSocketFactory.java+72 −0 added@@ -0,0 +1,72 @@ +package org.cloudfoundry.identity.uaa.security; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.security.SecureRandom; + +public class LdapSocketFactory extends SSLSocketFactory { + + private static SocketFactory instance; + private SSLSocketFactory delegate; + + public static SocketFactory getDefault() { + if(instance == null) { + instance = new LdapSocketFactory(); + } + + return instance; + } + + public LdapSocketFactory() { + try { + X509TrustManager trustManager = new X509ExpiryCheckingTrustManager(); + TrustManager[] tma = new TrustManager[]{trustManager}; + SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, tma, new SecureRandom()); + this.delegate = sc.getSocketFactory(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public String[] getDefaultCipherSuites() { + return delegate.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException { + return delegate.createSocket(socket, s, i, b); + } + + @Override + public Socket createSocket(String s, int i) throws IOException{ + return delegate.createSocket(s, i); + } + + @Override + public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException { + return delegate.createSocket(s, i, inetAddress, i1); + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i) throws IOException { + return delegate.createSocket(inetAddress, i); + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException { + return delegate.createSocket(inetAddress, i, inetAddress1, i1); + } +}
server/src/main/java/org/cloudfoundry/identity/uaa/security/X509ExpiryCheckingTrustManager.java+65 −0 added@@ -0,0 +1,65 @@ +package org.cloudfoundry.identity.uaa.security; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +public class X509ExpiryCheckingTrustManager implements X509TrustManager { + + private X509TrustManager delegate; + + public X509ExpiryCheckingTrustManager() { + try { + TrustManagerFactory tmf; + tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init((KeyStore) null); + X509TrustManager x509Tm = null; + for (TrustManager tm : tmf.getTrustManagers()) { + if (tm instanceof X509TrustManager) { + x509Tm = (X509TrustManager) tm; + break; + } + } + delegate = x509Tm; + } catch (NoSuchAlgorithmException | KeyStoreException e) { + } + } + + protected void setDelegate(X509TrustManager delegate) { + this.delegate = delegate; + } + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + if (delegate == null) { + throw new CertificateException(); + } else { + delegate.checkClientTrusted(x509Certificates, s); + } + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + if (delegate == null) { + throw new CertificateException(); + } else { + delegate.checkServerTrusted(x509Certificates, s); + } + for (X509Certificate certificate : x509Certificates) { + certificate.checkValidity(); + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + if (delegate != null) { + return delegate.getAcceptedIssuers(); + } + return new X509Certificate[0]; + } +}
server/src/test/java/org/cloudfoundry/identity/uaa/provider/ldap/ProcessLdapPropertiesTest.java+12 −1 modified@@ -35,4 +35,15 @@ public void testProcess() throws Exception { process.setBaseUrl("ldaps://localhost:636"); assertEquals(ProcessLdapProperties.SKIP_SSL_VERIFICATION_SOCKET_FACTORY, process.process(properties).get(LDAP_SOCKET_FACTORY)); } -} \ No newline at end of file + + @Test + public void process_whenSslValidationIsEnabled() throws Exception { + Map<String,String> properties = new HashMap<>(); + ProcessLdapProperties process = new ProcessLdapProperties("ldap://localhost:389", false); + assertNull(process.process(properties).get(LDAP_SOCKET_FACTORY)); + process.setDisableSslVerification(false); + assertNull(process.process(properties).get(LDAP_SOCKET_FACTORY)); + process.setBaseUrl("ldaps://localhost:636"); + assertEquals(ProcessLdapProperties.EXPIRY_CHECKING_SOCKET_FACTORY, process.process(properties).get(LDAP_SOCKET_FACTORY)); + } +}
server/src/test/java/org/cloudfoundry/identity/uaa/security/LdapSocketFactoryTest.java+7 −0 added@@ -0,0 +1,7 @@ +package org.cloudfoundry.identity.uaa.security; + +import static org.junit.Assert.*; + +public class LdapSocketFactoryTest { + +}
server/src/test/java/org/cloudfoundry/identity/uaa/security/X509ExpiryCheckingTrustManagerTest.java+59 −0 added@@ -0,0 +1,59 @@ +package org.cloudfoundry.identity.uaa.security; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.security.saml.trust.X509TrustManager; + +import java.security.cert.CertificateExpiredException; +import java.security.cert.X509Certificate; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; + +public class X509ExpiryCheckingTrustManagerTest { + + @Test + public void checkServerTrusted_throwsExceptionWhenCertIsExpired() throws Exception { + X509ExpiryCheckingTrustManager manager = new X509ExpiryCheckingTrustManager(); + X509TrustManager mockedDelegate = Mockito.mock(X509TrustManager.class); + manager.setDelegate(mockedDelegate); + X509Certificate certificate = Mockito.mock(X509Certificate.class); + X509Certificate[] x509Certificates = {certificate}; + + doNothing().when(mockedDelegate).checkServerTrusted(x509Certificates, "string"); + doThrow(new CertificateExpiredException()).when(certificate).checkValidity(); + try { + manager.checkServerTrusted(x509Certificates,"string"); + Assert.fail(); + } catch (CertificateExpiredException e) { + verify(mockedDelegate).checkServerTrusted(x509Certificates, "string"); + verify(certificate).checkValidity(); + } + } + + @Test + public void checkClientTrusted_callsDelegate() throws Exception { + X509ExpiryCheckingTrustManager manager = new X509ExpiryCheckingTrustManager(); + X509TrustManager mockedDelegate = Mockito.mock(X509TrustManager.class); + manager.setDelegate(mockedDelegate); + + X509Certificate certificate = Mockito.mock(X509Certificate.class); + X509Certificate[] x509Certificates = {certificate}; + + doNothing().when(mockedDelegate).checkClientTrusted(x509Certificates, "string"); + manager.checkClientTrusted(x509Certificates, "string"); + verify(mockedDelegate).checkClientTrusted(x509Certificates, "string"); + } + + @Test + public void checkAcceptedIssuers_callsDelegate() throws Exception { + X509ExpiryCheckingTrustManager manager = new X509ExpiryCheckingTrustManager(); + X509TrustManager mockedDelegate = Mockito.mock(X509TrustManager.class); + manager.setDelegate(mockedDelegate); + + manager.getAcceptedIssuers(); + verify(mockedDelegate).getAcceptedIssuers(); + } +}
.travis.yml+1 −1 modified@@ -41,7 +41,7 @@ install: fi - mkdir -p $HOME/build/cloudfoundry/uaa/uaa/build/reports/tests script: -- ./gradlew -Dspring.profiles.active=$TESTENV jacocoRootReport +- ./gradlew -Dspring.profiles.active=$TESTENV -Djavax.net.ssl.trustStore=$TRAVIS_BUILD_DIR/scripts/ldap/truststore-with-ldap-certs.jks -Djavax.net.ssl.trustStoreType=JKS jacocoRootReport after_success: - ./gradlew coveralls - for i in $(find $HOME/build/cloudfoundry/uaa/ -name reports -type d); do rm -rf $i; done
uaa/src/main/resources/uaa.yml+2 −2 modified@@ -1,8 +1,8 @@ -# Configuration in this file is overridden by an external file +# Configuration in this file ixs overridden by an external file # if any of these exist: # [$UAA_CONFIG_URL, $UAA_CONFIG_PATH/uaa.yml, $CLOUD_FOUNDRY_CONFIG_PATH/uaa.yml] -#spring_profiles: mysql,default +#spring_profiles: mysql,default,ldap #spring_profiles: postgresql,default #spring_profiles: ldap,default,hsqldb #spring_profiles: saml
uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/LdapLoginIT.java+195 −0 added@@ -0,0 +1,195 @@ +package org.cloudfoundry.identity.uaa.integration.feature; + +import org.cloudfoundry.identity.uaa.ServerRunning; +import org.cloudfoundry.identity.uaa.constants.OriginKeys; +import org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils; +import org.cloudfoundry.identity.uaa.integration.util.ScreenshotOnFail; +import org.cloudfoundry.identity.uaa.login.test.LoginServerClassRunner; +import org.cloudfoundry.identity.uaa.provider.IdentityProvider; +import org.cloudfoundry.identity.uaa.provider.LdapIdentityProviderDefinition; +import org.cloudfoundry.identity.uaa.scim.ScimUser; +import org.cloudfoundry.identity.uaa.test.UaaTestAccounts; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.oauth2.client.test.TestAccounts; +import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +import static org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils.doesSupportZoneDNS; +import static org.junit.Assert.assertThat; +import static org.junit.Assume.assumeTrue; + +@RunWith(LoginServerClassRunner.class) +@ContextConfiguration(classes = DefaultIntegrationTestConfig.class) +public class LdapLoginIT { + + + + @Autowired + @Rule + public IntegrationTestRule integrationTestRule; + + @Rule + public ScreenshotOnFail screenShootRule = new ScreenshotOnFail(); + + @Autowired + RestOperations restOperations; + + @Autowired + WebDriver webDriver; + + @Value("${integration.test.base_url}") + String baseUrl; + + @Autowired + TestClient testClient; + + ServerRunning serverRunning = ServerRunning.isRunning(); + + + @Before + public void clearWebDriverOfCookies() throws Exception { + screenShootRule.setWebDriver(webDriver); + webDriver.get(baseUrl + "/logout.do"); + webDriver.get(baseUrl.replace("localhost", "testzone1.localhost") + "/logout.do"); + webDriver.get(baseUrl.replace("localhost", "testzone2.localhost") + "/logout.do"); + webDriver.manage().deleteAllCookies(); + } + + @Test + public void ldapLogin_withValidSelfSignedCert() throws Exception { + //ensure we are able to resolve DNS for hostname testzone2.localhost + assumeTrue("Expected testzone1/2/3/4.localhost to resolve to 127.0.0.1", doesSupportZoneDNS()); + String zoneId = "testzone2"; + String zoneUrl = baseUrl.replace("localhost", "testzone2.localhost"); + + //identity client token + RestTemplate identityClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[]{"zones.write", "zones.read", "scim.zones"}, "identity", "identitysecret") + ); + //admin client token - to create users + RestTemplate adminClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[0], "admin", "adminsecret") + ); + //create the zone + IntegrationTestUtils.createZoneOrUpdateSubdomain(identityClient, baseUrl, zoneId, zoneId); + + //create a zone admin user + String email = new RandomValueStringGenerator().generate() +"@samltesting.org"; + ScimUser user = IntegrationTestUtils.createUser(adminClient, baseUrl,email ,"firstname", "lastname", email, true); + IntegrationTestUtils.makeZoneAdmin(identityClient, baseUrl, user.getId(), zoneId); + + //get the zone admin token + String zoneAdminToken = + IntegrationTestUtils.getAuthorizationCodeToken(serverRunning, + UaaTestAccounts.standard(serverRunning), + "identity", + "identitysecret", + email, + "secr3T"); + + LdapIdentityProviderDefinition ldapIdentityProviderDefinition = LdapIdentityProviderDefinition.searchAndBindMapGroupToScopes( + "ldaps://52.87.212.253:636/", + "cn=admin,dc=test,dc=com", + "password", + "dc=test,dc=com", + "cn={0}", + "ou=scopes,dc=test,dc=com", + "member={0}", + "mail", + null, + false, + true, + true, + 100, + false); + + IdentityProvider provider = new IdentityProvider(); + provider.setIdentityZoneId(zoneId); + provider.setType(OriginKeys.LDAP); + provider.setActive(true); + provider.setConfig(ldapIdentityProviderDefinition); + provider.setOriginKey(OriginKeys.LDAP); + provider.setName("simplesamlphp for uaa"); + provider = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken,baseUrl,provider); + + webDriver.get(zoneUrl + "/login"); + webDriver.findElement(By.name("username")).sendKeys("marissa4"); + webDriver.findElement(By.name("password")).sendKeys("ldap4"); + webDriver.findElement(By.xpath("//input[@value='Sign in']")).click(); + assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString("Where to")); + } + + @Test + public void ldapLogin_withExpiredSelfSignedCert() throws Exception { + //ensure we are able to resolve DNS for hostname testzone1.localhost + assumeTrue("Expected testzone1/2/3/4.localhost to resolve to 127.0.0.1", doesSupportZoneDNS()); + String zoneId = "testzone1"; + String zoneUrl = baseUrl.replace("localhost", "testzone1.localhost"); + + //identity client token + RestTemplate identityClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[]{"zones.write", "zones.read", "scim.zones"}, "identity", "identitysecret") + ); + //admin client token - to create users + RestTemplate adminClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[0], "admin", "adminsecret") + ); + //create the zone + IntegrationTestUtils.createZoneOrUpdateSubdomain(identityClient, baseUrl, zoneId, zoneId); + + //create a zone admin user + String email = new RandomValueStringGenerator().generate() +"@samltesting.org"; + ScimUser user = IntegrationTestUtils.createUser(adminClient, baseUrl,email ,"firstname", "lastname", email, true); + IntegrationTestUtils.makeZoneAdmin(identityClient, baseUrl, user.getId(), zoneId); + + //get the zone admin token + String zoneAdminToken = + IntegrationTestUtils.getAuthorizationCodeToken(serverRunning, + UaaTestAccounts.standard(serverRunning), + "identity", + "identitysecret", + email, + "secr3T"); + + LdapIdentityProviderDefinition ldapIdentityProviderDefinition = LdapIdentityProviderDefinition.searchAndBindMapGroupToScopes( + "ldaps://52.20.5.106:636/", + "cn=admin,dc=test,dc=com", + "password", + "dc=test,dc=com", + "cn={0}", + "ou=scopes,dc=test,dc=com", + "member={0}", + "mail", + null, + false, + true, + true, + 100, + false); + + IdentityProvider provider = new IdentityProvider(); + provider.setIdentityZoneId(zoneId); + provider.setType(OriginKeys.LDAP); + provider.setActive(true); + provider.setConfig(ldapIdentityProviderDefinition); + provider.setOriginKey(OriginKeys.LDAP); + provider.setName("simplesamlphp for uaa"); + provider = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken,baseUrl,provider); + + webDriver.get(zoneUrl + "/login"); + webDriver.findElement(By.name("username")).sendKeys("marissa4"); + webDriver.findElement(By.name("password")).sendKeys("ldap4"); + webDriver.findElement(By.xpath("//input[@value='Sign in']")).click(); + assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString("Welcome to The Twiglet Zone[" + zoneId + "]!")); + } +}
bc91ccd2029eWrap trustmanager in custom trustmanager
11 files changed · +423 −7
scripts/ldap/truststore-with-ldap-certs.jks+0 −0 addedserver.jks+0 −0 addedserver/src/main/java/org/cloudfoundry/identity/uaa/provider/ldap/ProcessLdapProperties.java+10 −3 modified@@ -14,13 +14,16 @@ package org.cloudfoundry.identity.uaa.provider.ldap; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; import java.util.LinkedHashMap; import java.util.Map; public class ProcessLdapProperties { public static final String LDAP_SOCKET_FACTORY = "java.naming.ldap.factory.socket"; public static final String SKIP_SSL_VERIFICATION_SOCKET_FACTORY = "org.apache.directory.api.util.DummySSLSocketFactory"; + public static final String EXPIRY_CHECKING_SOCKET_FACTORY = "org.cloudfoundry.identity.uaa.security.LdapSocketFactory"; private boolean disableSslVerification; private String baseUrl; @@ -30,10 +33,14 @@ public ProcessLdapProperties(String baseUrl, boolean disableSslVerification) { this.disableSslVerification = disableSslVerification; } - public Map process(Map map) { + public Map process(Map map) throws KeyManagementException, NoSuchAlgorithmException { Map result = new LinkedHashMap(map); - if (isDisableSslVerification() && isLdapsUrl()) { - result.put(LDAP_SOCKET_FACTORY, SKIP_SSL_VERIFICATION_SOCKET_FACTORY); + if(isLdapsUrl()) { + if (isDisableSslVerification()) { + result.put(LDAP_SOCKET_FACTORY, SKIP_SSL_VERIFICATION_SOCKET_FACTORY); + } else { + result.put(LDAP_SOCKET_FACTORY, EXPIRY_CHECKING_SOCKET_FACTORY); + } } return result; }
server/src/main/java/org/cloudfoundry/identity/uaa/security/LdapSocketFactory.java+72 −0 added@@ -0,0 +1,72 @@ +package org.cloudfoundry.identity.uaa.security; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.security.SecureRandom; + +public class LdapSocketFactory extends SSLSocketFactory { + + private static SocketFactory instance; + private SSLSocketFactory delegate; + + public static SocketFactory getDefault() { + if(instance == null) { + instance = new LdapSocketFactory(); + } + + return instance; + } + + public LdapSocketFactory() { + try { + X509TrustManager trustManager = new X509ExpiryCheckingTrustManager(); + TrustManager[] tma = new TrustManager[]{trustManager}; + SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, tma, new SecureRandom()); + this.delegate = sc.getSocketFactory(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public String[] getDefaultCipherSuites() { + return delegate.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException { + return delegate.createSocket(socket, s, i, b); + } + + @Override + public Socket createSocket(String s, int i) throws IOException{ + return delegate.createSocket(s, i); + } + + @Override + public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException { + return delegate.createSocket(s, i, inetAddress, i1); + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i) throws IOException { + return delegate.createSocket(inetAddress, i); + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException { + return delegate.createSocket(inetAddress, i, inetAddress1, i1); + } +}
server/src/main/java/org/cloudfoundry/identity/uaa/security/X509ExpiryCheckingTrustManager.java+65 −0 added@@ -0,0 +1,65 @@ +package org.cloudfoundry.identity.uaa.security; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +public class X509ExpiryCheckingTrustManager implements X509TrustManager { + + private X509TrustManager delegate; + + public X509ExpiryCheckingTrustManager() { + try { + TrustManagerFactory tmf; + tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init((KeyStore) null); + X509TrustManager x509Tm = null; + for (TrustManager tm : tmf.getTrustManagers()) { + if (tm instanceof X509TrustManager) { + x509Tm = (X509TrustManager) tm; + break; + } + } + delegate = x509Tm; + } catch (NoSuchAlgorithmException | KeyStoreException e) { + } + } + + protected void setDelegate(X509TrustManager delegate) { + this.delegate = delegate; + } + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + if (delegate == null) { + throw new CertificateException(); + } else { + delegate.checkClientTrusted(x509Certificates, s); + } + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + if (delegate == null) { + throw new CertificateException(); + } else { + delegate.checkServerTrusted(x509Certificates, s); + } + for (X509Certificate certificate : x509Certificates) { + certificate.checkValidity(); + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + if (delegate != null) { + return delegate.getAcceptedIssuers(); + } + return new X509Certificate[0]; + } +}
server/src/test/java/org/cloudfoundry/identity/uaa/provider/ldap/ProcessLdapPropertiesTest.java+12 −1 modified@@ -35,4 +35,15 @@ public void testProcess() throws Exception { process.setBaseUrl("ldaps://localhost:636"); assertEquals(ProcessLdapProperties.SKIP_SSL_VERIFICATION_SOCKET_FACTORY, process.process(properties).get(LDAP_SOCKET_FACTORY)); } -} \ No newline at end of file + + @Test + public void process_whenSslValidationIsEnabled() throws Exception { + Map<String,String> properties = new HashMap<>(); + ProcessLdapProperties process = new ProcessLdapProperties("ldap://localhost:389", false); + assertNull(process.process(properties).get(LDAP_SOCKET_FACTORY)); + process.setDisableSslVerification(false); + assertNull(process.process(properties).get(LDAP_SOCKET_FACTORY)); + process.setBaseUrl("ldaps://localhost:636"); + assertEquals(ProcessLdapProperties.EXPIRY_CHECKING_SOCKET_FACTORY, process.process(properties).get(LDAP_SOCKET_FACTORY)); + } +}
server/src/test/java/org/cloudfoundry/identity/uaa/security/LdapSocketFactoryTest.java+7 −0 added@@ -0,0 +1,7 @@ +package org.cloudfoundry.identity.uaa.security; + +import static org.junit.Assert.*; + +public class LdapSocketFactoryTest { + +}
server/src/test/java/org/cloudfoundry/identity/uaa/security/X509ExpiryCheckingTrustManagerTest.java+59 −0 added@@ -0,0 +1,59 @@ +package org.cloudfoundry.identity.uaa.security; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.security.saml.trust.X509TrustManager; + +import java.security.cert.CertificateExpiredException; +import java.security.cert.X509Certificate; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; + +public class X509ExpiryCheckingTrustManagerTest { + + @Test + public void checkServerTrusted_throwsExceptionWhenCertIsExpired() throws Exception { + X509ExpiryCheckingTrustManager manager = new X509ExpiryCheckingTrustManager(); + X509TrustManager mockedDelegate = Mockito.mock(X509TrustManager.class); + manager.setDelegate(mockedDelegate); + X509Certificate certificate = Mockito.mock(X509Certificate.class); + X509Certificate[] x509Certificates = {certificate}; + + doNothing().when(mockedDelegate).checkServerTrusted(x509Certificates, "string"); + doThrow(new CertificateExpiredException()).when(certificate).checkValidity(); + try { + manager.checkServerTrusted(x509Certificates,"string"); + Assert.fail(); + } catch (CertificateExpiredException e) { + verify(mockedDelegate).checkServerTrusted(x509Certificates, "string"); + verify(certificate).checkValidity(); + } + } + + @Test + public void checkClientTrusted_callsDelegate() throws Exception { + X509ExpiryCheckingTrustManager manager = new X509ExpiryCheckingTrustManager(); + X509TrustManager mockedDelegate = Mockito.mock(X509TrustManager.class); + manager.setDelegate(mockedDelegate); + + X509Certificate certificate = Mockito.mock(X509Certificate.class); + X509Certificate[] x509Certificates = {certificate}; + + doNothing().when(mockedDelegate).checkClientTrusted(x509Certificates, "string"); + manager.checkClientTrusted(x509Certificates, "string"); + verify(mockedDelegate).checkClientTrusted(x509Certificates, "string"); + } + + @Test + public void checkAcceptedIssuers_callsDelegate() throws Exception { + X509ExpiryCheckingTrustManager manager = new X509ExpiryCheckingTrustManager(); + X509TrustManager mockedDelegate = Mockito.mock(X509TrustManager.class); + manager.setDelegate(mockedDelegate); + + manager.getAcceptedIssuers(); + verify(mockedDelegate).getAcceptedIssuers(); + } +}
.travis.yml+1 −1 modified@@ -41,7 +41,7 @@ install: fi - mkdir -p $HOME/build/cloudfoundry/uaa/uaa/build/reports/tests script: -- ./gradlew -Dspring.profiles.active=$TESTENV jacocoRootReport +- ./gradlew -Dspring.profiles.active=$TESTENV -Djavax.net.ssl.trustStore=$TRAVIS_BUILD_DIR/scripts/ldap/truststore-with-ldap-certs.jks -Djavax.net.ssl.trustStoreType=JKS jacocoRootReport after_success: - ./gradlew coveralls - for i in $(find $HOME/build/cloudfoundry/uaa/ -name reports -type d); do rm -rf $i; done
uaa/src/main/resources/uaa.yml+2 −2 modified@@ -1,8 +1,8 @@ -# Configuration in this file is overridden by an external file +# Configuration in this file ixs overridden by an external file # if any of these exist: # [$UAA_CONFIG_URL, $UAA_CONFIG_PATH/uaa.yml, $CLOUD_FOUNDRY_CONFIG_PATH/uaa.yml] -#spring_profiles: mysql,default +#spring_profiles: mysql,default,ldap #spring_profiles: postgresql,default #spring_profiles: ldap,default,hsqldb #spring_profiles: saml
uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/LdapLoginIT.java+195 −0 added@@ -0,0 +1,195 @@ +package org.cloudfoundry.identity.uaa.integration.feature; + +import org.cloudfoundry.identity.uaa.ServerRunning; +import org.cloudfoundry.identity.uaa.constants.OriginKeys; +import org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils; +import org.cloudfoundry.identity.uaa.integration.util.ScreenshotOnFail; +import org.cloudfoundry.identity.uaa.login.test.LoginServerClassRunner; +import org.cloudfoundry.identity.uaa.provider.IdentityProvider; +import org.cloudfoundry.identity.uaa.provider.LdapIdentityProviderDefinition; +import org.cloudfoundry.identity.uaa.scim.ScimUser; +import org.cloudfoundry.identity.uaa.test.UaaTestAccounts; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.oauth2.client.test.TestAccounts; +import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +import static org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils.doesSupportZoneDNS; +import static org.junit.Assert.assertThat; +import static org.junit.Assume.assumeTrue; + +@RunWith(LoginServerClassRunner.class) +@ContextConfiguration(classes = DefaultIntegrationTestConfig.class) +public class LdapLoginIT { + + + + @Autowired + @Rule + public IntegrationTestRule integrationTestRule; + + @Rule + public ScreenshotOnFail screenShootRule = new ScreenshotOnFail(); + + @Autowired + RestOperations restOperations; + + @Autowired + WebDriver webDriver; + + @Value("${integration.test.base_url}") + String baseUrl; + + @Autowired + TestClient testClient; + + ServerRunning serverRunning = ServerRunning.isRunning(); + + + @Before + public void clearWebDriverOfCookies() throws Exception { + screenShootRule.setWebDriver(webDriver); + webDriver.get(baseUrl + "/logout.do"); + webDriver.get(baseUrl.replace("localhost", "testzone1.localhost") + "/logout.do"); + webDriver.get(baseUrl.replace("localhost", "testzone2.localhost") + "/logout.do"); + webDriver.manage().deleteAllCookies(); + } + + @Test + public void ldapLogin_withValidSelfSignedCert() throws Exception { + //ensure we are able to resolve DNS for hostname testzone2.localhost + assumeTrue("Expected testzone1/2/3/4.localhost to resolve to 127.0.0.1", doesSupportZoneDNS()); + String zoneId = "testzone2"; + String zoneUrl = baseUrl.replace("localhost", "testzone2.localhost"); + + //identity client token + RestTemplate identityClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[]{"zones.write", "zones.read", "scim.zones"}, "identity", "identitysecret") + ); + //admin client token - to create users + RestTemplate adminClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[0], "admin", "adminsecret") + ); + //create the zone + IntegrationTestUtils.createZoneOrUpdateSubdomain(identityClient, baseUrl, zoneId, zoneId); + + //create a zone admin user + String email = new RandomValueStringGenerator().generate() +"@samltesting.org"; + ScimUser user = IntegrationTestUtils.createUser(adminClient, baseUrl,email ,"firstname", "lastname", email, true); + IntegrationTestUtils.makeZoneAdmin(identityClient, baseUrl, user.getId(), zoneId); + + //get the zone admin token + String zoneAdminToken = + IntegrationTestUtils.getAuthorizationCodeToken(serverRunning, + UaaTestAccounts.standard(serverRunning), + "identity", + "identitysecret", + email, + "secr3T"); + + LdapIdentityProviderDefinition ldapIdentityProviderDefinition = LdapIdentityProviderDefinition.searchAndBindMapGroupToScopes( + "ldaps://52.87.212.253:636/", + "cn=admin,dc=test,dc=com", + "password", + "dc=test,dc=com", + "cn={0}", + "ou=scopes,dc=test,dc=com", + "member={0}", + "mail", + null, + false, + true, + true, + 100, + false); + + IdentityProvider provider = new IdentityProvider(); + provider.setIdentityZoneId(zoneId); + provider.setType(OriginKeys.LDAP); + provider.setActive(true); + provider.setConfig(ldapIdentityProviderDefinition); + provider.setOriginKey(OriginKeys.LDAP); + provider.setName("simplesamlphp for uaa"); + provider = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken,baseUrl,provider); + + webDriver.get(zoneUrl + "/login"); + webDriver.findElement(By.name("username")).sendKeys("marissa4"); + webDriver.findElement(By.name("password")).sendKeys("ldap4"); + webDriver.findElement(By.xpath("//input[@value='Sign in']")).click(); + assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString("Where to")); + } + + @Test + public void ldapLogin_withExpiredSelfSignedCert() throws Exception { + //ensure we are able to resolve DNS for hostname testzone1.localhost + assumeTrue("Expected testzone1/2/3/4.localhost to resolve to 127.0.0.1", doesSupportZoneDNS()); + String zoneId = "testzone1"; + String zoneUrl = baseUrl.replace("localhost", "testzone1.localhost"); + + //identity client token + RestTemplate identityClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[]{"zones.write", "zones.read", "scim.zones"}, "identity", "identitysecret") + ); + //admin client token - to create users + RestTemplate adminClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[0], "admin", "adminsecret") + ); + //create the zone + IntegrationTestUtils.createZoneOrUpdateSubdomain(identityClient, baseUrl, zoneId, zoneId); + + //create a zone admin user + String email = new RandomValueStringGenerator().generate() +"@samltesting.org"; + ScimUser user = IntegrationTestUtils.createUser(adminClient, baseUrl,email ,"firstname", "lastname", email, true); + IntegrationTestUtils.makeZoneAdmin(identityClient, baseUrl, user.getId(), zoneId); + + //get the zone admin token + String zoneAdminToken = + IntegrationTestUtils.getAuthorizationCodeToken(serverRunning, + UaaTestAccounts.standard(serverRunning), + "identity", + "identitysecret", + email, + "secr3T"); + + LdapIdentityProviderDefinition ldapIdentityProviderDefinition = LdapIdentityProviderDefinition.searchAndBindMapGroupToScopes( + "ldaps://52.20.5.106:636/", + "cn=admin,dc=test,dc=com", + "password", + "dc=test,dc=com", + "cn={0}", + "ou=scopes,dc=test,dc=com", + "member={0}", + "mail", + null, + false, + true, + true, + 100, + false); + + IdentityProvider provider = new IdentityProvider(); + provider.setIdentityZoneId(zoneId); + provider.setType(OriginKeys.LDAP); + provider.setActive(true); + provider.setConfig(ldapIdentityProviderDefinition); + provider.setOriginKey(OriginKeys.LDAP); + provider.setName("simplesamlphp for uaa"); + provider = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken,baseUrl,provider); + + webDriver.get(zoneUrl + "/login"); + webDriver.findElement(By.name("username")).sendKeys("marissa4"); + webDriver.findElement(By.name("password")).sendKeys("ldap4"); + webDriver.findElement(By.xpath("//input[@value='Sign in']")).click(); + assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString("Welcome to The Twiglet Zone[" + zoneId + "]!")); + } +}
f97049df1c6cWrap trustmanager in custom trustmanager
11 files changed · +423 −7
scripts/ldap/truststore-with-ldap-certs.jks+0 −0 addedserver.jks+0 −0 addedserver/src/main/java/org/cloudfoundry/identity/uaa/provider/ldap/ProcessLdapProperties.java+10 −3 modified@@ -14,13 +14,16 @@ package org.cloudfoundry.identity.uaa.provider.ldap; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; import java.util.LinkedHashMap; import java.util.Map; public class ProcessLdapProperties { public static final String LDAP_SOCKET_FACTORY = "java.naming.ldap.factory.socket"; public static final String SKIP_SSL_VERIFICATION_SOCKET_FACTORY = "org.apache.directory.api.util.DummySSLSocketFactory"; + public static final String EXPIRY_CHECKING_SOCKET_FACTORY = "org.cloudfoundry.identity.uaa.security.LdapSocketFactory"; private boolean disableSslVerification; private String baseUrl; @@ -30,10 +33,14 @@ public ProcessLdapProperties(String baseUrl, boolean disableSslVerification) { this.disableSslVerification = disableSslVerification; } - public Map process(Map map) { + public Map process(Map map) throws KeyManagementException, NoSuchAlgorithmException { Map result = new LinkedHashMap(map); - if (isDisableSslVerification() && isLdapsUrl()) { - result.put(LDAP_SOCKET_FACTORY, SKIP_SSL_VERIFICATION_SOCKET_FACTORY); + if(isLdapsUrl()) { + if (isDisableSslVerification()) { + result.put(LDAP_SOCKET_FACTORY, SKIP_SSL_VERIFICATION_SOCKET_FACTORY); + } else { + result.put(LDAP_SOCKET_FACTORY, EXPIRY_CHECKING_SOCKET_FACTORY); + } } return result; }
server/src/main/java/org/cloudfoundry/identity/uaa/security/LdapSocketFactory.java+72 −0 added@@ -0,0 +1,72 @@ +package org.cloudfoundry.identity.uaa.security; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.security.SecureRandom; + +public class LdapSocketFactory extends SSLSocketFactory { + + private static SocketFactory instance; + private SSLSocketFactory delegate; + + public static SocketFactory getDefault() { + if(instance == null) { + instance = new LdapSocketFactory(); + } + + return instance; + } + + public LdapSocketFactory() { + try { + X509TrustManager trustManager = new X509ExpiryCheckingTrustManager(); + TrustManager[] tma = new TrustManager[]{trustManager}; + SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, tma, new SecureRandom()); + this.delegate = sc.getSocketFactory(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public String[] getDefaultCipherSuites() { + return delegate.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException { + return delegate.createSocket(socket, s, i, b); + } + + @Override + public Socket createSocket(String s, int i) throws IOException{ + return delegate.createSocket(s, i); + } + + @Override + public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException { + return delegate.createSocket(s, i, inetAddress, i1); + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i) throws IOException { + return delegate.createSocket(inetAddress, i); + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException { + return delegate.createSocket(inetAddress, i, inetAddress1, i1); + } +}
server/src/main/java/org/cloudfoundry/identity/uaa/security/X509ExpiryCheckingTrustManager.java+65 −0 added@@ -0,0 +1,65 @@ +package org.cloudfoundry.identity.uaa.security; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +public class X509ExpiryCheckingTrustManager implements X509TrustManager { + + private X509TrustManager delegate; + + public X509ExpiryCheckingTrustManager() { + try { + TrustManagerFactory tmf; + tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init((KeyStore) null); + X509TrustManager x509Tm = null; + for (TrustManager tm : tmf.getTrustManagers()) { + if (tm instanceof X509TrustManager) { + x509Tm = (X509TrustManager) tm; + break; + } + } + delegate = x509Tm; + } catch (NoSuchAlgorithmException | KeyStoreException e) { + } + } + + protected void setDelegate(X509TrustManager delegate) { + this.delegate = delegate; + } + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + if (delegate == null) { + throw new CertificateException(); + } else { + delegate.checkClientTrusted(x509Certificates, s); + } + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + if (delegate == null) { + throw new CertificateException(); + } else { + delegate.checkServerTrusted(x509Certificates, s); + } + for (X509Certificate certificate : x509Certificates) { + certificate.checkValidity(); + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + if (delegate != null) { + return delegate.getAcceptedIssuers(); + } + return new X509Certificate[0]; + } +}
server/src/test/java/org/cloudfoundry/identity/uaa/provider/ldap/ProcessLdapPropertiesTest.java+12 −1 modified@@ -35,4 +35,15 @@ public void testProcess() throws Exception { process.setBaseUrl("ldaps://localhost:636"); assertEquals(ProcessLdapProperties.SKIP_SSL_VERIFICATION_SOCKET_FACTORY, process.process(properties).get(LDAP_SOCKET_FACTORY)); } -} \ No newline at end of file + + @Test + public void process_whenSslValidationIsEnabled() throws Exception { + Map<String,String> properties = new HashMap<>(); + ProcessLdapProperties process = new ProcessLdapProperties("ldap://localhost:389", false); + assertNull(process.process(properties).get(LDAP_SOCKET_FACTORY)); + process.setDisableSslVerification(false); + assertNull(process.process(properties).get(LDAP_SOCKET_FACTORY)); + process.setBaseUrl("ldaps://localhost:636"); + assertEquals(ProcessLdapProperties.EXPIRY_CHECKING_SOCKET_FACTORY, process.process(properties).get(LDAP_SOCKET_FACTORY)); + } +}
server/src/test/java/org/cloudfoundry/identity/uaa/security/LdapSocketFactoryTest.java+7 −0 added@@ -0,0 +1,7 @@ +package org.cloudfoundry.identity.uaa.security; + +import static org.junit.Assert.*; + +public class LdapSocketFactoryTest { + +}
server/src/test/java/org/cloudfoundry/identity/uaa/security/X509ExpiryCheckingTrustManagerTest.java+59 −0 added@@ -0,0 +1,59 @@ +package org.cloudfoundry.identity.uaa.security; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.security.saml.trust.X509TrustManager; + +import java.security.cert.CertificateExpiredException; +import java.security.cert.X509Certificate; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; + +public class X509ExpiryCheckingTrustManagerTest { + + @Test + public void checkServerTrusted_throwsExceptionWhenCertIsExpired() throws Exception { + X509ExpiryCheckingTrustManager manager = new X509ExpiryCheckingTrustManager(); + X509TrustManager mockedDelegate = Mockito.mock(X509TrustManager.class); + manager.setDelegate(mockedDelegate); + X509Certificate certificate = Mockito.mock(X509Certificate.class); + X509Certificate[] x509Certificates = {certificate}; + + doNothing().when(mockedDelegate).checkServerTrusted(x509Certificates, "string"); + doThrow(new CertificateExpiredException()).when(certificate).checkValidity(); + try { + manager.checkServerTrusted(x509Certificates,"string"); + Assert.fail(); + } catch (CertificateExpiredException e) { + verify(mockedDelegate).checkServerTrusted(x509Certificates, "string"); + verify(certificate).checkValidity(); + } + } + + @Test + public void checkClientTrusted_callsDelegate() throws Exception { + X509ExpiryCheckingTrustManager manager = new X509ExpiryCheckingTrustManager(); + X509TrustManager mockedDelegate = Mockito.mock(X509TrustManager.class); + manager.setDelegate(mockedDelegate); + + X509Certificate certificate = Mockito.mock(X509Certificate.class); + X509Certificate[] x509Certificates = {certificate}; + + doNothing().when(mockedDelegate).checkClientTrusted(x509Certificates, "string"); + manager.checkClientTrusted(x509Certificates, "string"); + verify(mockedDelegate).checkClientTrusted(x509Certificates, "string"); + } + + @Test + public void checkAcceptedIssuers_callsDelegate() throws Exception { + X509ExpiryCheckingTrustManager manager = new X509ExpiryCheckingTrustManager(); + X509TrustManager mockedDelegate = Mockito.mock(X509TrustManager.class); + manager.setDelegate(mockedDelegate); + + manager.getAcceptedIssuers(); + verify(mockedDelegate).getAcceptedIssuers(); + } +}
.travis.yml+1 −1 modified@@ -42,7 +42,7 @@ install: fi - mkdir -p $HOME/build/cloudfoundry/uaa/uaa/build/reports/tests script: -- ./gradlew -Dspring.profiles.active=$TESTENV jacocoRootReport +- ./gradlew -Dspring.profiles.active=$TESTENV -Djavax.net.ssl.trustStore=$TRAVIS_BUILD_DIR/scripts/ldap/truststore-with-ldap-certs.jks -Djavax.net.ssl.trustStoreType=JKS jacocoRootReport after_success: - ./gradlew coveralls - for i in $(find $HOME/build/cloudfoundry/uaa/ -name reports -type d); do rm -rf $i; done
uaa/src/main/resources/uaa.yml+2 −2 modified@@ -1,8 +1,8 @@ -# Configuration in this file is overridden by an external file +# Configuration in this file ixs overridden by an external file # if any of these exist: # [$UAA_CONFIG_URL, $UAA_CONFIG_PATH/uaa.yml, $CLOUD_FOUNDRY_CONFIG_PATH/uaa.yml] -#spring_profiles: mysql,default +#spring_profiles: mysql,default,ldap #spring_profiles: postgresql,default #spring_profiles: ldap,default,hsqldb #spring_profiles: saml
uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/LdapLoginIT.java+195 −0 added@@ -0,0 +1,195 @@ +package org.cloudfoundry.identity.uaa.integration.feature; + +import org.cloudfoundry.identity.uaa.ServerRunning; +import org.cloudfoundry.identity.uaa.constants.OriginKeys; +import org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils; +import org.cloudfoundry.identity.uaa.integration.util.ScreenshotOnFail; +import org.cloudfoundry.identity.uaa.login.test.LoginServerClassRunner; +import org.cloudfoundry.identity.uaa.provider.IdentityProvider; +import org.cloudfoundry.identity.uaa.provider.LdapIdentityProviderDefinition; +import org.cloudfoundry.identity.uaa.scim.ScimUser; +import org.cloudfoundry.identity.uaa.test.UaaTestAccounts; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.oauth2.client.test.TestAccounts; +import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +import static org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils.doesSupportZoneDNS; +import static org.junit.Assert.assertThat; +import static org.junit.Assume.assumeTrue; + +@RunWith(LoginServerClassRunner.class) +@ContextConfiguration(classes = DefaultIntegrationTestConfig.class) +public class LdapLoginIT { + + + + @Autowired + @Rule + public IntegrationTestRule integrationTestRule; + + @Rule + public ScreenshotOnFail screenShootRule = new ScreenshotOnFail(); + + @Autowired + RestOperations restOperations; + + @Autowired + WebDriver webDriver; + + @Value("${integration.test.base_url}") + String baseUrl; + + @Autowired + TestClient testClient; + + ServerRunning serverRunning = ServerRunning.isRunning(); + + + @Before + public void clearWebDriverOfCookies() throws Exception { + screenShootRule.setWebDriver(webDriver); + webDriver.get(baseUrl + "/logout.do"); + webDriver.get(baseUrl.replace("localhost", "testzone1.localhost") + "/logout.do"); + webDriver.get(baseUrl.replace("localhost", "testzone2.localhost") + "/logout.do"); + webDriver.manage().deleteAllCookies(); + } + + @Test + public void ldapLogin_withValidSelfSignedCert() throws Exception { + //ensure we are able to resolve DNS for hostname testzone2.localhost + assumeTrue("Expected testzone1/2/3/4.localhost to resolve to 127.0.0.1", doesSupportZoneDNS()); + String zoneId = "testzone2"; + String zoneUrl = baseUrl.replace("localhost", "testzone2.localhost"); + + //identity client token + RestTemplate identityClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[]{"zones.write", "zones.read", "scim.zones"}, "identity", "identitysecret") + ); + //admin client token - to create users + RestTemplate adminClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[0], "admin", "adminsecret") + ); + //create the zone + IntegrationTestUtils.createZoneOrUpdateSubdomain(identityClient, baseUrl, zoneId, zoneId); + + //create a zone admin user + String email = new RandomValueStringGenerator().generate() +"@samltesting.org"; + ScimUser user = IntegrationTestUtils.createUser(adminClient, baseUrl,email ,"firstname", "lastname", email, true); + IntegrationTestUtils.makeZoneAdmin(identityClient, baseUrl, user.getId(), zoneId); + + //get the zone admin token + String zoneAdminToken = + IntegrationTestUtils.getAuthorizationCodeToken(serverRunning, + UaaTestAccounts.standard(serverRunning), + "identity", + "identitysecret", + email, + "secr3T"); + + LdapIdentityProviderDefinition ldapIdentityProviderDefinition = LdapIdentityProviderDefinition.searchAndBindMapGroupToScopes( + "ldaps://52.87.212.253:636/", + "cn=admin,dc=test,dc=com", + "password", + "dc=test,dc=com", + "cn={0}", + "ou=scopes,dc=test,dc=com", + "member={0}", + "mail", + null, + false, + true, + true, + 100, + false); + + IdentityProvider provider = new IdentityProvider(); + provider.setIdentityZoneId(zoneId); + provider.setType(OriginKeys.LDAP); + provider.setActive(true); + provider.setConfig(ldapIdentityProviderDefinition); + provider.setOriginKey(OriginKeys.LDAP); + provider.setName("simplesamlphp for uaa"); + provider = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken,baseUrl,provider); + + webDriver.get(zoneUrl + "/login"); + webDriver.findElement(By.name("username")).sendKeys("marissa4"); + webDriver.findElement(By.name("password")).sendKeys("ldap4"); + webDriver.findElement(By.xpath("//input[@value='Sign in']")).click(); + assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString("Where to")); + } + + @Test + public void ldapLogin_withExpiredSelfSignedCert() throws Exception { + //ensure we are able to resolve DNS for hostname testzone1.localhost + assumeTrue("Expected testzone1/2/3/4.localhost to resolve to 127.0.0.1", doesSupportZoneDNS()); + String zoneId = "testzone1"; + String zoneUrl = baseUrl.replace("localhost", "testzone1.localhost"); + + //identity client token + RestTemplate identityClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[]{"zones.write", "zones.read", "scim.zones"}, "identity", "identitysecret") + ); + //admin client token - to create users + RestTemplate adminClient = IntegrationTestUtils.getClientCredentialsTemplate( + IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[0], "admin", "adminsecret") + ); + //create the zone + IntegrationTestUtils.createZoneOrUpdateSubdomain(identityClient, baseUrl, zoneId, zoneId); + + //create a zone admin user + String email = new RandomValueStringGenerator().generate() +"@samltesting.org"; + ScimUser user = IntegrationTestUtils.createUser(adminClient, baseUrl,email ,"firstname", "lastname", email, true); + IntegrationTestUtils.makeZoneAdmin(identityClient, baseUrl, user.getId(), zoneId); + + //get the zone admin token + String zoneAdminToken = + IntegrationTestUtils.getAuthorizationCodeToken(serverRunning, + UaaTestAccounts.standard(serverRunning), + "identity", + "identitysecret", + email, + "secr3T"); + + LdapIdentityProviderDefinition ldapIdentityProviderDefinition = LdapIdentityProviderDefinition.searchAndBindMapGroupToScopes( + "ldaps://52.20.5.106:636/", + "cn=admin,dc=test,dc=com", + "password", + "dc=test,dc=com", + "cn={0}", + "ou=scopes,dc=test,dc=com", + "member={0}", + "mail", + null, + false, + true, + true, + 100, + false); + + IdentityProvider provider = new IdentityProvider(); + provider.setIdentityZoneId(zoneId); + provider.setType(OriginKeys.LDAP); + provider.setActive(true); + provider.setConfig(ldapIdentityProviderDefinition); + provider.setOriginKey(OriginKeys.LDAP); + provider.setName("simplesamlphp for uaa"); + provider = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken,baseUrl,provider); + + webDriver.get(zoneUrl + "/login"); + webDriver.findElement(By.name("username")).sendKeys("marissa4"); + webDriver.findElement(By.name("password")).sendKeys("ldap4"); + webDriver.findElement(By.xpath("//input[@value='Sign in']")).click(); + assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString("Welcome to The Twiglet Zone[" + zoneId + "]!")); + } +}
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
12- github.com/advisories/GHSA-rc2r-w8jv-vggpghsaADVISORY
- github.com/cloudfoundry/cf-release/releases/tag/v240nvdRelease NotesThird Party AdvisoryWEB
- github.com/cloudfoundry/uaa-release/releases/tag/v11.3nvdRelease NotesThird Party AdvisoryWEB
- github.com/cloudfoundry/uaa-release/releases/tag/v12.3nvdRelease NotesThird Party AdvisoryWEB
- github.com/cloudfoundry/uaa/releases/tag/2.7.4.6nvdRelease NotesThird Party AdvisoryWEB
- github.com/cloudfoundry/uaa/releases/tag/3.3.0.3nvdRelease NotesThird Party AdvisoryWEB
- github.com/cloudfoundry/uaa/releases/tag/3.4.2nvdRelease NotesThird Party AdvisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2016-5016ghsaADVISORY
- pivotal.io/security/cve-2016-5016nvdVendor AdvisoryWEB
- github.com/cloudfoundry/uaa/commit/0a78612f981c541ad2d997e6a365f2a0b3e799d9ghsaWEB
- github.com/cloudfoundry/uaa/commit/bc91ccd2029e8f1cea0c647f0c9aad4585f7a2cghsaWEB
- github.com/cloudfoundry/uaa/commit/f97049df1c6c03effda5049c41704ac831ff3925ghsaWEB
News mentions
0No linked articles in our index yet.