You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GSSAPI通过JNDI连接LDAP遇KrbException错误求助及用户创建疑问

使用GSSAPI通过JNDI连接LDAP时遇到Kerberos数据库找不到服务器错误,及创建用户密码设置咨询

问题描述

我尝试通过GSSAPI+JNDI连接LDAP,相关代码与配置如下:

核心代码片段

URL url= this.getClass().getClassLoader().getResource("conf/jaas.conf");
System.setProperty("java.security.auth.login.config", url.getPath());
System.setProperty("sun.security.krb5.debug", "true");
String loginAppName = "test.test";
LoginContext lc = new LoginContext(loginAppName, new SampleCallbackHandler("test","password"));

lc.login();
Subject subject = lc.getSubject();
Subject.doAs(subject, new JndiAction(new String[] { "" }));

jaas.conf 配置

test.test {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true
doNotPrompt=false
debug=true;
};

JndiAction 实现

static class JndiAction implements java.security.PrivilegedAction {
        private String[] args;

        public JndiAction(String[] origArgs) {
            this.args = (String[])origArgs.clone();
        }

        public Object run() {
            performJndiOperation(args);
            return null;
        }

        private static void performJndiOperation(String[] args) {
            // Set up environment for creating initial context
            try {
                Hashtable<String, String> env = new Hashtable<>();
                env.put(Context.PROVIDER_URL, "ldap://localhost:389");
                System.setProperty("sun.security.krb5.debug", "true");

                env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
                env.put("javax.security.sasl.server.authentication", "true");
                env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
                env.put(Context.SECURITY_PRINCIPAL, "test@test.test");
                env.put(Context.SECURITY_CREDENTIALS, "password");
                InitialLdapContext context1 = new InitialLdapContext(env, null);
                context1.close();
            } catch (NamingException e) {
                e.printStackTrace();
            }
        }
    }

krb5.conf 配置

[libdefaults]
default_realm = TEST.TEST
default_tkt_enctypes = arcfour-hmac-md5
default_tgs_enctypes = arcfour-hmac-md5
permitted_enctypes = arcfour-hmac-md5

dns_lookup_kdc = true
dns_lookup_realm = false

[realms]
WORKSPACE.TEST = {
kdc = localhost
}

遇到的异常

>>> KDCRep: init() encoding tag is 126 req type is 13
>>>KRBError:
     sTime is Thu Mar 28 16:12:02 CST 2024 1711613522000
     suSec is 178908
     error code is 7
     error Message is Server not found in Kerberos database
     sname is ldap/localhost@WORKSPACE.TEST
     msgType is 30
KrbException: Server not found in Kerberos database (7)
    at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:70)
    ...(省略部分栈信息)
Caused by: KrbException: Identifier doesn't match expected value (906)
    ...

同时想咨询:使用此方式创建LDAP用户时,能否设置密码?

问题解决

1. 修复Kerberos服务器找不到的错误

从报错信息能看到,客户端请求的服务主体是ldap/localhost@WORKSPACE.TEST,但你的配置存在明显问题:

  • krb5.conf中default_realm设为TEST.TEST,但[realms]块仅配置了WORKSPACE.TEST,两者域不匹配
  • LDAP的Kerberos服务主体必须属于你配置的默认域,或需明确指定服务所属域

按以下步骤修正:

  • 统一krb5.conf的域配置:
    如果你的Kerberos实际域是WORKSPACE.TEST,修改default_realm为该值:
    [libdefaults]
    default_realm = WORKSPACE.TEST
    default_tkt_enctypes = arcfour-hmac-md5
    default_tgs_enctypes = arcfour-hmac-md5
    permitted_enctypes = arcfour-hmac-md5
    
    dns_lookup_kdc = true
    dns_lookup_realm = false
    
    [realms]
    WORKSPACE.TEST = {
    kdc = localhost
    }
    
    若实际域是TEST.TEST,则修改[realms]块:
    [realms]
    TEST.TEST = {
    kdc = localhost
    }
    
  • 确认LDAP服务已注册正确的Kerberos主体:
    在KDC上为LDAP服务器创建ldap/localhost@你的域名(如ldap/localhost@WORKSPACE.TEST)的服务主体,并生成对应keytab文件,确保LDAP服务可读取该文件。
  • 清理本地票据缓存:
    执行kdestroy命令清除旧的缓存票据,避免残留配置干扰。
  • 移除JNDI环境中的冗余配置:
    使用Subject.doAs进行GSSAPI认证时,无需设置Context.SECURITY_PRINCIPAL和Context.SECURITY_CREDENTIALS,这两个参数会与GSSAPI认证冲突,直接删除以下两行代码:
    // 删除这两行
    env.put(Context.SECURITY_PRINCIPAL, "test@test.test");
    env.put(Context.SECURITY_CREDENTIALS, "password");
    

2. 创建LDAP用户时的密码设置问题

可以设置密码,但需注意以下几点:

  • 你通过GSSAPI认证的账号必须拥有创建用户及修改密码的权限(通常是LDAP管理员权限或对应ACE权限)
  • 密码设置需适配LDAP服务器类型:
    • OpenLDAP:一般使用userPassword属性,值可采用加密格式(如SSHA、MD5),也可直接设置明文(生产环境不推荐):
      Attributes attrs = new BasicAttributes();
      attrs.put("userPassword", "newPassword");
      // 示例用户DN:"uid=newuser,ou=users,dc=workspace,dc=test"
      context1.createSubcontext("uid=newuser,ou=users,dc=workspace,dc=test", attrs);
      
    • Active Directory:需使用unicodePwd属性,值必须是UTF-16LE编码的、双引号包裹的明文密码,且必须通过SSL/TLS连接LDAP(默认端口636):
      String unicodePwd = "\"newPassword\"";
      byte[] passwordBytes = unicodePwd.getBytes(StandardCharsets.UTF_16LE);
      Attributes attrs = new BasicAttributes();
      attrs.put("unicodePwd", passwordBytes);
      // 修改用户密码示例
      context1.modifyAttributes("CN=New User,CN=Users,DC=workspace,DC=test", DirContext.REPLACE_ATTRIBUTE, attrs);
      
  • 生产环境必须使用LDAPS(SSL/TLS)进行密码相关操作,避免明文传输风险。

内容的提问来源于stack exchange,提问作者cccccyy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 00:14:53