Merge pull request #2012 from erjain/net7-duende-fix
update to Net7 and Duende IdentityServer 6.2
This commit is contained in:
		
						commit
						e15a62270c
					
				
							
								
								
									
										2
									
								
								.github/workflows/catalog-api.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/catalog-api.yml
									
									
									
									
										vendored
									
									
								
							| @ -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 | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.github/workflows/ordering-api.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ordering-api.yml
									
									
									
									
										vendored
									
									
								
							| @ -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 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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,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 | ||||||
|  | |||||||
| @ -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; | ||||||
| @ -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.UI.Client" Version="6.0.5" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.Uris" Version="5.0.1" /> |     <PackageReference Include="AspNetCore.HealthChecks.Uris" Version="6.0.3" /> | ||||||
|     <PackageReference Include="Google.Protobuf" Version="3.15.0" /> |     <PackageReference Include="Google.Protobuf" Version="3.21.9" /> | ||||||
|     <PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.34.0" /> |     <PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.50.0" /> | ||||||
|     <PackageReference Include="Grpc.Core" Version="2.34.0" /> |     <PackageReference Include="Grpc.Core" Version="2.46.5" /> | ||||||
|     <PackageReference Include="Grpc.Net.ClientFactory" Version="2.34.0" /> |     <PackageReference Include="Grpc.Net.ClientFactory" Version="2.50.0" /> | ||||||
|     <PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" /> |     <PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" /> | ||||||
|     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.9" /> |     <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="Microsoft.Extensions.Diagnostics.HealthChecks" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" /> |     <PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" /> | ||||||
|     <PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" /> |     <PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" /> | ||||||
|     <PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" /> |     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  | |||||||
| @ -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) | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -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,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 | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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 => |         services.AddAuthentication("Bearer") | ||||||
|         { |  | ||||||
|             options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; |  | ||||||
|             options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; |  | ||||||
| 
 |  | ||||||
|         }) |  | ||||||
|         .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 | ||||||
|             { |             { | ||||||
|  | |||||||
| @ -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.UI.Client" Version="6.0.5" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.Uris" Version="5.0.1" /> |     <PackageReference Include="AspNetCore.HealthChecks.Uris" Version="6.0.3" /> | ||||||
|     <PackageReference Include="Google.Protobuf" Version="3.15.0" /> |     <PackageReference Include="Google.Protobuf" Version="3.21.9" /> | ||||||
|     <PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.34.0" /> |     <PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.50.0" /> | ||||||
|     <PackageReference Include="Grpc.Core" Version="2.34.0" /> |     <PackageReference Include="Grpc.Core" Version="2.46.5" /> | ||||||
|     <PackageReference Include="Grpc.Net.Client" Version="2.34.0" /> |     <PackageReference Include="Grpc.Net.Client" Version="2.50.0" /> | ||||||
|     <PackageReference Include="Grpc.Net.ClientFactory" Version="2.34.0" /> |     <PackageReference Include="Grpc.Net.ClientFactory" Version="2.50.0" /> | ||||||
|     <PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" /> |     <PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" /> | ||||||
|     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.9" /> |     <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="Microsoft.Extensions.Diagnostics.HealthChecks" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" /> |     <PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" /> | ||||||
|     <PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" /> |     <PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" /> | ||||||
|     <PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" /> |     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  | |||||||
| @ -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.DependencyInjection.Abstractions" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" /> |     <PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| </Project> | </Project> | ||||||
|  | |||||||
| @ -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="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" /> | ||||||
|     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> |     <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,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> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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="Microsoft.Extensions.Logging" Version="7.0.0" />     | ||||||
|     <PackageReference Include="Polly" Version="7.2.1" /> |     <PackageReference Include="Polly" Version="7.2.3" /> | ||||||
|     <PackageReference Include="RabbitMQ.Client" Version="6.2.1" /> |     <PackageReference Include="RabbitMQ.Client" Version="6.4.0" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  | |||||||
| @ -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="Autofac" Version="6.5.0" /> | ||||||
|     <PackageReference Include="Azure.Messaging.ServiceBus" Version="7.2.1" /> |     <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> | ||||||
|  | |||||||
| @ -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.Relational" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" /> |     <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0" />     |     <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />     | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  | |||||||
| @ -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.Relational" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.2" /> |     <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.2" /> |     <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" /> |     <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.0" /> |     <PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Polly" Version="7.2.1" /> |     <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> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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.AzureServiceBus" Version="6.0.4" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="5.0.1" /> |     <PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.Redis" Version="5.0.2" /> |     <PackageReference Include="AspNetCore.HealthChecks.Redis" Version="6.0.4" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" /> |     <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" /> | ||||||
|     <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0-preview.1" /> |     <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" /> | ||||||
|     <PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.1" /> |     <PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.2" /> | ||||||
|     <PackageReference Include="Azure.Identity" Version="1.4.0" /> |     <PackageReference Include="Azure.Identity" Version="1.9.0-beta.1" /> | ||||||
| 	  <PackageReference Include="Google.Protobuf" Version="3.15.0" /> | 	  <PackageReference Include="Google.Protobuf" Version="3.21.9" /> | ||||||
| 	  <PackageReference Include="Grpc.AspNetCore.Server" Version="2.34.0" /> | 	  <PackageReference Include="Grpc.AspNetCore.Server" Version="2.50.0" /> | ||||||
| 	  <PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" /> | 	  <PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" /> | ||||||
| 	  <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.18.0" /> | 	  <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0-beta1" /> | ||||||
|     <PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.18.0" /> |     <PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0-beta1" /> | ||||||
|     <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2-beta2" /> |     <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="3.1.0" /> | ||||||
|     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.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.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" /> |     <PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.24" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" /> |     <PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" />     |     <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />     | ||||||
|     <PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" /> |     <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.Settings.Configuration" Version="3.5.0-dev-00359" /> | ||||||
|     <PackageReference Include="Serilog.Sinks.Console" Version="4.0.1-dev-00876" /> |     <PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" /> | ||||||
|     <PackageReference Include="Serilog.Sinks.Http" Version="8.0.0-beta.9" /> |     <PackageReference Include="Serilog.Sinks.Http" Version="8.0.0" /> | ||||||
|     <PackageReference Include="Serilog.Sinks.Seq" Version="4.1.0-dev-00166" /> |     <PackageReference Include="Serilog.Sinks.Seq" Version="5.2.3-dev-00260" /> | ||||||
|     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" /> |     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> | ||||||
|     <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" /> |     <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  | |||||||
| @ -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,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 | ||||||
|  | |||||||
| @ -59,3 +59,4 @@ 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; | ||||||
| @ -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(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -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 => |         services.AddAuthentication("Bearer").AddJwtBearer(options => | ||||||
|         { |  | ||||||
|             options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; |  | ||||||
|             options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; |  | ||||||
| 
 |  | ||||||
|         }).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"); | ||||||
|  |             }); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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.Mvc.Testing" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.0" /> |     <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.0" /> | ||||||
| 	<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="6.0.0" /> | 	<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" /> |     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" /> | ||||||
|     <PackageReference Include="Moq" Version="4.15.2" /> |     <PackageReference Include="Moq" Version="4.18.2" /> | ||||||
|     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> |     <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> | ||||||
|  | |||||||
| @ -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="MediatR" Version="11.1.0" /> | ||||||
|     <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0" /> |     <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="6.0.0" /> |     <PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" /> |     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" /> | ||||||
|     <PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.0" /> |     <PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Moq" Version="4.15.2" /> |     <PackageReference Include="Moq" Version="4.18.2" /> | ||||||
|     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> |     <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> | ||||||
|  | |||||||
| @ -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="System.IdentityModel.Tokens.Jwt" Version="6.25.0" /> | ||||||
| 	  <PackageReference Include="Azure.Identity" Version="1.5.0-beta.3" /> | 	  <PackageReference Include="Azure.Identity" Version="1.9.0-beta.1" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="5.1.1" /> |     <PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="6.0.4" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="5.0.1" /> |     <PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="6.1.1" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="5.0.1" /> |     <PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="5.0.3" /> |     <PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="6.0.2" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" /> |     <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" /> | ||||||
|     <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0-preview.1" /> |     <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" /> | ||||||
|     <PackageReference Include="Google.Protobuf" Version="3.15.0" /> |     <PackageReference Include="Google.Protobuf" Version="3.21.9" /> | ||||||
|     <PackageReference Include="Grpc.AspNetCore.Server" Version="2.34.0" /> |     <PackageReference Include="Grpc.AspNetCore.Server" Version="2.50.0" /> | ||||||
|     <PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />     |     <PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" />     | ||||||
|     <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.18.0" /> |     <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0-beta1" /> | ||||||
|     <PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.18.0" /> |     <PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0-beta1" /> | ||||||
|     <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2-beta2" /> |     <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.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" /> |     <PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.24" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" /> |     <PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" /> |     <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" /> | ||||||
|     <PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" /> |     <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.Settings.Configuration" Version="3.5.0-dev-00359" /> | ||||||
|     <PackageReference Include="Serilog.Sinks.Console" Version="4.0.1-dev-00876" /> |     <PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" /> | ||||||
|     <PackageReference Include="Serilog.Sinks.Http" Version="8.0.0-beta.9" /> |     <PackageReference Include="Serilog.Sinks.Http" Version="8.0.0" /> | ||||||
|     <PackageReference Include="Serilog.Sinks.Seq" Version="4.1.0-dev-00166" /> |     <PackageReference Include="Serilog.Sinks.Seq" Version="5.2.3-dev-00260" /> | ||||||
|     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" /> |     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> | ||||||
|     <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" /> |     <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" /> | ||||||
|     <PackageReference Include="System.Data.SqlClient" version="4.8.2"/> |     <PackageReference Include="System.Data.SqlClient" version="4.8.5" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="6.0.0" /> |     <PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" /> |     <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.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> | ||||||
|  | |||||||
| @ -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,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 | ||||||
|  | |||||||
| @ -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(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -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.Mvc.Testing" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.0" /> |     <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" /> |     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" /> | ||||||
|     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> |     <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> | ||||||
|  | |||||||
| @ -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.EntityFrameworkCore.InMemory" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" /> |     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" /> | ||||||
|     <PackageReference Include="Microsoft.NETCore.Platforms" Version="6.0.0" /> |     <PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Moq" Version="4.15.2" /> |     <PackageReference Include="Moq" Version="4.18.2" /> | ||||||
|     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> |     <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> | ||||||
|  | |||||||
| @ -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(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
										
											Binary file not shown.
										
									
								
							| @ -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 | ||||||
| { | { | ||||||
| @ -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"]}/" }, |                     PostLogoutRedirectUris = { $"{configuration["SpaClient"]}/" }, | ||||||
|                     AllowedCorsOrigins =     { $"{clientsUrl["Spa"]}" }, |                     AllowedCorsOrigins =     { $"{configuration["SpaClient"]}" }, | ||||||
|                     AllowedScopes = |                     AllowedScopes = | ||||||
|                     { |                     { | ||||||
|                         IdentityServerConstants.StandardScopes.OpenId, |                         IdentityServerConstants.StandardScopes.OpenId, | ||||||
| @ -66,10 +81,10 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration | |||||||
|                     { |                     { | ||||||
|                         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> | ||||||
|                     { |                     { | ||||||
| @ -94,19 +109,20 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration | |||||||
| 
 | 
 | ||||||
|                         new Secret("secret".Sha256()) |                         new Secret("secret".Sha256()) | ||||||
|                     }, |                     }, | ||||||
|                     ClientUri = $"{clientsUrl["Mvc"]}",                             // public uri of the client |                     ClientUri = $"{configuration["MvcClient"]}",                             // public uri of the client | ||||||
|                     AllowedGrantTypes = GrantTypes.Hybrid, |                     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 |                     ClientUri = $"{configuration["WebhooksWebClient"]}",                             // public uri of the client | ||||||
|                     AllowedGrantTypes = GrantTypes.Hybrid, |                     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 |                     ClientUri = $"{configuration["Mvc"]}",                             // public uri of the client | ||||||
|                     AllowedGrantTypes = GrantTypes.Hybrid, |                     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" }, |                     RedirectUris = { $"{configuration["BasketApiClient"]}/swagger/oauth2-redirect.html" }, | ||||||
|                     PostLogoutRedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/" }, |                     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" }, |                     RedirectUris = { $"{configuration["OrderingApiClient"]}/swagger/oauth2-redirect.html" }, | ||||||
|                     PostLogoutRedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/" }, |                     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" }, |                     RedirectUris = { $"{configuration["MobileShoppingAggClient"]}/swagger/oauth2-redirect.html" }, | ||||||
|                     PostLogoutRedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/" }, |                     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" }, |                     RedirectUris = { $"{configuration["WebShoppingAggClient"]}/swagger/oauth2-redirect.html" }, | ||||||
|                     PostLogoutRedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/" }, |                     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" }, |                     RedirectUris = { $"{configuration["WebhooksApiClient"]}/swagger/oauth2-redirect.html" }, | ||||||
|                     PostLogoutRedirectUris = { $"{clientsUrl["WebhooksApi"]}/swagger/" }, |                     PostLogoutRedirectUris = { $"{configuration["WebhooksApiClient"]}/swagger/" }, | ||||||
| 
 | 
 | ||||||
|                     AllowedScopes = |                     AllowedScopes = | ||||||
|                     { |                     { | ||||||
|  | |||||||
| @ -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); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,7 +1,7 @@ | |||||||
| 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) |     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) | ||||||
|         : base(options) |         : base(options) | ||||||
|     { |     { | ||||||
| @ -14,5 +14,4 @@ | |||||||
|         // For example, you can rename the ASP.NET Identity table names and more. |         // For example, you can rename the ASP.NET Identity table names and more. | ||||||
|         // Add your customizations after calling base.OnModelCreating(builder); |         // Add your customizations after calling base.OnModelCreating(builder); | ||||||
|     } |     } | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -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); ; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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 => | ||||||
| @ -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 | ||||||
|     { |     { | ||||||
| @ -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 => | ||||||
| @ -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); | ||||||
|  | |||||||
| @ -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,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,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; } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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 Duende.IdentityServer; | ||||||
| global using IdentityServer4.EntityFramework.Mappers; | global using Duende.IdentityServer.Configuration; | ||||||
| global using IdentityServer4.EntityFramework.Options; | global using Duende.IdentityServer.Events; | ||||||
| global using IdentityServer4.Models; | global using Duende.IdentityServer.Extensions; | ||||||
| global using IdentityServer4.Services; | global using Duende.IdentityServer.Models; | ||||||
| global using IdentityServer4.Stores; | global using Duende.IdentityServer.Services; | ||||||
| global using IdentityServer4.Validation; | global using Duende.IdentityServer.Stores; | ||||||
| global using IdentityServer4; | 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; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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\**\*;"> |     <PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="6.0.2" /> | ||||||
|       <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> |     <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" /> | ||||||
|     </Content> |     <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" /> | ||||||
|   </ItemGroup> |     <PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="6.2.0" /> | ||||||
| 
 |     <PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" Version="6.2.0" /> | ||||||
|   <ItemGroup> |     <PackageReference Include="Duende.IdentityServer.EntityFramework" Version="6.2.0" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="5.0.3" /> |     <PackageReference Include="Duende.IdentityServer.Storage" Version="6.2.0" /> | ||||||
|     <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" /> |     <PackageReference Include="Duende.IdentityServer" Version="6.2.0" /> | ||||||
|     <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0-preview.1" /> |     <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0-beta1" /> | ||||||
|     <PackageReference Include="IdentityServer4.AspNetIdentity" Version="3.1.4" /> |     <PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0-beta1" /> | ||||||
|     <PackageReference Include="IdentityServer4.EntityFramework.Storage" Version="3.1.4" /> |     <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="3.1.0" /> | ||||||
|     <PackageReference Include="IdentityServer4.EntityFramework" Version="3.1.4" /> |     <PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="7.0.0" /> | ||||||
|     <PackageReference Include="IdentityServer4.Storage" Version="3.1.4" /> |     <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.0" /> | ||||||
|     <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="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.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.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.Relational" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" /> | 
 | ||||||
|     <PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" /> | 	  <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" /> |     <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" /> | ||||||
|     <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" /> |     <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="Polly" Version="7.2.3" /> | ||||||
|     <PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" /> |     <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.Settings.Configuration" Version="3.5.0-dev-00359" /> | ||||||
|     <PackageReference Include="Serilog.Sinks.Console" Version="4.0.1-dev-00876" /> |     <PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" /> | ||||||
|     <PackageReference Include="Serilog.Sinks.Http" Version="8.0.0-beta.9" /> |     <PackageReference Include="Serilog.Sinks.Http" Version="8.0.0" /> | ||||||
|     <PackageReference Include="Serilog.Sinks.Seq" Version="5.0.1" /> |     <PackageReference Include="Serilog.Sinks.Seq" Version="5.2.3-dev-00260" /> | ||||||
|     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" /> |     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> | ||||||
|     <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" /> |     <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" /> | ||||||
| 	  <PackageReference Include="System.Data.SqlClient" version="4.8.2" /> | 	  <PackageReference Include="System.Data.SqlClient" version="4.8.5" /> | ||||||
|     <PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.1" /> |     <PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.2" /> | ||||||
|     <PackageReference Include="Azure.Identity" Version="1.4.0" /> |     <PackageReference Include="Azure.Identity" Version="1.9.0-beta.1" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
| 	<ItemGroup> | 	<ItemGroup> | ||||||
|     <EmbeddedResource Include="Certificate\idsrv3test.pfx" /> | 	  <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> | 	</ItemGroup> | ||||||
| 
 | 	<ProjectExtensions> | ||||||
|   <ItemGroup> | 		<VisualStudio> | ||||||
|     <None Update="Setup\*"> | 			<UserProperties appsettings_1json__JsonSchema="" /> | ||||||
|       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | 		</VisualStudio> | ||||||
|     </None> | 	</ProjectExtensions> | ||||||
|   </ItemGroup> |  | ||||||
| 
 |  | ||||||
|   <ItemGroup> |  | ||||||
|     <Folder Include="Extensions\" /> |  | ||||||
|   </ItemGroup> |  | ||||||
| 
 |  | ||||||
| </Project> | </Project> | ||||||
|  | |||||||
| @ -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 |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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; } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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; } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | namespace Microsoft.eShopOnContainers.Services.Identity.API.Models.AccountViewModels | ||||||
|  | { | ||||||
|  |     public class RedirectViewModel | ||||||
|  |     { | ||||||
|  |         public string RedirectUrl { get; set; } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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"; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,71 +1,75 @@ | |||||||
| string Namespace = typeof(Startup).Namespace; | var appName = "Identity.API"; | ||||||
| string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1); | 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); |     app.Logger.LogInformation("Seeding database ({ApplicationName})...", appName); | ||||||
|     var host = BuildWebHost(configuration, args); |  | ||||||
| 
 | 
 | ||||||
|     Log.Information("Applying migrations ({ApplicationContext})...", AppName); |     // Apply database migration automatically. Note that this approach is not | ||||||
|     host.MigrateDbContext<PersistedGrantDbContext>((_, __) => { }) |     // recommended for production scenarios. Consider generating SQL scripts from | ||||||
|         .MigrateDbContext<ApplicationDbContext>((context, services) => |     // migrations instead. | ||||||
|  |     using (var scope = app.Services.CreateScope()) | ||||||
|     { |     { | ||||||
|             var env = services.GetService<IWebHostEnvironment>(); |         await SeedData.EnsureSeedData(scope, app.Configuration, app.Logger); | ||||||
|             var logger = services.GetService<ILogger<ApplicationDbContextSeed>>(); |     } | ||||||
|             var settings = services.GetService<IOptions<AppSettings>>(); |  | ||||||
| 
 | 
 | ||||||
|             new ApplicationDbContextSeed() |     app.Logger.LogInformation("Starting web host ({ApplicationName})...", appName); | ||||||
|                 .SeedAsync(context, env, logger, settings) |     app.Run(); | ||||||
|                 .Wait(); |  | ||||||
|         }) |  | ||||||
|         .MigrateDbContext<ConfigurationDbContext>((context, services) => |  | ||||||
|         { |  | ||||||
|             new ConfigurationDbContextSeed() |  | ||||||
|                 .SeedAsync(context, configuration) |  | ||||||
|                 .Wait(); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     Log.Information("Starting web host ({ApplicationContext})...", AppName); |  | ||||||
|     host.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(); |     Serilog.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(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| IConfiguration GetConfiguration() | IConfiguration GetConfiguration() | ||||||
|  | |||||||
							
								
								
									
										117
									
								
								src/Services/Identity/Identity.API/ProgramExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/Services/Identity/Identity.API/ProgramExtensions.cs
									
									
									
									
									
										Normal 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(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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"; | ||||||
|  | } | ||||||
| @ -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 } }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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; | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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; | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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 | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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"; | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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 | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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
									
								
								src/Services/Identity/Identity.API/Quickstart/Extensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/Services/Identity/Identity.API/Quickstart/Extensions.cs
									
									
									
									
									
										Normal 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 }); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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 | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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; } | ||||||
|  | } | ||||||
| @ -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); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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
									
								
								src/Services/Identity/Identity.API/SeedData.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/Services/Identity/Identity.API/SeedData.cs
									
									
									
									
									
										Normal 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(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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 |  | ||||||
| 
 | 
										
											Binary file not shown.
										
									
								
							Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user