forked from AzureAD/microsoft-identity-web
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for Microsoft.Graph 5.x (AzureAD#2276)
* Spec-in dev ex with Graph 5 * add graph beta support (AzureAD#2273) * fix sample (AzureAD#2278) * Fixing the tests * Adding GraphServiceClient modifiers (WithAppOnly, WithSCopes, ....) (AzureAD#2279) * Updating the README.md --------- Co-authored-by: jennyf19 <[email protected]>
- Loading branch information
Showing
24 changed files
with
936 additions
and
15 deletions.
There are no files selected for viewing
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
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
18 changes: 18 additions & 0 deletions
18
src/Microsoft.Identity.Web.GraphServiceClient/GraphAuthenticationOptions.cs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using Microsoft.Kiota.Abstractions; | ||
|
||
namespace Microsoft.Identity.Web | ||
{ | ||
/// <summary> | ||
/// Authentication options controlling the authentication request to the Microsoft Graph service. | ||
/// </summary> | ||
public class GraphAuthenticationOptions : GraphServiceClientOptions, IRequestOption | ||
{ | ||
/// <summary> | ||
/// Base URL for the Microsoft Graph API. By default: <c>"https://graph.microsoft.com/v1.0/"</c> | ||
/// </summary> | ||
public new string BaseUrl { get { return base.BaseUrl!; } } | ||
} | ||
} |
145 changes: 145 additions & 0 deletions
145
src/Microsoft.Identity.Web.GraphServiceClient/GraphAuthenticationProvider.cs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Net.Http; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.Identity.Abstractions; | ||
using Microsoft.Kiota.Abstractions; | ||
using Microsoft.Kiota.Abstractions.Authentication; | ||
|
||
namespace Microsoft.Identity.Web | ||
{ | ||
/// <summary> | ||
/// Authentication provider for Microsoft Graph, based on IAuthorizationHeaderProvider. This is richer | ||
/// than <see cref="BaseBearerTokenAuthenticationProvider"/> which only supports the bearer protocol. | ||
/// </summary> | ||
internal class GraphAuthenticationProvider : IAuthenticationProvider | ||
{ | ||
const string ScopeKey = "scopes"; | ||
private const string AuthorizationHeaderKey = "Authorization"; | ||
private const string AuthorizationHeaderProviderOptionsKey = "authorizationHeaderProviderOptions"; | ||
readonly IAuthorizationHeaderProvider _authorizationHeaderProvider; | ||
readonly GraphServiceClientOptions _defaultAuthenticationOptions; | ||
|
||
/// <summary> | ||
/// Constructor from the authorization header provider. | ||
/// </summary> | ||
/// <param name="authorizationHeaderProvider"></param> | ||
/// <param name="defaultAuthenticationOptions"></param> | ||
public GraphAuthenticationProvider(IAuthorizationHeaderProvider authorizationHeaderProvider, | ||
GraphServiceClientOptions defaultAuthenticationOptions) | ||
{ | ||
_authorizationHeaderProvider = authorizationHeaderProvider; | ||
_defaultAuthenticationOptions = defaultAuthenticationOptions; | ||
} | ||
|
||
/// <summary> | ||
/// Method that performs the authentication, and adds the right headers to the request. | ||
/// </summary> | ||
/// <param name="request"></param> | ||
/// <param name="additionalAuthenticationContext"></param> | ||
/// <param name="cancellationToken"></param> | ||
/// <returns></returns> | ||
/// <exception cref="ArgumentNullException"></exception> | ||
public async Task AuthenticateRequestAsync( | ||
RequestInformation request, | ||
Dictionary<string, object>? additionalAuthenticationContext = null, | ||
CancellationToken cancellationToken = default) | ||
{ | ||
_ = Throws.IfNull(request); | ||
|
||
// Attempts to get the scopes | ||
IEnumerable<string>? scopes; | ||
GraphServiceClientOptions? graphServiceClientOptions; | ||
|
||
if (additionalAuthenticationContext != null) | ||
{ | ||
scopes = additionalAuthenticationContext.ContainsKey(ScopeKey) ? (string[])additionalAuthenticationContext[ScopeKey] : _defaultAuthenticationOptions?.Scopes; | ||
graphServiceClientOptions = additionalAuthenticationContext.ContainsKey(AuthorizationHeaderProviderOptionsKey) ? | ||
(GraphServiceClientOptions)additionalAuthenticationContext[AuthorizationHeaderProviderOptionsKey] : | ||
_defaultAuthenticationOptions; | ||
} | ||
else | ||
{ | ||
scopes = _defaultAuthenticationOptions.Scopes; | ||
graphServiceClientOptions = _defaultAuthenticationOptions; | ||
} | ||
|
||
// Remove the authorization header if it exists | ||
if (request.Headers.ContainsKey(AuthorizationHeaderKey)) | ||
{ | ||
request.Headers.Remove(AuthorizationHeaderKey); | ||
} | ||
|
||
// Data coming from the request (needed in protocols like "Pop") | ||
AuthorizationHeaderProviderOptions? authorizationHeaderProviderOptions; | ||
if (string.Compare(graphServiceClientOptions?.ProtocolScheme, "bearer", StringComparison.OrdinalIgnoreCase) == 0) | ||
{ | ||
authorizationHeaderProviderOptions = new AuthorizationHeaderProviderOptions(graphServiceClientOptions!); | ||
authorizationHeaderProviderOptions.BaseUrl = request.URI.Host; | ||
authorizationHeaderProviderOptions.RelativePath = request.URI.LocalPath; | ||
authorizationHeaderProviderOptions.HttpMethod = GetHttpMethod(request.HttpMethod); | ||
} | ||
else | ||
{ | ||
authorizationHeaderProviderOptions = graphServiceClientOptions; | ||
} | ||
|
||
// Add the authorization header | ||
if (!request.Headers.ContainsKey(AuthorizationHeaderKey)) | ||
{ | ||
string authorizationHeader; | ||
if (authorizationHeaderProviderOptions!.RequestAppToken) | ||
{ | ||
authorizationHeader = await _authorizationHeaderProvider.CreateAuthorizationHeaderForAppAsync(scopes!.FirstOrDefault()!, | ||
authorizationHeaderProviderOptions); | ||
} | ||
else | ||
{ | ||
authorizationHeader = await _authorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync( | ||
scopes!, | ||
authorizationHeaderProviderOptions); | ||
} | ||
request.Headers.Add(AuthorizationHeaderKey, authorizationHeader); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Transforms the Kiota HTTP Method (enum) into a .NET HttpMethod (static members). | ||
/// </summary> | ||
/// <param name="httpMethod">Kiota Http method</param> | ||
/// <returns>HttpMethod</returns> | ||
private HttpMethod GetHttpMethod(Method httpMethod) | ||
{ | ||
switch (httpMethod) | ||
{ | ||
case Method.GET: | ||
return HttpMethod.Get; | ||
case Method.POST: | ||
return HttpMethod.Post; | ||
case Method.PUT: | ||
return HttpMethod.Put; | ||
case Method.PATCH: | ||
#if NETFRAMEWORK || NETSTANDARD2_0 | ||
return HttpMethod.Put; | ||
#else | ||
return HttpMethod.Patch; | ||
#endif | ||
case Method.DELETE: | ||
return HttpMethod.Delete; | ||
case Method.OPTIONS: | ||
return HttpMethod.Options; | ||
case Method.TRACE: | ||
return HttpMethod.Trace; | ||
case Method.HEAD: | ||
return HttpMethod.Head; | ||
default: | ||
throw new ArgumentOutOfRangeException(); | ||
} | ||
} | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
src/Microsoft.Identity.Web.GraphServiceClient/GraphServiceClientOptions.cs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using Microsoft.Identity.Abstractions; | ||
using System.Collections.Generic; | ||
|
||
namespace Microsoft.Identity.Web | ||
{ | ||
/// <summary> | ||
/// Options passed-in to call Microsoft Graph. | ||
/// </summary> | ||
public class GraphServiceClientOptions : AuthorizationHeaderProviderOptions | ||
{ | ||
/// <summary> | ||
/// Options used to configure the authentication provider for Microsoft Graph. | ||
/// </summary> | ||
public GraphServiceClientOptions() | ||
{ | ||
BaseUrl = Constants.GraphBaseUrlV1; | ||
Scopes = new[] { Constants.UserReadScope }; | ||
} | ||
|
||
/// <summary> | ||
/// Scopes required to call the downstream web API. | ||
/// For instance "user.read mail.read". | ||
/// For Microsoft identity, in the case of application tokens (token | ||
/// requested by the app on behalf of itself), there should be only one scope, and it | ||
/// should end in "./default") | ||
/// </summary> | ||
public IEnumerable<string> Scopes { get; set; } | ||
} | ||
} |
74 changes: 74 additions & 0 deletions
74
src/Microsoft.Identity.Web.GraphServiceClient/GraphServiceCollectionExtensions.cs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Net.Http; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Options; | ||
using Microsoft.Graph; | ||
using Microsoft.Identity.Abstractions; | ||
|
||
namespace Microsoft.Identity.Web | ||
{ | ||
/// <summary> | ||
/// Extensions methods on a MicrosoftIdentityAppCallingWebApiAuthenticationBuilder builder | ||
/// to add support to call Microsoft Graph. | ||
/// </summary> | ||
public static class GraphServiceCollectionExtensions | ||
{ | ||
/// <summary> | ||
/// Add support to call Microsoft Graph. From a named option and a configuration section. | ||
/// </summary> | ||
/// <param name="services">Builder.</param> | ||
/// <returns>The service collection to chain.</returns> | ||
public static IServiceCollection AddMicrosoftGraph(this IServiceCollection services) | ||
{ | ||
services.AddTokenAcquisition(); | ||
services.AddHttpClient(); | ||
return services.AddMicrosoftGraph(options => { }); | ||
} | ||
|
||
/// <summary> | ||
/// Add support to call Microsoft Graph. From a base Graph URL and a default scope. | ||
/// </summary> | ||
/// <param name="services">Builder.</param> | ||
/// <param name="configurationSection">Configuration section containing the Microsoft graph config.</param> | ||
/// <returns>The service collection to chain.</returns> | ||
public static IServiceCollection AddMicrosoftGraph(this IServiceCollection services, IConfiguration configurationSection) | ||
{ | ||
return services.AddMicrosoftGraph(o => configurationSection.Bind(o)); | ||
} | ||
|
||
/// <summary> | ||
/// Add support to call Microsoft Graph. From a base Graph URL and a default scope. | ||
/// </summary> | ||
/// <param name="services">Builder.</param> | ||
/// <param name="configureMicrosoftGraphOptions">Delegate to configure the graph service options</param> | ||
/// <returns>The service collection to chain.</returns> | ||
public static IServiceCollection AddMicrosoftGraph(this IServiceCollection services, Action<GraphServiceClientOptions> configureMicrosoftGraphOptions) | ||
{ | ||
// https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests | ||
services.AddOptions<GraphServiceClientOptions>().Configure(configureMicrosoftGraphOptions); | ||
|
||
services.AddScoped<GraphServiceClient, GraphServiceClient>(serviceProvider => | ||
{ | ||
var authorizationHeaderProvider = serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>(); | ||
var options = serviceProvider.GetRequiredService<IOptions<GraphServiceClientOptions>>(); | ||
var httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>(); | ||
var microsoftGraphOptions = options.Value; | ||
if (microsoftGraphOptions.Scopes == null) | ||
{ | ||
Throws.ArgumentNullException("scopes", IDWebErrorMessage.CalledApiScopesAreNull); | ||
} | ||
|
||
var httpClient = httpClientFactory.CreateClient("GraphServiceClient"); | ||
|
||
GraphServiceClient graphServiceClient = new(httpClient, | ||
new GraphAuthenticationProvider(authorizationHeaderProvider, microsoftGraphOptions), microsoftGraphOptions.BaseUrl); | ||
return graphServiceClient; | ||
}); | ||
return services; | ||
} | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
...icrosoft.Identity.Web.GraphServiceClient/Microsoft.Identity.Web.GraphServiceClient.csproj
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
|
||
<Title>Microsoft Identity Web, Microsoft Graph v5+ helper</Title> | ||
<Product>Microsoft Identity Web</Product> | ||
<Description> | ||
This package enables ASP.NET Core web apps and web APIs to use the Microsoft identity platform (formerly Azure AD v2.0). | ||
This package is specifically used for web applications, which sign-in users and call Microsoft Graph, and for protected web APIs | ||
that call Microsoft Graph. Works specifically with MS Graph SDK v5 and above. For MS Graph SDK v4 support, please use Microsoft.Identity.Web.MicrosoftGraph. | ||
</Description> | ||
<ProjectGuid>{4DF02DF7-D092-4F45-8892-8A1D3E612706}</ProjectGuid> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.Graph" Version="5.12.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Microsoft.Identity.Web.TokenAcquisition\Microsoft.Identity.Web.TokenAcquisition.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Oops, something went wrong.