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

Update identity to enable live testing in sovereign clouds for multiple services #19203

Merged
merged 17 commits into from
May 4, 2021
Merged
2 changes: 1 addition & 1 deletion sdk/core/Azure.Core.TestFramework/src/TestEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ static TestEnvironment()
/// <summary>
/// The URL of the Azure Authority host to be used for authentication. Recorded.
/// </summary>
public string AuthorityHostUrl => GetRecordedOptionalVariable("AZURE_AUTHORITY_HOST");
public string AuthorityHostUrl => GetRecordedOptionalVariable("AZURE_AUTHORITY_HOST") ?? AzureAuthorityHosts.AzurePublicCloud.ToString();

/// <summary>
/// The suffix for Azure Storage accounts for the active cloud environment, such as "core.windows.net". Recorded.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
Expand Down Expand Up @@ -35,7 +36,7 @@ public async Task FromCertificatePath(bool usePem)

var credential = InstrumentClient(new ClientCertificateCredential(tenantId, clientId, certPath, options));

var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(AzureAuthorityHosts.AzurePublicCloud) });
var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(new Uri(TestEnvironment.AuthorityHostUrl)) });

// ensure we can initially acquire a token
AccessToken token = await credential.GetTokenAsync(tokenRequestContext);
Expand Down Expand Up @@ -70,7 +71,7 @@ public async Task FromX509Certificate2()

var credential = InstrumentClient(new ClientCertificateCredential(tenantId, clientId, cert, options));

var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(AzureAuthorityHosts.AzurePublicCloud) });
var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(new Uri(TestEnvironment.AuthorityHostUrl)) });

// ensure we can initially acquire a token
AccessToken token = await credential.GetTokenAsync(tokenRequestContext);
Expand Down Expand Up @@ -105,7 +106,7 @@ public async Task IncludeX5CClaimHeader()

var credential = InstrumentClient(new ClientCertificateCredential(tenantId, clientId, certPath, options));

var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(AzureAuthorityHosts.AzurePublicCloud) });
var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(new Uri(TestEnvironment.AuthorityHostUrl)) });

// ensure we can initially acquire a token
AccessToken token = await credential.GetTokenAsync(tokenRequestContext);
Expand All @@ -124,7 +125,7 @@ public void IncorrectCertificate()

var credential = InstrumentClient(new ClientCertificateCredential(tenantId, clientId, new X509Certificate2(certPath), options));

var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(AzureAuthorityHosts.AzurePublicCloud) });
var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(new Uri(TestEnvironment.AuthorityHostUrl)) });

// ensure the incorrect client claim is rejected, handled and wrapped in AuthenticationFailedException
Assert.ThrowsAsync<AuthenticationFailedException>(async () => await credential.GetTokenAsync(tokenRequestContext));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public async Task GetToken()

var credential = InstrumentClient(new ClientSecretCredential(tenantId, clientId, secret, options));

var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(AzureAuthorityHosts.AzurePublicCloud) });
var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(new Uri(TestEnvironment.AuthorityHostUrl)) });

// ensure we can initially acquire a token
AccessToken token = await credential.GetTokenAsync(tokenRequestContext);
Expand Down Expand Up @@ -70,7 +70,7 @@ public void GetTokenIncorrectPassword()

var credential = InstrumentClient(new ClientSecretCredential(tenantId, clientId, secret, options));

var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(AzureAuthorityHosts.AzurePublicCloud) });
var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(new Uri(TestEnvironment.AuthorityHostUrl)) });

// ensure we can initially acquire a token
Assert.ThrowsAsync<AuthenticationFailedException>(async () => await credential.GetTokenAsync(tokenRequestContext));
Expand Down
2 changes: 2 additions & 0 deletions sdk/identity/Azure.Identity/tests/CredentialTestHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,10 @@ public static async Task<string> GetRefreshTokenAsync(IdentityTestEnvironment te
var clientId = "aebc6443-996d-45c2-90f0-388ff96faa56";
var username = testEnvironment.Username;
var password = testEnvironment.Password;
var authorityUri = new Uri(new Uri(testEnvironment.AuthorityHostUrl), testEnvironment.TestTenantId).ToString();

var client = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(authorityUri)
.WithTenantId(testEnvironment.TestTenantId)
.Build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public async Task DefaultAzureCredential_UseVisualStudioCredential()

using (ClientDiagnosticListener diagnosticListener = new ClientDiagnosticListener(s => s.StartsWith("Azure.Identity")))
{
token = await credential.GetTokenAsync(new TokenRequestContext(new[] {"https://vault.azure.net/.default"}), CancellationToken.None);
token = await credential.GetTokenAsync(new TokenRequestContext(new[] {TestEnvironment.KeyvaultScope}), CancellationToken.None);
scopes = diagnosticListener.Scopes;
}

Expand All @@ -66,6 +66,7 @@ public async Task DefaultAzureCredential_UseVisualStudioCodeCredential()
ExcludeEnvironmentCredential = true,
ExcludeInteractiveBrowserCredential = true,
ExcludeSharedTokenCacheCredential = true,
ExcludeManagedIdentityCredential = true,
VisualStudioCodeTenantId = TestEnvironment.TestTenantId
});

Expand All @@ -82,7 +83,7 @@ public async Task DefaultAzureCredential_UseVisualStudioCodeCredential()
using (await CredentialTestHelpers.CreateRefreshTokenFixtureAsync(TestEnvironment, Mode, ExpectedServiceName, cloudName))
using (ClientDiagnosticListener diagnosticListener = new ClientDiagnosticListener(s => s.StartsWith("Azure.Identity")))
{
token = await credential.GetTokenAsync(new TokenRequestContext(new[] {"https://vault.azure.net/.default"}), CancellationToken.None);
token = await credential.GetTokenAsync(new TokenRequestContext(new[] {TestEnvironment.KeyvaultScope}), CancellationToken.None);
scopes = diagnosticListener.Scopes;
}

Expand All @@ -102,6 +103,7 @@ public async Task DefaultAzureCredential_UseVisualStudioCodeCredential_ParallelC
ExcludeEnvironmentCredential = true,
ExcludeInteractiveBrowserCredential = true,
ExcludeSharedTokenCacheCredential = true,
ExcludeManagedIdentityCredential = true,
VisualStudioCodeTenantId = TestEnvironment.TestTenantId
});

Expand All @@ -117,7 +119,7 @@ public async Task DefaultAzureCredential_UseVisualStudioCodeCredential_ParallelC
{
for (int i = 0; i < 10; i++)
{
tasks.Add(Task.Run(async () => await credential.GetTokenAsync(new TokenRequestContext(new[] {"https://vault.azure.net/.default"}), CancellationToken.None)));
tasks.Add(Task.Run(async () => await credential.GetTokenAsync(new TokenRequestContext(new[] {TestEnvironment.KeyvaultScope}), CancellationToken.None)));
}

await Task.WhenAll(tasks);
Expand Down Expand Up @@ -153,7 +155,7 @@ public async Task DefaultAzureCredential_UseAzureCliCredential()

using (ClientDiagnosticListener diagnosticListener = new ClientDiagnosticListener(s => s.StartsWith("Azure.Identity")))
{
token = await credential.GetTokenAsync(new TokenRequestContext(new[] {"https://vault.azure.net/.default"}), CancellationToken.None);
token = await credential.GetTokenAsync(new TokenRequestContext(new[] {TestEnvironment.KeyvaultScope}), CancellationToken.None);
scopes = diagnosticListener.Scopes;
}

Expand Down Expand Up @@ -187,7 +189,7 @@ public async Task DefaultAzureCredential_UseAzureCliCredential_ParallelCalls()
var tasks = new List<Task<AccessToken>>();
for (int i = 0; i < 10; i++)
{
tasks.Add(Task.Run(async () => await credential.GetTokenAsync(new TokenRequestContext(new[] {"https://vault.azure.net/.default"}), CancellationToken.None)));
tasks.Add(Task.Run(async () => await credential.GetTokenAsync(new TokenRequestContext(new[] {TestEnvironment.KeyvaultScope}), CancellationToken.None)));
}

await Task.WhenAll(tasks);
Expand Down Expand Up @@ -218,7 +220,7 @@ public void DefaultAzureCredential_AllCredentialsHaveFailed_CredentialUnavailabl

using (ClientDiagnosticListener diagnosticListener = new ClientDiagnosticListener(s => s.StartsWith("Azure.Identity")))
{
Assert.CatchAsync<CredentialUnavailableException>(async () => await credential.GetTokenAsync(new TokenRequestContext(new[] {"https://vault.azure.net/.default"}), CancellationToken.None));
Assert.CatchAsync<CredentialUnavailableException>(async () => await credential.GetTokenAsync(new TokenRequestContext(new[] {TestEnvironment.KeyvaultScope}), CancellationToken.None));
scopes = diagnosticListener.Scopes;
}

Expand Down Expand Up @@ -275,7 +277,7 @@ public void DefaultAzureCredential_AllCredentialsHaveFailed_LastAuthenticationFa

using (ClientDiagnosticListener diagnosticListener = new ClientDiagnosticListener(s => s.StartsWith("Azure.Identity")))
{
Assert.CatchAsync<AuthenticationFailedException>(async () => await credential.GetTokenAsync(new TokenRequestContext(new[] {"https://vault.azure.net/.default"}), CancellationToken.None));
Assert.CatchAsync<AuthenticationFailedException>(async () => await credential.GetTokenAsync(new TokenRequestContext(new[] {TestEnvironment.KeyvaultScope}), CancellationToken.None));
scopes = diagnosticListener.Scopes;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ public async Task AuthenticateWithDeviceCodeMockVerifyCallbackCancellationAsync(
[Test]
public void AuthenticateWithDeviceCodeCallbackThrowsAsync()
{
IdentityTestEnvironment testEnvironment = new IdentityTestEnvironment();
var expectedCode = Guid.NewGuid().ToString();

var expectedToken = Guid.NewGuid().ToString();
Expand All @@ -188,14 +189,15 @@ public void AuthenticateWithDeviceCodeCallbackThrowsAsync()

var cred = InstrumentClient(new DeviceCodeCredential(ThrowingDeviceCodeCallback, ClientId, options: options));

var ex = Assert.ThrowsAsync<AuthenticationFailedException>(async () => await cred.GetTokenAsync(new TokenRequestContext(new string[] { "https://vault.azure.net/.default" }), cancelSource.Token));
var ex = Assert.ThrowsAsync<AuthenticationFailedException>(async () => await cred.GetTokenAsync(new TokenRequestContext(new string[] { testEnvironment.KeyvaultScope }), cancelSource.Token));

Assert.IsInstanceOf(typeof(MockException), ex.InnerException);
}

[Test]
public void DisableAutomaticAuthenticationException()
{
IdentityTestEnvironment testEnvironment = new IdentityTestEnvironment();
var expectedCode = Guid.NewGuid().ToString();

var cred = InstrumentClient(new DeviceCodeCredential(new DeviceCodeCredentialOptions { DisableAutomaticAuthentication = true, DeviceCodeCallback = (code, cancelToken) => VerifyDeviceCode(code, expectedCode) }));
Expand All @@ -209,14 +211,15 @@ public void DisableAutomaticAuthenticationException()

private MockResponse ProcessMockRequest(MockRequest mockRequest, string code, string token)
{
IdentityTestEnvironment testEnvironment = new IdentityTestEnvironment();
string requestUrl = mockRequest.Uri.ToUri().AbsoluteUri;

if (requestUrl.StartsWith("https://login.microsoftonline.com/common/discovery/instance"))
if (requestUrl.StartsWith(new Uri(new Uri(testEnvironment.AuthorityHostUrl), "common/discovery/instance").ToString()))
{
return DiscoveryInstanceResponse;
}

if (requestUrl.StartsWith("https://login.microsoftonline.com/organizations/v2.0/.well-known/openid-configuration"))
if (requestUrl.StartsWith(new Uri(new Uri(testEnvironment.AuthorityHostUrl), "organizations/v2.0/.well-known/openid-configuration").ToString()))
{
return OpenIdConfigurationResponse;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class IdentityTestEnvironment : TestEnvironment

public string TestPassword => GetOptionalVariable("AZURE_IDENTITY_TEST_PASSWORD") ?? "SANITIZED";
public string TestTenantId => GetRecordedOptionalVariable("TENANT_ID") ?? GetRecordedVariable("AZURE_IDENTITY_TEST_TENANTID");
public string KeyvaultScope => GetRecordedOptionalVariable("AZURE_KEYVAULT_SCOPE") ?? "SANITIZED";

public string ServicePrincipalClientId => GetRecordedVariable("IDENTITY_SP_CLIENT_ID");
public string ServicePrincipalTenantId => GetRecordedVariable("IDENTITY_SP_TENANT_ID");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public async Task GetToken()

var cred = InstrumentClient(new UsernamePasswordCredential(username, password, tenantId, ClientId, options));

AccessToken token = await cred.GetTokenAsync(new TokenRequestContext(new string[] { "https://vault.azure.net/.default" }));
AccessToken token = await cred.GetTokenAsync(new TokenRequestContext(new string[] { TestEnvironment.KeyvaultScope }));

Assert.IsNotNull(token.Token);
}
Expand Down Expand Up @@ -107,7 +107,7 @@ public async Task AuthenticateWithContext()

var cred = InstrumentClient(new UsernamePasswordCredential(username, password, tenantId, ClientId, options));

AuthenticationRecord record = await cred.AuthenticateAsync(new TokenRequestContext(new[] { "https://vault.azure.net/.default" }));
AuthenticationRecord record = await cred.AuthenticateAsync(new TokenRequestContext(new[] { TestEnvironment.KeyvaultScope }));

Assert.IsNotNull(record);

Expand Down
Loading