LDAP Simple Authentication with Spring API

此範例為: 給予一個admin的dn與password做query,然後針對某一個user做驗證。在此範例中ldapTemplate.authenticate的第一個參數,即使你沒有設定一個對應base,也會從contextSource所設定的base開始找尋。我是以cn為使用者的名稱。

LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl("ldap://192.168.1.13:389");
contextSource.setBase("dc=testldap,dc=org");
contextSource.setUserDn("cn=admin,dc=testldap,dc=org");
contextSource.setPassword("123456");
contextSource.afterPropertiesSet();
 
LdapTemplate ldapTemplate = new LdapTemplate(contextSource);
try {
	ldapTemplate.afterPropertiesSet();
	Filter filter = new EqualsFilter("cn", "tonylin");
	boolean authed = ldapTemplate.authenticate("ou=sw", filter.encode(), "123456");
	Assert.assertTrue(ldapTemplate.authenticate("ou=sw", filter.encode(), "123456"));
	Assert.assertFalse(ldapTemplate.authenticate("ou=sw", filter.encode(), "654321"));
} catch (Exception e) {
	Assert.fail(e.getMessage());
}

LDAP server如果允許SSL連線,且client已經將server的certificate加為可信任的,我們只要依照Normal範例,將URL的protocol與port做調整就可以使用了:

LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl("ldaps://192.168.1.13:636");
contextSource.setBase("dc=testldap,dc=org");
contextSource.setUserDn("cn=admin,dc=testldap,dc=org");
contextSource.setPassword("123456");
contextSource.afterPropertiesSet();
 
LdapTemplate ldapTemplate = new LdapTemplate(contextSource);
try {
	ldapTemplate.afterPropertiesSet();
	Filter filter = new EqualsFilter("cn", "tonylin");
	boolean authed = ldapTemplate.authenticate("ou=sw", filter.encode(), "123456");
	Assert.assertTrue(ldapTemplate.authenticate("ou=sw", filter.encode(), "123456"));
	Assert.assertFalse(ldapTemplate.authenticate("ou=sw", filter.encode(), "654321"));
} catch (Exception e) {
	Assert.fail(e.getMessage());
}

有幾個要點:

  • 使用ldap protocol。
  • 透過DefaultTlsDirContextAuthenticationStrategy讓client與server negotiate。
  • 由於會做hostname的verify,為了測試,所以我們先override去避掉它。
  • 做authenticate時,透過LookupAttemptingCallback讓它在連線完成後做search,以驗證密碼是否正確。
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl("ldap://192.168.1.13:389");
contextSource.setBase("dc=testldap,dc=org");
contextSource.setUserDn("cn=admin,dc=testldap,dc=org");
contextSource.setPassword("123456");
 
DefaultTlsDirContextAuthenticationStrategy strategy = new DefaultTlsDirContextAuthenticationStrategy();
strategy.setHostnameVerifier((hostname, sslsession) -> {
	return true;
});
 
contextSource.setAuthenticationStrategy(strategy);
contextSource.afterPropertiesSet();
 
LdapTemplate ldapTemplate = new LdapTemplate(contextSource);
try {
	ldapTemplate.afterPropertiesSet();
	Filter filter = new EqualsFilter("cn", "tonylin");
	Assert.assertTrue(ldapTemplate.authenticate("ou=sw", filter.encode(), "123456", new LookupAttemptingCallback()));
	Assert.assertFalse(ldapTemplate.authenticate("ou=sw", filter.encode(), "654321", new LookupAttemptingCallback()));
} catch (Exception e) {
	Assert.fail(e.getMessage());
}

為了確認真的是TLS,透別使用wireshark觀察一下: link