-3

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.

helenDeveloper
  • 624
  • 3
  • 8
  • 15

1 Answers1

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