如何在java中使用LDAP与数据库?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在java中使用LDAP与数据库?相关的知识,希望对你有一定的参考价值。

我是LDAP概念及其功能的新手。我在相关网站上阅读了一些关于它的教程并安装Apache Directory Studio并按照this的说明进行操作。另一方面,我在Java有一个Spring Boot framework项目,需要使用LDAP对用户进行身份验证。我的问题是我不知道如何将我的数据库连接到LDAP以及这些如何与其他人协作?以及如何从我的LDAP项目连接到Java?我在互联网上搜索很多,但我找不到有用的文章甚至是围绕这些问题的样本。

答案

您的数据库与LDAP无关。 Spring有KerberosAuthenticationProvider,它可以针对LDAP验证用户身份。如果您需要搜索LDAP并查询其他一些数据,则必须手动执行。下面是一些代码,用于从LDAP中检索电子邮件,电话和名称。它只是概念的证明,而不是生产准备。

域test.local的所有设置 - 将其替换为您的域名。同样在krb.conf中设置您的域控制器名称。

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 

以上是关于如何在java中使用LDAP与数据库?的主要内容,如果未能解决你的问题,请参考以下文章

基于 Web 的 Java 应用程序来读取 LDAP

如何在片段中使用 GetJsonFromUrlTask​​.java

Java如何使用DN从ldap获取属性?

LDAP 的 Spring Security Java 配置

LDAP在JAVA中如何模糊查询

LDAP在JAVA中如何模糊查询