Skip to content

Commit 3d6ec19

Browse files
trwalketrwalkeashok672gladjohnbgavrilMS
authored
Adding FMI Integration tests (#5149)
* Adding FMI Integration tests * Clean up * Adding more FMI-FIC tests * Update * Updating FMI tests * Update NativeInterop version to 0.18.1 (#5164) * Update Directory.Packages.props * Update Directory.Packages.props * Update Directory.Packages.props Co-authored-by: Gladwin Johnson <[email protected]> --------- Co-authored-by: Gladwin Johnson <[email protected]> * Revert "Update MSAL to send "fmi-bearer" client assertion type based … (#5166) Revert "Update MSAL to send "fmi-bearer" client assertion type based on the client id (#5160)" This reverts commit cac074c. Co-authored-by: trwalke <[email protected]> * Update MSAL to send "fmi-bearer" client assertion type based on the client id (#5160) * Update MSAL to send "fmi-bearer" client assertion type based on the provided client id * Removing extra logic * Fix for client assertion. * Add test --------- Co-authored-by: trwalke <[email protected]> Co-authored-by: Bogdan Gavril <[email protected]> * Update CHANGELOG.md for 4.69.1 (#5168) * Update CHANGELOG.md * Apply suggestions from code review Co-authored-by: Gladwin Johnson <[email protected]> --------- Co-authored-by: Gladwin Johnson <[email protected]> * Updating integration tests with latest spec changes. * Update tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/FmiIntegrationTests.cs Co-authored-by: Bogdan Gavril <[email protected]> * Updating FMI Integration tests --------- Co-authored-by: trwalke <[email protected]> Co-authored-by: Ashok Kumar Ramakrishnan <[email protected]> Co-authored-by: Gladwin Johnson <[email protected]> Co-authored-by: Bogdan Gavril <[email protected]>
1 parent 52648ab commit 3d6ec19

File tree

1 file changed

+346
-0
lines changed

1 file changed

+346
-0
lines changed
Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Linq;
5+
using System.Security.Cryptography.X509Certificates;
6+
using System.Threading.Tasks;
7+
using Microsoft.Identity.Client;
8+
using Microsoft.Identity.Test.LabInfrastructure;
9+
using Microsoft.Identity.Test.Unit;
10+
using Microsoft.VisualStudio.TestTools.UnitTesting;
11+
using Microsoft.Identity.Test.Common.Core.Helpers;
12+
using System;
13+
using System.IdentityModel.Tokens.Jwt;
14+
15+
namespace Microsoft.Identity.Test.Integration.NetCore.HeadlessTests
16+
{
17+
/// <summary>
18+
/// The tests in this file are demonstrations of the various authentication flows outlined in the "FMI protocol spec v1.0" Section 3.2
19+
/// https://microsoft.sharepoint.com/:w:/t/aad/protocols/EThMH6es0UNKhsFlVgBiBegByuZQ6CnaCzzAdAV0excHVA?e=m5xXtV
20+
/// </summary>
21+
[TestClass]
22+
public class FmiIntegrationTests
23+
{
24+
private byte[] _serializedCache;
25+
26+
[TestMethod]
27+
//RMA getting FMI cred for a leaf entity or sub-RMA
28+
[Ignore("Requires Coorp net to run")]
29+
public async Task Flow1_RmaCredential_From_CertTestAsync()
30+
{
31+
//Arrange
32+
X509Certificate2 cert = CertificateHelper.FindCertificateByName(TestConstants.AutomationTestCertName);
33+
string expectedExternalCacheKey = null;
34+
35+
Action<TokenCacheNotificationArgs> extCacheKeyEvaluator = (args) =>
36+
{
37+
if (expectedExternalCacheKey != null)
38+
{
39+
Assert.IsTrue(args.SuggestedCacheKey.Contains(expectedExternalCacheKey));
40+
}
41+
};
42+
43+
//Fmi app/scenario parameters
44+
var clientId = "4df2cbbb-8612-49c1-87c8-f334d6d065ad";
45+
var scope = "api://AzureFMITokenExchange/.default";
46+
47+
//Act
48+
//Create application
49+
var confidentialApp = ConfidentialClientApplicationBuilder
50+
.Create(clientId)
51+
.WithAuthority("https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca", true)
52+
.WithExtraQueryParameters("dc=ESTS-PUB-SCUS-LZ1-FD000-TEST1") //Enables MSAL to target ESTS Test slice
53+
.WithExperimentalFeatures(true) //WithFmiPath is experimental so experimental features needs to be enabled on the app
54+
.WithCertificate(cert, sendX5C: true) //sendX5c enables SN+I auth which is required for FMI flows
55+
.BuildConcrete();
56+
57+
//Configure token cache serialization
58+
confidentialApp.AppTokenCache.SetBeforeAccess(BeforeCacheAccess);
59+
confidentialApp.AppTokenCache.SetAfterAccess(AfterCacheAccess);
60+
61+
//Recording test data for Asserts
62+
var appCacheAccess = confidentialApp.AppTokenCache.RecordAccess(extCacheKeyEvaluator);
63+
expectedExternalCacheKey = "zm2n0E62zwTsnNsozptLsoOoB_C7i-GfpxHYQQINJUw";
64+
65+
//Acquire Fmi Cred
66+
var authResult = await confidentialApp.AcquireTokenForClient(new[] { scope })
67+
.WithFmiPath("SomeFmiPath/FmiCredentialPath") //Sets fmi path in client credential request.
68+
.ExecuteAsync()
69+
.ConfigureAwait(false);
70+
71+
//Assert
72+
AssertResults(authResult,
73+
confidentialApp,
74+
"-login.windows.net-atext-4df2cbbb-8612-49c1-87c8-f334d6d065ad-f645ad92-e38d-4d1a-b510-d1b09a74a8ca-api://azurefmitokenexchange/.default-zm2n0e62zwtsnnsozptlsooob_c7i-gfpxhyqqinjuw",
75+
"a9dd8a2a-df54-4ae0-84f9-38c8d57e5265",
76+
"SomeFmiPath/FmiCredentialPath");
77+
}
78+
79+
[TestMethod]
80+
//RMA getting FMI token for a leaf entity
81+
[Ignore("Requires Coorp net to run")]
82+
public async Task Flow2_RmaToken_From_CertTestAsync()
83+
{
84+
//Arrange
85+
X509Certificate2 cert = CertificateHelper.FindCertificateByName(TestConstants.AutomationTestCertName);
86+
string expectedExternalCacheKey = null;
87+
88+
Action<TokenCacheNotificationArgs> extCacheKeyEvaluator = (args) =>
89+
{
90+
if (expectedExternalCacheKey != null)
91+
{
92+
Assert.IsTrue(args.SuggestedCacheKey.Contains(expectedExternalCacheKey));
93+
}
94+
};
95+
96+
//Fmi app/scenario parameters
97+
var clientId = "4df2cbbb-8612-49c1-87c8-f334d6d065ad";
98+
var scope = "022907d3-0f1b-48f7-badc-1ba6abab6d66/.default"; //Guid for api://AzureFMITokenExchange
99+
100+
//Act
101+
//Create application
102+
var confidentialApp = ConfidentialClientApplicationBuilder
103+
.Create(clientId)
104+
.WithAuthority("https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca", true)
105+
.WithExtraQueryParameters("dc=ESTS-PUB-SCUS-LZ1-FD000-TEST1") //Enables MSAL to target ESTS Test slice
106+
.WithExperimentalFeatures(true) //WithFmiPath is experimental so experimental features needs to be enabled on the app
107+
.WithCertificate(cert, sendX5C: true) //sendX5c enables SN+I auth which is required for FMI flows
108+
.BuildConcrete();
109+
110+
//Configure token cache serialization
111+
confidentialApp.AppTokenCache.SetBeforeAccess(BeforeCacheAccess);
112+
confidentialApp.AppTokenCache.SetAfterAccess(AfterCacheAccess);
113+
114+
//Recording test data for Asserts
115+
var appCacheAccess = confidentialApp.AppTokenCache.RecordAccess(extCacheKeyEvaluator);
116+
expectedExternalCacheKey = "zm2n0E62zwTsnNsozptLsoOoB_C7i-GfpxHYQQINJUw";
117+
118+
//Acquire Token
119+
var authResult = await confidentialApp.AcquireTokenForClient(new[] { scope })
120+
.WithFmiPath("SomeFmiPath/FmiCredentialPath") //Sets fmi path in client credential request.
121+
.ExecuteAsync()
122+
.ConfigureAwait(false);
123+
124+
//Assert
125+
AssertResults(authResult,
126+
confidentialApp,
127+
"-login.windows.net-atext-4df2cbbb-8612-49c1-87c8-f334d6d065ad-f645ad92-e38d-4d1a-b510-d1b09a74a8ca-022907d3-0f1b-48f7-badc-1ba6abab6d66/.default-zm2n0e62zwtsnnsozptlsooob_c7i-gfpxhyqqinjuw",
128+
"022907d3-0f1b-48f7-badc-1ba6abab6d66",
129+
"SomeFmiPath/FmiCredentialPath");
130+
}
131+
132+
[TestMethod]
133+
//Sub-RMA getting FMI cred for a child sub-RMA
134+
[Ignore("Requires Coorp net to run")]
135+
public async Task Flow3_FmiCredential_From_RmaCredential()
136+
{
137+
//Arrange
138+
X509Certificate2 cert = CertificateHelper.FindCertificateByName(TestConstants.AutomationTestCertName);
139+
string expectedExternalCacheKey = null;
140+
141+
Action<TokenCacheNotificationArgs> extCacheKeyEvaluator = (args) =>
142+
{
143+
if (expectedExternalCacheKey != null)
144+
{
145+
Assert.IsTrue(args.SuggestedCacheKey.Contains(expectedExternalCacheKey));
146+
}
147+
};
148+
149+
//Fmi app/scenario parameters
150+
var clientId = "urn:microsoft:identity:fmi";
151+
var scope = "api://AzureFMITokenExchange/.default";
152+
153+
//Act
154+
//Create application
155+
var confidentialApp = ConfidentialClientApplicationBuilder
156+
.Create(clientId)
157+
.WithAuthority("https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca", true)
158+
.WithExtraQueryParameters("dc=ESTS-PUB-SCUS-LZ1-FD000-TEST1") //Enables MSAL to target ESTS Test slice
159+
.WithExperimentalFeatures(true) //WithFmiPath is experimental so experimental features needs to be enabled on the app
160+
.WithClientAssertion((options) => GetParentCredential(options)) //This api acquires the FMI credential needed to authenticate
161+
.BuildConcrete();
162+
163+
//FOR TESTING ONLY: Configure token cache serialization
164+
confidentialApp.AppTokenCache.SetBeforeAccess(BeforeCacheAccess);
165+
confidentialApp.AppTokenCache.SetAfterAccess(AfterCacheAccess);
166+
167+
//Recording test data for Asserts
168+
var appCacheAccess = confidentialApp.AppTokenCache.RecordAccess(extCacheKeyEvaluator);
169+
expectedExternalCacheKey = "7CX57Q63os7benQ6ER0sxgJPtNQSv7TGb5zexcidFoI";
170+
171+
//Acquire Fmi Cred
172+
var authResult = await confidentialApp.AcquireTokenForClient(new[] { scope })
173+
.WithFmiPath("SomeFmiPath/Path") //Sets fmi path in client credential request.
174+
.ExecuteAsync()
175+
.ConfigureAwait(false);
176+
177+
//Assert
178+
AssertResults(authResult,
179+
confidentialApp,
180+
"-login.windows.net-atext-urn:microsoft:identity:fmi-f645ad92-e38d-4d1a-b510-d1b09a74a8ca-api://azurefmitokenexchange/.default-7cx57q63os7benq6er0sxgjptnqsv7tgb5zexcidfoi",
181+
"a9dd8a2a-df54-4ae0-84f9-38c8d57e5265",
182+
"SomeFmiPath/Path");
183+
}
184+
185+
[TestMethod]
186+
//Sub-RMA getting FIC for leaf entity.
187+
[Ignore("Waiting for ESTS Implementation. Also requires Coorp net to run")]
188+
public async Task Flow4_SubRma_FmiCredential_For_leaf()
189+
{
190+
//Arrange
191+
X509Certificate2 cert = CertificateHelper.FindCertificateByName(TestConstants.AutomationTestCertName);
192+
string expectedExternalCacheKey = null;
193+
194+
Action<TokenCacheNotificationArgs> extCacheKeyEvaluator = (args) =>
195+
{
196+
if (expectedExternalCacheKey != null)
197+
{
198+
Assert.IsTrue(args.SuggestedCacheKey.Contains(expectedExternalCacheKey));
199+
}
200+
};
201+
202+
//Fmi app/scenario parameters
203+
var clientId = "urn:microsoft:identity:fmi";
204+
var scope = "022907d3-0f1b-48f7-badc-1ba6abab6d66/.default"; //Guid for api://AzureFMITokenExchange
205+
206+
//Act
207+
//Create application
208+
var confidentialApp = ConfidentialClientApplicationBuilder
209+
.Create(clientId)
210+
.WithAuthority("https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca", true)
211+
.WithExtraQueryParameters("dc=ESTS-PUB-SCUS-LZ1-FD000-TEST1") //Enables MSAL to target ESTS Test slice
212+
.WithExperimentalFeatures(true) //WithFmiPath is experimental so experimental features needs to be enabled on the app
213+
.WithClientAssertion((options) => GetParentCredential(options)) //This api acquires the FMI credential needed to authenticate
214+
.BuildConcrete();
215+
216+
//Configure token cache serialization
217+
confidentialApp.AppTokenCache.SetBeforeAccess(BeforeCacheAccess);
218+
confidentialApp.AppTokenCache.SetAfterAccess(AfterCacheAccess);
219+
220+
//Recording test data for Asserts
221+
var appCacheAccess = confidentialApp.AppTokenCache.RecordAccess(extCacheKeyEvaluator);
222+
expectedExternalCacheKey = "";
223+
224+
//Acquire Fmi Cred
225+
var authResult = await confidentialApp.AcquireTokenForClient(new[] { scope })
226+
.WithFmiPath("SomeFmiPath/Path") //Sets fmi path in client credential request.
227+
.ExecuteAsync()
228+
.ConfigureAwait(false);
229+
230+
//Assert
231+
AssertResults(authResult,
232+
confidentialApp,
233+
"expectedInternalCacheKey",
234+
"expectedAudience",
235+
"SomeFmiPath/Path");
236+
}
237+
238+
[TestMethod]
239+
//Sub-RMA getting FMI token for leaf entity
240+
[Ignore("Requires Coorp net to run")]
241+
public async Task Flow5_SubRma_FmiToken_From_FmiCred_For_leafTestAsync()
242+
{
243+
//Arrange
244+
X509Certificate2 cert = CertificateHelper.FindCertificateByName(TestConstants.AutomationTestCertName);
245+
string expectedExternalCacheKey = null;
246+
247+
Action<TokenCacheNotificationArgs> extCacheKeyEvaluator = (args) =>
248+
{
249+
if (expectedExternalCacheKey != null)
250+
{
251+
Assert.IsTrue(args.SuggestedCacheKey.Contains(expectedExternalCacheKey));
252+
}
253+
};
254+
255+
//Fmi app/scenario parameters
256+
var clientId = "urn:microsoft:identity:fmi";
257+
var scope = "022907d3-0f1b-48f7-badc-1ba6abab6d66/.default"; //Guid for api://AzureFMITokenExchange
258+
259+
//Act
260+
//Create application
261+
var confidentialApp = ConfidentialClientApplicationBuilder
262+
.Create(clientId)
263+
.WithAuthority("https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca", true)
264+
.WithExtraQueryParameters("dc=ESTS-PUB-SCUS-LZ1-FD000-TEST1") //Enables MSAL to target ESTS Test slice
265+
.WithExperimentalFeatures(true) //WithFmiPath is experimental so experimental features needs to be enabled on the app
266+
.WithClientAssertion((options) => GetParentCredential(options)) //This api acquires the FMI credential needed to authenticate
267+
.BuildConcrete();
268+
269+
//Configure token cache serialization
270+
confidentialApp.AppTokenCache.SetBeforeAccess(BeforeCacheAccess);
271+
confidentialApp.AppTokenCache.SetAfterAccess(AfterCacheAccess);
272+
273+
//Recording test data for Asserts
274+
var appCacheAccess = confidentialApp.AppTokenCache.RecordAccess(extCacheKeyEvaluator);
275+
expectedExternalCacheKey = "7CX57Q63os7benQ6ER0sxgJPtNQSv7TGb5zexcidFoI";
276+
277+
//Acquire Fmi Cred
278+
var authResult = await confidentialApp.AcquireTokenForClient(new[] { scope })
279+
.WithFmiPath("SomeFmiPath/Path") //Sets fmi path in client credential request.
280+
.ExecuteAsync()
281+
.ConfigureAwait(false);
282+
283+
//Assert
284+
AssertResults(authResult,
285+
confidentialApp,
286+
"-login.windows.net-atext-urn:microsoft:identity:fmi-f645ad92-e38d-4d1a-b510-d1b09a74a8ca-022907d3-0f1b-48f7-badc-1ba6abab6d66/.default-7cx57q63os7benq6er0sxgjptnqsv7tgb5zexcidfoi",
287+
"022907d3-0f1b-48f7-badc-1ba6abab6d66",
288+
"SomeFmiPath/Path");
289+
}
290+
291+
private static async Task<string> GetParentCredential(AssertionRequestOptions options)
292+
{
293+
//Fmi app/scenario parameters
294+
var clientId = "4df2cbbb-8612-49c1-87c8-f334d6d065ad";
295+
var scope = "api://AzureFMITokenExchange/.default";
296+
297+
X509Certificate2 cert = CertificateHelper.FindCertificateByName(TestConstants.AutomationTestCertName);
298+
299+
//Create application
300+
var confidentialApp = ConfidentialClientApplicationBuilder
301+
.Create(clientId)
302+
.WithAuthority("https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca", true)
303+
.WithExtraQueryParameters("dc=ESTS-PUB-SCUS-LZ1-FD000-TEST1") //Enables MSAL to target ESTS Test slice
304+
.WithExperimentalFeatures(true) //WithFmiPath is experimental so experimental features needs to be enabled on the app
305+
.WithCertificate(cert, sendX5C: true) //sendX5c enables SN+I auth which is required for FMI flows
306+
.BuildConcrete();
307+
308+
//Acquire Token
309+
var authResult = await confidentialApp.AcquireTokenForClient(new[] { scope })
310+
.WithFmiPath("SomeFmiPath/FmiCredentialPath") //Sets fmi path in client credential request.
311+
.ExecuteAsync()
312+
.ConfigureAwait(false);
313+
314+
return authResult.AccessToken;
315+
}
316+
317+
private void BeforeCacheAccess(TokenCacheNotificationArgs args)
318+
{
319+
args.TokenCache.DeserializeMsalV3(_serializedCache);
320+
}
321+
322+
private void AfterCacheAccess(TokenCacheNotificationArgs args)
323+
{
324+
_serializedCache = args.TokenCache.SerializeMsalV3();
325+
}
326+
327+
private void AssertResults(
328+
AuthenticationResult authResult,
329+
ConfidentialClientApplication confidentialApp,
330+
string expectedInternalCacheKey,
331+
string expectedAudience,
332+
string expectedFmiPath)
333+
{
334+
var handler = new JwtSecurityTokenHandler();
335+
var jsonToken = handler.ReadToken(authResult.AccessToken) as JwtSecurityToken;
336+
var subject = jsonToken.Payload["sub"].ToString();
337+
var audience = jsonToken.Payload["aud"].ToString();
338+
var token = confidentialApp.AppTokenCacheInternal.Accessor.GetAllAccessTokens().First();
339+
340+
Assert.IsNotNull(authResult);
341+
Assert.AreEqual(expectedAudience, audience);
342+
Assert.IsTrue(subject.Contains(expectedFmiPath));
343+
Assert.AreEqual(expectedInternalCacheKey, token.CacheKey);
344+
}
345+
}
346+
}

0 commit comments

Comments
 (0)