Skip to content

Commit 55f4f17

Browse files
committed
Port *MgRequestContext.
1 parent 0e3cdbb commit 55f4f17

27 files changed

+329
-121
lines changed

config/ModuleMetadata.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@
2626
],
2727
"versions": {
2828
"authentication": {
29-
"prerelease": "preview12",
29+
"prerelease": "preview1",
3030
"version": "2.0.0"
3131
},
3232
"beta": {
33-
"prerelease": "preview12",
33+
"prerelease": "preview1",
3434
"version": "2.0.0"
3535
},
3636
"v1.0": {
37-
"prerelease": "preview12",
37+
"prerelease": "preview1",
3838
"version": "2.0.0"
3939
}
4040
}

src/Authentication/Authentication.Core/Common/GraphSession.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// ------------------------------------------------------------------------------
44

55
using Microsoft.Graph.PowerShell.Authentication.Core;
6+
using Microsoft.Graph.PowerShell.Authentication.Core.Interfaces;
67
using Microsoft.Graph.PowerShell.Authentication.Core.TokenCache;
78
using Microsoft.Graph.PowerShell.Authentication.Interfaces;
89
using System;
@@ -45,6 +46,11 @@ public class GraphSession : IGraphSession
4546
/// </summary>
4647
public IGraphEnvironment Environment { get; set; }
4748

49+
/// <summary>
50+
/// Gets or Sets <see cref="IRequestContext"/>.
51+
/// </summary>
52+
public IRequestContext RequestContext { get; set; }
53+
4854
/// <summary>
4955
/// Represents a collection of Microsoft Graph PowerShell meta-info.
5056
/// </summary>

src/Authentication/Authentication.Core/ErrorConstants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ internal static class Codes
2020
public static class Message
2121
{
2222
public const string MissingAuthContext = "Authentication needed. Please call Connect-MgGraph.";
23+
public const string MissingSessionProperty = "{0} is missing. Please call Connect-MgGraph then try again.";
2324
internal const string InvalidJWT = "Invalid JWT access token.";
2425
internal const string InvalidScope = "Please retry by specifying a sign-in -Audience or -TenantId to Connect-MgGraph. e.g., Connect-MgGraph -Audience 'organizations' -Scopes 'YOUR_SCOPES' -UseDeviceAuthentication.";
2526
internal const string NullOrEmptyParameter = "Parameter '{0}' cannot be null or empty.";
26-
internal const string MacKeyChainFailed = "{0} failed with result code {1}.";
2727
internal const string AuthenticationTimeout = "Authentication timed out after {0} seconds due to inactivity. Please try again.";
2828
internal const string InvalidUserProvidedToken = "The provided access token is invalid. Set a valid access token to `-{0}` parameter and try again.";
2929
internal const string ExpiredUserProvidedToken = "The provided access token has expired. Set a valid access token to `-{0}` parameter and try again.";

src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ public interface IAuthContext
4949
X509Certificate2 Certificate { get; set; }
5050
ContextScope ContextScope { get; set; }
5151
Version PSHostVersion { get; set; }
52-
TimeSpan ClientTimeout { get; set; }
5352
SecureString ClientSecret { get; set; }
5453
}
5554
}

src/Authentication/Authentication.Core/Interfaces/IGraphSession.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
33
// ------------------------------------------------------------------------------
44

5+
using Microsoft.Graph.PowerShell.Authentication.Core.Interfaces;
6+
57
namespace Microsoft.Graph.PowerShell.Authentication.Interfaces
68
{
79
public interface IGraphSession
810
{
911
IAuthContext AuthContext { get; set; }
1012
IDataStore DataStore { get; set; }
13+
IRequestContext RequestContext { get; set; }
1114
}
1215
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// ------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
3+
// ------------------------------------------------------------------------------
4+
5+
using System;
6+
7+
namespace Microsoft.Graph.PowerShell.Authentication.Core.Interfaces
8+
{
9+
public interface IRequestContext
10+
{
11+
int RetryDelay { get; set; }
12+
int MaxRetry { get; set; }
13+
TimeSpan RetriesTimeLimit { get; set; }
14+
TimeSpan ClientTimeout { get; set; }
15+
}
16+
}

src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<TargetFrameworks>netstandard2.0;net6.0;net472</TargetFrameworks>
55
<RootNamespace>Microsoft.Graph.PowerShell.Authentication.Core</RootNamespace>
6-
<VersionPrefix>1.11.0</VersionPrefix>
6+
<VersionPrefix>2.0.0</VersionPrefix>
77
<VersionSuffix>preview1</VersionSuffix>
88
</PropertyGroup>
99
<PropertyGroup>

src/Authentication/Authentication.Test/Helpers/AuthenticationHelpersTests.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace Microsoft.Graph.Authentication.Test.Helpers
1919
{
2020
public class AuthenticationHelpersTests : IDisposable
2121
{
22-
private MockAuthRecord mockAuthRecord;
22+
private readonly MockAuthRecord mockAuthRecord;
2323
public AuthenticationHelpersTests()
2424
{
2525
GraphSession.Initialize(() => new GraphSession());
@@ -160,6 +160,7 @@ public async Task ShouldUseClientCredentialProviderWhenAppOnlyContextIsProvidedA
160160
AuthContext appOnlyAuthContext = new AuthContext
161161
{
162162
AuthType = AuthenticationType.AppOnly,
163+
TokenCredentialType = TokenCredentialType.ClientCertificate,
163164
ClientId = mockAuthRecord.ClientId,
164165
CertificateSubjectName = "cn=dummyCert",
165166
ContextScope = ContextScope.Process,
@@ -186,6 +187,7 @@ public async Task ShouldUseInMemoryCertificateWhenProvidedAsync()
186187
AuthContext appOnlyAuthContext = new AuthContext
187188
{
188189
AuthType = AuthenticationType.AppOnly,
190+
TokenCredentialType = TokenCredentialType.ClientCertificate,
189191
ClientId = mockAuthRecord.ClientId,
190192
Certificate = certificate,
191193
ContextScope = ContextScope.Process,
@@ -211,11 +213,12 @@ public async Task ShouldUseCertNameInsteadOfPassedInCertificateWhenBothAreSpecif
211213
AuthContext appOnlyAuthContext = new AuthContext
212214
{
213215
AuthType = AuthenticationType.AppOnly,
216+
TokenCredentialType = TokenCredentialType.ClientCertificate,
214217
ClientId = mockAuthRecord.ClientId,
215218
CertificateSubjectName = dummyCertName,
216219
Certificate = inMemoryCertificate,
217220
ContextScope = ContextScope.Process,
218-
TenantId= mockAuthRecord.TenantId
221+
TenantId = mockAuthRecord.TenantId
219222
};
220223
// Act
221224
TokenCredential tokenCredential = await AuthenticationHelpers.GetTokenCredentialAsync(appOnlyAuthContext, default);
@@ -239,6 +242,7 @@ public async Task ShouldUseCertThumbPrintInsteadOfPassedInCertificateWhenBothAre
239242
AuthContext appOnlyAuthContext = new AuthContext
240243
{
241244
AuthType = AuthenticationType.AppOnly,
245+
TokenCredentialType = TokenCredentialType.ClientCertificate,
242246
ClientId = mockAuthRecord.ClientId,
243247
CertificateThumbprint = storedDummyCertificate.Thumbprint,
244248
Certificate = inMemoryCertificate,
@@ -264,6 +268,7 @@ public async Task ShouldThrowIfNonExistentCertNameIsProvidedAsync()
264268
AuthContext appOnlyAuthContext = new AuthContext
265269
{
266270
AuthType = AuthenticationType.AppOnly,
271+
TokenCredentialType = TokenCredentialType.ClientCertificate,
267272
ClientId = mockAuthRecord.ClientId,
268273
CertificateSubjectName = dummyCertName,
269274
ContextScope = ContextScope.Process,
@@ -284,6 +289,7 @@ public async Task ShouldThrowIfNullInMemoryCertIsProvidedAsync()
284289
AuthContext appOnlyAuthContext = new AuthContext
285290
{
286291
AuthType = AuthenticationType.AppOnly,
292+
TokenCredentialType = TokenCredentialType.ClientCertificate,
287293
ClientId = mockAuthRecord.ClientId,
288294
Certificate = null,
289295
ContextScope = ContextScope.Process,
@@ -369,7 +375,7 @@ private static void DeleteSelfSignedCertByThumbprint(string certificateThumbPrin
369375
xStore.Remove(xCertificate);
370376
}
371377
}
372-
378+
373379
public void Dispose() => mockAuthRecord.DeleteCache();
374380
}
375381
}

src/Authentication/Authentication.Test/Helpers/HttpHelpersTests.cs

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
// ------------------------------------------------------------------------------
22
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
33
// ------------------------------------------------------------------------------
4-
using System;
5-
using System.Net.Http;
6-
using System.Threading.Tasks;
74
using Microsoft.Graph.PowerShell.Authentication;
85
using Microsoft.Graph.PowerShell.Authentication.Core.TokenCache;
96
using Microsoft.Graph.PowerShell.Authentication.Core.Utilities;
107
using Microsoft.Graph.PowerShell.Authentication.Helpers;
8+
using Microsoft.Graph.PowerShell.Authentication.Models;
9+
using System;
10+
using System.Collections.Generic;
11+
using System.Net.Http;
12+
using System.Threading.Tasks;
1113
using Xunit;
1214

1315
namespace Microsoft.Graph.Authentication.Test.Helpers
@@ -23,31 +25,31 @@ public void GetGraphHttpClientWithDefaultParametersShouldReturnHttpClientWithDef
2325
AuthType = AuthenticationType.UserProvidedAccessToken,
2426
ContextScope = ContextScope.Process
2527
};
28+
GraphSession.Instance.RequestContext = new RequestContext();
2629

2730
HttpClient httpClient = HttpHelpers.GetGraphHttpClient();
2831

29-
Assert.Equal(GraphSession.Instance.AuthContext.ClientTimeout, TimeSpan.FromSeconds(Constants.ClientTimeout));
30-
Assert.Equal(httpClient.Timeout, GraphSession.Instance.AuthContext.ClientTimeout);
32+
Assert.Equal(GraphSession.Instance.RequestContext.ClientTimeout, TimeSpan.FromSeconds(Constants.ClientTimeout));
33+
Assert.Equal(httpClient.Timeout, GraphSession.Instance.RequestContext.ClientTimeout);
3134

3235
// reset static instance.
3336
GraphSession.Reset();
3437
}
3538

3639
[Fact]
37-
public async Task GetGraphHttpClientWithClientTimeoutParameterShouldReturnHttpClientWithSpecifiedTimeoutAsync()
40+
public void GetGraphHttpClientWithClientTimeoutParameterShouldReturnHttpClientWithSpecifiedTimeout()
3841
{
3942
GraphSession.Initialize(() => new GraphSession());
4043
TimeSpan timeSpan = TimeSpan.FromSeconds(10);
41-
var authContext = new AuthContext
44+
GraphSession.Instance.AuthContext = new AuthContext
4245
{
4346
AuthType = AuthenticationType.UserProvidedAccessToken,
4447
ContextScope = ContextScope.Process
4548
};
46-
IAuthenticationProvider authProvider = await AuthenticationHelpers.GetAuthenticationProviderAsync(authContext);
49+
GraphSession.Instance.RequestContext = new RequestContext { ClientTimeout = timeSpan };
4750

48-
HttpClient httpClient = HttpHelpers.GetGraphHttpClient(authProvider, timeSpan);
51+
HttpClient httpClient = HttpHelpers.GetGraphHttpClient();
4952

50-
Assert.Equal(authContext.ClientTimeout, TimeSpan.FromSeconds(Constants.ClientTimeout));
5153
Assert.Equal(httpClient.Timeout, timeSpan);
5254

5355
// reset static instance.
@@ -62,13 +64,13 @@ public void GetGraphHttpClientShouldReturnHttpClientWithCustomerProvidedTimeout(
6264
GraphSession.Instance.AuthContext = new AuthContext
6365
{
6466
AuthType = AuthenticationType.UserProvidedAccessToken,
65-
ContextScope = ContextScope.Process,
66-
ClientTimeout = timeSpan
67+
ContextScope = ContextScope.Process
6768
};
69+
GraphSession.Instance.RequestContext = new RequestContext { ClientTimeout = timeSpan };
6870

6971
HttpClient httpClient = HttpHelpers.GetGraphHttpClient();
7072

71-
Assert.Equal(GraphSession.Instance.AuthContext.ClientTimeout, timeSpan);
73+
Assert.Equal(GraphSession.Instance.RequestContext.ClientTimeout, timeSpan);
7274
Assert.Equal(httpClient.Timeout, timeSpan);
7375

7476
// reset static instance.
@@ -88,6 +90,7 @@ public void GetGraphHttpClientShouldReturnInSessionHttpClientWhenSessionHasAClie
8890
{
8991
BaseAddress = new Uri("https://test.contoso.com/v1.0/")
9092
};
93+
GraphSession.Instance.RequestContext = new RequestContext();
9194

9295
HttpClient httpClient = HttpHelpers.GetGraphHttpClient();
9396

@@ -109,6 +112,7 @@ public void GetGraphHttpClientShouldReturnNewHttpClientWhenSessionHasNoClient()
109112
ContextScope = ContextScope.Process,
110113
};
111114
GraphSession.Instance.GraphHttpClient = null;
115+
GraphSession.Instance.RequestContext = new RequestContext();
112116

113117
HttpClient httpClient = HttpHelpers.GetGraphHttpClient();
114118

@@ -129,6 +133,7 @@ public void GetGraphHttpClientShouldReturnNewHttpClientWhenSessionIsNew()
129133
AuthType = AuthenticationType.UserProvidedAccessToken,
130134
ContextScope = ContextScope.Process,
131135
};
136+
GraphSession.Instance.RequestContext = new RequestContext();
132137

133138
HttpClient httpClient = HttpHelpers.GetGraphHttpClient();
134139

@@ -170,6 +175,7 @@ public async Task GetGraphHttpClientShouldReturnNewHttpClientOnSignOutThenSignIn
170175
AuthType = AuthenticationType.UserProvidedAccessToken,
171176
ContextScope = ContextScope.Process,
172177
};
178+
GraphSession.Instance.RequestContext = new RequestContext();
173179
HttpClient httpClientAttempt2 = HttpHelpers.GetGraphHttpClient();
174180

175181
Assert.NotNull(httpClientAttempt1);
@@ -182,5 +188,29 @@ public async Task GetGraphHttpClientShouldReturnNewHttpClientOnSignOutThenSignIn
182188
// reset static instance.
183189
GraphSession.Reset();
184190
}
191+
192+
[Fact]
193+
public async void GetGraphHttpClientShouldBeThreadSafeAsync()
194+
{
195+
GraphSession.Initialize(() => new GraphSession());
196+
GraphSession.Instance.RequestContext = new RequestContext();
197+
GraphSession.Instance.AuthContext = new AuthContext
198+
{
199+
AuthType = AuthenticationType.UserProvidedAccessToken,
200+
ContextScope = ContextScope.Process,
201+
PSHostVersion = new Version("7.2.7")
202+
};
203+
204+
var tasks = new List<Task<HttpClient>>();
205+
for (int i = 0; i < 100; i++)
206+
{
207+
tasks.Add(Task.Factory.StartNew(() => HttpHelpers.GetGraphHttpClient()));
208+
}
209+
var exception = await Record.ExceptionAsync(() => Task.WhenAll(tasks));
210+
Assert.Null(exception);
211+
212+
// reset static instance.
213+
GraphSession.Reset();
214+
}
185215
}
186216
}

src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ private async Task ProcessRecordAsync()
158158
{
159159
IAuthContext authContext = new AuthContext { TenantId = TenantId, PSHostVersion = this.Host.Version };
160160
if (MyInvocation.BoundParameters.ContainsKey(nameof(ClientTimeout)))
161-
authContext.ClientTimeout = TimeSpan.FromSeconds(ClientTimeout);
161+
GraphSession.Instance.RequestContext.ClientTimeout = TimeSpan.FromSeconds(ClientTimeout);
162162

163163
GraphSession.Instance.Environment = environment;
164164
GraphSession.Instance.GraphHttpClient = null;

0 commit comments

Comments
 (0)