Skip to content

Commit

Permalink
Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
qetza committed Jul 4, 2021
1 parent 10b4ced commit e46bd1b
Show file tree
Hide file tree
Showing 2 changed files with 322 additions and 0 deletions.
117 changes: 117 additions & 0 deletions tests/Microsoft.Identity.Web.Test/HttpClientBuilderExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Net.Http;

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Identity.Web.Test.Common;

using Xunit;

namespace Microsoft.Identity.Web.Test
{
public class HttpClientBuilderExtensionsTests
{
private const string HttpClientName = "test-client";
private const string ServiceName = "test-service";

private readonly IConfigurationSection _configSection;

public HttpClientBuilderExtensionsTests()
{
_configSection = GetConfigSection(ServiceName);
}

private IConfigurationSection GetConfigSection(string key)
{
var builder = new ConfigurationBuilder();
builder.AddInMemoryCollection(
new Dictionary<string, string>()
{
{ $"{key}:Scopes", TestConstants.Scopes },
{ $"{key}:Tenant", TestConstants.TenantIdAsGuid },
{ $"{key}:UserFlow", TestConstants.B2CSignUpSignInUserFlow },
{ $"{key}:IsProofOfPossessionRequest", "false" },
{ $"{key}:AuthenticationScheme", JwtBearerDefaults.AuthenticationScheme },
});

return builder.Build().GetSection(key);
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void AddMicrosoftIdentityAuthenticationHandler_WithConfiguration(bool useApp)
{
// arrange
var services = new ServiceCollection();

// act
if (useApp)
{
services.AddHttpClient(HttpClientName)
.AddMicrosoftIdentityAppAuthenticationHandler(ServiceName, _configSection);
}
else
{
services.AddHttpClient(HttpClientName)
.AddMicrosoftIdentityUserAuthenticationHandler(ServiceName, _configSection);
}

// assert
Assert.Contains(services, s => s.ServiceType == typeof(IConfigureOptions<MicrosoftIdentityAuthenticationMessageHandlerOptions>));

var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptionsSnapshot<MicrosoftIdentityAuthenticationMessageHandlerOptions>>();

Assert.Equal(TestConstants.Scopes, options.Get(ServiceName).Scopes);
Assert.Equal(TestConstants.TenantIdAsGuid, options.Get(ServiceName).Tenant);
Assert.Equal(TestConstants.B2CSignUpSignInUserFlow, options.Get(ServiceName).UserFlow);
Assert.False(options.Get(ServiceName).IsProofOfPossessionRequest);
Assert.Equal(JwtBearerDefaults.AuthenticationScheme, options.Get(ServiceName).AuthenticationScheme);
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void AddMicrosoftIdentityAuthenticationHandler_WithOptions(bool useApp)
{
// arrange
var services = new ServiceCollection();
Action<MicrosoftIdentityAuthenticationMessageHandlerOptions> configureOptions = options =>
{
options.Scopes = TestConstants.GraphScopes;
options.Tenant = TestConstants.TenantIdAsGuid;
options.UserFlow = TestConstants.B2CResetPasswordUserFlow;
options.IsProofOfPossessionRequest = true;
options.AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme;
};

// act
if (useApp)
{
services.AddHttpClient(HttpClientName)
.AddMicrosoftIdentityAppAuthenticationHandler(ServiceName, configureOptions);
}
else
{
services.AddHttpClient(HttpClientName)
.AddMicrosoftIdentityUserAuthenticationHandler(ServiceName, configureOptions);
}

// assert
Assert.Contains(services, s => s.ServiceType == typeof(IConfigureOptions<MicrosoftIdentityAuthenticationMessageHandlerOptions>));

var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptionsSnapshot<MicrosoftIdentityAuthenticationMessageHandlerOptions>>();

Assert.Equal(TestConstants.GraphScopes, options.Get(ServiceName).Scopes);
Assert.Equal(TestConstants.TenantIdAsGuid, options.Get(ServiceName).Tenant);
Assert.Equal(TestConstants.B2CResetPasswordUserFlow, options.Get(ServiceName).UserFlow);
Assert.True(options.Get(ServiceName).IsProofOfPossessionRequest);
Assert.Equal(JwtBearerDefaults.AuthenticationScheme, options.Get(ServiceName).AuthenticationScheme);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Identity.Client;
using Microsoft.Identity.Web.Test.Common;

using NSubstitute;

using Xunit;

namespace Microsoft.Identity.Web.Test
{
public class MicrosoftIdentityAuthenticationMessageHandlerTests
{
private const string HttpClientName = "test-client";

private readonly AuthenticationResult _authenticationResult;
private readonly MockHttpMessageHandler _mockedMessageHandler;
private readonly MicrosoftIdentityAuthenticationMessageHandlerOptions _handlerOptions;
private readonly MicrosoftIdentityOptions _identityOptions;

public MicrosoftIdentityAuthenticationMessageHandlerTests()
{
_authenticationResult = GetAuthenticationResult();
_mockedMessageHandler = new MockHttpMessageHandler();
_handlerOptions = new MicrosoftIdentityAuthenticationMessageHandlerOptions
{
AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme,
IsProofOfPossessionRequest = false,
Scopes = TestConstants.Scopes,
Tenant = TestConstants.TenantIdAsGuid,
TokenAcquisitionOptions = new TokenAcquisitionOptions(),
UserFlow = TestConstants.B2CSignUpSignInUserFlow,
};
_identityOptions = new MicrosoftIdentityOptions();
}

private AuthenticationResult GetAuthenticationResult()
{
return new AuthenticationResult(
"token",
false,
"id",
DateTimeOffset.UtcNow.AddMinutes(1),
DateTimeOffset.UtcNow.AddMinutes(2),
TestConstants.TenantIdAsGuid,
null,
"id",
Enumerable.Empty<string>(),
Guid.NewGuid());
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task MicrosoftIdentityAuthenticationMessageHandler_Adds_AuthorizationHeader(bool useApp)
{
// arrange
var tokenAcquisition = Substitute.For<ITokenAcquisition>();

var options = Substitute.For<IOptionsMonitor<MicrosoftIdentityAuthenticationMessageHandlerOptions>>();
options.CurrentValue.Returns(_handlerOptions);

var services = new ServiceCollection();
var builder = services.AddHttpClient(HttpClientName)
.ConfigurePrimaryHttpMessageHandler(() => _mockedMessageHandler);

if (useApp)
{
tokenAcquisition.GetAuthenticationResultForAppAsync(default, default, default, default)
.ReturnsForAnyArgs(_authenticationResult);

builder.AddHttpMessageHandler(() => new MicrosoftIdentityAppAuthenticationMessageHandler(tokenAcquisition, options));
}
else
{
tokenAcquisition.GetAuthenticationResultForUserAsync(default, default, default, default, default, default)
.ReturnsForAnyArgs(_authenticationResult);

var identityOptions = Substitute.For<IOptionsMonitor<MicrosoftIdentityOptions>>();
identityOptions.Get(string.Empty).Returns(_identityOptions);

builder.AddHttpMessageHandler(() => new MicrosoftIdentityUserAuthenticationMessageHandler(tokenAcquisition, options, identityOptions));
}

var provider = services.BuildServiceProvider();
var factory = provider.GetRequiredService<IHttpClientFactory>();

var client = factory.CreateClient(HttpClientName);
using var request = new HttpRequestMessage(HttpMethod.Get, TestConstants.GraphBaseUrlBeta);

// act
var response = await client.SendAsync(request).ConfigureAwait(false);

// assert
if (useApp)
{
await tokenAcquisition.Received().GetAuthenticationResultForAppAsync(
_handlerOptions.Scopes,
_handlerOptions.AuthenticationScheme,
_handlerOptions.Tenant,
Arg.Any<TokenAcquisitionOptions>() /* options are cloned */)
.ConfigureAwait(false);
}
else
{
await tokenAcquisition.Received().GetAuthenticationResultForUserAsync(
Arg.Is<string[]>(scopes => scopes.SequenceEqual(_handlerOptions.GetScopes())),
authenticationScheme: _handlerOptions.AuthenticationScheme,
tenantId: _handlerOptions.Tenant,
userFlow: _handlerOptions.UserFlow,
tokenAcquisitionOptions: Arg.Any<TokenAcquisitionOptions>() /* options are cloned */)
.ConfigureAwait(false);
}

Assert.True(_mockedMessageHandler.Requests[0].Headers.Contains(Constants.Authorization));
Assert.Equal($"Bearer {_authenticationResult.AccessToken}", _mockedMessageHandler.Requests[0].Headers.GetValues(Constants.Authorization).ElementAt(0));
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task MicrosoftIdentityAuthenticationMessageHandler_Replaces_AuthorizationHeader(bool useApp)
{
// arrange
var tokenAcquisition = Substitute.For<ITokenAcquisition>();

var options = Substitute.For<IOptionsMonitor<MicrosoftIdentityAuthenticationMessageHandlerOptions>>();
options.CurrentValue.Returns(_handlerOptions);

var services = new ServiceCollection();
var builder = services.AddHttpClient(HttpClientName)
.ConfigurePrimaryHttpMessageHandler(() => _mockedMessageHandler);

if (useApp)
{
tokenAcquisition.GetAuthenticationResultForAppAsync(default, default, default, default)
.ReturnsForAnyArgs(_authenticationResult);

builder.AddHttpMessageHandler(() => new MicrosoftIdentityAppAuthenticationMessageHandler(tokenAcquisition, options));
}
else
{
tokenAcquisition.GetAuthenticationResultForUserAsync(default, default, default, default, default, default)
.ReturnsForAnyArgs(_authenticationResult);

var identityOptions = Substitute.For<IOptionsMonitor<MicrosoftIdentityOptions>>();
identityOptions.Get(string.Empty).Returns(_identityOptions);

builder.AddHttpMessageHandler(() => new MicrosoftIdentityUserAuthenticationMessageHandler(tokenAcquisition, options, identityOptions));
}

var provider = services.BuildServiceProvider();
var factory = provider.GetRequiredService<IHttpClientFactory>();

var client = factory.CreateClient(HttpClientName);
using var request = new HttpRequestMessage(HttpMethod.Get, TestConstants.GraphBaseUrlBeta);
request.Headers.Add(Constants.Authorization, "auth");

// act
var response = await client.SendAsync(request).ConfigureAwait(false);

// assert
Assert.True(_mockedMessageHandler.Requests[0].Headers.Contains(Constants.Authorization));
Assert.Equal($"Bearer {_authenticationResult.AccessToken}", _mockedMessageHandler.Requests[0].Headers.GetValues(Constants.Authorization).ElementAt(0));
}

private class MockHttpMessageHandler : HttpMessageHandler
{
private readonly HttpStatusCode _statusCode;
private readonly string _reason;
private readonly HttpContent _content;
private readonly List<HttpRequestMessage> _requests = new List<HttpRequestMessage>();

public IReadOnlyList<HttpRequestMessage> Requests => _requests;

public MockHttpMessageHandler(HttpStatusCode statusCode = HttpStatusCode.OK, HttpContent content = default, string reason = default)
{
_statusCode = statusCode;
_reason = reason;
_content = content;
}

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
_requests.Add(request);

return Task.FromResult(new HttpResponseMessage
{
StatusCode = _statusCode,
ReasonPhrase = _reason,
Content = _content,
});
}
}
}
}

0 comments on commit e46bd1b

Please sign in to comment.