差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

Both sides previous revision 前次修改
下次修改
前次修改
java:ldap:spring:ldapauthenticationprovider:secureconnection [2016/05/10 14:41]
tony [How to?]
java:ldap:spring:ldapauthenticationprovider:secureconnection [2023/06/25 09:48] (目前版本)
行 8: 行 8:
   * StartTLS: 使用ldap,通常port為389,是非加密連線的擴充。連線時會透過定義好的溝通方式,將連線升級為加密連線,可以是SSL也可以是TLS;一般用於server內部溝通。   * StartTLS: 使用ldap,通常port為389,是非加密連線的擴充。連線時會透過定義好的溝通方式,將連線升級為加密連線,可以是SSL也可以是TLS;一般用於server內部溝通。
 TLS和StartTLS非常容易混淆,甚至認為它是同種東西。像LdapAdmin、Linux、Cisco Firesight等就是把StartTLS當TLS,而Apache Studio、SonicWall是稱為StartTLS或StartTLS extension。 TLS和StartTLS非常容易混淆,甚至認為它是同種東西。像LdapAdmin、Linux、Cisco Firesight等就是把StartTLS當TLS,而Apache Studio、SonicWall是稱為StartTLS或StartTLS extension。
 +==== SSL ====
 +要使用SSL只要將protocol改為ldaps並注意使用的port即可,我分別以驗證成功與失敗做例子:​
 +<code java>
 +@Test
 +public void testSSL(){
 + 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();​
 +
 + LdapAuthenticationProvider provider = createProvider(contextSource);​
 +
 + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("​tonylin",​ "​123456"​);​
 + try {
 + Authentication ret = provider.authenticate(token);​
 + Collection<?​ extends GrantedAuthority>​ authorities = ret.getAuthorities();​
 + assertEquals(1,​ authorities.size());​
 + assertEquals("​mis",​ authorities.toArray(new GrantedAuthority[0])[0].getAuthority());​
 + } catch( Exception e ){
 + fail();
 + }
 +
 + token = new UsernamePasswordAuthenticationToken("​tonylin",​ "​12345678"​);​
 + try {
 + provider.authenticate(token);​
 + fail();
 + } catch( BadCredentialsException e ){
 + assertEquals("​Bad credentials",​ e.getMessage());​
 + }
 +}
 +
 +private LdapAuthenticationProvider createProvider(LdapContextSource contextSource){
 + FilterBasedLdapUserSearch userSearch = new FilterBasedLdapUserSearch("​ou=sw",​ "​uid={0}",​ contextSource);​
 + BindAuthenticator authenticator = new BindAuthenticator(contextSource);​
 + authenticator.setUserSearch(userSearch);​
 +
 + DefaultLdapAuthoritiesPopulator authoritiesPopulator = new DefaultLdapAuthoritiesPopulator(contextSource,​ "​ou=sw"​);​
 +
 + authoritiesPopulator.setGroupSearchFilter("​uniqueMember={0}"​);​
 + authoritiesPopulator.setConvertToUpperCase(false);​
 + authoritiesPopulator.setRolePrefix(""​);​
 + authoritiesPopulator.setSearchSubtree(true);​
 +
 + return new LdapAuthenticationProvider(authenticator,​ authoritiesPopulator);​
 +}
 +</​code>​
 +==== StartTLS ====
 +Spring提供了DefaultTlsDirContextAuthenticationStrategy讓你可以輕鬆使用TLS,當然也可以不透過它自己使用JNDI達到目的。與SSL的不同在於,DefaultTlsDirContextAuthenticationStrategy在做handshake後,會做hostname的verify,為了測試我們透過override setHostnameVerifier去跳過;而在驗證錯誤時,會是接到AuthenticationException的例外:​
 +<code java>
 +@Test
 +public void testTLS(){
 + 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();​
 +
 + LdapAuthenticationProvider provider = createProvider(contextSource);​
 +
 + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("​tonylin",​ "​123456"​);​
 + try {
 + Authentication ret = provider.authenticate(token);​
 + Collection<?​ extends GrantedAuthority>​ authorities = ret.getAuthorities();​
 + assertEquals(1,​ authorities.size());​
 + assertEquals("​mis",​ authorities.toArray(new GrantedAuthority[0])[0].getAuthority());​
 + } catch( Exception e ){
 + fail(e.getMessage());​
 + }
 +
 + token = new UsernamePasswordAuthenticationToken("​tonylin",​ "​12345678"​);​
 + try {
 + provider.authenticate(token);​
 + fail();
 + } catch( AuthenticationException e ){
 + assertTrue(e.getMessage().contains("​Invalid Credentials"​));​
 + }
 +}
 +</​code>​
 +如果在連不到LDAP server的情況下,通常都要等待20秒。我們可以透過以下方式去調整連線與從Server讀取資料的timeout:​
 +<code java>
 +Map<​String,​Object>​ baseEnv = new HashMap<>​();​
 +baseEnv.put("​com.sun.jndi.ldap.read.timeout",​ "​1000"​);​
 +baseEnv.put("​com.sun.jndi.ldap.connect.timeout",​ "​1000"​);​
 +
 +contextSource.setBaseEnvironmentProperties(baseEnv);​
 +</​code>​
 +如果出現TLS already started的錯誤,這可能是spring connection pool造成的,可以透過設定以下flag取消pool暫時解決;使用ldaps+StartTLS也會有一樣問題。
 +<code java>
 +ldapContextSource.setCacheEnvironmentProperties(false);​
 +ldapContextSource.setPooled(false);​
 +</​code>​
 +===== 最後 =====
 +除了以上內容外,還有些議題沒特別說明:​
 +  * **SSL + VerifyHostname**:​ Hostname驗證是為了抵禦中間人攻擊,因此SSL應也需要Hostname驗證。目前我已經有做法可以解決。
 +  * **Disable Connection Pool**: Connection Pool是為了減少重建連線的Effort,但目前Spring的StartTLS並無法正常使用。
 +這些議題有機會再研究與分享。
 ===== Reference ===== ===== Reference =====
   * [[https://​www.fastmail.com/​help/​technical/​ssltlsstarttls.html|SSL VS. TLS VS. STARTTLS]]   * [[https://​www.fastmail.com/​help/​technical/​ssltlsstarttls.html|SSL VS. TLS VS. STARTTLS]]
行 17: 行 122:
   * [[http://​www.cisco.com/​c/​en/​us/​support/​docs/​security/​firesight-management-center/​118738-configure-firesight-00.html|UI Design of Firesight system]]   * [[http://​www.cisco.com/​c/​en/​us/​support/​docs/​security/​firesight-management-center/​118738-configure-firesight-00.html|UI Design of Firesight system]]
   * [[http://​www.derekseaman.com/​2011/​06/​citrix-netscaler-active-directory.html|UI Design of Citrix-Netscaler]]   * [[http://​www.derekseaman.com/​2011/​06/​citrix-netscaler-active-directory.html|UI Design of Citrix-Netscaler]]
 +  * [[http://​www.openldap.org/​faq/​data/​cache/​1063.html|TLS already started - Connection Pool]] 
 +  * [[http://​forum.spring.io/​forum/​spring-projects/​data/​ldap/​19764-tls-and-setupauthenticatedenvironment|TLS already started - don't use ldaps]]
 =====  ===== =====  =====
 ---- ----
 \\ \\
 ~~DISQUS~~ ~~DISQUS~~