Skip to content

Commit

Permalink
Fix for #1136 - case insensitive comparison to detect app service env (
Browse files Browse the repository at this point in the history
…#1168)

* Fix for #1136 - case insensitive comparison to detect app service env

* Add another test to keep SQ happy

* Test

* update test (#1173)

Co-authored-by: jennyf19 <[email protected]>
  • Loading branch information
bgavrilMS and jennyf19 authored May 1, 2021
1 parent 88e379d commit 298909f
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ namespace Microsoft.Identity.Web
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";
private const string AppServicesAuthIdTokenHeader = "X-MS-TOKEN-AAD-ID-TOKEN";
internal const string AppServicesAuthEnabledEnvironmentVariable = "WEBSITE_AUTH_ENABLED"; // True
internal const string AppServicesAuthOpenIdIssuerEnvironmentVariable = "WEBSITE_AUTH_OPENID_ISSUER"; // for instance https://sts.windows.net/<tenantId>/
internal const string AppServicesAuthClientIdEnvironmentVariable = "WEBSITE_AUTH_CLIENT_ID"; // A GUID
internal const string AppServicesAuthClientSecretEnvironmentVariable = "WEBSITE_AUTH_CLIENT_SECRET"; // A string
internal const string AppServicesAuthLogoutPathEnvironmentVariable = "WEBSITE_AUTH_LOGOUT_PATH"; // /.auth/logout
internal const string AppServicesAuthIdentityProviderEnvironmentVariable = "WEBSITE_AUTH_DEFAULT_PROVIDER"; // AzureActiveDirectory
internal const string AppServicesAuthAzureActiveDirectory = "AzureActiveDirectory";
internal const string AppServicesAuthIdTokenHeader = "X-MS-TOKEN-AAD-ID-TOKEN";
private const string AppServicesAuthIdpTokenHeader = "X-MS-CLIENT-PRINCIPAL-IDP";

// 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";
internal const string AppServicesAuthDebugHeadersEnvironmentVariable = "APP_SERVICES_AUTH_LOCAL_DEBUG";

/// <summary>
/// Is App Services authentication enabled?.
Expand All @@ -36,8 +36,17 @@ public static bool IsAppServicesAadAuthenticationEnabled
{
get
{
return (Environment.GetEnvironmentVariable(AppServicesAuthEnabledEnvironmentVariable) == Constants.True)
&& Environment.GetEnvironmentVariable(AppServicesAuthIdentityProviderEnvironmentVariable) == AppServicesAuthAzureActiveDirectory;
return

string.Equals(
Environment.GetEnvironmentVariable(AppServicesAuthEnabledEnvironmentVariable),
Constants.True,
StringComparison.OrdinalIgnoreCase) &&

string.Equals(
Environment.GetEnvironmentVariable(AppServicesAuthIdentityProviderEnvironmentVariable),
AppServicesAuthAzureActiveDirectory,
StringComparison.OrdinalIgnoreCase);
}
}

Expand Down Expand Up @@ -93,7 +102,7 @@ internal static string? Issuer
{
string? headerPlusValue = Environment.GetEnvironmentVariable(AppServicesAuthDebugHeadersEnvironmentVariable)
?.Split(';')
?.FirstOrDefault(h => h.StartsWith(header));
?.FirstOrDefault(h => h.StartsWith(header, StringComparison.OrdinalIgnoreCase));
return headerPlusValue?.Substring(header.Length + 1);
}
#endif
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.Primitives;
using Xunit;

namespace Microsoft.Identity.Web.Test
{
public class AppServicesAuthenticationInformationTests
{
[Fact]
public void SimulateGetttingHeaderFromDebugEnvironmentVariable()
{
try
{
Environment.SetEnvironmentVariable(
AppServicesAuthenticationInformation.AppServicesAuthDebugHeadersEnvironmentVariable,
$"a;{AppServicesAuthenticationInformation.AppServicesAuthIdTokenHeader}:xyz");

var res = AppServicesAuthenticationInformation.GetIdToken(
new Dictionary<string, StringValues>()
{
{ AppServicesAuthenticationInformation.AppServicesAuthIdTokenHeader, new StringValues(string.Empty) },
});

#if DEBUG
Assert.Equal("xyz", res);
#else
Assert.Equal(string.Empty, res);
#endif
}
finally
{
Environment.SetEnvironmentVariable(
AppServicesAuthenticationInformation.AppServicesAuthDebugHeadersEnvironmentVariable,
string.Empty);
}
}
}
}
48 changes: 47 additions & 1 deletion tests/Microsoft.Identity.Web.Test/WebAppExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,21 @@ public class WebAppExtensionsTests

public WebAppExtensionsTests()
{
ResetAppServiceEnv();
_configSection = GetConfigSection(ConfigSectionName);
_env = new HostingEnvironment { EnvironmentName = Environments.Development };
}

private void ResetAppServiceEnv()
{
Environment.SetEnvironmentVariable(AppServicesAuthenticationInformation.AppServicesAuthEnabledEnvironmentVariable, string.Empty);
Environment.SetEnvironmentVariable(AppServicesAuthenticationInformation.AppServicesAuthIdentityProviderEnvironmentVariable, string.Empty);
Environment.SetEnvironmentVariable(AppServicesAuthenticationInformation.AppServicesAuthClientIdEnvironmentVariable, string.Empty);
Environment.SetEnvironmentVariable(AppServicesAuthenticationInformation.AppServicesAuthClientSecretEnvironmentVariable, string.Empty);
Environment.SetEnvironmentVariable(AppServicesAuthenticationInformation.AppServicesAuthLogoutPathEnvironmentVariable, string.Empty);
Environment.SetEnvironmentVariable(AppServicesAuthenticationInformation.AppServicesAuthIdentityProviderEnvironmentVariable, string.Empty);
}

[Theory]
[InlineData(true)]
[InlineData(false)]
Expand Down Expand Up @@ -411,6 +422,39 @@ public void AddMicrosoftIdentityWebApp_AddsInMemoryTokenCaches()
Assert.Contains(services, s => s.ServiceType == typeof(IMsalTokenCacheProvider));
}

[Theory]
[InlineData("tRue", "azureactivedirectory")]
[InlineData("true", "azureactivedirectory")]
[InlineData("tRue", AppServicesAuthenticationInformation.AppServicesAuthAzureActiveDirectory)]
[InlineData("true", AppServicesAuthenticationInformation.AppServicesAuthAzureActiveDirectory)]
// Regression for https://github.com/AzureAD/microsoft-identity-web/issues/1163
public void AppServices_EnvironmentTest(string appServicesEnvEnabledValue, string idpEnvValue)
{
try
{
// Arrange
Environment.SetEnvironmentVariable(
AppServicesAuthenticationInformation.AppServicesAuthEnabledEnvironmentVariable, appServicesEnvEnabledValue);

Environment.SetEnvironmentVariable(
AppServicesAuthenticationInformation.AppServicesAuthIdentityProviderEnvironmentVariable,
idpEnvValue);

var services = new ServiceCollection();

// Act
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(_configureMsOptions);

// Assert
Assert.Contains(services, s => s.ServiceType == typeof(AppServicesAuthenticationHandler));
}
finally
{
ResetAppServiceEnv();
}
}

[Fact]
public void AddMicrosoftGraphUsingFactoryFunction()
{
Expand Down Expand Up @@ -552,6 +596,8 @@ private void AddMicrosoftIdentityWebApp_TestCommon(IServiceCollection services,
Assert.Contains(services, s => s.ServiceType == typeof(IConfigureOptions<OpenIdConnectOptions>));
Assert.Contains(services, s => s.ServiceType == typeof(IConfigureOptions<MicrosoftIdentityOptions>));
Assert.Contains(services, s => s.ServiceType == typeof(IPostConfigureOptions<CookieAuthenticationOptions>));
Assert.DoesNotContain(services, s => s.ServiceType == typeof(AppServicesAuthenticationHandler));

Assert.Equal(ServiceLifetime.Singleton, services.First(s => s.ServiceType == typeof(MicrosoftIdentityIssuerValidatorFactory)).Lifetime);

// Assert properties set
Expand Down Expand Up @@ -634,7 +680,7 @@ private async Task AddMicrosoftIdentityWebApp_TestB2cSpecificSetup(IServiceColle

await remoteFailureFuncMock.ReceivedWithAnyArgs().Invoke(Arg.Any<RemoteFailureContext>()).ConfigureAwait(false);
// Assert issuer is updated to non-default user flow
Assert.Contains(TestConstants.B2CEditProfileUserFlow, redirectContext.ProtocolMessage.IssuerAddress);
Assert.Contains(TestConstants.B2CEditProfileUserFlow, redirectContext.ProtocolMessage.IssuerAddress, System.StringComparison.OrdinalIgnoreCase);
Assert.NotNull(redirectContext.ProtocolMessage.Parameters[ClaimConstants.ClientInfo]);
Assert.Equal(Constants.One, redirectContext.ProtocolMessage.Parameters[ClaimConstants.ClientInfo].ToString(CultureInfo.InvariantCulture));
}
Expand Down

0 comments on commit 298909f

Please sign in to comment.