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

🪟 [4/n] Null Accounts: Update IWA to use CachedAuth #279

Merged
merged 5 commits into from
Apr 26, 2023
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
100 changes: 35 additions & 65 deletions src/MSALWrapper.Test/AuthFlow/IntegratedWindowsAuthenticationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ namespace Microsoft.Authentication.MSALWrapper.Test
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

using FluentAssertions;

using Microsoft.Authentication.MSALWrapper;
using Microsoft.Authentication.MSALWrapper.AuthFlow;
using Microsoft.Authentication.TestHelper;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Identity.Client;
using Microsoft.IdentityModel.JsonWebTokens;

using Moq;
using NLog.Extensions.Logging;
using NLog.Targets;

using NUnit.Framework;

public class IntegratedWindowsAuthenticationTest
Expand All @@ -32,7 +33,6 @@ public class IntegratedWindowsAuthenticationTest
private static readonly Guid ClientId = new Guid("5af6def2-05ec-4cab-b9aa-323d75b5df40");
private static readonly Guid TenantId = new Guid("8254f6f7-a09f-4752-8bd6-391adc3b912e");

private MemoryTarget logTarget;
private ILogger logger;

// MSAL Specific Mocks
Expand All @@ -44,18 +44,24 @@ public class IntegratedWindowsAuthenticationTest
[SetUp]
public void Setup()
{
(this.logger, this.logTarget) = MemoryLogger.Create();
(this.logger, _) = MemoryLogger.Create();

// MSAL Mocks
this.testAccount = new Mock<IAccount>(MockBehavior.Strict);
this.testAccount.Setup(a => a.Username).Returns(TestUser);

this.pcaWrapperMock = new Mock<IPCAWrapper>(MockBehavior.Strict);

// Mock successful token result
this.tokenResult = new TokenResult(new JsonWebToken(TokenResultTest.FakeToken), Guid.NewGuid());
}

[TearDown]
public void Teardown()
{
this.pcaWrapperMock.VerifyAll();
this.testAccount.VerifyAll();
}

public AuthFlow.IntegratedWindowsAuthentication Subject() => new AuthFlow.IntegratedWindowsAuthentication(this.logger, ClientId, TenantId, this.scopes, pcaWrapper: this.pcaWrapperMock.Object);

[Test]
Expand All @@ -69,7 +75,6 @@ public async Task CachedAuthSuccess()
var authFlowResult = await iwa.GetTokenAsync();

// Assert
this.pcaWrapperMock.VerifyAll();
authFlowResult.TokenResult.Should().Be(this.tokenResult);
authFlowResult.TokenResult.IsSilent.Should().BeTrue();
authFlowResult.Errors.Should().BeEmpty();
Expand All @@ -81,36 +86,34 @@ public async Task GetCachedToken_ReturnsNull()
{
this.MockAccount();
this.CachedAuthReturnsNull();
this.IWAReturnsResult();

// Act
AuthFlow.IntegratedWindowsAuthentication iwa = this.Subject();
var authFlowResult = await iwa.GetTokenAsync();

// Assert
this.pcaWrapperMock.VerifyAll();
authFlowResult.TokenResult.Should().Be(null);
authFlowResult.Errors.Should().HaveCount(1);
authFlowResult.TokenResult.Should().Be(this.tokenResult);
authFlowResult.TokenResult.IsSilent.Should().BeTrue();
authFlowResult.Errors.Should().BeEmpty();
authFlowResult.AuthFlowName.Should().Be("iwa");
}

[Test]
public void General_Exceptions_Are_ReThrown()
{
var message = "Something somwhere has gone terribly wrong!";
this.MockAccount();
this.pcaWrapperMock
.Setup((pca) => pca.GetTokenSilentAsync(this.scopes, this.testAccount.Object, It.IsAny<CancellationToken>()))
.Throws(new Exception(message));

this.MockAccount();

// Act
AuthFlow.IntegratedWindowsAuthentication iwa = this.Subject();
Func<Task> subject = async () => await iwa.GetTokenAsync();

// Assert
subject.Should().ThrowExactlyAsync<Exception>().WithMessage(message);

this.pcaWrapperMock.VerifyAll();
}

[Test]
Expand All @@ -124,7 +127,6 @@ public async Task CachedAuth_Throws_ServiceException()
var authFlowResult = await iwa.GetTokenAsync();

// Assert
this.pcaWrapperMock.VerifyAll();
authFlowResult.TokenResult.Should().Be(null);
authFlowResult.Errors.Should().HaveCount(1);
authFlowResult.Errors[0].Should().BeOfType(typeof(MsalServiceException));
Expand All @@ -136,18 +138,17 @@ public async Task GetTokenSilent_OperationCanceledException()
{
this.MockAccount();
this.CachedAuthTimeout();
this.IWAReturnsResult();

// Act
AuthFlow.IntegratedWindowsAuthentication iwa = this.Subject();
var authFlowResult = await iwa.GetTokenAsync();

// Assert
this.pcaWrapperMock.VerifyAll();
authFlowResult.TokenResult.Should().Be(null);
authFlowResult.Errors.Should().HaveCount(2);
authFlowResult.TokenResult.Should().Be(this.tokenResult);
authFlowResult.Errors.Should().HaveCount(1);
authFlowResult.Errors[0].Should().BeOfType(typeof(AuthenticationTimeoutException));
authFlowResult.Errors[0].Message.Should().Be("Get Token Silent timed out after 00:00:15");
authFlowResult.Errors[1].Should().BeOfType(typeof(NullTokenResultException));
authFlowResult.Errors[0].Message.Should().Be("Get Token Silent timed out after 00:00:30");
authFlowResult.AuthFlowName.Should().Be("iwa");
}

Expand All @@ -162,7 +163,6 @@ public async Task GetTokenSilent_MsalClientException()
var authFlowResult = await iwa.GetTokenAsync();

// Assert
this.pcaWrapperMock.VerifyAll();
authFlowResult.TokenResult.Should().Be(null);
authFlowResult.Errors.Should().HaveCount(1);
authFlowResult.Errors[0].Should().BeOfType(typeof(MsalClientException));
Expand All @@ -180,7 +180,6 @@ public async Task GetTokenSilent_NullReferenceException()
var authFlowResult = await iwa.GetTokenAsync();

// Assert
this.pcaWrapperMock.VerifyAll();
authFlowResult.TokenResult.Should().Be(null);
authFlowResult.Errors.Should().HaveCount(1);
authFlowResult.Errors[0].Should().BeOfType(typeof(NullReferenceException));
Expand All @@ -191,118 +190,102 @@ public async Task GetTokenSilent_NullReferenceException()
public async Task NoCachedAccounts_IWASuccess()
{
this.MockAccountReturnsNull();
this.CachedAuthUIRequiredNoAccount();
this.IWAReturnsResult();

// Act
AuthFlow.IntegratedWindowsAuthentication iwa = this.Subject();
var authFlowResult = await iwa.GetTokenAsync();

// Assert
this.pcaWrapperMock.VerifyAll();
authFlowResult.TokenResult.Should().Be(this.tokenResult);
authFlowResult.TokenResult.IsSilent.Should().BeTrue();
authFlowResult.Errors.Should().HaveCount(1);
authFlowResult.Errors.Should().BeEmpty();
authFlowResult.AuthFlowName.Should().Be("iwa");
}

[Test]
public async Task GetTokenIWA_ReturnsNull()
{
this.MockAccountReturnsNull();
this.CachedAuthUIRequired();
this.IWAReturnsNull();

// Act
AuthFlow.IntegratedWindowsAuthentication iwa = this.Subject();
var authFlowResult = await iwa.GetTokenAsync();

// Assert
this.pcaWrapperMock.VerifyAll();
authFlowResult.TokenResult.Should().Be(null);
authFlowResult.Errors.Should().HaveCount(1);
authFlowResult.Errors[0].Should().BeOfType(typeof(MsalUiRequiredException));
authFlowResult.Errors.Should().BeEmpty();
authFlowResult.AuthFlowName.Should().Be("iwa");
}

[Test]
public async Task GetTokenIWA_MsalUIRequired_2FA()
{
this.MockAccountReturnsNull();
this.CachedAuthUIRequired();
this.IWAUIRequiredFor2FA();

// Act
AuthFlow.IntegratedWindowsAuthentication iwa = this.Subject();
var authFlowResult = await iwa.GetTokenAsync();

this.pcaWrapperMock.VerifyAll();
// Assert
authFlowResult.TokenResult.Should().Be(null);
authFlowResult.Errors.Should().HaveCount(2);
authFlowResult.Errors.Should().HaveCount(1);
authFlowResult.Errors[0].Should().BeOfType(typeof(MsalUiRequiredException));
authFlowResult.Errors[1].Should().BeOfType(typeof(MsalUiRequiredException));
authFlowResult.Errors[1].Message.Should().Be("AADSTS50076 MSAL UI Required Exception!");
authFlowResult.Errors[0].Message.Should().Be("AADSTS50076 MSAL UI Required Exception!");
authFlowResult.AuthFlowName.Should().Be("iwa");
}

[Test]
public async Task GetTokenIWA_GenericMsalUIRequired()
{
this.MockAccountReturnsNull();
this.CachedAuthUIRequired();
this.IWAGenericUIRequiredException();

// Act
AuthFlow.IntegratedWindowsAuthentication iwa = this.Subject();
var authFlowResult = await iwa.GetTokenAsync();

this.pcaWrapperMock.VerifyAll();
// Assert
authFlowResult.TokenResult.Should().Be(null);
authFlowResult.Errors.Should().HaveCount(2);
authFlowResult.Errors.Should().HaveCount(1);
authFlowResult.Errors[0].Should().BeOfType(typeof(MsalUiRequiredException));
authFlowResult.Errors[1].Should().BeOfType(typeof(MsalUiRequiredException));
authFlowResult.Errors[1].Message.Should().Be("MSAL UI Required Exception!");
authFlowResult.Errors[0].Message.Should().Be("MSAL UI Required Exception!");
authFlowResult.AuthFlowName.Should().Be("iwa");
}

[Test]
public async Task GetTokenIWA_MsalServiceException()
{
this.MockAccountReturnsNull();
this.CachedAuthUIRequired();
this.IWAServiceException();

// Act
AuthFlow.IntegratedWindowsAuthentication iwa = this.Subject();
var authFlowResult = await iwa.GetTokenAsync();

// Assert - this method should not throw for known types of excpeptions, instead return null, so
// our caller can retry auth another way.
this.pcaWrapperMock.VerifyAll();
// Assert
authFlowResult.TokenResult.Should().Be(null);
authFlowResult.Errors.Should().HaveCount(2);
authFlowResult.Errors[0].Should().BeOfType(typeof(MsalUiRequiredException));
authFlowResult.Errors[1].Should().BeOfType(typeof(MsalServiceException));
authFlowResult.Errors.Should().HaveCount(1);
authFlowResult.Errors[0].Should().BeOfType(typeof(MsalServiceException));
authFlowResult.AuthFlowName.Should().Be("iwa");
}

[Test]
public async Task GetTokenIWA_MsalClientException()
{
this.MockAccountReturnsNull();
this.CachedAuthUIRequired();
this.IWAClientException();

// Act
AuthFlow.IntegratedWindowsAuthentication iwa = this.Subject();
var authFlowResult = await iwa.GetTokenAsync();

// Assert
this.pcaWrapperMock.VerifyAll();
authFlowResult.TokenResult.Should().Be(null);
authFlowResult.Errors.Should().HaveCount(2);
authFlowResult.Errors[0].Should().BeOfType(typeof(MsalUiRequiredException));
authFlowResult.Errors[1].Should().BeOfType(typeof(MsalClientException));
authFlowResult.Errors.Should().HaveCount(1);
authFlowResult.Errors[0].Should().BeOfType(typeof(MsalClientException));
authFlowResult.AuthFlowName.Should().Be("iwa");
}

Expand All @@ -320,13 +303,6 @@ private void CachedAuthReturnsNull()
.ReturnsAsync((TokenResult)null);
}

private void CachedAuthUIRequired()
{
this.pcaWrapperMock
.Setup((pca) => pca.GetTokenSilentAsync(this.scopes, null, It.IsAny<CancellationToken>()))
.Throws(new MsalUiRequiredException("1", "UI is required"));
}

private void CachedAuthServiceException()
{
this.pcaWrapperMock
Expand Down Expand Up @@ -369,13 +345,6 @@ private void IWAReturnsNull()
.ReturnsAsync((TokenResult)null);
}

private void CachedAuthUIRequiredNoAccount()
{
this.pcaWrapperMock
.Setup((pca) => pca.GetTokenSilentAsync(this.scopes, null, It.IsAny<CancellationToken>()))
.Throws(new MsalUiRequiredException("1", "No account hint given!"));
}

private void IWAUIRequiredFor2FA()
{
this.pcaWrapperMock
Expand Down Expand Up @@ -406,6 +375,7 @@ private void IWAClientException()

private void MockAccount()
{
this.testAccount.Setup(a => a.Username).Returns(TestUser);
this.pcaWrapperMock
.Setup(pca => pca.TryToGetCachedAccountAsync(It.IsAny<string>()))
.ReturnsAsync(this.testAccount.Object);
Expand Down
Loading