Skip to content

Commit e9453ac

Browse files
authored
[Communication] - BearerTokenAuthenticationPolicy - Create ChatClient with BearerTokenAuthenticationPolicy (Azure#16582)
* [ChatClient] New methods to create pipeline via BearerTokenAuthenticationPolicy * [ChatThreadClient] have the init take in a bearer auth token instead for easier init method * [TokenCredentialStub] Copying the TokenCredentialStub so it can be shared * [ChatClientsTest] Using new ChatClient to test init with bearer authentication * [ChatClientTest] using the new chat client with bearer authentication * [ChatClient] removing new constructor. using user credential to create bearer auth policy * [ChatLiveTestBase] Remove unused using frameworks * [CommunicationTokenCredential] created new token credential to construct bearer auth policy * [CommunicationTokenCredential] Adding missed file, empty the scope in constructor * [ChatThreadClient] Code clean up * [ChatThreadClient] fixing compiler issue with too many parameters * [CommunicationTokenCredential] tiny optimization * [ChatClient] Updating the names as style as per PR feedback * [CommunicationUserAuthenticationPolicy] removing unused policy * [Communication] - CommunicationTokenCredentialTests - Adding new unit tests * [Communication] - CommunicationTokenCredentialTests - Removing unused method and using * [CommunicationTokenCredential] Passing in the cancellation token * [TokenCredentialStub] revert the introduction of credential stub as per pr feedback
1 parent 8d15a74 commit e9453ac

File tree

9 files changed

+176
-50
lines changed

9 files changed

+176
-50
lines changed

sdk/communication/Azure.Communication.Chat/src/Azure.Communication.Chat.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
</ItemGroup>
1919

2020
<ItemGroup>
21-
<Compile Include="..\..\Shared\src\CommunicationUserAuthenticationPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
21+
<Compile Include="..\..\Shared\src\CommunicationTokenCredential.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2222
<Compile Include="$(AzureCoreSharedSources)AzureResourceProviderNamespaceAttribute.cs" Link="Shared\Core\%(RecursiveDir)\%(Filename)%(Extension)" />
2323
<Compile Include="$(AzureCoreSharedSources)Argument.cs" Link="Shared\%(RecursiveDir)\%(Filename)%(Extension)" />
2424
<Compile Include="$(AzureCoreSharedSources)ClientDiagnostics.cs" Link="Shared\%(RecursiveDir)\%(Filename)%(Extension)" />

sdk/communication/Azure.Communication.Chat/src/ChatClient.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,9 @@ public virtual Response DeleteChatThread(string threadId, CancellationToken canc
281281

282282
private static HttpPipeline CreatePipelineFromOptions(ChatClientOptions options, CommunicationUserCredential communicationUserCredential)
283283
{
284-
var httpPipelinePolicy = new CommunicationUserAuthenticationPolicy(communicationUserCredential);
285-
HttpPipeline httpPipeline = HttpPipelineBuilder.Build(options, httpPipelinePolicy);
286-
return httpPipeline;
284+
var tokenCredential = new CommunicationTokenCredential(communicationUserCredential);
285+
var authenticationPolicy = new BearerTokenAuthenticationPolicy(tokenCredential, "");
286+
return HttpPipelineBuilder.Build(options, authenticationPolicy);
287287
}
288288
}
289289
}

sdk/communication/Azure.Communication.Chat/src/ChatThreadClient.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ public virtual async Task<Response> AddMembersAsync(IEnumerable<ChatThreadMember
347347
scope.Start();
348348
try
349349
{
350-
return await _chatRestClient.AddChatThreadMembersAsync(Id, members.Select(x=>x.ToChatThreadMemberInternal()), cancellationToken).ConfigureAwait(false);
350+
return await _chatRestClient.AddChatThreadMembersAsync(Id, members.Select(x => x.ToChatThreadMemberInternal()), cancellationToken).ConfigureAwait(false);
351351
}
352352
catch (Exception ex)
353353
{
@@ -588,9 +588,9 @@ Page<ReadReceipt> FirstPageFunc(int? pageSizeHint)
588588

589589
private static HttpPipeline CreatePipelineFromOptions(ChatClientOptions options, CommunicationUserCredential communicationUserCredential)
590590
{
591-
var httpPipelinePolicy = new CommunicationUserAuthenticationPolicy(communicationUserCredential);
592-
HttpPipeline httpPipeline = HttpPipelineBuilder.Build(options, httpPipelinePolicy);
593-
return httpPipeline;
591+
var tokenCredential = new CommunicationTokenCredential(communicationUserCredential);
592+
var authenticationPolicy = new BearerTokenAuthenticationPolicy(tokenCredential, "");
593+
return HttpPipelineBuilder.Build(options, authenticationPolicy);
594594
}
595595
}
596596
}

sdk/communication/Azure.Communication.Chat/tests/ChatClients/ChatClientsLiveTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public void ThreadCGUD_MemberAUR_MessageGSU_NotificationT()
134134
var expectedPageSize = 2;
135135
var messagesCounterTotal = 0;
136136
var messagesCounter = 0;
137-
foreach (Page<ChatMessage> messagesPage in messagesPaginationTest.AsPages(continuationToken,2))
137+
foreach (Page<ChatMessage> messagesPage in messagesPaginationTest.AsPages(continuationToken, 2))
138138
{
139139
messagesCounter = 0;
140140
foreach (ChatMessage messagePage in messagesPage.Values)

sdk/communication/Azure.Communication.Chat/tests/Infrastructure/ChatLiveTestBase.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using System.Threading.Tasks;
77
using Azure.Communication.Administration;
88
using Azure.Communication.Identity;
9-
using Azure.Communication.Pipeline;
109
using Azure.Core.TestFramework;
1110

1211
namespace Azure.Communication.Chat.Tests

sdk/communication/Azure.Communication.Common/tests/Azure.Communication.Common.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<ItemGroup>
1414
<Compile Include="$(AzureCoreSharedSources)ConnectionString.cs" Link="Shared\%(RecursiveDir)\%(Filename)%(Extension)" />
1515
<Compile Include="..\..\Shared\src\HMACAuthenticationPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
16+
<Compile Include="..\..\Shared\src\CommunicationTokenCredential.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
1617
<ProjectReference Include="$(AzureCoreTestFramework)" />
1718
<ProjectReference Include="..\src\Azure.Communication.Common.csproj" />
1819
</ItemGroup>
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using Azure.Communication.Identity;
7+
using Azure.Core;
8+
using NUnit.Framework;
9+
10+
namespace Azure.Communication.Pipeline
11+
{
12+
public class CommunicationTokenCredentialTests
13+
{
14+
private const string SampleToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjMyNTAzNjgwMDAwfQ.9i7FNNHHJT8cOzo-yrAUJyBSfJ-tPPk2emcHavOEpWc";
15+
private const long SampleTokenExpiry = 32503680000;
16+
private const string ExpiredToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEwMH0.1h_scYkNp-G98-O4cW6KvfJZwiz54uJMyeDACE4nypg";
17+
private static string FetchTokenForUserFromMyServer(string userId, CancellationToken cancellationToken) => SampleToken;
18+
private static ValueTask<string> FetchTokenForUserFromMyServerAsync(string userId, CancellationToken cancellationToken) => new ValueTask<string>(SampleToken);
19+
20+
public TokenRequestContext MockTokenRequestContext()
21+
{
22+
var resource = "the resource value";
23+
return new TokenRequestContext(new[] { resource });
24+
}
25+
26+
[Test]
27+
public async Task CommunicationTokenCredential_CreateStaticToken()
28+
{
29+
var token = ExpiredToken;
30+
31+
using var userCredential = new CommunicationUserCredential(token);
32+
var communicationTokenCredential = new CommunicationTokenCredential(userCredential);
33+
34+
await communicationTokenCredential.GetTokenAsync(MockTokenRequestContext(), CancellationToken.None);
35+
}
36+
37+
[Test]
38+
public async Task CommunicationTokenCredential_CreateRefreshableWithoutInitialToken()
39+
{
40+
var userCredential = new CommunicationUserCredential(
41+
refreshProactively: true, // Indicates if the token should be proactively refreshed in the background or only on-demand
42+
tokenRefresher: cancellationToken => FetchTokenForUserFromMyServer("bob@contoso.com", cancellationToken),
43+
asyncTokenRefresher: cancellationToken => FetchTokenForUserFromMyServerAsync("bob@contoso.com", cancellationToken));
44+
var communicationTokenCredential = new CommunicationTokenCredential(userCredential);
45+
46+
await communicationTokenCredential.GetTokenAsync(MockTokenRequestContext(), CancellationToken.None);
47+
}
48+
49+
[Test]
50+
public async Task CommunicationTokenCredential_CreateRefreshableWithInitialToken()
51+
{
52+
var initialToken = ExpiredToken;
53+
var userCredential = new CommunicationUserCredential(
54+
refreshProactively: true, // Indicates if the token should be proactively refreshed in the background or only on-demand
55+
tokenRefresher: cancellationToken => FetchTokenForUserFromMyServer("bob@contoso.com", cancellationToken),
56+
asyncTokenRefresher: cancellationToken => FetchTokenForUserFromMyServerAsync("bob@contoso.com", cancellationToken),
57+
initialToken);
58+
var communicationTokenCredential = new CommunicationTokenCredential(userCredential);
59+
60+
await communicationTokenCredential.GetTokenAsync(MockTokenRequestContext(), CancellationToken.None);
61+
}
62+
63+
[Test]
64+
public async Task CommunicationTokenCredential_DecodesToken()
65+
{
66+
var initialToken = SampleToken;
67+
var userCredential = new CommunicationUserCredential(initialToken);
68+
var communicationTokenCredential = new CommunicationTokenCredential(userCredential);
69+
70+
var accessToken = await communicationTokenCredential.GetTokenAsync(MockTokenRequestContext(), CancellationToken.None);
71+
72+
Assert.AreEqual(initialToken, accessToken.Token);
73+
Assert.AreEqual(SampleTokenExpiry, accessToken.ExpiresOn.ToUnixTimeSeconds());
74+
}
75+
76+
[Test]
77+
public void CommunicationTokenCredential_StaticTokenReturnsExpiredToken()
78+
{
79+
var userCredential = new CommunicationUserCredential(ExpiredToken);
80+
var communicationTokenCredential = new CommunicationTokenCredential(userCredential);
81+
82+
var accessToken = communicationTokenCredential.GetToken(MockTokenRequestContext(), CancellationToken.None);
83+
Assert.AreEqual(ExpiredToken, accessToken.Token);
84+
}
85+
86+
[Test]
87+
public async Task CommunicationTokenCredential_StaticTokenAsyncReturnsExpiredToken()
88+
{
89+
var userCredential = new CommunicationUserCredential(ExpiredToken);
90+
var communicationTokenCredential = new CommunicationTokenCredential(userCredential);
91+
92+
var accessToken = await communicationTokenCredential.GetTokenAsync(MockTokenRequestContext(), CancellationToken.None);
93+
Assert.AreEqual(ExpiredToken, accessToken.Token);
94+
}
95+
96+
[Test]
97+
[TestCase(true)]
98+
[TestCase(false)]
99+
public void CommunicationTokenCredential_PassesCancelToken(bool refreshProactively)
100+
{
101+
var cancellationToken = new CancellationToken();
102+
CancellationToken? actualCancellationToken = null;
103+
104+
var userCredential = new CommunicationUserCredential(
105+
refreshProactively,
106+
RefreshToken,
107+
c => new ValueTask<string>(RefreshToken(c)),
108+
ExpiredToken);
109+
110+
var communicationTokenCredential = new CommunicationTokenCredential(userCredential);
111+
var accessToken = communicationTokenCredential.GetToken(MockTokenRequestContext(), cancellationToken);
112+
Assert.AreEqual(cancellationToken.GetHashCode(), actualCancellationToken.GetHashCode());
113+
114+
string RefreshToken(CancellationToken token)
115+
{
116+
actualCancellationToken = token;
117+
return SampleToken;
118+
}
119+
}
120+
121+
[Test]
122+
[TestCase(true)]
123+
[TestCase(false)]
124+
public async Task CommunicationTokenCredential_PassesAsyncCancelToken(bool refreshProactively)
125+
{
126+
var cancellationToken = new CancellationToken();
127+
CancellationToken? actualCancellationToken = null;
128+
129+
var userCredential = new CommunicationUserCredential(
130+
refreshProactively,
131+
RefreshToken,
132+
c => new ValueTask<string>(RefreshToken(c)),
133+
ExpiredToken);
134+
135+
var communicationTokenCredential = new CommunicationTokenCredential(userCredential);
136+
var accessToken = await communicationTokenCredential.GetTokenAsync(MockTokenRequestContext(), cancellationToken);
137+
Assert.AreEqual(cancellationToken.GetHashCode(), actualCancellationToken.GetHashCode());
138+
139+
string RefreshToken(CancellationToken token)
140+
{
141+
actualCancellationToken = token;
142+
return SampleToken;
143+
}
144+
}
145+
}
146+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Azure.Communication.Identity;
5+
using Azure.Core;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
namespace Azure.Communication.Pipeline
10+
{
11+
internal class CommunicationTokenCredential : TokenCredential
12+
{
13+
private readonly CommunicationUserCredential _credential;
14+
15+
public CommunicationTokenCredential(CommunicationUserCredential credential) => _credential = credential;
16+
17+
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken) => _credential.GetToken(cancellationToken);
18+
public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken) => _credential.GetTokenAsync(cancellationToken);
19+
}
20+
}

sdk/communication/Shared/src/CommunicationUserAuthenticationPolicy.cs

Lines changed: 0 additions & 40 deletions
This file was deleted.

0 commit comments

Comments
 (0)