java连接AD(Microsoft Active Directory)模拟用户登录认证_登录认证


文章目录

  • 一、背景
  • 二、页面效果
  • 三、代码
  • LdapLoginRequest请求实体类
  • Response返回结果
  • Msg
  • ADTest测试类
  • 补充说明
  • 代码
  • 四、认证结果
  • 认证成功
  • 认证失败
  • 本人其他相关文章链接


一、背景

亲测可用,之前搜索了很多博客,啥样的都有,就是不介绍报错以及配置用处,根本不懂照抄那些配置是干啥的,稀里糊涂的按照博客搭完也跑不起来,因此记录这个。

项目背景:公司项目当前采用http协议+shiro+mysql的登录认证方式,而现在想支持ldap协议认证登录然后能够访问自己公司的项目网站。

举例说明:假设我们公司有自己的门户网站,现在我们收购了一家公司,他们数据库采用ldap存储用户数据,那么为了他们账户能登陆我们公司项目所以需要集成,而不是再把他们的账户重新在mysql再创建一遍,万一人家有1W个账户呢,不累死了且也不现实啊。

需要安装AD+kerberos,且ldap和kerberos安装在同一台服务器上,当前版本如下:

  • windows server 2016
  • 服务器IP:10.110.25.48

我公司电脑室windows10的,我是VietualBox安装的windows server 2016,类似安装个虚拟机,然后去安装AD。

二、页面效果

java连接AD(Microsoft Active Directory)模拟用户登录认证_java连接AD_02

前提条件
需要先搭建LDAP环境(AD或者Openldap)情况下,再进行如下操作比如点击“测试连接”按钮查看是否能通。

  • Upload ldap public Key按钮:上传ldap的公钥,通常用于加密通信或者验证数字签名,特别是在安全和认证领域中使用较多。
  • Upload kerberos keytab按钮:上传kerberos的keytab文件,通常用于存储主体(Principal)的加密密钥的文件,可实现用户无密码登录或者安全认证等操作。(该文件可上传可不上传,区别就在认证方式不一样而已)
  • Ldap IP urls:配置LDAP服务器的IP。
  • Ldap account name:配置用于测试连接的账户名。
  • Ldap account password:配置用于测试连接的账户密码。
  • Domain name:搭建AD与服务器的时候,配置设置的根域名。
  • 测试按钮:用于测试连接登录认证是否成功。
  • 应用按钮:用于保存数据库入库。

三、代码

LdapLoginRequest请求实体类

package com.example.ldaptest2.entity;

public class LdapLoginRequest {
    private String username;

    private String password;

    private String principal;

    /**
     * kerberos keytab文件的绝对路径
     */
    private String keytabFilePath;

    /**
     * ldap服务器标识,只能为1或2
     */
    private String ldapFlag;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPrincipal() {
        return principal;
    }

    public void setPrincipal(String principal) {
        this.principal = principal;
    }

    public String getKeytabFilePath() {
        return keytabFilePath;
    }

    public void setKeytabFilePath(String keytabFilePath) {
        this.keytabFilePath = keytabFilePath;
    }

    public String getLdapFlag() {
        return ldapFlag;
    }

    public void setLdapFlag(String ldapFlag) {
        this.ldapFlag = ldapFlag;
    }

    @Override
    public String toString() {
        return "LdapLoginRequest{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", principal='" + principal + '\'' +
                ", keytabFilePath='" + keytabFilePath + '\'' +
                ", ldapFlag='" + ldapFlag + '\'' +
                '}';
    }
}

Response返回结果

package com.example.ldaptest2;

import com.example.ldaptest2.entity.LdapLoginRequest;
import com.example.ldaptest2.entity.Response;
import com.sun.security.auth.module.Krb5LoginModule;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.security.krb5.Config;
import sun.security.krb5.KrbException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

/**
 * AD域登录认证
 */
public class ADTest {
    private static final Logger log = LoggerFactory.getLogger(ADTest.class);
    public static final String LDAP_SERVER1_CONFIG_PATH = "C:\\Users\\211145187\\Desktop\\fsdownload";
    public static final String KERBEROS_KEYTAB_CONFIG_PATH = "C:\\Users\\211145187\\Desktop\\fsdownload\\ldap.keytab";
    public static final String KRB5_CONF_FILE_NAME = "krb5.conf";
    public static final String KEYSTORE_FILE_NAME = "ldap_keystore.jks";
    //kerberos的认证命令密码:明文是ldap@1993
    public static final String KEYSTORE_PASSWORD = "bGRhcEAxOTkz";
    public static final String KEYSTORE_TYPE = "JKS";

    public static void main(String[] args) {
        LdapLoginRequest request = new LdapLoginRequest();
        request.setUsername("testuser26");
        request.setPassword("Bingo@1993");
        request.setPrincipal("testuser26@TESTLDAP.CAT.COM");
        request.setKeytabFilePath(KERBEROS_KEYTAB_CONFIG_PATH);

        File keystoreFile = new File(LDAP_SERVER1_CONFIG_PATH + File.separator + KEYSTORE_FILE_NAME);
        if (keystoreFile.exists()) {
            try {
                setCertificate(LDAP_SERVER1_CONFIG_PATH + File.separator + KEYSTORE_FILE_NAME);
            } catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException |
                    KeyManagementException e) {
                log.error("SSL证书加载异常");
                return;
            }
        }
        Response response = null;
        if (StringUtils.isNotBlank(request.getKeytabFilePath())) {
            File keytabFile = new File(request.getKeytabFilePath());
            if (keytabFile.exists()) {
                response = loginWithKeytab(request, LDAP_SERVER1_CONFIG_PATH);
                log.info("response from loginWithKeytab:{}", response);
            } else {
                log.warn("keytab file does not exit");
            }
        }
        if (response != null && response.getCode() == 200) {
            return;
        } else {
            response = loginWithPassword(request, LDAP_SERVER1_CONFIG_PATH);
            log.info("response from loginWithPassword:{}", response);
            return;
        }
    }


    private static class KerberosCallbackHandler implements javax.security.auth.callback.CallbackHandler {
        private final String username;
        private final String password;

        public KerberosCallbackHandler(String username, String password) {
            this.username = username;
            this.password = password;
        }

        @Override
        public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
            for (Callback callback : callbacks) {
                if (callback instanceof NameCallback) {
                    ((NameCallback) callback).setName(username);
                } else if (callback instanceof PasswordCallback) {
                    ((PasswordCallback) callback).setPassword(password.toCharArray());
                } else {
                    throw new UnsupportedCallbackException(callback);
                }
            }
        }
    }

    private void refreshConfig() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class<?> configClass = Config.class;
        Field instanceField = configClass.getDeclaredField("instance");
        instanceField.setAccessible(true);
        instanceField.set(null, null);
        Method refreshMethod = configClass.getDeclaredMethod("refresh");
        refreshMethod.setAccessible(true);
        refreshMethod.invoke(null);
    }

    private static Response loginWithPassword(LdapLoginRequest request, String configPath) {
        try {
            sun.security.krb5.Config.refresh();
//            refreshConfig();
        } catch (KrbException e) {
            log.error("refresh config error", e);
        }
        System.setProperty("java.security.krb5.conf", configPath + File.separator + KRB5_CONF_FILE_NAME);
        System.setProperty("sun.security.krb5.debug", "true");

        LoginContext loginContext = null;
        try {
            loginContext = new LoginContext("com.sun.security.jgss.krb5.initiate", null, new KerberosCallbackHandler(request.getUsername(), request.getPassword()),
                    new Configuration() {
                        @Override
                        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
                            Map<String, String> options = new HashMap<>();
                            options.put("useKeyTab", "false");
                            options.put("useTicketCache", "false");
                            options.put("storeKey", "true");
                            options.put("refreshKrb5Config", "true");
                            return new AppConfigurationEntry[]{
                                    new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
                                            AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options)
                            };
                        }
                    });
            loginContext.login();
            Subject subject = loginContext.getSubject();
            return checkTicket(subject);
        } catch (LoginException e) {
            log.error("login error: ", e);
            return handleException(e);
        } finally {
            try {
                if (loginContext != null) {
                    loginContext.logout();
                }
                log.info("loginWithPassword login success!");
            } catch (LoginException e) {
                log.error("logout error: ", e);
            }
        }
    }

    private static Response loginWithKeytab(LdapLoginRequest request, String configPath) {
        try {
            sun.security.krb5.Config.refresh();
//            refreshConfig();
        } catch (KrbException e) {
            log.error("refresh config error", e);
        }
        if (StringUtils.isBlank(request.getKeytabFilePath())) {
            return Response.error("非法参数异常");
        }
        File keytabFile = new File(request.getKeytabFilePath());
        if (!keytabFile.exists()) {
            return Response.error("keytab文件不存在");
        }
        System.setProperty("java.security.krb5.conf", configPath + File.separator + KRB5_CONF_FILE_NAME);
        System.setProperty("sun.security.krb5.debug", "true");
        Map<String, String> options = new Hashtable<>();
        options.put("useKeyTab", "true");
        options.put("keyTab", request.getKeytabFilePath());
        options.put("storeKey", "true");
        options.put("principal", request.getPrincipal());
        options.put("refreshKrb5Config", "true");
        options.put("useTicketCache", "false");
        options.put("debug", "true");
        LoginContext loginContext = null;
        try {
            Configuration jaasConfig = new Configuration() {
                @Override
                public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
                    return new AppConfigurationEntry[]{
                            new AppConfigurationEntry(Krb5LoginModule.class.getName(),
                                    AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options)
                    };
                }
            };
            loginContext = new LoginContext("com.sun.security.jgss.krb5.initiate", null, null, jaasConfig);
            loginContext.login();
            Subject subject = loginContext.getSubject();
            return checkTicket(subject);
        } catch (LoginException e) {
            log.error("login error: ", e);
            return handleException(e);
        } finally {
            try {
                assert loginContext != null;
                loginContext.logout();
                log.info("loginWithKeytab login success!");
            } catch (LoginException e) {
                log.error("logout error: ", e);
            }
        }
    }

    private static Response checkTicket(Subject subject) {
        log.info("subject: {}", subject);
        if (subject.getPrivateCredentials(KerberosTicket.class).isEmpty()) {
            log.info("kerberos authentication failed");
            return Response.error("kerberos认证失败");
        } else {
            log.info("kerberos authentication succeeded");
            return Response.success();
        }
    }

    private static Response handleException(Exception e) {
        if (e.getCause() != null && e.getCause() instanceof KrbException) {
            KrbException krbException = (KrbException) e.getCause();
            int returnCode = krbException.returnCode();
            log.info("returnCode:{}", returnCode);
            switch (returnCode) {
                case 6:
                    return Response.error("账号不存在");
                case 24:
                    return Response.error("密码不正确");
                default:
                    return Response.error("未知错误");
            }
        }
        return Response.error("kerberos认证失败");
    }

    private static void setCertificate(String keyStorePath) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, KeyManagementException {
        try (FileInputStream fis = new FileInputStream(keyStorePath)) {
            KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
            keyStore.load(fis, new String(Base64.getDecoder().decode(KEYSTORE_PASSWORD)).toCharArray());
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
            SSLContext.setDefault(sslContext);
        }
    }
}

Msg

package com.example.ldaptest2.enums;

import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.HashMap;
import java.util.Map;

/**
 * Msg
 *
 * @author:
 * @date: 2020-06-18
 */
@AllArgsConstructor
@Getter
public enum Msg {

    /**
     * 请求类型错误
     */
    SUCCESS(200, "success"), FAILED(20001, "Operation failed"),
    EXCUTE_ERROR(16001, "Service invocation exception, please try again later"),
    UNKNOW_ERROR(16002, "unknown error"),
    PARAM_ERROR(16003, "request param error"),
    DATA_SAVE_FAIL(16004, "data save fail"),
    ID_IS_NOT_EXIST(16005, "id isn't exist"),
    QUERY_RESULT_IS_EMPTY(16006, "request result is null"),
    NAME_IS_EXIST(16007, "name already exist"),
    ID_IS_NOT_EXIST_DATA(16008, "There is no data for the current ID"),
    DATASOURCE_NOT_EXIST(16009, "datasource not exist"),
    JDBC_EXCEPTION(16010, "jdbc connection or search exception"),
    TASK_HAS_BEEN_STOPPED(16011, "task has been stopped");

    private int code;
    private String msg;

    private static final Map<Integer, Msg> MAP = new HashMap<>();

    static {
        for (Msg msgEnum : Msg.values()) {
            MAP.put(msgEnum.code, msgEnum);
        }
    }

    /**
     * 通过code获取枚举
     *
     * @param code
     *            code
     * @return 枚举
     */
    public static Msg getByCode(int code) {
        return MAP.get(code);
    }
}

ADTest测试类

补充说明

部分补充说明:

  • 说明点1:认证方式分2种:一种是用户名+密码登录认证;另一种是用户名+keytab登录认证;
  • 说明点2:AD用户名testuser26,密码Bingo@1993,用户主体testuser26@TESTLDAP.CAT.COM,因为搭建AD环境时生成keytab采用的是主用主体,所以采用用户主体进行登录认证
  • 说明点3:LDAP公钥证书必须上传后缀名为.jks的文件,比如名称为ldap_keystore.jks,在搭建AD环境时生成的导出的其实是xxx.cer的后缀文件,但实际使用的必须是xxx.jks的文件,所以需要输入命令生成。我们采用的是,页面只能上传.cer文件,然后我后端代码执行命令生成.jks文件。
keytool -import -alias ad-server-cert -file /home/ems/ems_file/ldap/ldapServerConfig/ldap_keystore.cer -keystore /home/ems/ems_file/ldap/ldapServerConfig/ldap_keystore.jks -storepass ldap@1993
  • 说明点4:用户主体由用户名+@大写域名方式拼接而成
  • 说明点5:登录认证还需要加载配置文件krb5.conf,改配置文件内容如下,这些其实是安装kerberos时候使用的文件,具体可看我的文章了解每一项意义,Centos7.9安装kerberos
[libdefaults]
    default_realm = TESTLDAP.CAT.COM
    forwardable = true
    permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 des3-cbc-sha1 arcfour-hmac des-cbc-crc

[realms]
    TESTLDAP.CAT.COM = {
        kdc = testldap.cat.com
        admin_server = testldap.cat.com
    }

[domain_realm]
    .testldap.cat.com = TESTLDAP.CAT.COM
    testldap.cat.com = TESTLDAP.CAT.COM
  • 说明点6:认证方式解答,之所以“keytab认证方式”失败后再次调用“用户名+密码认证方式”,是因为keytab文件是需要持续更新的,假设你们单位有100人,而你上传的keytab里面只包含50人而未及时更新keytab文件,那么也需要保证所有ldap账户都能登录认证使用项目。
采用先判断keytab文件是否上传
	如果上传了,先采用“keytab认证方式”
		认证成功,则放行访问公司项目首页
		认证失败,再调用“用户名+密码认证方式”
			认证成功,则放行访问公司项目首页
			认证失败,则弹窗报错
	如果未上传,则采用“用户名+密码认证方式”
		认证成功,则放行访问公司项目首页
		认证失败,则弹窗报错

说明点7:想看keytab文件里用户主体都叫啥可以把文件上传任意一台linux环境,然后执行命令

klist -ke  <xx/xxx/ldap.keytab>

java连接AD(Microsoft Active Directory)模拟用户登录认证_java连接AD_03


说明点8:代码中的KEYSTORE_PASSWORD 是加密后的,是为了安全考虑,尽量不要使用明文,万一人家监控到你的代码参数,就泄露了。

//kerberos的认证命令密码:明文是ldap@1993
public static final String KEYSTORE_PASSWORD = "bGRhcEAxOTkz";

代码

package com.example.ldaptest2;

import com.example.ldaptest2.entity.LdapLoginRequest;
import com.example.ldaptest2.entity.Response;
import com.sun.security.auth.module.Krb5LoginModule;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.security.krb5.Config;
import sun.security.krb5.KrbException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

/**
 * AD域登录认证
 */
public class ADTest {
    private static final Logger log = LoggerFactory.getLogger(ADTest.class);
    public static final String LDAP_SERVER1_CONFIG_PATH = "C:\\Users\\211145187\\Desktop\\fsdownload";
    public static final String KERBEROS_KEYTAB_CONFIG_PATH = "C:\\Users\\211145187\\Desktop\\fsdownload\\ldap.keytab";
    public static final String KRB5_CONF_FILE_NAME = "krb5.conf";
    public static final String KEYSTORE_FILE_NAME = "ldap_keystore.jks";
    //kerberos的认证命令密码:明文是ldap@1993
    public static final String KEYSTORE_PASSWORD = "bGRhcEAxOTkz";
    public static final String KEYSTORE_TYPE = "JKS";

    public static void main(String[] args) {
        LdapLoginRequest request = new LdapLoginRequest();
        request.setUsername("testuser26");
        request.setPassword("Bingo@1993");
        request.setPrincipal("testuser26@TESTLDAP.CAT.COM");
        request.setKeytabFilePath(KERBEROS_KEYTAB_CONFIG_PATH);

        File keystoreFile = new File(LDAP_SERVER1_CONFIG_PATH + File.separator + KEYSTORE_FILE_NAME);
        if (keystoreFile.exists()) {
            try {
                setCertificate(LDAP_SERVER1_CONFIG_PATH + File.separator + KEYSTORE_FILE_NAME);
            } catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException |
                    KeyManagementException e) {
                log.error("SSL证书加载异常");
                return;
            }
        }
        Response response = null;
        if (StringUtils.isNotBlank(request.getKeytabFilePath())) {
            File keytabFile = new File(request.getKeytabFilePath());
            if (keytabFile.exists()) {
                response = loginWithKeytab(request, LDAP_SERVER1_CONFIG_PATH);
                log.info("response from loginWithKeytab:{}", response);
            } else {
                log.warn("keytab file does not exit");
            }
        }
        if (response != null && response.getCode() == 200) {
            return;
        } else {
            response = loginWithPassword(request, LDAP_SERVER1_CONFIG_PATH);
            log.info("response from loginWithPassword:{}", response);
            return;
        }
    }


    private static class KerberosCallbackHandler implements javax.security.auth.callback.CallbackHandler {
        private final String username;
        private final String password;

        public KerberosCallbackHandler(String username, String password) {
            this.username = username;
            this.password = password;
        }

        @Override
        public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
            for (Callback callback : callbacks) {
                if (callback instanceof NameCallback) {
                    ((NameCallback) callback).setName(username);
                } else if (callback instanceof PasswordCallback) {
                    ((PasswordCallback) callback).setPassword(password.toCharArray());
                } else {
                    throw new UnsupportedCallbackException(callback);
                }
            }
        }
    }

    private void refreshConfig() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class<?> configClass = Config.class;
        Field instanceField = configClass.getDeclaredField("instance");
        instanceField.setAccessible(true);
        instanceField.set(null, null);
        Method refreshMethod = configClass.getDeclaredMethod("refresh");
        refreshMethod.setAccessible(true);
        refreshMethod.invoke(null);
    }

    private static Response loginWithPassword(LdapLoginRequest request, String configPath) {
        try {
            sun.security.krb5.Config.refresh();
//            refreshConfig();
        } catch (KrbException e) {
            log.error("refresh config error", e);
        }
        System.setProperty("java.security.krb5.conf", configPath + File.separator + KRB5_CONF_FILE_NAME);
        System.setProperty("sun.security.krb5.debug", "true");

        LoginContext loginContext = null;
        try {
            loginContext = new LoginContext("com.sun.security.jgss.krb5.initiate", null, new KerberosCallbackHandler(request.getUsername(), request.getPassword()),
                    new Configuration() {
                        @Override
                        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
                            Map<String, String> options = new HashMap<>();
                            options.put("useKeyTab", "false");
                            options.put("useTicketCache", "false");
                            options.put("storeKey", "true");
                            options.put("refreshKrb5Config", "true");
                            return new AppConfigurationEntry[]{
                                    new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
                                            AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options)
                            };
                        }
                    });
            loginContext.login();
            Subject subject = loginContext.getSubject();
            return checkTicket(subject);
        } catch (LoginException e) {
            log.error("login error: ", e);
            return handleException(e);
        } finally {
            try {
                if (loginContext != null) {
                    loginContext.logout();
                }
                log.info("loginWithPassword login success!");
            } catch (LoginException e) {
                log.error("logout error: ", e);
            }
        }
    }

    private static Response loginWithKeytab(LdapLoginRequest request, String configPath) {
        try {
            sun.security.krb5.Config.refresh();
//            refreshConfig();
        } catch (KrbException e) {
            log.error("refresh config error", e);
        }
        if (StringUtils.isBlank(request.getKeytabFilePath())) {
            return Response.error("非法参数异常");
        }
        File keytabFile = new File(request.getKeytabFilePath());
        if (!keytabFile.exists()) {
            return Response.error("keytab文件不存在");
        }
        System.setProperty("java.security.krb5.conf", configPath + File.separator + KRB5_CONF_FILE_NAME);
        System.setProperty("sun.security.krb5.debug", "true");
        Map<String, String> options = new Hashtable<>();
        options.put("useKeyTab", "true");
        options.put("keyTab", request.getKeytabFilePath());
        options.put("storeKey", "true");
        options.put("principal", request.getPrincipal());
        options.put("refreshKrb5Config", "true");
        options.put("useTicketCache", "false");
        options.put("debug", "true");
        LoginContext loginContext = null;
        try {
            Configuration jaasConfig = new Configuration() {
                @Override
                public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
                    return new AppConfigurationEntry[]{
                            new AppConfigurationEntry(Krb5LoginModule.class.getName(),
                                    AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options)
                    };
                }
            };
            loginContext = new LoginContext("com.sun.security.jgss.krb5.initiate", null, null, jaasConfig);
            loginContext.login();
            Subject subject = loginContext.getSubject();
            return checkTicket(subject);
        } catch (LoginException e) {
            log.error("login error: ", e);
            return handleException(e);
        } finally {
            try {
                assert loginContext != null;
                loginContext.logout();
                log.info("loginWithKeytab login success!");
            } catch (LoginException e) {
                log.error("logout error: ", e);
            }
        }
    }

    private static Response checkTicket(Subject subject) {
        log.info("subject: {}", subject);
        if (subject.getPrivateCredentials(KerberosTicket.class).isEmpty()) {
            log.info("kerberos authentication failed");
            return Response.error("kerberos认证失败");
        } else {
            log.info("kerberos authentication succeeded");
            return Response.success();
        }
    }

    private static Response handleException(Exception e) {
        if (e.getCause() != null && e.getCause() instanceof KrbException) {
            KrbException krbException = (KrbException) e.getCause();
            int returnCode = krbException.returnCode();
            log.info("returnCode:{}", returnCode);
            switch (returnCode) {
                case 6:
                    return Response.error("账号不存在");
                case 24:
                    return Response.error("密码不正确");
                default:
                    return Response.error("未知错误");
            }
        }
        return Response.error("kerberos认证失败");
    }

    private static void setCertificate(String keyStorePath) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, KeyManagementException {
        try (FileInputStream fis = new FileInputStream(keyStorePath)) {
            KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
            keyStore.load(fis, new String(Base64.getDecoder().decode(KEYSTORE_PASSWORD)).toCharArray());
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
            SSLContext.setDefault(sslContext);
        }
    }
}

四、认证结果

认证成功

E:\Java8\jdk1.8.0_192\bin\java.exe "-javaagent:E:\JetBrains\IntelliJ IDEA 2020.3.1\lib\idea_rt.jar=10827:E:\JetBrains\IntelliJ IDEA 2020.3.1\bin" -Dfile.encoding=UTF-8 -classpath E:\Java8\jdk1.8.0_192\jre\lib\charsets.jar;E:\Java8\jdk1.8.0_192\jre\lib\deploy.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\access-bridge-64.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\cldrdata.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\dnsns.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\jaccess.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\jfxrt.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\localedata.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\nashorn.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\sunec.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\sunjce_provider.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\sunmscapi.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\sunpkcs11.jar;E:\Java8\jdk1.8.0_192\jre\lib\ext\zipfs.jar;E:\Java8\jdk1.8.0_192\jre\lib\javaws.jar;E:\Java8\jdk1.8.0_192\jre\lib\jce.jar;E:\Java8\jdk1.8.0_192\jre\lib\jfr.jar;E:\Java8\jdk1.8.0_192\jre\lib\jfxswt.jar;E:\Java8\jdk1.8.0_192\jre\lib\jsse.jar;E:\Java8\jdk1.8.0_192\jre\lib\management-agent.jar;E:\Java8\jdk1.8.0_192\jre\lib\plugin.jar;E:\Java8\jdk1.8.0_192\jre\lib\resources.jar;E:\Java8\jdk1.8.0_192\jre\lib\rt.jar;G:\WorkSpace\ldap-test2\target\test-classes;G:\WorkSpace\ldap-test2\target\classes;E:\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-starter-web\1.4.7.RELEASE\spring-boot-starter-web-1.4.7.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-starter\1.4.7.RELEASE\spring-boot-starter-1.4.7.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot\1.4.7.RELEASE\spring-boot-1.4.7.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-autoconfigure\1.4.7.RELEASE\spring-boot-autoconfigure-1.4.7.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-starter-logging\1.4.7.RELEASE\spring-boot-starter-logging-1.4.7.RELEASE.jar;E:\apache-maven-3.6.3\repository\ch\qos\logback\logback-classic\1.1.11\logback-classic-1.1.11.jar;E:\apache-maven-3.6.3\repository\ch\qos\logback\logback-core\1.1.11\logback-core-1.1.11.jar;E:\apache-maven-3.6.3\repository\org\slf4j\jul-to-slf4j\1.7.25\jul-to-slf4j-1.7.25.jar;E:\apache-maven-3.6.3\repository\org\slf4j\log4j-over-slf4j\1.7.25\log4j-over-slf4j-1.7.25.jar;E:\apache-maven-3.6.3\repository\org\yaml\snakeyaml\1.17\snakeyaml-1.17.jar;E:\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-starter-tomcat\1.4.7.RELEASE\spring-boot-starter-tomcat-1.4.7.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\apache\tomcat\embed\tomcat-embed-core\8.5.15\tomcat-embed-core-8.5.15.jar;E:\apache-maven-3.6.3\repository\org\apache\tomcat\embed\tomcat-embed-el\8.5.15\tomcat-embed-el-8.5.15.jar;E:\apache-maven-3.6.3\repository\org\apache\tomcat\embed\tomcat-embed-websocket\8.5.15\tomcat-embed-websocket-8.5.15.jar;E:\apache-maven-3.6.3\repository\org\hibernate\hibernate-validator\5.2.5.Final\hibernate-validator-5.2.5.Final.jar;E:\apache-maven-3.6.3\repository\javax\validation\validation-api\1.1.0.Final\validation-api-1.1.0.Final.jar;E:\apache-maven-3.6.3\repository\org\jboss\logging\jboss-logging\3.3.1.Final\jboss-logging-3.3.1.Final.jar;E:\apache-maven-3.6.3\repository\com\fasterxml\classmate\1.3.3\classmate-1.3.3.jar;E:\apache-maven-3.6.3\repository\com\fasterxml\jackson\core\jackson-databind\2.8.8\jackson-databind-2.8.8.jar;E:\apache-maven-3.6.3\repository\com\fasterxml\jackson\core\jackson-annotations\2.8.8\jackson-annotations-2.8.8.jar;E:\apache-maven-3.6.3\repository\com\fasterxml\jackson\core\jackson-core\2.8.8\jackson-core-2.8.8.jar;E:\apache-maven-3.6.3\repository\org\springframework\spring-web\4.3.9.RELEASE\spring-web-4.3.9.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\spring-webmvc\4.3.9.RELEASE\spring-webmvc-4.3.9.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\projectlombok\lombok\1.18.22\lombok-1.18.22.jar;E:\apache-maven-3.6.3\repository\junit\junit\4.13\junit-4.13.jar;E:\apache-maven-3.6.3\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;E:\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-starter-test\1.4.7.RELEASE\spring-boot-starter-test-1.4.7.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-test\1.4.7.RELEASE\spring-boot-test-1.4.7.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-test-autoconfigure\1.4.7.RELEASE\spring-boot-test-autoconfigure-1.4.7.RELEASE.jar;E:\apache-maven-3.6.3\repository\com\jayway\jsonpath\json-path\2.2.0\json-path-2.2.0.jar;E:\apache-maven-3.6.3\repository\net\minidev\json-smart\2.2.1\json-smart-2.2.1.jar;E:\apache-maven-3.6.3\repository\net\minidev\accessors-smart\1.1\accessors-smart-1.1.jar;E:\apache-maven-3.6.3\repository\org\ow2\asm\asm\5.0.3\asm-5.0.3.jar;E:\apache-maven-3.6.3\repository\org\assertj\assertj-core\2.5.0\assertj-core-2.5.0.jar;E:\apache-maven-3.6.3\repository\org\mockito\mockito-core\1.10.19\mockito-core-1.10.19.jar;E:\apache-maven-3.6.3\repository\org\objenesis\objenesis\2.1\objenesis-2.1.jar;E:\apache-maven-3.6.3\repository\org\hamcrest\hamcrest-library\1.3\hamcrest-library-1.3.jar;E:\apache-maven-3.6.3\repository\org\skyscreamer\jsonassert\1.3.0\jsonassert-1.3.0.jar;E:\apache-maven-3.6.3\repository\org\json\json\20140107\json-20140107.jar;E:\apache-maven-3.6.3\repository\org\springframework\spring-core\4.3.9.RELEASE\spring-core-4.3.9.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\spring-test\4.3.9.RELEASE\spring-test-4.3.9.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-starter-security\1.4.7.RELEASE\spring-boot-starter-security-1.4.7.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\spring-aop\4.3.9.RELEASE\spring-aop-4.3.9.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\security\spring-security-config\4.1.4.RELEASE\spring-security-config-4.1.4.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\security\spring-security-web\4.1.4.RELEASE\spring-security-web-4.1.4.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\boot\spring-boot-starter-data-ldap\2.6.3\spring-boot-starter-data-ldap-2.6.3.jar;E:\apache-maven-3.6.3\repository\org\springframework\data\spring-data-ldap\2.6.3\spring-data-ldap-2.6.3.jar;E:\apache-maven-3.6.3\repository\org\springframework\spring-context\4.3.9.RELEASE\spring-context-4.3.9.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\data\spring-data-commons\1.12.11.RELEASE\spring-data-commons-1.12.11.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\slf4j\jcl-over-slf4j\1.7.25\jcl-over-slf4j-1.7.25.jar;E:\apache-maven-3.6.3\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;E:\apache-maven-3.6.3\repository\com\sun\ldapbp\1.0\ldapbp-1.0.jar;E:\apache-maven-3.6.3\repository\org\springframework\ldap\spring-ldap-core\2.4.0\spring-ldap-core-2.4.0.jar;E:\apache-maven-3.6.3\repository\org\springframework\spring-beans\4.3.9.RELEASE\spring-beans-4.3.9.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\spring-tx\4.3.9.RELEASE\spring-tx-4.3.9.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\apache\directory\api\api-all\2.0.0\api-all-2.0.0.jar;E:\apache-maven-3.6.3\repository\org\apache\servicemix\bundles\org.apache.servicemix.bundles.xpp3\1.1.4c_7\org.apache.servicemix.bundles.xpp3-1.1.4c_7.jar;E:\apache-maven-3.6.3\repository\org\apache\servicemix\bundles\org.apache.servicemix.bundles.dom4j\2.1.1_1\org.apache.servicemix.bundles.dom4j-2.1.1_1.jar;E:\apache-maven-3.6.3\repository\org\apache\commons\commons-pool2\2.4.2\commons-pool2-2.4.2.jar;E:\apache-maven-3.6.3\repository\org\apache\mina\mina-core\2.1.3\mina-core-2.1.3.jar;E:\apache-maven-3.6.3\repository\org\apache\commons\commons-lang3\3.9\commons-lang3-3.9.jar;E:\apache-maven-3.6.3\repository\org\apache\commons\commons-collections4\4.4\commons-collections4-4.4.jar;E:\apache-maven-3.6.3\repository\org\apache\servicemix\bundles\org.apache.servicemix.bundles.antlr\2.7.7_5\org.apache.servicemix.bundles.antlr-2.7.7_5.jar;E:\apache-maven-3.6.3\repository\commons-codec\commons-codec\1.10\commons-codec-1.10.jar;E:\apache-maven-3.6.3\repository\org\springframework\security\kerberos\spring-security-kerberos-core\1.0.1.RELEASE\spring-security-kerberos-core-1.0.1.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\security\kerberos\spring-security-kerberos-client\1.0.1.RELEASE\spring-security-kerberos-client-1.0.1.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\apache\httpcomponents\httpclient\4.5.3\httpclient-4.5.3.jar;E:\apache-maven-3.6.3\repository\org\apache\httpcomponents\httpcore\4.4.6\httpcore-4.4.6.jar;E:\apache-maven-3.6.3\repository\org\springframework\security\kerberos\spring-security-kerberos-web\1.0.1.RELEASE\spring-security-kerberos-web-1.0.1.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\security\spring-security-ldap\4.2.3.RELEASE\spring-security-ldap-4.2.3.RELEASE.jar;E:\apache-maven-3.6.3\repository\org\springframework\security\spring-security-core\4.2.3.RELEASE\spring-security-core-4.2.3.RELEASE.jar;E:\apache-maven-3.6.3\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;E:\apache-maven-3.6.3\repository\org\springframework\spring-expression\4.3.9.RELEASE\spring-expression-4.3.9.RELEASE.jar com.example.ldaptest2.ADTest
Debug is  true storeKey true useTicketCache false useKeyTab true doNotPrompt false ticketCache is null isInitiator true KeyTab is C:\Users\211145187\Desktop\fsdownload\ldap.keytab refreshKrb5Config is true principal is testuser26@TESTLDAP.CAT.COM tryFirstPass is false useFirstPass is false storePass is false clearPass is false
Refreshing Kerberos configuration
principal is testuser26@TESTLDAP.CAT.COM
Will use keytab
Commit Succeeded 

10:41:07.376 [main] INFO com.example.ldaptest2.ADTest - subject: 主体: 
	主用户: testuser26@TESTLDAP.CAT.COM
	专用身份证明: Ticket (hex) = 
0000: 61 82 04 52 30 82 04 4E   A0 03 02 01 05 A1 12 1B  a..R0..N........
0010: 10 54 45 53 54 4C 44 41   50 2E 43 41 54 2E 43 4F  .TESTLDAP.CAT.CO
0020: 4D A2 25 30 23 A0 03 02   01 02 A1 1C 30 1A 1B 06  M.%0#.......0...
0030: 6B 72 62 74 67 74 1B 10   54 45 53 54 4C 44 41 50  krbtgt..TESTLDAP
0040: 2E 43 41 54 2E 43 4F 4D   A3 82 04 0A 30 82 04 06  .CAT.COM....0...
0050: A0 03 02 01 12 A1 03 02   01 02 A2 82 03 F8 04 82  ................
0060: 03 F4 32 37 7A 5F 23 6B   5A CB 5D 22 91 95 E5 B8  ..27z_#kZ.]"....
0070: 31 07 0F B2 DA F9 F8 FE   8F B5 90 FE D1 AD 70 4A  1.............pJ
0080: 0B D9 8C 5C 4A 01 D7 54   B2 94 7B 46 E6 D2 C7 EA  ...\J..T...F....
0090: C2 B2 A1 A1 C6 70 2B EC   E5 A7 AB 4F 3A 80 A6 CB  .....p+....O:...
00A0: 37 1A 9C AF 19 7F 68 A4   65 9A 8D 53 AF 36 D9 F5  7.....h.e..S.6..
00B0: F2 F4 E0 50 0A EC F3 FA   13 77 44 50 C9 1F E5 31  ...P.....wDP...1
00C0: 64 A4 A4 33 34 D0 C9 B4   D0 C9 97 61 D8 A1 C6 D1  d..34......a....
00D0: 47 3E 03 AE CE E1 9B 91   80 06 22 63 61 37 98 D3  G>........"ca7..
00E0: 64 70 8D 03 0B D1 FD 23   3B B6 AF 08 03 82 8B D3  dp.....#;.......
00F0: 08 AE 9C FE DE 81 3F C4   37 18 B3 A6 F8 CC CC 8D  ......?.7.......
0100: EE E7 3B 26 23 58 E2 1D   91 CD 07 81 AE A4 88 13  ..;&#X..........
0110: F0 D6 28 9D 4D 56 F3 80   D2 9C 07 41 DE 62 2E 8F  ..(.MV.....A.b..
0120: F7 89 F8 70 1E B1 0A FE   20 0E 07 81 19 06 C8 71  ...p.... ......q
0130: 3B D5 6B 98 C7 24 52 A0   DF 0E D2 02 EB 52 32 EF  ;.k..$R......R2.
0140: 42 2F 14 31 BF 29 FB ED   CB 62 2A AD D5 EA BD FD  B/.1.)...b*.....
0150: A6 ED A6 7E EC 55 2F F7   4C CA D7 9D E7 17 A0 2B  .....U/.L......+
0160: 36 B2 46 CB 8D D9 2C 97   97 EA C7 CA 75 30 AA 3B  6.F...,.....u0.;
0170: DD 3F 37 2E 1E 73 34 08   66 26 BF 45 D1 7E D1 99  .?7..s4.f&.E....
0180: 56 0A 4A 81 7C 15 0A 83   EB BF B3 17 F0 9C 35 C8  V.J...........5.
0190: 9A 3A 98 FD CF B9 DF 2D   2A 84 32 8B 5E D3 92 41  .:.....-*.2.^..A
01A0: 00 DF 21 D2 4F 0A 81 7A   64 E2 50 9F 9D 89 EB F1  ..!.O..zd.P.....
01B0: B3 63 4B 49 59 E8 C3 AB   97 DD 4F FA 6C 68 B1 DD  .cKIY.....O.lh..
01C0: B9 E1 5D F0 E4 49 88 D3   00 11 4C 20 A8 54 AD CC  ..]..I....L .T..
01D0: BF 52 17 FC DB 91 26 F7   59 A5 5C 6D 26 C2 78 C2  .R....&.Y.\m&.x.
01E0: EA 9E 6D CB 92 47 F5 0B   8F 10 08 95 24 DD 91 49  ..m..G......$..I
01F0: 18 45 58 BE 10 95 7F 08   71 E0 81 2E 3F 94 72 99  .EX.....q...?.r.
0200: 2C 8D D1 A7 DA 80 12 95   6D A0 4E 4B CA D9 D6 54  ,.......m.NK...T
0210: 74 63 F0 BE 9B E1 1C 8C   9E C5 A0 4E CD A9 DD 82  tc.........N....
0220: C3 BD 8C E2 70 08 6F 1E   01 F5 8A 01 90 FF CA 0A  ....p.o.........
0230: 64 FB 03 C6 88 30 C9 65   CB 81 49 C1 5C 82 BB E6  d....0.e..I.\...
0240: 72 07 A9 D5 7A EC 31 1E   40 51 DB DD 21 D0 A9 80  r...z.1.@Q..!...
0250: DF 41 A8 D1 F6 94 7C 7D   CE 0D 9B 76 2F FD E6 13  .A.........v/...
0260: 81 04 51 04 2D 80 37 A6   75 51 CF 1D E9 D4 0F 22  ..Q.-.7.uQ....."
0270: E0 FB 02 08 76 96 35 25   45 CC A7 35 AB 8B 23 05  ....v.5%E..5..#.
0280: 80 1D EC B4 BD A8 A6 AB   E4 64 DC D7 40 8D 7C 4A  .........d..@..J
0290: FC 7A D6 83 02 E9 96 52   83 9A F1 7D 85 F4 66 A0  .z.....R......f.
02A0: 71 AB AB F2 CB 99 A7 25   69 C1 86 69 84 A2 E9 D7  q......%i..i....
02B0: 07 93 77 CA 3A 0F 16 36   4C 86 E4 F1 5E 21 A3 AD  ..w.:..6L...^!..
02C0: CD 02 DA A5 DC 30 88 6B   F9 59 24 E9 C1 5C D1 35  .....0.k.Y$..\.5
02D0: 7E 6D 8D E1 73 BF BE 36   26 7E 5B 89 57 6E FB 97  .m..s..6&.[.Wn..
02E0: AB 99 B1 2F B3 EC 01 79   B7 11 06 19 97 7F 1F 11  .../...y........
02F0: C7 8D 7A 03 28 75 73 FF   2C 9B F7 0F 6E CC 7E DD  ..z.(us.,...n...
0300: F2 E4 9C A2 E6 3C C6 AC   48 C7 4C 38 67 94 E5 DD  .....<..H.L8g...
0310: CC A9 97 3B 7B 27 58 ED   9F D1 F1 FB 63 1F D8 E8  ...;.'X.....c...
0320: 6C F2 73 8D C2 50 3E D9   79 40 E8 F5 C1 75 04 1B  l.s..P>.y@...u..
0330: 0E 40 37 6F AC CD 96 00   3B C9 AA D3 F1 D0 D2 3A  .@7o....;......:
0340: C2 7E 0D A1 CC 18 4E C6   D9 A8 6D DA D8 F4 84 6E  ......N...m....n
0350: A5 9B 35 D7 A2 64 27 3C   3B 93 A9 61 86 94 6B D6  ..5..d'<;..a..k.
0360: 5E 0D B6 31 78 1D A6 83   E1 84 C3 90 1B 33 E4 E1  ^..1x........3..
0370: 6D DF 13 C1 88 B8 7F B9   FD 01 3A 49 32 5D F0 00  m.........:I2]..
0380: D9 53 97 CE 6F B0 A3 C8   64 A2 57 32 1B F7 2C 0D  .S..o...d.W2..,.
0390: EC 0E 1E 06 52 14 EA 7F   47 25 E5 4C AC 95 8D 72  ....R...G%.L...r
03A0: 31 28 A4 A7 8B F4 00 11   AB A1 9D D9 B4 B4 A4 DB  1(..............
03B0: 2A 82 75 8F EA 8E 9E 44   3D D5 23 9E C5 86 8F 81  *.u....D=.#.....
03C0: B9 3C 01 95 31 25 ED 48   26 A5 4F 91 E5 C9 AF 87  .<..1%.H&.O.....
03D0: 0E 5C B6 71 9C 82 9D 02   FA 3E 6B B5 C2 1E FE F2  .\.q.....>k.....
03E0: 32 33 54 39 A9 8B EB F1   82 1A 7E 27 11 D4 FD 2E  23T9.......'....
03F0: 37 5D 03 3B 05 D3 09 51   0F 70 9A 43 E1 44 45 1F  7].;...Q.p.C.DE.
0400: 16 48 69 64 07 E7 9E F9   28 36 4E 6F B6 97 2A EF  .Hid....(6No..*.
0410: 22 7C 2E 62 82 03 3C C2   97 D2 D0 C9 04 D0 78 00  "..b..<.......x.
0420: B9 2B 66 CA 3C F5 D1 07   50 B3 2E 0D 4B 15 1A AD  .+f.<...P...K...
0430: B8 9F 4B 54 55 C1 BC 3C   5C 1A BF 63 A4 C4 65 93  ..KTU..<\..c..e.
0440: CA 4D 9E 2C 56 33 A1 43   7A 15 B8 26 6E 4D DD A2  .M.,V3.Cz..&nM..
0450: C6 BC 5B 48 72 C7                                  ..[Hr.

Client Principal = testuser26@TESTLDAP.CAT.COM
Server Principal = krbtgt/TESTLDAP.CAT.COM@TESTLDAP.CAT.COM
Session Key = EncryptionKey: keyType=18 keyBytes (hex dump)=
0000: 76 A5 11 BD 7B B4 8B 9A   B4 7B 2D F8 F2 4D 28 62  v.........-..M(b
0010: 89 E4 5F 92 3E C3 61 C5   28 39 63 D2 96 D6 CA FA  .._.>.a.(9c.....


Forwardable Ticket true
Forwarded Ticket false
Proxiable Ticket false
Proxy Ticket false
Postdated Ticket false
Renewable Ticket false
Initial Ticket false
Auth Time = Fri Jul 05 10:41:07 CST 2024
Start Time = Fri Jul 05 10:41:07 CST 2024
End Time = Fri Jul 05 20:41:07 CST 2024
Renew Till = null
Client Addresses  Null 
	专用身份证明: C:\Users\211145187\Desktop\fsdownload\ldap.keytab for testuser26@TESTLDAP.CAT.COM

10:41:07.395 [main] INFO com.example.ldaptest2.ADTest - kerberos authentication succeeded
		[Krb5LoginModule]: Entering logout
		[Krb5LoginModule]: logged out Subject
10:41:07.398 [main] INFO com.example.ldaptest2.ADTest - loginWithKeytab login success!
10:41:07.398 [main] INFO com.example.ldaptest2.ADTest - response from loginWithKeytab:Response(code=200, msg=success, info=null)

Process finished with exit code 0

认证失败

10:42:38.883 [main] ERROR com.example.ldaptest2.ADTest - login error: 
10:42:38.884 [main] INFO com.example.ldaptest2.ADTest - returnCode:6
10:42:38.889 [main] INFO com.example.ldaptest2.ADTest - loginWithPassword login success!
10:42:38.889 [main] INFO com.example.ldaptest2.ADTest - response from loginWithPassword:Response(code=20001, msg=账号不存在, info=null)