何もかもこの夏の暑さのせいです
ようやっとプロジェクトの設定を変更するときが来ました。長かったです。
……もっと短くまとめられるはずなんですけどねー。
Microsoftのエバンジェリストの方々はすごいです。
ACSの設定忘れ
ACSの設定で、1か所設定しなければいけない部分を設定し忘れていました。それは、「規則グループ」です。
これを設定していないと、ACSはIDプロバイダから何を取得していいのかわからず、エラーになります。
まずはACSの設定ポータルで「規則グループ」を選び、自動で作成されている規則を選択します。
選択したら、「ルール」の欄に「生成」のリンクがありますので選択します。
デフォルトの状態で規則を生成してくれますので、全てのIDプロバイダにチェックが入っている状態で「生成」をクリックします。
最後に、真ん中近辺にある「保存」のボタンをクリックして生成した規則を保存しておきます。
これでIDプロバイダから指定のClaimが取得できるようになります。
VisualStudio2012のプロジェクトの設定
ここまででACSの設定は済んでいますよね。基本的なところはデフォルトにしてしまったので、特に難しいものでもなかったと思います。
さて、次はそのACSを使用するようにプロジェクトを設定していくことにします。
今回は画像少な目に……。少な目に……(涙目)
ルートページの作成
何はなくとも、/ で表されるルートのページを作っておきましょう。ASP.NET MVC4を選びましたので、コントローラーを作成していけばページは作られます。
前回作成したプロジェクト内にControllersというディレクトリがありますので、そこを右クリックし、「追加」→「コントローラー」を選択します。
上記のようなダイアログが表示されますので、「コントローラー名」の欄にHomeControllerとなるように入力、また、テンプレートはEmpty MVC controllerを選び「追加」をクリックします。
次に、Viewsディレクトリで右クリックし、「追加」→「新規ディレクトリ」を選択します。
すると、新しいディレクトリが作成されますので、ディレクトリ名をHomeに変更します。
そして、今変更したHomeディレクトリで右クリックし、「追加」→「表示...」を選択し、ビュー名をIndexとしたファイルを作成します。
作成の際に、「レイアウトまたはマスターページを使用する」の下の欄に_Layout.cshtmlを選択するように設定しておきます。
これにより、レイアウトにテンプレート的な何かを使用することができるようになります。
(この場合、_Layout.cshtmlファイルですね)
これで / の設定は終わりました。
ためしにF5でデバッグをしてみると、「Index」と書いたページが表示されます。
基本的にASP.NET MVC4に関することは今回は扱いません。
ざっと手順だけ書きますので、なぜそういうことをしているのかは自分で勉強してください。
(気が向いたらまた書くかもしれませんが)
ログインページの作成
さて、やっとログインのページを作成するときが来ました。ACSの設定からもわかるように、ログイン関係はLoginControllerの1ファイルで済ませるつもりです。
先ほどのHomeControllerと同様に、LoginControllerを作成し、次のような関数を作成します。
public class LoginController : Controller { public ActionResult Index() { string returnUrl = this.Request.Params["ReturnUrl"]; if (string.IsNullOrEmpty(returnUrl)) { returnUrl = "/"; } Session["login_return_url"] = returnUrl; return View(); } public ActionResult LoggedIn() { string returnUrl = (string)Session["login_return_url"]; Session.Remove("login_return_url"); if (!string.IsNullOrEmpty(returnUrl)) { return Redirect(returnUrl); } return Redirect("/"); } public ActionResult Error() { var t = this; Session.Remove("login_return_url"); return Redirect("/"); } }
ログイン後に表示するURLがパラメータになってわたってくるときがありますので、その対処のみ入れてあります。
次に、表示ファイルを作りますが、今度は Views\Login\Index.cshtml を以下の内容で作成します。
ここでは、実行状況を判定して、読み込むURLを変更しています。
読み込み元はACSの「アプリケーション統合」→アプリケーション名→「オプション2」に記されているURLをコピペして記載し、JSONP用の戻り関数を「setProviders」に設定したものです。
アプリケーション名で選択する際、ローカルとWebSites用と両方とも辿って記載しています。
@{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Login</h2> <div> <ul id="providers"></ul> </div> @section scripts { <script type="text/javascript"> function setProviders(data) { for (var i = 0; i < data.length; i++) { $("#providers").append("<li><a href=\"" + data[i].LoginUrl + "\">" + data[i].Name + "</a></li>"); } } </script> @if (Request.IsLocal) { <script type="text/javascript" src="https://acstst.accesscontrol.windows.net:443/v2/metadata/IdentityProviders.js?protocol=wsfederation&realm=http%3a%2f%2flocalhost%3a30994%2f&reply_to=http%3a%2f%2flocalhost%3a30994%2flogin%2floggedin&context=&request_id=&version=1.0&callback=setProviders"></script> } else { <script type="text/javascript" src="https://acstst.accesscontrol.windows.net:443/v2/metadata/IdentityProviders.js?protocol=wsfederation&realm=https%3a%2f%2facstest.azurewebsites.net%2f&reply_to=https%3a%2f%2facstest.azurewebsites.net%2flogin%2floggedin&context=&request_id=&version=1.0&callback=setProviders"></script> } }
基本のソースコードはここまでです。
WIFを生成物に含めるようにする
前々回に設定したWIF3.5の環境。
実はDLLをプロジェクトに読み込んでやらなければいけません。
一応、WIFで認証処理されますので……。
プロジェクトの「参照設定」→「参照の追加」を選択。
出てきたダイアログ内で、「アセンブリ」→「拡張子」と選び、一覧の中から「Microsoft.IdentityModel」にカーソルを合わせ、名前の左に出てきた四角をクリックします。
すると、チェックがつきますので、OKをクリックします。
ソリューションエクスプローラーに戻ってきたら、「詳細設定」内に増えている「Microsoft.IdentityModel」を右クリックし、プロパティを選びます。
プロパティ設定画面が表示されますので、「ローカルコピー」の欄をTrueに変更します。
こうすることで、Microsoft.IdentityModelが生成物の中に含められ、使用できるようになります。
(WebSitesにはデフォルトでは入っていないのです)
WIF SDKを使用してACSを使用するように設定する
すみません、今回超長いです。
まだまだやること沢山あります。
見捨てないください。
WIF SDKに入っているFedUtil.exeを使用して認証部分をACSを使用するように変更します。
FedUtil.exeは通常 C:\Program Files (x86)\Windows Identity Foundation SDK\v3.5 にあるはずです。
起動するとまずは変更するWeb.Configの位置と、領域のURLを入力します。
ここではまずローカル環境のものを設定しておきます。
入力後、Nextを押すとhttpでセキュアじゃない、と言われますが気にせず続けます。
すると、ACSのWS-FederationのURLを入力する画面に切り替わるので、ACSの設定の「アプリケーション統合」に記載されているWS-FederationメタデータのURLを入力します。
あとはアプリが終了するまでNextやFinishやらのボタンを押していけばおっけー。
Web.Configがいろいろ書き換えられますが、まず手直しするのが以下の部分。
</appSettings> <!-- <location path="FederationMetadata"> <system.web> <authorization> <allow users="*" /> </authorization> </system.web> </location> --> <system.web> <!-- <authorization> <deny users="?" /> </authorization> --> <authentication mode="Forms"><forms loginUrl="~/login" timeout="2880" /></authentication> <!-- <authentication mode="None" /> --> <httpRuntime requestValidationMode="2.0" /> <compilation debug="true" targetFramework="4.0">
初期設定のままだと、どのページを見てもログインしていなければログインページにリダイレクトされます。
ちょっとウザいので、デフォルトリダイレクトはさせずに、ログインが必要な場合のとび先を /login になるように変更しておきます。
また、認証プロトコル的にエラーになるので、その回避(httpRuntimeの行)を行っておきます。
そして、重要な変更はだいたい以下のようにWeb.Configに追加されています。
<microsoft.identityModel> <service> <audienceUris> <add value="http://localhost:30994/" /> </audienceUris> <federatedAuthentication> <wsFederation passiveRedirectEnabled="true" issuer="https://acstst.accesscontrol.windows.net/v2/wsfederation" realm="http://localhost:30994/" requireHttps="false" /> <cookieHandler requireSsl="false" /> </federatedAuthentication> <applicationService> <claimTypeRequired> <!--Following are the claims offered by STS 'https://acstst.accesscontrol.windows.net/'. Add or uncomment claims that you require by your application and then update the federation metadata of this application.--> <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" /> <claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" /> <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" optional="true" />--> <!--<claimType type="http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider" optional="true" />--> </claimTypeRequired> </applicationService> <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <trustedIssuers> <add thumbprint="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" name="https://acstst.accesscontrol.windows.net/" /> </trustedIssuers> </issuerNameRegistry> <certificateValidation certificateValidationMode="None" /> </service> </microsoft.identityModel>
ここで設定したのはローカルデバッグ環境用なので、WebSitesにデプロイする際の設定も行っておきます。
上記の部分をWeb.Configからコピーし、Web.Release.Configに貼り付けます。
そして、領域部分を書き換え、デプロイ時に反映されるように変更します。
変更後のWeb.Release.Configは以下のようになります。
<?xml version="1.0"?> <!-- For more information on using Web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 --> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <!-- In the example below, the "SetAttributes" transform will change the value of "connectionString" to use "ReleaseSQLServer" only when the "Match" locator finds an atrribute "name" that has a value of "MyDB". <connectionStrings> <add name="MyDB" connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/> </connectionStrings> --> <system.web> <compilation xdt:Transform="RemoveAttributes(debug)" /> <!-- In the example below, the "Replace" transform will replace the entire <customErrors> section of your Web.config file. Note that because there is only one customErrors section under the <system.web> node, there is no need to use the "xdt:Locator" attribute. <customErrors defaultRedirect="GenericError.htm" mode="RemoteOnly" xdt:Transform="Replace"> <error statusCode="500" redirect="InternalError.htm"/> </customErrors> --> </system.web> <microsoft.identityModel> <service> <audienceUris> <add value="https://acstest.azurewebsites.net/" xdt:Transform="Replace" /> </audienceUris> <federatedAuthentication> <wsFederation passiveRedirectEnabled="true" issuer="https://acstst.accesscontrol.windows.net/v2/wsfederation" realm="https://acstest.azurewebsites.net/" requireHttps="true" xdt:Transform="Replace" /> <cookieHandler requireSsl="true" xdt:Transform="Replace" /> </federatedAuthentication> <applicationService> <claimTypeRequired> <!--Following are the claims offered by STS 'https://acstst.accesscontrol.windows.net/'. Add or uncomment claims that you require by your application and then update the federation metadata of this application.--> <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" /> <claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" /> <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" optional="true" />--> <!--<claimType type="http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider" optional="true" />--> </claimTypeRequired> </applicationService> <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <trustedIssuers> <add thumbprint="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" name="https://acstst.accesscontrol.windows.net/" /> </trustedIssuers> </issuerNameRegistry> <certificateValidation certificateValidationMode="None" /> </service> </microsoft.identityModel> </configuration>
実際のところ、必要なのは xdt:Transform="Replace" を付加した3行分だけなんですけど。
このように設定しておくことで、環境を切り替えることができるようになっています。
WebSites対応
さて、最後の大詰めです。
現状で動かしてみると、ローカルのデバッグ環境では問題なく動くのに、デプロイしてみるとログイン直後にエラーになってしまいます。
これはなにやら、セキュリティ的なエラーが発生しているらしいです。
(System.Security.Cryptography.CryptographicException)
ここはもう、そういうもんなのです。
……というわけにもいかず。
調べてみると、代替案があることがわかります。
VS2012に戻り、ソリューションエクスプローラーの「参照設定」を右クリックし、「NuGetパッケージの管理」を選びます。
NuGetが開いたなら、「identity」で検索をし、出てきた候補の中から「Thinktecture.IdentityModel」をインストールします。
インストールが済んだら、Web.Configに以下の設定を追加します。
<microsoft.identityModel> <service> <audienceUris> <add value="http://localhost:30994/" /> </audienceUris> <federatedAuthentication> <wsFederation passiveRedirectEnabled="true" issuer="https://acstst.accesscontrol.windows.net/v2/wsfederation" realm="http://localhost:30994/" requireHttps="false" /> <cookieHandler requireSsl="false" /> </federatedAuthentication> <applicationService> <claimTypeRequired> <!--Following are the claims offered by STS 'https://acstst.accesscontrol.windows.net/'. Add or uncomment claims that you require by your application and then update the federation metadata of this application.--> <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" /> <claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" /> <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" optional="true" />--> <!--<claimType type="http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider" optional="true" />--> </claimTypeRequired> </applicationService> <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <trustedIssuers> <add thumbprint="2362F91373ED4C69F2B9CBE528100F2B33386B78" name="https://acstst.accesscontrol.windows.net/" /> </trustedIssuers> </issuerNameRegistry> <certificateValidation certificateValidationMode="None" /> <!-- ここから追加 --> <securityTokenHandlers> <remove type="Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add type="Thinktecture.IdentityModel.Web.MachineKeySessionSecurityTokenHandler, Thinktecture.IdentityModel" /> </securityTokenHandlers> <!-- ここまで追加 --> </service> </microsoft.identityModel>
このあたりのことは、Dominick BaierさんのBlogに詳細が書かれています。
……ま、まあ、難しいことはわからないんだけどねっ!
夜中でも暑いです
なんとか駆け足でざっと書いてみましたが……。
ますますもって長い!
いらん事書きすぎです。
実際、慣れてしまえば10分かからない作業なのに……。
とりあえず、ここまでの変更でWindows8 + VisualStudio2012でWebSitesでも無事にACSを使ったサイトを作れるようになりました。
本当はこんなに苦労しなくても、Azureが.Net4.5環境に移行してくれればIdentity and Access toolsだけでかたが付くんですけど。ふぅ。
0 件のコメント:
コメントを投稿