Spring LDAP authentication with multiple user OU and multiple access CNs

六月ゝ 毕业季﹏ 提交于 2020-01-06 08:33:20

问题


How do I solve the following LDAP authentication situation using Spring Security/LDAP as much as possible.

  • User belongs to one of 2 LDAP organizational units (ou): Clients or Employees

  • User belongs to one of 3 access groups (cn - groupofuniquenames) or their subgroups (cn)

So basically it would be:

  1. Finding user's DN in LDAP (client or employee)

  2. Binding user to check password

  3. Searching one by one through all 3 access groups and their subgroups to find uniquename attribute with user's DN.

I have looked into various tutorials and examples but none of them seem to relate and I was unable to combine them. It would be easier if access group was an Organizational Unit, but it's not.

The entire page and all of it's servlets are supposed to be behind authentication.

Question is a bit specific but hopefully useful for community. Any ideas or suggestions are most welcome.

The code I currently use is modified version from spring documentation.

<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>

The above code doesn't seem to return authorities. Is there a way to send the output to debug console? Can't read LDAP logs.

Also, if I comment out the AuthoritiesPopulator, then the authentication seems to work when checking with security tags, i.e. <sec:authorize access="isAuthenticated()">logged in</sec:authorize>, but for some reason intercept-url prevent me from entering site using <security:intercept-url pattern="/site/**" access="isAuthenticated()" />. I don't understand it.


回答1:


Your step 1 and 2 are the practical default for LDAP authentication.

Regarding step 3: some LDAP servers maintain a reciprocal relationship for groups and their members. So when a user is added to a group, both the member attribute on the group and the memberOf attribute on the user are populated. This would simplify things because you can then retrieve the users' memberOf attribute and find your groups.

Since you are querying the groups, I assume this is not the case for you. My recommendation would be, to create a list of desired groups that contains the 3 main access groups and their subgroups. Depending on the desired flexibility, you should probably apply some caching there.

Next, query the LDAP server for all groups having your user as a member using (&(objectClass=groupOfUniqueNames)(member=cn=youruser,ou=some,o=org)) returning the DN list only, no attributes (for performance reasons).

Now you can go through the list of returned groups and see if your desired groups are among them.

This approach ensures that you only need one query total at login time (assuming you cache the groups list), instead of one per group.




回答2:


It appears the main problem was with specifying search base argument in DefaultLdapAuthoritiesPopulator. Changing value to "" in DefaultLdapAuthoritiesPopulator bean solved the problem and started returning user's authorities.

<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>


来源:https://stackoverflow.com/questions/24364435/spring-ldap-authentication-with-multiple-user-ou-and-multiple-access-cns

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!