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

AAD: Handling Azure.Core.TokenCredential #2191

Merged
merged 64 commits into from
May 27, 2021
Merged
Show file tree
Hide file tree
Changes from 52 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
84eba5c
getting started. defining classes and tests
TimothyMothra Mar 11, 2021
180c039
more tests. currently passing
TimothyMothra Mar 12, 2021
d501eef
cleanup
TimothyMothra Mar 12, 2021
5a556d3
saving work in progress
TimothyMothra Mar 23, 2021
2f7f7f8
cleanup
TimothyMothra Mar 24, 2021
9beac17
cleanup
TimothyMothra Mar 24, 2021
14b65b2
cleanup
TimothyMothra Mar 24, 2021
8446075
save work in progress. all tests passing
TimothyMothra Mar 24, 2021
0fe4b8c
cleanup
TimothyMothra Mar 24, 2021
52785bb
change interface to abstract class.
TimothyMothra Mar 25, 2021
acb3fd0
cleanup
TimothyMothra Mar 25, 2021
66592c9
working reflection for GetTokenAsync
TimothyMothra Mar 25, 2021
33570ec
cleanup. tests pass
TimothyMothra Mar 25, 2021
f181df5
cleanup
TimothyMothra Mar 26, 2021
7b30407
rewriting reflection to fully use Expression.Lambda. tests partially …
TimothyMothra Mar 27, 2021
4e38ac2
cleanup
TimothyMothra Mar 29, 2021
862d3f2
change from Lambda<Func> to LambdaExpression. Tests pass
TimothyMothra Mar 29, 2021
ddcbecd
have a working example of aysnc + Expression tree. need to cleanup
TimothyMothra Mar 30, 2021
0a82f7b
this works. tests pass. needs significant cleanup.
TimothyMothra Mar 30, 2021
47ce7e5
significant refactor. cleanup. all tests pass
TimothyMothra Mar 30, 2021
76fd2d7
update scope
TimothyMothra Mar 31, 2021
c5e44de
save change to publicapi doc
TimothyMothra Mar 31, 2021
46f35e6
cleanup
TimothyMothra Mar 31, 2021
2464125
set default in abstract class
TimothyMothra Apr 5, 2021
8a93434
Merge branch 'develop' into tilee/feature_aad
TimothyMothra Apr 14, 2021
159bbc9
update publicapi
TimothyMothra Apr 14, 2021
f03f03f
Merge branch 'develop' into tilee/feature_aad
TimothyMothra Apr 15, 2021
740c1d0
merge develop
TimothyMothra Apr 28, 2021
003873b
Merge branch 'develop' into tilee/feature_aad
TimothyMothra May 7, 2021
1ff482a
fix dependencies
TimothyMothra May 7, 2021
87876f2
fix dependencies
TimothyMothra May 7, 2021
930ef53
Merge branch 'develop' into tilee/feature_aad
TimothyMothra May 20, 2021
c9735a9
add new project
TimothyMothra May 20, 2021
b0b4b7e
add .Net v5 to linux build definition
TimothyMothra May 20, 2021
ca89417
cleanup
TimothyMothra May 20, 2021
5a4d63e
testing change to linux definition
TimothyMothra May 20, 2021
e4050ec
add support for net5.0 to Microsoft.ApplicationInsights.Tests.csproj
TimothyMothra May 20, 2021
5773479
fix for TimeSpan cannot be null
TimothyMothra May 20, 2021
926a6e7
fix
TimothyMothra May 20, 2021
0412341
remove extra test project
TimothyMothra May 20, 2021
0bcd87f
cleanup yml
TimothyMothra May 20, 2021
57088cb
disabling netcoreapp 2.1 in linux build.
TimothyMothra May 20, 2021
bbecdd8
Merge branch 'tilee/aad_newtestproject' into tilee/feature_aad
TimothyMothra May 20, 2021
a7c3462
migrate AAD tests to Base Test project
TimothyMothra May 21, 2021
5d6011a
update Endpoints for Ingestion
TimothyMothra May 21, 2021
edb4e57
merge develop
TimothyMothra May 21, 2021
d4b0378
moving tests to Base Test project
TimothyMothra May 21, 2021
a82e321
remove Authentication.Test project
TimothyMothra May 21, 2021
393f0a2
remove change to AssemblyInfo
TimothyMothra May 21, 2021
0bf32ba
resolving merge conflict
TimothyMothra May 21, 2021
5e3ef5d
Revert "resolving merge conflict"
TimothyMothra May 24, 2021
dbe07d0
Merge branch 'develop' into tilee/feature_aad
TimothyMothra May 24, 2021
dc11249
Merge branch 'develop' into tilee/feature_aad
TimothyMothra May 26, 2021
7d6ad67
remove Azure.Core dependency
TimothyMothra May 26, 2021
2f3b668
cleanup csproj
TimothyMothra May 26, 2021
4b9b761
cleanup EOF
TimothyMothra May 26, 2021
4cf03ca
cleanup test
TimothyMothra May 26, 2021
62bbe38
cleanup. removing abstract class CredentialEnvelope
TimothyMothra May 26, 2021
aac78ed
fxcop
TimothyMothra May 26, 2021
ad1f387
revert changes to EndpointContainer
TimothyMothra May 26, 2021
7bfe41e
add interface ICredentialEnvelope
TimothyMothra May 26, 2021
6b00f3b
exception handling
TimothyMothra May 26, 2021
957f33f
set ConfigureAwait(true)
TimothyMothra May 26, 2021
d9da395
code review comments
TimothyMothra May 27, 2021
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
@@ -1,3 +1,11 @@
Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope
Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.CredentialEnvelope() -> void
Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.CredentialEnvelope.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope
Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.SetCredential(object tokenCredential) -> void
abstract Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.Credential.get -> object
abstract Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.GetToken(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> string
abstract Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.GetTokenAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<string>
static Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.GetScopes() -> string[]
Microsoft.ApplicationInsights.Channel.IAsyncFlushable
Microsoft.ApplicationInsights.Channel.IAsyncFlushable.FlushAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<bool>
Microsoft.ApplicationInsights.Channel.InMemoryChannel.FlushAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<bool>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope
Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.CredentialEnvelope() -> void
Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.CredentialEnvelope.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope
Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.SetCredential(object tokenCredential) -> void
abstract Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.Credential.get -> object
abstract Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.GetToken(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> string
abstract Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.GetTokenAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<string>
static Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.GetScopes() -> string[]
Microsoft.ApplicationInsights.Channel.IAsyncFlushable
Microsoft.ApplicationInsights.Channel.IAsyncFlushable.FlushAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<bool>
Microsoft.ApplicationInsights.Channel.InMemoryChannel.FlushAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<bool>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope
Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.CredentialEnvelope() -> void
Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.CredentialEnvelope.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope
Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.SetCredential(Azure.Core.TokenCredential tokenCredential) -> void
abstract Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.Credential.get -> object
abstract Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.GetToken(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> string
abstract Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.GetTokenAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<string>
static Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.CredentialEnvelope.GetScopes() -> string[]
Microsoft.ApplicationInsights.Channel.IAsyncFlushable
Microsoft.ApplicationInsights.Channel.IAsyncFlushable.FlushAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<bool>
Microsoft.ApplicationInsights.Channel.InMemoryChannel.FlushAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<bool>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
namespace Microsoft.ApplicationInsights.TestFramework.Extensibility.Implementation.Authentication
{
using System;
using System.Threading.Tasks;

using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication;
using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
[TestCategory("AAD")]
public class CredentialEnvelopeTests
{
/// <summary>
/// This tests verifies that each supported language can create and set a Credential.
/// </summary>
[TestMethod]
public void VerifyCanSetCredential()
{
#if NET452 || NET46
// *THIS IS COMPLICATED*
// In this case, the test runner is NET452 or NET46.
// The Azure.Core.TokenCredential is NOT SUPPORTED in these frameworks, so we cannot run this test.
// This does not affect the end user because we REQUIRE the end user to create their own instance of TokenCredential.
// This ensures that the end user is consuming the AI SDK in one of the newer frameworks.
#elif NET461
var mockCredential = new MockCredential();

var telemetryConfiguration = new TelemetryConfiguration();
telemetryConfiguration.SetCredential(mockCredential);

Assert.IsInstanceOfType(telemetryConfiguration.CredentialEnvelope, typeof(ReflectionCredentialEnvelope));
Assert.AreEqual(mockCredential, telemetryConfiguration.CredentialEnvelope.Credential);
#elif NETCOREAPP2_1 || NETCOREAPP3_1 || NET5_0

var mockCredential = new MockCredential();

var telemetryConfiguration = new TelemetryConfiguration();
telemetryConfiguration.SetCredential(mockCredential);

Assert.IsInstanceOfType(telemetryConfiguration.CredentialEnvelope, typeof(TokenCredentialEnvelope));
Assert.AreEqual(mockCredential, telemetryConfiguration.CredentialEnvelope.Credential);
#else
throw new NotImplementedException("this is a testing gap");
#endif
}

#if NET461
/// <summary>
/// For older frameworks, TelemetryConfiguration accepts an <see cref="Object"/> parameter.
/// This method will use reflection to verify the type at runtime.
/// This test is to verify that we cannot set invalid types.
/// </summary>
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void VerifyCannotSetInvalidObjectOnTelemetryConfiguration()
{
var telemetryConfiguration = new TelemetryConfiguration();
telemetryConfiguration.SetCredential(Guid.Empty);
}
#endif

#if NETCOREAPP2_1 || NETCOREAPP3_1 || NET5_0
/// <summary>
/// This test verifies that both <see cref="TokenCredentialEnvelope"/> and <see cref="ReflectionCredentialEnvelope"/> return identical tokens.
/// This test can only run in frameworks that support both types.
/// </summary>
[TestMethod]
public void VerifyCanGetTokenString()
{
var mockCredential = new MockCredential();

var tokenCredentialEnvelope = new TokenCredentialEnvelope(mockCredential);
var token = tokenCredentialEnvelope.GetToken();
Assert.IsNotNull(token);

var reflectionCredentialEnvelope = new ReflectionCredentialEnvelope(mockCredential);
var tokenFromReflection = reflectionCredentialEnvelope.GetToken();
Assert.IsNotNull(tokenFromReflection);

Assert.AreEqual(token, tokenFromReflection);
}

/// <summary>
/// This test verifies that both <see cref="TokenCredentialEnvelope"/> and <see cref="ReflectionCredentialEnvelope"/> return identical tokens.
/// This test can only run in frameworks that support both types.
/// </summary>
[TestMethod]
public async Task VerifyCanGetTokenStringAsync()
{
var mockCredential = new MockCredential();

var tokenCredentialEnvelope = new TokenCredentialEnvelope(mockCredential);
var token = await tokenCredentialEnvelope.GetTokenAsync();
Assert.IsNotNull(token);

var reflectionCredentialEnvelope = new ReflectionCredentialEnvelope(mockCredential);
var tokenFromReflection = await reflectionCredentialEnvelope.GetTokenAsync();
Assert.IsNotNull(tokenFromReflection);

Assert.AreEqual(token, tokenFromReflection);
}
#endif
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#if NET461 || NETCOREAPP2_1 || NETCOREAPP3_1 || NET5_0
namespace Microsoft.ApplicationInsights.TestFramework.Extensibility.Implementation.Authentication
{
using System;
using System.Threading;
using System.Threading.Tasks;

using Azure.Core;


/// <remarks>
/// Copied from (https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/core/Azure.Core.TestFramework/src/MockCredential.cs).
/// </remarks>
public class MockCredential : TokenCredential
{
public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
return new ValueTask<AccessToken>(GetToken(requestContext, cancellationToken));
}

public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
return new AccessToken("TEST TOKEN " + string.Join(" ", requestContext.Scopes), DateTimeOffset.MaxValue);
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#if NET461 || NETCOREAPP2_1 || NETCOREAPP3_1 || NET5_0
namespace Microsoft.ApplicationInsights.TestFramework.Extensibility.Implementation.Authentication
{
using System;
using System.Threading;
using System.Threading.Tasks;

using Azure.Core;

using Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication;
using Microsoft.VisualStudio.TestTools.UnitTesting;

/// <summary>
/// The <see cref="ReflectionCredentialEnvelope"/> cannot take a dependency on <see cref="Azure.Core.TokenCredential"/>.
/// We must use reflection to interact with this class.
/// These tests are to confirm that we can correctly identity classes that implement TokenCredential and address it's methods.
/// </summary>
[TestClass]
[TestCategory("AAD")]
public class ReflectionCredentialEnvelopeTests
{
[TestMethod]
public void VerifyCanIdentifyValidClass()
{
var testClass2 = new TestClass2();
_ = new ReflectionCredentialEnvelope(testClass2);
TimothyMothra marked this conversation as resolved.
Show resolved Hide resolved
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void VerifyCanIdentityInvalidClass()
{
var notTokenCredential2 = new NotTokenCredential2();
_ = new ReflectionCredentialEnvelope(notTokenCredential2);
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void VerifyCannotSetInvalidType()
{
_ = new ReflectionCredentialEnvelope(Guid.Empty);
}

//[TestMethod]
//public void VerifyGetTokenAsExpression_UsingCompileTimeTypes()
//{
// var mockCredential = new MockCredential();
// var requestContext = new TokenRequestContext(new string[] { "test/scope" });

// var expression = ReflectionCredentialEnvelope.GetTokenAsExpression(mockCredential, requestContext).Compile();

// var testResult = expression(mockCredential, requestContext, CancellationToken.None);
// Assert.AreEqual("TEST TOKEN test/scope", testResult);
//}

///// <summary>
///// This more closely represents how this would be used in a production environment.
///// </summary>
//[TestMethod]
//public void VerifyGetTokenAsExpression_UsingDynamicTypes()
//{
// // This currently throws ArgumentExceptions:
// // ParameterExpression of type 'Microsoft.ApplicationInsights.Authentication.Tests.MockCredential' cannot be used for delegate parameter of type 'System.Object'
// // ParameterExpression of type 'Azure.Core.TokenRequestContext' cannot be used for delegate parameter of type 'System.Object'


// var mockCredential = (object)new MockCredential();
// var requestContext = ReflectionCredentialEnvelope.MakeTokenRequestContext(new[] { "test/scope" });

// var expression = ReflectionCredentialEnvelope.GetTokenAsExpression(mockCredential, requestContext).Compile();

// var testResult = expression(mockCredential, requestContext, CancellationToken.None);
// Assert.AreEqual("TEST TOKEN test/scope", testResult);
//}

[TestMethod]
public void VerifyCanMakeTokenRequestContext()
{
var testScope = new string[] { "test/scope" };

var requestContext = new TokenRequestContext(testScope);

var tokenRequestContext = ReflectionCredentialEnvelope.AzureCore.MakeTokenRequestContext(testScope);
Assert.IsInstanceOfType(tokenRequestContext, typeof(TokenRequestContext));
}


[TestMethod]
public void VerifyGetToken_AsLambdaExpression_UsingCompileTimeTypes()
{
var mockCredential = new MockCredential();
var requestContext = new TokenRequestContext(new string[] { "test/scope" });

var testResult = ReflectionCredentialEnvelope.AzureCore.InvokeGetToken(mockCredential, requestContext, CancellationToken.None);

Assert.AreEqual("TEST TOKEN test/scope", testResult);
}

/// <summary>
/// This more closely represents how this would be used in a production environment.
/// </summary>
[TestMethod]
public void VerifyGetToken_AsLambdaExpression_UsingDynamicTypes()
{
var mockCredential = (object)new MockCredential();
var requestContext = ReflectionCredentialEnvelope.AzureCore.MakeTokenRequestContext(new[] { "test/scope" });

var testResult = ReflectionCredentialEnvelope.AzureCore.InvokeGetToken(mockCredential, requestContext, CancellationToken.None);

Assert.AreEqual("TEST TOKEN test/scope", testResult);
}


[TestMethod]
public async Task VerifyGetTokenAsync_AsLambdaExpression_UsingCompileTimeTypes()
{
var mockCredential = new MockCredential();
var requestContext = new TokenRequestContext(new string[] { "test/scope" });

var testResult = await ReflectionCredentialEnvelope.AzureCore.InvokeGetTokenAsync(mockCredential, requestContext, CancellationToken.None);

Assert.AreEqual("TEST TOKEN test/scope", testResult);
}

/// <summary>
/// This more closely represents how this would be used in a production environment.
/// </summary>
[TestMethod]
public async Task VerifyGetTokenAsync_AsLambdaExpression_UsingDynamicTypes()
{
var mockCredential = (object)new MockCredential();
var requestContext = ReflectionCredentialEnvelope.AzureCore.MakeTokenRequestContext(new[] { "test/scope" });

var testResult = await ReflectionCredentialEnvelope.AzureCore.InvokeGetTokenAsync(mockCredential, requestContext, CancellationToken.None);

Assert.AreEqual("TEST TOKEN test/scope", testResult);
}

#region TestClasses
private class TestClass1 : Azure.Core.TokenCredential
{
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}

public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}

private class TestClass2 : TestClass1 { }

private abstract class NotTokenCredential
{
public abstract AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken);

public abstract ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken);
}

private class NotTokenCredential1 : NotTokenCredential
{
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}

public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}

private class NotTokenCredential2 : NotTokenCredential1 { }
#endregion
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
<Reference Include="System.Xml.Linq" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net461' Or '$(TargetFramework)' == 'netcoreapp2.1' Or '$(TargetFramework)' == 'netcoreapp3.1' Or '$(TargetFramework)' == 'net5.0'">
<PackageReference Include="Azure.Identity" Version="1.3.0" /> <!-- Supports: netstandard2.0 -->
</ItemGroup>

<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
Expand Down
Loading