Login UI が出せない Client の OAuth フロー (Azure AD)


開発者にとっての Microsoft Azure Active Directory

こんにちは。

以下、Azure AD v1 endpoint の話ですが、週末の Azure AD セミナー (in 札幌) で参加者の方からご質問をいただきましたので記載しておきます。(割と最近サポートされたフローですので、ご存じない方も多いかもしれないので。)

プリンター、デジタルカメラ、ロボットなどのデバイスや、Linux 上のコンソール アプリなど、利用する Client Application の環境によってログイン画面 (SignIn UI) を表示できない場合があります。このような場合は、「Azure AD : Backend Server-Side アプリの開発」で紹介した方法を組み合わせるか、本投稿で紹介する Device Login (Device Profile Flow) を使います。

補足 : なお、「Azure AD を使った API (Service) 連携の Client 開発 (OAuth 2.0 紹介)」で解説した grant_type=password の方式でもログイン画面を抑制できますが、解説した通りこの方法はお勧めしません。

仮に、このニーズに「Azure AD : Backend Server-Side アプリの開発」の方法で対処すると、ユーザーを特定するために、ログイン画面に代わる何某かの仕組み (カードによる認証、音声認証、など) を独自に実装する必要があります。また、private key (証明書) をデバイス側 (Client) に配るわけにはいかないので、デバイスと連携する専用のサービスを立てる必要もあるでしょう。つまり、さまざまなカスタマイズや作り込みができますが (自由度が高いですが)、その一方で、こうした用途向けのやや大袈裟な実装が必要になります。解説したように、「Azure AD : Backend Server-Side アプリの開発」は、本来、バックエンドでの情報同期など、Server-to-server での利用を想定しているためです。
一方、今回紹介するフロー (Device Login) を使うと、後述の通り、テキストの伝達さえできれば、こうした余計な実装は不要で、利用者が所有するスマートフォン (Phone) などの他デバイスを代用することで、ただちに User としてログインができます。
どちらが正解というわけではなく、用途 (ニーズ) に応じて適した方法を使ってください。

なお、今回、Azure Active Directory (Azure AD) v1 endpoint を使いますが、今後、このフローは v2 endpoint でも対応予定です。「Azure AD : Backend Server-Side アプリの開発」の方式では「組織単位で有効化する」という概念のため個人アカウント (Microsoft Account) を対象にすることは困難ですが、今回紹介する Device Login (Device Profile Flow) は User 単位の token が使えるため、今後、個人アカウント (Microsoft Account) でも使えるようになれば、Office 開発などにも さらに大きな広がり (可能性) が出てきます。(例えば、プリンターのような入力方法の制限されたデバイス上から個人を特定して、OneDrive のドキュメントにアクセスするなど。) 多くの場面で利用される可能性を秘めた方法ですので、今後の Update に期待してください。

Device Login の動作

実際、Linux などで、Azure CLI (Command Line Interface) など Azure AD によるログインが必要なコンソール アプリを使う際は、ここで述べる Device Login の方式が使われています。
Device Login がどのようなものか、今回はこの Azure CLI を例に、その動きを見てみましょう。

まず、コンソール上から Azure CLI へログインしてみてください。(Azure CLI がインストールされた環境から、azure login コマンドを実行します。) 下図の通り https://aka.ms/devicelogin での認証を要求するメッセージが表示されます。

上記メッセージに従って、ブラウザーを起動して https://aka.ms/devicelogin を表示し、表示される画面 (下図) に、上記で与えられたコード (今回の場合、B4Y7GS4SU) を入力します。
手持ちのスマートフォン、タブレットなど、ブラウザーが使えるデバイスなら何でも OK です。

コードの入力が完了すると、ブラウザーに、いつものログイン画面 (SignIn UI) が表示されるので、ここに ID、パスワードを入力してログインします。(必要に応じ、AD FS フェデレーション、二要素認証などが入っても構いません。)
ログインが完了したら、もうブラウザーは不要です。(閉じてしまって構いません。)

上記のログインが完了すると、コンソール上の Azure CLI にも通知され、ログインが完了します。

HTTP Flow

このフローを使った基本的な Application 開発の流れは「Azure AD を使った API (Service) 連携の Client 開発 (OAuth 2.0 紹介)」と同じで、Application を Azure AD に登録し、そこで得られる client id, redirect uri などを使って HTTP Flow の処理をプログラミングします。以下、この HTTP Flow を紹介します。
なお、このフローを使用するには、あらかじめ Web Application Client ではなく、Native Application Client として Azure AD に登録してください。

まず、Application は、今回のログインで必要になる Code (User Code) を取得するため、以下の HTTP Request をおこないます。(下記の client id や resource は、適宜、登録した Application に応じて変更してください。)

GET https://login.microsoftonline.com/common/oauth2/devicecode?resource=https%3A%2F%2Foutlook.office365.com%2F&client_id=17ec406b-265a-4c2e-a10c-a91902c5dfbd
Accept: application/json

上記の Request の結果 (HTTP Response) として、Azure AD は下記の通り、User Code、Device Code、および利用者に表示するメッセージの内容を返します。利用者が入力するのは User Code であり、Device Code は利用者に見えませんが、このあとの Application と Azure AD の連携において内部で使用される識別子です。

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "user_code": "GXGPCE4CC",
  "device_code": "GAAABAAEAiL9Kn2Z27Uu...",
  "verification_url": "https://aka.ms/devicelogin",
  "expires_in": "900",
  "interval": "5",
  "message": "To sign in, use a web browser to open the page https://aka.ms/devicelogin. Enter the code GXGPCE4CC to authenticate."
}

Console Application などでは、下図のように、この受け取った Message を利用者に表示すると良いでしょう。もちろん、Device の性質にあわせて、User Code を音声で知らせたり、別のデバイスに送信するなど、さまざまな実装が考えられます。(テキストが伝達できれば方法は問いません。)
なお、この User Code の入力の受付は、上記結果の通り、900 秒間 (15 分間) 有効です。(900 秒を過ぎると無効になります。)

以降、Application 側では、上記の Device Code を使って下記の Request をおこない、利用者がログインしたかどうか確認できます。

POST https://login.microsoftonline.com/common/oauth2/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json

resource=https%3A%2F%2Foutlook.office365.com%2F&client_id=17ec406b-265a-4c2e-a10c-a91902c5dfbd&grant_type=device_code&code=GAAABAAEAiL9Kn2Z27Uu...

もし、利用者がまだログインをしていない場合は、下記の通り authorization_pending の Error が返ります。利用者がログインを完了するまで、アプリケーションはこの確認を何度もおこないます。

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8

{
  "error": "authorization_pending",
  "error_description": "AADSTS70016: Pending end-user authorization.\r\nTrace ID: 14613dff-d719-4b49-a937-b623263415a9\r\nCorrelation ID: f4e1c3a8-15a8-4ae4-8389-19a5a0ce2e06\r\nTimestamp: 2016-03-12 01:18:44Z",
  "error_codes": [
    70016
  ],
  "timestamp": "2016-03-12 01:18:44Z",
  "trace_id": "14613dff-d719-4b49-a937-b623263415a9",
  "correlation_id": "f4e1c3a8-15a8-4ae4-8389-19a5a0ce2e06"
}

利用者がログインを完了した場合は、上記の HTTP Request の結果として、下記の通り、access token, refresh token が返ります。
以降は、「Azure AD を使った API (Service) 連携の Client 開発 (OAuth 2.0 紹介)」で解説したように、これらの token を使って、検証や API 呼び出しをおこないます。

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "token_type": "Bearer",
  "expires_in": "3599",
  "scope": "Mail.Read",
  "expires_on": "1457749187",
  "not_before": "1457745287",
  "resource": "https://outlook.office365.com/",
  "access_token": "eyJ0eXAiOi...",
  "refresh_token": "AAABAAAAiL...",
  "id_token": "eyJ0eXAiOi..."
}

ADAL (Active Directory Authentication Library) の利用

ADAL (Active Directory Authentication Library) を使用する場合は、現在 Prelease 版として出ている ADAL 3 を使用してください。
下記の通り、AcquireDeviceCodeAsync、AcquireTokenByDeviceCodeAsync のメソッドを使って簡単に実装できます。

using Microsoft.IdentityModel.Clients.ActiveDirectory;
...

static void Main(string[] args)
{
  var ctx = new AuthenticationContext("https://login.microsoftonline.com/common");
  // Get user code, device code, and user message
  DeviceCodeResult codeResult = ctx.AcquireDeviceCodeAsync("https://outlook.office365.com/", "17ec406b-265a-4c2e-a10c-a91902c5dfbd").Result;
  // Display message to user
  Console.WriteLine(codeResult.Message);
  // Wait and get token
  var result = ctx.AcquireTokenByDeviceCodeAsync(codeResult).Result;
  // Display token result
  Console.WriteLine("Access Token : {0}", result.AccessToken);
  Console.ReadLine();
}

 

※ 参考資料

Invoking an API protected by Azure AD from a text-only device (Vittorio Bertocci)
https://azure.microsoft.com/en-us/documentation/samples/active-directory-dotnet-deviceprofile/

Comments (0)