Spnego を使用して Kerberos チケットを復号化する
-
12-10-2019 - |
質問
私はspnegoを使用しています( http://spnego.sourceforge.net ) JBoss での Kerberos 認証用。
PAC データを含む認証データにアクセスするには、kerberos チケットを復号化する必要があります。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 からの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);
}
また、GetUserPrincipal()を介してlogonInfoを開示する新しいhttpfilter(spnego.sf.netからForked from Spnego.sf.net)を書きました。
上記のコードを全面的に示すプロジェクトの例は、こちらにあります:
https://github.com/eleotlecram/jetty-spnego-demo
SPNEGO-PACフィルター(上記の例で使用)は、こちらをご覧ください。
https://github.com/eleotlecram/spnego.sf.net-fork
これが誰にとっても役立つことを願っています。
__
マルセル
メカニズムトークンを取得した場合 spnegoToken
このような:
byte[] mechanismToken = spnegoToken.getMechanismToken();
メカニズムトークンは通常aです 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);
クライアントブラウザから受け取ったバイトシーケンスは、チケットルート -レベル0である単一のderapplicationspecificに解析されます。
ルートには次のものが含まれます。
- DERObjectIdentifier - SPNEGO OID
- DERSequence - レベル 1
レベル 1 には以下が含まれます。
- DERObjectIdentifier の配列 - メカタイプ
- DEROctetString - ラップされた DERApplicationSpeciific - レベル 2
レベル 2 には次の内容が含まれます。
- DERObjectIndentifier - Kerberos OID
- KRB5_AP_REQ タグ
0x01 0x00
, 、ブール値 (false) として解析されます。 - DERApplicationSpecific - DERSequence のコンテナ - レベル 3
レベル 3 には次の内容が含まれます。
- バージョン番号 - 5である必要があります
- メッセージタイプ - 14 (AP_REQ)
- AP オプション (DERBITString)
- DERApplicationSpecific - チケット部分を含むラップされた DERSequence
- 追加のチケット部分を含む DERSequeuence - 未処理
チケット部分 - レベル 4 には以下が含まれます。
- チケットのバージョン - 5 である必要があります
- チケット レルム - ユーザーが認証されるレルムの名前
- サーバー名の DERSequence。各サーバー名は 2 つの文字列の DERSequence です。サーバー名とインスタンス名
- 暗号化された部分を含む DERSequence
暗号化された部分シーケンス (レベル 5) には以下が含まれます。
- 使用アルゴリズム番号
- 1、3 - DES
- 16 - デス3-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)
問題は、シーケンス 0x01 0x00 が見つかった場合に ArrayIndexOutOfBoundException をスローする DERBoolean コンストラクターにありました。そのコンストラクターを変更する必要がありました。
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(ほぼ1年)を使用してからしばらく経ちました...あなたは非常にクールな質問をしています。
私は少し掘り下げて、MS-ADと一緒に働いていたが、今日それを感じていないだけで、しばらく前から持っていたいくつかのコードを実行しようとしていました: - /
うまくいけば、それはあなたにいくつかの洞察を与えることができます。