Azure Graph Apiを使ってAzure ADにアプリ登録

はじめまして、デベロッパーの金山です。

今回はAzure Graph APIを使ってアプリ登録を行ってみます。
具体的には過去の記事 [AAD] WebアプリをAAD認証させる で行っている
「AAD へのアプリの登録」をエンジニアらしくプログラムで自動化してしまおうという話です。
具体的には「アプリ登録を行うWebアプリ」を作ります。
下図がイメージです。とあるユーザ「アプリを登録するアプリ」にログインすると
ユーザの属するADテナント内にアプリが登録されるという流れを実装してみたいと思います。

%e3%82%a4%e3%83%a1%e3%83%bc%e3%82%b8

実装の流れとしては以下になります。

  1. アプリを登録するための権限を取得
  2. GraphAPIを使ってアプリを登録する

早速やっていきたいと思います。

1.アプリを登録するための権限を取得

権限を取得するためには以下の情報が必要になります。

  • ADを操作する権限のアクセストークン
  • アプリの登録先AADのテナントID

上記二つの情報を得るにはAAD認証を通して取得する必要があります。
話がややこしいですが、「アプリ登録を行うためのアプリ」もAAD認証を使用するので、
AADに対してアプリ登録をしてあげる必要があります。これは手動でする必要があります。

新ポータルで行う場合には、下図のようにメニューから AAD を選択して AAD の管理画面を開きます。

aad%e6%96%b0%e3%83%9d%e3%83%bc%e3%82%bf%e3%83%ab

「アプリの登録」メニューから+新規ボタンを押してアプリの作成を行います。
今回は以下の設定で登録してください

名前 : RegisterAppとしてみます
アプリケーションの種類  :  Webアプリ/API
サイオンURL : 「https://localhost:44302/」

aad%e3%82%a2%e3%83%97%e3%83%aa%e7%99%bb%e9%8c%b2

アプリ登録が完了したら、アプリの登録から設定→「必要なアクセス許可」を選択

%e3%82%a2%e3%83%97%e3%83%aa%e3%81%ae%e8%a8%ad%e5%ae%9a
「Access the directory as the signed-in user」を追加します
permission

次にADにアクセスするためのパスワードを取得します
同じ設定画面にある「キー」から適当な名前を設定して生成してメモしておきます。
key
最後にアプリケーションIDをメモして登録完了です。
%e3%82%a2%e3%83%97%e3%83%aa%e3%81%ae%e8%a8%ad%e5%ae%9a

次にいよいよアプリを作ります

今回はIndex.htmlにアクセスすると自動的にAD認証のページに飛ばされて、
認証が通ったらアプリが勝手に登録されてしまうような恐ろしいアプリを作ってしまいたいと思います。

まず、VisualStudioでASP.Net MVCの空アプリのプロジェクトを作ります。
認証用にIdentityModel.Clients.ActiveDirectorytoy
Jsonのパース用にNewtonsoft-json
これらのライブラリが必要になるので
パッケージマネージャから以下のコマンド実行してインストールしましょう

Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory
Install-Package Newtonsoft.Json

次に必要なコントローラとViewを追加していまいましょう。
ControllerにコントローラをHomeControllerという名前で追加します。
Views/Homeにindexという名前のビューを追加。
ここまでで下図のようなフォルダ構成になるかと思います。

%e3%81%93%e3%81%93%e3%81%be%e3%81%a7%e3%81%ae%e7%8a%b6%e6%85%8b

次に起動時のURLを先ほど登録したアプリとそろえる必要があるので変更します。
プロジェクトを右クリック⇒プロパティ⇒WebからプロジェクトのURLを
https://localhost:44302/に変更します

url%e6%9b%b8%e3%81%8d%e6%8f%9b%e3%81%88
次にHomeControllerを以下のように実装します。
これによりテナントIDとアクセストークンが取得出来る状態になります。


public class HomeController : Controller
 {
 string clientid = "{appID}"; //アプリ登録時にメモしたアプリケーションID
 string password = "{password}"; //アプリ登録時にメモしたキーのパスワード

 // GET: Home
 // アプリを実行するとまずここに入ります
 public ActionResult Index()
 {
 //Microsoftのログイン画面に飛ぶURLを作成します
 string authorizationRequest = String.Format(
 "https://login.windows.net/common/oauth2/authorize?response_type=code&client_id={0}&resource={1}&redirect_uri={2}&state=abc",
 Uri.EscapeDataString(clientid), //アプリケーションID
 Uri.EscapeDataString("https://graph.windows.net"),//ここでGrapAPIを使うと宣言します
 Uri.EscapeDataString(this.Request.Url.GetLeftPart(UriPartial.Authority).ToString() + "/Home/ProcessCode")
 );
 return new RedirectResult(authorizationRequest);
 }

 //AD認証が成功するとここにリダイレクトされます
 public async System.Threading.Tasks.Task<ActionResult> ProcessCode(string code, string error, string error_description, string resource, string state)
 {

 // AD認証が通るとAD情報が取得できるようになります
 ClientCredential credential = new ClientCredential(clientid, password);
 AuthenticationContext authContext = new AuthenticationContext("https://login.windows.net/common/");

 AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
 code, new Uri(Request.Url.GetLeftPart(UriPartial.Path)), credential); // ADテナントの情報を問い合わせます

 // resultからアクセストークンとテナントIDが取得できます
 // result.AccessToken;
 // result.TenantId
 return new RedirectResult("Index");
 }

}

2.GraphAPIを使ってアプリを登録する

いよいよGraphAPIを使ってアプリの登録します。
以下のURIへアプリ情報をPOSTするとアプリの登録が行えます

https://graph.windows.net/{取得したテナントID}/directoryObjects

パラメータとしては以下のAPIのバージョンを指定する必要があります。

Key Value
Api-Version 今回は1.6を指定

POSTする内容は以下になります

Key Value 説明
odata.type Microsoft.DirectoryServices
.Application
Applicationである事を認識させる
objectType Application Applicationであることを指定する
availableToOtherTenants bool マルチテナントの場合はTrueにする
displayName appName; 登録するアプリ名を指定する
homepage homepage; アプリのホームページを指定する
Oauth2AllowImplicitFlow true; 多段階認証を許可する
publicClient false; ここをFalseにするとWebアプリとして
trueだとネイティブで登録される
identifierUris URL(配列) 識別用のURIを指定する
複数指定可能
replyUrls URL(配列) 認証後のリダイレクト先URLを指定する

これらの情報をPOSTしてあげるとアプリが登録されます
最後に登録まで行っているサンプルコードになります。

 public class HomeController : Controller
 {
 string clientid = "{appid}"; //アプリ登録時にメモしたアプリケーションID
 string password = "{password}"; //アプリ登録時にメモしたキーのパスワード
 // GET: Home
 // アプリを実行するとまずここに入ります
 public ActionResult Index()
 {

 //Microsoftのログイン画面に飛ぶURLを作成します
 string authorizationRequest = String.Format(
 "https://login.windows.net/common/oauth2/authorize?response_type=code&client_id={0}&resource={1}&redirect_uri={2}&state=abc",
 Uri.EscapeDataString(clientid), //アプリケーションID
 Uri.EscapeDataString("https://graph.windows.net"),//ここでGrapAPIを使うと宣言します
 Uri.EscapeDataString(this.Request.Url.GetLeftPart(UriPartial.Authority).ToString() + "/Home/ProcessCode")
 );
 return new RedirectResult(authorizationRequest);
 }

 // 認証が成功するとここにリダイレクトされます
 public async System.Threading.Tasks.Task<ActionResult>  ProcessCode(string code, string error, string error_description, string resource, string state)
 {

 // AD認証が通るとAD情報が取得できるようになります
 ClientCredential credential = new ClientCredential(clientid, password);
 AuthenticationContext authContext = new AuthenticationContext("https://login.windows.net/common/");

 AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
 code, new Uri(Request.Url.GetLeftPart(UriPartial.Path)), credential); // ADテナントの情報を問い合わせます

 // resultからアクセストークンとテナントIDが取得できます
 // result.AccessToken;
 // result.TenantId
//ここからGraphAPIで登録する実装
 var tenantId = result.TenantId;
 var accessToken = result.AccessToken;
 string appName = "登録テストアプリ";
 string homepage = "http://localhost";
 string identifierUri = "http://localhost:1234";
 string replyUrl = "http://localhost:1234";

 string graphRequest = String.Format("https://graph.windows.net/{0}/directoryObjects?api-version=1.6", tenantId);
 HttpClient client = new HttpClient();
 HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, graphRequest);
 request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

 JObject jobject = new JObject();
 jobject["odata.type"] = "Microsoft.DirectoryServices.Application"; // odata.typeでアプリケーションだと指定する
 jobject["objectType"] = "Application";
 jobject["availableToOtherTenants"] = false;
 jobject["displayName"] = appName;
 jobject["homepage"] = homepage;
 jobject["Oauth2AllowImplicitFlow"] = true;

 jobject["publicClient"] = false; // ここをFalseにするとWebアプリとして登録 trueだとネイティブで登録される
 jobject["identifierUris"] = new JArray() { identifierUri };
 jobject["replyUrls"] = new JArray() { replyUrl };

 request.Content = new StringContent(jobject.ToString());
 request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
 HttpResponseMessage response = await client.SendAsync(request);

 string content = await response.Content.ReadAsStringAsync();
 JObject jResult = JObject.Parse(content);

 return new RedirectResult("Index");
 }

 }

参考:
https://msdn.microsoft.com/library/azure/ad/graph/api/api-catalog
https://msdn.microsoft.com/ja-jp/library/azure/ad/graph/api/functions-and-actions
https://msdn.microsoft.com/ja-jp/library/azure/ad/graph/api/entity-and-complex-type-reference
http://blah.winsmarts.com/2015-1-Programmatically_register_native_apps_in_Azure_AD_or_Office_365.aspx

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中