diff --git a/core/src/main/java/org/springframework/security/userdetails/ldap/LdapUserDetailsService.java b/core/src/main/java/org/springframework/security/userdetails/ldap/LdapUserDetailsService.java
new file mode 100644
index 0000000000..e07cc5206c
--- /dev/null
+++ b/core/src/main/java/org/springframework/security/userdetails/ldap/LdapUserDetailsService.java
@@ -0,0 +1,44 @@
+package org.springframework.security.userdetails.ldap;
+
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.ldap.LdapUserSearch;
+import org.springframework.security.providers.ldap.LdapAuthoritiesPopulator;
+import org.springframework.security.userdetails.UserDetails;
+import org.springframework.security.userdetails.UserDetailsService;
+import org.springframework.security.userdetails.UsernameNotFoundException;
+import org.springframework.ldap.core.DirContextOperations;
+import org.springframework.util.Assert;
+
+/**
+ * LDAP implementation of UserDetailsService based around an {@link LdapUserSearch}
+ * and an {@link LdapAuthoritiesPopulator}. The final UserDetails object
+ * returned from loadUserByUsername is created by the configured UserDetailsContextMapper.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ */
+public class LdapUserDetailsService implements UserDetailsService {
+ private LdapUserSearch userSearch;
+ private LdapAuthoritiesPopulator authoritiesPopulator;
+ private UserDetailsContextMapper userDetailsMapper = new LdapUserDetailsMapper();
+
+ public LdapUserDetailsService(LdapUserSearch userSearch, LdapAuthoritiesPopulator authoritiesPopulator) {
+ Assert.notNull(userSearch, "userSearch must not be null");
+ Assert.notNull(authoritiesPopulator, "authoritiesPopulator must not be null");
+ this.userSearch = userSearch;
+ this.authoritiesPopulator = authoritiesPopulator;
+ }
+
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ DirContextOperations userData = userSearch.searchForUser(username);
+
+ GrantedAuthority[] authorities = authoritiesPopulator.getGrantedAuthorities(userData, username);
+
+ return userDetailsMapper.mapUserFromContext(userData, username, authorities);
+ }
+
+ public void setUserDetailsMapper(UserDetailsContextMapper userDetailsMapper) {
+ Assert.notNull(userDetailsMapper, "userDetailsMapper must not be null");
+ this.userDetailsMapper = userDetailsMapper;
+ }
+}