【Microsoft ID プラットフォーム】(Azure AD) ASP.NET Web アプリ編-

はじめに（背景)
----

シングルページ アプリの検証-Node.js編-の続きとなります。
https://qiita.com/Design_Tshirt7/items/553958e3724cc3718aa9

背景は、上記と同じとなりますが、初めてご訪問頂いた人もいると思いますので、記載させて頂きます。

Office365を導入して、数年が経ちました。
皆様が慣れてきて、そろそろ、Office365とのシングルサインをすれば、便利になるんじゃない！！との声が出来てきました。そして、上司から、"Single Sign On よろしく！"との恐ろしい声がかかりました。

確かにIDaaSとしてのAzure ADは既に稼働しているので、後は、連携するアプリケーションの準備が出来れば可能ですが、、、このオンプレWebアプリケーションとIDaaSとのSSOは敷居が高い。

なぜなら、アプリケーション側でSAML/OpenIDConnect/OAuthとおしゃべりができないので、改修が必須となる。そこで、Microsoft ID プラットフォームを使えば、ライブラリが提供されているので、これをうまく活用すれば、SSOの敷居が少しでも低くるなると考え、検証を開始致しました。

Microsoft ID プラットフォーム
----
『Microsoft ID プラットフォーム (旧称: 開発者向け Azure Active Directory)』

https://docs.microsoft.com/ja-jp/azure/active-directory/develop/

>Microsoft ID プラットフォームは、Azure Active Directory (Azure AD) 開発者プラットフォームの進化版です。 これにより、すべての Microsoft ID にサインインして、Microsoft API (Microsoft Graph) や開発者が構築した API を呼び出すためのトークンを取得するアプリケーションを開発者が構築できます。 これはフル機能を備えたプラットフォームであり、OAuth 2.0 および OpenID Connect 標準に準拠した認証サービス、オープンソース ライブラリ、アプリケーションの登録および構成、充実した概念とリファレンスのドキュメント、クイック スタート サンプル、コード サンプル、チュートリアル、攻略ガイドによって構成されています。

ふむふむ。確かにサンプルコードがあるので、できそうかも。。。

いざトライ！！
----
1.参照ページ
『クイック スタート:ASP.NET Web アプリに Microsoft ID プラットフォーム サインインを追加する』

https://docs.microsoft.com/ja-jp/azure/active-directory/develop/quickstart-v2-aspnet-webapp

2.登場人物
1.Identity Provider (Azure AD)
* オンマイクロソフトアカウントを使います。
2.Relying Party (ASP.NET)
　* Visual Studio 2019 (事前の準備をお願い致します。インストール方法は割愛させて頂きます)
* サンプルコード (以降の手順でダウンロード致します。)

3.手順
◆手順 1:アプリケーションの登録

1.Azure portal(https://portal.azure.com) にサインインします。

2.[ホーム]-> [Azure AD Active Directory] -> [アプリの登録]へ進む。

<img width=200 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/2df3a3b9-587a-103b-8b80-dd750883532c.png" alt=1.appregistration.PNG>

3.[新規登録] をクリックします。

<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/a9ba1bef-8fb7-2fbc-9e08-fd7f4d76562c.png" alt="2.newregistration.PNG">

4.アプリケーション登録で下記項目を選択して、[登録]をクリック。
(1).名前欄：任意のアプリケーション名を入力
(2).サポートされているアカントの種類：この組織ディレクトリのみに含まれるアカウント
(3).リダイレクトURL：空白　=> (後ほど、入力されます。)

<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/6f5eeb3a-e1e3-3b96-0601-d029d82997ec.png" alt="3.appreg.PNG">

5.登録したアプリケーションが表示されますので、[クイックスタート]をクリック。

<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/fe5f4815-cbec-c8c8-d009-885fa5c3eb8e.png" alt="4.appreg2.PNG">

6.クイックスタートガイドの[ASP.NET]をクリック。

<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/9d00d918-a675-962a-8976-5670e51e8396.png" alt="5.ASP.NET.PNG">

7.[これらの変更を行います]をクリック。

<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/2c39391c-d464-8cb8-8377-b1ba00771ac2.png" alt="6.changeconf.PNG">

8.下記構成内容が表示されますので、[更新する]をクリック。
(1).リダイレクト URI : http://localhost:44368
(2).アクセストークン・IDトークン：Ture
*上記トークンは、インプリシットフローで利用するトークンとなります。

<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/f8e37fb9-6cf6-8a65-0e42-363147414f6b.png" alt="7.update.PNG">

*下記の[認証]画面から構成の反映を確認可能です。

<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/ea0492df-060d-3ab9-13c6-8e3cef98f5e7.png" alt="8.Authentication.PNG">

◆手順 2:プロジェクトのダウンロード
1.Visual Studio 2019 を使用して IIS Expressサーバーでプロジェクトを実行致しますので、プロジェクトファイルをダウンロードします。

プロジェクトファイル：AppModelv2-WebApp-OpenIDConnect-DotNet-master.zip

<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/90de708f-826b-8875-b8af-b6832fed2ff5.png" alt="1.download.PNG">

◆手順 3:Visual Studio 2019 の構成

1.ローカルフォルダーに zip ファイルを展開します。

<img width="400" alt="1.file.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/214e6083-20a0-f29e-542f-f5abdfef1fa8.png">

2.Visual Studio 2019を起動して、[プロジェクトやソリューションを開く]をクリック。

<img width="400" alt="2.open.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/8defaca5-f140-6421-800e-5f863e82d1c2.png">

3.ソリューション(AppModelv2-WebApp-OpenIDConnect-DotNet.sln)を選択して[開く]をクリック。

<img width="400" alt="3.projectselection.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/137f30e9-d8e7-0ced-fc29-ccec3d86d9ba.png">

4.[表示]->[その他のウィンドウ]->[パッケージ マネージャー コンソール]を選択して、クリック。 

<img width="400" alt="4.package.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/a3a38373-2c0f-cbd9-30cf-83cf2b4ed71c.png">

5.以下を実行。

Update-Package Microsoft.CodeDom.Providers.DotNetCompilerPlatform -r

<img width="500" alt="5.updatecommand.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/a860b5cc-b20e-7eb3-49ec-30680574f45f.png">

6.上記の実行結果となります。完了したらコンソールウィンドウを閉じてください。

<img width="500" alt="6.complete.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/9c3ed7ef-c7e3-e857-09d9-54ad2a688c32.png">

7.[ソリューションエクスプローラー]->[Web.config] を選択してクリック。

<img width="500" alt="7.webconfig.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/03da941e-9a71-0c9b-9879-2312569026fb.png">

8.[Web.config] を編集し、ClientId パラメーターと Tenant パラメーターを書き換えます。
●注意事項："redirectUri"が設定されることを確認してください。この設定が無いと、手順4のサインインの際に手順1のアプリケーションの登録で設定したリダイレクトURLにリダイレクトされないです。

<img width="500" alt="8.edit-2.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/5395ccae-0c6e-dad1-a936-f88362661cca.png">


◆手順4: サインイン

* Fiddlerでパケットキャプチャ。
* 前回、シーケンスを確認せずに、いきなりFiddlerログをみてしまったので、ダウンロードしたコアプロジェクトサンプルの仕組みをきちんと確認。

<img width="400" alt="シーケンス.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/9b7fe046-82c2-191d-7ca6-434e51610130.png">

0.IIS Expressを使って、Webサービスを起動。
<img width="400" alt="1.iis.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/cac3d871-fb63-f8c2-f94a-e6fd3d7b4af6.png">

<b>1.ログイン</b> 
https://yoursite.com へアクセスして、[Sign in with Microsoft]をクリック。

<img width="400" alt="2.aspnet.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/5565b8ba-b89e-3f54-9358-451f877cf1ed.png">

<b>2.認証リクエストの流れ (RPからWebブラウザを経てIDプロバイダへ)</b>
●2-1.リダイレクト
RP(ASP.NET)は、HTTPステータスコード 302を返す。
302を返す際には、Locationヘッダーに『認可エンドポイント』(IDP)のURLが含まれる。

```
HTTP/1.1 302 Found
Location: https://login.microsoftonline.com/a94216cd-7c42-4b24-8ba0-ce5c210951bd/oauth2/v2.0/authorize?
client_id=08b255f7-0c55-4982-9aa4-60d667199641
&redirect_uri=https://localhost:44368/
&response_mode=form_post
&response_type=id_token
&scope=openid profile
&state=OpenIdConnect.AuthenticationProperties=vbhdLE2ZQXh
&nonce=637170666510133284.MDQ5MjVkYTUtOTAwNy00
```

●2-2.Azure ADエンドポイント情報 (/.well-known/openid-configuration) の確認

GET https://login.microsoftonline.com/a94216cd-7c42-4b24-8ba0-ce5c210951bd/v2.0/.well-known/openid-configuration HTTP/1.1
User-Agent: Microsoft ASP.NET Core OpenIdConnect middleware

```
"authorization_endpoint":"https://login.microsoftonline.com/a94216cd-7c42-4b24-8ba0-ce5c210951bd/oauth2/v2.0/authorize",
"token_endpoint":"https://login.microsoftonline.com/a94216cd-7c42-4b24-8ba0ce5c210951bd/oauth2/v2.0/token"
"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo"
```

2-3.認証リクエスト (WebブラウザからIDプロバイダへ) 
認可エンドポイントへの認証リクエスト。下記6個のクエリパラメーターが含まれる。

```
GET https://login.microsoftonline.com/a94216cd-7c42-4b24-8ba0-ce5c210951bd/oauth2/v2.0/authorize?
&response_type=id_token
&client_id=08b255f7-0c55-4982-9aa4-60d667199641
&state=OpenIdConnect.AuthenticationProperties=vbhdLE2ZQXh
&scope=openid profile
&redirect_uri=https://localhost:44368/
&nonce=637170666510133284.MDQ5MjVkYTUtOTAwNy0 
&response_mode=form_post
HTTP/1.1
```

<b>response_type</b>
"idtoken"が設定されているので、サンプルのシーケンス通り、レスポンスには、アクセストークンは含まれず、IDトークンだけが返ってくるパラメーターとなっている。
<b>client_id</b>
Azure ADのアプリ登録の際に発行されたクライアントID
<b>state</b>
RPが設定したランダムを値。
<b>scope</b>
RPが要求するスコープ。
<b>redirect_uri</b>
Azure ADのアプリ登録の際に登録したリダイレクトURI
<b>nonce</b>
　リプレイアタック(不正に傍受した正しいIDトークンを送りつけて、不正アクセスを実現する攻撃)対策として、IDトークンの検証の際に利用する値。

<b>3.資格情報(ID/パスワード)を入力</b>

<b>4.認証レスポンスの流れ (IDプロバイダからWebブラウザを経てRP)</b>

●4-1.同意
<img width="400" alt="3.consent.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/e931ed10-4454-0c1a-f7a0-13f0f7b2f70d.png">

●4-2.認証レスポンス (IDプロバイダからWebブラウザ)
★IDトークン

```
POST https://login.microsoftonline.com/a94216cd-7c42-4b24-8ba0-ce5c210951bd/Consent/Set HTTP/1.1
name="id_token" value="eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtp
```
*ヘッダー、ペイロードを確認。
<img width="500" alt="4.jwtPNG.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/fae2c0cb-6ee8-ab98-6222-0a81177b9264.png">

★アクセストークン
Locationヘッダのフラグメントには、値はありませんでした。
<img width="278" alt="4.access_token.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/fbc8b724-f090-246d-cf3e-a22a4298a2ee.png">

下記URLの記載で、アクセストークンを取得するには、response_typeを変更する必要がございます。今回は、ASP.NET Webアプリが動くかどうかの検証となりますので、このまま進ませていただきます。

https://docs.microsoft.com/ja-jp/azure/active-directory/develop/v1-protocols-openid-connect-code

>アクセス トークンの取得
アクセス トークンを取得するには、前に示したサインイン要求を変更する必要があります。
GET https://login.microsoftonline.com/{tenant}/oauth2/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e        // Your registered Application ID
&response_type=id_token+code
&redirect_uri=http%3A%2F%2Flocalhost%3a12345          // Your registered Redirect Uri, url encoded
&response_mode=form_post                              // `form_post' or 'fragment'
&scope=openid
&resource=https%3A%2F%2Fservice.contoso.com%2F        // The identifier of the protected resource (web API) that your application needs access to
&state=12345                                          // Any value, provided by your app
&nonce=678910                                         // Any value, provided by your app
アクセス許可スコープを要求に組み込み、response_type=code+id_token を使うことによって、authorize エンドポイントはユーザーが scope クエリ パラメーターで示されているアクセス許可に同意したことを確認し、アクセス トークンと引き換えに承認コードをアプリに返します。

<b>5.サインイン</b>
無事、サインインできました。[See your claims]をクリックするとclaimの中身が確認できます。
<img width="400" alt="4.hello.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/28191e1d-018e-4220-f689-b0352aa15a20.png">

<img width="400" alt="5.clam.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/fcd23514-3908-f4df-7264-0a6dfb366792.png">


まとめ
------
今回、アクセストークンが確認できなかったのが、残念です。
まだまだ、検証は続きますので、わかり次第、更新したいと思います。

次回は、ASP.NET Coreの検証を予定しております。

最後に、私の記事が少しでも、皆様の役に立てれば幸いでございます。