I am new to LDAP
concept and its functions. I have read some tutorial about it on the related sites and install Apache Directory Studio
and followed the instructions from this. On the other hand, I have a Java
project in Spring Boot framework
that needs to authenticate users by using LDAP
. My problem is that I do not know how I can connect my database to LDAP
and how these collaborate with each others? and how I can connect to LDAP
from my Java
project? I search alot on the Internet but I could not find useful articles or even samples around these issues.
Asked
Active
Viewed 867 times
-3

helenDeveloper
- 624
- 3
- 8
- 15
1 Answers
0
Your database is not related to LDAP. Spring have KerberosAuthenticationProvider, it can authentificate users against LDAP. If you need to search LDAP and query some additional data, you have to do it manually. Below some code to retrive email, phone and name from LDAP. It is just proof of concept and not production ready.
all settings for domain test.local - replace it with your domain name. Also in krb.conf set your domain controller name.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider;
import org.springframework.stereotype.Component;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import java.util.Hashtable;
@Component
public class ExtendedKerberosAuthentificationProvider extends KerberosAuthenticationProvider {
private final static Logger logger = LoggerFactory.getLogger(ExtendedKerberosAuthentificationProvider.class);
@Autowired
private UserService userService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Authentication auth = super.authenticate(authentication);
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken)authentication;
LdapContext ctx = getLdapContext(token.getName(), token.getCredentials().toString());
if(ctx!= null){
String phone = loadPhoneFromLDAP(token.getName(), ctx);
if(phone != null){
UserDetails details = userService.loadUserByUsername(token.getName());
UserService.User user = (UserService.User) details;
user.getAccount().setPhone(phone);
UsernamePasswordAuthenticationToken output = new UsernamePasswordAuthenticationToken(user, auth.getCredentials(), user.getAuthorities());
output.setDetails(authentication.getDetails());
output.eraseCredentials();
return output;
}else {
throw new UsernameNotFoundException("Phone not found in AD for user :" + token.getName());
}
}else{
throw new UsernameNotFoundException("Cannot create AD naming context, but user was authenticated with Kerberos");
}
}
public LdapContext getLdapContext(String user, String password){
try{
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "Simple");
env.put(Context.SECURITY_PRINCIPAL, user + "@" + Constants.DOMAIN.toUpperCase());
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(Context.REFERRAL, "follow");
env.put(Context.PROVIDER_URL, "ldap://" +Constants.DOMAIN + ":389");
logger.debug("Attempting to connect to AD...");
LdapContext ctx = new InitialLdapContext(env, null);
logger.debug("Connection Successful.");
return ctx;
}catch(NamingException ex){
logger.error("LDAP Connection: FAILED", ex);
return null;
}
}
private String loadPhoneFromLDAP(String username, LdapContext ctx) {
try {
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] attrIDs = {
"mobile",
"mail",
"canonicalName"};
constraints.setReturningAttributes(attrIDs);
NamingEnumeration answer = ctx.search("DC=test,DC=local",
"(&(objectCategory=person)(objectClass=user)(sAMAccountName="+ username +"))", constraints);
String phone = null;
if (answer.hasMore()) {
Attributes attrs = ((SearchResult) answer.next()).getAttributes();
logger.debug(attrs.get("mail").toString());
logger.debug(attrs.get("mobile").toString());
logger.debug(attrs.get("canonicalName").toString());
phone = (String) attrs.get("mobile").get();
}else{
logger.error("user not found");
}
return phone;
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
return null;
}
}
}
import ExtendedKerberosAuthentificationProvider;
import UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.kerberos.authentication.sun.GlobalSunJaasKerberosConfig;
import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient;
@Configuration
@ImportResource(value = "classpath:spring-security-context.xml")
class SecurityConfig {
@Autowired
public UserService userService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public GlobalSunJaasKerberosConfig globalSunJaasKerberosConfig(){
GlobalSunJaasKerberosConfig globalSunJaasKerberosConfig = new GlobalSunJaasKerberosConfig();
globalSunJaasKerberosConfig.setDebug(true);
globalSunJaasKerberosConfig.setKrbConfLocation("<path to krb.conf>");
return globalSunJaasKerberosConfig;
}
@Bean
public ExtendedKerberosAuthentificationProvider kerberosAuthenticationProvider() {
ExtendedKerberosAuthentificationProvider provider = new ExtendedKerberosAuthentificationProvider();
SunJaasKerberosClient client = new SunJaasKerberosClient();
client.setDebug(true);
provider.setKerberosClient(client);
provider.setUserDetailsService(userService);
return provider;
}
}
=====================
public final static String DOMAIN = "test.local";
krb.conf
[libdefaults]
default_realm = TEST.LOCAL
default_tkt_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
default_tgs_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
permitted_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
[realms]
TEST.LOCAL = {
kdc = <some-server>.test.local
default_domain = TEST.LOCAL
}
[domain_realm]
.test.local = TEST.LOCAL
test.local = TEST.LOCAL

user1516873
- 5,060
- 2
- 37
- 56
-
thank you so much. I saw [this](https://stackoverflow.com/questions/837876/could-someone-please-explain-ldap) which was so useful. and now I know that LDAP fetch data from active directory . In your answer I do not know how you set up active directory and import users in it? @user1516873 – helenDeveloper Dec 29 '17 at 21:09
-
My answer is about how to implement authentication provider using additional data from LDAP, for example, OTP implementation. It is not about how to set up AD or fill it with users, such task usually in system administator competence. – user1516873 Jan 09 '18 at 13:59