当前位置: 首页 > 知识库问答 >
问题:

如何使用Windows Java客户端保存Kerberos服务票证?

屠嘉
2023-03-14

我已经编写了一个在Windows下运行的简单JavaHTTP客户端。客户端与需要通过SPNego进行Kerberos身份验证的Web服务器进行通信。

我遇到了两个问题:

>

  • 服务票证没有存储在我的凭据缓存中。执行请求后,我希望看到一个Kerberos服务票存储在我的凭据缓存下的C:\用户\

    如果我在循环中运行100次以下的代码,它只运行n次(其中n是1到100之间的随机数)。失败的请求返回一条401错误消息,因为Java无法检索服务票证(请记住:由于我的应用程序不在请求之间存储服务票证,所以它会尝试为每个请求从TGT获取一个新的服务票证)。我已经在这个问题的底部添加了错误消息。

    我在JDK的bin文件夹中通过kinit创建了一个TGT。以下代码段用于发出简单的GET请求:

      static void testJavaHttpKerberosAuthentication() throws IOException {
        URL obj = new URL(URI);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();
        int responseCode = con.getResponseCode();
        System.out.println("\nSending 'GET' request to URL : " + URI);
        System.out.println("Response Code : " + responseCode);
    
        BufferedReader in = new BufferedReader(
        new InputStreamReader(con.getInputStream()));
        String inputLine;
        StringBuffer response = new StringBuffer();
        while ((inputLine = in.readLine()) != null) {
          response.append(inputLine);
        }
        in.close();
    
        //print result
        System.out.println(response.toString());
      }
    

    以下是我jaas.conf的内容(如下所述):

    com.sun.security.jgss.krb5.initiate {
    com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=false useTicketCache=true;
    };
    

    我用以下参数运行我的应用程序:

    -Djava.security.auth.login.config=D:\jaas.conf
    -Dsun.security.krb5.debug=true
    -Djavax.security.auth.useSubjectCredsOnly=false
    

    我不是在用krb5。ini,因为我的客户端从域配置中获得了正确的KDC。

    我可以通过以下命令为我的凭据缓存生成TGT:

    C:\Program Files\Java\jdk1.8.0_77\bin>kinit
    Password for <user>@<domain>:
    New ticket is stored in cache file C:\Users\<user>\krb5cc_<user>
    

    最后,这里是授权失败时的异常和Kerberos调试输出(参考问题2)。请注意,ctime显然是错误的。我有过许多不同的尝试,ctime的时间跨度从1970年到2040年不等。有趣的是,并不是每个请求都会发生这种情况。

    >>>KRBError:
     cTime is Wed Jun 07 12:24:03 CEST 2017 1496831043000
     sTime is Tue Mar 29 16:38:24 CEST 2016 1459262304000
     suSec is 283371
     error code is 34
     error Message is Request is a replay
     sname is HTTP/<spn>@<domain>
     msgType is 30
     KrbException: Request is a replay (34) - PROCESS_TGS
    

    我已经尝试过使用Subject.doAs来处理JAAS,但是这会导致同样的问题。通过浏览器访问服务器运行良好(尽管这不是可比性,因为浏览器使用的是Windows本地凭据缓存AFAICT)。

    对于如何调试这样的问题,我非常感谢您的建议。

    编辑:通过KRB5CCNAME环境变量显式指定凭据缓存的路径不会更改行为。TGT似乎是从凭据缓存中获取的,但服务票证没有存储在那里。


  • 共有3个答案

    宦树
    2023-03-14

    JAAS不会将票据持久化到缓存中,您必须使用kinit或通过代码以编程方式调用kinit代码。我在这里写了一个关于这个问题的问答。

    穆锋
    2023-03-14

    关于偶尔出现的随机时间值:我们发现在krb5中设置udp_preference_limit=1。ini解决了这个问题。这有效地告诉Kerberos始终尝试先使用TCP发送包。显然,切换到UDP时存在问题(不确定是UDP还是协议之间的切换)。

    阙阳
    2023-03-14

    关于缓存

    • 您的kinit版本显然使用了Linux标准,即文件:
    • Java通常使用Windows标准,即MIT Kerberos for Windows服务管理的API:

    可能的解决方法:在Windows上使用Kerberos UI创建TGT,或者通过设置KRB5CCNAME强制Java使用文件缓存。

    参考:MIT Kerberos文档,尤其是关于硬编码默认值的最后一个链接

    ~~~~~~~

    关于随机时间值

     类似资料:
    • 我们已经实现了Kerberos java客户端,它运行良好。然而,当kerberos票证过期时,Java客户端应用程序会在控制台中请求用户名,这反过来会使应用程序挂起。在SoapUI等工具中,我们观察到当Kerberos票证过期时,系统抛出未经授权的错误。我们希望实现类似的行为,即如果Kerberos票证过期,则应抛出未经授权的错误,而不是等待用户输入凭据。请帮忙。 为Kerberos测试设置客户

    • 我正在运行JMeter,它依赖于JDK 1.8的Krb5LoginMoules。 在我看来,不能跨多个请求维护kerberos会话。这将导致HTTP 401和每次请求前重新握手。 我正试图重现一个有严重间歇性性能问题的生产环境,我希望在测试中包括Kerberos/SSO身份验证,但我无法将其设置为像使用REST服务器的Windows客户端那样运行。 REST服务器向数百个Excel加载项客户端提供

    • 问题内容: 有谁知道如何使用Java GSS-API从密钥分发中心(KDC)获取服务票证? 我有一个胖客户端应用程序,该应用程序首先使用Krb5LoginModule通过JAAS进行身份验证以从票证缓存中获取TGT(背景:Windows例如使用kerberos实现,并将票证授予票证存储在安全的存储区域中)。从LoginManager中,我获得包含TGT的Subject对象。现在,我希望当我为我的服

    • 任务:将Kerberos active directory身份验证添加到不安全的报告和数据操作桌面应用程序。此应用程序是。。。 用Stackless Python 2.7编写 使用Twisted进行客户端-服务器交互 客户端编译为exe并在Windows上运行 服务器在Linux(红帽)上运行 目前,我们从用户帐户中提取Windows网络ID(登录名)并传递到服务器,服务器会查找用户配置为具有的权

    • websocket客户端(使用Autobahn/Python和Twisted)需要连接到websocket服务器:客户端需要向服务器提供其客户端证书,客户端需要检查服务器的证书。例如,这些证书是在Kubernetes minikube安装过程中创建的。特别地: 服务器证书(据我所知为X509格式) 客户端证书~/。minikube/客户。按键 我已经检查过,我可以成功地使用这些证书密钥使用发出库伯

    • 我想在一些计算机之间建立点对点连接,这样用户就可以在没有外部服务器的情况下聊天和交换文件。我最初的想法如下: 我在服务器上制作了一个中央服务器插座,所有应用程序都可以连接到该插座。此ServerSocket跟踪已连接的套接字(客户端),并将新连接的客户端的IP和端口提供给所有其他客户端。每个客户端都会创建一个新的ServerSocket,所有客户端都可以连接到它。 换句话说:每个客户端都有一个Se