SPNEGO認証はカスタムJavaクライアントからは機能しますが、Webブラウザーからは機能しません

FlyingSheep:

Webブラウザー(Internet Explorer 11)からカスタムJava Application Serverによって提供されるWebサービスへのSPNEGOを介した認証で問題が発生しています。

カスタムJavaクライアントアプリケーションを使用して、同じアプリケーションサーバーに対してSPNEGOを使用して正常に認証できます。

カスタムJavaクライアントとアプリケーションサーバーの実装の詳細は以下にあります。

以下の理由により、WebブラウザーからのSPNEGOが機能していないと思います。

a)Internet Explorerからのトークンは有効なSPNEGOトークンですか?

Webブラウザーが提供するGSSAPIトークンは、Javaクライアントが提供するものとは異なり、有効なSPNEGO / Kerberosトークンではない可能性があります。Javaクライアントは、「Negotiate YIMMQA ...」(OK)で始まる承認ヘッダーを提供しますが、Webブラウザーは、「Negotiate oYIMRz ...」(おそらくNOT OK)で始まる承認ヘッダーを提供します。

および/または

b)サーバープリンシパル名の形式

歴史的な理由により、アプリケーションサーバーは実際にはMicrosoft Active Directoryユーザープリンシパル(format = "user @ DOMAIN")であるサービスプリンシパル名を使用して実行されていますが、WebブラウザーのSPNEGO実装は要求されたURLを使用してサービスを構築していると思いますプリンシパル名。確かに、これは、Linuxバックエンドに対してLinuxで実行するときに、私のカスタムJavaクライアントが行うこととまったく同じです。

実装の詳細:

Java Application ServerはWindows Server 2012で実行されます。Kerberos/ SPNEGOの実装は、純粋なJava JAAS + GSSAPIです。

JavaクライアントはWindows(7/10)で実行され、Java SSPI(ワッフル経由)またはJAAS + GSSAPIのいずれかを使用するように構成できます。どちらの実装でも、サーバーによって受け入れられるGSSトークンが作成されます。

生成されたGSS / SPNEGOトークンは、Webサービス要求(クライアント)および応答(サーバー)のヘッダーで転送されます。

サーバーはOids "1.3.6.1.5.5.2"(SPNEGO)および "1.2.840.113554.1.2.2"(Kerberos)を使用しています。

カスタムJavaクライアント(OK)を使用したテスト:

サーバーは、1つのハンドシェイクでJavaクライアントを認証できます。Javaクライアントは、「Negotiate YIMMQA ...」で始まる承認ヘッダーを使用してWebサービスを直接呼び出します。サーバーでBase64でデコードされた後、gssapiDataは3140バイト長で、acceptSecContext()の呼び出しは成功します。

この呼び出しからgssapiDataを文字列に変換し、人間が読めるものを検索すると、最初の方で「EXAMPLE.COM」と「user-DEV」が見つかります。これは、サーバーが使用しているSPN、Active Directoryユーザープリンシパル(「[email protected]」)のように見えます。

Internet Explorer 11を使用したテスト(OKではない):

ブラウザからの最初の呼び出しには、空の認証ヘッダーがあります。サーバーは「ネゴシエート」と表示されます—> OK。

ブラウザからの2番目の呼び出しには、「Negotiate YH4GBis ...」で始まる認証ヘッダーがあります。Base64でデコードされると、gssapiDataは128バイトの長さになります。明らかにこれにはサービスチケットが含まれていません。

gssapiDataを文字列に変換すると、途中で「NTLMSSP」という文字が見つかります。ブラウザがNTLMを提案していると思います。サーバーがこの通話を拒否しました。

ブラウザーからの3番目の呼び出しには、「Negotiate oYIMRz ...」で始まる認証ヘッダーがあります。Base64がデコードされると、gssapiDataは3147バイトの長さになります(Javaクライアントからの長さに非常に近くなります)。

ただし、私のサーバーがこれに対してacceptSecContext()を実行すると、エラーがスローされます。「GSS例外:欠陥のあるトークンが検出されました(メカニズムレベル:GSSヘッダーが適切なタグを見つけられませんでした)。—>できません。

これは、トークンが無効であること、または間違ったOidを使用してトークンを読み取っていることを示唆しています。

この呼び出しからgssapiDataを文字列に変換すると、最初に「HTTP」と「APPSERVER.example.com」が見つかります。これは、URLをベースとして構築されたKerberosサービスプリンシパル名(SPN)のように見えます。—>これは、私のアプリケーションサーバーがSPNで「HTTP / APPSERVER.example.com」または「HTTP/[email protected]」のような形式で実行されている必要があることを示唆しています(2番目の形式は私のLinux / FreeIPA構成で使用)。

余談ですが、この質問の焦点であるWindowsプラットフォームでは、SPNまたはエイリアスを同じものに作成または変更したり、別のWebブラウザーを試したりする権限がありません。私のLinux開発環境では、追加の入力を提供する場合があります。

FlyingSheep:

素早い回答

2つの修正が必要でした:

1)Internet Explorer(IE)は、URLに基​​づいてサービスプリンシパル名(SPN)を作成します。たとえば、https//appserver.example.com/fooはSPN "HTTP / APPSERVER.example.com"になります。

したがって、適切なサービスプリンシパル名を、アプリケーションサーバーで使用されるユーザープリンシパル名(UPN)のエイリアスとして、上記の形式でActive Directoryに設定する必要がありました。

そして

2)Internet Explorerからのトークンは有効なSPNEGOトークンですが、サーバー上のGSS APIでは受け入れられません。

ただし、着信トークンのいくつかの単純な文字列操作で、GSSが受け入れて正常に認証するKerbeosトークンを抽出できます。

より長い答え

1)サービスプリンシパル名...

この問題をここに投稿した後、サーバーのUPN [email protected]のエイリアスとして2つのSPN HTTP / APPSERVER.example.comとHTTP / APPSERVERを設定しました。

サーバーは引き続きUPN [email protected]を使用して実行されます。(サーバーが新しいSPNの1つで実行する必要があるという私の最初の仮定は間違っていました。)

これでJavaクライアントは、新しいSPNを使用してKerberosサービスチケットを取得し、サーバーによって認証されるトークンを作成できるようになりました。

ただし、Internet Explorerからのトークンは引き続き拒否されます。

2)Internet Explorerと私のJavaクライアントのトークン...

Javaクライアントからのトークンは次のように始まります。

YIIMdwYGKwYBBQUCoI ....を交渉する

Base64デコードされ、16進バイトとして表されます。

60 82 0C 77 06 06 2B 06 01 05 05 02 A0………

このうち06 06 2B 06 01 05 05 02はSPNEGO OID 1.3.6.1.5.5.2です。

Internet Explorerからのトークンは次のように始まります。

oYIMPjCCDDqgAwoBAaKCDDEEggwtYIIMKQYJKoZIhvcSAQICを交渉する

Base64デコードされ、16進バイトとして表されます。

A1 82 0C 3E 30 82 0C 3A A0 03 0A 01 01 A2 82 0C 31 04 82 0C 2D 60 82 0C 29 06 09 2A 86 48 86 F7 12 01 02 02…。

これは「A1」で始まるSpnego NegTokenTargです。ただし、Javaクラスsun.security.jgss.GSSHeaderは、「60」で始まらないGSSトークンを拒否します。

バイトごとにIE NegTokenTargを調べると、最初の21バイトの後に、一連のバイトがアプリのトークンのバイトに非常に近いことがわかります。

60 82 0C 29 06 09 2A 86 48 86 F7 12 01 02 02 ...

そのうち06 09 2A 86 48 86 F7 12 01 02 02はKerberos OID 1.2.840.113554.1.2.2です

元のトークンの最初の21バイトを破棄してこのトークンを抽出した場合(またはgssContext.acceptSecContext(gssapiData、offset、gssapiData.length)にオフセット21を指定した場合)、GSS APIは新しいトークンを読み取って抽出できますユーザープリンシパル、つまりInternet Explorerからの要求を認証します。

以下のコード例は、base64でエンドコード化された認証文字列の文字列操作を使用して同じことを実現しています。

String auth =req.headers("Authorization");
if ( auth != null && auth.startsWith("Negotiate ")) {
    //smells like an SPNEGO request, so get the token from the http headers
    String authBody = auth.substring("Negotiate ".length());
    if (authBody.startsWith("oY")) {
        // This is a NegTokenTarg from IE, which GSS API does not properly handle.
        // However if we chop of the first (28) chars, we find a Kerberos Token starting with "60 82 0C" that GSS can handle.            
        authBody=authBody.substring(authBody.indexOf("YI", 2));
     }

     try {                 
         byte gssapiData[] = Base64.getDecoder().decode(authBody);               
         gssContext = initGSSContext(MyUtils.SPNEGOOID, MyUtils.KRB5OID);
         byte token[] = gssContext.acceptSecContext(gssapiData, offset, gssapiData.length);


         ..etc.

結論としては、

a)Java GSS APIの弱点:GSSは、NegTokenTargであるSPNEGOトークンを直接受け入れません。

または

b)Internet Explorerと私のサーバー間の相互作用。IEがNSSを送信しますが、これはGSS APIでは予期されていません。

IE-サーバーの相互作用は次のとおりです。

1)IEからの要求(ネゴシエートなし)

2)Negotiateを使用してサーバーから拒否する

3)Kerberosではなく、NTLMのように見えるネゴシエートヘッダー+トークンを使用したIEからの2番目の要求。->これが問題のルートの原因である可能性があります。

4)ネゴシエート+ SPNEGOトークンを使用してサーバーから拒否する

5)IEからの3番目の要求、Negotiateヘッダー+ SPNEGO NegTokenTarg

背景情報:

私のApplication Serverは、Kerberos / Spnego機能にJava JAAS + GSSを使用しています。私のカスタムクライアントは、Java JAAS + GSS、またはMicrosoft SSPI + Waffleのいずれかを使用できます。

このMicrosoftドキュメントは、SPNEGOトークンの形式を理解するのに非常に役立ちました。

https://msdn.microsoft.com/en-us/library/ms995330.aspx

また、このブログでは、負の10進数バイトを「処理」する方法を理解しています。(-128から-1の数値は、128から255に変換されます)。

http://sketchytech.blogspot.com/2015/11/bytes-for-beginners-representation-of.html

私のターゲットエンドユーザーの企業標準ブラウザーはInternet Explorerであり、「より良い」ものを使用する現実的なオプションがないため、グーグルでChromiumとFirefoxのSPN処理コードに出くわしました。リンクは以下のとおりです。Chromiumコードには、広範なコメントと、ナレッジベースの記事およびSMEブログへのリンクがあります。

Chromiumnコード

https://cs.chromium.org/chromium/src/net/http/http_auth_handler_negotiate.cc?type=cs&l=142

FireFoxコード

https://dxr.mozilla.org/mozilla-central/source/extensions/auth/nsAuthSSPI.cpp#98

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

Laravelioc自動解決-コントローラーからは機能しますが、カスタムクラスからは機能しません

分類Dev

Pythonインポートはインタラクティブに機能しますが、スクリプトからは機能しません

分類Dev

ブラウザからのAPI呼び出しは機能しますが、フロントエンドアプリからは機能しません

分類Dev

PythonでWebURLを使用してファイルをダウンロードする方法は?ブラウザからのダウンロードは機能しますが、Pythonのリクエストからは機能しません

分類Dev

ブラウザからのAjaxは機能しませんが、PostManからは機能します

分類Dev

Web認証はブラウザ間で機能しますか?

分類Dev

Firestoreルールはプレイグラウンドで機能しますが、外部リクエストからは機能しません

分類Dev

ImageMagickからの変換はコマンドラインで機能しますが、ローカルホストからは機能しません

分類Dev

HTTP DELETEはブラウザからは機能しますが、PostmanまたはIOSアプリからは機能しません

分類Dev

Mysqliはコマンドラインから機能しますが、HTML /ブラウザ経由では機能しません

分類Dev

Graphene GraphiQLはブラウザーでは機能しませんが、Insomniaクライアントは問題なく機能します

分類Dev

Shopifyは、getリクエストを使用してカートにアイテムを追加しますが、ブラウザーでは機能しますが、golangスクリプトでは機能しません

分類Dev

スクリプトはJSFiddleで機能しますが、ブラウザーでは機能しません

分類Dev

<script>タグはデスクトップブラウザでは機能しますが、モバイルでは機能しません(MEANアプリ)

分類Dev

Ubuntuのchmodコマンドはコマンドラインからは機能しますが、bashスクリプトからは機能しません

分類Dev

カスタムdjango認証バックエンドは、最初はユーザーをログインしませんが、2回目は機能します

分類Dev

CSSカスタムカーソルが機能しません。ブラウザはそれをサポートしなくなりましたか?

分類Dev

Scrapyのカスタムファイルパイプラインは、ログがすべての機能にアクセスする必要があるにもかかわらず、ファイルをダウンロードしません

分類Dev

Googleスプレッドシートからのデータの取得はjsfiddleで機能しますが、ローカルクライアントでは機能しません

分類Dev

rmコマンドと!コマンドラインからは機能しますが、bashスクリプトからは機能しません

分類Dev

スクリプトはブラウザでは機能しますが、NodeJSでは機能しません

分類Dev

JavaアプレットはIDEで機能しますが、ブラウザでは機能しません

分類Dev

VPN設定からは機能しますがRASPHONEからは機能しません-カスタムスクリプト(ルーティングテーブルを更新するため)が失敗しました(8007026f)

分類Dev

18.04では、サードモニターはライブUSBからは機能しますが、HDDからは機能しません

分類Dev

18.04では、サードモニターはライブUSBからは機能しますが、HDDからは機能しません

分類Dev

WebブラウザからのYoutube / Facebookライブストリームはどのように機能しますか

分類Dev

gnome-terminalコマンドはコマンドラインからは機能しますが、Cinnamonショートカット(またはスクリプト)からは機能しません

分類Dev

ハイパーリンククリックイベントはphonegapでは機能しませんが、ブラウザでは機能します

分類Dev

プログラムはターミナルからは正常に実行されますが、シェルスクリプトからは機能しません

Related 関連記事

  1. 1

    Laravelioc自動解決-コントローラーからは機能しますが、カスタムクラスからは機能しません

  2. 2

    Pythonインポートはインタラクティブに機能しますが、スクリプトからは機能しません

  3. 3

    ブラウザからのAPI呼び出しは機能しますが、フロントエンドアプリからは機能しません

  4. 4

    PythonでWebURLを使用してファイルをダウンロードする方法は?ブラウザからのダウンロードは機能しますが、Pythonのリクエストからは機能しません

  5. 5

    ブラウザからのAjaxは機能しませんが、PostManからは機能します

  6. 6

    Web認証はブラウザ間で機能しますか?

  7. 7

    Firestoreルールはプレイグラウンドで機能しますが、外部リクエストからは機能しません

  8. 8

    ImageMagickからの変換はコマンドラインで機能しますが、ローカルホストからは機能しません

  9. 9

    HTTP DELETEはブラウザからは機能しますが、PostmanまたはIOSアプリからは機能しません

  10. 10

    Mysqliはコマンドラインから機能しますが、HTML /ブラウザ経由では機能しません

  11. 11

    Graphene GraphiQLはブラウザーでは機能しませんが、Insomniaクライアントは問題なく機能します

  12. 12

    Shopifyは、getリクエストを使用してカートにアイテムを追加しますが、ブラウザーでは機能しますが、golangスクリプトでは機能しません

  13. 13

    スクリプトはJSFiddleで機能しますが、ブラウザーでは機能しません

  14. 14

    <script>タグはデスクトップブラウザでは機能しますが、モバイルでは機能しません(MEANアプリ)

  15. 15

    Ubuntuのchmodコマンドはコマンドラインからは機能しますが、bashスクリプトからは機能しません

  16. 16

    カスタムdjango認証バックエンドは、最初はユーザーをログインしませんが、2回目は機能します

  17. 17

    CSSカスタムカーソルが機能しません。ブラウザはそれをサポートしなくなりましたか?

  18. 18

    Scrapyのカスタムファイルパイプラインは、ログがすべての機能にアクセスする必要があるにもかかわらず、ファイルをダウンロードしません

  19. 19

    Googleスプレッドシートからのデータの取得はjsfiddleで機能しますが、ローカルクライアントでは機能しません

  20. 20

    rmコマンドと!コマンドラインからは機能しますが、bashスクリプトからは機能しません

  21. 21

    スクリプトはブラウザでは機能しますが、NodeJSでは機能しません

  22. 22

    JavaアプレットはIDEで機能しますが、ブラウザでは機能しません

  23. 23

    VPN設定からは機能しますがRASPHONEからは機能しません-カスタムスクリプト(ルーティングテーブルを更新するため)が失敗しました(8007026f)

  24. 24

    18.04では、サードモニターはライブUSBからは機能しますが、HDDからは機能しません

  25. 25

    18.04では、サードモニターはライブUSBからは機能しますが、HDDからは機能しません

  26. 26

    WebブラウザからのYoutube / Facebookライブストリームはどのように機能しますか

  27. 27

    gnome-terminalコマンドはコマンドラインからは機能しますが、Cinnamonショートカット(またはスクリプト)からは機能しません

  28. 28

    ハイパーリンククリックイベントはphonegapでは機能しませんが、ブラウザでは機能します

  29. 29

    プログラムはターミナルからは正常に実行されますが、シェルスクリプトからは機能しません

ホットタグ

アーカイブ