Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

renaming #701

Merged
merged 3 commits into from
Oct 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ public IActionResult Challenge(
[HttpGet("{scheme?}")]
public IActionResult SignOut([FromRoute] string scheme)
{
if (AppServiceAuthenticationInformation.IsAppServiceAadAuthenticationEnabled)
if (AppServicesAuthenticationInformation.IsAppServicesAadAuthenticationEnabled)
{
return LocalRedirect(AppServiceAuthenticationInformation.LogoutUrl);
return LocalRedirect(AppServicesAuthenticationInformation.LogoutUrl);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,30 @@
// Licensed under the MIT License.

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;

namespace Microsoft.Identity.Web
{
/// <summary>
/// Extension methods related to App Service authentication (Easy Auth).
/// Extension methods related to App Services authentication (Easy Auth).
/// </summary>
public static class AppServiceAuthenticationBuilderExtensions
public static class AppServicesAuthenticationBuilderExtensions
{
/// <summary>
/// Add authentication with App Services.
/// </summary>
/// <param name="builder">Authentication builder.</param>
/// <returns>The builder, to chain commands.</returns>
public static AuthenticationBuilder AddAppServiceAuthentication(
public static AuthenticationBuilder AddAppServicesAuthentication(
this AuthenticationBuilder builder)
{
if (builder is null)
{
throw new System.ArgumentNullException(nameof(builder));
}

builder.AddScheme<AppServiceAuthenticationOptions, AppServiceAuthenticationHandler>(
AppServiceAuthenticationDefaults.AuthenticationScheme,
AppServiceAuthenticationDefaults.AuthenticationScheme,
builder.AddScheme<AppServicesAuthenticationOptions, AppServicesAuthenticationHandler>(
AppServicesAuthenticationDefaults.AuthenticationScheme,
AppServicesAuthenticationDefaults.AuthenticationScheme,
options => { });

return builder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ namespace Microsoft.Identity.Web
/// <summary>
/// Default values related to AppServiceAuthentication handler.
/// </summary>
public class AppServiceAuthenticationDefaults
public class AppServicesAuthenticationDefaults
{
/// <summary>
/// The default value used for AppServiceAuthenticationOptions.AuthenticationScheme.
/// </summary>
public const string AuthenticationScheme = "EasyAuth";
public const string AuthenticationScheme = "AppServicesAuthentication";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Microsoft.Identity.Web
/// <summary>
/// App service authentication handler.
/// </summary>
public class AppServiceAuthenticationHandler : AuthenticationHandler<AppServiceAuthenticationOptions>
public class AppServicesAuthenticationHandler : AuthenticationHandler<AppServicesAuthenticationOptions>
{
/// <summary>
/// Constructor for the AppServiceAuthenticationHandler.
Expand All @@ -26,8 +26,8 @@ public class AppServiceAuthenticationHandler : AuthenticationHandler<AppServiceA
/// <param name="logger">Logger factory.</param>
/// <param name="encoder">URL encoder.</param>
/// <param name="clock">System clock.</param>
public AppServiceAuthenticationHandler(
IOptionsMonitor<AppServiceAuthenticationOptions> options,
public AppServicesAuthenticationHandler(
IOptionsMonitor<AppServicesAuthenticationOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
Expand All @@ -36,13 +36,13 @@ public AppServiceAuthenticationHandler(
}

// Constants
private const string EasyAuthIdTokenHeader = "X-MS-TOKEN-AAD-ID-TOKEN";
private const string EasyAuthIdpTokenHeader = "X-MS-CLIENT-PRINCIPAL-IDP";
private const string AppServicesAuthIdTokenHeader = "X-MS-TOKEN-AAD-ID-TOKEN";
private const string AppServicesAuthIdpTokenHeader = "X-MS-CLIENT-PRINCIPAL-IDP";

/// <inheritdoc/>
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (AppServiceAuthenticationInformation.IsAppServiceAadAuthenticationEnabled)
if (AppServicesAuthenticationInformation.IsAppServicesAadAuthenticationEnabled)
{
string? idToken = GetIdToken();
string? idp = GetIdp();
Expand All @@ -53,10 +53,10 @@ protected override Task<AuthenticateResult> HandleAuthenticateAsync()
ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(
jsonWebToken.Claims,
idp,
"name", // v1.0
Constants.NameClaim, // v1.0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes me think that we need to check the "ver" claim, and use the right constant (NameClaim or prefered_username, depending on the version.

ClaimsIdentity.DefaultRoleClaimType));

AuthenticationTicket ticket = new AuthenticationTicket(claimsPrincipal, AppServiceAuthenticationDefaults.AuthenticationScheme);
AuthenticationTicket ticket = new AuthenticationTicket(claimsPrincipal, AppServicesAuthenticationDefaults.AuthenticationScheme);
AuthenticateResult success = AuthenticateResult.Success(ticket);
return Task<AuthenticateResult>.FromResult<AuthenticateResult>(success);
}
Expand All @@ -68,23 +68,23 @@ protected override Task<AuthenticateResult> HandleAuthenticateAsync()

private string? GetIdp()
{
string? idp = Context.Request.Headers[EasyAuthIdpTokenHeader];
string? idp = Context.Request.Headers[AppServicesAuthIdpTokenHeader];
#if DEBUG
if (string.IsNullOrEmpty(idp))
{
idp = AppServiceAuthenticationInformation.SimulateGetttingHeaderFromDebugEnvironmentVariable(EasyAuthIdpTokenHeader);
idp = AppServicesAuthenticationInformation.SimulateGetttingHeaderFromDebugEnvironmentVariable(AppServicesAuthIdpTokenHeader);
}
#endif
return idp;
}

private string? GetIdToken()
{
string? idToken = Context.Request.Headers[EasyAuthIdTokenHeader];
string? idToken = Context.Request.Headers[AppServicesAuthIdTokenHeader];
#if DEBUG
if (string.IsNullOrEmpty(idToken))
{
idToken = AppServiceAuthenticationInformation.SimulateGetttingHeaderFromDebugEnvironmentVariable(EasyAuthIdTokenHeader);
idToken = AppServicesAuthenticationInformation.SimulateGetttingHeaderFromDebugEnvironmentVariable(AppServicesAuthIdTokenHeader);
}
#endif
return idToken;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Linq;

namespace Microsoft.Identity.Web
{
/// <summary>
/// Information about the App Services configuration on the host.
/// </summary>
public static class AppServicesAuthenticationInformation
{
// Environment variables.
private const string AppServicesAuthEnabledEnvironmentVariable = "WEBSITE_AUTH_ENABLED"; // True
private const string AppServicesAuthOpenIdIssuerEnvironmentVariable = "WEBSITE_AUTH_OPENID_ISSUER"; // for instance https://sts.windows.net/<tenantId>/
private const string AppServicesAuthClientIdEnvironmentVariable = "WEBSITE_AUTH_CLIENT_ID"; // A GUID
private const string AppServicesAuthClientSecretEnvironmentVariable = "WEBSITE_AUTH_CLIENT_SECRET"; // A string
private const string AppServicesAuthLogoutPathEnvironmentVariable = "WEBSITE_AUTH_LOGOUT_PATH"; // /.auth/logout
private const string AppServicesAuthIdentityProviderEnvironmentVariable = "WEBSITE_AUTH_DEFAULT_PROVIDER"; // AzureActiveDirectory
private const string AppServicesAuthAzureActiveDirectory = "AzureActiveDirectory";

// Artificially added by Microsoft.Identity.Web to help debugging App Services. See the Debug controller of the test app
private const string AppServicesAuthDebugHeadersEnvironmentVariable = "APP_SERVICES_AUTH_LOCAL_DEBUG";

/// <summary>
/// Is App Services authentication enabled?.
/// </summary>
public static bool IsAppServicesAadAuthenticationEnabled
{
get
{
return (Environment.GetEnvironmentVariable(AppServicesAuthEnabledEnvironmentVariable) == Constants.True)
&& Environment.GetEnvironmentVariable(AppServicesAuthIdentityProviderEnvironmentVariable) == AppServicesAuthAzureActiveDirectory;
}
}

/// <summary>
/// Logout URL for App Services Auth web sites.
/// </summary>
public static string? LogoutUrl
{
get
{
return Environment.GetEnvironmentVariable(AppServicesAuthLogoutPathEnvironmentVariable);
}
}

/// <summary>
/// ClientID of the App Services Auth web site.
/// </summary>
internal static string? ClientId
{
get
{
return Environment.GetEnvironmentVariable(AppServicesAuthClientIdEnvironmentVariable);
}
}

/// <summary>
/// Client secret of the App Services Auth web site.
/// </summary>
internal static string? ClientSecret
{
get
{
return Environment.GetEnvironmentVariable(AppServicesAuthClientSecretEnvironmentVariable);
}
}

/// <summary>
/// Issuer of the App Services Auth web site.
/// </summary>
internal static string? Issuer
{
get
{
return Environment.GetEnvironmentVariable(AppServicesAuthOpenIdIssuerEnvironmentVariable);
}
}

#if DEBUG
/// <summary>
/// Get headers from environment to help debugging App Services authentication.
/// </summary>
internal static string? SimulateGetttingHeaderFromDebugEnvironmentVariable(string header)
{
string? headerPlusValue = Environment.GetEnvironmentVariable(AppServicesAuthDebugHeadersEnvironmentVariable)
?.Split(';')
?.FirstOrDefault(h => h.StartsWith(header));
return headerPlusValue?.Substring(header.Length + 1);
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
namespace Microsoft.Identity.Web
{
/// <summary>
/// Options for Azure AppService authentication.
/// Options for Azure App Services authentication.
/// </summary>
public class AppServiceAuthenticationOptions : AuthenticationSchemeOptions
public class AppServicesAuthenticationOptions : AuthenticationSchemeOptions
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
namespace Microsoft.Identity.Web
{
/// <summary>
/// Implementation of ITokenAcquisition for App services authentication (EasyAuth).
/// Implementation of ITokenAcquisition for App Services authentication (EasyAuth).
/// </summary>
public class AppServicesAuthenticationTokenAcquisition : ITokenAcquisition
{
private IConfidentialClientApplication _confidentialClientApplication;
private IHttpContextAccessor _httpContextAccessor;
private IMsalHttpClientFactory _httpClientFactory;
private IMsalTokenCacheProvider _tokenCacheProvider;
private IConfidentialClientApplication? _confidentialClientApplication;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IMsalHttpClientFactory _httpClientFactory;
private readonly IMsalTokenCacheProvider _tokenCacheProvider;

private HttpContext? CurrentHttpContext
{
Expand All @@ -36,7 +36,10 @@ private HttpContext? CurrentHttpContext
/// <param name="tokenCacheProvider">The App token cache provider.</param>
/// <param name="httpContextAccessor">Access to the HttpContext of the request.</param>
/// <param name="httpClientFactory">HTTP client factory.</param>
public AppServicesAuthenticationTokenAcquisition(IMsalTokenCacheProvider tokenCacheProvider, IHttpContextAccessor httpContextAccessor, IHttpClientFactory httpClientFactory)
public AppServicesAuthenticationTokenAcquisition(
IMsalTokenCacheProvider tokenCacheProvider,
IHttpContextAccessor httpContextAccessor,
IHttpClientFactory httpClientFactory)
{
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
_httpClientFactory = new MsalAspNetCoreHttpClientFactory(httpClientFactory);
Expand All @@ -49,16 +52,17 @@ private async Task<IConfidentialClientApplication> GetOrCreateApplication()
{
ConfidentialClientApplicationOptions options = new ConfidentialClientApplicationOptions()
{
ClientId = AppServiceAuthenticationInformation.ClientId,
ClientSecret = AppServiceAuthenticationInformation.ClientSecret,
Instance = AppServiceAuthenticationInformation.Issuer,
ClientId = AppServicesAuthenticationInformation.ClientId,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should consider some refactoring in tokenAcqusition so we don't have to repeat this code. not something for this PR, but something for the future we shoudl consider.

ClientSecret = AppServicesAuthenticationInformation.ClientSecret,
Instance = AppServicesAuthenticationInformation.Issuer,
};
_confidentialClientApplication = ConfidentialClientApplicationBuilder.CreateWithApplicationOptions(options)
.WithHttpClientFactory(_httpClientFactory)
.Build();
await _tokenCacheProvider.InitializeAsync(_confidentialClientApplication.AppTokenCache).ConfigureAwait(false);
await _tokenCacheProvider.InitializeAsync(_confidentialClientApplication.UserTokenCache).ConfigureAwait(false);
}

return _confidentialClientApplication;
}

Expand All @@ -74,7 +78,7 @@ public async Task<string> GetAccessTokenForAppAsync(
throw new ArgumentNullException(nameof(scope));
}

var app = await GetOrCreateApplication();
var app = await GetOrCreateApplication().ConfigureAwait(false);
AuthenticationResult result = await app.AcquireTokenForClient(new string[] { scope })
.ExecuteAsync()
.ConfigureAwait(false);
Expand All @@ -83,28 +87,39 @@ public async Task<string> GetAccessTokenForAppAsync(
}

/// <inheritdoc/>
public Task<string> GetAccessTokenForUserAsync(IEnumerable<string> scopes, string? tenantId = null, string? userFlow = null, ClaimsPrincipal? user = null, TokenAcquisitionOptions? tokenAcquisitionOptions = null)
public async Task<string> GetAccessTokenForUserAsync(
IEnumerable<string> scopes,
string? tenantId = null,
string? userFlow = null,
ClaimsPrincipal? user = null,
TokenAcquisitionOptions? tokenAcquisitionOptions = null)
{
string accessToken = GetAccessToken(CurrentHttpContext.Request.Headers);
return Task.FromResult(accessToken);
string accessToken = GetAccessToken(CurrentHttpContext?.Request.Headers);

return await Task.FromResult(accessToken).ConfigureAwait(false);
}

private string? GetAccessToken(IHeaderDictionary? headers)
private string GetAccessToken(IHeaderDictionary? headers)
{
const string easyAuthAccessTokenHeader = "X-MS-TOKEN-AAD-ACCESS-TOKEN";
const string AppServicesAuthAccessTokenHeader = "X-MS-TOKEN-AAD-ACCESS-TOKEN";

string? accessToken = null;
if (headers != null)
{
accessToken = headers[easyAuthAccessTokenHeader];
accessToken = headers[AppServicesAuthAccessTokenHeader];
}
#if DEBUG
if (string.IsNullOrEmpty(accessToken))
{
accessToken = AppServiceAuthenticationInformation.SimulateGetttingHeaderFromDebugEnvironmentVariable(easyAuthAccessTokenHeader);
accessToken = AppServicesAuthenticationInformation.SimulateGetttingHeaderFromDebugEnvironmentVariable(AppServicesAuthAccessTokenHeader);
}
#endif
return accessToken;
if (!string.IsNullOrEmpty(accessToken))
{
return accessToken;
}

return string.Empty;
}

/// <inheritdoc/>
Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.Identity.Web/Constants/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public static class Constants
internal const string Authorization = "Authorization";
internal const string ApplicationJson = "application/json";
internal const string ISessionStore = "ISessionStore";
internal const string True = "True";

// Blazor challenge URI
internal const string BlazorChallengeUri = "MicrosoftIdentity/Account/Challenge?redirectUri=";
Expand Down
Loading