Is it possible to use Spring Security (3.1.X) to get LDAP information on another user who has been authenticated against?

I am using Spring Security to authenticate a user on an Active Directory server. The UserUserContext user interface is also introduced in the ldapAuthenticationProvider bean to provide access to additional LDAP attributes. Everything works well. I have no problem with what I want to get from an authenticated user.

The problem is that I want to get some attributes, especially the email address, from the Active Directory server from a user other than the user who is logged in. Is it possible to achieve this using what I already have or is my only option to use a completely separate method to access the LDAP attributes of another user?

[edit] Configuration follows

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) { } } 
+6
source share
2 answers

@ Perform what you did is great, although there is actually an easier way. Instead of using LdapTemplate just use the beans that you have already registered for DefaultLdapAuthoritiesPopulator and FilterBasedLdapUserSearch . That way, you can get the same UserDetails object that also has privileges filled and reuses existing code for your net.xxxx.xxxxx.utilities.CustomUserDetailsContextMapper .

Here is what you need to do:

  • Separate the beens to be entered as named beans, and use the ref attributes for the properties and constructor-arg ( DefaultLdapAuthoritiesPopulator , FilterBasedLdapUserSearch , net.xxxx.xxxxx.utilities.CustomUserDetailsContextMapper ).
  • In LdapDao paste the links to:
    • FilterBasedLdapUserSearch - userSearch
    • DefaultLdapAuthoritiesPopulator - authPop
    • net.xxxx.xxxxx.utilities.CustomUserDetailsContextMapper - userMapper
  • Add the following method to your 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; } } 

Now you can just call getUserDetails(String) to get the same object that you do when retrieving the current input context, and you can use the same code, etc.

+4
source

I finally figured out how to do this. I answer this if it helps someone else who needs it. I would be surprised if I were the only one.

First, I had to move my security-config.xml file from the WEB-INF structure and put it in the spring resource directory. contextSource bean I was able to reuse. However, I could not reuse the CustomUserDetailsContextMapper.java or CustomUserDetails.java , as they were too specific for spring security, and not just for getting LDAP data from an unverified user.

In the end, I wrote a separate class for LDAP access, in which a common contextSource was embedded. This class is below.

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; } } } 
+7
source

Source: https://habr.com/ru/post/927041/


All Articles