使用 Spnego 解密 kerberos 票证
-
12-10-2019 - |
题
我正在使用 spnego ( http://spnego.sourceforge.net ) 用于 JBoss 下的 kerberos 身份验证。
我需要解密 kerberos 票证才能访问包含 PAC 数据的授权数据。需要 PAC 数据来决定向用户授予哪些角色。
如何访问和解密kerberos票证?我已经在网上搜索了示例,但没有费力。
解决方案
这些家伙有完整的PAC解码实施:
http://jaaslounge.sourceforge.net/
您可以这样使用令牌解析器:
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);
如果您想解密基础的Kerberos票,您将需要跳一些篮球。不确定您是否需要。
授予
其他提示
我已经成功地使用了Servlet过滤器 http://spnego.sourceforge.net 与PAC解析器的结合 http://jaaslounge.sourceforge.net/ 无需使用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);
}
我还写了一个新的httpfilter(摘自spnego.sf.net):spnego-pac,它通过getuserprincipal()披露了logoninfo。
可以在此处找到一个完整说明上述代码的示例项目:
https://github.com/eleotlecram/jetty-spnego-demo
Spnego-PAC过滤器(在上面的示例中使用)可以在此处找到:
https://github.com/eleotlecram/spnego.sf.net-fork
希望这对任何人都有帮助。
__
马塞尔
如果您从 spnegoToken
像这样:
byte[] mechanismToken = spnegoToken.getMechanismToken();
令牌令牌通常是 KerberosApRequest
. 。有一个 KerberosToken
构造函数 KerberosApRequest
. 。只需传递 mechanismToken
字节数组以及解密内容的钥匙。
我针对这个问题提供了我自己的解决方案:
我的解决方案基于 BouncyCastle 库(用于解析令牌的部分)和 JaasLounge(用于解密令牌的加密部分)。不幸的是,从 JaasLounge 解码整个 spnego 令牌的代码未能满足我的要求。我必须自己写。
我已经逐部分解码了票证,首先从 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]);
}
untag() 是我的辅助函数,用于删除 DERTaggedObject 包装
private DERObject untag(DERObject src) {
if (src instanceof DERTaggedObject) {
return ((DERTaggedObject) src).getObject();
}
return src;
}
为了从给定的 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);
}
最后,当我得到包含加密部分的 DEROctetStream 时,我刚刚使用了 KerberosEncData:
KerberosEncData encData = new KerberosEncData(decrypted, matchingKey);
我们从客户端浏览器中收到的字节序列将被解析为单个derapplicationspefific,ticket root -0。
根包含:
- DERObjectIdentifier - SPNEGO OID
- DERSequence - 1 级
1 级包含:
- DERObjectIdentifier 的序列 - 机械类型
- DEROctetString - 包装的 DERApplicationSepecific - 级别 2
2 级包含:
- DERObjectIndentifier - Kerberos OID
- KRB5_AP_REQ 标签
0x01 0x00
, ,解析为布尔值(假) - DERApplicationSpecific - DERSequence 容器 - 级别 3
第 3 级包含:
- 版本号 - 应为 5
- 消息类型 - 14 (AP_REQ)
- AP 选项 (DERBITString)
- DERApplicationSpecific - 使用票证部分包装 DERSequence
- 具有附加票证部分的 DERSeqeuence - 未处理
票证部分 - 第 4 级包含:
- 门票版本 - 应该是 5
- 票证领域 - 用户进行身份验证的领域的名称
- DER 服务器名称的序列。每个服务器名称都是由 2 个字符串组成的 DERSequence:服务器名称和实例名称
- 具有加密部分的 DERSequence
加密部分序列(级别 5)包含:
- 使用的算法数量
- 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)
问题出在 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];
}
哇已经有一段时间了,因为我使用了Spnego(将近一年)...您问一个非常酷的问题。
我做了一些挖掘,并打算尝试使用MS-AD工作的一些代码,但今天没有感觉到: - /
希望这能给您一些见识。