- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在开发一个使用 JAAS 执行身份验证的 Java 应用程序,应该按如下方式工作:(i) 当用户 uclient
的票证已经在本地缓存中时,它应该在不询问凭据的情况下对用户进行身份验证, (ii) 当缓存中没有 'uclient' 的票时,它应该询问用户名/密码并将获得的票保存到本地缓存中。
我的应用程序能够执行“i”但不能执行“ii”,它正确地验证了用户(创建主题/主体)但它不会将 Krb 票证保存到缓存中。
问题
请注意,我的应用程序必须同时在 Windows AD 和 Linux Realms 中运行。
关于我的环境和我当前代码的更多数据
我在配置了 FreeIPA 客户端和服务器的 Linux Kerberos Realm 中测试客户端应用程序。我有一个为领域 AUTHDEMO.IT 提供 KDC 的 Linux VM,以及一个被认可到 AUTHDEMO.IT 领域的 linux VM。 krb5.conf
配置:
includedir /var/lib/sss/pubconf/krb5.include.d/
[libdefaults]
default_realm = AUTHDEMO.IT
dns_lookup_realm = true
dns_lookup_kdc = true
rdns = false
ticket_lifetime = 24h
forwardable = true
udp_preference_limit = 0
default_ccache_name = KEYRING:persistent:%{uid}
[realms]
AUTHDEMO.IT = {
pkinit_anchors = FILE:/etc/ipa/ca.crt
}
[domain_realm]
.authdemo.it = AUTHDEMO.IT
authdemo.it = AUTHDEMO.IT
这是应用程序的 jaas.conf
:
JaasDemo {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true
principal=uclient
debug=true;
};
我没有指定默认缓存文件名,我已经在调试中验证它默认为:/tmp/krb5cc_1000
其中 1000 是运行用户的 uid。
在 JaasDemo 类实例中,我使用此 login
方法执行身份验证:
public LoginContext login(){
LoginContext lc = null;
try {
System.out.println("Initialize logincontext");
lc = new LoginContext("JaasLogin",
new TextCallbackHandler());
} catch (LoginException | SecurityException le) {
System.err.println("Cannot create LoginContext."
+ le.getMessage());
return lc;
}
try {
// attempt authentication
System.out.println("Attempt login");
lc.login();
} catch (LoginException le) {
System.err.println("Authentication failed:");
System.err.println(" " + le.getMessage());
return lc;
}
System.out.println("Authentication succeeded!");
return lc;
}
我已经使用此命令执行了我的应用程序(请注意详细 kerberos 日志记录的选项):
java -Dsun.security.krb5.debug=true -Dsun.security.jgss.debug=true -Djava.security.auth.login.config=jaas.conf -jar myapp.jar
以下是应用程序在不同情况下的输出,请注意,当被询问时,用户会以交互方式提供正确的凭据。第一种情况不存在的/tmp/krb5cc_1000
文件:
Initialize logincontext
Attempt login
Debug is true storeKey false useTicketCache true useKeyTab false doNotPrompt false ticketCache is null isInitiator true KeyTab is null refreshKrb5Config is false principal is uclient tryFirstPass is false useFirstPass is false storePass is false clearPass is false
Acquire TGT from Cache
>>>KinitOptions cache name is /tmp/krb5cc_1000
Principal is uclient@AUTHDEMO.IT
null credentials from Ticket Cache
**Login Handler invoked, providing username and password to login manager..**
[Krb5LoginModule] user entered username: uclient
Using builtin default etypes for default_tkt_enctypes
default etypes for default_tkt_enctypes: 18 17 16 23.
>>> KrbAsReq creating message
getKDCFromDNS using UDP
>>> KrbKdcReq send: kdc=authdemo2.authdemo.it. UDP:88, timeout=30000, number of retries =3, #bytes=143
>>> KDCCommunication: kdc=authdemo2.authdemo.it. UDP:88, timeout=30000,Attempt =1, #bytes=143
>>> KrbKdcReq send: #bytes read=283
>>>Pre-Authentication Data:
PA-DATA type = 136
>>>Pre-Authentication Data:
PA-DATA type = 19
PA-ETYPE-INFO2 etype = 18, salt = REMOVED 3@, s2kparams = null
PA-ETYPE-INFO2 etype = 17, salt = REMOVED, s2kparams = null
>>>Pre-Authentication Data:
PA-DATA type = 2
PA-ENC-TIMESTAMP
>>>Pre-Authentication Data:
PA-DATA type = 133
>>> KdcAccessibility: remove authdemo2.authdemo.it.:88
>>> KDCRep: init() encoding tag is 126 req type is 11
>>>KRBError:
cTime is Wed Jun 29 17:12:49 CEST 1988 583600369000
sTime is Wed Aug 02 15:53:28 CEST 2017 1501682008000
suSec is 981130
error code is 25
error Message is Additional pre-authentication required
cname is uclient@AUTHDEMO.IT
sname is krbtgt/AUTHDEMO.IT@AUTHDEMO.IT
eData provided.
msgType is 30
>>>Pre-Authentication Data:
PA-DATA type = 136
>>>Pre-Authentication Data:
PA-DATA type = 19
PA-ETYPE-INFO2 etype = 18, salt = REMOVED 3@, s2kparams = null
PA-ETYPE-INFO2 etype = 17, salt = REMOVED, s2kparams = null
>>>Pre-Authentication Data:
PA-DATA type = 2
PA-ENC-TIMESTAMP
>>>Pre-Authentication Data:
PA-DATA type = 133
KRBError received: NEEDED_PREAUTH
KrbAsReqBuilder: PREAUTH FAILED/REQ, re-send AS-REQ
Using builtin default etypes for default_tkt_enctypes
default etypes for default_tkt_enctypes: 18 17 16 23.
Using builtin default etypes for default_tkt_enctypes
default etypes for default_tkt_enctypes: 18 17 16 23.
>>> EType: sun.security.krb5.internal.crypto.Aes256CtsHmacSha1EType
>>> KrbAsReq creating message
getKDCFromDNS using UDP
>>> KrbKdcReq send: kdc=authdemo2.authdemo.it. UDP:88, timeout=30000, number of retries =3, #bytes=225
>>> KDCCommunication: kdc=authdemo2.authdemo.it. UDP:88, timeout=30000,Attempt =1, #bytes=225
>>> KrbKdcReq send: #bytes read=674
>>> KdcAccessibility: remove authdemo2.authdemo.it.:88
>>> EType: sun.security.krb5.internal.crypto.Aes256CtsHmacSha1EType
>>> KrbAsRep cons in KrbAsReq.getReply uclient
principal is uclient@AUTHDEMO.IT
Commit Succeeded
Authentication succeeded!
Subject.toString:
Principal: uclient@AUTHDEMO.IT
Private Credential: Ticket (hex) =
REMOVED TICKET DETAILS K.
Client Principal = uclient@AUTHDEMO.IT
Server Principal = krbtgt/AUTHDEMO.IT@AUTHDEMO.IT
Session Key = EncryptionKey: keyType=18 keyBytes (hex dump)=
REMOVED
Forwardable Ticket true
Forwarded Ticket false
Proxiable Ticket false
Proxy Ticket false
Postdated Ticket false
Renewable Ticket false
Initial Ticket false
Auth Time = Wed Aug 02 15:53:28 CEST 2017
Start Time = Wed Aug 02 15:53:28 CEST 2017
End Time = Thu Aug 03 15:53:28 CEST 2017
Renew Till = null
Client Addresses Null
第二种情况 /tmp/krb5cc_1000
文件存在,其中包含另一个用户的票证(使用 kinit -c 创建);应用程序正确验证,但获取的票证不会持久保存到缓存文件中。
klist status first than application execution:
klist -c /tmp/krb5cc_1000
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: otheruser@AUTHDEMO.IT
Valid starting Expires Service principal
08/02/2017 16:05:19 08/03/2017 16:05:13 krbtgt/AUTHDEMO.IT@AUTHDEMO.IT
应用程序的输出:
Initialize logincontext
Attempt login
Debug is true storeKey false useTicketCache true useKeyTab false doNotPrompt false ticketCache is null isInitiator true KeyTab is null refreshKrb5Config is false principal is uclient tryFirstPass is false useFirstPass is false storePass is false clearPass is false
Acquire TGT from Cache
>>>KinitOptions cache name is /tmp/krb5cc_1000
java.io.IOException: Primary principals don't match.
at sun.security.krb5.internal.ccache.FileCredentialsCache.load(FileCredentialsCache.java:179)
at sun.security.krb5.internal.ccache.FileCredentialsCache.acquireInstance(FileCredentialsCache.java:82)
at sun.security.krb5.internal.ccache.CredentialsCache.getInstance(CredentialsCache.java:83)
at sun.security.krb5.Credentials.acquireTGTFromCache(Credentials.java:333)
at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:665)
at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:617)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755)
at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
at javax.security.auth.login.LoginContext.login(LoginContext.java:587)
at it.kerberosdemo.login.JaasDemo.login(JaasDemo.java:45)
at it.kerberosdemo.login.JaasDemo.login(JaasDemo.java:27)
at it.male.kerberosdemo.client.ClientMain.main(ClientMain.java:29)
Principal is uclient@AUTHDEMO.IT
null credentials from Ticket Cache
Login Handler invokerd, providing username and password to login manager..
[Krb5LoginModule] user entered username: uclient
Using builtin default etypes for default_tkt_enctypes
default etypes for default_tkt_enctypes: 18 17 16 23.
>>> KrbAsReq creating message
getKDCFromDNS using UDP
>>> KrbKdcReq send: kdc=authdemo2.authdemo.it. UDP:88, timeout=30000, number of retries =3, #bytes=143
>>> KDCCommunication: kdc=authdemo2.authdemo.it. UDP:88, timeout=30000,Attempt =1, #bytes=143
>>> KrbKdcReq send: #bytes read=283
>>>Pre-Authentication Data:
PA-DATA type = 136
>>>Pre-Authentication Data:
PA-DATA type = 19
PA-ETYPE-INFO2 etype = 18, salt = REMOVED, s2kparams = null
PA-ETYPE-INFO2 etype = 17, salt = REMOVED, s2kparams = null
>>>Pre-Authentication Data:
PA-DATA type = 2
PA-ENC-TIMESTAMP
>>>Pre-Authentication Data:
PA-DATA type = 133
>>> KdcAccessibility: remove authdemo2.authdemo.it.:88
>>> KDCRep: init() encoding tag is 126 req type is 11
>>>KRBError:
cTime is Mon Sep 22 16:38:56 CEST 2031 1947854336000
sTime is Wed Aug 02 16:07:05 CEST 2017 1501682825000
suSec is 803283
error code is 25
error Message is Additional pre-authentication required
cname is uclient@AUTHDEMO.IT
sname is krbtgt/AUTHDEMO.IT@AUTHDEMO.IT
eData provided.
msgType is 30
>>>Pre-Authentication Data:
PA-DATA type = 136
...OMITTED IDENTICAL
klist 确认没有将“uclient”的票添加到缓存文件中。
问候
最佳答案
终于找到问题1+2的答案了
与 java 发行版捆绑在一起的 kinit
命令是一个 java 应用程序,它对进入领域/域的用户进行身份验证,并将获得的票证保存在 ccache
文件中。kinit
命令代码在 OpenJDK 的 sun.security.krb5.internal.tools
包中可用。主类是 sun.security.krb5.internal.tools.Kinit
。为了获取(验证)并保留 Kerberos 票据,您可以将所有 tool
包复制到您的应用程序中,并从 Kinit
类调用方法 main(String[ ] arv)
通过提供 cli 参数。您也可以像我所做的那样更改 Kinit
类,以便更好地与您的代码集成。
Kinit
代码对于了解内部私有(private) Kerberos 代码的内部工作原理和自定义它非常有用。例如,有一个 KDCOptions
实例,您可以手动配置它以请求可更新票证等等。让我们研究一下吧! ;-)
请考虑:
我可以确认我的代码在 OpenJDK 和 Oracle JDK 上都能正常工作。
大局
目前我的应用程序使用 Jaas 来通过查看本地 ccache
文件中的 Krb 凭据进行身份验证,如果失败,它会执行提到的 kinit
代码多于。然后,它使用更新后的 ccache
文件中的 Jaas 进行身份验证。
下一步
我目前正在尝试将 Kerberos 票证直接从主题对象中的凭据保存到 ccache。
我将尝试使用 sun.security.krb5.internal.ccache.FileCredentialCache
类,但它看起来是一种低级方法。下面看看kinit代码中CredentialCache
抽象类的使用,可能会有用。如果成功,我会更新线程。
谢谢
感谢 Michael-O 向我展示了 sun.security.krb5.internal
包,我终于在其中找到了 kinit
代码。
问候
关于java - JAAS - 无法将 Kerberos 票证保存到缓存文件,并且无法从头开始创建缓存......和其他细节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45463635/
我需要用这样的数据构建一个表: ┌────────┬───────────┬────────┐ │ ID │ Name │ Age │ ├────
我是一名优秀的程序员,十分优秀!