使用Spnego解密kerberos票

Dan*_*lor 14 java jboss kerberos active-directory spnego

我正在使用spnego(http://spnego.sourceforge.net)在JBoss下进行kerberos身份验证.

我需要解密kerberos票证才能访问包含PAC数据的授权数据.需要PAC数据来决定将哪些角色授予用户.

如何访问和解密kerberos票?我在网上搜索了一些例子,但没有努力.

Gra*_*mak 8

这些人有完整的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);
Run Code Online (Sandbox Code Playgroud)

如果要解密基础Kerberos票证,您将需要跳过一些箍.不确定你是否需要它.

格兰特

  • "如果你想解密底层的Kerberos票,你需要跳过一些箍.不确定你是否需要它." - 这就是我说的原因.它需要额外的代码才能获得Kerberos票证.我会提供跟进回复. (3认同)

ele*_*ram 8

我已成功使用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);
}   
Run Code Online (Sandbox Code Playgroud)

我还写了一个新的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

希望这对任何人都有帮助.

__
马塞尔


Gra*_*mak 5

如果你从spnegoToken这样得到机制令牌:

byte[] mechanismToken = spnegoToken.getMechanismToken(); 
Run Code Online (Sandbox Code Playgroud)

机制令牌通常是一个KerberosApRequest.有一个KerberosToken构造函数,需要一个KerberosApRequest.只需传入mechanismToken字节数组和密钥即可解密内容.


Dan*_*lor 5

我提供了自己的问题解决方案:

我的解决方案基于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]);
}
Run Code Online (Sandbox Code Playgroud)

untag()是我的辅助函数,用于删除DERTaggedObject包装

private DERObject untag(DERObject src) {
    if (src instanceof DERTaggedObject) {
        return ((DERTaggedObject) src).getObject();
    }
    return src;
}
Run Code Online (Sandbox Code Playgroud)

为了从给定的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);
}
Run Code Online (Sandbox Code Playgroud)

最后,当我得到包含加密部分的DEROctetStream时,我刚刚使用了KerberosEncData:

KerberosEncData encData = new KerberosEncData(decrypted, matchingKey);
Run Code Online (Sandbox Code Playgroud)

我们从客户端浏览器接收的字节序列将被解析为单个DERApplicationSpecific,它是票根 - 级别0.
根包含:

  • DERObjectIdentifier - SPNEGO OID
  • DERSequence - 1级

1级包含:

  • DERObjectIdentifier的序列 - 机械类型
  • DEROctetString - 包裹DERApplicationSepecific - 级别2

2级包含:

  • DERObjectIndentifier - Kerberos OID
  • KRB5_AP_REQ标记0x01 0x00,解析为布尔值(false)
  • DERApplicationSpecific - DERSequence的容器 - 级别3

3级包含:

  • 版本号 - 应为5
  • 消息类型 -​​ 14(AP_REQ)
  • AP选项(DERBITString)
  • DERApplicationSpecific - 包含票证部分的DERSequence
  • DERSeqeuence与额外的票证部分 - 未处理

机票部分 - 第4级包含:

  • 机票版本 - 应为5
  • 票证领域 - 用户通过身份验证的领域的名称
  • 服务器名称的后缀.每个服务器名称是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];
}
Run Code Online (Sandbox Code Playgroud)