Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Microsoft.Identity.Web.sln
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphServiceClientTests", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimulateOidc", "tests\IntegrationTests\SimulateOidc\SimulateOidc.csproj", "{9014A1C1-7552-4950-AB86-7BE97B301701}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ciam-webapp-calls-api", "Ciam-webapp-calls-api", "{550A2811-1E95-4381-967D-97CC2409B715}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "myWebApi", "tests\DevApps\ciam\myWebApi\myWebApi.csproj", "{123D0BD0-1896-498A-8641-C6E80D070968}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "myWebApp", "tests\DevApps\ciam\myWebApp\myWebApp.csproj", "{1C23A824-A9D3-46BC-822A-9BA3DE00CEB8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -391,6 +397,14 @@ Global
{9014A1C1-7552-4950-AB86-7BE97B301701}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9014A1C1-7552-4950-AB86-7BE97B301701}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9014A1C1-7552-4950-AB86-7BE97B301701}.Release|Any CPU.Build.0 = Release|Any CPU
{123D0BD0-1896-498A-8641-C6E80D070968}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{123D0BD0-1896-498A-8641-C6E80D070968}.Debug|Any CPU.Build.0 = Debug|Any CPU
{123D0BD0-1896-498A-8641-C6E80D070968}.Release|Any CPU.ActiveCfg = Release|Any CPU
{123D0BD0-1896-498A-8641-C6E80D070968}.Release|Any CPU.Build.0 = Release|Any CPU
{1C23A824-A9D3-46BC-822A-9BA3DE00CEB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1C23A824-A9D3-46BC-822A-9BA3DE00CEB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C23A824-A9D3-46BC-822A-9BA3DE00CEB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C23A824-A9D3-46BC-822A-9BA3DE00CEB8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -469,6 +483,9 @@ Global
{608F0E0B-A52D-4E0F-9B1A-BA9BDA866484} = {1DDE1AAC-5AE6-4725-94B6-A26C58D3423F}
{F686A507-CAC6-4349-9112-27F5AEFBF12B} = {A7B1AE31-4E89-42A0-8264-FBEA795AB7D2}
{9014A1C1-7552-4950-AB86-7BE97B301701} = {A7B1AE31-4E89-42A0-8264-FBEA795AB7D2}
{550A2811-1E95-4381-967D-97CC2409B715} = {7786D2DD-9EE4-42E1-B587-740A2E15C41D}
{123D0BD0-1896-498A-8641-C6E80D070968} = {550A2811-1E95-4381-967D-97CC2409B715}
{1C23A824-A9D3-46BC-822A-9BA3DE00CEB8} = {550A2811-1E95-4381-967D-97CC2409B715}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {104367F1-CE75-4F40-B32F-F14853973187}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Linq;
using System;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;

Expand All @@ -23,7 +25,22 @@ public void PostConfigure(
#endif
JwtBearerOptions options)
{
MergedOptions.UpdateMergedOptionsFromJwtBearerOptions(options, _mergedOptionsMonitor.Get(name ?? string.Empty));
MergedOptions mergedOptions = _mergedOptionsMonitor.Get(name ?? string.Empty);

// Take into account extra query parameters
UpdateOptionsMetadata(options, mergedOptions);
MergedOptions.UpdateMergedOptionsFromJwtBearerOptions(options, mergedOptions);
}

private static void UpdateOptionsMetadata(JwtBearerOptions options, MergedOptions mergedOptions)
{
options.MetadataAddress ??= options.Authority + "/.well-known/openid-configuration";

if (mergedOptions.ExtraQueryParameters != null)
{
options.MetadataAddress += options.MetadataAddress.Contains('?', StringComparison.OrdinalIgnoreCase) ? "&" : "?";
options.MetadataAddress += string.Join("&", mergedOptions.ExtraQueryParameters.Select(p => $"{p.Key}={p.Value}"));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,17 +173,17 @@ private static void AddMicrosoftIdentityWebApiImplementation(
msIdOptionsMonitor.Get(jwtBearerScheme); // needed for firing the PostConfigure.
MergedOptions mergedOptions = mergedOptionsMonitor.Get(jwtBearerScheme);

// Process CIAM tenants
if (mergedOptions.Authority != null)
{
mergedOptions.Authority = AuthorityHelpers.BuildCiamAuthorityIfNeeded(mergedOptions.Authority);
if (mergedOptions.ExtraQueryParameters != null)
{
options.MetadataAddress = mergedOptions.Authority + "/.well-known/openid-configuration?" + string.Join("&", mergedOptions.ExtraQueryParameters.Select(p => $"{p.Key}={p.Value}"));
}
options.Authority = mergedOptions.Authority;
}

// Validate the configuration of the web API
MergedOptionsValidation.Validate(mergedOptions);

// Ensure a well-formed authority was provided
if (string.IsNullOrWhiteSpace(options.Authority))
{
options.Authority = AuthorityHelpers.BuildAuthority(mergedOptions);
Expand Down Expand Up @@ -253,6 +253,38 @@ private static void AddMicrosoftIdentityWebApiImplementation(
});
}

/*
private static void UpdateOptionsMetadata(JwtBearerOptions options, MergedOptions mergedOptions)
{
if (mergedOptions.ExtraQueryParameters != null)
{
if (options.MetadataAddress == null)
{
options.MetadataAddress = options.Authority + "/.well-known/openid-configuration?" + string.Join("&", mergedOptions.ExtraQueryParameters.Select(p => $"{p.Key}={p.Value}"));

}
else
{
if (options.MetadataAddress.Contains('?', StringComparison.OrdinalIgnoreCase))
{
options.MetadataAddress += "&" + string.Join("&", mergedOptions.ExtraQueryParameters.Select(p => $"{p.Key}={p.Value}"));
}
else
{
options.MetadataAddress += "?" + string.Join("&", mergedOptions.ExtraQueryParameters.Select(p => $"{p.Key}={p.Value}"));
}
}
}
else
{
if (options.MetadataAddress == null)
{
options.MetadataAddress = options.Authority + "/.well-known/openid-configuration";
}
}
}
*/

/// <summary>
/// In order to ensure that the Web API only accepts tokens from tenants where it has been consented and provisioned, a token that
/// has neither Roles nor Scopes claims should be rejected. To enforce that rule, add an event handler to the beginning of the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web.Resource;

namespace myWebApi.Controllers;

[Authorize]
[ApiController]
[Route("[controller]")]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

private readonly ILogger<WeatherForecastController> _logger;

public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}

[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
31 changes: 31 additions & 0 deletions tests/DevApps/ciam/myWebApi/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();
31 changes: 31 additions & 0 deletions tests/DevApps/ciam/myWebApi/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:32434",
"sslPort": 44385
}
},
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7082;http://localhost:5299",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
12 changes: 12 additions & 0 deletions tests/DevApps/ciam/myWebApi/WeatherForecast.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace myWebApi;

public class WeatherForecast
{
public DateOnly Date { get; set; }

public int TemperatureC { get; set; }

public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

public string? Summary { get; set; }
}
8 changes: 8 additions & 0 deletions tests/DevApps/ciam/myWebApi/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
15 changes: 15 additions & 0 deletions tests/DevApps/ciam/myWebApi/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"AzureAd": {
"ClientId": "63e6d091-0e6d-4c8b-be67-d405e02ae3d8",
"Scopes": "access_as_user",
"CallbackPath": "/signin-oidc",
"Authority": "https://TrialTenantJmprieur.ciamlogin.com/"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
24 changes: 24 additions & 0 deletions tests/DevApps/ciam/myWebApi/myWebApi.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFrameworks>net7.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspnet-myWebApi-17be892d-3bb3-4282-92e2-301b02c86ed6</UserSecretsId>
<UseWIP>true</UseWIP>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.10" />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.0.1

should use the Directory.Build.Props for the test, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll address this later (with the fact that it's still using IDownstreamWebApi. It's straight from the project templates)

<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>

<ItemGroup Condition="'$(UseWIP)' == 'false' ">
<PackageReference Include="Microsoft.Identity.Web" Version="2.13.3" />
</ItemGroup>

<ItemGroup Condition="'$(UseWIP)' == 'true' ">
<ProjectReference Include="..\..\..\..\src\Microsoft.Identity.Web\Microsoft.Identity.Web.csproj" />
</ItemGroup>

</Project>
26 changes: 26 additions & 0 deletions tests/DevApps/ciam/myWebApp/Pages/Error.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@page
@model ErrorModel
@{
ViewData["Title"] = "Error";
}

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}

<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
27 changes: 27 additions & 0 deletions tests/DevApps/ciam/myWebApp/Pages/Error.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace myWebApp.Pages;

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }

public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

private readonly ILogger<ErrorModel> _logger;

public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}

public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}

14 changes: 14 additions & 0 deletions tests/DevApps/ciam/myWebApp/Pages/Index.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}

<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<div>Api result</div>

<div>@ViewData["ApiResult"]</div>
Loading