【发布时间】:2023-11-29 06:13:01
【问题描述】:
我想从 Authorization HTTP 标头中的 Kerberos 票证中读取用户名。我正在使用 Java。
我花了几天时间尝试通过阅读有关该主题的一堆网站来实现这一点,但未能做到这一点。 Kerberos 对我来说是新的/陌生的。
这是我所取得的成就:
- 当用户首次访问站点时 - 没有 Authorization 标头,服务器会以 401 + 标头响应:WWW-Authenticate=Negotiate。
- 各种神奇的事情发生在客户端。
- 用户返回一个 HTTP 请求,其中包含 Authorization 标头,其值如下:“Negotiate YHcGB...=="
- 将 base64 编码票证解码为字节数组。
从这里开始,这是一次穿越未知的恐怖旅程。据我所知,接下来的步骤应该是:
- 以用户身份登录 AD/Kerberos/服务器。
- 解码票证。
这就是我所拥有的:
login.conf
ServicePrincipalLoginContext
{
com.sun.security.auth.module.Krb5LoginModule
required
principal="HTTP/some.server.com@MY.DOMAIN.COM"
doNotPrompt=true
useTicketCache=true
password=mYpasSword
debug=true;
};
JavaClass.java
String encodedTicket = authorization.substring("Negotiate ".length());
byte[] ticket = Base64.decode(encodedTicket);
LoginContext lc = new LoginContext("ServicePrincipalLoginContext");
lc.login();
Subject serviceSubject = lc.getSubject();
Subject.doAs(serviceSubject, new ServiceTicketDecoder(ticket));
ServiceTicketDecoder.java
public String run() throws Exception {
Oid kerberos5Oid = new Oid("1.2.840.113554.1.2.2");
GSSManager gssManager = GSSManager.getInstance();
String service = "krbtgt/MY.DOMAIN.COM@MY.DOMAIN.COM";
GSSName serviceName = gssManager.createName(service, GSSName.NT_USER_NAME);
GSSCredential serviceCredentials = gssManager.createCredential(serviceName, GSSCredential.INDEFINITE_LIFETIME, kerberos5Oid, GSSCredential.ACCEPT_ONLY);
GSSContext gssContext = gssManager.createContext(serviceCredentials);
gssContext.acceptSecContext(this.serviceTicket, 0, this.serviceTicket.length);
GSSName srcName = gssContext.getSrcName();
return srcName.toString;
}
JavaClass.java 中的登录正常,所以我假设 login.conf 正常。在 ServiceTicketDecoder.java 中的 "GSSCredential serviceCredentials = gssManager.createCredential(..." 上抛出以下异常:
java.security.PrivilegedActionException: GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos Key)
我不确定这是否是正确的方法。我也不知道“字符串服务”的价值应该是什么或如何获取该信息。你能帮帮我吗?
编辑: 登录.conf
ServicePrincipalLoginContext
{
com.sun.security.auth.module.Krb5LoginModule
required
principal="HTTP/some.server.com@MY.DOMAIN.COM"
doNotPrompt=true
useTicketCache=true
keyTab="C:/server-http.keytab"
debug=true;
};
我收到了一个密钥表文件。显然 HTTP/some.server.com 用户的帐户已经是服务主体帐户。我现在在 lc.login() 的 JavaClass.java 上有一个问题:
javax.security.auth.login.LoginException: KDC has no support for encryption type (14)
Caused by: KrbException: KDC has no support for encryption type (14)
Caused by: KrbException: Identifier doesn't match expected value (906)
keytab 文件使用 des-cbc-md5 加密,我在 krb.conf 文件中定义了以下内容:
[libdefaults]
default_realm = MY.DOMAIN.COM
default_tkt_enctypes = des-cbc-md5
default_tgs_enctypes = des-cbc-md5
如果我将默认编码类型更改为例如aes128-cts,我得到以下异常:
javax.security.auth.login.LoginException: Do not have keys of types listed in default_tkt_enctypes available; only have keys of following type: DES CBC mode with MD5
我不明白这是怎么回事......
【问题讨论】:
-
我想知道“各种神奇的事情都发生在客户端”。您能否更具体地说明如何通过 http 请求从用户 pc 获取 kerberos 令牌