java 使用 Spnego 解密 kerberos 票证
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4508555/
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
Decrypt kerberos ticket using Spnego
提问by Danubian Sailor
I'm using spnego ( http://spnego.sourceforge.net) for kerberos authentication under JBoss.
我在 JBoss 下使用 spnego ( http://spnego.sourceforge.net) 进行 kerberos 身份验证。
I need to decrypt kerberos ticket to access the authorization-data which will containt PAC data. The PAC data is needed to decide which roles are to be granted to user.
我需要解密 kerberos 票证以访问将包含 PAC 数据的授权数据。需要 PAC 数据来决定将哪些角色授予用户。
How to access and decrypt kerberos ticket? I've searched net for examples, but without effort.
如何访问和解密 kerberos 票证?我在网上搜索过例子,但没有努力。
采纳答案by Grant Cermak
These guys have a full PAC decoding implementation:
这些家伙有完整的 PAC 解码实现:
http://jaaslounge.sourceforge.net/
http://jaaslounge.sourceforge.net/
You can use the token parser like this:
您可以像这样使用令牌解析器:
HttpServletRequest request = (HttpServletRequest) req;
String header = request.getHeader("Authorization");
byte[] base64Token = header.substring(10).getBytes("UTF-8");
byte[] spnegoHeader = Base64.decode(base64Token);
SpnegoInitToken spnegoToken = new SpnegoInitToken(spnegoHeader);
You're going to need to jump though some hoops if you want to decrypt the underlying Kerberos ticket. Not sure if you need that.
如果您想解密底层 Kerberos 票证,您将需要跳过一些障碍。不确定你是否需要那个。
Grant
授予
回答by eleotlecram
I have successfully used the servlet filter from http://spnego.sourceforge.netin combination with the PAC parser from http://jaaslounge.sourceforge.net/without the need to do something explicitly with DER/ASN.1 parsers :
我已经成功地将http://spnego.sourceforge.net中的 servlet 过滤器与http://jaaslounge.sourceforge.net/ 中的 PAC 解析器结合使用,而无需对 DER/ASN.1 解析器进行显式操作:
/**
* Retrieve LogonInfo (for example, Group SID) from the PAC Authorization Data
* from a Kerberos Ticket that was issued by Active Directory.
*/
byte[] kerberosTokenData = gssapiData;
try {
SpnegoToken token = SpnegoToken.parse(gssapiData);
kerberosTokenData = token.getMechanismToken();
} catch (DecodingException dex) {
// Chromium bug: sends a Kerberos response instead of an spnego response
// with a Kerberos mechanism
} catch (Exception ex) {
log.error("", ex);
}
try {
Object[] keyObjs = IteratorUtils.toArray(loginContext.getSubject()
.getPrivateCredentials(KerberosKey.class).iterator());
KerberosKey[] keys = new KerberosKey[keyObjs.length];
System.arraycopy(keyObjs, 0, keys, 0, keyObjs.length);
KerberosToken token = new KerberosToken(kerberosTokenData, keys);
log.info("Authorizations: ");
for (KerberosAuthData authData : token.getTicket().getEncData()
.getUserAuthorizations()) {
if (authData instanceof KerberosPacAuthData) {
PacSid[] groupSIDs = ((KerberosPacAuthData) authData)
.getPac().getLogonInfo().getGroupSids();
log.info("GroupSids: " + Arrays.toString(groupSIDs));
response.getWriter().println("Found group SIDs: " +
Arrays.toString(groupSIDs));
} else {
log.info("AuthData without PAC: " + authData.toString());
}
}
} catch (Exception ex) {
log.error("", ex);
}
I've also written a new HttpFilter (forked from spnego.sf.net): spnego-pac, that discloses the LogonInfo through the getUserPrincipal().
我还编写了一个新的 HttpFilter(派生自 spnego.sf.net):spnego-pac,它通过 getUserPrincipal() 公开 LogonInfo。
An example project demonstrating the above code in full can be found here:
可以在此处找到完整演示上述代码的示例项目:
https://github.com/EleotleCram/jetty-spnego-demo
https://github.com/EleotleCram/jetty-spnego-demo
The spnego-pac filter (used in the above example) can be found here:
spnego-pac 过滤器(在上面的例子中使用)可以在这里找到:
https://github.com/EleotleCram/spnego.sf.net-fork
https://github.com/EleotleCram/spnego.sf.net-fork
Hope this is helpful to anyone.
希望这对任何人都有帮助。
__
Marcel
__
马塞尔
回答by Danubian Sailor
I provide my own solution to the problem:
我提供了我自己的问题解决方案:
I've based my solution on BouncyCastle library (for parsing parts of token) and JaasLounge (for decrypting encrypted part of token). Unfortunatelly, the code for decoding whole spnego token from JaasLounge failed for my requirements. I had to write it myself.
我的解决方案基于 BouncyCastle 库(用于解析令牌的部分)和 JaasLounge(用于解密令牌的加密部分)。不幸的是,从 JaasLounge 解码整个 spnego 令牌的代码未能满足我的要求。我不得不自己写。
I've decoded ticket part by part, firstly constructing DERObjects from byte[] array:
我已经部分地解码了票证,首先从 byte[] 数组构造 DERObjects:
private DERObject[] readDERObjects(byte[] bytes) throws IOException {
ASN1InputStream stream = new ASN1InputStream(new ByteArrayInputStream(
bytes));
List<DERObject> objects = new ArrayList<DERObject>();
DERObject curObj;
while ((curObj = stream.readObject()) != null) {
objects.add(untag(curObj));
}
return objects.toArray(new DERObject[0]);
}
The untag() is my helper function, to remove DERTaggedObject wrapping
untag() 是我的辅助函数,用于移除 DERTaggedObject 包装
private DERObject untag(DERObject src) {
if (src instanceof DERTaggedObject) {
return ((DERTaggedObject) src).getObject();
}
return src;
}
For extracting sequence of DERObject from given DERObject I've written another helper function:
为了从给定的 DERObject 中提取 DERObject 的序列,我编写了另一个辅助函数:
private DERObject[] readDERObjects(DERObject container) throws IOException {
// do operation varying from the type of container
if (container instanceof DERSequence) {
// decode using enumerator
List<DERObject> objects = new ArrayList<DERObject>();
DERSequence seq = (DERSequence) container;
Enumeration enumer = seq.getObjects();
while (enumer.hasMoreElements()) {
DERObject curObj = (DERObject) enumer.nextElement();
objects.add(untag(curObj));
}
return objects.toArray(new DERObject[0]);
}
if (container instanceof DERApplicationSpecific) {
DERApplicationSpecific aps = (DERApplicationSpecific) container;
byte[] bytes = aps.getContents();
return readDERObjects(bytes);
}
if (container instanceof DEROctetString) {
DEROctetString octets = (DEROctetString) container;
byte[] bytes = octets.getOctets();
return readDERObjects(bytes);
}
throw new IllegalArgumentException("Unable to decode sequence from "+container);
}
At the end, when I've got DEROctetStream, that contained encrypted part, I've just used KerberosEncData:
最后,当我得到包含加密部分的 DEROctetStream 时,我刚刚使用了 KerberosEncData:
KerberosEncData encData = new KerberosEncData(decrypted, matchingKey);
The byte sequence we receive from client browser will be parsed into single DERApplicationSpecific
which is ticket root - level 0.
The root contains:
我们从客户端浏览器接收到的字节序列将被解析为单个 DERApplicationSpecific,它是票根 - 级别 0。
根包含:
- DERObjectIdentifier - SPNEGO OID
- DERSequence - level 1
- DERObjectIdentifier - SPNEGO OID
- DERSequence - 级别 1
Level 1 contains:
级别 1 包含:
- SEQUENCE of DERObjectIdentifier - mech types
- DEROctetString - wrapped DERApplicationSepecific - level 2
- DERObjectIdentifier 的序列 - 机械类型
- DEROctetString - 包装的 DERApplicationSpecific - 级别 2
Level 2 contains:
级别 2 包含:
- DERObjectIndentifier - Kerberos OID
- KRB5_AP_REQ tag
0x01 0x00
, parsed as boolean (false) - DERApplicationSpecific - container of DERSequence - level 3
- DERObjectIndentifier - Kerberos OID
- KRB5_AP_REQ 标记
0x01 0x00
,解析为布尔值 (false) - DERApplicationSpecific - DERSequence 的容器 - 级别 3
Level 3 contains:
第 3 级包含:
- version number - should be 5
- message type - 14 (AP_REQ)
- AP options (DERBITString)
- DERApplicationSpecific - wrapped DERSequence with ticket part
- DERSeqeuence with additional ticket part - not processed
- 版本号 - 应该是 5
- 消息类型 - 14 (AP_REQ)
- AP 选项 (DERBITString)
- DERApplicationSpecific - 带有票据部分的包装的 DERSequence
- 带有附加票部分的 DERSeqeuence - 未处理
Ticket part - level 4 contains:
门票部分 - 级别 4 包含:
- Ticket version - should be 5
- Ticket realm - the name of the realm in which user is authenticated
- DERSequence of server names. Each server name is DERSequence of 2 strings: server name and instance name
- DERSequence with encrypted part
- 门票版本 - 应该是 5
- 票证领域 - 对用户进行身份验证的领域的名称
- DER 服务器名称的序列。每个服务器名称都是 2 个字符串的 DERSequence:服务器名称和实例名称
- 带加密部分的 DERSequence
Encrypted part sequence (level 5) contains:
加密部分序列(级别 5)包含:
- Used algorithm number
- 1, 3 - DES
- 16 - des3-cbc-sha1-kd
- 17 - ETYPE-AES128-CTS-HMAC-SHA1-96
- 18 - ETYPE-AES256-CTS-HMAC-SHA1-96
- 23 - RC4-HMAC
- 24 - RC4-HMAC-EXP
- Key version number
- Encrypted part (DEROctetStream)
- 使用的算法编号
- 1, 3 - DES
- 16 - des3-cbc-sha1-kd
- 17 - ETYPE-AES128-CTS-HMAC-SHA1-96
- 18 - ETYPE-AES256-CTS-HMAC-SHA1-96
- 23 - RC4-HMAC
- 24 - RC4-HMAC-EXP
- 密钥版本号
- 加密部分(DEROctetStream)
The problem was with DERBoolean constructor, that throw ArrayIndexOutOfBoundException, when sequence 0x01 0x00 was found. I had to change that constructor:
问题出在 DERBoolean 构造函数上,当发现序列 0x01 0x00 时,该构造函数抛出 ArrayIndexOutOfBoundException。我不得不改变那个构造函数:
public DERBoolean(
byte[] value)
{
// 2011-01-24 llech make it byte[0] proof, sequence 01 00 is KRB5_AP_REQ
if (value.length == 0)
this.value = 0;
else
this.value = value[0];
}
回答by Grant Cermak
If you get the mechanism token from the spnegoToken
like this:
如果你从spnegoToken
这样得到机制令牌:
byte[] mechanismToken = spnegoToken.getMechanismToken();
The mechanism token is usually a KerberosApRequest
. There is a KerberosToken
constructor which takes a KerberosApRequest
. Simply pass in the mechanismToken
byte array along with the key to decrypt the contents.
机制令牌通常是一个KerberosApRequest
. 有一个KerberosToken
构造函数需要一个KerberosApRequest
. 只需将mechanismToken
字节数组与密钥一起传入即可解密内容。
回答by Dave G
Wow been a while since I've used spnego (nearly a year) ... You're asking a very cool question.
哇,自从我使用 spnego(将近一年)以来已经有一段时间了......你问了一个非常酷的问题。
I did a little digging and was going to try and run up some code I had from a while back that was working with MS-AD but just not feeling it today :-/
我做了一些挖掘,并打算尝试运行一些我以前使用 MS-AD 使用的代码,但今天没有感觉:-/
Anyway, I found this link through google: http://www.google.com/url?sa=t&source=web&cd=1&sqi=2&ved=0CBMQFjAA&url=http%3A%2F%2Fbofriis.dk%2Ffiles%2Fms_kerberos_pac.pdf&rct=j&q=java%20kerberos%20privilege%20attribute%20certificate&ei=2FASTbaLGcP38Abk07iQDg&usg=AFQjCNHcIfQRUTxkQUvLRcgOaQksCALTHA&sig2=g8yn7ie1PbzSkE2Mfv41Bw&cad=rja
无论如何,我通过谷歌找到了这个链接:http: //www.google.com/url?sa=t&source=web&cd=1&sqi=2&ved=0CBMQFjAA&url= http%3A%2F%2Fbofriis.dk%2Ffiles%2Fms_kerberos_pac.pdf&rct=j& q =java%20kerberos%20privilege%20attribute%20certificate&ei=2FASTbaLGcP38Abk07iQDg&usg=AFQjCNHcIfQRUTxkQUvLRcgOaQksCALTHA&sig2=g8yn7ie1PbzSkE2Mfv4rja
Hopefully that can give you some insight.
希望这能给你一些见解。