Uncategorized

Azure AD (Entra ID) の Graph API の活用

注意 : Azure Active Directory Graph は今後サポートされません。代わりに Microsoft Graph を使用してください。(同等の Azure AD 管理用の API が提供されています。)

開発者にとっての Azure Active Directory (Microsoft Entra ID)

こんにちは。

Azure Active Directory Graph (Graph API) を使うと、REST の呼び出しで、ユーザーの作成・変更をおこなうような管理機能を提供したり、アプリケーション上でユーザー一覧 (ユーザー選択画面など) を提供したり、後述のようにバックエンドでユーザー情報を同期することなども可能です。(特に同期ソリューションは、Azure AD とカスタム アプリ (SaaS) を Federation させる上で重要な機能です。)

今回は、この Graph API について、その利用手順と概念を解説します。

2015/11 追記 :  本投稿で紹介する Azure AD Graph API も含め、Microsoft が提供するすべてのサービス / データの API が Microsoft Graph API に統一されました。(詳細は「Active Directory Team Blog : Introducing the Microsoft Graph –The Azure AD GraphAPI goes big time!」をご参照ください。)
今後は、 Microsoft Graph で下記と同様の開発 (プログラミング) が可能です。

 

認証処理と Access Token の取得

Graph API (Url は https://graph.windows.net/<tenant realm>) は後述で見ていくように REST で提供されていますが、この API 自身も Azure AD 上の Service Application (Web API) として、OAuth 2 による Access Token を取得してアクセスします。

これまで述べてきたように Access Token の取得方法はいくつかあります。(以下のいずれかの方法で取得できます。)

  • Azure AD を使った API (Service) 連携の Client 開発」で紹介したフローを使って、ログイン画面を表示して Access Token を取得できます。(ログイン画面を使って、ユーザーにログインさせます。)
    ここで述べるような Azure AD テナントの情報の読み込み・書き込みをおこなうには、「Azure Active Directory の Common Consent Framework」で記載している方法で、作成する Application (Client) の Permission (アクセス許可) として [Read and write directory data] を設定します。(この場合、必ず、管理者のアカウントでログインする必要があります。)
  • その他の方法として、「Azure AD : Backend Server-Side アプリの開発 (Deamon, Service など)」で解説した方法で Application Permissions を使って Access Token を取得できます。この場合、特定ユーザーではログインしないので、ログイン画面は表示されません。(この方法は、バックエンドの同期アプリなどで使えます。)

補足 : もし、People Picker のような一般ユーザーが使う機能を実装するときには、[Read all users’ basic profile] などの新しく追加された Delegated Permission を使用してください。この場合、管理者によるログインは不要です。(「New graph API consent permissions」を参照してください。)
ここでは、Azure AD の管理を目的とした使用方法を紹介するので、管理者権限が必要です。

なお、.NET (C# など)、Cordova、Objective-C、Android SDK などを使用されている方は、Active Directory Authentication Library (ADAL) を使用して Access Token を取得しても構いません。

. . .using Microsoft.IdentityModel.Clients.ActiveDirectory;. . .private void button1_Click(object sender, EventArgs e){  //  // Get access token using login UI  //  AuthenticationContext context =new AuthenticationContext("https://login.microsoftonline.com/o365demo01.onmicrosoft.com");  AuthenticationResult assertion = context.AcquireToken("https://graph.windows.net",  // resource (graph api)"39ff4d28-9cba-448c-acae-612705e54257",  // client idnew Uri("https://localhost/sampleapp"));  string authHeader = assertion.CreateAuthorizationHeader();}. . .

補足 : Azure Team Blog で紹介しているように、.NET 版の Active Directory Authentication Library (ADAL) の version 0.6 以降では、Full Managed (100% .NET) になりました。
0.6 以前では、 環境の相違 (x86, x64) に注意してください。

 

Graph API の呼び出し

つぎに、上記で取得した Access Token を使って、Graph API の REST サービスからデータを取得します。

例えば、下記の HTTP Request は o365demo01.onmicrosoft.com の Directory の User 一覧を取得します。
api-version の指定は必ず必要です。(現在サポートされている api-version については「MSDN : Azure AD Graph API Versioning」を参考にしてください。)

GET https://graph.windows.net/o365demo01.onmicrosoft.com/usersAuthorization: Bearer {access token}api-version: 1.0

結果 (HTTP Response) は以下の通りです。

HTTP/1.1 200 OKContent-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8Access-Control-Allow-Origin: *{  "odata.metadata": "https://graph.windows.net/o365demo01.onmicrosoft.com/$metadata#directoryObjects/Microsoft.WindowsAzure.ActiveDirectory.User",  "value": [{  "odata.type": "Microsoft.WindowsAzure.ActiveDirectory.User",  "objectType": "User",  "objectId": "ca3645ea-e265-42c0-b1ff-bfb467c0352e",  "accountEnabled": true,  "assignedLicenses": [{  "disabledPlans": [  ],  "skuId": "3b555118-da6a-4418-894f-7df1e2096870"}  ],  "assignedPlans": [{  "assignedTimestamp": "2015-04-06T09:50:28Z",  "capabilityStatus": "Enabled",  "service": "SharePoint",  "servicePlanId": "c7699d2e-19aa-44de-8edf-1736da088ca1"},{  "assignedTimestamp": "2015-04-06T09:50:28Z",  "capabilityStatus": "Enabled",  "service": "exchange",  "servicePlanId": "9aaf7827-d63c-4b61-89c3-182f06f82e5c"},{  "assignedTimestamp": "2015-04-06T09:50:28Z",  "capabilityStatus": "Deleted",  "service": "RMSOnline",  "servicePlanId": "bea4c11e-220a-4e6d-8eb8-8ea15d019f90"},{  "assignedTimestamp": "2015-04-06T09:50:28Z",  "capabilityStatus": "Deleted",  "service": "MicrosoftOffice",  "servicePlanId": "43de0ff5-c92c-492b-9116-175376d08c38"},{  "assignedTimestamp": "2015-04-06T09:50:28Z",  "capabilityStatus": "Enabled",  "service": "MicrosoftCommunicationsOnline",  "servicePlanId": "0feaeb32-d00e-4d66-bd5a-43b5b83db82c"},{  "assignedTimestamp": "2015-04-06T09:50:28Z",  "capabilityStatus": "Enabled",  "service": "SharePoint",  "servicePlanId": "e95bec33-7c88-4a70-8e19-b10bd9d0c014"},{  "assignedTimestamp": "2015-04-06T09:50:28Z",  "capabilityStatus": "Deleted",  "service": "SharePoint",  "servicePlanId": "5dbe027f-2339-4123-9542-606e4d348a72"},{  "assignedTimestamp": "2015-04-06T09:50:28Z",  "capabilityStatus": "Deleted",  "service": "exchange",  "servicePlanId": "efb87545-963c-4e0d-99df-69c6916d9eb0"}  ],  "city": null,  "country": null,  "department": null,  "dirSyncEnabled": null,  "displayName": "Taro Demo",  "facsimileTelephoneNumber": null,  "givenName": "Taro",  "jobTitle": null,  "lastDirSyncTime": null,  "mail": "demouser01@o365demo01.onmicrosoft.com",  "mailNickname": "demouser01",  "mobile": null,  "otherMails": [  ],  "passwordPolicies": "DisablePasswordExpiration",  "passwordProfile": null,  "physicalDeliveryOfficeName": null,  "postalCode": null,  "preferredLanguage": "ja-JP",  "provisionedPlans": [{  "capabilityStatus": "Enabled",  "provisioningStatus": "Success",  "service": "MicrosoftCommunicationsOnline"},{  "capabilityStatus": "Deleted",  "provisioningStatus": "Success",  "service": "exchange"},{  "capabilityStatus": "Enabled",  "provisioningStatus": "Success",  "service": "exchange"},{  "capabilityStatus": "Deleted",  "provisioningStatus": "Success",  "service": "MicrosoftOffice"},{  "capabilityStatus": "Enabled",  "provisioningStatus": "Success",  "service": "SharePoint"},{  "capabilityStatus": "Deleted",  "provisioningStatus": "Success",  "service": "SharePoint"},{  "capabilityStatus": "Enabled",  "provisioningStatus": "Success",  "service": "SharePoint"}  ],  "provisioningErrors": [  ],  "proxyAddresses": ["SMTP:demouser01@o365demo01.onmicrosoft.com"  ],  "state": null,  "streetAddress": null,  "surname": "Demo",  "telephoneNumber": null,  "usageLocation": "JP",  "userPrincipalName": "demouser01@o365demo01.onmicrosoft.com"},{  "odata.type": "Microsoft.WindowsAzure.ActiveDirectory.User",  "objectType": "User",  "objectId": "234ddd85-8988-4335-a4a5-5b63fe5652b8",  "accountEnabled": true,  "assignedLicenses": [{  "disabledPlans": [  ],  "skuId": "3b555118-da6a-4418-894f-7df1e2096870"}  ],  "assignedPlans": [{  "assignedTimestamp": "2015-04-06T09:50:09Z",  "capabilityStatus": "Enabled",  "service": "SharePoint",  "servicePlanId": "c7699d2e-19aa-44de-8edf-1736da088ca1"},{  "assignedTimestamp": "2015-04-06T09:50:09Z",  "capabilityStatus": "Enabled",  "service": "exchange",  "servicePlanId": "9aaf7827-d63c-4b61-89c3-182f06f82e5c"},{  "assignedTimestamp": "2015-04-06T09:50:09Z",  "capabilityStatus": "Deleted",  "service": "RMSOnline",  "servicePlanId": "bea4c11e-220a-4e6d-8eb8-8ea15d019f90"},{  "assignedTimestamp": "2015-04-06T09:50:09Z",  "capabilityStatus": "Deleted",  "service": "MicrosoftOffice",  "servicePlanId": "43de0ff5-c92c-492b-9116-175376d08c38"},{  "assignedTimestamp": "2015-04-06T09:50:09Z",  "capabilityStatus": "Enabled",  "service": "MicrosoftCommunicationsOnline",  "servicePlanId": "0feaeb32-d00e-4d66-bd5a-43b5b83db82c"},{  "assignedTimestamp": "2015-04-06T09:50:09Z",  "capabilityStatus": "Enabled",  "service": "SharePoint",  "servicePlanId": "e95bec33-7c88-4a70-8e19-b10bd9d0c014"},{  "assignedTimestamp": "2015-04-06T09:50:09Z",  "capabilityStatus": "Deleted",  "service": "SharePoint",  "servicePlanId": "5dbe027f-2339-4123-9542-606e4d348a72"},{  "assignedTimestamp": "2015-04-06T09:50:09Z",  "capabilityStatus": "Deleted",  "service": "exchange",  "servicePlanId": "efb87545-963c-4e0d-99df-69c6916d9eb0"}  ],  "city": "Demo-City",  "country": null,  "department": null,  "dirSyncEnabled": null,  "displayName": "Matsuzaki Tsuyoshi",  "facsimileTelephoneNumber": null,  "givenName": "Tsuyoshi",  "jobTitle": null,  "lastDirSyncTime": null,  "mail": "tsmatsuz@o365demo01.onmicrosoft.com",  "mailNickname": "tsmatsuz",  "mobile": "+81 9011110000",  "otherMails": ["tsmatsuz_demo@hotmail.com"  ],  "passwordPolicies": "DisablePasswordExpiration",  "passwordProfile": null,  "physicalDeliveryOfficeName": null,  "postalCode": "1110000",  "preferredLanguage": "ja-JP",  "provisionedPlans": [{  "capabilityStatus": "Deleted",  "provisioningStatus": "Success",  "service": "exchange"},{  "capabilityStatus": "Enabled",  "provisioningStatus": "Success",  "service": "exchange"},{  "capabilityStatus": "Deleted",  "provisioningStatus": "Success",  "service": "MicrosoftOffice"},{  "capabilityStatus": "Enabled",  "provisioningStatus": "Success",  "service": "MicrosoftCommunicationsOnline"},{  "capabilityStatus": "Enabled",  "provisioningStatus": "Success",  "service": "SharePoint"},{  "capabilityStatus": "Deleted",  "provisioningStatus": "Success",  "service": "SharePoint"},{  "capabilityStatus": "Enabled",  "provisioningStatus": "Success",  "service": "SharePoint"}  ],  "provisioningErrors": [  ],  "proxyAddresses": ["SMTP:tsmatsuz@o365demo01.onmicrosoft.com"  ],  "state": "Tokyo",  "streetAddress": "1-1-1, Demo-Street Demo-City",  "surname": "Matsuzaki",  "telephoneNumber": "09011112222",  "usageLocation": "JP",  "userPrincipalName": "tsmatsuz@o365demo01.onmicrosoft.com"}  ]}

OData に対応しているので、下記の通り Query (検索) も可能です。(下記は、Mail Address が「tsmatsuz@o365demo01.onmicrosoft.com」の User を取得しています。)
Azure Active Directory Graph で使用可能なクエリーの内容は「MSDN : Azure AD Graph Common Queries」に記載されています。

GET https://graph.windows.net/o365demo01.onmicrosoft.com/users()?$filter=mail%20eq%20'tsmatsuz%40o365demo01.onmicrosoft.com'Authorization: Bearer {access token}api-version: 1.0

Graph API を使って更新処理 (追加、変更、削除) も可能です。
下記では、ObjectId が 234ddd85-8988-4335-a4a5-5b63fe5652b8 の User の DisplayName のみを変更 (Update) しています。

MERGE https://graph.windows.net/o365demo01.onmicrosoft.com/directoryObjects/234ddd85-8988-4335-a4a5-5b63fe5652b8/Microsoft.DirectoryServices.Userapi-version: 1.0Content-Type: application/json;odata=minimalmetadataAccept: application/json;odata=minimalmetadataAuthorization: Bearer {access token}{  "odata.type":"Microsoft.DirectoryServices.User",  "displayName":"Tsuyoshi Matsuzaki"}

また、Graph API を使用して、ユーザー情報などの差分 (変更) の追跡が可能です。
例えば、差分情報の取得 (Differential Query) を使って、独自のユーザー管理システムとの (User 情報などの) 同期処理 (Sync) もプログラミングできます。(Office 365 Identity program で Certify された WS-Federation プロバイダーや Shibboleth 以外のカスタム・アプリケーションで同期をおこなう場合には、この方法を使用します。)

補足 : プログラミングの概念は、一般の Sync のプログラミングに類似しており、SkipToken という変更ポイントを管理するキーを生成し、このキーを元に、その時点から現在までの差分を取得できます。詳細は「Azure AD Graph API Differential Query」を参照してください。

この他に、Users エンティティなどの Store の拡張 (プロパティの追加など) や、Permission 管理、Application Role 管理などの細かな管理タスクも実行できます。(処理内容によっては、最新の api-version を使用してください。)

Graph Explorer を使用すると、Browser を使用して Graph API の Request / Response を簡単に確認できます。
また、「MSDN : Azure Graph REST APIs Reference」で Graph API を interactive に確認可能になりましたので、同様に Request / Response を簡単に確認できます。(2015/05/01 追記)

 

Azure Active Directory Graph Client Library

.NET (C# など) を使用している方は、NuGet から Azure Active Directory Graph Client Library (Microsoft.Azure.ActiveDirectory.GraphClient) を取得してプログラミングできます。(上述の ADAL と共に使用します。)

例えば、下記は、Mail Address が「tsmatsuz@o365demo01.onmicrosoft.com」の User を取得して、その User の DisplayName を Update するサンプル コードです。

...using Microsoft.IdentityModel.Clients.ActiveDirectory;using Microsoft.Azure.ActiveDirectory.GraphClient;...private async void button1_Click(object sender, EventArgs e){  Uri serviceRoot = new Uri(new Uri("https://graph.windows.net"),"o365demo01.onmicrosoft.com");  ActiveDirectoryClient cl = new ActiveDirectoryClient(serviceRoot,async () => await GetToken());  var u = await cl.Users.Where(user => user.Mail.Equals("tsmatsuz@o365demo01.onmicrosoft.com")).ExecuteSingleAsync();  u.DisplayName = "Tsuyoshi Matsuzaki";  await u.UpdateAsync();  MessageBox.Show("Finished !");}private Task<string> GetToken(){  AuthenticationContext context =new AuthenticationContext("https://login.microsoftonline.com/o365demo01.onmicrosoft.com");  AuthenticationResult assertion = context.AcquireToken("https://graph.windows.net","39ff4d28-9cba-448c-acae-612705e54257",  // client idnew Uri("https://localhost/sampleapp"));  return Task.Factory.StartNew<string>(() => assertion.AccessToken);}. . .

 

※ 変更履歴 :

2015/03/19  エンドポイントを https://login.windows.net から https://login.microsoftonline.com (新エンドポイント) に変更しました

2015/04/10  最新の情報に Update。また、Application スコープの認証方法についての解説は「Azure AD : Backend Server-Side アプリの開発 (Deamon, Service など)」を参照するように変更

2015/05/01  Interactive Graph API reference の記述を追加

2015/11/19  Microsoft Graph API について追記

2017/05/26  画面を新ポータル (https://portal.azure.com) に変更

 

Categories: Uncategorized

Tagged as: , ,

7 replies»

Leave a Reply