Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JAAS-无法将Kerberos票证持久化到缓存文件,并且无法从头创建缓存。。以及其他细节_Java_Kerberos_Jaas - Fatal编程技术网

Java JAAS-无法将Kerberos票证持久化到缓存文件,并且无法从头创建缓存。。以及其他细节

Java JAAS-无法将Kerberos票证持久化到缓存文件,并且无法从头创建缓存。。以及其他细节,java,kerberos,jaas,Java,Kerberos,Jaas,我正在开发一个用JAAS执行身份验证的Java应用程序,应该如下工作:(I)当用户uclient的票证已经在本地缓存中时,它应该在不询问凭据的情况下对用户进行身份验证,(ii)当缓存中没有“uclient”的票证时,它应该请求用户名/密码,并将获取的票证保存到本地缓存中 我的应用程序能够执行“i”,但不能执行“ii”,它正确地验证用户(创建主体/主体),但不会将Krb票证持久化到缓存中 问题 我如何实现/实施这一点 和。。这会不会造成 Kerberos缓存文件为空/不存在时?-如何从Java编程

我正在开发一个用JAAS执行身份验证的Java应用程序,应该如下工作:(I)当用户
uclient
的票证已经在本地缓存中时,它应该在不询问凭据的情况下对用户进行身份验证,(ii)当缓存中没有“uclient”的票证时,它应该请求用户名/密码,并将获取的票证保存到本地缓存中

我的应用程序能够执行“i”,但不能执行“ii”,它正确地验证用户(创建主体/主体),但不会将Krb票证持久化到缓存中

问题

  • 我如何实现/实施这一点
  • 和。。这会不会造成 Kerberos缓存文件为空/不存在时?-如何从Java编程实现缓存文件的创建/初始化
  • 和。。只是为了 好奇,JavaJAAS能够管理linux密钥环吗?(在 Jaas无法自动管理它们的那一刻)
  • Java JaaS是否只能管理/持久化缓存中默认主体的票证或者,在一个缓存文件中有许多主体的票证的情况下,如何使用JaaS进行管理
  • 请注意,我的应用程序必须同时在Windows AD和Linux领域工作

    有关我的环境和当前代码的更多数据

    我正在一个配置了FreeIPA客户端和服务器的Linux Kerberos领域中测试客户端应用程序。我有一个Linux虚拟机,它为AUTHDEMO.IT领域提供KDC,还有一个Linux虚拟机,它被认可为AUTHDEMO.IT领域<代码>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; 
    };
    
    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
    
    我没有指定默认的缓存文件名,我在调试中验证了它默认为:
    /tmp/krb5cc_1000
    ,其中1000是正在运行的用户的uid

    在JaasDemo类实例中,我使用以下
    登录方法执行身份验证:

    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日志记录的选项):

    下面是应用程序在不同情况下的输出,请注意,当被询问时,用户以交互方式提供正确的凭据。 第一种情况不存在
    /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状态优先于应用程序执行:

    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
    
    应用程序的输出:

    JaasDemo {
       com.sun.security.auth.module.Krb5LoginModule required 
       useTicketCache=true
       principal=uclient
       debug=true; 
    };
    
    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”的票证添加到缓存文件中


    你不能。Java不支持将TGT或服务票证持久化回可与MIT Kerberos或Heimdal一起使用的基于文件的缓存。Oracle有一些私有类可以这样做,但我不建议这样做。

    最后我找到了问题1+2的答案

    与java发行版捆绑在一起的
    kinit
    命令是一个java应用程序,它对域/域中的用户进行身份验证,并将获取的票据保存在
    ccache
    文件中。 OpenJDK的
    sun.security.krb5.internal.tools
    包中提供了
    kinit
    命令代码。 主类是
    sun.security.krb5.internal.tools.Kinit
    。为了获取(身份验证)并保存Kerberos票证,您可以将所有
    工具
    包复制到应用程序中,并通过提供cli参数从
    Kinit
    类调用方法
    main(String[]arv)
    。您还可以像我所做的那样,更改
    Kinit
    类,以便更好地与代码集成

    Kinit
    code对于理解内部私有Kerberos代码的内部工作原理和对其进行自定义非常有用。例如,有一个
    KDCOptions
    实例,您可以手动配置该实例,以请求可续签票证等。让我们研究一下!;-)

    请考虑:

    • 不能保证内部代码的接口在未来的JDK版本中保持不变
    • 不能保证不同JDK供应商之间的内部代码接口是相同的
    我可以确认我的代码在OpenJDK和OracleJDK中都运行良好

    大局

    目前,我的应用程序使用Jaas通过查看本地
    ccache
    文件中的Krb凭据进行身份验证,如果失败,它将执行上面提到的
    kinit
    代码。然后,它使用更新的
    ccache
    文件中的Jaas进行身份验证

    下一步

    我当前正在尝试直接从Subject对象中的凭据将Kerberos票证持久化到ccache。
    我将尝试使用
    sun.security.krb5.internal.ccache.FileCredentialCache
    类,但它看起来是一种低级的方法。 让我们看一下kinit代码中
    CredentialCache
    抽象类的用法,可能会很有用。 如果成功,我将更新线程

    谢谢

    感谢Michael-O向我展示了
    sun.security.krb5.internal
    软件包,在那里我终于找到了
    kinit
    代码


    关于

    其他问题。

    3-出于好奇,Java JaaS是否能够管理linux密钥环?(此时Jaas无法自动管理它们)

    否, 内部JavaKRB类只管理文件,而不是密钥环

    4-Java JaaS是否只能管理/持久化缓存中默认主体的票证或者在我有票的情况下如何处理JaaS