首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Java未保存在凭据缓存中的Java服务票证

使用Java未保存在凭据缓存中的Java服务票证
EN

Stack Overflow用户
提问于 2017-05-04 15:18:58
回答 1查看 2.9K关注 0票数 5

我使用GSS创建了2个Kerberos演示客户端。一个在Python3,第二个在Java中。这两个客户端似乎大致等同,而且都是“工作”的,因为我得到了一个被我的Java服务主体接受的服务票。

但是,在测试中,我注意到Python客户端将服务票证保存在kerberos凭据缓存中,而Java客户端似乎没有保存票证。

我使用"klist“来查看凭证缓存的内容。

我的客户端运行在一个Lubuntu17.04虚拟机上,使用FreeIPA作为Kerberos环境。我正在使用OpenJDK 8 u131。

问题1: Java是否没有将服务票保存到凭据缓存?或者我可以修改我的代码,这样它就这样做了吗?

问题2:没有将服务票证保存到缓存中,这有什么缺点吗?

我的假设是,缓存的服务票减少了与KDC的交互,但如何使用Windows客户端保存Kerberos服务票证?上的评论表明情况并非如此,但这个微软technote说,“每次客户机想要访问这个特定的服务器时,都不需要返回到KDC”。

问题3:从python缓存的服务票在几分钟后消失--在到期日期之前很久。是什么让他们消失的?

Python代码

代码语言:javascript
复制
#!/usr/bin/python3.5

import gssapi
from io import BytesIO

server_name = 'HTTP/app-srv.acme.com@ACME.COM'
service_name = gssapi.Name(server_name)

client_ctx = gssapi.SecurityContext(name=service_name, usage='initiate')
initial_client_token = client_ctx.step()

Java代码

代码语言:javascript
复制
System.setProperty("java.security.krb5.conf","/etc/krb5.conf");
System.setProperty("javax.security.auth.useSubjectCredsOnly","false");

GSSManager manager = GSSManager.getInstance();
GSSName clientName;
GSSContext context = null;

//try catch removed for brevity
GSSName serverName = 
      manager.createName("HTTP/app-srv.acme.com@ACME.COM", null);

Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");

//use default credentials
context = manager.createContext(serverName,
    krb5Oid,
    null,
    GSSContext.DEFAULT_LIFETIME);

context.requestMutualAuth(false);
context.requestConf(false);
context.requestInteg(true);

byte[] token = new byte[0];         
token = context.initSecContext(token, 0, token.length);

编辑:

虽然最初的问题集中在使用Java来构建客户端,但是GSS并不是必须的。我对其他在Java上工作的Kerberos方法持开放态度。现在,我正在试验Apache客户端。

到目前为止,Java似乎存在两个问题:

1)它使用凭证缓存获取TGT ( Ok),但不缓存服务票(Not )。

2)不能访问密钥环类型的凭证缓存。(由行为、调试Java运行时安全类以及代码中的注释确认。对于Lubuntu / FreeIPA组合,我使用的KEYRING是开箱即用的默认值。这不适用于Windows,也可能不适用于其他Linux组合。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-07 19:13:58

编辑2:

我应该问的问题是:

由于Java没有使用凭据缓存,我如何防止重复的SGT请求对我的KDC造成影响。

我把原来的答案放在最下面,因为如果主要集中在原来的问题上。

经过另一轮的深入调试和测试,我找到了一个可以接受的解决方案。

在我最初的解决方案中使用JAAS和JAAS,而不是没有JAAS的“纯”,这就产生了很大的不同!

是的,可能存在于凭据缓存中的现有服务票证(SGT)没有被加载,也没有任何新获得的SGT写入缓存,但是KDC没有不断地被锤击(真正的问题)。

纯GSS和带有JAAS的GSS都使用客户端主体。该主题有一个内存中的privateCredentials集,用于存储TGT和SGT.

关键的区别是:

  • “纯GSS": subject + privateCredentials是在GSSContext中创建的,并且只存在于GSSContext存在的时间。
  • GSS与JAAS:主题是由JAAS在GSSContext之外创建的,因此可以为应用程序的生命周期服务,在应用程序的生命周期中跨越许多GSSContexts。

建立的第一个GSSContext将查询主题的privateCredentials以获得一个SGT,而不是找到一个,然后从KDC请求一个SGT。

SGT被添加到主题的privateCredentials中,并且由于主题的生存期比GSSContext长,所以在创建GSSContexts之后,它是可用的,就像SGT一样。这些将在主题的privateCredentials中找到SGT,并且不需要为新的SGT点击KDC。

因此,根据我特定的Java客户机,打开一次并可能运行几个小时,一切都很好。创建的第一个GSSContext将命中SGT的KDC,然后所有后续创建的GSSContexts都将使用它,直到客户机关闭为止。没有使用凭据缓存,但这并不有害。

鉴于一个活动时间短得多的客户端,多次重新打开,并且可能是并行的,那么使用/不使用凭据缓存可能是一个更严重的问题。

代码语言:javascript
复制
private void initJAASandGSS() {
    LoginContext loginContext = null;               
    TextCallbackHandler cbHandler = new TextCallbackHandler();
    try {
        loginContext = new LoginContext("wSOXClientGSSJAASLogin", cbHandler);
        loginContext.login();
        mySubject = loginContext.getSubject();
    } catch (LoginException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    gssManager = GSSManager.getInstance();

    try {
        //TODO: LAMB: This name should be got from config / built from config / serviceIdentifier
        serverName = gssManager.createName("HTTP/app-srv.acme.com@ACME.COM", null);
        Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
    } catch (GSSException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();        
    }
}

private String getGSSwJAASServiceToken()  {

    byte[] token = null;
    String encodedToken = null;

    token = Subject.doAs(mySubject, new PrivilegedAction<byte[]>(){
        public byte[] run(){
            try{

                System.setProperty("javax.security.auth.useSubjectCredsOnly","true");
                GSSContext context = gssManager.createContext(serverName,
                    krb5Oid,
                    null,
                    GSSContext.DEFAULT_LIFETIME);

                context.requestMutualAuth(false);
                context.requestConf(false);
                context.requestInteg(true);

                byte[] ret = new byte[0];           
                ret = context.initSecContext(ret, 0, ret.length);

                context.dispose();

                return ret;

            } catch(Exception e){
                Log.log(Log.ERROR, e);
                throw new otms.util.OTMSRuntimeException("Start Client (Kerberos) failed, cause: " + e.getMessage());
            }
        }
    });

    encodedToken = Base64.getEncoder().encodeToString(token);
    return encodedToken;
}

结束编辑2:原始答案如下:

问题1: Java是否没有将服务票保存到凭据缓存?或者我可以修改我的代码,这样它就这样做了吗?

编辑:根本原因分析。

在调试sun.security.*类很多小时之后,我现在了解了GSS和sun.security代码正在做/不做什么--至少在Java 8u 131中是这样的。

在本例中,我们有一个凭证缓存,它是Java可以访问的类型,包含有效的票证授予票(TGT)和有效的服务票证(SGT)。

1)创建客户机主体时,从缓存(Credentials.acquireTGTFromCache())加载TGT,并将其存储在主题的privateCredentials集中。-> (OK)

只有TGT被加载,TGT没有加载并保存到主题privateCredentials中。->(不确定)

2)稍后,在GSSContext.initSecContext()流程的深处,安全代码实际上试图从主题的privateCredentials中检索服务票证。相关代码是Krb5Context.initSecContext() / KrbUtils.getTicket() / SubjectComber.find()/findAux()。但是,由于SGT从未在步骤1中加载过,因此不会找到SGT!因此,向KDC请求并使用一个新的SGT。

对于每个服务请求,都会重复这种情况。

为了好玩,严格地作为概念黑客的证明,我在登录和initSecContext()之间添加了几行代码来解析凭证缓存、提取凭据、转换为Krb凭据,并将它们添加到主题的私有凭据中。

在步骤2中,找到并使用现有的SGT。没有新中士被要求从KDC。

我不会发布这个黑客的代码,因为它调用我们不应该调用的sun内部类,而且我不希望激励其他任何人这样做。我也不打算用这个黑客作为解决方案。

->根本原因不是没有将服务票证保存到缓存中,而是因为服务票没有保存到缓存中;

a) SGT没有从凭据缓存加载到客户机主体的主题

( b)没有公共API或配置设置这样做。

这会影响GSS的使用和不使用JAAS。

那我该怎么办呢?

(1)在JAAS中使用/GSS,每个SGT请求都会碰到KDC ->不太好。

( ii)正如Samson在下面的注释中所建议的,只在应用程序的初始登录时使用Java,然后对于所有进一步的调用,使用令牌或cookie对后续调用(一种自行构建的kerberos-light)使用另一种安全机制。

(三)考虑GSS的替代方案,如.这意味着超出了这个答案的范围,而且很可能被证明是从平底锅跳到火上。

我向Oracle提交了一个Java特性请求,建议从缓存中检索SGT并将其存储在主题凭据中(就像TGT的情况一样)。

id=JDK-8180144

问题2:没有将服务票证保存到缓存中,这有什么缺点吗?

使用服务票证的凭据缓存可以减少客户端与KDC之间的交互。由此产生的结果是,在没有缓存服务票的情况下,每个请求都需要与KDC进行交互,这可能导致KDC被锤击。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43786908

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档