【Microsoft ID プラットフォーム】(Azure AD) Java Web アプリ (WAR file)-設定編-

はじめに（背景)
----
下記検証の続きとなります。

SPA (Node.js)
https://qiita.com/Design_Tshirt7/items/553958e3724cc3718aa9
ASP.NET
https://qiita.com/Design_Tshirt7/items/c282d645c2117be12d4e
ASP.NET Core
https://qiita.com/Design_Tshirt7/items/ed8d45a0dff76b741c03

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

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 標準に準拠した認証サービス、オープンソース ライブラリ、アプリケーションの登録および構成、充実した概念とリファレンスのドキュメント、クイック スタート サンプル、コード サンプル、チュートリアル、攻略ガイドによって構成されています。

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

注意点
----

いつもなら、いざトライなのですが、、始める前に4つ程、注意点がございます。

(1).MSからクイックスタートで案内されているURLでは情報が足りなさすぎるので、下記ページで進めさせて頂きます。

『A Java Web application that signs in users with the Microsoft identity platform and calls Microsoft Graph』
https://docs.microsoft.com/en-us/samples/azure-samples/ms-identity-java-webapp/ms-identity-java-webapp/

(2).クイックスタートの手順では、応答URLがhttp://との案内ですが、HTTPでは、動作しません。応答URLをhttpsとして進めさせて頂きます。理由は、後ほど、解説致します。

<img width="500" alt="Notice.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/28b2affe-9862-8854-f335-15a667dada4d.png">

(3).コードサンプルの実行では、WAR fileを使って検証致します。
* IDE (Eclipse)は別記事で、アップロードさせていただきます。

>Step 5: Run the application
Run it directly from your IDE by using the embedded spring boot server or package it to a WAR file using maven and deploy it a J2EE container solution such as Apache Tomcat.

(4).他の検証手順と同じ手順にしたいと思いますので、参照ページと手順が前後致します。最終的には、参照ページと同じ結果となりますので、ご安心を!!

いざトライ！！
----

1.参照ページ
『A Java Web application that signs in users with the Microsoft identity platform and calls Microsoft Graph』
https://docs.microsoft.com/en-us/samples/azure-samples/ms-identity-java-webapp/ms-identity-java-webapp/

2.登場人物
1.Identity Provider (Azure AD)
* オンマイクロソフトアカウントを使います。
2.Relying Party (Java)
 (事前の準備をお願い致します。インストール方法は割愛させて頂きます)
- Java Development Kit (JDK) 8 以降
- Maven
- Tomcat

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

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

2.[ホーム]-> [Azure AD Active Directory] -> [アプリの登録]へ進む。
<img width="200" alt="1.appregi.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/04216dd7-5367-0ff3-f487-154e6f510c8f.png">

3.[新規登録] をクリックします。
<img width="400" alt="2.appnew.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/55f569bf-a6d5-38f2-632d-00ad1a155cb8.png">

4.アプリケーション登録で下記項目を選択して、[登録]をクリック。
(1).名前欄：任意のアプリケーション名を入力
(2).サポートされているアカントの種類：この組織ディレクトリのみに含まれるアカウント
(3).リダイレクトURL：空白　=> (後ほど、入力されます。)
<img width="400" alt="1.reg.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/d8593d2f-9d63-fddb-312d-96fe0a1a684f.png">

5.登録したアプリケーションが表示されますので、[クイックスタート]をクリック。
<img width="400" alt="2.quick.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/a7b90ad7-d9bc-7360-873c-c3e6e2d0dbb7.png">

6.クイックスタートガイドの[Java]をクリック。
<img width="400" alt="3.java.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/6034019e-9664-aa54-7eb4-abc7a23cb192.png">

7.[これらの変更を行います]をクリック。
<img width="400" alt="3.change.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/cb4a4f61-cfa1-aeaf-f92d-9deaaa591f5a.png">


8.下記構成内容が表示されますので、[更新する]をクリック。
(1).リダイレクト URI : 
http://localhost:8080/msal4jsample/secure/aad
http://localhost:8080/msal4jsample/graph/me
(2).クライアントシークレット
* 認可コードフローとなりますので、アクセストーンとIDトークンのチェックは無しとなっております。
<img width="400" alt="4.update.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/03f4286d-5336-14fd-1f68-475eb76aaf75.png">

9.クライアントシークレットが表示されますので、コピーをして、[完了]をクリック。
* クライアントシークレットは以降の手順で必要となりますので、必ずコピーをお願い致します。
<img width="400" alt="5.secret.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/fc9aef1c-d9a6-5017-21cf-883c30cf7867.png">

10.下記の[認証]画面から応答URLをhttpsに変更にして、[保存]をクリック。
*私の環境では、8080が他サービスと競合しておりますので、8443にポート番号も変えております。
[変更前]
<img width="500" alt="6.authn.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/cb235935-6693-6ab4-e6e1-c5e6286257af.png">
[変更後]
<img width="500" alt="7.changeHTTPs.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/8b8b602d-fc15-89e0-1a53-8e869f88a1fb.png">

<b>◆手順2:プロジェクトのダウンロード</b>
1.warを作成する為のプロジェクトファイルをダウンロードします。

プロジェクトファイル：ms-identity-java-webapp-master.zip
<img width="400" alt="1.download.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/a878ae5e-38cb-a554-7468-3b923f1cafe9.png">

<b>◆手順3:コード サンプルの構成</b>
1.ZIP ファイルをローカル フォルダーに展開します。
<img width="400" alt="1.folder.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/6a8773a0-a63d-7d5f-9b76-2739df10cbfa.png">

2.src\main\resources\のapplication.propertiesファイルを編集致します。
<img width="400" alt="2.appchange.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/10e01902-d395-32d0-8847-c832689e00a7.png">

|name|value|
|---|---|
|aad.clientId (クライアントID) |23bc5499-964d-40a9-bde1-3a9a540c49f1|
|aad.authority (テナントID) |a94216cd-7c42-4b24-8ba0-ce5c210951bd|
|aad.secretKey (クライアントシークレット)|J5jBkhbd]04pYoZ4pJEWvnWyp_WTS/M/|
|server.port|8443|

<img width="400" alt="3.resources.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/a3566163-0cc5-5c89-c5cf-b27a8e362c78.png">

*server.portは応答URLで登録したポート番号に合わせてください。
*参照ページURLの説明はhttpとなっておりますが、ダウンロードしたファイルは、httpsになっております。


<b>◆手順4:Java, Maven, Tomcatのダウンロード&設定</b>
検証で使った各バージョンは、下記となります。

```
C:\>java -version
java version "1.8.0_172"
Java(TM) SE Runtime Environment (build 1.8.0_172-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.172-b11, mixed mode)
```

```
C:\>mvn -version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: C:\apache-maven-3.6.3\bin\..
Java version: 1.8.0_172, vendor: Oracle Corporation, runtime: C:\Program Files\Java\jdk1.8.0_172\jre
Default locale: ja_JP, platform encoding: MS932
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
```

```
C:\tomcat9\bin>version.bat
Using CATALINA_BASE:   "C:\tomcat9"
Using CATALINA_HOME:   "C:\tomcat9"
Using CATALINA_TMPDIR: "C:\tomcat9\temp"
Using JRE_HOME:        "C:\Program Files\Java\jdk1.8.0_172"
Using CLASSPATH:       "C:\tomcat9\bin\bootstrap.jar;C:\tomcat9\bin\tomcat-juli.jar"
Server version: Apache Tomcat/9.0.30
Server built:   Dec 7 2019 16:42:04 UTC
Server number:  9.0.30.0
OS Name:        Windows 10
OS Version:     10.0
Architecture:   amd64
JVM Version:    1.8.0_172-b11
JVM Vendor:     Oracle Corporation
```

★TomcatへのSSL対応処理

(1).keytoolを使用して、証明書ファイルの作成
(2).server.xmlのHTTPS通信設定 (Connector port="8443")

```
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol" maxThreads="150" SSLEnabled="true" >
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig>
<Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
certificateFile="conf/localhost-rsa-cert.pem" certificateChainFile="conf/localhost-rsa-chain.pem" type="RSA" />
</SSLHostConfig>
    </Connector>
```

<b>◆手順5:コード サンプルの実行</b>
1.POM.XMLの編集
C:\tmp\ms-identity-java-webapp\pom.xmlに下記dependencyを追加。
* pom.xmlファイル
<img width="277" alt="5.pomxlm.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/cf592689-1932-59eb-7dbd-617058c16016.png">
* 追加する内容

```
 <dependency> 
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-tomcat</artifactId>
   <scope>provided</scope>
 </dependency>
```

<img width="337" alt="4.pom.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/45d30c37-b2ee-97ac-fbc5-5db033b2acb8.png">

2.MsalWebSampleApplication.javaの編集

C:\tmp\ms-identity-java-webapp2\src\main\java\com\microsoft\azure\msalwebsample\MsalWebSampleApplication.javaを下記内容に変更

<img width="485" alt="6.java.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/155cb7ef-9a21-f72f-e64c-52bd8dfb504c.png">

```
 package com.microsoft.azure.msalwebsample;

 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.builder.SpringApplicationBuilder;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

 @SpringBootApplication
 public class MsalWebSampleApplication extends SpringBootServletInitializer {

  public static void main(String[] args) {
   SpringApplication.run(MsalWebSampleApplication.class, args);
  }

  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
   return builder.sources(MsalWebSampleApplication.class);
  }
 }
```

3.WARファイルの作成 (mvn package)

<img width="754" alt="7.mvn.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/07d75b21-99a3-8547-aef9-43c09f5068d7.png">

4.msal-web-sample-0.1.0.warをROOT.warに変更

『mvn package』を実行するとtargetフォルダが作成されて、warファイルが作成されますので、作成されたwarファイルをROOT.warに変更する。
*変更前
<img width="434" alt="8.war.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/d652954e-907d-ae84-cfa4-ad7c7a61513d.png">
*変更後
<img width="414" alt="9.ROOT.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/6f50a989-91d4-c14c-c635-0dd31812d87f.png">

5.tomcat起動

C:\tomcat9\bin\Tomcat9w.exeを右クリック-> 管理者として実行 -> start

<img width="461" alt="11.Tomcat.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/44d0f951-06d9-e838-7728-3457f80ebd1e.png">


6.Root.warの配置

tomcat9\webapps\にROOT.warを配置すると自動的にROOTフォルダを作成がされる。このRootフォルダを使って、サインインすることになります。

<img width="549" alt="10.move1.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/238947e1-1e05-5b2e-961a-5e04b3439605.png">


<img width="525" alt="10.move2.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/7ef7336d-f1b9-e6d8-5483-c6ffacd64eb9.png">


<b>◆手順6: サインイン</b>
*事前情報
Fiddlerログを基にトークンの取得情報を途中まで書いたのですが、長くなってしまったので、別記事でアップロードさせていただきます。

*事前準備
(1).Fiddlerでパケットキャプチャの準備。
(2).ダウンロードしたコアプロジェクトサンプルの仕組みをきちんと確認。

<img width="500" alt="flow.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/70b444e4-6d50-48a3-404c-86eb4a0d186e.png">

<b>0.Tomcatを起動。</b>
<img width="500" alt="11.Tomcat.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/ceb35720-9ec8-b633-25b3-54d1142b7ad8.png">

<b>1.認可コードの取得（認可エンドポイント)</b>
●1-1.『https&#58;//localhost:8443』へアクセスして、Proceed to localhost (unsafe)をクリック
<img width="500" alt="1.signin.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/597f37db-507c-4c14-3932-6c3886a5a67a.png">

●1-2.Login to call Microsoft Graphが表示されますので、[Login]をクリック</b>
<img width="500" alt="2.login.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/ecee94f1-36c3-879a-f8a3-33fa31f13487.png">

●1-3.資格情報(ID/パスワード)の入力
●1-4.要求されているアクセス許可を承諾
<img width="310" alt="3.consent.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/4450df3e-6d6d-63bf-1915-db10fbebbd7a.png">
●1-5.ログイン完了
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/86bf087d-2ad0-b9cc-de6d-c449cef83b30.png">

<b>2.User Infoエンドポイントへのアクセス</b>
2-1.[Show User Info]をクリック。
<img width="400" alt="4.login.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/2e2f8c21-d36f-63a9-f257-f4c800a4c850.png">
2-2.[承諾]をクリック。
<img width="313" alt="5.consent-2.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/3da71576-342b-2df2-9565-ba78ae73a1d4.png">
2-3.現在ログインしているユーザーの情報が表示されます。
<img width="500" alt="6.userinfo.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/1beef5a6-c435-6d64-6ae9-b7c3f3947f40.png">

HTTPSを使う理由
------
●8080を利用すると下記エラーページが表示される。
<img width="434" alt="ERROR PAGE.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/0dd19ae6-1c46-27e2-d359-e966755edc90.png">

●理由
HTTPS通信を使っていない為、OAuthのstateパラメータの検証に失敗している。

なぜなら、Chrome 80 のSame-site Cookieの更新に伴い、ChromeがHTTPS通信、且つsame-site: none パラメータが付与されたcookieのみを、POSTリクエストに含めるよう変更があった為となります。

stateパラメータは、通常OAtuhのフローにてCSRF攻撃を防ぐためのパラメータとして使われ、本来ならば、下記流れで、認証を完了致します。(*1参照)

(1).認証リクエストの開始時に、アプリケーションのoriginのCookieにstateパラメータを保存し、同時に同じ値を認証リクエストのクエリーに含め Azure ADに渡される。
(2).Azure ADは認証完了後、stateパラメータを、もとのアプリケーションにクエリーパラメータとして引き回します。アプリケーションはこのstateのパラメータと、Cookieに保存されたstate パラメータの値を比較することにより、同一のユーザーエージェント (ブラウザー) からのアクセスであることを判断し、認証を完了させます。

HTTP通信で動作させた場合、アプリケーションが発行したCookieをブラウザーが保存できず、認証後にアプリケーションに戻った際、正常にCookieを送信できてない為、エラー表示となって、認証が完了できない状態になる(*2)ので、HTTPSが必須となります。

*1.『Microsoft ID プラットフォームと OAuth 2.0 認証コード フロー』
https://docs.microsoft.com/ja-jp/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-authorization-code

|パラメーター&nbsp;&nbsp;|説明|
|---|---|
|state|要求に含まれ、かつトークンの応答として返される値。 任意の文字列を指定することができます。 <b>クロスサイトリクエストフォージェリ攻撃</b>を防ぐために通常、ランダムに生成された一意の値が使用されます。 この値を使用すると、認証要求の前にアプリ内でユーザーの状態 (表示中のページやビューなど) に関する情報をエンコードすることもできます。|

*2.
(1).認証リクエスト Set-Cookie : msal_web_app_auth_state=xxx
<img width="842" alt="before1.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/6132532a-f507-9db3-170b-b2ac2faa22ce.png">
(2).Cookeiが保存されていないので、認証に失敗する。
<img width="711" alt="after1.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/ce43740b-4002-c696-ac60-27ef3248cc62.png">
Cookieが保存される場合は、下記となります。
<img width="692" alt="noerror.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579284/c696ba75-e2a1-096c-601b-a36fc79796c2.png">


まとめ
------
トークンの取得情報は別記事でアップロードさせていただきます。
次回も、Java Web アプリの検証を予定しております。今度は、Eclipseを使っての検証となります。

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