我已经使用GSS-API创建了2个演示Kerberos客户端。一个在Python3中,第二个在Java中。这两个客户端似乎大体上是等效的,并且都“工作”,因为我得到了一个服务票据,该票据被我的Java GSS-API服务主体所接受。
然而,在测试中,我注意到Python客户端将服务票据保存在kerberos凭据缓存中,而Java客户端似乎没有保存票据。
我使用“klist”查看凭证缓存的内容。
我的客户机运行在Lubuntu 17.04虚拟机上,使用FreeIPA作为Kerberos环境。我正在使用OpenJDK 8 u131。
问题1:Java GSS-API是否未将服务票据保存到凭据缓存?或者我可以改变我的代码吗?
问题2:服务票证没有保存到缓存有什么缺点吗?
我的假设是缓存的服务票证减少了与KDC的交互,但是关于如何使用WindowsJava客户端保存Kerberos服务票证?的评论表明情况并非如此,但此Microsoft技术说明说“客户端每次想要访问此特定服务器时都不需要返回KDC”。
问题3:python客户机缓存的服务票据在几分钟后消失——比到期日期早得多。是什么导致它们消失?
Python代码
#!/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代码
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-API构建Java Kerberos客户端,但GSS不是必须的。我对其他适用于Java的Kerberos方法持开放态度。现在我正在用Apache Kerby kerb客户端进行实验。
到目前为止,Java GSS-API似乎有两个问题:
1) 它使用凭证缓存来获取TGT(正常),但不缓存服务票据(不正常)。
2) 它无法访问KEYRING类型的凭据缓存。(通过行为、调试Java运行时安全类以及代码中的注释确认。对于Lubuntu/FreeIPA组合,我使用的KEYRING是现成的默认值。这不适用于Windows,也可能不适用于其他Linux Kerberos组合。
编辑2:
我应该问的问题是:
由于Java GSS没有使用凭证缓存,如何防止我的KDC因重复的SGT请求而受到攻击。
我把我的原始答案留在底部,因为它主要集中在原始问题上。
经过另一轮深入调试和测试,我找到了一个可以接受的解决根本问题的方法。
在JAAS中使用JavaGSS API,而不是在我的原始解决方案中使用没有JAAS的“纯”GSS,会有很大的不同!
是的,可能在凭据缓存中的现有服务票证(SGTs)没有被加载,也没有将任何新获取的SGTs写回缓存,但是KDC不会经常被敲击(真正的问题)。
纯GSS和带有JAAS的GSS都使用客户主体。主题有一个内存中的私有凭据集,用于存储TGT和SGT。
关键区别在于:
>
带有JAAS的GSS:主题是由JAAS在GSSContext之外创建的,因此可以在应用程序的生命周期内存在,在应用程序的生命周期内跨越许多GSSContext。
建立的第一个GSSContext将查询主题的私有凭据以获取SGT,而不是找到一个,然后从KDC请求SGT。
SGT被添加到受试者的私人凭证中,由于受试者的寿命长于GSSContext,因此在创建以下GSSContext时,它与SGT一样可用。这些将在受试者的私人证书中找到中士,并且不需要点击KDC来获得新的中士。
因此,从我的特定Java Fat客户端(打开一次并可能运行数小时)来看,一切都正常。创建的第一个GSSContext将命中SGT的KDC,然后由所有后续创建的GSSContext使用,直到客户端关闭。凭据缓存未被使用,但这不会造成影响。
鉴于客户机的寿命要短得多,可能会同时多次重新打开,那么使用/不使用凭据缓存可能是一个更严重的问题。
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 GSS-API是否未将服务票据保存到凭据缓存?或者我可以改变我的代码吗?
编辑:根本原因分析。
经过数小时的sun安全调试。*类,我现在了解了GSS和Java安全代码在做什么/不做什么-至少在Java 8U 131中是这样。
在本例中,我们有一个Java GSS可以访问的凭证缓存,包含一个有效的票据授予票据(TGT)和一个有效的服务票据(SGT)。
1) 创建客户端主体主体时,TGT从缓存(Credentials.acquireTGTFromCache())加载,并存储在主体的PrivateCdentials集中--
仅加载TGT,不加载SGT并将其保存到受试者私人凭据--
2) 后来,深入到GSSContext。initSecContext()过程中,安全代码实际上尝试从主题的私有凭据中检索服务票证。相关代码是Krb5Context。initSecContext()/KrbUtils。getTicket()/SubjectComber.find()/findAux()。然而,由于在步骤1)中从未加载SGT,因此将找不到SGT!因此,从KDC请求并使用一个新的SGT。
对每个服务请求重复此操作。
只是为了好玩,严格来说是作为概念验证黑客,我在登录名和initSecContext()之间添加了几行代码来解析凭据缓存、提取凭据、转换为Krb凭据,并将它们添加到主题的私人凭据中。
完成此操作后,在步骤2)中找到并使用现有的SGT。KDC不请求新的SGT。
我不会发布这个黑客的代码,因为它调用了我们不应该调用的sun内部类,我不希望激励其他人这么做。我也不打算用这个黑客作为解决方案。
—
a) SGT未从凭据缓存加载到客户端主体的主体
和
b) 没有公共API或配置设置来执行此操作。
这会影响带JAAS和不带JAAS的GSS-API。
那么我该怎么办?
i) 将Java GSS-API/GSS-API与JAAS“按原样”一起使用,每个SGT请求都会命中KDC-
ii)正如Samson在下面的评论中建议的那样,使用JavaGSS-API仅用于应用程序的初始登录,然后对于所有进一步的调用,使用代币或cookie为后续调用使用替代安全机制(一种自建kerberos-light)。
iii)考虑GSS-API的替代方案,例如Apache Kerby边框客户端。这具有超出本答案范围的含义,并且很可能被证明是从众所周知的煎锅跳到火上。
我已经向Oracle提交了Java功能请求,建议应该从缓存中检索SGTs并存储在主题凭据中(TGTs已经是这种情况)。
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8180144
问题2:服务票证没有保存到缓存有什么缺点吗?
使用服务票证的凭据缓存减少了客户端和KDC之间的交互。由此产生的推论是,在不缓存服务票证的情况下,每个请求都需要与KDC进行交互,这可能导致KDC受到攻击。
我已经编写了一个在Windows下运行的简单JavaHTTP客户端。客户端与需要通过SPNego进行Kerberos身份验证的Web服务器进行通信。 我遇到了两个问题: > 服务票证没有存储在我的凭据缓存中。执行请求后,我希望看到一个Kerberos服务票存储在我的凭据缓存下的
本文向大家介绍java使用hashMap缓存保存数据的方法,包括了java使用hashMap缓存保存数据的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了java使用hashMap缓存保存数据的方法。分享给大家供大家参考,具体如下: 更多关于java算法相关内容感兴趣的读者可查看本站专题:《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇
我试图在使用JGit拉取回购时使用Kerberos身份验证,但出现以下错误: 来自Ticket Cache的空凭据 [Krb5LoginMoules]身份验证失败 这是我的登录名。形态 我使用自定义的JcshConfigSessionFactory和重写配置方法,如下所示 “klist”说凭证缓存是API(我在MacOS Sierra上)。我怎样才能克服这次失败?
Quarkus有类似于开箱即用?(在文件中找不到任何提及) 要穿上某种服务方式, 这将在一段时间内保留/缓存prev响应,并保留调用堆栈/日志。 类似于那个Spring注释?
我将React应用程序转换为PWA,它的工作部分正常。 我遵循了本教程:https://medium.com/@toricpope/transform-a-react-app-to-a-progressive-web-app-pwa-dea336bd96e6 然而,本文只展示了如何缓存静态数据,我还需要存储来自服务器的数据,我可以按照本文第一个答案的说明来做:如何将API中的数据缓存到React
从我的Service Worker中,我在浏览器缓存中保存了一些资产,以及Service Worker脚本本身,它工作正常,这样我就可以在我的devols缓存选项卡中看到Service Worker url和所有其他资产。 现在,当我脱机时,我的服务人员将侦听事件并从缓存中获取所有资产。 但是,当页面尝试注册工作程序本身时,似乎没有获取事件,因此我在控制台中遇到以下错误: 控制台错误 控制台ero