Skip to content

Commit

Permalink
[Identity] Fix SharedTokenCacheCredential default behavior. (#28309)
Browse files Browse the repository at this point in the history
* Fix SharedTokenCacheCredential default behavior

* revert live test

* revert inadvertant regional test update

* adding stcc cache test

* update API spec
  • Loading branch information
schaabs authored Apr 28, 2022
1 parent 57955d8 commit 3d85c0a
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ public InteractiveBrowserCredentialBrokerOptions() { }
public partial class SharedTokenCacheCredentialBrokerOptions : Azure.Identity.SharedTokenCacheCredentialOptions
{
public SharedTokenCacheCredentialBrokerOptions() { }
public SharedTokenCacheCredentialBrokerOptions(Azure.Identity.TokenCachePersistenceOptions tokenCacheOptions) { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ public InteractiveBrowserCredentialBrokerOptions() { }
public partial class SharedTokenCacheCredentialBrokerOptions : Azure.Identity.SharedTokenCacheCredentialOptions
{
public SharedTokenCacheCredentialBrokerOptions() { }
public SharedTokenCacheCredentialBrokerOptions(Azure.Identity.TokenCachePersistenceOptions tokenCacheOptions) { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@ namespace Azure.Identity.BrokeredAuthentication
/// </summary>
public class SharedTokenCacheCredentialBrokerOptions : SharedTokenCacheCredentialOptions, IMsalPublicClientInitializerOptions
{
/// <summary>
/// Initializes a new instance of <see cref="SharedTokenCacheCredentialBrokerOptions"/>.
/// </summary>
public SharedTokenCacheCredentialBrokerOptions()
: this(null)
{ }

/// <summary>
/// Initializes a new instance of <see cref="SharedTokenCacheCredentialBrokerOptions"/>.
/// </summary>
/// <param name="tokenCacheOptions">The <see cref="TokenCachePersistenceOptions"/> that will apply to the token cache used by this credential.</param>
public SharedTokenCacheCredentialBrokerOptions(TokenCachePersistenceOptions tokenCacheOptions)
: base(tokenCacheOptions)
{
}

Action<PublicClientApplicationBuilder> IMsalPublicClientInitializerOptions.BeforeBuildClient => AddBroker;

private void AddBroker(PublicClientApplicationBuilder builder)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using NUnit.Framework;

namespace Azure.Identity.BrokeredAuthentication.Tests
{
public class SharedTokenCacheCredentialBrokerOptionsTests
{
[Test]
public void VerifyTokenCacheOptionsCtorParam()
{
// verify passed in TokenCachePeristenceOptions are honored
var persistenceOptions = new TokenCachePersistenceOptions { Name = "mocktokencachename" };

var credentialOptions = new SharedTokenCacheCredentialBrokerOptions(persistenceOptions);

Assert.AreEqual(persistenceOptions, credentialOptions.TokenCachePersistenceOptions);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public class SharedTokenCacheCredentialOptions : TokenCredentialOptions, ITokenC
{
private string _tenantId;

internal static readonly TokenCachePersistenceOptions s_defaulTokenCachetPersistenceOptions = new TokenCachePersistenceOptions();

/// <summary>
/// The client id of the application registration used to authenticate users in the cache.
/// </summary>
Expand Down Expand Up @@ -59,7 +61,8 @@ public SharedTokenCacheCredentialOptions()
/// <param name="tokenCacheOptions">The <see cref="TokenCachePersistenceOptions"/> that will apply to the token cache used by this credential.</param>
public SharedTokenCacheCredentialOptions(TokenCachePersistenceOptions tokenCacheOptions)
{
TokenCachePersistenceOptions = tokenCacheOptions;
// if no tokenCacheOptions were specified we should use the default shared token cache
TokenCachePersistenceOptions = tokenCacheOptions ?? s_defaulTokenCachetPersistenceOptions;
}
}
}
34 changes: 34 additions & 0 deletions sdk/identity/Azure.Identity/tests/Mock/MockTokenCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Threading.Tasks;

namespace Azure.Identity.Tests.Mock
{
public class MockTokenCache : UnsafeTokenCacheOptions
{
private readonly Func<Task<ReadOnlyMemory<byte>>> _refreshCacheDelegate;
private readonly Func<TokenCacheUpdatedArgs, Task> _cacheUpdatedDelegate;

public MockTokenCache(Func<Task<ReadOnlyMemory<byte>>> refreshDelegate = default, Func<TokenCacheUpdatedArgs, Task> updatedDelegate = default)
{
_refreshCacheDelegate = refreshDelegate;

_cacheUpdatedDelegate = updatedDelegate;
}

protected internal override Task<ReadOnlyMemory<byte>> RefreshCacheAsync()
{
return (_refreshCacheDelegate != null) ? _refreshCacheDelegate() : null;
}

protected internal override async Task TokenCacheUpdatedAsync(TokenCacheUpdatedArgs tokenCacheUpdatedArgs)
{
if (_cacheUpdatedDelegate != null)
{
await _cacheUpdatedDelegate(tokenCacheUpdatedArgs).ConfigureAwait(false);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using NUnit.Framework;

namespace Azure.Identity.Tests
{
public class SharedTokenCacheCredentialOptionsTests
{
[Test]
public void VerifyCachePersistenceOptionsCtorParam()
{
// verify passed in TokenCachePeristenceOptions are honored
var persistenceOptions = new TokenCachePersistenceOptions { Name = "mocktokencachename" };

var credentialOptions = new SharedTokenCacheCredentialOptions(persistenceOptions);

Assert.AreEqual(persistenceOptions, credentialOptions.TokenCachePersistenceOptions);

// verify passing null uses the default token cache persistence settings
credentialOptions = new SharedTokenCacheCredentialOptions(null);

Assert.AreEqual(SharedTokenCacheCredentialOptions.s_defaulTokenCachetPersistenceOptions, credentialOptions.TokenCachePersistenceOptions);

// verify calling the default constructor uses the default token cache persistence settings
credentialOptions = new SharedTokenCacheCredentialOptions();

Assert.AreEqual(SharedTokenCacheCredentialOptions.s_defaulTokenCachetPersistenceOptions, credentialOptions.TokenCachePersistenceOptions);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,25 @@ public void RespectsIsPIILoggingEnabled([Values(true, false)] bool isLoggingPIIE
Assert.AreEqual(isLoggingPIIEnabled, credential.Client.IsPiiLoggingEnabled);
}

[Test]
public void RespectsTokenCachePersistenceOptions()
{
bool cacheDelegateCalled = false;

var cachePersistenceOptions = new MockTokenCache(refreshDelegate: () =>
{
cacheDelegateCalled = true;
return Task.FromResult<ReadOnlyMemory<byte>>(null);
});

var credential = InstrumentClient(new SharedTokenCacheCredential(new SharedTokenCacheCredentialOptions(cachePersistenceOptions)));

Assert.ThrowsAsync<CredentialUnavailableException>(async () => await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));

Assert.IsTrue(cacheDelegateCalled);
}

[Test]
public async Task OneAccountNoTentantNoUsername()
{
Expand Down

0 comments on commit 3d85c0a

Please sign in to comment.