使用Spnego解密kerberos票
我正在使用spnego( http://spnego.sourceforge.net )在JBoss下进行kerberos身份validation。
我需要解密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票证,您将需要跳过一些箍。 不确定你是否需要它。
格兰特
我已成功使用http://spnego.sourceforge.net中的servletfilter与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); }
我还写了一个新的HttpFilter(从spnego.sf.net派生):spnego-pac,它通过getUserPrincipal()公开了LogonInfo。
可以在此处找到完整演示上述代码的示例项目:
https://github.com/EleotleCram/jetty-spnego-demo
spnego-pacfilter(在上面的例子中使用)可以在这里找到:
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 objects = new ArrayList (); 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 objects = new ArrayList (); 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);
我们从客户端浏览器接收的字节序列将被解析为单个DERApplicationSpecific,它是票根 – 级别0。
根包含:
- DERObjectIdentifier – SPNEGO OID
- DERSequence – 1级
1级包含:
- DERObjectIdentifier的序列 – 机械类型
- DEROctetString – 包裹DERApplicationSepecific – 级别2
2级包含:
- DERObjectIndentifier – Kerberos OID
- KRB5_AP_REQ标记
0x01 0x00
,解析为boolean(false) - DERApplicationSpecific – DERSequence的容器 – 级别3
3级包含:
- 版本号 – 应为5
- 消息类型 - 14(AP_REQ)
- AP选项(DERBITString)
- DERApplicationSpecific – 包含票证部分的DERSequence
- 带有额外票务部分的DERSeqeuence – 未处理
机票部分 – 第4级包含:
- 机票版本 – 应为5
- 票证领域 – 用户通过身份validation的领域的名称
- 服务器名称的后缀。 每个服务器名称是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的代码,但今天感觉不到: – /
无论如何,我通过谷歌找到了这个链接: http : //www.google.com/url? sa = t&source = web&cd = 1&sqi = 2&ed = 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
希望这可以给你一些见解。
- 为什么JDK1.8.0u121无法找到kerberos default_tkt_enctypes类型? (KrbException:default_tkt_enctypes没有支持的默认etypes)
- 在ssl(ldaps)的支持下连接活动目录
- 通过ssl作为匿名用户进行Active Directory身份validation
- 无法从Java获得与AD的连接
- 如何将Java连接到Active Directory
- 检测使用Java Web应用程序登录计算机的用户
- 如何使用Spring Security对Active Directory服务器进行身份validation?
- 密码的SPNEGO身份validation问题
- Java SimpleDateFormat总是返回1月份的月份