6

SpringSecurityを使用してActiveDirectoryサーバーに対してユーザーを認証します。CustomUserContextもldapAuthenticationProviderBeanに注入され、追加のLDAP属性へのアクセスを提供します。すべてが非常にうまく機能します。認証されたユーザーから必要なものを何でもプルできます。

私が抱えている問題は、ログインしているユーザー以外のユーザーのActive Directoryサーバーからいくつかの属性(具体的には電子メールアドレス)を取得したいということです。これは、私がすでに持っているものを活用することで実現できますか、または別のユーザーからLDAP属性にアクセスするために完全に別の方法を使用する唯一のオプションはありますか?

[編集] 構成は次のとおりです

security-config.xml

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

<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
    <property name="url" value="ldap://xxxx.xxxx.xxx:389" />
    <property name="base" value="dc=corp,dc=global,dc=xxxxx,dc=com" />
    <property name="userDn" value="CN=lna.authquery,OU=LDAPGroups,OU=NorthAmerica,DC=corp,DC=global,DC=xxxxx,DC=com" />
    <property name="password" value="xxxxxxx" />
    <property name="pooled" value="true" />
    <!-- AD Specific Setting for avoiding the partial exception error -->
    <property name="referral" value="follow" />
</bean>

<bean id="ldapAuthenticationProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider" >
    <constructor-arg>
        <bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
            <constructor-arg ref="contextSource" />
            <property name="userSearch">
                <bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
                    <constructor-arg index="0" value="" />
                    <constructor-arg index="1" value="(sAMAccountName={0})" />
                    <constructor-arg index="2" ref="contextSource" />
                </bean>
            </property>
        </bean>
    </constructor-arg>
    <constructor-arg>
        <bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
            <constructor-arg ref="contextSource" />
            <constructor-arg value="" />
            <property name="groupSearchFilter" value="(member={0})" />
            <property name="searchSubtree" value="true" />
            <!-- Settings below convert the adds the prefix ROLE_ to roles returned from AD -->
        </bean>
    </constructor-arg>
    <property name="userDetailsContextMapper">
       <bean class="net.xxxx.xxxxx.utilities.CustomUserDetailsContextMapper" />
    </property>
</bean>

<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
    <constructor-arg>
        <list>
            <ref local="ldapAuthenticationProvider" />
        </list>
    </constructor-arg>
</bean>

<sec:http pattern="/css/**" security="none"/>
<sec:http pattern="/images/**" security="none"/>
<sec:http auto-config="true" authentication-manager-ref="authenticationManager" >
    <sec:intercept-url pattern="/login.jsp*" requires-channel="https" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <sec:intercept-url pattern="/**" requires-channel="https" access="IS_AUTHENTICATED_FULLY"/>
    <sec:form-login login-page='/login.jsp' 
                    default-target-url="/home.html" 
                    authentication-failure-url="/login.jsp" />
</sec:http>  

CustomeUserDetails.java

package net.xxxx.xxxx.utilities;

import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

public class CustomUserDetails extends User {

    private static final long serialVersionUID = 1416132138315457558L;

     // extra instance variables
       final String fullname;
       final String email;
       final String title;

       public CustomUserDetails(String username, String password, boolean enabled, boolean accountNonExpired,
             boolean credentialsNonExpired, boolean accountNonLocked,
             Collection<? extends GrantedAuthority> authorities, String fullname,
             String email, String title) {

           super(username, password, enabled, accountNonExpired, credentialsNonExpired,
                accountNonLocked, authorities);

           this.fullname = fullname;
           this.email = email;
           this.title = title;
       }

       public String getFullname() {
           return this.fullname;
       }

       public String getEmail() {
           return this.email;
       }

       public String getTitle() {
           return this.title;
       }
}

CustomUserDetailsContextMapper.java

package net.xxxx.xxxxx.utilities;

import java.util.Collection;

public class CustomUserDetailsContextMapper implements UserDetailsContextMapper {

    public UserDetails mapUserFromContext(DirContextOperations ctx,
            String username, Collection<? extends GrantedAuthority> authorities) {

        String fullname = "";
        String email = "";
        String title = "";

        Attributes attributes = ctx.getAttributes();
        try {
            fullname = (String) attributes.get("displayName").get(); 
            email = (String) attributes.get("mail").get(); 
            title = (String) attributes.get("title").get(); 
        } catch (NamingException e) {
            e.printStackTrace();
        }

        CustomUserDetails details = new CustomUserDetails(username, "", true, true, true, true, authorities, fullname, email, title);
        return details;
    }

    public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {

    }

}
4

2 に答える 2

7

私はついにこれを行う方法を考え出すことになりました。これを行う必要がある他の誰かを助ける場合に備えて、私はこれに答えています。私だけだったらびっくりです。

まず、security-config.xmlファイルを WEB-INF 構造から移動し、Spring リソース ディレクトリに配置する必要がありました。contextSource再利用できた豆。ただし、これらのクラスはSpringセキュリティに固有すぎて、認証されていないユーザーからLDAPデータを取得するだけではないためCustomUserDetailsContextMapper.java、クラスを再利用できませんでした。CustomUserDetails.java

最終的に、共通の自動配線が組み込まれた LDAP アクセス用の別のクラスをcontextSource作成しました。そのクラスを以下に示します。

LdapDao.java

package net.xxxxx.xxx.dao;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import javax.naming.directory.Attributes;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.stereotype.Component;

@Component
public class LdapDao {

    LdapTemplate template;

    @Autowired
    public LdapDao(LdapContextSource contextSource) {
        template = new LdapTemplate(contextSource);
    }

    @SuppressWarnings("unchecked")
    public Map<String, String> getUserAttributes(String username) {
        Map<String, String> results = new HashMap<String, String>();

        String objectClass = "samAccountName=" + username;
        LinkedList<Map<String, String>> list = (LinkedList<Map<String, String>>) template.search("", objectClass, new UserAttributesMapper());
        if (!list.isEmpty()) {
            // Should only return one item
            results = list.get(0);
        }
        return results;
    }

    private class UserAttributesMapper implements AttributesMapper {

        @Override
        public Map<String, String> mapFromAttributes(Attributes attributes) throws javax.naming.NamingException {
            Map<String, String> map = new HashMap<String, String>();

            String fullname = (String) attributes.get("displayName").get(); 
            String email = (String) attributes.get("mail").get(); 
            String title = (String) attributes.get("title").get();

            map.put("fullname", fullname);
            map.put("email", email);
            map.put("title", title);
            return map;
        }
    }   
}
于 2012-10-17T17:05:07.680 に答える
4

@Billあなたがやったことは素晴らしいですが、実際にはもっと簡単な方法があります。に頼る代わりに、LdapTemplate既に登録した Bean を使用してDefaultLdapAuthoritiesPopulatorくださいFilterBasedLdapUserSearch。このようにしUserDetailsて、権限が設定された同じオブジェクトを取得し、既存のコードをnet.xxxx.xxxxx.utilities.CustomUserDetailsContextMapper.

必要な作業は次のとおりです。

  1. 名前付き Bean として注入する必要がある been を分割し、プロパティとs ( 、、 ) のref属性を使用します。constructor-argDefaultLdapAuthoritiesPopulatorFilterBasedLdapUserSearchnet.xxxx.xxxxx.utilities.CustomUserDetailsContextMapper
  2. あなたのLdapDao注入参照で:
    • FilterBasedLdapUserSearch-userSearch
    • DefaultLdapAuthoritiesPopulator-authPop
    • net.xxxx.xxxxx.utilities.CustomUserDetailsContextMapper-userMapper
  3. 次のメソッドを に追加しますLdapDao

.

public UserDetails getUserDetails(final String username) {
    try {
        DirContextOperations ctx = userSearch.searchForUser(username);
        return userMapper.mapUserFromContext(ctx, username,
                authPop.getGrantedAuthorities(ctx, username));
    } catch (UsernameNotFoundException ex) {
        return null;
    }
}

getUserDetails(String)これで、現在ログインしているコンテキストを取得するときに呼び出して同じオブジェクトを取得でき、同じコードなどを使用できます。

于 2013-05-17T06:47:23.600 に答える