Browse Source

Merge pull request #2012 from erjain/net7-duende-fix

update to Net7 and Duende IdentityServer 6.2
pull/2044/head
Tarun Jain 2 years ago
committed by GitHub
parent
commit
e15a62270c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
187 changed files with 3149 additions and 5070 deletions
  1. +1
    -1
      .github/workflows/catalog-api.yml
  2. +1
    -1
      .github/workflows/ordering-api.yml
  3. +2
    -2
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile
  4. +1
    -1
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile.develop
  5. +1
    -0
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/GlobalUsings.cs
  6. +14
    -13
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj
  7. +21
    -2
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs
  8. +2
    -2
      src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile
  9. +1
    -1
      src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile.develop
  10. +1
    -0
      src/ApiGateways/Web.Bff.Shopping/aggregator/GlobalUsings.cs
  11. +11
    -9
      src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs
  12. +15
    -14
      src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj
  13. +3
    -3
      src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj
  14. +4
    -4
      src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj
  15. +1
    -1
      src/BuildingBlocks/EventBus/EventBus/EventBus.csproj
  16. +5
    -5
      src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj
  17. +4
    -4
      src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj
  18. +5
    -5
      src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj
  19. +8
    -8
      src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj
  20. +28
    -27
      src/Services/Basket/Basket.API/Basket.API.csproj
  21. +2
    -2
      src/Services/Basket/Basket.API/Dockerfile
  22. +1
    -1
      src/Services/Basket/Basket.API/Dockerfile.develop
  23. +2
    -1
      src/Services/Basket/Basket.API/GlobalUsings.cs
  24. +1
    -1
      src/Services/Basket/Basket.API/Program.cs
  25. +13
    -6
      src/Services/Basket/Basket.API/Startup.cs
  26. +8
    -8
      src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj
  27. +9
    -9
      src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj
  28. +33
    -30
      src/Services/Catalog/Catalog.API/Catalog.API.csproj
  29. +2
    -2
      src/Services/Catalog/Catalog.API/Dockerfile
  30. +1
    -1
      src/Services/Catalog/Catalog.API/Dockerfile.develop
  31. +1
    -1
      src/Services/Catalog/Catalog.API/Program.cs
  32. +6
    -6
      src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj
  33. +7
    -7
      src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj
  34. +0
    -31
      src/Services/Identity/Identity.API/Certificate/Certificate.cs
  35. BIN
      src/Services/Identity/Identity.API/Certificate/idsrv3test.pfx
  36. +48
    -32
      src/Services/Identity/Identity.API/Configuration/Config.cs
  37. +0
    -299
      src/Services/Identity/Identity.API/Controllers/AccountController.cs
  38. +0
    -131
      src/Services/Identity/Identity.API/Controllers/ConsentController.cs
  39. +0
    -46
      src/Services/Identity/Identity.API/Controllers/HomeController.cs
  40. +12
    -13
      src/Services/Identity/Identity.API/Data/ApplicationDbContext.cs
  41. +0
    -218
      src/Services/Identity/Identity.API/Data/ApplicationDbContextSeed.cs
  42. +0
    -73
      src/Services/Identity/Identity.API/Data/ConfigurationDbContextSeed.cs
  43. +10
    -10
      src/Services/Identity/Identity.API/Data/Migrations/20210914100206_InitialMigration.Designer.cs
  44. +1
    -1
      src/Services/Identity/Identity.API/Data/Migrations/20210914100206_InitialMigration.cs
  45. +9
    -9
      src/Services/Identity/Identity.API/Data/Migrations/ApplicationDbContextModelSnapshot.cs
  46. +2
    -2
      src/Services/Identity/Identity.API/Devspaces/DevspacesRedirectUriValidator.cs
  47. +2
    -2
      src/Services/Identity/Identity.API/Dockerfile
  48. +1
    -1
      src/Services/Identity/Identity.API/Dockerfile.develop
  49. +0
    -46
      src/Services/Identity/Identity.API/Extensions/LinqSelectExtensions.cs
  50. +0
    -20
      src/Services/Identity/Identity.API/Factories/ApplicationDbContextFactory.cs
  51. +0
    -21
      src/Services/Identity/Identity.API/Factories/ConfigurationDbContextFactory.cs
  52. +0
    -21
      src/Services/Identity/Identity.API/Factories/PersistedGrantDbContextFactory.cs
  53. +14
    -14
      src/Services/Identity/Identity.API/GlobalUsings.cs
  54. +60
    -52
      src/Services/Identity/Identity.API/Identity.API.csproj
  55. +0
    -911
      src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20210813072543_InitialMigration.Designer.cs
  56. +0
    -607
      src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20210813072543_InitialMigration.cs
  57. +0
    -909
      src/Services/Identity/Identity.API/Migrations/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs
  58. +0
    -108
      src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20210813072513_InitialMigration.Designer.cs
  59. +0
    -75
      src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20210813072513_InitialMigration.cs
  60. +0
    -106
      src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/PersistedGrantDbContextModelSnapshot.cs
  61. +0
    -10
      src/Services/Identity/Identity.API/Models/AccountViewModels/ConsentInputModel.cs
  62. +0
    -61
      src/Services/Identity/Identity.API/Models/AccountViewModels/ConsentViewModel.cs
  63. +7
    -0
      src/Services/Identity/Identity.API/Models/AccountViewModels/RedirectViewModel.cs
  64. +13
    -0
      src/Services/Identity/Identity.API/Models/ConsentViewModels/ConsentInputModel.cs
  65. +12
    -0
      src/Services/Identity/Identity.API/Models/ConsentViewModels/ConsentOptions.cs
  66. +15
    -0
      src/Services/Identity/Identity.API/Models/ConsentViewModels/ConsentViewModel.cs
  67. +17
    -0
      src/Services/Identity/Identity.API/Models/ConsentViewModels/ProcessConsentResult.cs
  68. +12
    -0
      src/Services/Identity/Identity.API/Models/ConsentViewModels/ScopeViewModel.cs
  69. +58
    -54
      src/Services/Identity/Identity.API/Program.cs
  70. +117
    -0
      src/Services/Identity/Identity.API/ProgramExtensions.cs
  71. +341
    -0
      src/Services/Identity/Identity.API/Quickstart/Account/AccountController.cs
  72. +16
    -0
      src/Services/Identity/Identity.API/Quickstart/Account/AccountOptions.cs
  73. +238
    -0
      src/Services/Identity/Identity.API/Quickstart/Account/ExternalController.cs
  74. +10
    -0
      src/Services/Identity/Identity.API/Quickstart/Account/ExternalProvider.cs
  75. +18
    -0
      src/Services/Identity/Identity.API/Quickstart/Account/LoggedOutViewModel.cs
  76. +15
    -0
      src/Services/Identity/Identity.API/Quickstart/Account/LoginInputModel.cs
  77. +17
    -0
      src/Services/Identity/Identity.API/Quickstart/Account/LoginViewModel.cs
  78. +10
    -0
      src/Services/Identity/Identity.API/Quickstart/Account/LogoutInputModel.cs
  79. +10
    -0
      src/Services/Identity/Identity.API/Quickstart/Account/LogoutViewModel.cs
  80. +11
    -0
      src/Services/Identity/Identity.API/Quickstart/Account/RedirectViewModel.cs
  81. +247
    -0
      src/Services/Identity/Identity.API/Quickstart/Consent/ConsentController.cs
  82. +14
    -0
      src/Services/Identity/Identity.API/Quickstart/Consent/ConsentInputModel.cs
  83. +15
    -0
      src/Services/Identity/Identity.API/Quickstart/Consent/ConsentOptions.cs
  84. +16
    -0
      src/Services/Identity/Identity.API/Quickstart/Consent/ConsentViewModel.cs
  85. +17
    -0
      src/Services/Identity/Identity.API/Quickstart/Consent/ProcessConsentResult.cs
  86. +15
    -0
      src/Services/Identity/Identity.API/Quickstart/Consent/ScopeViewModel.cs
  87. +10
    -0
      src/Services/Identity/Identity.API/Quickstart/Device/DeviceAuthorizationInputModel.cs
  88. +11
    -0
      src/Services/Identity/Identity.API/Quickstart/Device/DeviceAuthorizationViewModel.cs
  89. +214
    -0
      src/Services/Identity/Identity.API/Quickstart/Device/DeviceController.cs
  90. +22
    -0
      src/Services/Identity/Identity.API/Quickstart/Diagnostics/DiagnosticsController.cs
  91. +28
    -0
      src/Services/Identity/Identity.API/Quickstart/Diagnostics/DiagnosticsViewModel.cs
  92. +22
    -0
      src/Services/Identity/Identity.API/Quickstart/Extensions.cs
  93. +85
    -0
      src/Services/Identity/Identity.API/Quickstart/Grants/GrantsController.cs
  94. +23
    -0
      src/Services/Identity/Identity.API/Quickstart/Grants/GrantsViewModel.cs
  95. +18
    -0
      src/Services/Identity/Identity.API/Quickstart/Home/ErrorViewModel.cs
  96. +63
    -0
      src/Services/Identity/Identity.API/Quickstart/Home/HomeController.cs
  97. +52
    -0
      src/Services/Identity/Identity.API/Quickstart/SecurityHeadersAttribute.cs
  98. +124
    -0
      src/Services/Identity/Identity.API/SeedData.cs
  99. +0
    -2
      src/Services/Identity/Identity.API/Setup/Users.csv
  100. BIN
      src/Services/Identity/Identity.API/Setup/images.zip

+ 1
- 1
.github/workflows/catalog-api.yml View File

@ -22,7 +22,7 @@ on:
env: env:
SERVICE: catalog-api SERVICE: catalog-api
IMAGE: catalog.api IMAGE: catalog.api
DOTNET_VERSION: 6.0.x
DOTNET_VERSION: 7.0.x
PROJECT_PATH: Services/Catalog/Catalog.API PROJECT_PATH: Services/Catalog/Catalog.API
TESTS_PATH: Services/Catalog/Catalog.UnitTests TESTS_PATH: Services/Catalog/Catalog.UnitTests


+ 1
- 1
.github/workflows/ordering-api.yml View File

@ -22,7 +22,7 @@ on:
env: env:
SERVICE: ordering-api SERVICE: ordering-api
IMAGE: ordering.api IMAGE: ordering.api
DOTNET_VERSION: 6.0.x
DOTNET_VERSION: 7.0.x
PROJECT_PATH: Services/Ordering/Ordering.API PROJECT_PATH: Services/Ordering/Ordering.API
TESTS_PATH: Services/Ordering/Ordering.UnitTests TESTS_PATH: Services/Ordering/Ordering.UnitTests


+ 2
- 2
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile View File

@ -1,8 +1,8 @@
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src WORKDIR /src
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles # It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles


+ 1
- 1
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile.develop View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:6.0
FROM mcr.microsoft.com/dotnet/sdk:7.0
ARG BUILD_CONFIGURATION=Debug ARG BUILD_CONFIGURATION=Debug
ENV ASPNETCORE_ENVIRONMENT=Development ENV ASPNETCORE_ENVIRONMENT=Development
ENV DOTNET_USE_POLLING_FILE_WATCHER=true ENV DOTNET_USE_POLLING_FILE_WATCHER=true


+ 1
- 0
src/ApiGateways/Mobile.Bff.Shopping/aggregator/GlobalUsings.cs View File

@ -39,3 +39,4 @@ global using System.Text.Json;
global using System.Threading.Tasks; global using System.Threading.Tasks;
global using System.Threading; global using System.Threading;
global using System; global using System;
global using Microsoft.IdentityModel.Tokens;

+ 14
- 13
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<AssemblyName>Mobile.Shopping.HttpAggregator</AssemblyName> <AssemblyName>Mobile.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator</RootNamespace> <RootNamespace>Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator</RootNamespace>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath> <DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
@ -14,19 +14,20 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="5.0.1" />
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Core" Version="2.34.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.9" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="6.0.3" />
<PackageReference Include="Google.Protobuf" Version="3.21.9" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.50.0" />
<PackageReference Include="Grpc.Core" Version="2.46.5" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.50.0" />
<PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.2" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="7.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 21
- 2
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs View File

@ -1,4 +1,7 @@
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator;
public class Startup public class Startup
{ {
@ -86,7 +89,7 @@ public static class ServiceCollectionExtensions
services.AddSwaggerGen(options => services.AddSwaggerGen(options =>
{ {
options.DescribeAllEnumsAsStrings();
//options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new OpenApiInfo options.SwaggerDoc("v1", new OpenApiInfo
{ {
Title = "Shopping Aggregator for Mobile Clients", Title = "Shopping Aggregator for Mobile Clients",
@ -143,10 +146,26 @@ public static class ServiceCollectionExtensions
options.Authority = identityUrl; options.Authority = identityUrl;
options.RequireHttpsMetadata = false; options.RequireHttpsMetadata = false;
options.Audience = "mobileshoppingagg"; options.Audience = "mobileshoppingagg";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
}); });
return services; return services;
} }
public static IServiceCollection AddCustomAuthorization(this IServiceCollection services, IConfiguration configuration)
{
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "mobileshoppingagg");
});
});
return services;
}
public static IServiceCollection AddHttpServices(this IServiceCollection services) public static IServiceCollection AddHttpServices(this IServiceCollection services)
{ {


+ 2
- 2
src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile View File

@ -1,8 +1,8 @@
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src WORKDIR /src
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles # It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles


+ 1
- 1
src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile.develop View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:6.0
FROM mcr.microsoft.com/dotnet/sdk:7.0
ARG BUILD_CONFIGURATION=Debug ARG BUILD_CONFIGURATION=Debug
ENV ASPNETCORE_ENVIRONMENT=Development ENV ASPNETCORE_ENVIRONMENT=Development
ENV DOTNET_USE_POLLING_FILE_WATCHER=true ENV DOTNET_USE_POLLING_FILE_WATCHER=true


+ 1
- 0
src/ApiGateways/Web.Bff.Shopping/aggregator/GlobalUsings.cs View File

@ -39,3 +39,4 @@ global using System.Text.Json;
global using System.Threading.Tasks; global using System.Threading.Tasks;
global using System.Threading; global using System.Threading;
global using System; global using System;
global using Microsoft.IdentityModel.Tokens;

+ 11
- 9
src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs View File

@ -1,4 +1,7 @@
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator;
public class Startup public class Startup
{ {
@ -22,6 +25,7 @@ public class Startup
services.AddCustomMvc(Configuration) services.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration) .AddCustomAuthentication(Configuration)
//.AddCustomAuthorization(Configuration)
.AddDevspaces() .AddDevspaces()
.AddApplicationServices() .AddApplicationServices()
.AddGrpcServices(); .AddGrpcServices();
@ -83,22 +87,20 @@ public static class ServiceCollectionExtensions
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
var identityUrl = configuration.GetValue<string>("urls:identity"); var identityUrl = configuration.GetValue<string>("urls:identity");
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
services.AddAuthentication("Bearer")
.AddJwtBearer(options => .AddJwtBearer(options =>
{ {
options.Authority = identityUrl; options.Authority = identityUrl;
options.RequireHttpsMetadata = false; options.RequireHttpsMetadata = false;
options.Audience = "webshoppingagg"; options.Audience = "webshoppingagg";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
}); });
return services; return services;
} }
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
{ {
services.AddOptions(); services.AddOptions();
@ -109,7 +111,7 @@ public static class ServiceCollectionExtensions
services.AddSwaggerGen(options => services.AddSwaggerGen(options =>
{ {
options.DescribeAllEnumsAsStrings();
//options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new OpenApiInfo options.SwaggerDoc("v1", new OpenApiInfo
{ {


+ 15
- 14
src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<AssemblyName>Web.Shopping.HttpAggregator</AssemblyName> <AssemblyName>Web.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator</RootNamespace> <RootNamespace>Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator</RootNamespace>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath> <DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
@ -14,20 +14,21 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="5.0.1" />
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Core" Version="2.34.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.34.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.9" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="6.0.3" />
<PackageReference Include="Google.Protobuf" Version="3.21.9" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.50.0" />
<PackageReference Include="Grpc.Core" Version="2.46.5" />
<PackageReference Include="Grpc.Net.Client" Version="2.50.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.50.0" />
<PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.2" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="7.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 3
- 3
src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj View File

@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

+ 4
- 4
src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj View File

@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit" Version="2.4.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 1
- 1
src/BuildingBlocks/EventBus/EventBus/EventBus.csproj View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBus</RootNamespace> <RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBus</RootNamespace>
</PropertyGroup> </PropertyGroup>


+ 5
- 5
src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj View File

@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ</RootNamespace> <RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Autofac" Version="6.1.0" />
<PackageReference Include="Autofac" Version="6.5.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Polly" Version="7.2.1" />
<PackageReference Include="RabbitMQ.Client" Version="6.2.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="RabbitMQ.Client" Version="6.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 4
- 4
src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj View File

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus</RootNamespace> <RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Autofac" Version="6.1.0" />
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.2.1" />
<PackageReference Include="Autofac" Version="6.5.0" />
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.11.1" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 5
- 5
src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj View File

@ -1,18 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF</RootNamespace> <RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 8
- 8
src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks> <GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
</PropertyGroup> </PropertyGroup>
@ -10,16 +10,16 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.2">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.0" />
<PackageReference Include="Polly" Version="7.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" /> <PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
</ItemGroup> </ItemGroup>


+ 28
- 27
src/Services/Basket/Basket.API/Basket.API.csproj View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath> <DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks> <GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
@ -14,36 +14,37 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.12.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="7.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.25.0" />
<PackageReference Include="Azure.Identity" Version="1.5.0-beta.3" /> <PackageReference Include="Azure.Identity" Version="1.5.0-beta.3" />
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="5.1.1" />
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="5.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="5.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0-preview.1" />
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.1" />
<PackageReference Include="Azure.Identity" Version="1.4.0" />
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.34.0" />
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.18.0" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.18.0" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2-beta2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="6.0.4" />
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="6.0.4" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.2" />
<PackageReference Include="Azure.Identity" Version="1.9.0-beta.1" />
<PackageReference Include="Google.Protobuf" Version="3.21.9" />
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.50.0" />
<PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0-beta1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0-beta1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" /> <PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.24" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="7.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" /> <PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0-dev-00291" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1-dev-00876" />
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0-beta.9" />
<PackageReference Include="Serilog.Sinks.Seq" Version="4.1.0-dev-00166" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.5.0-dev-00359" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" />
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.3-dev-00260" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 2
- 2
src/Services/Basket/Basket.API/Dockerfile View File

@ -1,8 +1,8 @@
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src WORKDIR /src
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles # It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles


+ 1
- 1
src/Services/Basket/Basket.API/Dockerfile.develop View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:6.0
FROM mcr.microsoft.com/dotnet/sdk:7.0
ARG BUILD_CONFIGURATION=Debug ARG BUILD_CONFIGURATION=Debug
ENV ASPNETCORE_ENVIRONMENT=Development ENV ASPNETCORE_ENVIRONMENT=Development
ENV DOTNET_USE_POLLING_FILE_WATCHER=true ENV DOTNET_USE_POLLING_FILE_WATCHER=true


+ 2
- 1
src/Services/Basket/Basket.API/GlobalUsings.cs View File

@ -58,4 +58,5 @@ global using System.Net;
global using System.Security.Claims; global using System.Security.Claims;
global using System.Text.Json; global using System.Text.Json;
global using System.Threading.Tasks; global using System.Threading.Tasks;
global using System;
global using System;
global using Microsoft.IdentityModel.Tokens;

+ 1
- 1
src/Services/Basket/Basket.API/Program.cs View File

@ -60,7 +60,7 @@ Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
.Enrich.FromLogContext() .Enrich.FromLogContext()
.WriteTo.Console() .WriteTo.Console()
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl) .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
.WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
.WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl, null)
.ReadFrom.Configuration(configuration) .ReadFrom.Configuration(configuration)
.CreateLogger(); .CreateLogger();
} }


+ 13
- 6
src/Services/Basket/Basket.API/Startup.cs View File

@ -1,3 +1,6 @@
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
namespace Microsoft.eShopOnContainers.Services.Basket.API; namespace Microsoft.eShopOnContainers.Services.Basket.API;
public class Startup public class Startup
{ {
@ -214,16 +217,20 @@ public class Startup
var identityUrl = Configuration.GetValue<string>("IdentityUrl"); var identityUrl = Configuration.GetValue<string>("IdentityUrl");
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
services.AddAuthentication("Bearer").AddJwtBearer(options =>
{ {
options.Authority = identityUrl; options.Authority = identityUrl;
options.RequireHttpsMetadata = false; options.RequireHttpsMetadata = false;
options.Audience = "basket"; options.Audience = "basket";
options.TokenValidationParameters.ValidateAudience = false;
});
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "basket");
});
}); });
} }


+ 8
- 8
src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
@ -16,16 +16,16 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="Moq" Version="4.15.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit" Version="2.4.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 9
- 9
src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj View File

@ -1,23 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks> <GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MediatR" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.0" />
<PackageReference Include="Moq" Version="4.15.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="MediatR" Version="11.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit" Version="2.4.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 33
- 30
src/Services/Catalog/Catalog.API/Catalog.API.csproj View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<DebugType>portable</DebugType> <DebugType>portable</DebugType>
<PreserveCompilationContext>true</PreserveCompilationContext> <PreserveCompilationContext>true</PreserveCompilationContext>
<AssemblyName>Catalog.API</AssemblyName> <AssemblyName>Catalog.API</AssemblyName>
@ -41,37 +41,40 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.12.2" />
<PackageReference Include="Azure.Identity" Version="1.5.0-beta.3" />
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="5.1.1" />
<PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="5.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="5.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="5.0.3" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0-preview.1" />
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.34.0" />
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.18.0" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.18.0" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2-beta2" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.25.0" />
<PackageReference Include="Azure.Identity" Version="1.9.0-beta.1" />
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="6.0.4" />
<PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="6.1.1" />
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="6.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Google.Protobuf" Version="3.21.9" />
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.50.0" />
<PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0-beta1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0-beta1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" /> <PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.24" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="7.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" /> <PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0-dev-00291" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1-dev-00876" />
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0-beta.9" />
<PackageReference Include="Serilog.Sinks.Seq" Version="4.1.0-dev-00166" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" />
<PackageReference Include="System.Data.SqlClient" version="4.8.2"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0"/>
<PackageReference Include="Serilog.Settings.Configuration" Version="3.5.0-dev-00359" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" />
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.3-dev-00260" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" />
<PackageReference Include="System.Data.SqlClient" version="4.8.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 2
- 2
src/Services/Catalog/Catalog.API/Dockerfile View File

@ -1,9 +1,9 @@
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
EXPOSE 443 EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src WORKDIR /src
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles # It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles


+ 1
- 1
src/Services/Catalog/Catalog.API/Dockerfile.develop View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:6.0
FROM mcr.microsoft.com/dotnet/sdk:7.0
ARG BUILD_CONFIGURATION=Debug ARG BUILD_CONFIGURATION=Debug
ENV ASPNETCORE_ENVIRONMENT=Development ENV ASPNETCORE_ENVIRONMENT=Development
ENV DOTNET_USE_POLLING_FILE_WATCHER=true ENV DOTNET_USE_POLLING_FILE_WATCHER=true


+ 1
- 1
src/Services/Catalog/Catalog.API/Program.cs View File

@ -66,7 +66,7 @@ Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
.Enrich.FromLogContext() .Enrich.FromLogContext()
.WriteTo.Console() .WriteTo.Console()
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl) .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
.WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
.WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl,null)
.ReadFrom.Configuration(configuration) .ReadFrom.Configuration(configuration)
.CreateLogger(); .CreateLogger();
} }


+ 6
- 6
src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
@ -33,14 +33,14 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit" Version="2.4.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 7
- 7
src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj View File

@ -1,21 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks> <GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="6.0.0" />
<PackageReference Include="Moq" Version="4.15.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit" Version="2.4.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 0
- 31
src/Services/Identity/Identity.API/Certificate/Certificate.cs View File

@ -1,31 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Identity.API.Certificates
{
static class Certificate
{
public static X509Certificate2 Get()
{
var assembly = typeof(Certificate).GetTypeInfo().Assembly;
var names = assembly.GetManifestResourceNames();
/***********************************************************************************************
* Please note that here we are using a local certificate only for testing purposes. In a
* real environment the certificate should be created and stored in a secure way, which is out
* of the scope of this project.
**********************************************************************************************/
using var stream = assembly.GetManifestResourceStream("Identity.API.Certificate.idsrv3test.pfx");
return new X509Certificate2(ReadStream(stream), "idsrv3test");
}
private static byte[] ReadStream(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using MemoryStream ms = new MemoryStream();
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
}

BIN
src/Services/Identity/Identity.API/Certificate/idsrv3test.pfx View File


+ 48
- 32
src/Services/Identity/Identity.API/Configuration/Config.cs View File

@ -1,4 +1,4 @@
using IdentityServer4.Models;
using Duende.IdentityServer.Models;
namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
{ {
@ -6,7 +6,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
{ {
// ApiResources define the apis in your system // ApiResources define the apis in your system
public static IEnumerable<ApiResource> GetApis() public static IEnumerable<ApiResource> GetApis()
{
{
return new List<ApiResource> return new List<ApiResource>
{ {
new ApiResource("orders", "Orders Service"), new ApiResource("orders", "Orders Service"),
@ -18,6 +18,21 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
}; };
} }
// ApiScope is used to protect the API
//The effect is the same as that of API resources in IdentityServer 3.x
public static IEnumerable<ApiScope> GetApiScopes()
{
return new List<ApiScope>
{
new ApiScope("orders", "Orders Service"),
new ApiScope("basket", "Basket Service"),
new ApiScope("mobileshoppingagg", "Mobile Shopping Aggregator"),
new ApiScope("webshoppingagg", "Web Shopping Aggregator"),
new ApiScope("orders.signalrhub", "Ordering Signalr Hub"),
new ApiScope("webhooks", "Webhooks registration Service"),
};
}
// Identity resources are data like user ID, name, or email address of a user // Identity resources are data like user ID, name, or email address of a user
// see: http://docs.identityserver.io/en/release/configuration/resources.html // see: http://docs.identityserver.io/en/release/configuration/resources.html
public static IEnumerable<IdentityResource> GetResources() public static IEnumerable<IdentityResource> GetResources()
@ -30,7 +45,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
} }
// client want to access resources (aka scopes) // client want to access resources (aka scopes)
public static IEnumerable<Client> GetClients(Dictionary<string, string> clientsUrl)
public static IEnumerable<Client> GetClients(IConfiguration configuration)
{ {
return new List<Client> return new List<Client>
{ {
@ -41,10 +56,10 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
ClientName = "eShop SPA OpenId Client", ClientName = "eShop SPA OpenId Client",
AllowedGrantTypes = GrantTypes.Implicit, AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true, AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["Spa"]}/" },
RedirectUris = { $"{configuration["SpaClient"]}/" },
RequireConsent = false, RequireConsent = false,
PostLogoutRedirectUris = { $"{clientsUrl["Spa"]}/" },
AllowedCorsOrigins = { $"{clientsUrl["Spa"]}" },
PostLogoutRedirectUris = { $"{configuration["SpaClient"]}/" },
AllowedCorsOrigins = { $"{configuration["SpaClient"]}" },
AllowedScopes = AllowedScopes =
{ {
IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.OpenId,
@ -63,13 +78,13 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Hybrid, AllowedGrantTypes = GrantTypes.Hybrid,
//Used to retrieve the access token on the back channel. //Used to retrieve the access token on the back channel.
ClientSecrets = ClientSecrets =
{
{
new Secret("secret".Sha256()) new Secret("secret".Sha256())
}, },
RedirectUris = { clientsUrl["Xamarin"] },
RedirectUris = { configuration["XamarinCallback"] },
RequireConsent = false, RequireConsent = false,
RequirePkce = true, RequirePkce = true,
PostLogoutRedirectUris = { $"{clientsUrl["Xamarin"]}/Account/Redirecting" },
PostLogoutRedirectUris = { $"{configuration["XamarinCallback"]}/Account/Redirecting" },
//AllowedCorsOrigins = { "http://eshopxamarin" }, //AllowedCorsOrigins = { "http://eshopxamarin" },
AllowedScopes = new List<string> AllowedScopes = new List<string>
{ {
@ -91,22 +106,23 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
ClientName = "MVC Client", ClientName = "MVC Client",
ClientSecrets = new List<Secret> ClientSecrets = new List<Secret>
{ {
new Secret("secret".Sha256()) new Secret("secret".Sha256())
}, },
ClientUri = $"{clientsUrl["Mvc"]}", // public uri of the client
AllowedGrantTypes = GrantTypes.Hybrid,
ClientUri = $"{configuration["MvcClient"]}", // public uri of the client
AllowedGrantTypes = GrantTypes.Code,
AllowAccessTokensViaBrowser = false, AllowAccessTokensViaBrowser = false,
RequireConsent = false, RequireConsent = false,
AllowOfflineAccess = true, AllowOfflineAccess = true,
AlwaysIncludeUserClaimsInIdToken = true, AlwaysIncludeUserClaimsInIdToken = true,
RequirePkce = false,
RedirectUris = new List<string> RedirectUris = new List<string>
{ {
$"{clientsUrl["Mvc"]}/signin-oidc"
$"{configuration["MvcClient"]}/signin-oidc"
}, },
PostLogoutRedirectUris = new List<string> PostLogoutRedirectUris = new List<string>
{ {
$"{clientsUrl["Mvc"]}/signout-callback-oidc"
$"{configuration["MvcClient"]}/signout-callback-oidc"
}, },
AllowedScopes = new List<string> AllowedScopes = new List<string>
{ {
@ -130,19 +146,19 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
{ {
new Secret("secret".Sha256()) new Secret("secret".Sha256())
}, },
ClientUri = $"{clientsUrl["WebhooksWeb"]}", // public uri of the client
AllowedGrantTypes = GrantTypes.Hybrid,
ClientUri = $"{configuration["WebhooksWebClient"]}", // public uri of the client
AllowedGrantTypes = GrantTypes.Code,
AllowAccessTokensViaBrowser = false, AllowAccessTokensViaBrowser = false,
RequireConsent = false, RequireConsent = false,
AllowOfflineAccess = true, AllowOfflineAccess = true,
AlwaysIncludeUserClaimsInIdToken = true, AlwaysIncludeUserClaimsInIdToken = true,
RedirectUris = new List<string> RedirectUris = new List<string>
{ {
$"{clientsUrl["WebhooksWeb"]}/signin-oidc"
$"{configuration["WebhooksWebClient"]}/signin-oidc"
}, },
PostLogoutRedirectUris = new List<string> PostLogoutRedirectUris = new List<string>
{ {
$"{clientsUrl["WebhooksWeb"]}/signout-callback-oidc"
$"{configuration["WebhooksWebClient"]}/signout-callback-oidc"
}, },
AllowedScopes = new List<string> AllowedScopes = new List<string>
{ {
@ -162,18 +178,18 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
{ {
new Secret("secret".Sha256()) new Secret("secret".Sha256())
}, },
ClientUri = $"{clientsUrl["Mvc"]}", // public uri of the client
AllowedGrantTypes = GrantTypes.Hybrid,
ClientUri = $"{configuration["Mvc"]}", // public uri of the client
AllowedGrantTypes = GrantTypes.Code,
AllowAccessTokensViaBrowser = true, AllowAccessTokensViaBrowser = true,
RequireConsent = false, RequireConsent = false,
AllowOfflineAccess = true, AllowOfflineAccess = true,
RedirectUris = new List<string> RedirectUris = new List<string>
{ {
$"{clientsUrl["Mvc"]}/signin-oidc"
$"{configuration["MvcClient"]}/signin-oidc"
}, },
PostLogoutRedirectUris = new List<string> PostLogoutRedirectUris = new List<string>
{ {
$"{clientsUrl["Mvc"]}/signout-callback-oidc"
$"{configuration["MvcClient"]}/signout-callback-oidc"
}, },
AllowedScopes = new List<string> AllowedScopes = new List<string>
{ {
@ -193,8 +209,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit, AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true, AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/" },
RedirectUris = { $"{configuration["BasketApiClient"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{configuration["BasketApiClient"]}/swagger/" },
AllowedScopes = AllowedScopes =
{ {
@ -208,8 +224,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit, AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true, AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/" },
RedirectUris = { $"{configuration["OrderingApiClient"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{configuration["OrderingApiClient"]}/swagger/" },
AllowedScopes = AllowedScopes =
{ {
@ -223,8 +239,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit, AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true, AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/" },
RedirectUris = { $"{configuration["MobileShoppingAggClient"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{configuration["MobileShoppingAggClient"]}/swagger/" },
AllowedScopes = AllowedScopes =
{ {
@ -238,8 +254,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit, AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true, AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/" },
RedirectUris = { $"{configuration["WebShoppingAggClient"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{configuration["WebShoppingAggClient"]}/swagger/" },
AllowedScopes = AllowedScopes =
{ {
@ -254,8 +270,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit, AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true, AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["WebhooksApi"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["WebhooksApi"]}/swagger/" },
RedirectUris = { $"{configuration["WebhooksApiClient"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{configuration["WebhooksApiClient"]}/swagger/" },
AllowedScopes = AllowedScopes =
{ {


+ 0
- 299
src/Services/Identity/Identity.API/Controllers/AccountController.cs View File

@ -1,299 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Identity.API.Controllers
{
/// <summary>
/// This sample controller implements a typical login/logout/provision workflow for local accounts.
/// The login service encapsulates the interactions with the user data store. This data store is in-memory only and cannot be used for production!
/// The interaction service provides a way for the UI to communicate with identityserver for validation and context retrieval
/// </summary>
public class AccountController : Controller
{
//private readonly InMemoryUserLoginService _loginService;
private readonly ILoginService<ApplicationUser> _loginService;
private readonly IIdentityServerInteractionService _interaction;
private readonly IClientStore _clientStore;
private readonly ILogger<AccountController> _logger;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IConfiguration _configuration;
public AccountController(
//InMemoryUserLoginService loginService,
ILoginService<ApplicationUser> loginService,
IIdentityServerInteractionService interaction,
IClientStore clientStore,
ILogger<AccountController> logger,
UserManager<ApplicationUser> userManager,
IConfiguration configuration)
{
_loginService = loginService;
_interaction = interaction;
_clientStore = clientStore;
_logger = logger;
_userManager = userManager;
_configuration = configuration;
}
/// <summary>
/// Show login page
/// </summary>
[HttpGet]
public async Task<IActionResult> Login(string returnUrl)
{
var context = await _interaction.GetAuthorizationContextAsync(returnUrl);
if (context?.IdP != null)
{
throw new NotImplementedException("External login is not implemented!");
}
var vm = await BuildLoginViewModelAsync(returnUrl, context);
ViewData["ReturnUrl"] = returnUrl;
return View(vm);
}
/// <summary>
/// Handle postback from username/password login
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = await _loginService.FindByUsername(model.Email);
if (await _loginService.ValidateCredentials(user, model.Password))
{
var tokenLifetime = _configuration.GetValue("TokenLifetimeMinutes", 120);
var props = new AuthenticationProperties
{
ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(tokenLifetime),
AllowRefresh = true,
RedirectUri = model.ReturnUrl
};
if (model.RememberMe)
{
var permanentTokenLifetime = _configuration.GetValue("PermanentTokenLifetimeDays", 365);
props.ExpiresUtc = DateTimeOffset.UtcNow.AddDays(permanentTokenLifetime);
props.IsPersistent = true;
};
await _loginService.SignInAsync(user, props);
// make sure the returnUrl is still valid, and if yes - redirect back to authorize endpoint
if (_interaction.IsValidReturnUrl(model.ReturnUrl))
{
return Redirect(model.ReturnUrl);
}
return Redirect("~/");
}
ModelState.AddModelError("", "Invalid username or password.");
}
// something went wrong, show form with error
var vm = await BuildLoginViewModelAsync(model);
ViewData["ReturnUrl"] = model.ReturnUrl;
return View(vm);
}
private async Task<LoginViewModel> BuildLoginViewModelAsync(string returnUrl, AuthorizationRequest context)
{
var allowLocal = true;
if (context?.ClientId != null)
{
var client = await _clientStore.FindEnabledClientByIdAsync(context.ClientId);
if (client != null)
{
allowLocal = client.EnableLocalLogin;
}
}
return new LoginViewModel
{
ReturnUrl = returnUrl,
Email = context?.LoginHint,
};
}
private async Task<LoginViewModel> BuildLoginViewModelAsync(LoginViewModel model)
{
var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
var vm = await BuildLoginViewModelAsync(model.ReturnUrl, context);
vm.Email = model.Email;
vm.RememberMe = model.RememberMe;
return vm;
}
/// <summary>
/// Show logout page
/// </summary>
[HttpGet]
public async Task<IActionResult> Logout(string logoutId)
{
if (User.Identity.IsAuthenticated == false)
{
// if the user is not authenticated, then just show logged out page
return await Logout(new LogoutViewModel { LogoutId = logoutId });
}
//Test for Xamarin.
var context = await _interaction.GetLogoutContextAsync(logoutId);
if (context?.ShowSignoutPrompt == false)
{
//it's safe to automatically sign-out
return await Logout(new LogoutViewModel { LogoutId = logoutId });
}
// show the logout prompt. this prevents attacks where the user
// is automatically signed out by another malicious web page.
var vm = new LogoutViewModel
{
LogoutId = logoutId
};
return View(vm);
}
/// <summary>
/// Handle logout page postback
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout(LogoutViewModel model)
{
var idp = User?.FindFirst(JwtClaimTypes.IdentityProvider)?.Value;
if (idp != null && idp != IdentityServerConstants.LocalIdentityProvider)
{
if (model.LogoutId == null)
{
// if there's no current logout context, we need to create one
// this captures necessary info from the current logged in user
// before we signout and redirect away to the external IdP for signout
model.LogoutId = await _interaction.CreateLogoutContextAsync();
}
string url = "/Account/Logout?logoutId=" + model.LogoutId;
try
{
// hack: try/catch to handle social providers that throw
await HttpContext.SignOutAsync(idp, new AuthenticationProperties
{
RedirectUri = url
});
}
catch (Exception ex)
{
_logger.LogError(ex, "LOGOUT ERROR: {ExceptionMessage}", ex.Message);
}
}
// delete authentication cookie
await HttpContext.SignOutAsync();
await HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme);
// set this so UI rendering sees an anonymous user
HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
// get context information (client name, post logout redirect URI and iframe for federated signout)
var logout = await _interaction.GetLogoutContextAsync(model.LogoutId);
return Redirect(logout?.PostLogoutRedirectUri);
}
public async Task<IActionResult> DeviceLogOut(string redirectUrl)
{
// delete authentication cookie
await HttpContext.SignOutAsync();
// set this so UI rendering sees an anonymous user
HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
return Redirect(redirectUrl);
}
// GET: /Account/Register
[HttpGet]
[AllowAnonymous]
public IActionResult Register(string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
return View();
}
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
CardHolderName = model.User.CardHolderName,
CardNumber = model.User.CardNumber,
CardType = model.User.CardType,
City = model.User.City,
Country = model.User.Country,
Expiration = model.User.Expiration,
LastName = model.User.LastName,
Name = model.User.Name,
Street = model.User.Street,
State = model.User.State,
ZipCode = model.User.ZipCode,
PhoneNumber = model.User.PhoneNumber,
SecurityNumber = model.User.SecurityNumber
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Errors.Count() > 0)
{
AddErrors(result);
// If we got this far, something failed, redisplay form
return View(model);
}
}
if (returnUrl != null)
{
if (HttpContext.User.Identity.IsAuthenticated)
return Redirect(returnUrl);
else
if (ModelState.IsValid)
return RedirectToAction("login", "account", new { returnUrl = returnUrl });
else
return View(model);
}
return RedirectToAction("index", "home");
}
[HttpGet]
public IActionResult Redirecting()
{
return View();
}
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
}
}

+ 0
- 131
src/Services/Identity/Identity.API/Controllers/ConsentController.cs View File

@ -1,131 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Identity.API.Controllers
{
/// <summary>
/// This controller implements the consent logic
/// </summary>
public class ConsentController : Controller
{
private readonly ILogger<ConsentController> _logger;
private readonly IClientStore _clientStore;
private readonly IResourceStore _resourceStore;
private readonly IIdentityServerInteractionService _interaction;
public ConsentController(
ILogger<ConsentController> logger,
IIdentityServerInteractionService interaction,
IClientStore clientStore,
IResourceStore resourceStore)
{
_logger = logger;
_interaction = interaction;
_clientStore = clientStore;
_resourceStore = resourceStore;
}
/// <summary>
/// Shows the consent screen
/// </summary>
/// <param name="returnUrl"></param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Index(string returnUrl)
{
var vm = await BuildViewModelAsync(returnUrl);
ViewData["ReturnUrl"] = returnUrl;
if (vm != null)
{
return View("Index", vm);
}
return View("Error");
}
/// <summary>
/// Handles the consent screen postback
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Index(ConsentInputModel model)
{
// parse the return URL back to an AuthorizeRequest object
var request = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
ConsentResponse response = null;
// user clicked 'no' - send back the standard 'access_denied' response
if (model.Button == "no")
{
response = ConsentResponse.Denied;
}
// user clicked 'yes' - validate the data
else if (model.Button == "yes")
{
// if the user consented to some scope, build the response model
if (model.ScopesConsented != null && model.ScopesConsented.Any())
{
response = new ConsentResponse
{
RememberConsent = model.RememberConsent,
ScopesConsented = model.ScopesConsented
};
}
else
{
ModelState.AddModelError("", "You must pick at least one permission.");
}
}
else
{
ModelState.AddModelError("", "Invalid Selection");
}
if (response != null)
{
// communicate outcome of consent back to identityserver
await _interaction.GrantConsentAsync(request, response);
// redirect back to authorization endpoint
return Redirect(model.ReturnUrl);
}
var vm = await BuildViewModelAsync(model.ReturnUrl, model);
if (vm != null)
{
return View("Index", vm);
}
return View("Error");
}
async Task<ConsentViewModel> BuildViewModelAsync(string returnUrl, ConsentInputModel model = null)
{
var request = await _interaction.GetAuthorizationContextAsync(returnUrl);
if (request != null)
{
var client = await _clientStore.FindEnabledClientByIdAsync(request.ClientId);
if (client != null)
{
var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested);
if (resources != null && (resources.IdentityResources.Any() || resources.ApiResources.Any()))
{
return new ConsentViewModel(model, returnUrl, request, client, resources);
}
else
{
_logger.LogError("No scopes matching: {0}", request.ScopesRequested.Aggregate((x, y) => x + ", " + y));
}
}
else
{
_logger.LogError("Invalid client id: {0}", request.ClientId);
}
}
else
{
_logger.LogError("No consent request matching request: {0}", returnUrl);
}
return null;
}
}
}

+ 0
- 46
src/Services/Identity/Identity.API/Controllers/HomeController.cs View File

@ -1,46 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Identity.API.Controllers
{
public class HomeController : Controller
{
private readonly IIdentityServerInteractionService _interaction;
private readonly IOptionsSnapshot<AppSettings> _settings;
private readonly IRedirectService _redirectSvc;
public HomeController(IIdentityServerInteractionService interaction, IOptionsSnapshot<AppSettings> settings, IRedirectService redirectSvc)
{
_interaction = interaction;
_settings = settings;
_redirectSvc = redirectSvc;
}
public IActionResult Index(string returnUrl)
{
return View();
}
public IActionResult ReturnToOriginalApplication(string returnUrl)
{
if (returnUrl != null)
return Redirect(_redirectSvc.ExtractRedirectUriFromReturnUrl(returnUrl));
else
return RedirectToAction("Index", "Home");
}
/// <summary>
/// Shows the error page
/// </summary>
public async Task<IActionResult> Error(string errorId)
{
var vm = new ErrorViewModel();
// retrieve error details from identityserver
var message = await _interaction.GetErrorContextAsync(errorId);
if (message != null)
{
vm.Error = message;
}
return View("Error", vm);
}
}
}

+ 12
- 13
src/Services/Identity/Identity.API/Data/ApplicationDbContext.cs View File

@ -1,18 +1,17 @@
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data;
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{ {
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{ {
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
} }
} }

+ 0
- 218
src/Services/Identity/Identity.API/Data/ApplicationDbContextSeed.cs View File

@ -1,218 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
{
using Microsoft.Extensions.Logging;
public class ApplicationDbContextSeed
{
private readonly IPasswordHasher<ApplicationUser> _passwordHasher = new PasswordHasher<ApplicationUser>();
public async Task SeedAsync(ApplicationDbContext context, IWebHostEnvironment env,
ILogger<ApplicationDbContextSeed> logger, IOptions<AppSettings> settings, int? retry = 0)
{
int retryForAvaiability = retry.Value;
try
{
var useCustomizationData = settings.Value.UseCustomizationData;
var contentRootPath = env.ContentRootPath;
var webroot = env.WebRootPath;
if (!context.Users.Any())
{
context.Users.AddRange(useCustomizationData
? GetUsersFromFile(contentRootPath, logger)
: GetDefaultUser());
await context.SaveChangesAsync();
}
if (useCustomizationData)
{
GetPreconfiguredImages(contentRootPath, webroot, logger);
}
}
catch (Exception ex)
{
if (retryForAvaiability < 10)
{
retryForAvaiability++;
logger.LogError(ex, "EXCEPTION ERROR while migrating {DbContextName}", nameof(ApplicationDbContext));
await SeedAsync(context, env, logger, settings, retryForAvaiability);
}
}
}
private IEnumerable<ApplicationUser> GetUsersFromFile(string contentRootPath, ILogger logger)
{
string csvFileUsers = Path.Combine(contentRootPath, "Setup", "Users.csv");
if (!File.Exists(csvFileUsers))
{
return GetDefaultUser();
}
string[] csvheaders;
try
{
string[] requiredHeaders = {
"cardholdername", "cardnumber", "cardtype", "city", "country",
"email", "expiration", "lastname", "name", "phonenumber",
"username", "zipcode", "state", "street", "securitynumber",
"normalizedemail", "normalizedusername", "password"
};
csvheaders = GetHeaders(requiredHeaders, csvFileUsers);
}
catch (Exception ex)
{
logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
return GetDefaultUser();
}
List<ApplicationUser> users = File.ReadAllLines(csvFileUsers)
.Skip(1) // skip header column
.Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"))
.SelectTry(column => CreateApplicationUser(column, csvheaders))
.OnCaughtException(ex => { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
.Where(x => x != null)
.ToList();
return users;
}
private ApplicationUser CreateApplicationUser(string[] column, string[] headers)
{
if (column.Count() != headers.Count())
{
throw new Exception($"column count '{column.Count()}' not the same as headers count'{headers.Count()}'");
}
string cardtypeString = column[Array.IndexOf(headers, "cardtype")].Trim('"').Trim();
if (!int.TryParse(cardtypeString, out int cardtype))
{
throw new Exception($"cardtype='{cardtypeString}' is not a number");
}
var user = new ApplicationUser
{
CardHolderName = column[Array.IndexOf(headers, "cardholdername")].Trim('"').Trim(),
CardNumber = column[Array.IndexOf(headers, "cardnumber")].Trim('"').Trim(),
CardType = cardtype,
City = column[Array.IndexOf(headers, "city")].Trim('"').Trim(),
Country = column[Array.IndexOf(headers, "country")].Trim('"').Trim(),
Email = column[Array.IndexOf(headers, "email")].Trim('"').Trim(),
Expiration = column[Array.IndexOf(headers, "expiration")].Trim('"').Trim(),
Id = Guid.NewGuid().ToString(),
LastName = column[Array.IndexOf(headers, "lastname")].Trim('"').Trim(),
Name = column[Array.IndexOf(headers, "name")].Trim('"').Trim(),
PhoneNumber = column[Array.IndexOf(headers, "phonenumber")].Trim('"').Trim(),
UserName = column[Array.IndexOf(headers, "username")].Trim('"').Trim(),
ZipCode = column[Array.IndexOf(headers, "zipcode")].Trim('"').Trim(),
State = column[Array.IndexOf(headers, "state")].Trim('"').Trim(),
Street = column[Array.IndexOf(headers, "street")].Trim('"').Trim(),
SecurityNumber = column[Array.IndexOf(headers, "securitynumber")].Trim('"').Trim(),
NormalizedEmail = column[Array.IndexOf(headers, "normalizedemail")].Trim('"').Trim(),
NormalizedUserName = column[Array.IndexOf(headers, "normalizedusername")].Trim('"').Trim(),
SecurityStamp = Guid.NewGuid().ToString("D"),
PasswordHash = column[Array.IndexOf(headers, "password")].Trim('"').Trim(), // Note: This is the password
};
user.PasswordHash = _passwordHasher.HashPassword(user, user.PasswordHash);
return user;
}
private IEnumerable<ApplicationUser> GetDefaultUser()
{
var user =
new ApplicationUser()
{
CardHolderName = "DemoUser",
CardNumber = "4012888888881881",
CardType = 1,
City = "Redmond",
Country = "U.S.",
Email = "demouser@microsoft.com",
Expiration = "12/25",
Id = Guid.NewGuid().ToString(),
LastName = "DemoLastName",
Name = "DemoUser",
PhoneNumber = "1234567890",
UserName = "demouser@microsoft.com",
ZipCode = "98052",
State = "WA",
Street = "15703 NE 61st Ct",
SecurityNumber = "535",
NormalizedEmail = "DEMOUSER@MICROSOFT.COM",
NormalizedUserName = "DEMOUSER@MICROSOFT.COM",
SecurityStamp = Guid.NewGuid().ToString("D"),
};
user.PasswordHash = _passwordHasher.HashPassword(user, "Pass@word1");
return new List<ApplicationUser>()
{
user
};
}
static string[] GetHeaders(string[] requiredHeaders, string csvfile)
{
string[] csvheaders = File.ReadLines(csvfile).First().ToLowerInvariant().Split(',');
if (csvheaders.Count() != requiredHeaders.Count())
{
throw new Exception($"requiredHeader count '{ requiredHeaders.Count()}' is different then read header '{csvheaders.Count()}'");
}
foreach (var requiredHeader in requiredHeaders)
{
if (!csvheaders.Contains(requiredHeader))
{
throw new Exception($"does not contain required header '{requiredHeader}'");
}
}
return csvheaders;
}
static void GetPreconfiguredImages(string contentRootPath, string webroot, ILogger logger)
{
try
{
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
if (!File.Exists(imagesZipFile))
{
logger.LogError("Zip file '{ZipFileName}' does not exists.", imagesZipFile);
return;
}
string imagePath = Path.Combine(webroot, "images");
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
using ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read);
foreach (ZipArchiveEntry entry in zip.Entries)
{
if (imageFiles.Contains(entry.Name))
{
string destinationFilename = Path.Combine(imagePath, entry.Name);
if (File.Exists(destinationFilename))
{
File.Delete(destinationFilename);
}
entry.ExtractToFile(destinationFilename);
}
else
{
logger.LogWarning("Skipped file '{FileName}' in zipfile '{ZipFileName}'", entry.Name, imagesZipFile);
}
}
}
catch (Exception ex)
{
logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); ;
}
}
}
}

+ 0
- 73
src/Services/Identity/Identity.API/Data/ConfigurationDbContextSeed.cs View File

@ -1,73 +0,0 @@
using IdentityServer4.EntityFramework.Entities;
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
{
public class ConfigurationDbContextSeed
{
public async Task SeedAsync(ConfigurationDbContext context, IConfiguration configuration)
{
//callbacks urls from config:
var clientUrls = new Dictionary<string, string>();
clientUrls.Add("Mvc", configuration.GetValue<string>("MvcClient"));
clientUrls.Add("Spa", configuration.GetValue<string>("SpaClient"));
clientUrls.Add("Xamarin", configuration.GetValue<string>("XamarinCallback"));
clientUrls.Add("BasketApi", configuration.GetValue<string>("BasketApiClient"));
clientUrls.Add("OrderingApi", configuration.GetValue<string>("OrderingApiClient"));
clientUrls.Add("MobileShoppingAgg", configuration.GetValue<string>("MobileShoppingAggClient"));
clientUrls.Add("WebShoppingAgg", configuration.GetValue<string>("WebShoppingAggClient"));
clientUrls.Add("WebhooksApi", configuration.GetValue<string>("WebhooksApiClient"));
clientUrls.Add("WebhooksWeb", configuration.GetValue<string>("WebhooksWebClient"));
if (!context.Clients.Any())
{
foreach (var client in Config.GetClients(clientUrls))
{
context.Clients.Add(client.ToEntity());
}
await context.SaveChangesAsync();
}
// Checking always for old redirects to fix existing deployments
// to use new swagger-ui redirect uri as of v3.0.0
// There should be no problem for new ones
// ref: https://github.com/dotnet-architecture/eShopOnContainers/issues/586
else
{
List<ClientRedirectUri> oldRedirects = (await context.Clients.Include(c => c.RedirectUris).ToListAsync())
.SelectMany(c => c.RedirectUris)
.Where(ru => ru.RedirectUri.EndsWith("/o2c.html"))
.ToList();
if (oldRedirects.Any())
{
foreach (var ru in oldRedirects)
{
ru.RedirectUri = ru.RedirectUri.Replace("/o2c.html", "/oauth2-redirect.html");
context.Update(ru.Client);
}
await context.SaveChangesAsync();
}
}
if (!context.IdentityResources.Any())
{
foreach (var resource in Config.GetResources())
{
context.IdentityResources.Add(resource.ToEntity());
}
await context.SaveChangesAsync();
}
if (!context.ApiResources.Any())
{
foreach (var api in Config.GetApis())
{
context.ApiResources.Add(api.ToEntity());
}
await context.SaveChangesAsync();
}
}
}
}

src/Services/Identity/Identity.API/Migrations/20210813072445_InitialMigration.Designer.cs → src/Services/Identity/Identity.API/Data/Migrations/20210914100206_InitialMigration.Designer.cs View File

@ -7,10 +7,10 @@ using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.eShopOnContainers.Services.Identity.API.Data; using Microsoft.eShopOnContainers.Services.Identity.API.Data;
namespace Identity.API.Migrations
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data.Migrations
{ {
[DbContext(typeof(ApplicationDbContext))] [DbContext(typeof(ApplicationDbContext))]
[Migration("20210813072445_InitialMigration")]
[Migration("20210914100206_InitialMigration")]
partial class InitialMigration partial class InitialMigration
{ {
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -18,7 +18,7 @@ namespace Identity.API.Migrations
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("ProductVersion", "5.0.9")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
@ -45,7 +45,7 @@ namespace Identity.API.Migrations
.HasDatabaseName("RoleNameIndex") .HasDatabaseName("RoleNameIndex")
.HasFilter("[NormalizedName] IS NOT NULL"); .HasFilter("[NormalizedName] IS NOT NULL");
b.ToTable("AspNetRoles", (string)null);
b.ToTable("AspNetRoles");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
@ -69,7 +69,7 @@ namespace Identity.API.Migrations
b.HasIndex("RoleId"); b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
b.ToTable("AspNetRoleClaims");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
@ -93,7 +93,7 @@ namespace Identity.API.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
b.ToTable("AspNetUserClaims");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
@ -115,7 +115,7 @@ namespace Identity.API.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
b.ToTable("AspNetUserLogins");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
@ -130,7 +130,7 @@ namespace Identity.API.Migrations
b.HasIndex("RoleId"); b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
b.ToTable("AspNetUserRoles");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
@ -149,7 +149,7 @@ namespace Identity.API.Migrations
b.HasKey("UserId", "LoginProvider", "Name"); b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
b.ToTable("AspNetUserTokens");
}); });
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", b => modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", b =>
@ -261,7 +261,7 @@ namespace Identity.API.Migrations
.HasDatabaseName("UserNameIndex") .HasDatabaseName("UserNameIndex")
.HasFilter("[NormalizedUserName] IS NOT NULL"); .HasFilter("[NormalizedUserName] IS NOT NULL");
b.ToTable("AspNetUsers", (string)null);
b.ToTable("AspNetUsers");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>

src/Services/Identity/Identity.API/Migrations/20210813072445_InitialMigration.cs → src/Services/Identity/Identity.API/Data/Migrations/20210914100206_InitialMigration.cs View File

@ -1,7 +1,7 @@
using System; using System;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
namespace Identity.API.Migrations
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data.Migrations
{ {
public partial class InitialMigration : Migration public partial class InitialMigration : Migration
{ {

src/Services/Identity/Identity.API/Migrations/ApplicationDbContextModelSnapshot.cs → src/Services/Identity/Identity.API/Data/Migrations/ApplicationDbContextModelSnapshot.cs View File

@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.eShopOnContainers.Services.Identity.API.Data; using Microsoft.eShopOnContainers.Services.Identity.API.Data;
namespace Identity.API.Migrations
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data.Migrations
{ {
[DbContext(typeof(ApplicationDbContext))] [DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot partial class ApplicationDbContextModelSnapshot : ModelSnapshot
@ -16,7 +16,7 @@ namespace Identity.API.Migrations
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("ProductVersion", "5.0.9")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
@ -43,7 +43,7 @@ namespace Identity.API.Migrations
.HasDatabaseName("RoleNameIndex") .HasDatabaseName("RoleNameIndex")
.HasFilter("[NormalizedName] IS NOT NULL"); .HasFilter("[NormalizedName] IS NOT NULL");
b.ToTable("AspNetRoles", (string)null);
b.ToTable("AspNetRoles");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
@ -67,7 +67,7 @@ namespace Identity.API.Migrations
b.HasIndex("RoleId"); b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
b.ToTable("AspNetRoleClaims");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
@ -91,7 +91,7 @@ namespace Identity.API.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
b.ToTable("AspNetUserClaims");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
@ -113,7 +113,7 @@ namespace Identity.API.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
b.ToTable("AspNetUserLogins");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
@ -128,7 +128,7 @@ namespace Identity.API.Migrations
b.HasIndex("RoleId"); b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
b.ToTable("AspNetUserRoles");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
@ -147,7 +147,7 @@ namespace Identity.API.Migrations
b.HasKey("UserId", "LoginProvider", "Name"); b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
b.ToTable("AspNetUserTokens");
}); });
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", b => modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", b =>
@ -259,7 +259,7 @@ namespace Identity.API.Migrations
.HasDatabaseName("UserNameIndex") .HasDatabaseName("UserNameIndex")
.HasFilter("[NormalizedUserName] IS NOT NULL"); .HasFilter("[NormalizedUserName] IS NOT NULL");
b.ToTable("AspNetUsers", (string)null);
b.ToTable("AspNetUsers");
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>

+ 2
- 2
src/Services/Identity/Identity.API/Devspaces/DevspacesRedirectUriValidator.cs View File

@ -10,14 +10,14 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Devspaces
_logger = logger; _logger = logger;
} }
public Task<bool> IsPostLogoutRedirectUriValidAsync(string requestedUri, IdentityServer4.Models.Client client)
public Task<bool> IsPostLogoutRedirectUriValidAsync(string requestedUri, Duende.IdentityServer.Models.Client client)
{ {
_logger.LogInformation("Client {ClientName} used post logout uri {RequestedUri}.", client.ClientName, requestedUri); _logger.LogInformation("Client {ClientName} used post logout uri {RequestedUri}.", client.ClientName, requestedUri);
return Task.FromResult(true); return Task.FromResult(true);
} }
public Task<bool> IsRedirectUriValidAsync(string requestedUri, IdentityServer4.Models.Client client)
public Task<bool> IsRedirectUriValidAsync(string requestedUri, Duende.IdentityServer.Models.Client client)
{ {
_logger.LogInformation("Client {ClientName} used post logout uri {RequestedUri}.", client.ClientName, requestedUri); _logger.LogInformation("Client {ClientName} used post logout uri {RequestedUri}.", client.ClientName, requestedUri);
return Task.FromResult(true); return Task.FromResult(true);


+ 2
- 2
src/Services/Identity/Identity.API/Dockerfile View File

@ -1,8 +1,8 @@
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src WORKDIR /src
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles # It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles


+ 1
- 1
src/Services/Identity/Identity.API/Dockerfile.develop View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:6.0
FROM mcr.microsoft.com/dotnet/sdk:7.0
ARG BUILD_CONFIGURATION=Debug ARG BUILD_CONFIGURATION=Debug
ENV ASPNETCORE_ENVIRONMENT=Development ENV ASPNETCORE_ENVIRONMENT=Development
ENV DOTNET_USE_POLLING_FILE_WATCHER=true ENV DOTNET_USE_POLLING_FILE_WATCHER=true


+ 0
- 46
src/Services/Identity/Identity.API/Extensions/LinqSelectExtensions.cs View File

@ -1,46 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Identity.API.Extensions
{
public static class LinqSelectExtensions
{
public static IEnumerable<SelectTryResult<TSource, TResult>> SelectTry<TSource, TResult>(this IEnumerable<TSource> enumerable, Func<TSource, TResult> selector)
{
foreach (TSource element in enumerable)
{
SelectTryResult<TSource, TResult> returnedValue;
try
{
returnedValue = new SelectTryResult<TSource, TResult>(element, selector(element), null);
}
catch (Exception ex)
{
returnedValue = new SelectTryResult<TSource, TResult>(element, default(TResult), ex);
}
yield return returnedValue;
}
}
public static IEnumerable<TResult> OnCaughtException<TSource, TResult>(this IEnumerable<SelectTryResult<TSource, TResult>> enumerable, Func<Exception, TResult> exceptionHandler)
{
return enumerable.Select(x => x.CaughtException == null ? x.Result : exceptionHandler(x.CaughtException));
}
public static IEnumerable<TResult> OnCaughtException<TSource, TResult>(this IEnumerable<SelectTryResult<TSource, TResult>> enumerable, Func<TSource, Exception, TResult> exceptionHandler)
{
return enumerable.Select(x => x.CaughtException == null ? x.Result : exceptionHandler(x.Source, x.CaughtException));
}
public class SelectTryResult<TSource, TResult>
{
internal SelectTryResult(TSource source, TResult result, Exception exception)
{
Source = source;
Result = result;
CaughtException = exception;
}
public TSource Source { get; private set; }
public TResult Result { get; private set; }
public Exception CaughtException { get; private set; }
}
}
}

+ 0
- 20
src/Services/Identity/Identity.API/Factories/ApplicationDbContextFactory.cs View File

@ -1,20 +0,0 @@
namespace Identity.API.Factories
{
public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContext CreateDbContext(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Path.Combine(Directory.GetCurrentDirectory()))
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
optionsBuilder.UseSqlServer(config["ConnectionString"], sqlServerOptionsAction: o => o.MigrationsAssembly("Identity.API"));
return new ApplicationDbContext(optionsBuilder.Options);
}
}
}

+ 0
- 21
src/Services/Identity/Identity.API/Factories/ConfigurationDbContextFactory.cs View File

@ -1,21 +0,0 @@
namespace Identity.API.Factories
{
public class ConfigurationDbContextFactory : IDesignTimeDbContextFactory<ConfigurationDbContext>
{
public ConfigurationDbContext CreateDbContext(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Path.Combine(Directory.GetCurrentDirectory()))
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();
var optionsBuilder = new DbContextOptionsBuilder<ConfigurationDbContext>();
var storeOptions = new ConfigurationStoreOptions();
optionsBuilder.UseSqlServer(config["ConnectionString"], sqlServerOptionsAction: o => o.MigrationsAssembly("Identity.API"));
return new ConfigurationDbContext(optionsBuilder.Options, storeOptions);
}
}
}

+ 0
- 21
src/Services/Identity/Identity.API/Factories/PersistedGrantDbContextFactory.cs View File

@ -1,21 +0,0 @@
namespace Identity.API.Factories
{
public class PersistedGrantDbContextFactory : IDesignTimeDbContextFactory<PersistedGrantDbContext>
{
public PersistedGrantDbContext CreateDbContext(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Path.Combine(Directory.GetCurrentDirectory()))
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();
var optionsBuilder = new DbContextOptionsBuilder<PersistedGrantDbContext>();
var operationOptions = new OperationalStoreOptions();
optionsBuilder.UseSqlServer(config["ConnectionString"], sqlServerOptionsAction: o => o.MigrationsAssembly("Identity.API"));
return new PersistedGrantDbContext(optionsBuilder.Options, operationOptions);
}
}
}

+ 14
- 14
src/Services/Identity/Identity.API/GlobalUsings.cs View File

@ -1,19 +1,18 @@
global using Microsoft.eShopOnContainers.Services.Identity.API.Extensions;
global using System.IO.Compression; global using System.IO.Compression;
global using Autofac.Extensions.DependencyInjection; global using Autofac.Extensions.DependencyInjection;
global using Autofac;
global using Azure.Core; global using Azure.Core;
global using Azure.Identity; global using Azure.Identity;
global using HealthChecks.UI.Client; global using HealthChecks.UI.Client;
global using IdentityModel; global using IdentityModel;
global using IdentityServer4.EntityFramework.DbContexts;
global using IdentityServer4.EntityFramework.Mappers;
global using IdentityServer4.EntityFramework.Options;
global using IdentityServer4.Models;
global using IdentityServer4.Services;
global using IdentityServer4.Stores;
global using IdentityServer4.Validation;
global using IdentityServer4;
global using Duende.IdentityServer;
global using Duende.IdentityServer.Configuration;
global using Duende.IdentityServer.Events;
global using Duende.IdentityServer.Extensions;
global using Duende.IdentityServer.Models;
global using Duende.IdentityServer.Services;
global using Duende.IdentityServer.Stores;
global using Duende.IdentityServer.Validation;
global using Microsoft.AspNetCore.Authentication; global using Microsoft.AspNetCore.Authentication;
global using Microsoft.AspNetCore.Authorization; global using Microsoft.AspNetCore.Authorization;
global using Microsoft.AspNetCore.Builder; global using Microsoft.AspNetCore.Builder;
@ -23,20 +22,21 @@ global using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
global using Microsoft.AspNetCore.Identity; global using Microsoft.AspNetCore.Identity;
global using Microsoft.AspNetCore.Mvc.Rendering; global using Microsoft.AspNetCore.Mvc.Rendering;
global using Microsoft.AspNetCore.Mvc; global using Microsoft.AspNetCore.Mvc;
global using Microsoft.AspNetCore.Mvc.Filters;
global using Microsoft.AspNetCore; global using Microsoft.AspNetCore;
global using Microsoft.EntityFrameworkCore.Design; global using Microsoft.EntityFrameworkCore.Design;
global using Microsoft.EntityFrameworkCore.Infrastructure; global using Microsoft.EntityFrameworkCore.Infrastructure;
global using Microsoft.EntityFrameworkCore.Metadata; global using Microsoft.EntityFrameworkCore.Metadata;
global using Microsoft.EntityFrameworkCore.Migrations; global using Microsoft.EntityFrameworkCore.Migrations;
global using Microsoft.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore;
global using Microsoft.eShopOnContainers.Services.Identity.API.Certificates;
global using Microsoft.eShopOnContainers.Services.Identity.API.Configuration;
global using Microsoft.eShopOnContainers.Services.Identity.API;
global using Microsoft.eShopOnContainers.Services.Identity.API.Data; global using Microsoft.eShopOnContainers.Services.Identity.API.Data;
global using Microsoft.eShopOnContainers.Services.Identity.API.Configuration;
global using Microsoft.eShopOnContainers.Services.Identity.API.Devspaces; global using Microsoft.eShopOnContainers.Services.Identity.API.Devspaces;
global using Microsoft.eShopOnContainers.Services.Identity.API.Models.AccountViewModels; global using Microsoft.eShopOnContainers.Services.Identity.API.Models.AccountViewModels;
global using Microsoft.eShopOnContainers.Services.Identity.API.Models; global using Microsoft.eShopOnContainers.Services.Identity.API.Models;
global using Microsoft.eShopOnContainers.Services.Identity.API.Services; global using Microsoft.eShopOnContainers.Services.Identity.API.Services;
global using Microsoft.eShopOnContainers.Services.Identity.API;
global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Diagnostics.HealthChecks; global using Microsoft.Extensions.Diagnostics.HealthChecks;
@ -44,7 +44,6 @@ global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Logging; global using Microsoft.Extensions.Logging;
global using Microsoft.Extensions.Options; global using Microsoft.Extensions.Options;
global using Polly; global using Polly;
global using Serilog;
global using StackExchange.Redis; global using StackExchange.Redis;
global using System.Collections.Generic; global using System.Collections.Generic;
global using System.ComponentModel.DataAnnotations; global using System.ComponentModel.DataAnnotations;
@ -58,6 +57,7 @@ global using System.Security.Cryptography.X509Certificates;
global using System.Text.RegularExpressions; global using System.Text.RegularExpressions;
global using System.Threading.Tasks; global using System.Threading.Tasks;
global using System; global using System;
global using Microsoft.AspNetCore.Http;


+ 60
- 52
src/Services/Identity/Identity.API/Identity.API.csproj View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<UserSecretsId>aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5</UserSecretsId> <UserSecretsId>aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5</UserSecretsId>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath> <DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks> <GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
@ -9,64 +9,72 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Content Include="Setup\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="5.0.3" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0-preview.1" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="3.1.4" />
<PackageReference Include="IdentityServer4.EntityFramework.Storage" Version="3.1.4" />
<PackageReference Include="IdentityServer4.EntityFramework" Version="3.1.4" />
<PackageReference Include="IdentityServer4.Storage" Version="3.1.4" />
<PackageReference Include="IdentityServer4" Version="3.1.4" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.18.0" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.18.0" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2-beta2" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="6.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="6.2.0" />
<PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" Version="6.2.0" />
<PackageReference Include="Duende.IdentityServer.EntityFramework" Version="6.2.0" />
<PackageReference Include="Duende.IdentityServer.Storage" Version="6.2.0" />
<PackageReference Include="Duende.IdentityServer" Version="6.2.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0-beta1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0-beta1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" /> <PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.24" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="7.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" /> <PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
<PackageReference Include="Polly" Version="7.2.2" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" />
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" /> <PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0-dev-00291" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1-dev-00876" />
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0-beta.9" />
<PackageReference Include="Serilog.Sinks.Seq" Version="5.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" />
<PackageReference Include="System.Data.SqlClient" version="4.8.2" />
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.1" />
<PackageReference Include="Azure.Identity" Version="1.4.0" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Certificate\idsrv3test.pfx" />
</ItemGroup>
<ItemGroup>
<None Update="Setup\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="Extensions\" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.5.0-dev-00359" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" />
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.3-dev-00260" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" />
<PackageReference Include="System.Data.SqlClient" version="4.8.5" />
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.2" />
<PackageReference Include="Azure.Identity" Version="1.9.0-beta.1" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="Views\Account\AccessDenied.cshtml" />
<None Include="Views\Account\LoggedOut.cshtml" />
<None Include="Views\Account\Login.cshtml" />
<None Include="Views\Account\Logout.cshtml" />
<None Include="Views\Consent\Index.cshtml" />
<None Include="Views\Device\Success.cshtml" />
<None Include="Views\Device\UserCodeCapture.cshtml" />
<None Include="Views\Device\UserCodeConfirmation.cshtml" />
<None Include="Views\Diagnostics\Index.cshtml" />
<None Include="Views\Grants\Index.cshtml" />
<None Include="Views\Home\Index.cshtml" />
<None Include="Views\Shared\Error.cshtml" />
<None Include="Views\Shared\Redirect.cshtml" />
<None Include="Views\Shared\_Layout.cshtml" />
<None Include="Views\Shared\_ScopeListItem.cshtml" />
<None Include="Views\Shared\_ValidationSummary.cshtml" />
<None Include="Views\_ViewImports.cshtml" />
<None Include="Views\_ViewStart.cshtml" />
</ItemGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties appsettings_1json__JsonSchema="" />
</VisualStudio>
</ProjectExtensions>
</Project> </Project>

+ 0
- 911
src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20210813072543_InitialMigration.Designer.cs View File

@ -1,911 +0,0 @@
// <auto-generated />
using System;
using IdentityServer4.EntityFramework.DbContexts;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Identity.API.Migrations.ConfigurationDb
{
[DbContext(typeof(ConfigurationDbContext))]
[Migration("20210813072543_InitialMigration")]
partial class InitialMigration
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<DateTime>("Created")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("Enabled")
.HasColumnType("bit");
b.Property<DateTime?>("LastAccessed")
.HasColumnType("datetime2");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("NonEditable")
.HasColumnType("bit");
b.Property<DateTime?>("Updated")
.HasColumnType("datetime2");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ApiResources", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("int");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiClaims", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("int");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiProperties", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("int");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("Emphasize")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("Required")
.HasColumnType("bit");
b.Property<bool>("ShowInDiscoveryDocument")
.HasColumnType("bit");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ApiScopes", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ApiScopeId")
.HasColumnType("int");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("ApiScopeId");
b.ToTable("ApiScopeClaims", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("int");
b.Property<DateTime>("Created")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<DateTime?>("Expiration")
.HasColumnType("datetime2");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiSecrets", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("AbsoluteRefreshTokenLifetime")
.HasColumnType("int");
b.Property<int>("AccessTokenLifetime")
.HasColumnType("int");
b.Property<int>("AccessTokenType")
.HasColumnType("int");
b.Property<bool>("AllowAccessTokensViaBrowser")
.HasColumnType("bit");
b.Property<bool>("AllowOfflineAccess")
.HasColumnType("bit");
b.Property<bool>("AllowPlainTextPkce")
.HasColumnType("bit");
b.Property<bool>("AllowRememberConsent")
.HasColumnType("bit");
b.Property<bool>("AlwaysIncludeUserClaimsInIdToken")
.HasColumnType("bit");
b.Property<bool>("AlwaysSendClientClaims")
.HasColumnType("bit");
b.Property<int>("AuthorizationCodeLifetime")
.HasColumnType("int");
b.Property<bool>("BackChannelLogoutSessionRequired")
.HasColumnType("bit");
b.Property<string>("BackChannelLogoutUri")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<string>("ClientClaimsPrefix")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ClientName")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ClientUri")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<int?>("ConsentLifetime")
.HasColumnType("int");
b.Property<DateTime>("Created")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<int>("DeviceCodeLifetime")
.HasColumnType("int");
b.Property<bool>("EnableLocalLogin")
.HasColumnType("bit");
b.Property<bool>("Enabled")
.HasColumnType("bit");
b.Property<bool>("FrontChannelLogoutSessionRequired")
.HasColumnType("bit");
b.Property<string>("FrontChannelLogoutUri")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<int>("IdentityTokenLifetime")
.HasColumnType("int");
b.Property<bool>("IncludeJwtId")
.HasColumnType("bit");
b.Property<DateTime?>("LastAccessed")
.HasColumnType("datetime2");
b.Property<string>("LogoUri")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<bool>("NonEditable")
.HasColumnType("bit");
b.Property<string>("PairWiseSubjectSalt")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ProtocolType")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("RefreshTokenExpiration")
.HasColumnType("int");
b.Property<int>("RefreshTokenUsage")
.HasColumnType("int");
b.Property<bool>("RequireClientSecret")
.HasColumnType("bit");
b.Property<bool>("RequireConsent")
.HasColumnType("bit");
b.Property<bool>("RequirePkce")
.HasColumnType("bit");
b.Property<int>("SlidingRefreshTokenLifetime")
.HasColumnType("int");
b.Property<bool>("UpdateAccessTokenClaimsOnRefresh")
.HasColumnType("bit");
b.Property<DateTime?>("Updated")
.HasColumnType("datetime2");
b.Property<string>("UserCodeType")
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<int?>("UserSsoLifetime")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ClientId")
.IsUnique();
b.ToTable("Clients", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientClaims", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("Origin")
.IsRequired()
.HasMaxLength(150)
.HasColumnType("nvarchar(150)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientCorsOrigins", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("GrantType")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientGrantTypes", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientIdPRestrictions", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("PostLogoutRedirectUri")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientPostLogoutRedirectUris", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientProperties", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("RedirectUri")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientRedirectUris", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("Scope")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientScopes", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<DateTime>("Created")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<DateTime?>("Expiration")
.HasColumnType("datetime2");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientSecrets", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("IdentityResourceId")
.HasColumnType("int");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("IdentityResourceId");
b.ToTable("IdentityClaims", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<DateTime>("Created")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("Emphasize")
.HasColumnType("bit");
b.Property<bool>("Enabled")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("NonEditable")
.HasColumnType("bit");
b.Property<bool>("Required")
.HasColumnType("bit");
b.Property<bool>("ShowInDiscoveryDocument")
.HasColumnType("bit");
b.Property<DateTime?>("Updated")
.HasColumnType("datetime2");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("IdentityResources", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("IdentityResourceId")
.HasColumnType("int");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.HasKey("Id");
b.HasIndex("IdentityResourceId");
b.ToTable("IdentityProperties", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("UserClaims")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Properties")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Scopes")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "ApiScope")
.WithMany("UserClaims")
.HasForeignKey("ApiScopeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiScope");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Secrets")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("Claims")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedCorsOrigins")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedGrantTypes")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("IdentityProviderRestrictions")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("PostLogoutRedirectUris")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("Properties")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("RedirectUris")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedScopes")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("ClientSecrets")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
.WithMany("UserClaims")
.HasForeignKey("IdentityResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("IdentityResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
.WithMany("Properties")
.HasForeignKey("IdentityResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("IdentityResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b =>
{
b.Navigation("Properties");
b.Navigation("Scopes");
b.Navigation("Secrets");
b.Navigation("UserClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
{
b.Navigation("UserClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b =>
{
b.Navigation("AllowedCorsOrigins");
b.Navigation("AllowedGrantTypes");
b.Navigation("AllowedScopes");
b.Navigation("Claims");
b.Navigation("ClientSecrets");
b.Navigation("IdentityProviderRestrictions");
b.Navigation("PostLogoutRedirectUris");
b.Navigation("Properties");
b.Navigation("RedirectUris");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b =>
{
b.Navigation("Properties");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}

+ 0
- 607
src/Services/Identity/Identity.API/Migrations/ConfigurationDb/20210813072543_InitialMigration.cs View File

@ -1,607 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Identity.API.Migrations.ConfigurationDb
{
public partial class InitialMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ApiResources",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Enabled = table.Column<bool>(type: "bit", nullable: false),
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
DisplayName = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
Created = table.Column<DateTime>(type: "datetime2", nullable: false),
Updated = table.Column<DateTime>(type: "datetime2", nullable: true),
LastAccessed = table.Column<DateTime>(type: "datetime2", nullable: true),
NonEditable = table.Column<bool>(type: "bit", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiResources", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Clients",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Enabled = table.Column<bool>(type: "bit", nullable: false),
ClientId = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
ProtocolType = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
RequireClientSecret = table.Column<bool>(type: "bit", nullable: false),
ClientName = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
ClientUri = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
LogoUri = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
RequireConsent = table.Column<bool>(type: "bit", nullable: false),
AllowRememberConsent = table.Column<bool>(type: "bit", nullable: false),
AlwaysIncludeUserClaimsInIdToken = table.Column<bool>(type: "bit", nullable: false),
RequirePkce = table.Column<bool>(type: "bit", nullable: false),
AllowPlainTextPkce = table.Column<bool>(type: "bit", nullable: false),
AllowAccessTokensViaBrowser = table.Column<bool>(type: "bit", nullable: false),
FrontChannelLogoutUri = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
FrontChannelLogoutSessionRequired = table.Column<bool>(type: "bit", nullable: false),
BackChannelLogoutUri = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
BackChannelLogoutSessionRequired = table.Column<bool>(type: "bit", nullable: false),
AllowOfflineAccess = table.Column<bool>(type: "bit", nullable: false),
IdentityTokenLifetime = table.Column<int>(type: "int", nullable: false),
AccessTokenLifetime = table.Column<int>(type: "int", nullable: false),
AuthorizationCodeLifetime = table.Column<int>(type: "int", nullable: false),
ConsentLifetime = table.Column<int>(type: "int", nullable: true),
AbsoluteRefreshTokenLifetime = table.Column<int>(type: "int", nullable: false),
SlidingRefreshTokenLifetime = table.Column<int>(type: "int", nullable: false),
RefreshTokenUsage = table.Column<int>(type: "int", nullable: false),
UpdateAccessTokenClaimsOnRefresh = table.Column<bool>(type: "bit", nullable: false),
RefreshTokenExpiration = table.Column<int>(type: "int", nullable: false),
AccessTokenType = table.Column<int>(type: "int", nullable: false),
EnableLocalLogin = table.Column<bool>(type: "bit", nullable: false),
IncludeJwtId = table.Column<bool>(type: "bit", nullable: false),
AlwaysSendClientClaims = table.Column<bool>(type: "bit", nullable: false),
ClientClaimsPrefix = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
PairWiseSubjectSalt = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
Created = table.Column<DateTime>(type: "datetime2", nullable: false),
Updated = table.Column<DateTime>(type: "datetime2", nullable: true),
LastAccessed = table.Column<DateTime>(type: "datetime2", nullable: true),
UserSsoLifetime = table.Column<int>(type: "int", nullable: true),
UserCodeType = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
DeviceCodeLifetime = table.Column<int>(type: "int", nullable: false),
NonEditable = table.Column<bool>(type: "bit", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Clients", x => x.Id);
});
migrationBuilder.CreateTable(
name: "IdentityResources",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Enabled = table.Column<bool>(type: "bit", nullable: false),
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
DisplayName = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
Required = table.Column<bool>(type: "bit", nullable: false),
Emphasize = table.Column<bool>(type: "bit", nullable: false),
ShowInDiscoveryDocument = table.Column<bool>(type: "bit", nullable: false),
Created = table.Column<DateTime>(type: "datetime2", nullable: false),
Updated = table.Column<DateTime>(type: "datetime2", nullable: true),
NonEditable = table.Column<bool>(type: "bit", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_IdentityResources", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ApiClaims",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ApiResourceId = table.Column<int>(type: "int", nullable: false),
Type = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiClaims", x => x.Id);
table.ForeignKey(
name: "FK_ApiClaims_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiProperties",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ApiResourceId = table.Column<int>(type: "int", nullable: false),
Key = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiProperties", x => x.Id);
table.ForeignKey(
name: "FK_ApiProperties_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiScopes",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
DisplayName = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
Required = table.Column<bool>(type: "bit", nullable: false),
Emphasize = table.Column<bool>(type: "bit", nullable: false),
ShowInDiscoveryDocument = table.Column<bool>(type: "bit", nullable: false),
ApiResourceId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiScopes", x => x.Id);
table.ForeignKey(
name: "FK_ApiScopes_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiSecrets",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ApiResourceId = table.Column<int>(type: "int", nullable: false),
Description = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
Value = table.Column<string>(type: "nvarchar(4000)", maxLength: 4000, nullable: false),
Expiration = table.Column<DateTime>(type: "datetime2", nullable: true),
Type = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
Created = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiSecrets", x => x.Id);
table.ForeignKey(
name: "FK_ApiSecrets_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientClaims",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Type = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
ClientId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientClaims", x => x.Id);
table.ForeignKey(
name: "FK_ClientClaims_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientCorsOrigins",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Origin = table.Column<string>(type: "nvarchar(150)", maxLength: 150, nullable: false),
ClientId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientCorsOrigins", x => x.Id);
table.ForeignKey(
name: "FK_ClientCorsOrigins_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientGrantTypes",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
GrantType = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
ClientId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientGrantTypes", x => x.Id);
table.ForeignKey(
name: "FK_ClientGrantTypes_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientIdPRestrictions",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Provider = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
ClientId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientIdPRestrictions", x => x.Id);
table.ForeignKey(
name: "FK_ClientIdPRestrictions_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientPostLogoutRedirectUris",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
PostLogoutRedirectUri = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: false),
ClientId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientPostLogoutRedirectUris", x => x.Id);
table.ForeignKey(
name: "FK_ClientPostLogoutRedirectUris_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientProperties",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ClientId = table.Column<int>(type: "int", nullable: false),
Key = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientProperties", x => x.Id);
table.ForeignKey(
name: "FK_ClientProperties_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientRedirectUris",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
RedirectUri = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: false),
ClientId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientRedirectUris", x => x.Id);
table.ForeignKey(
name: "FK_ClientRedirectUris_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientScopes",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Scope = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
ClientId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientScopes", x => x.Id);
table.ForeignKey(
name: "FK_ClientScopes_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientSecrets",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ClientId = table.Column<int>(type: "int", nullable: false),
Description = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
Value = table.Column<string>(type: "nvarchar(4000)", maxLength: 4000, nullable: false),
Expiration = table.Column<DateTime>(type: "datetime2", nullable: true),
Type = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
Created = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientSecrets", x => x.Id);
table.ForeignKey(
name: "FK_ClientSecrets_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "IdentityClaims",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
IdentityResourceId = table.Column<int>(type: "int", nullable: false),
Type = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_IdentityClaims", x => x.Id);
table.ForeignKey(
name: "FK_IdentityClaims_IdentityResources_IdentityResourceId",
column: x => x.IdentityResourceId,
principalTable: "IdentityResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "IdentityProperties",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
IdentityResourceId = table.Column<int>(type: "int", nullable: false),
Key = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_IdentityProperties", x => x.Id);
table.ForeignKey(
name: "FK_IdentityProperties_IdentityResources_IdentityResourceId",
column: x => x.IdentityResourceId,
principalTable: "IdentityResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiScopeClaims",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ApiScopeId = table.Column<int>(type: "int", nullable: false),
Type = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiScopeClaims", x => x.Id);
table.ForeignKey(
name: "FK_ApiScopeClaims_ApiScopes_ApiScopeId",
column: x => x.ApiScopeId,
principalTable: "ApiScopes",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ApiClaims_ApiResourceId",
table: "ApiClaims",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ApiProperties_ApiResourceId",
table: "ApiProperties",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ApiResources_Name",
table: "ApiResources",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ApiScopeClaims_ApiScopeId",
table: "ApiScopeClaims",
column: "ApiScopeId");
migrationBuilder.CreateIndex(
name: "IX_ApiScopes_ApiResourceId",
table: "ApiScopes",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ApiScopes_Name",
table: "ApiScopes",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ApiSecrets_ApiResourceId",
table: "ApiSecrets",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ClientClaims_ClientId",
table: "ClientClaims",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientCorsOrigins_ClientId",
table: "ClientCorsOrigins",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientGrantTypes_ClientId",
table: "ClientGrantTypes",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientIdPRestrictions_ClientId",
table: "ClientIdPRestrictions",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientPostLogoutRedirectUris_ClientId",
table: "ClientPostLogoutRedirectUris",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientProperties_ClientId",
table: "ClientProperties",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientRedirectUris_ClientId",
table: "ClientRedirectUris",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_Clients_ClientId",
table: "Clients",
column: "ClientId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ClientScopes_ClientId",
table: "ClientScopes",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientSecrets_ClientId",
table: "ClientSecrets",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_IdentityClaims_IdentityResourceId",
table: "IdentityClaims",
column: "IdentityResourceId");
migrationBuilder.CreateIndex(
name: "IX_IdentityProperties_IdentityResourceId",
table: "IdentityProperties",
column: "IdentityResourceId");
migrationBuilder.CreateIndex(
name: "IX_IdentityResources_Name",
table: "IdentityResources",
column: "Name",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ApiClaims");
migrationBuilder.DropTable(
name: "ApiProperties");
migrationBuilder.DropTable(
name: "ApiScopeClaims");
migrationBuilder.DropTable(
name: "ApiSecrets");
migrationBuilder.DropTable(
name: "ClientClaims");
migrationBuilder.DropTable(
name: "ClientCorsOrigins");
migrationBuilder.DropTable(
name: "ClientGrantTypes");
migrationBuilder.DropTable(
name: "ClientIdPRestrictions");
migrationBuilder.DropTable(
name: "ClientPostLogoutRedirectUris");
migrationBuilder.DropTable(
name: "ClientProperties");
migrationBuilder.DropTable(
name: "ClientRedirectUris");
migrationBuilder.DropTable(
name: "ClientScopes");
migrationBuilder.DropTable(
name: "ClientSecrets");
migrationBuilder.DropTable(
name: "IdentityClaims");
migrationBuilder.DropTable(
name: "IdentityProperties");
migrationBuilder.DropTable(
name: "ApiScopes");
migrationBuilder.DropTable(
name: "Clients");
migrationBuilder.DropTable(
name: "IdentityResources");
migrationBuilder.DropTable(
name: "ApiResources");
}
}
}

+ 0
- 909
src/Services/Identity/Identity.API/Migrations/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs View File

@ -1,909 +0,0 @@
// <auto-generated />
using System;
using IdentityServer4.EntityFramework.DbContexts;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Identity.API.Migrations.ConfigurationDb
{
[DbContext(typeof(ConfigurationDbContext))]
partial class ConfigurationDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<DateTime>("Created")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("Enabled")
.HasColumnType("bit");
b.Property<DateTime?>("LastAccessed")
.HasColumnType("datetime2");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("NonEditable")
.HasColumnType("bit");
b.Property<DateTime?>("Updated")
.HasColumnType("datetime2");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ApiResources", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("int");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiClaims", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("int");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiProperties", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("int");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("Emphasize")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("Required")
.HasColumnType("bit");
b.Property<bool>("ShowInDiscoveryDocument")
.HasColumnType("bit");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ApiScopes", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ApiScopeId")
.HasColumnType("int");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("ApiScopeId");
b.ToTable("ApiScopeClaims", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ApiResourceId")
.HasColumnType("int");
b.Property<DateTime>("Created")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<DateTime?>("Expiration")
.HasColumnType("datetime2");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.HasKey("Id");
b.HasIndex("ApiResourceId");
b.ToTable("ApiSecrets", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("AbsoluteRefreshTokenLifetime")
.HasColumnType("int");
b.Property<int>("AccessTokenLifetime")
.HasColumnType("int");
b.Property<int>("AccessTokenType")
.HasColumnType("int");
b.Property<bool>("AllowAccessTokensViaBrowser")
.HasColumnType("bit");
b.Property<bool>("AllowOfflineAccess")
.HasColumnType("bit");
b.Property<bool>("AllowPlainTextPkce")
.HasColumnType("bit");
b.Property<bool>("AllowRememberConsent")
.HasColumnType("bit");
b.Property<bool>("AlwaysIncludeUserClaimsInIdToken")
.HasColumnType("bit");
b.Property<bool>("AlwaysSendClientClaims")
.HasColumnType("bit");
b.Property<int>("AuthorizationCodeLifetime")
.HasColumnType("int");
b.Property<bool>("BackChannelLogoutSessionRequired")
.HasColumnType("bit");
b.Property<string>("BackChannelLogoutUri")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<string>("ClientClaimsPrefix")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ClientName")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ClientUri")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<int?>("ConsentLifetime")
.HasColumnType("int");
b.Property<DateTime>("Created")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<int>("DeviceCodeLifetime")
.HasColumnType("int");
b.Property<bool>("EnableLocalLogin")
.HasColumnType("bit");
b.Property<bool>("Enabled")
.HasColumnType("bit");
b.Property<bool>("FrontChannelLogoutSessionRequired")
.HasColumnType("bit");
b.Property<string>("FrontChannelLogoutUri")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<int>("IdentityTokenLifetime")
.HasColumnType("int");
b.Property<bool>("IncludeJwtId")
.HasColumnType("bit");
b.Property<DateTime?>("LastAccessed")
.HasColumnType("datetime2");
b.Property<string>("LogoUri")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<bool>("NonEditable")
.HasColumnType("bit");
b.Property<string>("PairWiseSubjectSalt")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ProtocolType")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("RefreshTokenExpiration")
.HasColumnType("int");
b.Property<int>("RefreshTokenUsage")
.HasColumnType("int");
b.Property<bool>("RequireClientSecret")
.HasColumnType("bit");
b.Property<bool>("RequireConsent")
.HasColumnType("bit");
b.Property<bool>("RequirePkce")
.HasColumnType("bit");
b.Property<int>("SlidingRefreshTokenLifetime")
.HasColumnType("int");
b.Property<bool>("UpdateAccessTokenClaimsOnRefresh")
.HasColumnType("bit");
b.Property<DateTime?>("Updated")
.HasColumnType("datetime2");
b.Property<string>("UserCodeType")
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<int?>("UserSsoLifetime")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ClientId")
.IsUnique();
b.ToTable("Clients", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientClaims", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("Origin")
.IsRequired()
.HasMaxLength(150)
.HasColumnType("nvarchar(150)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientCorsOrigins", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("GrantType")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientGrantTypes", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientIdPRestrictions", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("PostLogoutRedirectUri")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientPostLogoutRedirectUris", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientProperties", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("RedirectUri")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientRedirectUris", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<string>("Scope")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientScopes", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<DateTime>("Created")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<DateTime?>("Expiration")
.HasColumnType("datetime2");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.HasKey("Id");
b.HasIndex("ClientId");
b.ToTable("ClientSecrets", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("IdentityResourceId")
.HasColumnType("int");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("IdentityResourceId");
b.ToTable("IdentityClaims", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<DateTime>("Created")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("DisplayName")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("Emphasize")
.HasColumnType("bit");
b.Property<bool>("Enabled")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("NonEditable")
.HasColumnType("bit");
b.Property<bool>("Required")
.HasColumnType("bit");
b.Property<bool>("ShowInDiscoveryDocument")
.HasColumnType("bit");
b.Property<DateTime?>("Updated")
.HasColumnType("datetime2");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("IdentityResources", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("IdentityResourceId")
.HasColumnType("int");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("nvarchar(250)");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.HasKey("Id");
b.HasIndex("IdentityResourceId");
b.ToTable("IdentityProperties", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("UserClaims")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Properties")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Scopes")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "ApiScope")
.WithMany("UserClaims")
.HasForeignKey("ApiScopeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiScope");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
.WithMany("Secrets")
.HasForeignKey("ApiResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApiResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("Claims")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedCorsOrigins")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedGrantTypes")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("IdentityProviderRestrictions")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("PostLogoutRedirectUris")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("Properties")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("RedirectUris")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("AllowedScopes")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
.WithMany("ClientSecrets")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
.WithMany("UserClaims")
.HasForeignKey("IdentityResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("IdentityResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
{
b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
.WithMany("Properties")
.HasForeignKey("IdentityResourceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("IdentityResource");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b =>
{
b.Navigation("Properties");
b.Navigation("Scopes");
b.Navigation("Secrets");
b.Navigation("UserClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
{
b.Navigation("UserClaims");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b =>
{
b.Navigation("AllowedCorsOrigins");
b.Navigation("AllowedGrantTypes");
b.Navigation("AllowedScopes");
b.Navigation("Claims");
b.Navigation("ClientSecrets");
b.Navigation("IdentityProviderRestrictions");
b.Navigation("PostLogoutRedirectUris");
b.Navigation("Properties");
b.Navigation("RedirectUris");
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b =>
{
b.Navigation("Properties");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}

+ 0
- 108
src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20210813072513_InitialMigration.Designer.cs View File

@ -1,108 +0,0 @@
// <auto-generated />
using System;
using IdentityServer4.EntityFramework.DbContexts;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Identity.API.Migrations.PersistedGrantDb
{
[DbContext(typeof(PersistedGrantDbContext))]
[Migration("20210813072513_InitialMigration")]
partial class InitialMigration
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b =>
{
b.Property<string>("UserCode")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2");
b.Property<string>("Data")
.IsRequired()
.HasMaxLength(50000)
.HasColumnType("nvarchar(max)");
b.Property<string>("DeviceCode")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTime?>("Expiration")
.IsRequired()
.HasColumnType("datetime2");
b.Property<string>("SubjectId")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("UserCode");
b.HasIndex("DeviceCode")
.IsUnique();
b.HasIndex("Expiration");
b.ToTable("DeviceCodes", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b =>
{
b.Property<string>("Key")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2");
b.Property<string>("Data")
.IsRequired()
.HasMaxLength(50000)
.HasColumnType("nvarchar(max)");
b.Property<DateTime?>("Expiration")
.HasColumnType("datetime2");
b.Property<string>("SubjectId")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Key");
b.HasIndex("Expiration");
b.HasIndex("SubjectId", "ClientId", "Type");
b.ToTable("PersistedGrants", (string)null);
});
#pragma warning restore 612, 618
}
}
}

+ 0
- 75
src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/20210813072513_InitialMigration.cs View File

@ -1,75 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Identity.API.Migrations.PersistedGrantDb
{
public partial class InitialMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "DeviceCodes",
columns: table => new
{
UserCode = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
DeviceCode = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
SubjectId = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
ClientId = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
Expiration = table.Column<DateTime>(type: "datetime2", nullable: false),
Data = table.Column<string>(type: "nvarchar(max)", maxLength: 50000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_DeviceCodes", x => x.UserCode);
});
migrationBuilder.CreateTable(
name: "PersistedGrants",
columns: table => new
{
Key = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
Type = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
SubjectId = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
ClientId = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
Expiration = table.Column<DateTime>(type: "datetime2", nullable: true),
Data = table.Column<string>(type: "nvarchar(max)", maxLength: 50000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_PersistedGrants", x => x.Key);
});
migrationBuilder.CreateIndex(
name: "IX_DeviceCodes_DeviceCode",
table: "DeviceCodes",
column: "DeviceCode",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_DeviceCodes_Expiration",
table: "DeviceCodes",
column: "Expiration");
migrationBuilder.CreateIndex(
name: "IX_PersistedGrants_Expiration",
table: "PersistedGrants",
column: "Expiration");
migrationBuilder.CreateIndex(
name: "IX_PersistedGrants_SubjectId_ClientId_Type",
table: "PersistedGrants",
columns: new[] { "SubjectId", "ClientId", "Type" });
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "DeviceCodes");
migrationBuilder.DropTable(
name: "PersistedGrants");
}
}
}

+ 0
- 106
src/Services/Identity/Identity.API/Migrations/PersistedGrantDb/PersistedGrantDbContextModelSnapshot.cs View File

@ -1,106 +0,0 @@
// <auto-generated />
using System;
using IdentityServer4.EntityFramework.DbContexts;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Identity.API.Migrations.PersistedGrantDb
{
[DbContext(typeof(PersistedGrantDbContext))]
partial class PersistedGrantDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b =>
{
b.Property<string>("UserCode")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2");
b.Property<string>("Data")
.IsRequired()
.HasMaxLength(50000)
.HasColumnType("nvarchar(max)");
b.Property<string>("DeviceCode")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTime?>("Expiration")
.IsRequired()
.HasColumnType("datetime2");
b.Property<string>("SubjectId")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("UserCode");
b.HasIndex("DeviceCode")
.IsUnique();
b.HasIndex("Expiration");
b.ToTable("DeviceCodes", (string)null);
});
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b =>
{
b.Property<string>("Key")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ClientId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2");
b.Property<string>("Data")
.IsRequired()
.HasMaxLength(50000)
.HasColumnType("nvarchar(max)");
b.Property<DateTime?>("Expiration")
.HasColumnType("datetime2");
b.Property<string>("SubjectId")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Key");
b.HasIndex("Expiration");
b.HasIndex("SubjectId", "ClientId", "Type");
b.ToTable("PersistedGrants", (string)null);
});
#pragma warning restore 612, 618
}
}
}

+ 0
- 10
src/Services/Identity/Identity.API/Models/AccountViewModels/ConsentInputModel.cs View File

@ -1,10 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.AccountViewModels
{
public record ConsentInputModel
{
public string Button { get; init; }
public IEnumerable<string> ScopesConsented { get; init; }
public bool RememberConsent { get; init; }
public string ReturnUrl { get; init; }
}
}

+ 0
- 61
src/Services/Identity/Identity.API/Models/AccountViewModels/ConsentViewModel.cs View File

@ -1,61 +0,0 @@
using IdentityServer4.Models;
namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.AccountViewModels
{
public record ConsentViewModel : ConsentInputModel
{
public ConsentViewModel(ConsentInputModel model, string returnUrl, AuthorizationRequest request, Client client, Resources resources)
{
RememberConsent = model?.RememberConsent ?? true;
ScopesConsented = model?.ScopesConsented ?? Enumerable.Empty<string>();
ReturnUrl = returnUrl;
ClientName = client.ClientName;
ClientUrl = client.ClientUri;
ClientLogoUrl = client.LogoUri;
AllowRememberConsent = client.AllowRememberConsent;
IdentityScopes = resources.IdentityResources.Select(x => new ScopeViewModel(x, ScopesConsented.Contains(x.Name) || model == null)).ToArray();
ResourceScopes = resources.ApiResources.SelectMany(x => x.Scopes).Select(x => new ScopeViewModel(x, ScopesConsented.Contains(x.Name) || model == null)).ToArray();
}
public string ClientName { get; init; }
public string ClientUrl { get; init; }
public string ClientLogoUrl { get; init; }
public bool AllowRememberConsent { get; init; }
public IEnumerable<ScopeViewModel> IdentityScopes { get; init; }
public IEnumerable<ScopeViewModel> ResourceScopes { get; init; }
}
public record ScopeViewModel
{
public ScopeViewModel(Scope scope, bool check)
{
Name = scope.Name;
DisplayName = scope.DisplayName;
Description = scope.Description;
Emphasize = scope.Emphasize;
Required = scope.Required;
Checked = check || scope.Required;
}
public ScopeViewModel(IdentityResource identity, bool check)
{
Name = identity.Name;
DisplayName = identity.DisplayName;
Description = identity.Description;
Emphasize = identity.Emphasize;
Required = identity.Required;
Checked = check || identity.Required;
}
public string Name { get; init; }
public string DisplayName { get; init; }
public string Description { get; init; }
public bool Emphasize { get; init; }
public bool Required { get; init; }
public bool Checked { get; init; }
}
}

+ 7
- 0
src/Services/Identity/Identity.API/Models/AccountViewModels/RedirectViewModel.cs View File

@ -0,0 +1,7 @@
namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.AccountViewModels
{
public class RedirectViewModel
{
public string RedirectUrl { get; set; }
}
}

+ 13
- 0
src/Services/Identity/Identity.API/Models/ConsentViewModels/ConsentInputModel.cs View File

@ -0,0 +1,13 @@
using System.Collections.Generic;
namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.ConsentViewModels
{
public class ConsentInputModel
{
public string Button { get; set; }
public IEnumerable<string> ScopesConsented { get; set; }
public bool RememberConsent { get; set; }
public string ReturnUrl { get; set; }
public string Description { get; set; }
}
}

+ 12
- 0
src/Services/Identity/Identity.API/Models/ConsentViewModels/ConsentOptions.cs View File

@ -0,0 +1,12 @@
namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.ConsentViewModels
{
public class ConsentOptions
{
public static bool EnableOfflineAccess = true;
public static string OfflineAccessDisplayName = "Offline Access";
public static string OfflineAccessDescription = "Access to your applications and resources, even when you are offline";
public static readonly string MustChooseOneErrorMessage = "You must pick at least one permission";
public static readonly string InvalidSelectionErrorMessage = "Invalid selection";
}
}

+ 15
- 0
src/Services/Identity/Identity.API/Models/ConsentViewModels/ConsentViewModel.cs View File

@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.ConsentViewModels
{
public class ConsentViewModel : ConsentInputModel
{
public string ClientName { get; set; }
public string ClientUrl { get; set; }
public string ClientLogoUrl { get; set; }
public bool AllowRememberConsent { get; set; }
public IEnumerable<ScopeViewModel> IdentityScopes { get; set; }
public IEnumerable<ScopeViewModel> ApiScopes { get; set; }
}
}

+ 17
- 0
src/Services/Identity/Identity.API/Models/ConsentViewModels/ProcessConsentResult.cs View File

@ -0,0 +1,17 @@
using Duende.IdentityServer.Models;
namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.ConsentViewModels
{
public class ProcessConsentResult
{
public bool IsRedirect => RedirectUri != null;
public string RedirectUri { get; set; }
public Client Client { get; set; }
public bool ShowView => ViewModel != null;
public ConsentViewModel ViewModel { get; set; }
public bool HasValidationError => ValidationError != null;
public string ValidationError { get; set; }
}
}

+ 12
- 0
src/Services/Identity/Identity.API/Models/ConsentViewModels/ScopeViewModel.cs View File

@ -0,0 +1,12 @@
namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.ConsentViewModels
{
public class ScopeViewModel
{
public string Value { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public bool Emphasize { get; set; }
public bool Required { get; set; }
public bool Checked { get; set; }
}
}

+ 58
- 54
src/Services/Identity/Identity.API/Program.cs View File

@ -1,71 +1,75 @@
string Namespace = typeof(Startup).Namespace;
string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
var appName = "Identity.API";
var builder = WebApplication.CreateBuilder();
var configuration = GetConfiguration();
builder.AddCustomConfiguration();
builder.AddCustomSerilog();
builder.AddCustomMvc();
builder.AddCustomDatabase();
builder.AddCustomIdentity();
builder.AddCustomIdentityServer();
builder.AddCustomAuthentication();
builder.AddCustomHealthChecks();
builder.AddCustomApplicationServices();
Log.Logger = CreateSerilogLogger(configuration);
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
var pathBase = builder.Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
app.UsePathBase(pathBase);
}
app.UseStaticFiles();
// This cookie policy fixes login issues with Chrome 80+ using HHTP
app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode.Lax });
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapHealthChecks("/hc", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.MapHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
try try
{ {
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
var host = BuildWebHost(configuration, args);
Log.Information("Applying migrations ({ApplicationContext})...", AppName);
host.MigrateDbContext<PersistedGrantDbContext>((_, __) => { })
.MigrateDbContext<ApplicationDbContext>((context, services) =>
{
var env = services.GetService<IWebHostEnvironment>();
var logger = services.GetService<ILogger<ApplicationDbContextSeed>>();
var settings = services.GetService<IOptions<AppSettings>>();
new ApplicationDbContextSeed()
.SeedAsync(context, env, logger, settings)
.Wait();
})
.MigrateDbContext<ConfigurationDbContext>((context, services) =>
{
new ConfigurationDbContextSeed()
.SeedAsync(context, configuration)
.Wait();
});
Log.Information("Starting web host ({ApplicationContext})...", AppName);
host.Run();
app.Logger.LogInformation("Seeding database ({ApplicationName})...", appName);
// Apply database migration automatically. Note that this approach is not
// recommended for production scenarios. Consider generating SQL scripts from
// migrations instead.
using (var scope = app.Services.CreateScope())
{
await SeedData.EnsureSeedData(scope, app.Configuration, app.Logger);
}
app.Logger.LogInformation("Starting web host ({ApplicationName})...", appName);
app.Run();
return 0; return 0;
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
app.Logger.LogCritical(ex, "Host terminated unexpectedly ({ApplicationName})...", appName);
return 1; return 1;
} }
finally finally
{ {
Log.CloseAndFlush();
}
IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args)
.CaptureStartupErrors(false)
.ConfigureAppConfiguration(x => x.AddConfiguration(configuration))
.UseStartup<Startup>()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseSerilog()
.Build();
Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
{
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
var logstashUrl = configuration["Serilog:LogstashgUrl"];
return new LoggerConfiguration()
.MinimumLevel.Verbose()
.Enrich.WithProperty("ApplicationContext", AppName)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
.WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://localhost:8080" : logstashUrl)
.ReadFrom.Configuration(configuration)
.CreateLogger();
Serilog.Log.CloseAndFlush();
} }
IConfiguration GetConfiguration() IConfiguration GetConfiguration()


+ 117
- 0
src/Services/Identity/Identity.API/ProgramExtensions.cs View File

@ -0,0 +1,117 @@
using Serilog;
namespace Microsoft.eShopOnContainers.Services.Identity.API;
public static class ProgramExtensions
{
private const string AppName = "Identity API";
public static void AddCustomConfiguration(this WebApplicationBuilder builder)
{
builder.Configuration.AddConfiguration(GetConfiguration()).Build();
}
public static void AddCustomSerilog(this WebApplicationBuilder builder)
{
var seqServerUrl = builder.Configuration["SeqServerUrl"];
var logstashUrl = builder.Configuration["LogstashgUrl"];
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.Enrich.WithProperty("ApplicationContext", AppName)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
.WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://localhost:8080" : logstashUrl, null)
.ReadFrom.Configuration(builder.Configuration)
.CreateLogger();
builder.Host.UseSerilog();
}
public static void AddCustomMvc(this WebApplicationBuilder builder)
{
builder.Services.AddControllersWithViews();
builder.Services.AddControllers();
builder.Services.AddRazorPages();
}
public static void AddCustomDatabase(this WebApplicationBuilder builder) =>
builder.Services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlServer(builder.Configuration["ConnectionString"]));
public static void AddCustomIdentity(this WebApplicationBuilder builder)
{
builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
}
public static void AddCustomIdentityServer(this WebApplicationBuilder builder)
{
var identityServerBuilder = builder.Services.AddIdentityServer(options =>
{
options.IssuerUri = "null";
options.Authentication.CookieLifetime = TimeSpan.FromHours(2);
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
})
.AddInMemoryIdentityResources(Config.GetResources())
.AddInMemoryApiScopes(Config.GetApiScopes())
.AddInMemoryApiResources(Config.GetApis())
.AddInMemoryClients(Config.GetClients(builder.Configuration))
.AddAspNetIdentity<ApplicationUser>();
// not recommended for production - you need to store your key material somewhere secure
identityServerBuilder.AddDeveloperSigningCredential();
}
public static void AddCustomAuthentication(this WebApplicationBuilder builder)
{
builder.Services.AddAuthentication();
}
public static void AddCustomHealthChecks(this WebApplicationBuilder builder)
{
builder.Services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy())
.AddSqlServer(builder.Configuration["ConnectionString"],
name: "IdentityDB-check",
tags: new string[] { "IdentityDB" });
}
public static void AddCustomApplicationServices(this WebApplicationBuilder builder)
{
builder.Services.AddTransient<IProfileService, ProfileService>();
builder.Services.AddTransient<ILoginService<ApplicationUser>, EFLoginService>();
builder.Services.AddTransient<IRedirectService, RedirectService>();
}
static IConfiguration GetConfiguration()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
var config = builder.Build();
if (config.GetValue<bool>("UseVault", false))
{
TokenCredential credential = new ClientSecretCredential(
config["Vault:TenantId"],
config["Vault:ClientId"],
config["Vault:ClientSecret"]);
builder.AddAzureKeyVault(new Uri($"https://{config["Vault:Name"]}.vault.azure.net/"), credential);
}
return builder.Build();
}
}

+ 341
- 0
src/Services/Identity/Identity.API/Quickstart/Account/AccountController.cs View File

@ -0,0 +1,341 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using Duende.IdentityServer.Events;
using Duende.IdentityServer.Extensions;
using Duende.IdentityServer.Stores;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace IdentityServerHost.Quickstart.UI
{
[SecurityHeaders]
[AllowAnonymous]
public class AccountController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IIdentityServerInteractionService _interaction;
private readonly IClientStore _clientStore;
private readonly IAuthenticationSchemeProvider _schemeProvider;
private readonly IAuthenticationHandlerProvider _handlerProvider;
private readonly IEventService _events;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IIdentityServerInteractionService interaction,
IClientStore clientStore,
IAuthenticationSchemeProvider schemeProvider,
IAuthenticationHandlerProvider handlerProvider,
IEventService events)
{
_userManager = userManager;
_signInManager = signInManager;
_interaction = interaction;
_clientStore = clientStore;
_schemeProvider = schemeProvider;
_handlerProvider = handlerProvider;
_events = events;
}
/// <summary>
/// Entry point into the login workflow
/// </summary>
[HttpGet]
public async Task<IActionResult> Login(string returnUrl)
{
// build a model so we know what to show on the login page
var vm = await BuildLoginViewModelAsync(returnUrl);
ViewData["ReturnUrl"] = returnUrl;
if (vm.IsExternalLoginOnly)
{
// we only have one option for logging in and it's an external provider
return RedirectToAction("Challenge", "External", new { scheme = vm.ExternalLoginScheme, returnUrl });
}
return View(vm);
}
/// <summary>
/// Handle postback from username/password login
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginInputModel model, string button)
{
// check if we are in the context of an authorization request
var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
// the user clicked the "cancel" button
if (button != "login")
{
if (context != null)
{
// if the user cancels, send a result back into IdentityServer as if they
// denied the consent (even if this client does not require consent).
// this will send back an access denied OIDC error response to the client.
await _interaction.DenyAuthorizationAsync(context, AuthorizationError.AccessDenied);
// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
if (context.IsNativeClient())
{
// The client is native, so this change in how to
// return the response is for better UX for the end user.
return this.LoadingPage("Redirect", model.ReturnUrl);
}
return Redirect(model.ReturnUrl);
}
else
{
// since we don't have a valid context, then we just go back to the home page
return Redirect("~/");
}
}
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberLogin, lockoutOnFailure: true);
if (result.Succeeded)
{
var user = await _userManager.FindByNameAsync(model.Username);
await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName, clientId: context?.Client.ClientId));
if (context != null)
{
if (context.IsNativeClient())
{
// The client is native, so this change in how to
// return the response is for better UX for the end user.
return this.LoadingPage("Redirect", model.ReturnUrl);
}
// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
return Redirect(model.ReturnUrl);
}
// request for a local page
if (Url.IsLocalUrl(model.ReturnUrl))
{
return Redirect(model.ReturnUrl);
}
else if (string.IsNullOrEmpty(model.ReturnUrl))
{
return Redirect("~/");
}
else
{
// user might have clicked on a malicious link - should be logged
throw new Exception("invalid return URL");
}
}
await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials", clientId:context?.Client.ClientId));
ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
}
// something went wrong, show form with error
var vm = await BuildLoginViewModelAsync(model);
ViewData["ReturnUrl"] = model.ReturnUrl;
return View(vm);
}
/// <summary>
/// Show logout page
/// </summary>
[HttpGet]
public async Task<IActionResult> Logout(string logoutId)
{
// build a model so the logout page knows what to display
var vm = await BuildLogoutViewModelAsync(logoutId);
if (vm.ShowLogoutPrompt == false)
{
// if the request for logout was properly authenticated from IdentityServer, then
// we don't need to show the prompt and can just log the user out directly.
return await Logout(vm);
}
return View(vm);
}
/// <summary>
/// Handle logout page postback
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout(LogoutInputModel model)
{
// build a model so the logged out page knows what to display
var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);
if (User?.Identity.IsAuthenticated == true)
{
// delete local authentication cookie
await _signInManager.SignOutAsync();
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
}
// check if we need to trigger sign-out at an upstream identity provider
if (vm.TriggerExternalSignout)
{
// build a return URL so the upstream provider will redirect back
// to us after the user has logged out. this allows us to then
// complete our single sign-out processing.
string url = Url.Action("Logout", new { logoutId = vm.LogoutId });
// this triggers a redirect to the external provider for sign-out
return SignOut(new AuthenticationProperties { RedirectUri = url }, vm.ExternalAuthenticationScheme);
}
return View("LoggedOut", vm);
}
[HttpGet]
public IActionResult AccessDenied()
{
return View();
}
/*****************************************/
/* helper APIs for the AccountController */
/*****************************************/
private async Task<LoginViewModel> BuildLoginViewModelAsync(string returnUrl)
{
var context = await _interaction.GetAuthorizationContextAsync(returnUrl);
if (context?.IdP != null && await _schemeProvider.GetSchemeAsync(context.IdP) != null)
{
var local = context.IdP == IdentityServerConstants.LocalIdentityProvider;
// this is meant to short circuit the UI and only trigger the one external IdP
var vm = new LoginViewModel
{
EnableLocalLogin = local,
ReturnUrl = returnUrl,
Username = context?.LoginHint,
};
if (!local)
{
vm.ExternalProviders = new[] { new ExternalProvider { AuthenticationScheme = context.IdP } };
}
return vm;
}
var schemes = await _schemeProvider.GetAllSchemesAsync();
var providers = schemes
.Where(x => x.DisplayName != null)
.Select(x => new ExternalProvider
{
DisplayName = x.DisplayName ?? x.Name,
AuthenticationScheme = x.Name
}).ToList();
var allowLocal = true;
if (context?.Client.ClientId != null)
{
var client = await _clientStore.FindEnabledClientByIdAsync(context.Client.ClientId);
if (client != null)
{
allowLocal = client.EnableLocalLogin;
if (client.IdentityProviderRestrictions != null && client.IdentityProviderRestrictions.Any())
{
providers = providers.Where(provider => client.IdentityProviderRestrictions.Contains(provider.AuthenticationScheme)).ToList();
}
}
}
return new LoginViewModel
{
AllowRememberLogin = AccountOptions.AllowRememberLogin,
EnableLocalLogin = allowLocal && AccountOptions.AllowLocalLogin,
ReturnUrl = returnUrl,
Username = context?.LoginHint,
ExternalProviders = providers.ToArray()
};
}
private async Task<LoginViewModel> BuildLoginViewModelAsync(LoginInputModel model)
{
var vm = await BuildLoginViewModelAsync(model.ReturnUrl);
vm.Username = model.Username;
vm.RememberLogin = model.RememberLogin;
return vm;
}
private async Task<LogoutViewModel> BuildLogoutViewModelAsync(string logoutId)
{
var vm = new LogoutViewModel { LogoutId = logoutId, ShowLogoutPrompt = AccountOptions.ShowLogoutPrompt };
if (User?.Identity.IsAuthenticated != true)
{
// if the user is not authenticated, then just show logged out page
vm.ShowLogoutPrompt = false;
return vm;
}
var context = await _interaction.GetLogoutContextAsync(logoutId);
if (context?.ShowSignoutPrompt == false)
{
// it's safe to automatically sign-out
vm.ShowLogoutPrompt = false;
return vm;
}
// show the logout prompt. this prevents attacks where the user
// is automatically signed out by another malicious web page.
return vm;
}
private async Task<LoggedOutViewModel> BuildLoggedOutViewModelAsync(string logoutId)
{
// get context information (client name, post logout redirect URI and iframe for federated signout)
var logout = await _interaction.GetLogoutContextAsync(logoutId);
var vm = new LoggedOutViewModel
{
AutomaticRedirectAfterSignOut = AccountOptions.AutomaticRedirectAfterSignOut,
PostLogoutRedirectUri = logout?.PostLogoutRedirectUri,
ClientName = string.IsNullOrEmpty(logout?.ClientName) ? logout?.ClientId : logout?.ClientName,
SignOutIframeUrl = logout?.SignOutIFrameUrl,
LogoutId = logoutId
};
if (User?.Identity.IsAuthenticated == true)
{
var idp = User.FindFirst(JwtClaimTypes.IdentityProvider)?.Value;
if (idp != null && idp != IdentityServerConstants.LocalIdentityProvider)
{
var handler = await _handlerProvider.GetHandlerAsync(HttpContext, idp);
if (handler is IAuthenticationSignOutHandler)
{
if (vm.LogoutId == null)
{
// if there's no current logout context, we need to create one
// this captures necessary info from the current logged in user
// before we signout and redirect away to the external IdP for signout
vm.LogoutId = await _interaction.CreateLogoutContextAsync();
}
vm.ExternalAuthenticationScheme = idp;
}
}
}
return vm;
}
}
}

+ 16
- 0
src/Services/Identity/Identity.API/Quickstart/Account/AccountOptions.cs View File

@ -0,0 +1,16 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class AccountOptions
{
public static bool AllowLocalLogin = true;
public static bool AllowRememberLogin = true;
public static TimeSpan RememberMeLoginDuration = TimeSpan.FromDays(30);
public static bool ShowLogoutPrompt = false;
public static bool AutomaticRedirectAfterSignOut = true;
public static string InvalidCredentialsErrorMessage = "Invalid username or password";
}

+ 238
- 0
src/Services/Identity/Identity.API/Quickstart/Account/ExternalController.cs View File

@ -0,0 +1,238 @@
namespace IdentityServerHost.Quickstart.UI;
[SecurityHeaders]
[AllowAnonymous]
public class ExternalController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IIdentityServerInteractionService _interaction;
private readonly IClientStore _clientStore;
private readonly IEventService _events;
private readonly ILogger<ExternalController> _logger;
public ExternalController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IIdentityServerInteractionService interaction,
IClientStore clientStore,
IEventService events,
ILogger<ExternalController> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_interaction = interaction;
_clientStore = clientStore;
_events = events;
_logger = logger;
}
/// <summary>
/// initiate roundtrip to external authentication provider
/// </summary>
[HttpGet]
public IActionResult Challenge(string scheme, string returnUrl)
{
if (string.IsNullOrEmpty(returnUrl)) returnUrl = "~/";
// validate returnUrl - either it is a valid OIDC URL or back to a local page
if (Url.IsLocalUrl(returnUrl) == false && _interaction.IsValidReturnUrl(returnUrl) == false)
{
// user might have clicked on a malicious link - should be logged
throw new Exception("invalid return URL");
}
// start challenge and roundtrip the return URL and scheme
var props = new AuthenticationProperties
{
RedirectUri = Url.Action(nameof(Callback)),
Items =
{
{ "returnUrl", returnUrl },
{ "scheme", scheme },
}
};
return Challenge(props, scheme);
}
/// <summary>
/// Post processing of external authentication
/// </summary>
[HttpGet]
public async Task<IActionResult> Callback()
{
// read external identity from the temporary cookie
var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
if (result?.Succeeded != true)
{
throw new Exception("External authentication error");
}
if (_logger.IsEnabled(LogLevel.Debug))
{
var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}");
_logger.LogDebug("External claims: {@claims}", externalClaims);
}
// lookup our user and external provider info
var (user, provider, providerUserId, claims) = await FindUserFromExternalProviderAsync(result);
if (user == null)
{
// this might be where you might initiate a custom workflow for user registration
// in this sample we don't show how that would be done, as our sample implementation
// simply auto-provisions new external user
user = await AutoProvisionUserAsync(provider, providerUserId, claims);
}
// this allows us to collect any additional claims or properties
// for the specific protocols used and store them in the local auth cookie.
// this is typically used to store data needed for signout from those protocols.
var additionalLocalClaims = new List<Claim>();
var localSignInProps = new AuthenticationProperties();
ProcessLoginCallback(result, additionalLocalClaims, localSignInProps);
// issue authentication cookie for user
// we must issue the cookie maually, and can't use the SignInManager because
// it doesn't expose an API to issue additional claims from the login workflow
var principal = await _signInManager.CreateUserPrincipalAsync(user);
additionalLocalClaims.AddRange(principal.Claims);
var name = principal.FindFirst(JwtClaimTypes.Name)?.Value ?? user.Id;
var isuser = new IdentityServerUser(user.Id)
{
DisplayName = name,
IdentityProvider = provider,
AdditionalClaims = additionalLocalClaims
};
await HttpContext.SignInAsync(isuser, localSignInProps);
// delete temporary cookie used during external authentication
await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
// retrieve return URL
var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";
// check if external login is in the context of an OIDC request
var context = await _interaction.GetAuthorizationContextAsync(returnUrl);
await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, name, true, context?.Client.ClientId));
if (context != null)
{
if (context.IsNativeClient())
{
// The client is native, so this change in how to
// return the response is for better UX for the end user.
return this.LoadingPage("Redirect", returnUrl);
}
}
return Redirect(returnUrl);
}
private async Task<(ApplicationUser user, string provider, string providerUserId, IEnumerable<Claim> claims)>
FindUserFromExternalProviderAsync(AuthenticateResult result)
{
var externalUser = result.Principal;
// try to determine the unique id of the external user (issued by the provider)
// the most common claim type for that are the sub claim and the NameIdentifier
// depending on the external provider, some other claim type might be used
var userIdClaim = externalUser.FindFirst(JwtClaimTypes.Subject) ??
externalUser.FindFirst(ClaimTypes.NameIdentifier) ??
throw new Exception("Unknown userid");
// remove the user id claim so we don't include it as an extra claim if/when we provision the user
var claims = externalUser.Claims.ToList();
claims.Remove(userIdClaim);
var provider = result.Properties.Items["scheme"];
var providerUserId = userIdClaim.Value;
// find external user
var user = await _userManager.FindByLoginAsync(provider, providerUserId);
return (user, provider, providerUserId, claims);
}
private async Task<ApplicationUser> AutoProvisionUserAsync(string provider, string providerUserId, IEnumerable<Claim> claims)
{
// create a list of claims that we want to transfer into our store
var filtered = new List<Claim>();
// user's display name
var name = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Name)?.Value ??
claims.FirstOrDefault(x => x.Type == ClaimTypes.Name)?.Value;
if (name != null)
{
filtered.Add(new Claim(JwtClaimTypes.Name, name));
}
else
{
var first = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.GivenName)?.Value ??
claims.FirstOrDefault(x => x.Type == ClaimTypes.GivenName)?.Value;
var last = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.FamilyName)?.Value ??
claims.FirstOrDefault(x => x.Type == ClaimTypes.Surname)?.Value;
if (first != null && last != null)
{
filtered.Add(new Claim(JwtClaimTypes.Name, first + " " + last));
}
else if (first != null)
{
filtered.Add(new Claim(JwtClaimTypes.Name, first));
}
else if (last != null)
{
filtered.Add(new Claim(JwtClaimTypes.Name, last));
}
}
// email
var email = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Email)?.Value ??
claims.FirstOrDefault(x => x.Type == ClaimTypes.Email)?.Value;
if (email != null)
{
filtered.Add(new Claim(JwtClaimTypes.Email, email));
}
var user = new ApplicationUser
{
UserName = Guid.NewGuid().ToString(),
};
var identityResult = await _userManager.CreateAsync(user);
if (!identityResult.Succeeded) throw new Exception(identityResult.Errors.First().Description);
if (filtered.Any())
{
identityResult = await _userManager.AddClaimsAsync(user, filtered);
if (!identityResult.Succeeded) throw new Exception(identityResult.Errors.First().Description);
}
identityResult = await _userManager.AddLoginAsync(user, new UserLoginInfo(provider, providerUserId, provider));
if (!identityResult.Succeeded) throw new Exception(identityResult.Errors.First().Description);
return user;
}
// if the external login is OIDC-based, there are certain things we need to preserve to make logout work
// this will be different for WS-Fed, SAML2p or other protocols
private void ProcessLoginCallback(AuthenticateResult externalResult, List<Claim> localClaims, AuthenticationProperties localSignInProps)
{
// if the external system sent a session id claim, copy it over
// so we can use it for single sign-out
var sid = externalResult.Principal.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.SessionId);
if (sid != null)
{
localClaims.Add(new Claim(JwtClaimTypes.SessionId, sid.Value));
}
// if the external provider issued an id_token, we'll keep it for signout
var idToken = externalResult.Properties.GetTokenValue("id_token");
if (idToken != null)
{
localSignInProps.StoreTokens(new[] { new AuthenticationToken { Name = "id_token", Value = idToken } });
}
}
}

+ 10
- 0
src/Services/Identity/Identity.API/Quickstart/Account/ExternalProvider.cs View File

@ -0,0 +1,10 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class ExternalProvider
{
public string DisplayName { get; set; }
public string AuthenticationScheme { get; set; }
}

+ 18
- 0
src/Services/Identity/Identity.API/Quickstart/Account/LoggedOutViewModel.cs View File

@ -0,0 +1,18 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class LoggedOutViewModel
{
public string PostLogoutRedirectUri { get; set; }
public string ClientName { get; set; }
public string SignOutIframeUrl { get; set; }
public bool AutomaticRedirectAfterSignOut { get; set; }
public string LogoutId { get; set; }
public bool TriggerExternalSignout => ExternalAuthenticationScheme != null;
public string ExternalAuthenticationScheme { get; set; }
}

+ 15
- 0
src/Services/Identity/Identity.API/Quickstart/Account/LoginInputModel.cs View File

@ -0,0 +1,15 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class LoginInputModel
{
[Required]
public string Username { get; set; }
[Required]
public string Password { get; set; }
public bool RememberLogin { get; set; }
public string ReturnUrl { get; set; }
}

+ 17
- 0
src/Services/Identity/Identity.API/Quickstart/Account/LoginViewModel.cs View File

@ -0,0 +1,17 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class LoginViewModel : LoginInputModel
{
public bool AllowRememberLogin { get; set; } = true;
public bool EnableLocalLogin { get; set; } = true;
public IEnumerable<ExternalProvider> ExternalProviders { get; set; } = Enumerable.Empty<ExternalProvider>();
public IEnumerable<ExternalProvider> VisibleExternalProviders => ExternalProviders.Where(x => !String.IsNullOrWhiteSpace(x.DisplayName));
public bool IsExternalLoginOnly => EnableLocalLogin == false && ExternalProviders?.Count() == 1;
public string ExternalLoginScheme => IsExternalLoginOnly ? ExternalProviders?.SingleOrDefault()?.AuthenticationScheme : null;
}

+ 10
- 0
src/Services/Identity/Identity.API/Quickstart/Account/LogoutInputModel.cs View File

@ -0,0 +1,10 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class LogoutInputModel
{
public string LogoutId { get; set; }
}

+ 10
- 0
src/Services/Identity/Identity.API/Quickstart/Account/LogoutViewModel.cs View File

@ -0,0 +1,10 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class LogoutViewModel : LogoutInputModel
{
public bool ShowLogoutPrompt { get; set; } = true;
}

+ 11
- 0
src/Services/Identity/Identity.API/Quickstart/Account/RedirectViewModel.cs View File

@ -0,0 +1,11 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class RedirectViewModel
{
public string RedirectUrl { get; set; }
}

+ 247
- 0
src/Services/Identity/Identity.API/Quickstart/Consent/ConsentController.cs View File

@ -0,0 +1,247 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
/// <summary>
/// This controller processes the consent UI
/// </summary>
[SecurityHeaders]
[Authorize]
public class ConsentController : Controller
{
private readonly IIdentityServerInteractionService _interaction;
private readonly IEventService _events;
private readonly ILogger<ConsentController> _logger;
public ConsentController(
IIdentityServerInteractionService interaction,
IEventService events,
ILogger<ConsentController> logger)
{
_interaction = interaction;
_events = events;
_logger = logger;
}
/// <summary>
/// Shows the consent screen
/// </summary>
/// <param name="returnUrl"></param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Index(string returnUrl)
{
var vm = await BuildViewModelAsync(returnUrl);
if (vm != null)
{
return View("Index", vm);
}
return View("Error");
}
/// <summary>
/// Handles the consent screen postback
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Index(ConsentInputModel model)
{
var result = await ProcessConsent(model);
if (result.IsRedirect)
{
var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
if (context?.IsNativeClient() == true)
{
// The client is native, so this change in how to
// return the response is for better UX for the end user.
return this.LoadingPage("Redirect", result.RedirectUri);
}
return Redirect(result.RedirectUri);
}
if (result.HasValidationError)
{
ModelState.AddModelError(string.Empty, result.ValidationError);
}
if (result.ShowView)
{
return View("Index", result.ViewModel);
}
return View("Error");
}
/*****************************************/
/* helper APIs for the ConsentController */
/*****************************************/
private async Task<ProcessConsentResult> ProcessConsent(ConsentInputModel model)
{
var result = new ProcessConsentResult();
// validate return url is still valid
var request = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
if (request == null) return result;
ConsentResponse grantedConsent = null;
// user clicked 'no' - send back the standard 'access_denied' response
if (model?.Button == "no")
{
grantedConsent = new ConsentResponse { Error = AuthorizationError.AccessDenied };
// emit event
await _events.RaiseAsync(new ConsentDeniedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues));
}
// user clicked 'yes' - validate the data
else if (model?.Button == "yes")
{
// if the user consented to some scope, build the response model
if (model.ScopesConsented != null && model.ScopesConsented.Any())
{
var scopes = model.ScopesConsented;
if (ConsentOptions.EnableOfflineAccess == false)
{
scopes = scopes.Where(x => x != IdentityServerConstants.StandardScopes.OfflineAccess);
}
grantedConsent = new ConsentResponse
{
RememberConsent = model.RememberConsent,
ScopesValuesConsented = scopes.ToArray(),
Description = model.Description
};
// emit event
await _events.RaiseAsync(new ConsentGrantedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues, grantedConsent.ScopesValuesConsented, grantedConsent.RememberConsent));
}
else
{
result.ValidationError = ConsentOptions.MustChooseOneErrorMessage;
}
}
else
{
result.ValidationError = ConsentOptions.InvalidSelectionErrorMessage;
}
if (grantedConsent != null)
{
// communicate outcome of consent back to identityserver
await _interaction.GrantConsentAsync(request, grantedConsent);
// indicate that's it ok to redirect back to authorization endpoint
result.RedirectUri = model.ReturnUrl;
result.Client = request.Client;
}
else
{
// we need to redisplay the consent UI
result.ViewModel = await BuildViewModelAsync(model.ReturnUrl, model);
}
return result;
}
private async Task<ConsentViewModel> BuildViewModelAsync(string returnUrl, ConsentInputModel model = null)
{
var request = await _interaction.GetAuthorizationContextAsync(returnUrl);
if (request != null)
{
return CreateConsentViewModel(model, returnUrl, request);
}
else
{
_logger.LogError("No consent request matching request: {0}", returnUrl);
}
return null;
}
private ConsentViewModel CreateConsentViewModel(
ConsentInputModel model, string returnUrl,
AuthorizationRequest request)
{
var vm = new ConsentViewModel
{
RememberConsent = model?.RememberConsent ?? true,
ScopesConsented = model?.ScopesConsented ?? Enumerable.Empty<string>(),
Description = model?.Description,
ReturnUrl = returnUrl,
ClientName = request.Client.ClientName ?? request.Client.ClientId,
ClientUrl = request.Client.ClientUri,
ClientLogoUrl = request.Client.LogoUri,
AllowRememberConsent = request.Client.AllowRememberConsent
};
vm.IdentityScopes = request.ValidatedResources.Resources.IdentityResources.Select(x => CreateScopeViewModel(x, vm.ScopesConsented.Contains(x.Name) || model == null)).ToArray();
var apiScopes = new List<ScopeViewModel>();
foreach (var parsedScope in request.ValidatedResources.ParsedScopes)
{
var apiScope = request.ValidatedResources.Resources.FindApiScope(parsedScope.ParsedName);
if (apiScope != null)
{
var scopeVm = CreateScopeViewModel(parsedScope, apiScope, vm.ScopesConsented.Contains(parsedScope.RawValue) || model == null);
apiScopes.Add(scopeVm);
}
}
if (ConsentOptions.EnableOfflineAccess && request.ValidatedResources.Resources.OfflineAccess)
{
apiScopes.Add(GetOfflineAccessScope(vm.ScopesConsented.Contains(IdentityServerConstants.StandardScopes.OfflineAccess) || model == null));
}
vm.ApiScopes = apiScopes;
return vm;
}
private ScopeViewModel CreateScopeViewModel(IdentityResource identity, bool check)
{
return new ScopeViewModel
{
Value = identity.Name,
DisplayName = identity.DisplayName ?? identity.Name,
Description = identity.Description,
Emphasize = identity.Emphasize,
Required = identity.Required,
Checked = check || identity.Required
};
}
public ScopeViewModel CreateScopeViewModel(ParsedScopeValue parsedScopeValue, ApiScope apiScope, bool check)
{
var displayName = apiScope.DisplayName ?? apiScope.Name;
if (!String.IsNullOrWhiteSpace(parsedScopeValue.ParsedParameter))
{
displayName += ":" + parsedScopeValue.ParsedParameter;
}
return new ScopeViewModel
{
Value = parsedScopeValue.RawValue,
DisplayName = displayName,
Description = apiScope.Description,
Emphasize = apiScope.Emphasize,
Required = apiScope.Required,
Checked = check || apiScope.Required
};
}
private ScopeViewModel GetOfflineAccessScope(bool check)
{
return new ScopeViewModel
{
Value = IdentityServerConstants.StandardScopes.OfflineAccess,
DisplayName = ConsentOptions.OfflineAccessDisplayName,
Description = ConsentOptions.OfflineAccessDescription,
Emphasize = true,
Checked = check
};
}
}

+ 14
- 0
src/Services/Identity/Identity.API/Quickstart/Consent/ConsentInputModel.cs View File

@ -0,0 +1,14 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class ConsentInputModel
{
public string Button { get; set; }
public IEnumerable<string> ScopesConsented { get; set; }
public bool RememberConsent { get; set; }
public string ReturnUrl { get; set; }
public string Description { get; set; }
}

+ 15
- 0
src/Services/Identity/Identity.API/Quickstart/Consent/ConsentOptions.cs View File

@ -0,0 +1,15 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class ConsentOptions
{
public static bool EnableOfflineAccess = true;
public static string OfflineAccessDisplayName = "Offline Access";
public static string OfflineAccessDescription = "Access to your applications and resources, even when you are offline";
public static readonly string MustChooseOneErrorMessage = "You must pick at least one permission";
public static readonly string InvalidSelectionErrorMessage = "Invalid selection";
}

+ 16
- 0
src/Services/Identity/Identity.API/Quickstart/Consent/ConsentViewModel.cs View File

@ -0,0 +1,16 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class ConsentViewModel : ConsentInputModel
{
public string ClientName { get; set; }
public string ClientUrl { get; set; }
public string ClientLogoUrl { get; set; }
public bool AllowRememberConsent { get; set; }
public IEnumerable<ScopeViewModel> IdentityScopes { get; set; }
public IEnumerable<ScopeViewModel> ApiScopes { get; set; }
}

+ 17
- 0
src/Services/Identity/Identity.API/Quickstart/Consent/ProcessConsentResult.cs View File

@ -0,0 +1,17 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class ProcessConsentResult
{
public bool IsRedirect => RedirectUri != null;
public string RedirectUri { get; set; }
public Client Client { get; set; }
public bool ShowView => ViewModel != null;
public ConsentViewModel ViewModel { get; set; }
public bool HasValidationError => ValidationError != null;
public string ValidationError { get; set; }
}

+ 15
- 0
src/Services/Identity/Identity.API/Quickstart/Consent/ScopeViewModel.cs View File

@ -0,0 +1,15 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class ScopeViewModel
{
public string Value { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public bool Emphasize { get; set; }
public bool Required { get; set; }
public bool Checked { get; set; }
}

+ 10
- 0
src/Services/Identity/Identity.API/Quickstart/Device/DeviceAuthorizationInputModel.cs View File

@ -0,0 +1,10 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class DeviceAuthorizationInputModel : ConsentInputModel
{
public string UserCode { get; set; }
}

+ 11
- 0
src/Services/Identity/Identity.API/Quickstart/Device/DeviceAuthorizationViewModel.cs View File

@ -0,0 +1,11 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class DeviceAuthorizationViewModel : ConsentViewModel
{
public string UserCode { get; set; }
public bool ConfirmUserCode { get; set; }
}

+ 214
- 0
src/Services/Identity/Identity.API/Quickstart/Device/DeviceController.cs View File

@ -0,0 +1,214 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
[Authorize]
[SecurityHeaders]
public class DeviceController : Controller
{
private readonly IDeviceFlowInteractionService _interaction;
private readonly IEventService _events;
private readonly IOptions<IdentityServerOptions> _options;
private readonly ILogger<DeviceController> _logger;
public DeviceController(
IDeviceFlowInteractionService interaction,
IEventService eventService,
IOptions<IdentityServerOptions> options,
ILogger<DeviceController> logger)
{
_interaction = interaction;
_events = eventService;
_options = options;
_logger = logger;
}
[HttpGet]
public async Task<IActionResult> Index()
{
string userCodeParamName = _options.Value.UserInteraction.DeviceVerificationUserCodeParameter;
string userCode = Request.Query[userCodeParamName];
if (string.IsNullOrWhiteSpace(userCode)) return View("UserCodeCapture");
var vm = await BuildViewModelAsync(userCode);
if (vm == null) return View("Error");
vm.ConfirmUserCode = true;
return View("UserCodeConfirmation", vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> UserCodeCapture(string userCode)
{
var vm = await BuildViewModelAsync(userCode);
if (vm == null) return View("Error");
return View("UserCodeConfirmation", vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Callback(DeviceAuthorizationInputModel model)
{
if (model == null) throw new ArgumentNullException(nameof(model));
var result = await ProcessConsent(model);
if (result.HasValidationError) return View("Error");
return View("Success");
}
private async Task<ProcessConsentResult> ProcessConsent(DeviceAuthorizationInputModel model)
{
var result = new ProcessConsentResult();
var request = await _interaction.GetAuthorizationContextAsync(model.UserCode);
if (request == null) return result;
ConsentResponse grantedConsent = null;
// user clicked 'no' - send back the standard 'access_denied' response
if (model.Button == "no")
{
grantedConsent = new ConsentResponse { Error = AuthorizationError.AccessDenied };
// emit event
await _events.RaiseAsync(new ConsentDeniedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues));
}
// user clicked 'yes' - validate the data
else if (model.Button == "yes")
{
// if the user consented to some scope, build the response model
if (model.ScopesConsented != null && model.ScopesConsented.Any())
{
var scopes = model.ScopesConsented;
if (ConsentOptions.EnableOfflineAccess == false)
{
scopes = scopes.Where(x => x != IdentityServerConstants.StandardScopes.OfflineAccess);
}
grantedConsent = new ConsentResponse
{
RememberConsent = model.RememberConsent,
ScopesValuesConsented = scopes.ToArray(),
Description = model.Description
};
// emit event
await _events.RaiseAsync(new ConsentGrantedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues, grantedConsent.ScopesValuesConsented, grantedConsent.RememberConsent));
}
else
{
result.ValidationError = ConsentOptions.MustChooseOneErrorMessage;
}
}
else
{
result.ValidationError = ConsentOptions.InvalidSelectionErrorMessage;
}
if (grantedConsent != null)
{
// communicate outcome of consent back to identityserver
await _interaction.HandleRequestAsync(model.UserCode, grantedConsent);
// indicate that's it ok to redirect back to authorization endpoint
result.RedirectUri = model.ReturnUrl;
result.Client = request.Client;
}
else
{
// we need to redisplay the consent UI
result.ViewModel = await BuildViewModelAsync(model.UserCode, model);
}
return result;
}
private async Task<DeviceAuthorizationViewModel> BuildViewModelAsync(string userCode, DeviceAuthorizationInputModel model = null)
{
var request = await _interaction.GetAuthorizationContextAsync(userCode);
if (request != null)
{
return CreateConsentViewModel(userCode, model, request);
}
return null;
}
private DeviceAuthorizationViewModel CreateConsentViewModel(string userCode, DeviceAuthorizationInputModel model, DeviceFlowAuthorizationRequest request)
{
var vm = new DeviceAuthorizationViewModel
{
UserCode = userCode,
Description = model?.Description,
RememberConsent = model?.RememberConsent ?? true,
ScopesConsented = model?.ScopesConsented ?? Enumerable.Empty<string>(),
ClientName = request.Client.ClientName ?? request.Client.ClientId,
ClientUrl = request.Client.ClientUri,
ClientLogoUrl = request.Client.LogoUri,
AllowRememberConsent = request.Client.AllowRememberConsent
};
vm.IdentityScopes = request.ValidatedResources.Resources.IdentityResources.Select(x => CreateScopeViewModel(x, vm.ScopesConsented.Contains(x.Name) || model == null)).ToArray();
var apiScopes = new List<ScopeViewModel>();
foreach (var parsedScope in request.ValidatedResources.ParsedScopes)
{
var apiScope = request.ValidatedResources.Resources.FindApiScope(parsedScope.ParsedName);
if (apiScope != null)
{
var scopeVm = CreateScopeViewModel(parsedScope, apiScope, vm.ScopesConsented.Contains(parsedScope.RawValue) || model == null);
apiScopes.Add(scopeVm);
}
}
if (ConsentOptions.EnableOfflineAccess && request.ValidatedResources.Resources.OfflineAccess)
{
apiScopes.Add(GetOfflineAccessScope(vm.ScopesConsented.Contains(IdentityServerConstants.StandardScopes.OfflineAccess) || model == null));
}
vm.ApiScopes = apiScopes;
return vm;
}
private ScopeViewModel CreateScopeViewModel(IdentityResource identity, bool check)
{
return new ScopeViewModel
{
Value = identity.Name,
DisplayName = identity.DisplayName ?? identity.Name,
Description = identity.Description,
Emphasize = identity.Emphasize,
Required = identity.Required,
Checked = check || identity.Required
};
}
public ScopeViewModel CreateScopeViewModel(ParsedScopeValue parsedScopeValue, ApiScope apiScope, bool check)
{
return new ScopeViewModel
{
Value = parsedScopeValue.RawValue,
DisplayName = apiScope.DisplayName ?? apiScope.Name,
Description = apiScope.Description,
Emphasize = apiScope.Emphasize,
Required = apiScope.Required,
Checked = check || apiScope.Required
};
}
private ScopeViewModel GetOfflineAccessScope(bool check)
{
return new ScopeViewModel
{
Value = IdentityServerConstants.StandardScopes.OfflineAccess,
DisplayName = ConsentOptions.OfflineAccessDisplayName,
Description = ConsentOptions.OfflineAccessDescription,
Emphasize = true,
Checked = check
};
}
}

+ 22
- 0
src/Services/Identity/Identity.API/Quickstart/Diagnostics/DiagnosticsController.cs View File

@ -0,0 +1,22 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
[SecurityHeaders]
[Authorize]
public class DiagnosticsController : Controller
{
public async Task<IActionResult> Index()
{
var localAddresses = new string[] { "127.0.0.1", "::1", HttpContext.Connection.LocalIpAddress.ToString() };
if (!localAddresses.Contains(HttpContext.Connection.RemoteIpAddress.ToString()))
{
return NotFound();
}
var model = new DiagnosticsViewModel(await HttpContext.AuthenticateAsync());
return View(model);
}
}

+ 28
- 0
src/Services/Identity/Identity.API/Quickstart/Diagnostics/DiagnosticsViewModel.cs View File

@ -0,0 +1,28 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using System.Text;
using System.Text.Json;
namespace IdentityServerHost.Quickstart.UI;
public class DiagnosticsViewModel
{
public DiagnosticsViewModel(AuthenticateResult result)
{
AuthenticateResult = result;
if (result.Properties.Items.ContainsKey("client_list"))
{
var encoded = result.Properties.Items["client_list"];
var bytes = Base64Url.Decode(encoded);
var value = Encoding.UTF8.GetString(bytes);
Clients = JsonSerializer.Deserialize<string[]>(value);
}
}
public AuthenticateResult AuthenticateResult { get; }
public IEnumerable<string> Clients { get; } = new List<string>();
}

+ 22
- 0
src/Services/Identity/Identity.API/Quickstart/Extensions.cs View File

@ -0,0 +1,22 @@
namespace IdentityServerHost.Quickstart.UI;
public static class Extensions
{
/// <summary>
/// Checks if the redirect URI is for a native client.
/// </summary>
/// <returns></returns>
public static bool IsNativeClient(this AuthorizationRequest context)
{
return !context.RedirectUri.StartsWith("https", StringComparison.Ordinal)
&& !context.RedirectUri.StartsWith("http", StringComparison.Ordinal);
}
public static IActionResult LoadingPage(this Controller controller, string viewName, string redirectUri)
{
controller.HttpContext.Response.StatusCode = 200;
controller.HttpContext.Response.Headers["Location"] = "";
return controller.View(viewName, new RedirectViewModel { RedirectUrl = redirectUri });
}
}

+ 85
- 0
src/Services/Identity/Identity.API/Quickstart/Grants/GrantsController.cs View File

@ -0,0 +1,85 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
/// <summary>
/// This sample controller allows a user to revoke grants given to clients
/// </summary>
[SecurityHeaders]
[Authorize]
public class GrantsController : Controller
{
private readonly IIdentityServerInteractionService _interaction;
private readonly IClientStore _clients;
private readonly IResourceStore _resources;
private readonly IEventService _events;
public GrantsController(IIdentityServerInteractionService interaction,
IClientStore clients,
IResourceStore resources,
IEventService events)
{
_interaction = interaction;
_clients = clients;
_resources = resources;
_events = events;
}
/// <summary>
/// Show list of grants
/// </summary>
[HttpGet]
public async Task<IActionResult> Index()
{
return View("Index", await BuildViewModelAsync());
}
/// <summary>
/// Handle postback to revoke a client
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Revoke(string clientId)
{
await _interaction.RevokeUserConsentAsync(clientId);
await _events.RaiseAsync(new GrantsRevokedEvent(User.GetSubjectId(), clientId));
return RedirectToAction("Index");
}
private async Task<GrantsViewModel> BuildViewModelAsync()
{
var grants = await _interaction.GetAllUserGrantsAsync();
var list = new List<GrantViewModel>();
foreach (var grant in grants)
{
var client = await _clients.FindClientByIdAsync(grant.ClientId);
if (client != null)
{
var resources = await _resources.FindResourcesByScopeAsync(grant.Scopes);
var item = new GrantViewModel()
{
ClientId = client.ClientId,
ClientName = client.ClientName ?? client.ClientId,
ClientLogoUrl = client.LogoUri,
ClientUrl = client.ClientUri,
Description = grant.Description,
Created = grant.CreationTime,
Expires = grant.Expiration,
IdentityGrantNames = resources.IdentityResources.Select(x => x.DisplayName ?? x.Name).ToArray(),
ApiGrantNames = resources.ApiScopes.Select(x => x.DisplayName ?? x.Name).ToArray()
};
list.Add(item);
}
}
return new GrantsViewModel
{
Grants = list
};
}
}

+ 23
- 0
src/Services/Identity/Identity.API/Quickstart/Grants/GrantsViewModel.cs View File

@ -0,0 +1,23 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class GrantsViewModel
{
public IEnumerable<GrantViewModel> Grants { get; set; }
}
public class GrantViewModel
{
public string ClientId { get; set; }
public string ClientName { get; set; }
public string ClientUrl { get; set; }
public string ClientLogoUrl { get; set; }
public string Description { get; set; }
public DateTime Created { get; set; }
public DateTime? Expires { get; set; }
public IEnumerable<string> IdentityGrantNames { get; set; }
public IEnumerable<string> ApiGrantNames { get; set; }
}

+ 18
- 0
src/Services/Identity/Identity.API/Quickstart/Home/ErrorViewModel.cs View File

@ -0,0 +1,18 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class ErrorViewModel
{
public ErrorViewModel()
{
}
public ErrorViewModel(string error)
{
Error = new ErrorMessage { Error = error };
}
public ErrorMessage Error { get; set; }
}

+ 63
- 0
src/Services/Identity/Identity.API/Quickstart/Home/HomeController.cs View File

@ -0,0 +1,63 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace IdentityServerHost.Quickstart.UI
{
[SecurityHeaders]
[AllowAnonymous]
public class HomeController : Controller
{
private readonly IIdentityServerInteractionService _interaction;
private readonly IWebHostEnvironment _environment;
private readonly ILogger _logger;
public HomeController(
IIdentityServerInteractionService interaction,
IWebHostEnvironment environment,
ILogger<HomeController> logger)
{
_interaction = interaction;
_environment = environment;
_logger = logger;
}
public IActionResult Index()
{
if (_environment.IsDevelopment())
{
// only show in development
return View();
}
_logger.LogInformation("Homepage is disabled in production. Returning 404.");
return NotFound();
}
/// <summary>
/// Shows the error page
/// </summary>
public async Task<IActionResult> Error(string errorId)
{
var vm = new ErrorViewModel();
// retrieve error details from identityserver
var message = await _interaction.GetErrorContextAsync(errorId);
if (message != null)
{
vm.Error = message;
if (!_environment.IsDevelopment())
{
// only show in development
message.ErrorDescription = null;
}
}
return View("Error", vm);
}
}
}

+ 52
- 0
src/Services/Identity/Identity.API/Quickstart/SecurityHeadersAttribute.cs View File

@ -0,0 +1,52 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServerHost.Quickstart.UI;
public class SecurityHeadersAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
var result = context.Result;
if (result is ViewResult)
{
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
if (!context.HttpContext.Response.Headers.ContainsKey("X-Content-Type-Options"))
{
context.HttpContext.Response.Headers.Add("X-Content-Type-Options", "nosniff");
}
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
if (!context.HttpContext.Response.Headers.ContainsKey("X-Frame-Options"))
{
context.HttpContext.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
}
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
var csp = "default-src 'self'; object-src 'none'; frame-ancestors 'none'; sandbox allow-forms allow-same-origin allow-scripts; base-uri 'self';";
// also consider adding upgrade-insecure-requests once you have HTTPS in place for production
//csp += "upgrade-insecure-requests;";
// also an example if you need client images to be displayed from twitter
// csp += "img-src 'self' https://pbs.twimg.com;";
// once for standards compliant browsers
if (!context.HttpContext.Response.Headers.ContainsKey("Content-Security-Policy"))
{
context.HttpContext.Response.Headers.Add("Content-Security-Policy", csp);
}
// and once again for IE
if (!context.HttpContext.Response.Headers.ContainsKey("X-Content-Security-Policy"))
{
context.HttpContext.Response.Headers.Add("X-Content-Security-Policy", csp);
}
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
var referrer_policy = "no-referrer";
if (!context.HttpContext.Response.Headers.ContainsKey("Referrer-Policy"))
{
context.HttpContext.Response.Headers.Add("Referrer-Policy", referrer_policy);
}
}
}
}

+ 124
- 0
src/Services/Identity/Identity.API/SeedData.cs View File

@ -0,0 +1,124 @@
using System.Threading.Tasks;
using System;
namespace Microsoft.eShopOnContainers.Services.Identity.API;
public class SeedData
{
public static async Task EnsureSeedData(IServiceScope scope, IConfiguration configuration, Microsoft.Extensions.Logging.ILogger logger)
{
var retryPolicy = CreateRetryPolicy(configuration, logger);
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await retryPolicy.ExecuteAsync(async () =>
{
await context.Database.MigrateAsync();
var userMgr = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var alice = await userMgr.FindByNameAsync("alice");
if (alice == null)
{
alice = new ApplicationUser
{
UserName = "alice",
Email = "AliceSmith@email.com",
EmailConfirmed = true,
CardHolderName = "Alice Smith",
CardNumber = "4012888888881881",
CardType = 1,
City = "Redmond",
Country = "U.S.",
Expiration = "12/24",
Id = Guid.NewGuid().ToString(),
LastName = "Smith",
Name = "Alice",
PhoneNumber = "1234567890",
ZipCode = "98052",
State = "WA",
Street = "15703 NE 61st Ct",
SecurityNumber = "123"
};
var result = userMgr.CreateAsync(alice, "Pass123$").Result;
if (!result.Succeeded)
{
throw new Exception(result.Errors.First().Description);
}
logger.LogDebug("alice created");
}
else
{
logger.LogDebug("alice already exists");
}
var bob = await userMgr.FindByNameAsync("bob");
if (bob == null)
{
bob = new ApplicationUser
{
UserName = "bob",
Email = "BobSmith@email.com",
EmailConfirmed = true,
CardHolderName = "Bob Smith",
CardNumber = "4012888888881881",
CardType = 1,
City = "Redmond",
Country = "U.S.",
Expiration = "12/24",
Id = Guid.NewGuid().ToString(),
LastName = "Smith",
Name = "Bob",
PhoneNumber = "1234567890",
ZipCode = "98052",
State = "WA",
Street = "15703 NE 61st Ct",
SecurityNumber = "456"
};
var result = await userMgr.CreateAsync(bob, "Pass123$");
if (!result.Succeeded)
{
throw new Exception(result.Errors.First().Description);
}
logger.LogDebug("bob created");
}
else
{
logger.LogDebug("bob already exists");
}
});
}
private static AsyncPolicy CreateRetryPolicy(IConfiguration configuration, Microsoft.Extensions.Logging.ILogger logger)
{
var retryMigrations = false;
bool.TryParse(configuration["RetryMigrations"], out retryMigrations);
// Only use a retry policy if configured to do so.
// When running in an orchestrator/K8s, it will take care of restarting failed services.
if (retryMigrations)
{
return Policy.Handle<Exception>().
WaitAndRetryForeverAsync(
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
onRetry: (exception, retry, timeSpan) =>
{
logger.LogWarning(
exception,
"Exception {ExceptionType} with message {Message} detected during database migration (retry attempt {retry})",
exception.GetType().Name,
exception.Message,
retry);
}
);
}
return Policy.NoOpAsync();
}
}

+ 0
- 2
src/Services/Identity/Identity.API/Setup/Users.csv View File

@ -1,2 +0,0 @@
CardHolderName,CardNumber,CardType,City,Country,Email,Expiration,LastName,Name,PhoneNumber,UserName,ZipCode,State,Street,SecurityNumber,NormalizedEmail,NormalizedUserName,Password
DemoUser,4012888888881881,1,Redmond,U.S.,demouser@microsoft.com,12/25,DemoLastName,DemoUser,1234567890,demouser@microsoft.com,98052,WA,15703 NE 61st Ct,535,DEMOUSER@MICROSOFT.COM,DEMOUSER@MICROSOFT.COM,Pass@word1

BIN
src/Services/Identity/Identity.API/Setup/images.zip View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save