JAAS Kerberos 没有像我预期的那样从 keytab 添加密钥
JAAS Kerberos not adding keys from keytab as I expect
所以我正在尝试为 AIX 服务器(即 IBM JRE)实施 SSO/Integrated 安全系统。它使用 Kerberos 对 AD 进行身份验证。
请记住以下数据已经过清理。
命令我的 AD 管理员用于在 AD 服务器上创建密钥表文件(注意 /kvno 2)。
ktpass /princ HTTP/local.domain.com@LOCALDOMAIN.NET /mapuser PSLDAP@LOCALDOMAIN.NET /pass <PASSWORD> /crypto ALL /ptype KRB5_NT_PRINCIPAL /kvno 2 /out krb5.keytab
我的 krb5.conf 文件:
[libdefaults]
default_realm = LOCALDOMAIN.NET
default_keytab_name = FILE:/keytabs/krb.keytab
default_tkt_enctypes = rc4-hmac
default_tgs_enctypes = rc4-hmac
dns_lookup_kdc = true
dns_lookup_realm = true
[realms]
LOCALDOMAIN.NET = {
kdc = localdc08.localdomain.net:88
kdc = otherdc08.localdomain.net:88
admin_server = localdc08.localdomain.net:749
master_kdc = localdc08.localdomain.net
default_domain = LOCALDOMAIN.NET
}
[domain_realm]
.LOCALDOMAIN.NET = LOCALDOMAIN.NET
LOCALDOMAIN.NET = LOCALDOMAIN.NET
localdc08.localdomain.net = LOCALDOMAIN.NET
localdc08.localdomain.net = LOCALDOMAIN.NET
localdomain.net = LOCALDOMAIN.NET
.localdomain.net = LOCALDOMAIN.NET
[logging]
kdc = FILE:/var/krb5/log/krb5kdc.log
admin_server = FILE:/var/krb5/log/kadmin.log
kadmin_local = FILE:/var/krb5/log/kadmin_local.log
default = FILE:/var/krb5/log/krb5lib.log
这是我的 krb5Login.conf 登录模块:
krbServer {
com.ibm.security.auth.module.Krb5LoginModule required
credsType=acceptor
refreshKrb5Config=true
principal="HTTP/local.domain.com"
useKeytab="/keytabs/krb5.keytab"
debug=true;
};
这是 java 我是 运行(因为 IP 不能透露全部内容)
context = new LoginContext("krbServer");
context.login();
// Get server credentials
Subject sub = context.getSubject();
serverCred = Subject.doAs(sub, new PrivilegedExceptionAction<GSSCredential>() {
public GSSCredential run() throws GSSException {
// mechanism OID for SPNEGO authentication
Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
// null name defaults to currently logged in name
GSSCredential cred = authManager.createCredential(null,
GSSCredential.INDEFINITE_LIFETIME,
spnegoOid,
GSSCredential.ACCEPT_ONLY);
return cred;
}
});
context.logout();
当我调用上面的代码时,我得到以下调试输出:
Constructor With Arg: krbServer Version: 1.7.0 Home: /dev/jre
LoginContext Constructed
[JGSS_DBG_CRED] Thread-2 JAAS config: debug=true
[JGSS_DBG_CRED] Thread-2 JAAS config: principal=HTTP/local.domain.com
[JGSS_DBG_CRED] Thread-2 JAAS config: credsType=accept only
[JGSS_DBG_CRED] Thread-2 config: useDefaultCcache=false (default)
[JGSS_DBG_CRED] Thread-2 config: useCcache=null
[JGSS_DBG_CRED] Thread-2 config: useDefaultKeytab=false
[JGSS_DBG_CRED] Thread-2 config: useKeytab=/keytabs/krb5.keytab
[KRB_DBG_CFG] Config:Thread-2: ConfigFile: /etc/krb5/krb5.conf
[JGSS_DBG_CRED] Thread-2 JAAS config: forwardable=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: renewable=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: proxiable=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: tryFirstPass=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: useFirstPass=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: moduleBanner=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: interactive login? no
[JGSS_DBG_CRED] Thread-2 JAAS config: refreshKrb5Config = true
[KRB_DBG_CFG] Config:Thread-2: ConfigFile: /etc/krb5/krb5.conf
[KRB_DBG_KDC] KdcComm:Thread-2: >>> KdcAccessibility: reset
[KRB_DBG_KDC] KdcComm:Thread-2: >>> KdcAccessibility: reset
[JGSS_DBG_CRED] Thread-2 Try keytab for principal=HTTP/local.domain.com
[KRB_DBG_KTAB] KeyTab:Thread-2Loading the keytab file ... >>> KeyTab: load() entry length: 73
[KRB_DBG_KTAB] KeyTableInputStream:Thread-2: >>> KeyTabInputStream, readName(): LOCALDOMAIN.NET
[KRB_DBG_KTAB] KeyTableInputStream:Thread-2: >>> KeyTabInputStream, readName(): HTTP
[KRB_DBG_KTAB] KeyTableInputStream:Thread-2: >>> KeyTabInputStream, readName(): local.domain.com
[KRB_DBG_KDC] EncryptionKey:Thread-2: >>> EncryptionKey: config default key type is rc4-hmac
[KRB_DBG_KTAB] KeyTab:Thread-2: Added key: 23 version: 2
[KRB_DBG_KTAB] KeyTab:Thread-2: Ordering keys wrt default_tkt_enctypes list
[JGSS_DBG_CRED] Thread-2 No Kerberos creds in keytab for principal HTTP/local.domain.com
[JGSS_DBG_CRED] Thread-2 Login successful
[JGSS_DBG_CRED] Thread-2 kprincipal : HTTP/local.domain.com@LOCALDOMAIN.NET
[JGSS_DBG_CRED] Thread-2 HTTP/local.domain.com@LOCALDOMAIN.NET added to Subject
[JGSS_DBG_CRED] Thread-2 Attempting to add KeyTab to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
[JGSS_DBG_CRED] Thread-2 find keys for HTTP/local.domain.com@LOCALDOMAIN.NET
[KRB_DBG_KTAB] KeyTab:Thread-2: Added key: 23 version: 2
[KRB_DBG_KTAB] KeyTab:Thread-2: Ordering keys wrt default_tkt_enctypes list
[JGSS_DBG_CRED] Thread-2 No keys to add to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
LoginContext login() method executed
LoginContext getSubject() method executed
Subject doAs() method executed, serverCred Name: default Lifetime: 2147483647
[JGSS_DBG_CRED] Thread-2 KeyTab is removed from subject
[JGSS_DBG_CRED] Thread-2 KerberosKey Kerberos Principal HTTP/local.domain.com@LOCALDOMAIN.NETKey Version 2key EncryptionKey: keyType=23 keyBytes (hex dump)=
0000: <MASKED>
当我打电话给
public String validate(String encToken) {
byte[] token = Base64.decode(encToken);
GSSContext authContext;
try {
authContext = authManager.createContext(serverCred);
authContext.acceptSecContext(token, 0, token.length);
if (authContext.isEstablished()) {
return authContext.getSrcName().toString();
}
} catch (GSSException e) {
// fall through to the return
}
return null;
}
}
我发现在我的令牌上调用的 "acceptSecContext" 命令 return 是一个值。我的印象是 acceptSecContext 只有 return 是一个需要传回给发起者的值。但是,发起者并不期望返回响应。此外(更重要的是).isEstablished() 方法 returns false.
所以我的问题是
1) 上面的设置有什么问题吗?
2) 为什么调用context对象的login()方法会出现这种情况?
[JGSS_DBG_CRED] Thread-2 Attempting to add KeyTab to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
[JGSS_DBG_CRED] Thread-2 find keys for HTTP/local.domain.com@LOCALDOMAIN.NET
[KRB_DBG_KTAB] KeyTab:Thread-2: Added key: 23 version: 2
[KRB_DBG_KTAB] KeyTab:Thread-2: Ordering keys wrt default_tkt_enctypes list
[JGSS_DBG_CRED] Thread-2 No keys to add to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
如果它找到密钥 23 版本 2,为什么它会说“没有要添加到 principal@domain 的 Subject 的密钥?为什么它不添加它找到的密钥?kvno= 有问题吗? 2?
3) 我已经进行了非常详尽的搜索,但我无法确定如何解析 acceptSecContext 的输出以找出 return 值是什么。我收到的 return 值(base-64 编码)是 oQcwBaADCgEC
。
编辑:更新。来自 acceptSecContext 十六进制值的 return 值为:
0xA1 0x07 0x30 0x05 0xA0 0x03 0x0A 0x01 0x02
从以下站点 (https://msdn.microsoft.com/en-us/library/ms995330.aspx#http-sso-2_topic2) 得知第一个十六进制值 (A1) 对应于一个 NegTokenTarg。这就说得通了。
下一个八位位组应该是长度(如果长度需要更多八位位组,则最高位为 1)。由于最高位为 0,因此长度为 7 个八位字节。退房。
下一个八位位组(0x30)表示一个Constructed SEQUENCE,下一个八位位组是SEQUENCE长度(0x05); 5 个八位字节,签出。
然后我们有 0xA0、0x03、0x0A、0x01,它们表示序列元素 0 (negResult)。
最后的八位字节 (0x02) 是枚举值,即 "rejected"。
所以我的令牌被拒绝了。我如何计算出 "why"?我想我需要让 AD 团队参与进来,以查明他们到底发生了什么。
您是否尝试过手动测试 kinit 和 SPN 提供的密钥表?同样在您的 jaas.conf 中,您可能会使用 useKeyTab=true 和 keyTab="keytab_filename"。但这可能是您的 IBM JDK.
特有的东西
我已经为遇到类似问题的其他人发现了这个问题。
事实证明,OID 没有工作。
对我的 java 检索服务器凭据的代码进行以下更改解决了问题:
serverCred = Subject.doAs(sub, new PrivilegedExceptionAction<GSSCredential>() {
public GSSCredential run() throws GSSException {
// mechanism OID for SPNEGO authentication
Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
// null name defaults to currently logged in name
GSSCredential cred = authManager.createCredential(null,
GSSCredential.INDEFINITE_LIFETIME,
spnegoOid,
GSSCredential.ACCEPT_ONLY);
cred.add(null,
GSSCredential.INDEFINITE_LIFETIME,
GSSCredential.INDEFINITE_LIFETIME,
new Oid("1.2.840.113554.1.2.2"),
GSSCredential.ACCEPT_ONLY);
return cred;
}
我认为这与我没有来回协商任何事情(发起者和接受者)这一事实有关,所以 SPNEGO 从未真正有机会告诉发起者它喜欢什么机制以及什么是可用的,但是我的印象是 SPNEGO Oid 可以容纳许多不同的机制,所以我不太清楚它起作用的原因,但它起作用了。
附录:经过进一步研究,我找到了对这个问题的模糊引用,原因是 "Some functionality deep in the GSSCredential implementation in AIX"。所以你有它。
所以我正在尝试为 AIX 服务器(即 IBM JRE)实施 SSO/Integrated 安全系统。它使用 Kerberos 对 AD 进行身份验证。
请记住以下数据已经过清理。
命令我的 AD 管理员用于在 AD 服务器上创建密钥表文件(注意 /kvno 2)。
ktpass /princ HTTP/local.domain.com@LOCALDOMAIN.NET /mapuser PSLDAP@LOCALDOMAIN.NET /pass <PASSWORD> /crypto ALL /ptype KRB5_NT_PRINCIPAL /kvno 2 /out krb5.keytab
我的 krb5.conf 文件:
[libdefaults]
default_realm = LOCALDOMAIN.NET
default_keytab_name = FILE:/keytabs/krb.keytab
default_tkt_enctypes = rc4-hmac
default_tgs_enctypes = rc4-hmac
dns_lookup_kdc = true
dns_lookup_realm = true
[realms]
LOCALDOMAIN.NET = {
kdc = localdc08.localdomain.net:88
kdc = otherdc08.localdomain.net:88
admin_server = localdc08.localdomain.net:749
master_kdc = localdc08.localdomain.net
default_domain = LOCALDOMAIN.NET
}
[domain_realm]
.LOCALDOMAIN.NET = LOCALDOMAIN.NET
LOCALDOMAIN.NET = LOCALDOMAIN.NET
localdc08.localdomain.net = LOCALDOMAIN.NET
localdc08.localdomain.net = LOCALDOMAIN.NET
localdomain.net = LOCALDOMAIN.NET
.localdomain.net = LOCALDOMAIN.NET
[logging]
kdc = FILE:/var/krb5/log/krb5kdc.log
admin_server = FILE:/var/krb5/log/kadmin.log
kadmin_local = FILE:/var/krb5/log/kadmin_local.log
default = FILE:/var/krb5/log/krb5lib.log
这是我的 krb5Login.conf 登录模块:
krbServer {
com.ibm.security.auth.module.Krb5LoginModule required
credsType=acceptor
refreshKrb5Config=true
principal="HTTP/local.domain.com"
useKeytab="/keytabs/krb5.keytab"
debug=true;
};
这是 java 我是 运行(因为 IP 不能透露全部内容)
context = new LoginContext("krbServer");
context.login();
// Get server credentials
Subject sub = context.getSubject();
serverCred = Subject.doAs(sub, new PrivilegedExceptionAction<GSSCredential>() {
public GSSCredential run() throws GSSException {
// mechanism OID for SPNEGO authentication
Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
// null name defaults to currently logged in name
GSSCredential cred = authManager.createCredential(null,
GSSCredential.INDEFINITE_LIFETIME,
spnegoOid,
GSSCredential.ACCEPT_ONLY);
return cred;
}
});
context.logout();
当我调用上面的代码时,我得到以下调试输出:
Constructor With Arg: krbServer Version: 1.7.0 Home: /dev/jre
LoginContext Constructed
[JGSS_DBG_CRED] Thread-2 JAAS config: debug=true
[JGSS_DBG_CRED] Thread-2 JAAS config: principal=HTTP/local.domain.com
[JGSS_DBG_CRED] Thread-2 JAAS config: credsType=accept only
[JGSS_DBG_CRED] Thread-2 config: useDefaultCcache=false (default)
[JGSS_DBG_CRED] Thread-2 config: useCcache=null
[JGSS_DBG_CRED] Thread-2 config: useDefaultKeytab=false
[JGSS_DBG_CRED] Thread-2 config: useKeytab=/keytabs/krb5.keytab
[KRB_DBG_CFG] Config:Thread-2: ConfigFile: /etc/krb5/krb5.conf
[JGSS_DBG_CRED] Thread-2 JAAS config: forwardable=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: renewable=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: proxiable=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: tryFirstPass=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: useFirstPass=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: moduleBanner=false (default)
[JGSS_DBG_CRED] Thread-2 JAAS config: interactive login? no
[JGSS_DBG_CRED] Thread-2 JAAS config: refreshKrb5Config = true
[KRB_DBG_CFG] Config:Thread-2: ConfigFile: /etc/krb5/krb5.conf
[KRB_DBG_KDC] KdcComm:Thread-2: >>> KdcAccessibility: reset
[KRB_DBG_KDC] KdcComm:Thread-2: >>> KdcAccessibility: reset
[JGSS_DBG_CRED] Thread-2 Try keytab for principal=HTTP/local.domain.com
[KRB_DBG_KTAB] KeyTab:Thread-2Loading the keytab file ... >>> KeyTab: load() entry length: 73
[KRB_DBG_KTAB] KeyTableInputStream:Thread-2: >>> KeyTabInputStream, readName(): LOCALDOMAIN.NET
[KRB_DBG_KTAB] KeyTableInputStream:Thread-2: >>> KeyTabInputStream, readName(): HTTP
[KRB_DBG_KTAB] KeyTableInputStream:Thread-2: >>> KeyTabInputStream, readName(): local.domain.com
[KRB_DBG_KDC] EncryptionKey:Thread-2: >>> EncryptionKey: config default key type is rc4-hmac
[KRB_DBG_KTAB] KeyTab:Thread-2: Added key: 23 version: 2
[KRB_DBG_KTAB] KeyTab:Thread-2: Ordering keys wrt default_tkt_enctypes list
[JGSS_DBG_CRED] Thread-2 No Kerberos creds in keytab for principal HTTP/local.domain.com
[JGSS_DBG_CRED] Thread-2 Login successful
[JGSS_DBG_CRED] Thread-2 kprincipal : HTTP/local.domain.com@LOCALDOMAIN.NET
[JGSS_DBG_CRED] Thread-2 HTTP/local.domain.com@LOCALDOMAIN.NET added to Subject
[JGSS_DBG_CRED] Thread-2 Attempting to add KeyTab to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
[JGSS_DBG_CRED] Thread-2 find keys for HTTP/local.domain.com@LOCALDOMAIN.NET
[KRB_DBG_KTAB] KeyTab:Thread-2: Added key: 23 version: 2
[KRB_DBG_KTAB] KeyTab:Thread-2: Ordering keys wrt default_tkt_enctypes list
[JGSS_DBG_CRED] Thread-2 No keys to add to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
LoginContext login() method executed
LoginContext getSubject() method executed
Subject doAs() method executed, serverCred Name: default Lifetime: 2147483647
[JGSS_DBG_CRED] Thread-2 KeyTab is removed from subject
[JGSS_DBG_CRED] Thread-2 KerberosKey Kerberos Principal HTTP/local.domain.com@LOCALDOMAIN.NETKey Version 2key EncryptionKey: keyType=23 keyBytes (hex dump)=
0000: <MASKED>
当我打电话给
public String validate(String encToken) {
byte[] token = Base64.decode(encToken);
GSSContext authContext;
try {
authContext = authManager.createContext(serverCred);
authContext.acceptSecContext(token, 0, token.length);
if (authContext.isEstablished()) {
return authContext.getSrcName().toString();
}
} catch (GSSException e) {
// fall through to the return
}
return null;
}
}
我发现在我的令牌上调用的 "acceptSecContext" 命令 return 是一个值。我的印象是 acceptSecContext 只有 return 是一个需要传回给发起者的值。但是,发起者并不期望返回响应。此外(更重要的是).isEstablished() 方法 returns false.
所以我的问题是
1) 上面的设置有什么问题吗?
2) 为什么调用context对象的login()方法会出现这种情况?
[JGSS_DBG_CRED] Thread-2 Attempting to add KeyTab to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
[JGSS_DBG_CRED] Thread-2 find keys for HTTP/local.domain.com@LOCALDOMAIN.NET
[KRB_DBG_KTAB] KeyTab:Thread-2: Added key: 23 version: 2
[KRB_DBG_KTAB] KeyTab:Thread-2: Ordering keys wrt default_tkt_enctypes list
[JGSS_DBG_CRED] Thread-2 No keys to add to Subject for HTTP/local.domain.com@LOCALDOMAIN.NET
如果它找到密钥 23 版本 2,为什么它会说“没有要添加到 principal@domain 的 Subject 的密钥?为什么它不添加它找到的密钥?kvno= 有问题吗? 2?
3) 我已经进行了非常详尽的搜索,但我无法确定如何解析 acceptSecContext 的输出以找出 return 值是什么。我收到的 return 值(base-64 编码)是 oQcwBaADCgEC
。
编辑:更新。来自 acceptSecContext 十六进制值的 return 值为: 0xA1 0x07 0x30 0x05 0xA0 0x03 0x0A 0x01 0x02
从以下站点 (https://msdn.microsoft.com/en-us/library/ms995330.aspx#http-sso-2_topic2) 得知第一个十六进制值 (A1) 对应于一个 NegTokenTarg。这就说得通了。
下一个八位位组应该是长度(如果长度需要更多八位位组,则最高位为 1)。由于最高位为 0,因此长度为 7 个八位字节。退房。
下一个八位位组(0x30)表示一个Constructed SEQUENCE,下一个八位位组是SEQUENCE长度(0x05); 5 个八位字节,签出。
然后我们有 0xA0、0x03、0x0A、0x01,它们表示序列元素 0 (negResult)。
最后的八位字节 (0x02) 是枚举值,即 "rejected"。
所以我的令牌被拒绝了。我如何计算出 "why"?我想我需要让 AD 团队参与进来,以查明他们到底发生了什么。
您是否尝试过手动测试 kinit 和 SPN 提供的密钥表?同样在您的 jaas.conf 中,您可能会使用 useKeyTab=true 和 keyTab="keytab_filename"。但这可能是您的 IBM JDK.
特有的东西我已经为遇到类似问题的其他人发现了这个问题。
事实证明,OID 没有工作。
对我的 java 检索服务器凭据的代码进行以下更改解决了问题:
serverCred = Subject.doAs(sub, new PrivilegedExceptionAction<GSSCredential>() {
public GSSCredential run() throws GSSException {
// mechanism OID for SPNEGO authentication
Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
// null name defaults to currently logged in name
GSSCredential cred = authManager.createCredential(null,
GSSCredential.INDEFINITE_LIFETIME,
spnegoOid,
GSSCredential.ACCEPT_ONLY);
cred.add(null,
GSSCredential.INDEFINITE_LIFETIME,
GSSCredential.INDEFINITE_LIFETIME,
new Oid("1.2.840.113554.1.2.2"),
GSSCredential.ACCEPT_ONLY);
return cred;
}
我认为这与我没有来回协商任何事情(发起者和接受者)这一事实有关,所以 SPNEGO 从未真正有机会告诉发起者它喜欢什么机制以及什么是可用的,但是我的印象是 SPNEGO Oid 可以容纳许多不同的机制,所以我不太清楚它起作用的原因,但它起作用了。
附录:经过进一步研究,我找到了对这个问题的模糊引用,原因是 "Some functionality deep in the GSSCredential implementation in AIX"。所以你有它。