トップ回答者
IIS Windows認証エラー時のリダイレクトについて

質問
-
毎々大変お世話になっております。
IISでWindows認証エラー(HTTPステータス:401)のときに別サイトへリダイレクトを行う方法を探しています。
以下のような動作をさせたいです。
※Windows認証NGのユーザはフォーム認証を行うサイトへ転送させたいため。<認証NGのとき>
リクエスト → IIS → ASP.net - Global.asax(AuthenticateRequestイベント) → リダイレクト(カスタムエラーで設定)<認証OKのとき>
リクエスト → IIS → ASP.net - Global.asax(AuthenticateRequestイベント → AuthorizeRequestイベント) → 後処理<試してみたこと>
HTTPステータス:401のときにWeb.configカスタムエラー(エラーページ)設定でリダイレクトするようにしたのですが
Windows認証成功となりうるユーザでアクセスした場合でも認証前にリダイレクトが発生してしまい
意図した動作にさせることができませんでした。(認証確認後にリダイレクトされるものと思っておりました。)
「IIS 認証エラー リダイレクト」などのキーワードで検索してみましたが有益な情報を得ることができませんでした。web.configに追加したコード
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="401" />
<error statusCode="401" path="[リダイレクト先URL]" responseMode="Redirect" />
</httpErrors>
</system.webServer>
<開発環境/動作環境>
Windows7 professional x64 SP1
VisualStudio2013 professional(VB)
ASP.net 4.5(「ASP.net 空のWebアプリケーション」から作成)
IIS Express 7.5
以上、よろしくお願いいたします。
回答
-
> ログイン済みのユーザの場合、ステップ(1)~(4)は同様の動作となりステップ
> (5)、(6)が省略され、(7)以降の処理されます。情報提供をありがとうございました。無駄な手間となってしまったようですみません。
自分でよく調べれば分かったことで、以下のページの Windows Integrated のセクションに、Kerberos も NTLM も、認証済み / 未認証ユーザーの違いはステップ (5), (6) の有無ということが書いてありました。
How IIS authenticates browser clients
https://support.microsoft.com/ja-jp/kb/264921/enそうすると、先の私のレスの手段はもちろんダメで、ステップ (5), (6) の有無の違いを利用してサーバー側のプログラムで自動的にリダイレクトに導くという手段は自分には思いつきません。
考えられるのは、サーバー側でダメならクライアント側で何とかできないかということで、カスタムエラーページを作ってそこで対応することです。具体的には以下の通りです。
ログインしてないユーザーがアクセス ⇒ ユーザー名とパスワード入力のためのダイアログが表示される ⇒ ユーザーが[X]または[キャンセル]ボタンをクリック ⇒ カスタムエラーページを表示する ⇒ そこで Form 認証サイトへ遷移することを通知し、スクリプトで自動的に遷移する・・・という感じです。
それには、カスタムエラーページを作って、一番最初の質問に書いてあった web.config で httpErrors 要素に error 属性を追加したコードで、path をそのカスタムエラーページへのパス、responseMode を "File" にすればよさそうです。
ちょっと難ありかもしれませんが、よろしければ検討ください。
- 回答としてマーク mikupedia 2015年6月29日 1:06
すべての返信
-
以前のスレッド ↓ の話の続きですか?
そして、現在は、そこに書いてあった、
> Windows認証用サイトでの401エラーはIISでFrom認証サイトへリダイレクトする設定としました。
を実現しようとしているという状況ですか?
-
佐祐理 様
>IISの動作以前にHTTPの認証の仕組みを理解すべきです。
>HTTPでは認証要求も認証失敗も401エラーを使用します。ですので質問のような動作になります。
当方のHTTPの理解不足についてお手数おかけします。
現動作が正しいということで別途方法を模索いたします。
なちゃ 様>ステータスコードでリダイレクトではなく、AuthenticateRequestイベントなどでUserを確認して未認証ならリダイレクトという方向ならどうでしょうか?
AuthenticateRequestイベントは以下のような挙動のため、
Userを確認して未認証という判断はおそらく行えないと思います。認証OKの場合、2回発生します。
AuthenticateRequest(User:NULL) → AuthenticateRequest(User:NOT NULL)認証NGの場合、1回発生します。
AuthenticateRequest(User:NULL)
SurferOnWww 様>以前のスレッド ↓ の話の続きですか?
>
>https://social.technet.microsoft.com/Forums/ja-JP/f805a035-ec72-4edf-b536-2bcdced35073/windows?forum=aspnetja
>
>そして、現在は、そこに書いてあった、
>
>> Windows認証用サイトでの401エラーはIISでFrom認証サイトへリダイレクトする設定としました。
>
>を実現しようとしているという状況ですか?上記の通りです。
先日確認した時は実現できていたような気がしたのですが当方の思い違いでした。
本来は該当スレッドの続きとして記載すべき内容だとは思いますが、
回答マークをつけてしまったため別スレッドを立てさせていただきました。
※が、回答マークも解除できたのですね・・・。度々申し訳ありません。仰るとおり、
Windows認証用サイトでの401エラーはIISでFrom認証サイトへリダイレクトを実現させるための方法を模索しています。
度々、お手数をおかけして申し訳ありません。 -
佐祐理 様のご指摘どおり認証フローが理解できていなかったのでいろいろ調べています。
(まだ、理解するには程遠いとは思いますが・・・AuthenticateRequestイベントで認証されていなければ認証ヘッダをつけてあげれば
なんとかなったりしないかなと安易な気持ちでいました。認証ヘッダ「WWW-Authenticate: Negotiate」をヒントに
http://keicode.com/iis/iis-authentication.php
のページを参照してみましたがそんな単純に行くものでもないのですね・・・ -
ブラウザーからのリクエストに対してWebサーバーの振る舞いですが、
- Basic認証、Digest認証、Windows認証の場合、
Webサーバーは401エラーを返します。
ブラウザーは認証情報と共に再度リクエストします。
Webサーバーは認証が成功した場合は元のコンテンツを返します。失敗した場合は401エラーを返します。 - Form認証の場合、
Webサーバーは301でログインページにリダイレクトします。
ブラウザーはログインページをリクエストします。
Webサーバーはログインページの内容を返します。
ブラウザーはログインフォームの内容を送信します。
Webサーバーは認証が成功した場合はCookieと共に元のアドレスに再度リダイレクトします。失敗した場合は再度ログインページを返します。
ブラウザーはCookieと共に元のアドレスをリクエストします。
Webサーバーは元のコンテンツを返します。
このような流れとなっているため、基本的にWindows認証とForm認証は最初の応答が異なるため相容れない存在です。その点も踏まえて先のスレッドではBasic認証かDigest認証を提案しました。(認証可能なアカウントに難がありましたが…。)
- Basic認証、Digest認証、Windows認証の場合、
-
佐祐理 様
ご丁寧に説明していただきありがとうございました。
先日ご提案いただいたBasic認証の件ですが
いろいろご配慮していただいたのにもかかわらず
真意を汲み取れず申し訳ありませんでした。本件についてはWindows認証失敗時のリダイレクトは標準機能では賄えないと判断し以下のような対応とすることにしました。
<Windows認証サイトへのアクセス>
Windows端末からのアクセス → Windows認証(認証OK) → メインサイトへリダイレクト
Windows端末からのアクセス → Windows認証(認証NG) → 401認証エラー
Windows以外の端末からのアクセス → フォーム認証サイトへリダイレクト
※OSはHTTPヘッダ情報「User-Agent」で判断なお、未認証時にメインサイトにアクセスされた場合は
クライアントOSによりにWindows認証サイトかForm認証サイトへリダイレクトさせようとおもいます。 -
ドメイン環境での統合 Windows 認証で検証する環境を持ってないのにこういうレスをするのもなんですが・・・
「Windows認証サイト」というのはイントラネット内の Active Directory ドメイン環境で統合 Windows 認証によってシングルサインオンが実現されていて、ユーザーは全員ドメインアカウントを持っていて、自分の PC を立ち上げる時にドメインにログイン済みのユーザーを対象にしているのですよね?
そして、今やりたいことは、ドメインアカウントを持っていない(もしくはブラウザが統合 Windows 認証をサポートしていない)ユーザーが「Windows認証サイト」にアクセスしてきたとき、別のアプリケーションとして作成した「From認証サイト」にリダイレクトするということですよね?
そうであれば、Fiddler2 などのパケットキャプチャツールで、ログイン済みのドメインユーザーがアクセスしてきたときと、ログインしてないユーザーがアクセスしてきたときの違いを調べると、ヒントが見つかるかもしれませんが、そのあたりはすでに検討済みなのでしょうか?
自分の開発環境(Vista SP2 32-bit, IIS7, ASP.NET 3.5)で試験用に作った Windows 認証サイトで、Visual Studio 2010 の[デバッグ開始(S)]でアプリを実行してみたところ、以下のような動きになります。もし、統合 Windows 認証によってドメインにログイン済みのユーザーの場合は違うステップになるなら、そのあたりの差を利用して何とかできるかもしれません。(そのあたりは自分は検証できないので分かりませんが、ひょっとしたら (3) ~ (6) のステップがログイン済みユーザには無いとか)
(1) Visual Studio から Default.aspx ページをデバッグ実行。
(2) ブラウザは Default.aspx を GET 要求。
(3) サーバー側で AuthenticateRequest イベント発生。Users は null。
(4) 401 応答が返ってくる。応答ヘッダには以下が含まれている。
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM(5) クライアントにはユーザー名とパスワード入力のためのダイアログが表示される。
(6) 正しいユーザー名とパスワード入力して[OK]ボタンをクリック
(7) ブラウザは Default.aspx を GET 要求。要求ヘッダには下記が含まれる。
Authorization: Negotiate TlRMTVNTUAABAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAGAHIXAAAADw==
(8) 401 応答が返ってくる。応答ヘッダには以下が含まれている。
WWW-Authenticate: Negotiate TlRMTVNTUAACAAAAEgASADgAAAAVgoriK+iSTbKH8koAAAAAAAAAAGgAaABKAAAABg
ByFwAAAA9QAEEAUABJAEsATwAtAFAAQwACABIAUABBAFAASQBLAE8ALQBQAEMAAQAS
AFAAQQBQAEkASwBPAC0AUABDAAQAEgBQAGEAcABpAGsAbwAtAFAAQwADABIAUABhAH
AAaQBrAG8ALQBQAEMABwAIAD+I+iIurtABAAAAAA==
(9) 再びブラウザは Default.aspx を GET 要求(自動的)。要求ヘッダには下記が含まれている。
Authorization: Negotiate
TlRMTVNTUAADAAAAGAAYAIwAAADYANgApAAAABIAEgBYAAAAEAAQAGoAAAASABIAeg
AAABAAEAB8AQAAFYKI4gYAchcAAAAPaHM/KqKX6no70323sYpFOFAAYQBwAGkAawBv
AC0AUABDAFAAYQBwAGkAawBvAFAAQwBQAEEAUABJAEsATwAtAFAAQwAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAPO+Sr/9QfrqLTPTQkRrELAQEAAAAAAAA/iPoiLq7QAVbT
xgHO5/3OAAAAAAIAEgBQAEEAUABJAEsATwAtAFAAQwABABIAUABBAFAASQBLAE8ALQ
BQAEMABAASAFAAYQBwAGkAawBvAC0AUABDAAMAEgBQAGEAcABpAGsAbwAtAFAAQwAH
AAgAP4j6Ii6u0AEGAAQAAgAAAAgAMAAwAAAAAAAAAAAAAAAAMAAA7rXvA8yvR+RRVd
0VofIOvScVdHuHEkE1uH2p76lsHgMAAAAAAAAAAAAAAAAMnKpktPLoqeT9X4D8ZbC5(10) サーバー側で AuthenticateRequest イベント発生。Users にはログインしたユーザーの WindowsPrincipal が設定されている。Users.Identity からは WindowsIdentity が取得できる。
(11) サーバー側で PostAuthenticateRequest イベント発生。Users にはログインしたユーザーの WindowsPrincipal が設定されている。Users.Identity からは WindowsIdentity が取得できる。
(12) 200 応答が返ってくる。ブラウザには期待通り Default.aspx が表示される。
(13) ブラウザ上の別ページ Default2.aspx へのリンクをクリック。
(14) 上の (7) ~ (12) ステップと同様な処置が Default2.aspx に対して繰り返される。
- 編集済み SurferOnWww 2015年6月24日 5:38 一部訂正
-
SurferOnWww 様
わざわざ、環境まで作ってご確認していただき大変お手数をおかけしました。
「Windows認証サイト」というのはイントラネット内の Active Directory ドメイン環境で統合 Windows 認証によってシングルサインオンが実現されていて、ユーザーは全員ドメインアカウントを持っていて、自分の PC を立ち上げる時にドメインにログイン済みのユーザーを対象にしているのですよね?
→ その通りです。
そして、今やりたいことは、ドメインアカウントを持っていない(もしくはブラウザが統合 Windows 認証をサポートしていない)ユーザーが「Windows認証サイト」にアクセスしてきたとき、別のアプリケーションとして作成した「From認証サイト」にリダイレクトするということですよね?
→ その通りです。
そうであれば、Fiddler2 などのパケットキャプチャツールで、ログイン済みのドメインユーザーがアクセスしてきたときと、ログインしてないユーザーがアクセスしてきたときの違いを調べると、ヒントが見つかるかもしれませんが、そのあたりはすでに検討済みなのでしょうか?
→ パケットキャプチャツールでの確認は未実施です。
ご確認いただいた環境での動作ですが当方でも同様の動きです。
佐祐理 様にご解説いただきましたが、認証要求と認証失敗がともにHTTPステータス401となり
ASP側またはIISのカスタムエラーの機能ではどちらか切り分けることができないため
今回やりたいことは実現できない可能性が大きいと思われます。
※HTTPステータスがそれぞれ違うコードであれば実現できたかもしれませんが、サブコードまで同じ。ドメイン不参加のWindowsユーザがアクセスしたときには
認証要求ヘッダがサーバから送信され認証ダイアログが表示されます。
もし、認証失敗するようなアカウントとパスワードが入力された場合は
AuthenticateRequestイベントは発生しませんが、リクエストヘッダにAuthorizationが含まれているので
HTTPステータス401とともにEndRequestイベントで判断することはできます。
※必ず何か入力しないとですし、入力をキャンセルされてしまうとサーバにリクエストがいかないため判断できない・・・ただ、Windowsユーザ名を取得したいため匿名アクセスの禁止しています。
匿名ユーザのアクセスでは初回リクエストのみで収束(認証エラー)してしまうため上記のような方法でもだめですね。 -
HTTP 401 を見て判断するというのではなくて、先のレスで書いたように、「もし、統合 Windows 認証によってドメインにログイン済みのユーザーの場合は違うステップになるなら、そのあたりの差を利用して何とかできるかもしれません。」という話なんですが。
少なくとも、ドメイン環境で統合 Windows 認証によってシングルサインオンが実現されていれば、ドメインにログイン済みのユーザーに対してはステップ (5) のダイアログが出ることはありません。なので、違いがあることは間違いないはずです。
しかし、ドメイン環境で (2) ~ (14) のステップがどう違うかを検証する環境は自分は持ってないし、質問者さんの環境で検証しないとわからないこともあるでしょうから、質問者さんの方で検証していただきたかったのですが・・・
もし、検証の結果、ドメインにログイン済みのユーザーの場合は必ずステップ (7) 以降から始まる(即ち、最初の要求で発生する AuthenticateRequest イベントでは User.Identity.IsAuthenticated は true になる)、ログインしてないユーザーがアクセスしてきたときは必ずステップ (2) から始まる(即ち、最初の要求で発生する AuthenticateRequest イベントでは User が null になる)のであれば、何とかする手段はあるのではないでしょうか。
何とかする手段というのは、例えば、
> ドメイン不参加のWindowsユーザがアクセスしたときには
> 認証要求ヘッダがサーバから送信され認証ダイアログが表示されます。の 2 行目に行く前に、以下のようにしてリダイレクトしてしまうと言うことです。
void Application_AuthenticateRequest(Object sender, EventArgs e) { if (User == null) { HttpContext.Current.Response.Redirect("リダイレクト先"); } }
質問者さんの環境で検証して結果を教えていただけると幸いです。
-
SurferOnWww 様
たびたびお世話になります。
>もし、統合 Windows 認証によってドメインにログイン済みのユーザーの場合は違うステップになるなら・・・
ドメイン環境で確認しました。
ログイン済みのユーザの場合、ステップ(1)~(4)は同様の動作となりステップ(5)、(6)が省略され、(7)以降の処理されます。
一度目の「Application_AuthenticateRequest」はいずれもuser.IdentityはNULLとなり、
認証完了後の二度目の「Application_AuthenticateRequest」でuser.Identityがセットされるという結果となりました。 -
> ログイン済みのユーザの場合、ステップ(1)~(4)は同様の動作となりステップ
> (5)、(6)が省略され、(7)以降の処理されます。情報提供をありがとうございました。無駄な手間となってしまったようですみません。
自分でよく調べれば分かったことで、以下のページの Windows Integrated のセクションに、Kerberos も NTLM も、認証済み / 未認証ユーザーの違いはステップ (5), (6) の有無ということが書いてありました。
How IIS authenticates browser clients
https://support.microsoft.com/ja-jp/kb/264921/enそうすると、先の私のレスの手段はもちろんダメで、ステップ (5), (6) の有無の違いを利用してサーバー側のプログラムで自動的にリダイレクトに導くという手段は自分には思いつきません。
考えられるのは、サーバー側でダメならクライアント側で何とかできないかということで、カスタムエラーページを作ってそこで対応することです。具体的には以下の通りです。
ログインしてないユーザーがアクセス ⇒ ユーザー名とパスワード入力のためのダイアログが表示される ⇒ ユーザーが[X]または[キャンセル]ボタンをクリック ⇒ カスタムエラーページを表示する ⇒ そこで Form 認証サイトへ遷移することを通知し、スクリプトで自動的に遷移する・・・という感じです。
それには、カスタムエラーページを作って、一番最初の質問に書いてあった web.config で httpErrors 要素に error 属性を追加したコードで、path をそのカスタムエラーページへのパス、responseMode を "File" にすればよさそうです。
ちょっと難ありかもしれませんが、よろしければ検討ください。
- 回答としてマーク mikupedia 2015年6月29日 1:06
-
【追伸】
上の案を自分の環境で検証してみましたが、無効なユーザー名やパスワードが入力された場合はカスタムエラーページは表示されす、上に書いた方法では対応できませんでした。
でも、質問者さんが先のレスの書いた、
> ※必ず何か入力しないとですし、入力をキャンセルされてしまうとサーバにリクエスト
> がいかないため判断できない・・・というところには対応できますし、無効なユーザー名やパスワードが入力された場合は、これも質問者さんが書いた、
> HTTPステータス401とともにEndRequestイベントで判断することはできます。
で対応できると思います。以下のような感じ:
void Application_EndRequest(object sender, EventArgs e) { if (User != null) { bool auth = User.Identity.IsAuthenticated; int statusCode = Response.StatusCode; if (auth && statusCode == 401) { HttpContext.Current.Response.Redirect("リダイレクト先"); } } }
ユーザー名とパスワードを入力するダイアログが表示されるのは避けられないとうところが難ありですが、それでもよければ上記の案を質問者さんの環境でも試してみてください。 -
SurferOnWww 様
今回は当方にお付き合いいただき、誠にありがとうございました。
やりたいことは現時点で全てを網羅することは不可ですね。ご提示していただきました案を早速こちらでも確認しました。
ローカルユーザ等でドメイン認証不可となるユーザの場合、
ブラウザの設定にもよりますが、認証ダイアログは出てしまいますね。ただ、
>上の案を自分の環境で検証してみましたが、
>無効なユーザー名やパスワードが入力された場合はカスタムエラーページは表示されす、
>上に書いた方法では対応できませんでした。こちらではきちんとカスタムエラーページとなるため、
当方が理想としていたものに近い動作となります。
よって、Application_EndRequestの処理は特に必要なく、
カスタムエラーの設定とエラーページの作成で対応できそうです。
IISやブラウザのバージョンによってひょっとすると動きが変わるかもしれませんね。
https://technet.microsoft.com/ja-jp/library/ee431601.aspx確認ブラウザはIE11です。
[インターネットオプション]-[ローカルイントラネット]-[レベルのカスタマイズ]から
ユーザ認証の方法を切り替えて確認しました。<system.webServer> <httpErrors errorMode="Custom"> <remove statusCode="401" /> <error statusCode="401" path="error.html" responseMode="File" /> </httpErrors> </system.webServer>
Windows以外はBeginRequestイベントでRequest.Headers("User-Agent")のOSがWindowsかどうかチェックすれば androidやiosは認証ダイアログなしでリダイレクトできますね。
今回はSurferOnWww 様、佐祐理 様、なちゃ 様には大変お世話になりました。
本件はこれをもって解決とし、クローズいたします。
お付き合いいただきありがとうございました。- 編集済み mikupedia 2015年6月29日 1:07 誤字訂正
-
> こちらではきちんとカスタムエラーページとなるため、
> 当方が理想としていたものに近い動作となります。
> よって、Application_EndRequestの処理は特に必要なく、
> カスタムエラーの設定とエラーページの作成で対応できそうです。
> IISやブラウザのバージョンによってひょっとすると動きが変わるかもしれませんね。自分の開発環境は Vista SP2 32-bit の IIS7、質問者さんの運用環境は前のスレッドによると Windows Server 2008R2 とのことでしたから IIS7.5 ということで、そのあたりの違いなのかもしれませんね。
ちなみに、自分の環境の場合、一番最初の要求で帰ってくる 401 エラーページと、認証ダイアログが表示され無効な ID / パスワードを入力したときに返ってくる 401 エラーページは違ったものになり、後者をカスタムエラーページに差し替えることは自分が試した限りできませんでした(give up しました)。
httpErrors の設定は、error 要素の path 属性を "C:\inetpub\custerr\ja-JP\HTTP401ErrorPage.htm" とした以外は質問者さんと全く同じなんですが。
ただ、その他に、質問者さんの環境では web.config に httpErrors を直接設定できるそうですが、自分の環境では applicationHost.config で以下のように設定されているので web.config では httpErrors を設定できないという違いはありました。
<section name="httpErrors" overrideModeDefault="Deny" />
ご参考まで。