Skip to content

Commit 686751e

Browse files
committed
Merging from master and resolving the conflicts
2 parents f161eb3 + 0ab28e7 commit 686751e

File tree

9 files changed

+135
-31
lines changed

9 files changed

+135
-31
lines changed

.gitignore

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
/2-WebApp-graph-user/2-1-Call-MSGraph/.vs
3636
/2-WebApp-graph-user/2-1-Call-MSGraph/bin
3737
/2-WebApp-graph-user/2-1-Call-MSGraph/obj
38+
/2-WebApp-graph-user/2-1-Call-MSGraph/TestResults
3839
/2-WebApp-graph-user/2-2-TokenCache/.vs
3940
/2-WebApp-graph-user/2-2-TokenCache/bin
4041
/2-WebApp-graph-user/2-2-TokenCache/obj
@@ -110,22 +111,16 @@
110111
/4-WebApp-your-API/Client/bin/Release/netcoreapp2.2
111112
/4-WebApp-your-API/Client/obj/Debug/netcoreapp2.2
112113
/4-WebApp-your-API/Client/obj/Release/netcoreapp2.2
113-
/Microsoft.Identity.Web.Test/obj/Release/netcoreapp2.2
114-
/Microsoft.Identity.Web.Test/obj/Debug/netcoreapp2.2
115-
/5-WebApp-AuthZ/5-2-Groups/bin/Release/netcoreapp2.2
116-
/5-WebApp-AuthZ/5-1-Roles/bin/Release/netcoreapp2.2
114+
/Microsoft.Identity.Web.Test/obj
115+
/Microsoft.Identity.Web.Test/bin
116+
/5-WebApp-AuthZ/5-2-Groups/bin
117+
/5-WebApp-AuthZ/5-1-Roles/bin
117118
/4-WebApp-your-API/TodoListService/obj
118119
/4-WebApp-your-API/TodoListService/bin
119120
/4-WebApp-your-API/Client/obj
120-
/2-WebApp-graph-user/2-4-Sovereign-Call-MSGraph/bin/Debug/netcoreapp2.2
121+
/2-WebApp-graph-user/2-4-Sovereign-Call-MSGraph/bin
121122
/2-WebApp-graph-user/2-4-Sovereign-Call-MSGraph/obj
122-
/2-WebApp-graph-user/2-4-Sovereign-Call-MSGraph/bin/Release/netcoreapp2.2
123-
/Microsoft.Identity.Web.Test/bin/Release/netcoreapp2.2
124123
/Microsoft.Identity.Web.Test/obj
125124
/4-WebApp-your-API/4-2-B2C/.vs
126125
/4-WebApp-your-API/4-2-B2C/Client/obj
127126
/4-WebApp-your-API/4-2-B2C/TodoListService/obj
128-
/2-WebApp-graph-user/2-3-Multi-Tenant/.vs/WebApp-OpenIDConnect-DotNet
129-
/2-WebApp-graph-user/2-3-Multi-Tenant/bin/Debug/netcoreapp2.2
130-
/2-WebApp-graph-user/2-3-Multi-Tenant/obj
131-
/Microsoft.Identity.Web.Test/bin/Release/netcoreapp3.0

2-WebApp-graph-user/2-1-Call-MSGraph/AspnetCoreWebApp-calls-Microsoft-Graph.sln

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApp-OpenIDConnect-DotNet
77
EndProject
88
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web", "..\..\Microsoft.Identity.Web\Microsoft.Identity.Web.csproj", "{E0CEF26A-6CE6-4505-851B-6580D5564752}"
99
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CD0BB564-6C1E-4FCE-B9AB-7C637FDEE569}"
11+
ProjectSection(SolutionItems) = preProject
12+
.editorconfig = .editorconfig
13+
EndProjectSection
14+
EndProject
15+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web.Test", "..\..\Microsoft.Identity.Web.Test\Microsoft.Identity.Web.Test.csproj", "{8CCEAE2A-BDF6-470C-B6DE-7FC81A74DBD7}"
16+
EndProject
1017
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web.UI", "..\..\Microsoft.Identity.Web.UI\Microsoft.Identity.Web.UI.csproj", "{8CC22202-F66C-4332-A4F0-A2C09EBA08EC}"
11-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web.Test", "..\..\Microsoft.Identity.Web.Test\Microsoft.Identity.Web.Test.csproj", "{0EEC3E2E-69D0-4A7F-98D6-4386330F4965}"
1218
EndProject
1319
Global
1420
GlobalSection(SolutionConfigurationPlatforms) = preSolution

2-WebApp-graph-user/2-1-Call-MSGraph/WebApp-OpenIDConnect-DotNet.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-
<PackageReference Include="Microsoft.Graph" Version="1.14.0" />
21+
<PackageReference Include="Microsoft.Graph" Version="1.21.0" />
2222
</ItemGroup>
2323

2424
<ItemGroup>

2-WebApp-graph-user/2-2-TokenCache/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ Note: if you had used the automation to setup your application mentioned in [Ste
175175

176176
Starting from the [previous phase of the tutorial](../../2-WebApp-graph-user/2-1-Call-MSGraph), the code was incrementally updated with the following steps:
177177

178+
### Reference Microsoft.Extensions.Caching.SqlServer
179+
180+
This sample proposes a distributed SQL token cache. To use it, you'll need to add a reference to the `Microsoft.Extensions.Caching.SqlServer` NuGet package
181+
178182
### Update the `Startup.cs` file to enable Token caching using Sql database.
179183

180184
```CSharp
@@ -205,6 +209,7 @@ The files `MSALAppSqlTokenCacheProvider.cs` and `MSALPerUserSqlTokenCacheProvide
205209
## Next steps
206210

207211
- Learn how to enable distributed caches in [token cache serialization](../2.2.%20token%20cache%20serialization)
212+
- Learn more about the [Distributed SQL Server Cache](https://docs.microsoft.com/aspnet/core/performance/caching/distributed#distributed-sql-server-cache)
208213
- Learn how the same principle you've just learnt can be used to call:
209214
- [several Microsoft APIs](../../3-WebApp-multi-APIs), which will enable you to learn how incremental consent and conditional access is managed in your Web App
210215
- 3rd party, or even [your own Web API](../../4-WebApp-your-API), which will enable you to learn about custom scopes

5-WebApp-AuthZ/5-2-Groups/Services/MicrosoftGraph-Rest/MSGraphService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ public async Task<UserGroupsAndDirectoryRoles> GetCurrentUserGroupsAndRolesAsync
277277
public async Task<List<Group>> GetMyMemberOfGroupsAsync(string accessToken)
278278
{
279279
List<Group> groups = new List<Group>();
280-
280+
PrepareAuthenticatedClient(accessToken);
281281
// Get groups the current user is a direct member of.
282282
IUserMemberOfCollectionWithReferencesPage memberOfGroups = await graphServiceClient.Me.MemberOf.Request().GetAsync();
283283
if (memberOfGroups?.Count > 0)
@@ -378,4 +378,4 @@ await Task.Run(() =>
378378
}
379379
}
380380
}
381-
}
381+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.AspNetCore.Authentication.JwtBearer;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Text;
8+
using Xunit;
9+
using System.Linq;
10+
11+
namespace Microsoft.Identity.Web.Test
12+
{
13+
public class WebApiServiceCollectionExtensionsTests
14+
{
15+
[Fact]
16+
public void TestAuthority()
17+
{
18+
// Arrange
19+
JwtBearerOptions options = new JwtBearerOptions();
20+
21+
// Act and Assert
22+
options.Authority = "https://login.microsoftonline.com/common";
23+
WebApiServiceCollectionExtensions.EnsureAuthorityIsV2_0(options);
24+
Assert.Equal("https://login.microsoftonline.com/common/v2.0", options.Authority);
25+
26+
options.Authority = "https://login.microsoftonline.us/organizations";
27+
WebApiServiceCollectionExtensions.EnsureAuthorityIsV2_0(options);
28+
Assert.Equal("https://login.microsoftonline.us/organizations/v2.0", options.Authority);
29+
30+
options.Authority = "https://login.microsoftonline.com/common/";
31+
WebApiServiceCollectionExtensions.EnsureAuthorityIsV2_0(options);
32+
Assert.Equal("https://login.microsoftonline.com/common/v2.0", options.Authority);
33+
34+
options.Authority = "https://login.microsoftonline.com/common/v2.0";
35+
WebApiServiceCollectionExtensions.EnsureAuthorityIsV2_0(options);
36+
Assert.Equal("https://login.microsoftonline.com/common/v2.0", options.Authority);
37+
38+
39+
options.Authority = "https://login.microsoftonline.com/common/v2.0";
40+
WebApiServiceCollectionExtensions.EnsureAuthorityIsV2_0(options);
41+
Assert.Equal("https://login.microsoftonline.com/common/v2.0", options.Authority);
42+
43+
}
44+
45+
[Fact]
46+
public void TestAudience()
47+
{
48+
JwtBearerOptions options = new JwtBearerOptions();
49+
50+
// Act and Assert
51+
options.Audience = "https://localhost";
52+
WebApiServiceCollectionExtensions.EnsureValidAudiencesContainsApiGuidIfGuidProvided(options);
53+
Assert.True(options.TokenValidationParameters.ValidAudiences.Count() == 1);
54+
Assert.True(options.TokenValidationParameters.ValidAudiences.First() == "https://localhost");
55+
56+
options.Audience = "api://1EE5A092-0DFD-42B6-88E5-C517C0141321";
57+
WebApiServiceCollectionExtensions.EnsureValidAudiencesContainsApiGuidIfGuidProvided(options);
58+
Assert.True(options.TokenValidationParameters.ValidAudiences.Count() == 1);
59+
Assert.True(options.TokenValidationParameters.ValidAudiences.First() == "api://1EE5A092-0DFD-42B6-88E5-C517C0141321");
60+
61+
options.Audience = "1EE5A092-0DFD-42B6-88E5-C517C0141321";
62+
WebApiServiceCollectionExtensions.EnsureValidAudiencesContainsApiGuidIfGuidProvided(options);
63+
Assert.True(options.TokenValidationParameters.ValidAudiences.Count() == 2);
64+
Assert.Contains("api://1EE5A092-0DFD-42B6-88E5-C517C0141321", options.TokenValidationParameters.ValidAudiences);
65+
Assert.Contains("1EE5A092-0DFD-42B6-88E5-C517C0141321", options.TokenValidationParameters.ValidAudiences);
66+
67+
}
68+
}
69+
}

Microsoft.Identity.Web/Microsoft.Identity.Web.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
</ItemGroup>
3535

3636
<ItemGroup Label="Build Tools" Condition="$([MSBuild]::IsOsPlatform('Windows'))">
37-
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All" />
37+
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
3838
</ItemGroup>
3939

4040

Microsoft.Identity.Web/TokenAcquisition.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,31 +309,31 @@ private IConfidentialClientApplication BuildConfidentialClientApplication()
309309
request.PathBase,
310310
microsoftIdentityOptions.CallbackPath.Value ?? string.Empty);
311311

312-
string authority = string.Empty;
312+
if (!applicationOptions.Instance.EndsWith("/"))
313+
applicationOptions.Instance += "/";
314+
315+
string authority ;
313316
IConfidentialClientApplication app = null;
314317

315318
if (microsoftIdentityOptions.IsB2C)
316319
{
317-
authority = $"{applicationOptions.Instance.TrimEnd('/')}/tfp/{microsoftIdentityOptions.Domain}/{microsoftIdentityOptions.DefaultUserFlow}";
320+
authority = $"{applicationOptions.Instance}tfp/{microsoftIdentityOptions.Domain}/{microsoftIdentityOptions.DefaultUserFlow}";
318321
app = ConfidentialClientApplicationBuilder
319322
.CreateWithApplicationOptions(applicationOptions)
320323
.WithRedirectUri(currentUri)
321324
.WithB2CAuthority(authority)
322325
.Build();
323326
}
324-
325327
else
326328
{
327-
authority = $"{applicationOptions.Instance.TrimEnd('/')}/{applicationOptions.TenantId}/";
329+
authority = $"{applicationOptions.Instance}{applicationOptions.TenantId}/";
328330
app = ConfidentialClientApplicationBuilder
329331
.CreateWithApplicationOptions(applicationOptions)
330332
.WithRedirectUri(currentUri)
331333
.WithAuthority(authority)
332334
.Build();
333335
}
334336

335-
336-
337337
// Initialize token cache providers
338338
_tokenCacheProvider?.InitializeAsync(app.AppTokenCache);
339339
_tokenCacheProvider?.InitializeAsync(app.UserTokenCache);

Microsoft.Identity.Web/WebApiServiceCollectionExtensions.cs

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -166,15 +166,12 @@ public static AuthenticationBuilder AddProtectedWebApi(
166166
if (string.IsNullOrWhiteSpace(options.Authority))
167167
options.Authority = AuthorityHelpers.BuildAuthority(microsoftIdentityOptions);
168168

169-
if (!AuthorityHelpers.IsV2Authority(options.Authority))
170-
options.Authority += "/v2.0";
169+
// This is an Microsoft identity platform Web API
170+
EnsureAuthorityIsV2_0(options);
171171

172-
// The valid audiences are both the Client ID (options.Audience) and api://{ClientID}
173-
options.TokenValidationParameters.ValidAudiences = new string[]
174-
{
175-
// If the developer doesn't set the Audience on JwtBearerOptions, use ClientId from MicrosoftIdentityOptions
176-
options.Audience, $"api://{options.Audience ?? microsoftIdentityOptions.ClientId}"
177-
};
172+
// The valid audience could be given as Client Id or as Uri.
173+
// If it does not start with 'api://', this variant is added to the list of valid audiences.
174+
EnsureValidAudiencesContainsApiGuidIfGuidProvided(options);
178175

179176
// If the developer registered an IssuerValidator, do not overwrite it
180177
if (options.TokenValidationParameters.IssuerValidator == null)
@@ -248,5 +245,37 @@ public static IServiceCollection AddProtectedWebApiCallsProtectedWebApi(
248245

249246
return services;
250247
}
248+
249+
/// <summary>
250+
/// Ensures that the authority is a v2.0 authority
251+
/// </summary>
252+
/// <param name="options">Jwt bearer options read from the config file
253+
/// or set by the developper, for which we want to ensure the authority
254+
/// is a v2.0 authority</param>
255+
internal static void EnsureAuthorityIsV2_0(JwtBearerOptions options)
256+
{
257+
var authority = options.Authority.Trim().TrimEnd('/');
258+
if (!authority.EndsWith("v2.0"))
259+
authority += "/v2.0";
260+
options.Authority = authority;
261+
}
262+
263+
264+
/// <summary>
265+
/// Ensure that if the audience is a GUID, api://{audience} is also added
266+
/// as a valid audience (this is the default App ID URL in the app registration
267+
/// portal)
268+
/// </summary>
269+
/// <param name="options">Jwt bearer options for which to ensure that
270+
/// api://GUID is a valid audience</param>
271+
internal static void EnsureValidAudiencesContainsApiGuidIfGuidProvided(JwtBearerOptions options)
272+
{
273+
var validAudiences = new List<string> { options.Audience };
274+
if (!options.Audience.StartsWith("api://", StringComparison.OrdinalIgnoreCase)
275+
&& Guid.TryParse(options.Audience, out _))
276+
validAudiences.Add($"api://{options.Audience}");
277+
278+
options.TokenValidationParameters.ValidAudiences = validAudiences;
279+
}
251280
}
252-
}
281+
}

0 commit comments

Comments
 (0)