JAAS - 无法将Kerberos票证持久化到缓存文件,无法从头开始创建缓存...以及其他详细信息 [英] JAAS - fails to persist Kerberos ticket to cache file, and unable to create cache from scratch.. and other details
问题描述
我正在开发一个使用JAAS执行身份验证的Java应用程序,应该按如下方式工作:(i)当用户 uclient
的故障单已经在本地缓存中时,它应该在不询问凭证的情况下对用户进行身份验证,(ii)当uclient的票证没有在缓存中时,它应该要求输入用户名/密码并将获取的票证保存到本地缓存中。
I'm developing a Java application that performs authentication with JAAS, should work as follows: (i) when the ticket for user uclient
is already in local cache it should authenticate the user without asking credentials, (ii) when no ticket for 'uclient' is in cache it should ask for username/password and save the acquired ticket into the local cache.
我的应用程序能够执行'i'但无法执行'ii',它正确地验证用户(创建主题/主体),但它不会将Krb票证持久存储到缓存中。
My application is able to perform 'i' but is not able to perform 'ii', it authenticates correctly the user (creates the Subject/Principal) but it doesn't persist the Krb ticket into the cache.
问题
- 如何实现/实现此目标?
- 并且..这是否会在空/不存在时创建
Kerberos缓存文件? - 如何从Java中以编程方式实现缓存文件创建/初始化? - 并且..仅仅为
好奇心,Java JaaS是否能够管理linux KEYRING? (在
时,Jaas无法自动管理它们) - Java JaaS是否只能管理/保留缓存中默认主体的票证? - 或者我如何管理JaaS,我在单个缓存文件中有很多主体的票?
- How do I achieve/implement this?
- And.. is this going to create the Kerberos cache file when empty/nonexistent? - How do I realize the cache file creation/initialization programmatically from Java?
- And.. just for curiosity, is the Java JaaS able to manage the linux KEYRINGs ? (At the moment Jaas was not able to automatically manage them)
- Is Java JaaS only able to manage/persist tickets for the Default principal in the cache? - Or how do I manage with JaaS a situation where I have tickets for a lot of principals in a single cache file?
请注意我的应用程序必须在Windows AD和Linux Realms中工作。
Please note that my application has to work in Windows AD and Linux Realms both.
我的环境和我当前代码的更多数据
我正在使用FreeIPA客户端和服务器配置的Linux Kerberos Realm中测试客户端应用程序。我有一个Linux VM,它为领域AUTHDEMO.IT提供KDC,以及一个支持AUTHDEMO.IT领域的Linux VM。 krb5.conf
配置:
I'm testing the client app in a Linux Kerberos Realm configured with FreeIPA client and server. I have a Linux VM that provides the KDC for a realm AUTHDEMO.IT , and a linux VM that is endorsed into the AUTHDEMO.IT realm. krb5.conf
configuration:
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。
I have not specified the default cache file name, I have verified in debug that it defaults to: /tmp/krb5cc_1000
where 1000 is the uid of running user.
在JaasDemo类实例中,我用这个执行身份验证 login
方法:
In the JaasDemo class instance I perform authentication with this login
method:
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日志记录的选项):
I have executed my application with this command (note the options for verbose kerberos logging):
java -Dsun.security.krb5.debug=true -Dsun.security.jgss.debug=true -Djava.security.auth.login.config=jaas.conf -jar myapp.jar
以下是输出在不同情况下的应用程序,请注意,当被要求时,用户以交互方式提供正确的凭据。
第一种情况不存在 / tmp / krb5cc_1000
文件:
Here follows the output of the application in different cases, please note that when asked, the user interactively provides the right credentials.
First case nonexistent /tmp/krb5cc_1000
file:
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创建);应用程序正确验证,但获取的票证不会持久保存到缓存文件。
Second case /tmp/krb5cc_1000
file exists that contains ticket for another user (created with kinit -c); the application correctly authenticates, but the acquired ticket is not persisted to the cache file.
klist状态优先于应用程序执行:
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添加到缓存文件中的票证。
klist confirms that no ticket is added for 'uclient' into the cache file.
问候
推荐答案
最后我找到了问题的答案1 + 2
与java发行版捆绑在一起的 kinit
命令是一个java应用程序,它将用户验证到域/域并将获取的票据保存在内部一个 ccache
文件。
kinit
命令代码可在 sun.security.krb5.internal.tools
包中找到OpenJDK的。
主要类是 sun.security.krb5.internal.tools.Kinit
。要获取(验证)并保留Kerberos票证,您可以将所有工具
包复制到您的应用程序中,并从 Kinit $ c $调用c>通过提供cli参数对方法
main(String [] arv)
进行分类。您也可以像我一样更改 Kinit
类,以便更好地与您的代码集成。
The kinit
command bundled with the java distribution is a java application that authenticates the user into the realm/domain and saves the acquired ticket inside a ccache
file.
The kinit
command code is available in the sun.security.krb5.internal.tools
package of the OpenJDK.
The main class is sun.security.krb5.internal.tools.Kinit
. In order to acquire (authenticate) and persist the Kerberos tickets you can copy all the tool
package into your application and invoke from Kinit
class the method main(String[] arv)
by providing the cli arguments. You can also, as I have done, change the Kinit
class in order to integrate better with your code.
Kinit
代码非常有用,以便了解内部私有Kerberos代码的内部工作方式以及自定义它。例如,有一个 KDCOptions
实例,您可以手动配置该实例以请求更新票证等等。我们来研究吧! ; - )
Kinit
code is very useful in order to understand inner workings of internal private Kerberos code and in order to customize it. For example there is a KDCOptions
instance that you can manually configure in order to ask for a renewable ticket and much more. Let's study it! ;-)
请考虑:
- 不保证接口在未来的JDK版本中,内部代码将保持不变
- 不保证不同JDK供应商之间的内部代码接口是相同的。
我可以确认我的代码在OpenJDK和Oracle JDK上都能正常工作。
I can confirm that my code is working fine with OpenJDK and Oracle JDK both.
大图
目前,我的应用程序使用Jaas通过查看本地 ccache $ c $中的Krb凭据进行身份验证c>文件,如果失败,它会执行上面提到的
kinit
代码。然后,它从更新的 ccache
文件中与Jaas进行身份验证。
At the moment my application uses Jaas in order to authenticate by looking at Krb credentials in the local ccache
file, in case of failure it executes the kinit
code as mentioned above. Then, it authenticates with Jaas from the updated ccache
file.
下一步
我正在尝试直接从主题对象的凭据中将Kerberos票证持久化到ccache。
我会尝试使用 sun.security.krb5.internal.ccache.FileCredentialCache
class但它看起来是一种低级的方式。
让我们看看在kinit代码中使用 CredentialCache
抽象类,可能会有用。
如果成功,我会更新帖子。
I'm currently trying to persist the Kerberos Ticket to ccache directly from the Credentials in a Subject Object.
I'll try to use the sun.security.krb5.internal.ccache.FileCredentialCache
class but it looks a low-level way to go.
Let's look at the use of CredentialCache
abstract class in the kinit code, may be useful.
I'll update the thread in case of success.
谢谢
感谢Michael-O向我展示了 sun.security.krb5.internal
包,我终于找到了 kinit
代码。
Thank you to Michael-O that showed me the sun.security.krb5.internal
package where I finally found out the kinit
code.
问候
这篇关于JAAS - 无法将Kerberos票证持久化到缓存文件,无法从头开始创建缓存...以及其他详细信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!