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:
|
||||
SERVICE: catalog-api
|
||||
IMAGE: catalog.api
|
||||
DOTNET_VERSION: 6.0.x
|
||||
DOTNET_VERSION: 7.0.x
|
||||
PROJECT_PATH: Services/Catalog/Catalog.API
|
||||
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:
|
||||
SERVICE: ordering-api
|
||||
IMAGE: ordering.api
|
||||
DOTNET_VERSION: 6.0.x
|
||||
DOTNET_VERSION: 7.0.x
|
||||
PROJECT_PATH: Services/Ordering/Ordering.API
|
||||
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
|
||||
EXPOSE 80
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
|
||||
WORKDIR /src
|
||||
|
||||
# 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
|
||||
ENV ASPNETCORE_ENVIRONMENT=Development
|
||||
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;
|
||||
global using System;
|
||||
global using Microsoft.IdentityModel.Tokens;
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<AssemblyName>Mobile.Shopping.HttpAggregator</AssemblyName>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator</RootNamespace>
|
||||
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||
@ -14,19 +14,20 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="5.0.1" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
|
||||
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.34.0" />
|
||||
<PackageReference Include="Grpc.Core" Version="2.34.0" />
|
||||
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.34.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.9" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="6.0.3" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.21.9" />
|
||||
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.50.0" />
|
||||
<PackageReference Include="Grpc.Core" Version="2.46.5" />
|
||||
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.50.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.2" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -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
|
||||
{
|
||||
@ -86,7 +89,7 @@ public static class ServiceCollectionExtensions
|
||||
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.DescribeAllEnumsAsStrings();
|
||||
//options.DescribeAllEnumsAsStrings();
|
||||
options.SwaggerDoc("v1", new OpenApiInfo
|
||||
{
|
||||
Title = "Shopping Aggregator for Mobile Clients",
|
||||
@ -143,10 +146,26 @@ public static class ServiceCollectionExtensions
|
||||
options.Authority = identityUrl;
|
||||
options.RequireHttpsMetadata = false;
|
||||
options.Audience = "mobileshoppingagg";
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateAudience = false
|
||||
};
|
||||
});
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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
|
||||
EXPOSE 80
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
|
||||
WORKDIR /src
|
||||
|
||||
# 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
|
||||
ENV ASPNETCORE_ENVIRONMENT=Development
|
||||
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;
|
||||
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
|
||||
{
|
||||
@ -22,6 +25,7 @@ public class Startup
|
||||
|
||||
services.AddCustomMvc(Configuration)
|
||||
.AddCustomAuthentication(Configuration)
|
||||
//.AddCustomAuthorization(Configuration)
|
||||
.AddDevspaces()
|
||||
.AddApplicationServices()
|
||||
.AddGrpcServices();
|
||||
@ -83,22 +87,20 @@ public static class ServiceCollectionExtensions
|
||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
|
||||
|
||||
var identityUrl = configuration.GetValue<string>("urls:identity");
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
|
||||
})
|
||||
services.AddAuthentication("Bearer")
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.Authority = identityUrl;
|
||||
options.RequireHttpsMetadata = false;
|
||||
options.Audience = "webshoppingagg";
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateAudience = false
|
||||
};
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddOptions();
|
||||
@ -109,7 +111,7 @@ public static class ServiceCollectionExtensions
|
||||
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.DescribeAllEnumsAsStrings();
|
||||
//options.DescribeAllEnumsAsStrings();
|
||||
|
||||
options.SwaggerDoc("v1", new OpenApiInfo
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<AssemblyName>Web.Shopping.HttpAggregator</AssemblyName>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator</RootNamespace>
|
||||
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||
@ -14,20 +14,21 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="5.0.1" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
|
||||
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.34.0" />
|
||||
<PackageReference Include="Grpc.Core" Version="2.34.0" />
|
||||
<PackageReference Include="Grpc.Net.Client" Version="2.34.0" />
|
||||
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.34.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.9" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="6.0.3" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.21.9" />
|
||||
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.50.0" />
|
||||
<PackageReference Include="Grpc.Core" Version="2.46.5" />
|
||||
<PackageReference Include="Grpc.Net.Client" Version="2.50.0" />
|
||||
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.50.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.2" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,11 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -1,16 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBus</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<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.Extensions.Logging" Version="5.0.0" />
|
||||
<PackageReference Include="Polly" Version="7.2.1" />
|
||||
<PackageReference Include="RabbitMQ.Client" Version="6.2.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
|
||||
<PackageReference Include="Polly" Version="7.2.3" />
|
||||
<PackageReference Include="RabbitMQ.Client" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,15 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="6.1.0" />
|
||||
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.2.1" />
|
||||
<PackageReference Include="Autofac" Version="6.5.0" />
|
||||
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.11.1" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,18 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
|
||||
</PropertyGroup>
|
||||
|
||||
@ -10,16 +10,16 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.2">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.0" />
|
||||
<PackageReference Include="Polly" Version="7.2.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
|
||||
<PackageReference Include="Polly" Version="7.2.3" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
|
||||
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
|
||||
@ -14,36 +14,37 @@
|
||||
</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="AspNetCore.HealthChecks.AzureServiceBus" Version="5.1.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="5.0.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="5.0.2" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0-preview.1" />
|
||||
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.1" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.4.0" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
|
||||
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.34.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.18.0" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.18.0" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2-beta2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="6.0.4" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="6.0.4" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.2" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.9.0-beta.1" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.21.9" />
|
||||
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.50.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0-beta1" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0-beta1" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.24" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" />
|
||||
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0-dev-00291" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1-dev-00876" />
|
||||
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0-beta.9" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="4.1.0-dev-00166" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.5.0-dev-00359" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" />
|
||||
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.3-dev-00260" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -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
|
||||
EXPOSE 80
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
|
||||
WORKDIR /src
|
||||
|
||||
# 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
|
||||
ENV ASPNETCORE_ENVIRONMENT=Development
|
||||
ENV DOTNET_USE_POLLING_FILE_WATCHER=true
|
||||
|
@ -58,4 +58,5 @@ global using System.Net;
|
||||
global using System.Security.Claims;
|
||||
global using System.Text.Json;
|
||||
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()
|
||||
.WriteTo.Console()
|
||||
.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)
|
||||
.CreateLogger();
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API;
|
||||
public class Startup
|
||||
{
|
||||
@ -214,16 +217,20 @@ public class Startup
|
||||
|
||||
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
|
||||
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
|
||||
}).AddJwtBearer(options =>
|
||||
services.AddAuthentication("Bearer").AddJwtBearer(options =>
|
||||
{
|
||||
options.Authority = identityUrl;
|
||||
options.RequireHttpsMetadata = false;
|
||||
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">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
@ -16,16 +16,16 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="Moq" Version="4.15.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,23 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MediatR" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.15.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PackageReference Include="MediatR" Version="11.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
|
||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<DebugType>portable</DebugType>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
<AssemblyName>Catalog.API</AssemblyName>
|
||||
@ -41,37 +41,40 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.12.2" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.5.0-beta.3" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="5.1.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="5.0.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="5.0.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="5.0.3" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0-preview.1" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
|
||||
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.34.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.18.0" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.18.0" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2-beta2" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.25.0" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.9.0-beta.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="6.0.4" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="6.1.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="6.0.2" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.21.9" />
|
||||
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.50.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.51.0-pre1" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0-beta1" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0-beta1" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.24" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" />
|
||||
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0-dev-00291" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1-dev-00876" />
|
||||
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0-beta.9" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="4.1.0-dev-00166" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" />
|
||||
<PackageReference Include="System.Data.SqlClient" version="4.8.2"/>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0"/>
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.5.0-dev-00359" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" />
|
||||
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.3-dev-00260" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" />
|
||||
<PackageReference Include="System.Data.SqlClient" version="4.8.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -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
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
|
||||
WORKDIR /src
|
||||
|
||||
# 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
|
||||
ENV ASPNETCORE_ENVIRONMENT=Development
|
||||
ENV DOTNET_USE_POLLING_FILE_WATCHER=true
|
||||
|
@ -66,7 +66,7 @@ Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console()
|
||||
.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)
|
||||
.CreateLogger();
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
@ -33,14 +33,14 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,21 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="6.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.15.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
|
||||
<PackageReference Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
</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
|
||||
{
|
||||
@ -6,7 +6,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
{
|
||||
// ApiResources define the apis in your system
|
||||
public static IEnumerable<ApiResource> GetApis()
|
||||
{
|
||||
{
|
||||
return new List<ApiResource>
|
||||
{
|
||||
new ApiResource("orders", "Orders Service"),
|
||||
@ -18,6 +18,21 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
};
|
||||
}
|
||||
|
||||
// ApiScope is used to protect the API
|
||||
//The effect is the same as that of API resources in IdentityServer 3.x
|
||||
public static IEnumerable<ApiScope> GetApiScopes()
|
||||
{
|
||||
return new List<ApiScope>
|
||||
{
|
||||
new ApiScope("orders", "Orders Service"),
|
||||
new ApiScope("basket", "Basket Service"),
|
||||
new ApiScope("mobileshoppingagg", "Mobile Shopping Aggregator"),
|
||||
new ApiScope("webshoppingagg", "Web Shopping Aggregator"),
|
||||
new ApiScope("orders.signalrhub", "Ordering Signalr Hub"),
|
||||
new ApiScope("webhooks", "Webhooks registration Service"),
|
||||
};
|
||||
}
|
||||
|
||||
// Identity resources are data like user ID, name, or email address of a user
|
||||
// see: http://docs.identityserver.io/en/release/configuration/resources.html
|
||||
public static IEnumerable<IdentityResource> GetResources()
|
||||
@ -30,7 +45,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
}
|
||||
|
||||
// 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>
|
||||
{
|
||||
@ -41,10 +56,10 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
ClientName = "eShop SPA OpenId Client",
|
||||
AllowedGrantTypes = GrantTypes.Implicit,
|
||||
AllowAccessTokensViaBrowser = true,
|
||||
RedirectUris = { $"{clientsUrl["Spa"]}/" },
|
||||
RedirectUris = { $"{configuration["SpaClient"]}/" },
|
||||
RequireConsent = false,
|
||||
PostLogoutRedirectUris = { $"{clientsUrl["Spa"]}/" },
|
||||
AllowedCorsOrigins = { $"{clientsUrl["Spa"]}" },
|
||||
PostLogoutRedirectUris = { $"{configuration["SpaClient"]}/" },
|
||||
AllowedCorsOrigins = { $"{configuration["SpaClient"]}" },
|
||||
AllowedScopes =
|
||||
{
|
||||
IdentityServerConstants.StandardScopes.OpenId,
|
||||
@ -63,13 +78,13 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
AllowedGrantTypes = GrantTypes.Hybrid,
|
||||
//Used to retrieve the access token on the back channel.
|
||||
ClientSecrets =
|
||||
{
|
||||
{
|
||||
new Secret("secret".Sha256())
|
||||
},
|
||||
RedirectUris = { clientsUrl["Xamarin"] },
|
||||
RedirectUris = { configuration["XamarinCallback"] },
|
||||
RequireConsent = false,
|
||||
RequirePkce = true,
|
||||
PostLogoutRedirectUris = { $"{clientsUrl["Xamarin"]}/Account/Redirecting" },
|
||||
PostLogoutRedirectUris = { $"{configuration["XamarinCallback"]}/Account/Redirecting" },
|
||||
//AllowedCorsOrigins = { "http://eshopxamarin" },
|
||||
AllowedScopes = new List<string>
|
||||
{
|
||||
@ -91,22 +106,23 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
ClientName = "MVC Client",
|
||||
ClientSecrets = new List<Secret>
|
||||
{
|
||||
|
||||
|
||||
new Secret("secret".Sha256())
|
||||
},
|
||||
ClientUri = $"{clientsUrl["Mvc"]}", // public uri of the client
|
||||
AllowedGrantTypes = GrantTypes.Hybrid,
|
||||
ClientUri = $"{configuration["MvcClient"]}", // public uri of the client
|
||||
AllowedGrantTypes = GrantTypes.Code,
|
||||
AllowAccessTokensViaBrowser = false,
|
||||
RequireConsent = false,
|
||||
AllowOfflineAccess = true,
|
||||
AlwaysIncludeUserClaimsInIdToken = true,
|
||||
RequirePkce = false,
|
||||
RedirectUris = new List<string>
|
||||
{
|
||||
$"{clientsUrl["Mvc"]}/signin-oidc"
|
||||
$"{configuration["MvcClient"]}/signin-oidc"
|
||||
},
|
||||
PostLogoutRedirectUris = new List<string>
|
||||
{
|
||||
$"{clientsUrl["Mvc"]}/signout-callback-oidc"
|
||||
$"{configuration["MvcClient"]}/signout-callback-oidc"
|
||||
},
|
||||
AllowedScopes = new List<string>
|
||||
{
|
||||
@ -130,19 +146,19 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
{
|
||||
new Secret("secret".Sha256())
|
||||
},
|
||||
ClientUri = $"{clientsUrl["WebhooksWeb"]}", // public uri of the client
|
||||
AllowedGrantTypes = GrantTypes.Hybrid,
|
||||
ClientUri = $"{configuration["WebhooksWebClient"]}", // public uri of the client
|
||||
AllowedGrantTypes = GrantTypes.Code,
|
||||
AllowAccessTokensViaBrowser = false,
|
||||
RequireConsent = false,
|
||||
AllowOfflineAccess = true,
|
||||
AlwaysIncludeUserClaimsInIdToken = true,
|
||||
RedirectUris = new List<string>
|
||||
{
|
||||
$"{clientsUrl["WebhooksWeb"]}/signin-oidc"
|
||||
$"{configuration["WebhooksWebClient"]}/signin-oidc"
|
||||
},
|
||||
PostLogoutRedirectUris = new List<string>
|
||||
{
|
||||
$"{clientsUrl["WebhooksWeb"]}/signout-callback-oidc"
|
||||
$"{configuration["WebhooksWebClient"]}/signout-callback-oidc"
|
||||
},
|
||||
AllowedScopes = new List<string>
|
||||
{
|
||||
@ -162,18 +178,18 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
{
|
||||
new Secret("secret".Sha256())
|
||||
},
|
||||
ClientUri = $"{clientsUrl["Mvc"]}", // public uri of the client
|
||||
AllowedGrantTypes = GrantTypes.Hybrid,
|
||||
ClientUri = $"{configuration["Mvc"]}", // public uri of the client
|
||||
AllowedGrantTypes = GrantTypes.Code,
|
||||
AllowAccessTokensViaBrowser = true,
|
||||
RequireConsent = false,
|
||||
AllowOfflineAccess = true,
|
||||
RedirectUris = new List<string>
|
||||
{
|
||||
$"{clientsUrl["Mvc"]}/signin-oidc"
|
||||
$"{configuration["MvcClient"]}/signin-oidc"
|
||||
},
|
||||
PostLogoutRedirectUris = new List<string>
|
||||
{
|
||||
$"{clientsUrl["Mvc"]}/signout-callback-oidc"
|
||||
$"{configuration["MvcClient"]}/signout-callback-oidc"
|
||||
},
|
||||
AllowedScopes = new List<string>
|
||||
{
|
||||
@ -193,8 +209,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
AllowedGrantTypes = GrantTypes.Implicit,
|
||||
AllowAccessTokensViaBrowser = true,
|
||||
|
||||
RedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/oauth2-redirect.html" },
|
||||
PostLogoutRedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/" },
|
||||
RedirectUris = { $"{configuration["BasketApiClient"]}/swagger/oauth2-redirect.html" },
|
||||
PostLogoutRedirectUris = { $"{configuration["BasketApiClient"]}/swagger/" },
|
||||
|
||||
AllowedScopes =
|
||||
{
|
||||
@ -208,8 +224,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
AllowedGrantTypes = GrantTypes.Implicit,
|
||||
AllowAccessTokensViaBrowser = true,
|
||||
|
||||
RedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/oauth2-redirect.html" },
|
||||
PostLogoutRedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/" },
|
||||
RedirectUris = { $"{configuration["OrderingApiClient"]}/swagger/oauth2-redirect.html" },
|
||||
PostLogoutRedirectUris = { $"{configuration["OrderingApiClient"]}/swagger/" },
|
||||
|
||||
AllowedScopes =
|
||||
{
|
||||
@ -223,8 +239,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
AllowedGrantTypes = GrantTypes.Implicit,
|
||||
AllowAccessTokensViaBrowser = true,
|
||||
|
||||
RedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/oauth2-redirect.html" },
|
||||
PostLogoutRedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/" },
|
||||
RedirectUris = { $"{configuration["MobileShoppingAggClient"]}/swagger/oauth2-redirect.html" },
|
||||
PostLogoutRedirectUris = { $"{configuration["MobileShoppingAggClient"]}/swagger/" },
|
||||
|
||||
AllowedScopes =
|
||||
{
|
||||
@ -238,8 +254,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
AllowedGrantTypes = GrantTypes.Implicit,
|
||||
AllowAccessTokensViaBrowser = true,
|
||||
|
||||
RedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/oauth2-redirect.html" },
|
||||
PostLogoutRedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/" },
|
||||
RedirectUris = { $"{configuration["WebShoppingAggClient"]}/swagger/oauth2-redirect.html" },
|
||||
PostLogoutRedirectUris = { $"{configuration["WebShoppingAggClient"]}/swagger/" },
|
||||
|
||||
AllowedScopes =
|
||||
{
|
||||
@ -254,8 +270,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||
AllowedGrantTypes = GrantTypes.Implicit,
|
||||
AllowAccessTokensViaBrowser = true,
|
||||
|
||||
RedirectUris = { $"{clientsUrl["WebhooksApi"]}/swagger/oauth2-redirect.html" },
|
||||
PostLogoutRedirectUris = { $"{clientsUrl["WebhooksApi"]}/swagger/" },
|
||||
RedirectUris = { $"{configuration["WebhooksApiClient"]}/swagger/oauth2-redirect.html" },
|
||||
PostLogoutRedirectUris = { $"{configuration["WebhooksApiClient"]}/swagger/" },
|
||||
|
||||
AllowedScopes =
|
||||
{
|
||||
|
@ -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,18 +1,17 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
|
||||
{
|
||||
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
|
||||
{
|
||||
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data;
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
// Customize the ASP.NET Identity model and override the defaults if needed.
|
||||
// For example, you can rename the ASP.NET Identity table names and more.
|
||||
// Add your customizations after calling base.OnModelCreating(builder);
|
||||
}
|
||||
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
|
||||
{
|
||||
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
// Customize the ASP.NET Identity model and override the defaults if needed.
|
||||
// For example, you can rename the ASP.NET Identity table names and more.
|
||||
// Add your customizations after calling base.OnModelCreating(builder);
|
||||
}
|
||||
}
|
||||
|
@ -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.eShopOnContainers.Services.Identity.API.Data;
|
||||
|
||||
namespace Identity.API.Migrations
|
||||
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20210813072445_InitialMigration")]
|
||||
[Migration("20210914100206_InitialMigration")]
|
||||
partial class InitialMigration
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
@ -18,7 +18,7 @@ namespace Identity.API.Migrations
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||
.HasAnnotation("ProductVersion", "6.0.0")
|
||||
.HasAnnotation("ProductVersion", "5.0.9")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
@ -45,7 +45,7 @@ namespace Identity.API.Migrations
|
||||
.HasDatabaseName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles", (string)null);
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
@ -69,7 +69,7 @@ namespace Identity.API.Migrations
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims", (string)null);
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
@ -93,7 +93,7 @@ namespace Identity.API.Migrations
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims", (string)null);
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
@ -115,7 +115,7 @@ namespace Identity.API.Migrations
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins", (string)null);
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
@ -130,7 +130,7 @@ namespace Identity.API.Migrations
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles", (string)null);
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
@ -149,7 +149,7 @@ namespace Identity.API.Migrations
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens", (string)null);
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", b =>
|
||||
@ -261,7 +261,7 @@ namespace Identity.API.Migrations
|
||||
.HasDatabaseName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Identity.API.Migrations
|
||||
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data.Migrations
|
||||
{
|
||||
public partial class InitialMigration : Migration
|
||||
{
|
@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Microsoft.eShopOnContainers.Services.Identity.API.Data;
|
||||
|
||||
namespace Identity.API.Migrations
|
||||
namespace Microsoft.eShopOnContainers.Services.Identity.API.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
||||
@ -16,7 +16,7 @@ namespace Identity.API.Migrations
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||
.HasAnnotation("ProductVersion", "6.0.0")
|
||||
.HasAnnotation("ProductVersion", "5.0.9")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
@ -43,7 +43,7 @@ namespace Identity.API.Migrations
|
||||
.HasDatabaseName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles", (string)null);
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
@ -67,7 +67,7 @@ namespace Identity.API.Migrations
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims", (string)null);
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
@ -91,7 +91,7 @@ namespace Identity.API.Migrations
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims", (string)null);
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
@ -113,7 +113,7 @@ namespace Identity.API.Migrations
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins", (string)null);
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
@ -128,7 +128,7 @@ namespace Identity.API.Migrations
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles", (string)null);
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
@ -147,7 +147,7 @@ namespace Identity.API.Migrations
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens", (string)null);
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Identity.API.Models.ApplicationUser", b =>
|
||||
@ -259,7 +259,7 @@ namespace Identity.API.Migrations
|
||||
.HasDatabaseName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
@ -10,14 +10,14 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Devspaces
|
||||
_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);
|
||||
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);
|
||||
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
|
||||
EXPOSE 80
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
|
||||
WORKDIR /src
|
||||
|
||||
# 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
|
||||
ENV ASPNETCORE_ENVIRONMENT=Development
|
||||
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 Autofac.Extensions.DependencyInjection;
|
||||
global using Autofac;
|
||||
global using Azure.Core;
|
||||
global using Azure.Identity;
|
||||
global using HealthChecks.UI.Client;
|
||||
global using IdentityModel;
|
||||
global using IdentityServer4.EntityFramework.DbContexts;
|
||||
global using IdentityServer4.EntityFramework.Mappers;
|
||||
global using IdentityServer4.EntityFramework.Options;
|
||||
global using IdentityServer4.Models;
|
||||
global using IdentityServer4.Services;
|
||||
global using IdentityServer4.Stores;
|
||||
global using IdentityServer4.Validation;
|
||||
global using IdentityServer4;
|
||||
global using Duende.IdentityServer;
|
||||
global using Duende.IdentityServer.Configuration;
|
||||
global using Duende.IdentityServer.Events;
|
||||
global using Duende.IdentityServer.Extensions;
|
||||
global using Duende.IdentityServer.Models;
|
||||
global using Duende.IdentityServer.Services;
|
||||
global using Duende.IdentityServer.Stores;
|
||||
global using Duende.IdentityServer.Validation;
|
||||
global using Microsoft.AspNetCore.Authentication;
|
||||
global using Microsoft.AspNetCore.Authorization;
|
||||
global using Microsoft.AspNetCore.Builder;
|
||||
@ -23,20 +22,21 @@ global using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
global using Microsoft.AspNetCore.Identity;
|
||||
global using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
global using Microsoft.AspNetCore.Mvc;
|
||||
global using Microsoft.AspNetCore.Mvc.Filters;
|
||||
global using Microsoft.AspNetCore;
|
||||
global using Microsoft.EntityFrameworkCore.Design;
|
||||
global using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
global using Microsoft.EntityFrameworkCore.Metadata;
|
||||
global using Microsoft.EntityFrameworkCore.Migrations;
|
||||
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.Configuration;
|
||||
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;
|
||||
global using Microsoft.eShopOnContainers.Services.Identity.API.Services;
|
||||
global using Microsoft.eShopOnContainers.Services.Identity.API;
|
||||
global using Microsoft.Extensions.Configuration;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
@ -44,7 +44,6 @@ global using Microsoft.Extensions.Hosting;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
global using Microsoft.Extensions.Options;
|
||||
global using Polly;
|
||||
global using Serilog;
|
||||
global using StackExchange.Redis;
|
||||
global using System.Collections.Generic;
|
||||
global using System.ComponentModel.DataAnnotations;
|
||||
@ -58,6 +57,7 @@ global using System.Security.Cryptography.X509Certificates;
|
||||
global using System.Text.RegularExpressions;
|
||||
global using System.Threading.Tasks;
|
||||
global using System;
|
||||
global using Microsoft.AspNetCore.Http;
|
||||
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<UserSecretsId>aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5</UserSecretsId>
|
||||
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
|
||||
@ -9,64 +9,72 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Setup\**\*;">
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="5.0.3" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0-preview.1" />
|
||||
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="3.1.4" />
|
||||
<PackageReference Include="IdentityServer4.EntityFramework.Storage" Version="3.1.4" />
|
||||
<PackageReference Include="IdentityServer4.EntityFramework" Version="3.1.4" />
|
||||
<PackageReference Include="IdentityServer4.Storage" Version="3.1.4" />
|
||||
<PackageReference Include="IdentityServer4" Version="3.1.4" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.18.0" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.18.0" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2-beta2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.0" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="6.0.2" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="6.2.0" />
|
||||
<PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" Version="6.2.0" />
|
||||
<PackageReference Include="Duende.IdentityServer.EntityFramework" Version="6.2.0" />
|
||||
<PackageReference Include="Duende.IdentityServer.Storage" Version="6.2.0" />
|
||||
<PackageReference Include="Duende.IdentityServer" Version="6.2.0" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0-beta1" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0-beta1" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
|
||||
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.24" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
|
||||
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
|
||||
<PackageReference Include="Polly" Version="7.2.2" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" />
|
||||
<PackageReference Include="Polly" Version="7.2.3" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00289" />
|
||||
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0-dev-00291" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1-dev-00876" />
|
||||
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0-beta.9" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="5.0.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" />
|
||||
<PackageReference Include="System.Data.SqlClient" version="4.8.2" />
|
||||
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.1" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Certificate\idsrv3test.pfx" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Setup\*">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Extensions\" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.5.0-dev-00359" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896" />
|
||||
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.3-dev-00260" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" />
|
||||
<PackageReference Include="System.Data.SqlClient" version="4.8.5" />
|
||||
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.2" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.9.0-beta.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Views\Account\AccessDenied.cshtml" />
|
||||
<None Include="Views\Account\LoggedOut.cshtml" />
|
||||
<None Include="Views\Account\Login.cshtml" />
|
||||
<None Include="Views\Account\Logout.cshtml" />
|
||||
<None Include="Views\Consent\Index.cshtml" />
|
||||
<None Include="Views\Device\Success.cshtml" />
|
||||
<None Include="Views\Device\UserCodeCapture.cshtml" />
|
||||
<None Include="Views\Device\UserCodeConfirmation.cshtml" />
|
||||
<None Include="Views\Diagnostics\Index.cshtml" />
|
||||
<None Include="Views\Grants\Index.cshtml" />
|
||||
<None Include="Views\Home\Index.cshtml" />
|
||||
<None Include="Views\Shared\Error.cshtml" />
|
||||
<None Include="Views\Shared\Redirect.cshtml" />
|
||||
<None Include="Views\Shared\_Layout.cshtml" />
|
||||
<None Include="Views\Shared\_ScopeListItem.cshtml" />
|
||||
<None Include="Views\Shared\_ValidationSummary.cshtml" />
|
||||
<None Include="Views\_ViewImports.cshtml" />
|
||||
<None Include="Views\_ViewStart.cshtml" />
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties appsettings_1json__JsonSchema="" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
|
@ -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;
|
||||
string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
|
||||
var appName = "Identity.API";
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
|
||||
var configuration = GetConfiguration();
|
||||
builder.AddCustomConfiguration();
|
||||
builder.AddCustomSerilog();
|
||||
builder.AddCustomMvc();
|
||||
builder.AddCustomDatabase();
|
||||
builder.AddCustomIdentity();
|
||||
builder.AddCustomIdentityServer();
|
||||
builder.AddCustomAuthentication();
|
||||
builder.AddCustomHealthChecks();
|
||||
builder.AddCustomApplicationServices();
|
||||
|
||||
Log.Logger = CreateSerilogLogger(configuration);
|
||||
var app = builder.Build();
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
var pathBase = builder.Configuration["PATH_BASE"];
|
||||
if (!string.IsNullOrEmpty(pathBase))
|
||||
{
|
||||
app.UsePathBase(pathBase);
|
||||
}
|
||||
app.UseStaticFiles();
|
||||
|
||||
// This cookie policy fixes login issues with Chrome 80+ using HHTP
|
||||
app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode.Lax });
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseIdentityServer();
|
||||
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapDefaultControllerRoute();
|
||||
|
||||
app.MapHealthChecks("/hc", new HealthCheckOptions()
|
||||
{
|
||||
Predicate = _ => true,
|
||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||
});
|
||||
app.MapHealthChecks("/liveness", new HealthCheckOptions
|
||||
{
|
||||
Predicate = r => r.Name.Contains("self")
|
||||
});
|
||||
try
|
||||
{
|
||||
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||
var host = BuildWebHost(configuration, args);
|
||||
app.Logger.LogInformation("Seeding database ({ApplicationName})...", appName);
|
||||
|
||||
Log.Information("Applying migrations ({ApplicationContext})...", AppName);
|
||||
host.MigrateDbContext<PersistedGrantDbContext>((_, __) => { })
|
||||
.MigrateDbContext<ApplicationDbContext>((context, services) =>
|
||||
{
|
||||
var env = services.GetService<IWebHostEnvironment>();
|
||||
var logger = services.GetService<ILogger<ApplicationDbContextSeed>>();
|
||||
var settings = services.GetService<IOptions<AppSettings>>();
|
||||
// Apply database migration automatically. Note that this approach is not
|
||||
// recommended for production scenarios. Consider generating SQL scripts from
|
||||
// migrations instead.
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
await SeedData.EnsureSeedData(scope, app.Configuration, app.Logger);
|
||||
}
|
||||
|
||||
new ApplicationDbContextSeed()
|
||||
.SeedAsync(context, env, logger, settings)
|
||||
.Wait();
|
||||
})
|
||||
.MigrateDbContext<ConfigurationDbContext>((context, services) =>
|
||||
{
|
||||
new ConfigurationDbContextSeed()
|
||||
.SeedAsync(context, configuration)
|
||||
.Wait();
|
||||
});
|
||||
|
||||
Log.Information("Starting web host ({ApplicationContext})...", AppName);
|
||||
host.Run();
|
||||
app.Logger.LogInformation("Starting web host ({ApplicationName})...", appName);
|
||||
app.Run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
|
||||
app.Logger.LogCritical(ex, "Host terminated unexpectedly ({ApplicationName})...", appName);
|
||||
return 1;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
||||
IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.CaptureStartupErrors(false)
|
||||
.ConfigureAppConfiguration(x => x.AddConfiguration(configuration))
|
||||
.UseStartup<Startup>()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseSerilog()
|
||||
.Build();
|
||||
|
||||
Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||
{
|
||||
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
|
||||
var logstashUrl = configuration["Serilog:LogstashgUrl"];
|
||||
return new LoggerConfiguration()
|
||||
.MinimumLevel.Verbose()
|
||||
.Enrich.WithProperty("ApplicationContext", AppName)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console()
|
||||
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
|
||||
.WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://localhost:8080" : logstashUrl)
|
||||
.ReadFrom.Configuration(configuration)
|
||||
.CreateLogger();
|
||||
Serilog.Log.CloseAndFlush();
|
||||
}
|
||||
|
||||
IConfiguration GetConfiguration()
|
||||
|
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