具有多个用户OU和多个访问CN的Spring LDAP身份验证

时间:2014-06-23 11:11:40

标签: java spring authentication spring-security ldap

如何尽可能使用Spring Security / LDAP解决以下LDAP身份验证问题。

  • 用户属于2个LDAP组织单位之一( ou ):客户或员工

  • 用户属于3个访问组之一( cn - groupofuniquenames )或其子组( cn

基本上就是:

  1. 在LDAP(客户或员工)中查找用户的DN

  2. 绑定用户以检查密码

  3. 逐个搜索所有3个访问组及其子组,以查找具有用户DN的uniquename属性。

  4. 我已经查看了各种教程和示例,但它们似乎都没有关联,我无法将它们组合在一起。如果访问组是一个组织单位会更容易,但事实并非如此。

    整个页面及其所有servlet都应该在身份验证之后。

    问题有点具体,但希望对社区有用。任何想法或建议都是最受欢迎的。

    我目前使用的代码是spring文档中的修改版本。

    <bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
        <property name="rolePrefix" value=""></property>
    </bean>
    <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
        <constructor-arg name="decisionVoters" ref="roleVoter" />
    </bean>
    
    <security:http authentication-manager-ref="ldap-auth" access-decision-manager-ref="accessDecisionManager">
        <security:intercept-url pattern="/site/**" access="LDAP-Access-Group" />
        <security:form-login 
            login-page="/login" 
            authentication-failure-url="/denied"
            username-parameter="username" 
            password-parameter="password"
            default-target-url="/site/main" />
        <security:logout 
            invalidate-session="true" 
            logout-success-url="/login" 
            logout-url="/j_spring_security_logout" />
        <security:access-denied-handler error-page="/denied" />
        <security:session-management invalid-session-url="/login">
            <security:concurrency-control max-sessions="1" expired-url="/login" />            
        </security:session-management>
    </security:http>
    
    <bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
        <constructor-arg value="ldap://server:389/o=company,c=com"/>
    </bean>
    
    <security:authentication-manager id="ldap-auth">            
        <security:authentication-provider ref="ldapAuthProvider" />
    </security:authentication-manager>
    
    <bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
    <constructor-arg>
        <bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
            <constructor-arg ref="contextSource"/>
            <property name="userDnPatterns">
                <list>
                    <value>uid={0},ou=Employees</value>
                    <value>uid={0},ou=Clients</value>
                </list>
            </property>
        </bean>
    </constructor-arg>
    <constructor-arg>
        <bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
            <constructor-arg ref="contextSource"/>
            <constructor-arg value="ou=Access"/>
            <property name="searchSubtree" value="true"/>
            <property name="groupRoleAttribute" value="cn" />
        </bean>
    </constructor-arg>
    </bean>
    

    以上代码似乎没有返回权限。有没有办法将输出发送到调试控制台?无法读取LDAP日志。

    此外,如果我注释掉AuthoritiesPopulator,那么在使用安全标记(即<sec:authorize access="isAuthenticated()">logged in</sec:authorize>)进行检查时,身份验证似乎有效,但由于某种原因拦截网址阻止我使用<security:intercept-url pattern="/site/**" access="isAuthenticated()" />进入网站。我不明白。

2 个答案:

答案 0 :(得分:2)

您的步骤1和2是LDAP身份验证的实际默认值。

关于第3步:某些LDAP服务器为组及其成员保持互惠关系。因此,当用户添加到组时,将填充组上的member属性和用户上的memberOf属性。这会简化事情,因为您可以检索用户&#39; memberOf属性并找到您的群组。

由于您正在查询群组,我认为情况并非如此。我的建议是,创建一个包含3个主要访问组及其子组的所需组列表。根据所需的灵活性,您可能应该在那里应用一些缓存。

接下来,使用(&(objectClass=groupOfUniqueNames)(member=cn=youruser,ou=some,o=org))仅返回DN列表,没有属性(出于性能原因),查询LDAP服务器以查找将您的用户作为成员的所有组。

现在,您可以查看返回的组列表,看看您所需的组是否在其中。

此方法可确保您在登录时只需要一个查询总数(假设您缓存组列表),而不是每个组一个。

答案 1 :(得分:0)

似乎主要问题是在DefaultLdapAuthoritiesPopulator中指定搜索库参数。将价值改变为&#34;&#34;在DefaultLdapAuthoritiesPopulator bean中解决了问题并开始返回用户的权限。

<bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
    <constructor-arg value="ldap://server:389/o=company,c=com"/>
    <property name="anonymousReadOnly" value="true"/>
</bean>

<bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
    <constructor-arg>
        <bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
            <constructor-arg ref="contextSource"/>
            <property name="userDnPatterns">
                <list>
                    <value>uid={0},ou=Employees</value>
                    <value>uid={0},ou=Clients</value>
                </list>
            </property>         
        </bean>
    </constructor-arg>
    <constructor-arg>
        <bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
            <constructor-arg ref="contextSource"/>
            <constructor-arg value=""/>
            <property name="searchSubtree" value="true"/>
            <property name="groupRoleAttribute" value="cn"/>
            <property name="groupSearchFilter" value="uniquemember={0}"/>   
        </bean>
    </constructor-arg>
</bean>