2015-04-15 83 views
12

我幾乎讀了關於stackoverflow上Spring/Security/Ldap和ActiveDirectory的所有內容。即使我發現有用的提示和提示,我也無法解決我的問題。Spring Security 4.0.0 + ActiveDirectoryLdapAuthenticationProvider + BadCredentialsException PartialResultException

這裏是:我沒有使用用戶服務和自定義登錄頁面配置Spring Security,並且一切正常。然後,我嘗試切換到恰好是ActiveDirectory的最終身份驗證提供程序。

這裏是我的安全applicationContext.xml中(我提醒你這個設置是工作的罰款與用戶服務作爲認證供應商,因此,該文件實際上是進口的,等等):

<?xml version="1.0" encoding="UTF-8"?> 
<b:beans xmlns:b="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://www.springframework.org/schema/security" 
    xmlns:oauth="http://www.springframework.org/schema/security/oauth" 
    xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd http://www.springframework.org/schema/security/oauth http://www.springframework.org/schema/security/spring-security-oauth.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> 

<!-- Définitions globales de sécurité --> 
<global-method-security pre-post-annotations="enabled" /> 

<!-- Configuration de l'accès et du formulaire --> 
<!-- Permettre l'accès libre aux feuilles de style, polices et images --> 
<http pattern='/resources/css/**' security="none" /> 
<http pattern='/resources/fonts/**' security="none" /> 
<http pattern='/resources/images/**' security="none" /> 

<http use-expressions="true" access-denied-page="/403" disable-url-rewriting="true"> 

    <!-- Limitation à une seule session utilisateur concurrente --> 
    <session-management invalid-session-url="/identite?time=1"> 
     <concurrency-control max-sessions="1" expired-url="/identite?time=1" /> 
    </session-management> 

    <!-- Définitions pour le formulaire de la page JSP d'identification --> 
    <form-login login-page="/identite" login-processing-url="/identite.proc" default-target-url="/" always-use-default-target="true" authentication-failure-url="/identite?err=1" username-parameter="username" password-parameter="password" /> 

    <logout logout-url="/logout" logout-success-url="/identite?out=1" delete-cookies="JSESSIONID" invalidate-session="true" /> 

    <!-- Utiliser un canal chiffré pour les échanges --> 
    <intercept-url requires-channel="https" pattern="/identite*" access="permitAll()" /> 
    <intercept-url requires-channel="https" pattern="/**" access="isAuthenticated()" /> 
</http> 

<!-- Fournisseurs d'identité pour le formulaire (au final, LDAP) --> 
<authentication-manager erase-credentials="true"> 
    <ldap-authentication-provider ref="myADProvider" /> 
    <!-- This is the user-service authentication provider that is working fine 
     <authentication-provider> 
     <user-service> 
     <user name="Toto" authorities="ROLE_USER, ROLE_ADMIN" password="totototo" /> 
     </user-service> 
     </authentication-provider> 
    --> 
</authentication-manager> 

<b:bean id="myADProvider" 
    class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider"> 
    <b:constructor-arg value="fsappsuni" /> 
    <b:constructor-arg value="ldap://fsapps.company.uni:389/" /> 
    <b:property name="convertSubErrorCodesToExceptions" value="true" /> 
    <b:property name="useAuthenticationRequestCredentials" value="true" /> 
</b:bean> 

在bean myADProvider中,即使我將第一個構造函數參數更改爲fsapps.company.uni或company.uni或其他任何內容,它都不會更改以下錯誤。這個問題似乎是由於綁定之後的事實,使用錯誤的篩選器查找類似於(&(userPrincipalName = {0})(objectClass = user))而不是(&(sAMAccountName = {0})(objectClass =用戶))。由於我無法弄清楚如何改變這種情況,而您可以通過LDAP提供程序進行更改,於是我轉向LDAP提供程序,試圖使其無法成功,也沒有在同一地點絆倒問題。我還將我的Spring Framework從3.1.2升級到4.1.6.RELEASE和Spring Security從3.1.2升級到4.0.0.RELEASE,在閱讀ActiveDirectoryLdapAuthenticationProvider時遇到問題,希望問題在此期間得到解決關於這個問題的原始討論與3.x版本有關。

這裏是我的LDAP設置努力使認證使用Active Directory配置:

<?xml version="1.0" encoding="UTF-8"?> 
<b:beans xmlns:b="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://www.springframework.org/schema/security" 
    xmlns:oauth="http://www.springframework.org/schema/security/oauth" 
    xsi:schemaLocation="http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security-4.0.xsd 
    http://www.springframework.org/schema/security/oauth 
    http://www.springframework.org/schema/security/spring-security-oauth.xsd 
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd"> 

<!-- Définitions globales de sécurité --> 
<global-method-security pre-post-annotations="enabled" /> 

<!-- Configuration de l'accès et du formulaire --> 
<!-- Permettre l'accès libre aux feuilles de style, polices et images --> 
<http pattern='/resources/css/**' security="none" /> 
<http pattern='/resources/fonts/**' security="none" /> 
<http pattern='/resources/images/**' security="none" /> 

<http use-expressions="true" disable-url-rewriting="true"> 

    <!-- Limitation à une seule session utilisateur concurrente --> 
    <session-management invalid-session-url="/identite?time=1"> 
     <concurrency-control max-sessions="1" expired-url="/identite?time=1" /> 
    </session-management> 

    <!-- Définitions pour le formulaire de la page JSP d'identification --> 
    <form-login login-page="/identite" login-processing-url="/identite.proc" default-target-url="/" always-use-default-target="true" authentication-failure-url="/identite?err=1" username-parameter="username" password-parameter="password" /> 
    <csrf disabled="true" /> 

    <logout logout-url="/logout" logout-success-url="/identite?out=1" delete-cookies="JSESSIONID" invalidate-session="true" /> 

    <!-- Utiliser un canal chiffré pour les échanges --> 
    <intercept-url requires-channel="https" pattern="/identite*" access="permitAll()" /> 
    <intercept-url requires-channel="https" pattern="/**" access="isAuthenticated()" /> 
</http> 

<!-- Fournisseurs d'identité pour le formulaire (au final, LDAP) --> 
<ldap-server url="ldap://fsapps.company.uni/dc=fsapps,dc=company,dc=uni" port="389" /> 
<authentication-manager erase-credentials="true"> 
    <ldap-authentication-provider role-prefix="none" 
     user-search-filter="(&amp;(sAMAccountName={0})(objectClass=user))" 
     group-search-filter="(&amp;(member={0})(objectClass=group))" 
     user-search-base="dc=fsapps,dc=company,dc=uni"> 
    </ldap-authentication-provider> 
    <!-- <authentication-provider ref="myADProvider" ></authentication-provider> --> 
</authentication-manager> 

<!-- 
<b:bean id="myADProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider"> 
    <b:constructor-arg value="fsapps.company.uni" /> 
    <b:constructor-arg value="ldap://fsapps.company.uni:389/" /> 
    <b:property name="convertSubErrorCodesToExceptions" value="true" /> 
    <!- - 
    <b:property name="useAuthenticationRequestCredentials" value="true" /> 
    - -> 
</b:bean> 
<b:bean id="webSecurityExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"></b:bean> 
--> 

</b:beans> 

這個時候,我留下了廣告提供參考bean的配置部分。這也不是工作。

那麼,如何將用戶和組搜索路徑傳遞給AD提供者?或者,我該如何配置LDAP提供程序以使用AD並完成身份驗證?

這是我收到我的日誌與LDAP建立的消息,該廣告設置上面(認證錯誤主要是由於錯誤的搜索路徑)解釋說:

2015-04-15 16:19:13,252 DEBUG (o.s.s.a.ProviderManager.authenticate) [http-8443-1] Authentication attempt using org.springframework.security.ldap.authentication.LdapAuthenticationProvider MDC{} 
2015-04-15 16:19:13,252 DEBUG (o.s.s.l.a.AbstractLdapAuthenticationProvider.authenticate) [http-8443-1] Processing authentication request for user: ba5glag MDC{} 
2015-04-15 16:19:13,252 DEBUG (o.s.s.l.s.FilterBasedLdapUserSearch.searchForUser) [http-8443-1] Searching for user 'myuser', with user search [ searchFilter: '(&(sAMAccountName={0})(objectClass=user))', searchBase: 'dc=fsapps,dc=company,dc=uni', scope: subtree, searchTimeLimit: 0, derefLinkFlag: false ] MDC{} 
2015-04-15 16:19:13,299 DEBUG (o.s.s.a.DefaultAuthenticationEventPublisher.publishAuthenticationFailure) [http-8443-1] No event was found for the exception org.springframework.security.authentication.InternalAuthenticationServiceException MDC{} 
2015-04-15 16:19:13,299 ERROR (o.s.s.w.a.AbstractAuthenticationProcessingFilter.doFilter) [http-8443-1] An internal error occurred while trying to authenticate the user. MDC{} 
org.springframework.security.authentication.InternalAuthenticationServiceException: Uncategorized exception occured during LDAP processing; nested exception is javax.naming.NamingException: [LDAP: error code 1 - 00000000: LdapErr: DSID-0C090627, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, vece(unprintable character here)]; remaining name 'dc=fsapps,dc=company,dc=uni' 
     at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:207) ~[spring-security-ldap-4.0.0.RELEASE.jar:?] 
     at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:82) ~[spring-security-ldap-4.0.0.RELEASE.jar:?] 

我希望我提供所有需要的信息爲某人提供一些提示和指導來解決這個配置問題。

UPDATE 2015年4月16日〜10:20

我想出如何與ActiveDirectoryLdapAuthenticationProvider添加搜索篩選器。我還用Wireshark觀察了我的應用程序服務器和AD服務器之間的交換,以查看實際完成的操作。以下是我的發現,我相信我對解決我的問題並不遙遠。我更新了security-applicationContext.xml,因爲我現在專注於使ActiveDirectoryLdapAuthenticationProvider工作,所以我拋棄了ldap-server的東西。所以,現在這是一個更清潔的配置:

<?xml version="1.0" encoding="UTF-8"?> 
<b:beans xmlns:b="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://www.springframework.org/schema/security" 
    xmlns:oauth="http://www.springframework.org/schema/security/oauth" 
    xsi:schemaLocation="http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security-4.0.xsd 
    http://www.springframework.org/schema/security/oauth 
    http://www.springframework.org/schema/security/spring-security-oauth.xsd 
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd"> 

    <!-- Définitions globales de sécurité --> 
    <global-method-security pre-post-annotations="enabled" /> 

    <!-- Configuration de l'accès et du formulaire --> 
    <!-- Permettre l'accès libre aux feuilles de style, polices et images --> 
    <http pattern='/resources/css/**' security="none" /> 
    <http pattern='/resources/fonts/**' security="none" /> 
    <http pattern='/resources/images/**' security="none" /> 
    <http pattern='/resources/js/**' security="none" /> 

    <http use-expressions="true" disable-url-rewriting="true"> 

     <!-- Limitation à une seule session utilisateur concurrente --> 
     <session-management invalid-session-url="/identite?expiree=1"> 
      <concurrency-control max-sessions="1" expired-url="/identite?expiree=1" /> 
     </session-management> 

     <!-- Définitions pour le formulaire de la page JSP d'identification --> 
     <form-login login-page="/identite" login-processing-url="/identite.proc" default-target-url="/" always-use-default-target="true" authentication-failure-url="/identite?err=1" username-parameter="username" password-parameter="password" /> 
     <csrf disabled="true" /> 

     <logout logout-url="/logout" logout-success-url="/identite?termine=1" delete-cookies="JSESSIONID" invalidate-session="true" /> 

     <!-- Utiliser un canal chiffré pour les échanges --> 
     <intercept-url requires-channel="https" pattern="/identite*" access="permitAll()" /> 
     <intercept-url requires-channel="https" pattern="/**" access="isAuthenticated()" /> 
     <access-denied-handler error-page="/erreur403" /> 
    </http> 

    <!-- Fournisseurs d'identité pour le formulaire (au final, LDAP) --> 
    <authentication-manager erase-credentials="true"> 
     <authentication-provider ref="myADProvider" /> 
    </authentication-manager> 

    <b:bean id="myADProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider"> 
     <b:constructor-arg value="fsapps.company.uni" /> 
     <b:constructor-arg value="ldap://fsapps.company.uni:389/" /> 
     <b:property name="searchFilter" value="(&amp;(sAMAccountName={0})(objectClass=user))" /> 
     <b:property name="convertSubErrorCodesToExceptions" value="true" /> 
     <b:property name="useAuthenticationRequestCredentials" value="true" /> 
    </b:bean> 
    <b:bean id="webSecurityExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" /> 

</b:beans> 

對配置的評論很少。在我的ADProvider bean定義中,構造函數的第一個參數是fsapps.company。uni用於以[email protected]的形式創建主體,並使用以下格式的baseObject構建搜索請求的baseObject:dc = fsapps,dc = company,dc = uni。

第二個構造函數的參數用於建立通信。屬性類型的下一個名稱爲name =「searchFilter」的元素將調用類ActiveDirectoryLdapAuthenticationProvider的setSearchFilter()方法來設置搜索過濾器(這正是我最初尋求的一些進展)。因此,它現在設置爲搜索(&(sAMAccountName = {0})(objectClass = user))。

使用此設置,我可以在WireShark中看到LDAP對話並且綁定成功。綁定響應是成功的。接下來,搜索請求也成功,但不會返回任何結果。因此,我仍然得到我的日誌如下:

2015-04-16 10:30:28,201 DEBUG (o.s.s.a.ProviderManager.authenticate) [http-8443-2] Authentication attempt using org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider MDC{} 
2015-04-16 10:30:28,201 DEBUG (o.s.s.l.a.AbstractLdapAuthenticationProvider.authenticate) [http-8443-2] Processing authentication request for user: myusername MDC{} 
2015-04-16 10:30:28,294 DEBUG (o.s.s.l.SpringSecurityLdapTemplate.searchForSingleEntryInternal) [http-8443-2] Searching for entry under DN '', base = 'dc=fsapps,dc=company,dc=uni', filter = '(&(sAMAccountName={0})(objectClass=user))' MDC{} 
2015-04-16 10:30:28,294 INFO (o.s.s.l.SpringSecurityLdapTemplate.searchForSingleEntryInternal) [http-8443-2] Ignoring PartialResultException MDC{} 
2015-04-16 10:30:28,310 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-2] Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials MDC{} 
2015-04-16 10:30:28,310 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-2] Updated SecurityContextHolder to contain null Authentication MDC{} 
2015-04-16 10:30:28,310 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-2] Delegating to authentication failure handler org.springframework.se[email protected]2876b359 MDC{} 

我相信,我幾乎沒有,但仍然可以使用一些幫助,如果有人可以提供任何。仔細檢查後,它看起來第一個構造函數的參數被用來構造baseObject,並且userPrincipalName是我的問題。在我們的設置中,userPrincipalName使用的域名不是LDAP網址中的域名(即campus.company.com)。到目前爲止,我可以改變參數來匹配用於構建用戶主體的域名。現在,問題是這將改變必須匹配LDAP url模式的baseObject(即fsapps.company.uni)。

從文檔中,只有一個方法來設置搜索過濾器,但構造函數可以使用一個,兩個或三個參數。第三個參數是提供baseObject的值。

我的問題然後通過以下配置來解決,我必須使用所有可用的setter和構造函數的參數來使它工作。該myADProvider bean定義爲如下:

<b:bean id="myADProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider"> 
     <b:constructor-arg value="campus.company.com" /> 
     <b:constructor-arg value="ldap://fsapps.company.uni:389/" /> 
     <b:constructor-arg value="dc=fsapps,dc=company,dc=uni" /> 
     <b:property name="searchFilter" value="(&amp;(userPrincipalName={0})(objectClass=user))" /> 
     <b:property name="convertSubErrorCodesToExceptions" value="true" /> 
    </b:bean> 

在我的情況下,searchFilter財產可能已經因爲現在我退卻的默認值省略。儘管我的設置和問題有很長的描述。我希望別人能從中受益。

這裏是鏈接到ActiveDirectorLdapAuthenticationProvider類文檔:http://docs.spring.io/autorepo/docs/spring-security/4.0.0.RELEASE/apidocs/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.html

我發現Wireshark來看看發生了什麼應用程序服務器和AD服務器調試這個問題之間的事情非常有幫助。

回答

5

我無法使用Context.REFERRAL =「follow」解決此問題,實際上問題出在ActiveDirectoryLdapProvider類的searchForUser()方法的代碼中。在這個方法中,使用bindPrincipal調用SpringSecurityLdapTemplate.searchForSingleEntryInternal()方法,該方法實際上是userPrincipalName,它由傳遞給構造函數的參數在第一個參數和用戶名中組成。因此,即使您將搜索過濾器設置爲除userPrincipalName以外的其他任何內容,它也會傳遞一個userPrincipalName作爲參數0.因此,具有sAMAccountName的過濾器將無法與UPN一起使用並引發異常。

searchForUser()應該被修改或擴充來檢測searchFilter需要一個用戶名而不是UPN,或者提供額外的setter來使用searchFilter的模式設置參數。

但是在沒有修改代碼的情況下,沒有辦法讓這個類在這種情況下正常工作。這就是我最終做的。我寫了我自己的類,基本上是原始ActiveDirectoryLdapAUthenticationProvider的一個拷貝,只需對searchForUser()傳遞用戶名而不是bindPrincipal到searchForSingleEntryInternal()的簡單修改即可。

這是有點廢話,你可以輸入你想要的任何搜索過濾器,但只能使用一個實際上是userPrincipalName的參數,而不是別的。

1

我有點碰到類似的問題,做了一些研究。在我們的域名爲「my.company.com」的AD中,我們似乎有兩組用戶,其中一組使用UPN,格式爲[email protected],另一組使用user2 @ somethingelse。 COM。

而當我使用org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider並嘗試使用[email protected][email protected]對用戶進行身份驗證時 - 其中只有一個取決於我的操作傳遞給構造函數的域名。

我不是AD專家,但是看着微軟科技網文章:https://technet.microsoft.com/en-us/library/cc739093(v=ws.10).aspx看起來好像UPN後綴通常和域名一樣,它不是必須的,可以加上別的後綴。引用該文章

UPN的後半部分UPN後綴標識用戶帳戶所在的域 。此UPN後綴可以是DNS 域名,林中任何域的DNS名稱,也可以是由管理員創建的替代名稱,僅用於登錄 的目的。此替代UPN後綴不需要是有效的DNS名稱。

在Active Directory中,默認的UPN後綴是用戶帳戶創建的域的 的DNS名稱。在大多數情況下,這是在Internet上註冊爲企業域的 域名。使用 替代域名作爲UPN後綴可以提供額外的 登錄安全性並簡化用於登錄林中另一個域 的名稱。

例如,如果您的組織使用深度域樹,按部門和地區組織 ,則域名可能會變得很長。該域中的用戶的默認 用戶UPN可能是 sales.westcoast.microsoft.com。該 域中的用戶的登錄名將是[email protected]。創建UPN 後綴「microsoft」將允許同一用戶使用user @ microsoft的簡單更簡單的登錄名登錄。有關 用戶帳戶的更多信息,請參閱用戶和計算機帳戶和對象名稱。

但我認爲ActiveDirectoryLdapAuthenticationProvider.java似乎假設域名與UPN後綴相同。我做了一個本地修訂,以ActiveDirectoryLdapAuthenticationProvider.java不作出這樣的假設:

String createBindPrincipal(String username) { 
    if (domain == null || username.toLowerCase().endsWith(domain) || username.contains("@")) { 
      return username; 
    } 
    return username + "@" + domain; 
} 

現在都有着各自不同的UPN後綴的用戶可以進行搜索。如果我的假設是正確的,我可能會在Spring安全性方面發現一個錯誤。

+0

我不相信這是行得通的。如果您返回的用戶名沒有附加任何域,則與實際上具有域的UPN將不會匹配。根據我的知識,您建議的解決方案已經實施到最新版本的Spring Security中。 – Achille

+0

如果用戶名已包含@後綴,則建議的修補程序僅用於不添加域名(在構造函數中傳遞)。這種方式與相同的域,說sales.westcoast.microsoft.com,可以搜索用戶@微軟。 – sreddy

+0

對,從我測試它起,這實際上是工作的。但是,您需要告訴用戶在登錄時輸入完整的username @ domain條目。這不是我的情況的解決方案,因爲大多數用戶只是不知道他們在哪個領域。 爲了解決我們的難題,我們不是將用戶複製到AD域中,而是讓每個用戶都擁有本地域中的主體,形式爲:username @ localdomain。很明顯,要使這個解決方案有效,你必須確保跨域的用戶名不會發生衝突。 – Achille

1

在Spring Security 4.1.1/SpringBoot 1.4中。0的環境中,我這樣做是這樣的(在Java中):

@Configuration 
public class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter 
{ 
    public void init (AuthenticationManagerBuilder aAuth) throws Exception 
    { 

     ActiveDirectoryLdapAuthenticationProvider 
       myProvider = new ActiveDirectoryLdapAuthenticationProvider (ldapDomain, ldapUrl); 
     aAuth.authenticationProvider (myProvider); 
     aAuth.eraseCredentials (false); 
    } 
} 

我沒有遇到任何問題,用戶可以登錄使用sAMAccountName

相關問題