Created
December 1, 2012 14:04
-
-
Save rytmis/4182440 to your computer and use it in GitHub Desktop.
Windows Azure AD Authentication: Querying the Graph API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net; | |
using Microsoft.WindowsAzure.ActiveDirectory.Authentication; | |
using WAADDemo.ActiveDirectoryGraph.Microsoft.WindowsAzure.ActiveDirectory; | |
namespace WAADDemo | |
{ | |
/// <summary> | |
/// This class uses the Windows Azure Graph API to retrieve a given user's direct group memberships. | |
/// Except for the <see cref="GetUserGroups"/> method, the code in this class is heavily based on public | |
/// Graph API examples from Microsoft. | |
/// </summary> | |
public class GraphClient | |
{ | |
private readonly DirectoryDataService dataService; | |
private readonly string tenantDomainName; | |
private readonly string servicePrincipalSymmetricKey; | |
private readonly string tenantId; | |
private readonly string appPrincipalId; | |
// ReSharper disable InconsistentNaming | |
/// <summary> | |
/// Name of the HTTP header that contains the unique ID of a client request. | |
/// Used when making Graph API requests | |
/// </summary> | |
private const string HeaderName_ClientRequestId = "client-request-id"; | |
/// <summary> | |
/// Authorization header used when making Graph API requests | |
/// </summary> | |
private const string HeaderName_Authorization = "Authorization"; | |
/// <summary> | |
/// Version of the data contract, used when making Graph API requests | |
/// </summary> | |
private const string HeaderName_DataContractVersion = "x-ms-dirapi-data-contract-version"; | |
// ReSharper restore InconsistentNaming | |
private const string DataContractVersion = "0.8"; | |
public GraphClient(string tenantDomainName, string tenantId, string appPrincipalId, string servicePrincipalSymmetricKey) | |
{ | |
this.tenantDomainName = tenantDomainName; | |
this.tenantId = tenantId; | |
this.servicePrincipalSymmetricKey = servicePrincipalSymmetricKey; | |
this.appPrincipalId = appPrincipalId; | |
dataService = new DirectoryDataService(GetConnectionUri()); | |
dataService.SendingRequest += (sender, args) => | |
{ | |
var webRequest = ((HttpWebRequest)args.Request); | |
webRequest.Headers.Add(HeaderName_Authorization, GetAuthorizationHeader()); | |
webRequest.Headers.Add(HeaderName_DataContractVersion, DataContractVersion); | |
webRequest.Headers.Add(HeaderName_ClientRequestId, Guid.NewGuid().ToString()); | |
}; | |
} | |
/// <summary> | |
/// Identifier of the issuing resource for the symmetric key. | |
/// Used for getting an access token for requests. | |
/// Looks something like this: | |
/// A4423C7C-35F7-4679-99F8-5921A0482B63@tenantdomain.onmicrosoft.com | |
/// (the GUID here is an example, not the actual value) | |
/// </summary> | |
private string GetSymmetricKeyIssuingResource() | |
{ | |
return appPrincipalId + "@" + tenantDomainName; | |
} | |
/// <summary> | |
/// Realm identifier for the service we want to access. Which is the tenant domain | |
/// hosted at Windows Azure AD. | |
/// 00000002-0000-0000-c000-000000000000/graph.windows.net@yourtenantdomain.onmicrosoft.com | |
/// (the GUID here is the actual identifier) | |
/// </summary> | |
private string GetServiceRealm() | |
{ | |
return AzureAdPrincipalId + "/" + GraphApiServiceHost + "@" + tenantDomainName; | |
} | |
/// <summary> | |
/// URI of the Graph API we're accessing. | |
/// Looks something like this: | |
/// https://graph.windows.net/EA314D90-8751-4534-A96E-77A5DF0E72AB | |
/// (the GUID here is an example, not the actual value) | |
/// </summary> | |
private Uri GetConnectionUri() | |
{ | |
return new Uri(string.Format(@"https://{0}/{1}", GraphApiServiceHost, tenantId)); | |
} | |
/// <summary> | |
/// URI of the WAAD tenant domain. | |
/// Looks something like this: | |
/// https://accounts.accesscontrol.windows.net/yourtenantdomain.onmicrosoft.com | |
/// </summary> | |
private string GetFullTenantUri() | |
{ | |
return "https://accounts.accesscontrol.windows.net/" + tenantDomainName; | |
} | |
/// <summary> | |
/// This is the known identifier of the WAAD service principal | |
/// </summary> | |
private const string AzureAdPrincipalId = "00000002-0000-0000-c000-000000000000"; | |
/// <summary> | |
/// This is the domain name of the WAAD Graph API service | |
/// </summary> | |
private const string GraphApiServiceHost = "graph.windows.net"; | |
/// <summary> | |
/// Method to get the Oauth2 Authorization header from WAAD. This basically authenticates | |
/// the calling application to WAAD and gets a token with which further requests can be made. | |
/// </summary> | |
private string GetAuthorizationHeader() | |
{ | |
var authContext = new AuthenticationContext(GetFullTenantUri()); | |
var credential = new SymmetricKeyCredential(GetSymmetricKeyIssuingResource(), Convert.FromBase64String(servicePrincipalSymmetricKey)); | |
AssertionCredential assertionCredential = authContext.AcquireToken(GetServiceRealm(), credential); | |
return assertionCredential.CreateAuthorizationHeader(); | |
} | |
/// <summary> | |
/// Queries the Graph API for security groups in which an active user with the given | |
/// <paramref name="userPrincipalName"/> is a direct member. | |
/// </summary> | |
public IList<Group> GetUserGroups(string userPrincipalName) | |
{ | |
var user = dataService.Users | |
.Where(u => u.AccountEnabled == true && u.UserPrincipalName == userPrincipalName) | |
.AsEnumerable() | |
.SingleOrDefault(); | |
var groupReferences = dataService.LoadProperty(user, "MemberOf") | |
.OfType<ReferencedObject>() | |
.Where(r => r.ObjectType == "Group") | |
.Select(g => g.ObjectId); | |
return dataService.Groups | |
.AsEnumerable() | |
.Where(g => groupReferences.Contains(g.ObjectId)) | |
.ToList(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment