java 从授权标头中的 Kerberos 票证读取用户名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14354414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reading user name from Kerberos ticket in Authorization header
提问by user1982861
I want to read the user's name from the Kerberos ticket in the Authorization HTTP header. I am using Java.
我想从 Authorization HTTP 标头中的 Kerberos 票证中读取用户名。我正在使用 Java。
I have spent days trying to achieve this by reading through a bunch of sites on the subject but have not been able to do this. Kerberos is new/foreign to me.
我花了几天时间试图通过阅读有关该主题的一堆网站来实现这一目标,但未能做到这一点。Kerberos 对我来说是新的/陌生的。
This is what I've achieved:
这就是我所取得的成就:
- When a user first accesses the site - without the Authorization header, the server responds with 401 + header: WWW-Authenticate=Negotiate.
- All sorts of magical things happen on the client's side.
- User returns with a HTTP request that contains the Authorization header with a value like: "Negotiate YHcGB...=="
- Decode the base64 encoded ticket to a byte array.
- 当用户第一次访问站点时 - 没有 Authorization 标头,服务器以 401 + 标头响应:WWW-Authenticate=Negotiate。
- 各种神奇的事情都发生在客户端。
- 用户返回的 HTTP 请求包含授权标头,其值类似于:“Negotiate YHcGB...==”
- 将 base64 编码的票据解码为字节数组。
From here on it's a terrifying journey through the unknown. As far as I can tell, the next steps should be:
从这里开始,这是一次穿越未知的可怕旅程。据我所知,接下来的步骤应该是:
- Login to AD/Kerberos/ Server with a user.
- Decode the ticket.
- 以用户身份登录 AD/Kerberos/Server。
- 对票进行解码。
This is what I have:
这就是我所拥有的:
login.conf
登录配置文件
ServicePrincipalLoginContext
{
com.sun.security.auth.module.Krb5LoginModule
required
principal="HTTP/[email protected]"
doNotPrompt=true
useTicketCache=true
password=mYpasSword
debug=true;
};
JavaClass.java
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
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/[email protected]";
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;
}
The login in JavaClass.java works ok, so I'm assuming the login.conf is ok. On "GSSCredential serviceCredentials = gssManager.createCredential(..." in the ServiceTicketDecoder.java the following exception is thrown:
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)
I am not sure if this is the right approach. I also don't know what the value of the "String service" should be or how to get that information. Can you help me?
我不确定这是否是正确的方法。我也不知道“字符串服务”的价值应该是什么或如何获取该信息。你能帮助我吗?
EDIT: login.conf
编辑:login.conf
ServicePrincipalLoginContext
{
com.sun.security.auth.module.Krb5LoginModule
required
principal="HTTP/[email protected]"
doNotPrompt=true
useTicketCache=true
keyTab="C:/server-http.keytab"
debug=true;
};
I have received a keytab file. Apparently the HTTP/some.server.com user's account was already a service principal account. I now have a problem on JavaClass.java at lc.login():
我收到了一个密钥表文件。显然 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)
The keytab file is encrypted with des-cbc-md5 and I have the following defined in the krb.conf file:
密钥表文件使用 des-cbc-md5 加密,我在 krb.conf 文件中定义了以下内容:
[libdefaults]
default_realm = MY.DOMAIN.COM
default_tkt_enctypes = des-cbc-md5
default_tgs_enctypes = des-cbc-md5
If I change the default enctypes to e.g. aes128-cts, I get the following exception:
如果我将默认编码类型更改为例如 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
I don't understand what is wrong...
我不明白有什么问题...
采纳答案by Marko Topolnik
Kerberos is a trusted third-partysecurity system: the security token you receive from the client is decryptable only by you, and without contacting any Kerberos infrastructure servers (such as the KDC). You are on the right track; however, it appears you are missing this piece of background Kerberos knowledge to guide you in your further research.
Kerberos 是一个受信任的第三方安全系统:您从客户端收到的安全令牌只能由您解密,而无需联系任何 Kerberos 基础架构服务器(例如 KDC)。你走在正确的轨道上;但是,您似乎缺少这一 Kerberos 背景知识来指导您进行进一步研究。
The way this is achieved is that on the server you need a keytabfile that contains your server's secret key. The Kerberos server (Microsoft Windows Server, I presume) must have a service principal accountcreated for your service. An administrator can supply you with the keytab file generated for this account, which will contain the secret key.
实现这一点的方法是,在服务器上,您需要一个包含服务器密钥的密钥表文件。Kerberos 服务器(我认为是 Microsoft Windows Server)必须为您的服务创建一个服务主体帐户。管理员可以为您提供为此帐户生成的密钥表文件,其中将包含密钥。
You then need to configure the server to find this keytab file; it is used in the server-side step involving LoginContext.login
. Your code that accepts the security context must be executed inside a doPrivileged
code segment within which your server-side credentials are in effect.
然后你需要配置服务器来找到这个keytab文件;它用于涉及LoginContext.login
. 您接受安全上下文的doPrivileged
代码必须在您的服务器端凭据生效的代码段内执行。
回答by keredson
If all you want is the username there is an easier way.
如果您想要的只是用户名,则有一种更简单的方法。
request.getUserPrincipal().getName()
http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()http://docs.oracle.com/javase/7/docs/api/java/security/Principal.html
http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal() http://docs.oracle.com/javase/7/docs/api/java/security /Principal.html