Skip to content

Commit

Permalink
Update flows
Browse files Browse the repository at this point in the history
  • Loading branch information
damienbod committed Mar 27, 2022
1 parent 216e661 commit 248c714
Show file tree
Hide file tree
Showing 15 changed files with 423 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
/DecryptionCertificates/LogsApiDecryptionCertificates.txt
/DecryptionCertificates/LogsPortalDecryptionCertificates.txt
/AngularAzureADMultipleApis/AngularAzureAD/debug.log
/ClientCredentialsFlows/LogsServiceApi.txt
6 changes: 0 additions & 6 deletions BlazorWithApis/BlazorApis.sln
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorAzureADWithApis.Clien
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorAzureADWithApis.Shared", "BlazorAzureADWithApis\Shared\BlazorAzureADWithApis.Shared.csproj", "{E875E49E-FB31-446F-8B65-60BDC999AEAD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceApiClientConsole", "ServiceApiClientConsole\ServiceApiClientConsole.csproj", "{2E3A9029-51F0-48A2-94BB-0BE801AE0948}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -47,10 +45,6 @@ Global
{E875E49E-FB31-446F-8B65-60BDC999AEAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E875E49E-FB31-446F-8B65-60BDC999AEAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E875E49E-FB31-446F-8B65-60BDC999AEAD}.Release|Any CPU.Build.0 = Release|Any CPU
{2E3A9029-51F0-48A2-94BB-0BE801AE0948}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E3A9029-51F0-48A2-94BB-0BE801AE0948}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E3A9029-51F0-48A2-94BB-0BE801AE0948}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E3A9029-51F0-48A2-94BB-0BE801AE0948}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
31 changes: 31 additions & 0 deletions ClientCredentialsFlows/ServiceApi.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32228.430
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceApi", "ServiceApi\ServiceApi.csproj", "{FA20B046-FE9D-4466-9A1E-A295CD25A362}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceApiClientConsole", "ServiceApiClientConsole\ServiceApiClientConsole.csproj", "{1FA1A8F9-16CF-49B5-AD72-3D6D273BF185}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FA20B046-FE9D-4466-9A1E-A295CD25A362}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA20B046-FE9D-4466-9A1E-A295CD25A362}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA20B046-FE9D-4466-9A1E-A295CD25A362}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA20B046-FE9D-4466-9A1E-A295CD25A362}.Release|Any CPU.Build.0 = Release|Any CPU
{1FA1A8F9-16CF-49B5-AD72-3D6D273BF185}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1FA1A8F9-16CF-49B5-AD72-3D6D273BF185}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1FA1A8F9-16CF-49B5-AD72-3D6D273BF185}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1FA1A8F9-16CF-49B5-AD72-3D6D273BF185}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5EFBDAAA-4577-45E1-82A2-858CF42B1D78}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace ServiceApi.Controllers;

[Authorize(Policy = "ValidateAccessTokenPolicy", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
[Route("[controller]")]
public class ApiForServiceDataController : ControllerBase
{
[HttpGet]
public IEnumerable<string> Get()
{
return new List<string> { "app-app Service API data 1", "service API data 2" };
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace ServiceApi;

public class HasServiceApiRoleHandler : AuthorizationHandler<HasServiceApiRoleRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasServiceApiRoleRequirement requirement)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (requirement == null)
throw new ArgumentNullException(nameof(requirement));

var roleClaims = context.User.Claims.Where(t => t.Type == "roles");

if (roleClaims != null && HasServiceApiRole(roleClaims))
{
context.Succeed(requirement);
}

return Task.CompletedTask;
}

private static bool HasServiceApiRole(IEnumerable<Claim> roleClaims)
{
// we could also validate the "access_as_application" scope
foreach (var role in roleClaims)
{
if ("service-api" == role.Value)
{
return true;
}
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Microsoft.AspNetCore.Authorization;

namespace ServiceApi;

public class HasServiceApiRoleRequirement : IAuthorizationRequirement { }
52 changes: 52 additions & 0 deletions ClientCredentialsFlows/ServiceApi/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Events;
using Serilog.Sinks.SystemConsole.Themes;
using System;


namespace ServiceApi;

public class Program
{
public static int Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateLogger();

try
{
Log.Information("Starting web host");
CreateHostBuilder(args).Build().Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
.Enrich.FromLogContext()
.WriteTo.File("../LogsServiceApi.txt")
.WriteTo.Console(theme: AnsiConsoleTheme.Code)
)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
20 changes: 20 additions & 0 deletions ClientCredentialsFlows/ServiceApi/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "https://localhost:44324",
"sslPort": 44324
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
20 changes: 20 additions & 0 deletions ClientCredentialsFlows/ServiceApi/ServiceApi.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<WebProject_DirectoryAccessLevelKey>1</WebProject_DirectoryAccessLevelKey>
<UserSecretsId>196b270c-b0c0-4b90-8f04-d3108e701d51</UserSecretsId>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Identity.Web" Version="1.23.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.0" />
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog.AspNetCore" Version="5.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
</ItemGroup>

</Project>
126 changes: 126 additions & 0 deletions ClientCredentialsFlows/ServiceApi/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
using System;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Logging;
using Microsoft.OpenApi.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Serilog;

namespace ServiceApi;

public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
IdentityModelEventSource.ShowPII = true;
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

services.AddSingleton<IAuthorizationHandler, HasServiceApiRoleHandler>();

services.AddMicrosoftIdentityWebApiAuthentication(Configuration);

services.AddControllers();

services.AddAuthorization(options =>
{
options.AddPolicy("ValidateAccessTokenPolicy", validateAccessTokenPolicy =>
{
validateAccessTokenPolicy.Requirements.Add(new HasServiceApiRoleRequirement());

// Validate id of application for which the token was created
// In this case the CC client application
validateAccessTokenPolicy.RequireClaim("azp", "b178f3a5-7588-492a-924f-72d7887b7e48");

// only allow tokens which used "Private key JWT Client authentication"
// // https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens
// Indicates how the client was authenticated. For a public client, the value is "0".
// If client ID and client secret are used, the value is "1".
// If a client certificate was used for authentication, the value is "2".
validateAccessTokenPolicy.RequireClaim("azpacr", "1");
});
});

services.AddSwaggerGen(c =>
{
// add JWT Authentication
var securityScheme = new OpenApiSecurityScheme
{
Name = "JWT Authentication",
Description = "Enter JWT Bearer token **_only_**",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer", // must be lower case
BearerFormat = "JWT",
Reference = new OpenApiReference
{
Id = JwtBearerDefaults.AuthenticationScheme,
Type = ReferenceType.SecurityScheme
}
};
c.AddSecurityDefinition(securityScheme.Reference.Id, securityScheme);
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{securityScheme, Array.Empty<string>()}
});

c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "Service API One",
Version = "v1",
Description = "User API One",
Contact = new OpenApiContact
{
Name = "damienbod",
Email = string.Empty,
Url = new Uri("https://damienbod.com/"),
},
});
});

}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Service API One");
c.RoutePrefix = string.Empty;
});

// https://nblumhardt.com/2019/10/serilog-in-aspnetcore-3/
// https://nblumhardt.com/2019/10/serilog-mvc-logging/
app.UseSerilogRequestLogging();

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
16 changes: 16 additions & 0 deletions ClientCredentialsFlows/ServiceApi/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "damienbodhotmail.onmicrosoft.com",
"TenantId": "7ff95b15-dc21-4ba6-bc92-824856578fc1",
"ClientId": "b178f3a5-7588-492a-924f-72d7887b7e48"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Loading

0 comments on commit 248c714

Please sign in to comment.