使用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);
- OpenLDAP:一般使用
- 生产环境必须使用LDAPS(SSL/TLS)进行密码相关操作,避免明文传输风险。
内容的提问来源于stack exchange,提问作者cccccyy
相关产品推荐
相关产品推荐

