Add a website for functional E2E tests and make an OIDC id_token flow succeed
Add a couple of functional tests for doing an id_token flow and an authorization_code flow
This commit is contained in:
parent
f3e2511672
commit
b3c8ff4ae5
46
Identity.sln
46
Identity.sln
|
|
@ -1,6 +1,6 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26510.0
|
||||
VisualStudioVersion = 15.0.26811.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0F647068-6602-4E24-B1DC-8ED91481A50A}"
|
||||
EndProject
|
||||
|
|
@ -62,6 +62,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identi
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IdentityOIDCWebApplicationSample", "samples\IdentityOIDCWebApplicationSample\IdentityOIDCWebApplicationSample.csproj", "{D7CE9BDF-84E5-405D-8A4E-12E41DAC6935}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebSites", "WebSites", "{1F83D453-E094-4D28-BCFA-9E537ABB5AD6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.OpenIdConnect.WebSite", "test\WebSites\Identity.OpenIdConnect.WebSite\Identity.OpenIdConnect.WebSite.csproj", "{D6FF6433-336F-42E0-8F3A-60F3787A0261}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspnetCore.Identity.Service.FunctionalTests", "test\Microsoft.AspnetCore.Identity.Service.FunctionalTests\Microsoft.AspnetCore.Identity.Service.FunctionalTests.csproj", "{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -492,6 +498,38 @@ Global
|
|||
{D7CE9BDF-84E5-405D-8A4E-12E41DAC6935}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D7CE9BDF-84E5-405D-8A4E-12E41DAC6935}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D7CE9BDF-84E5-405D-8A4E-12E41DAC6935}.Release|x86.Build.0 = Release|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -524,5 +562,11 @@ Global
|
|||
{FADA11FC-DC06-4832-A569-7B2374A6CD42} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||
{174180AE-00AD-4C2D-9F96-2EE2C5E60457} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||
{D7CE9BDF-84E5-405D-8A4E-12E41DAC6935} = {58D94A0E-C2B7-43A7-8826-99ECBB1E0A50}
|
||||
{1F83D453-E094-4D28-BCFA-9E537ABB5AD6} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
|
||||
{D6FF6433-336F-42E0-8F3A-60F3787A0261} = {1F83D453-E094-4D28-BCFA-9E537ABB5AD6}
|
||||
{6E3E1BE7-CEAF-4565-AA0A-F5BE3FA7F39C} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {B3F2A592-CCE0-40C2-8CA4-7B1293DED874}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -1,10 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Rewrite;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
|
@ -14,19 +8,6 @@ namespace Microsoft.AspNetCore.Authentication.Extensions
|
|||
{
|
||||
public static class AuthenticationServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddWebApplicationAuthentication(this IServiceCollection services)
|
||||
{
|
||||
services.AddAuthentication(sharedOptions =>
|
||||
{
|
||||
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddOpenIdConnect()
|
||||
.AddCookie();
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseHttps(this IApplicationBuilder builder)
|
||||
{
|
||||
var configuration = builder.ApplicationServices.GetRequiredService<IConfiguration>();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
using IdentityOIDCWebApplicationSample.Identity.Data;
|
||||
using IdentityOIDCWebApplicationSample.Identity.Models;
|
||||
using IdentityOIDCWebApplicationSample.Identity.Services;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.Extensions;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Diagnostics.Identity.Service;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.Service;
|
||||
using Microsoft.AspNetCore.Identity.Service.AzureKeyVault;
|
||||
using Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Identity.Service.Extensions;
|
||||
using Microsoft.AspNetCore.Identity.Service.IntegratedWebClient;
|
||||
|
|
@ -41,9 +42,16 @@ namespace IdentityOIDCWebApplicationSample
|
|||
.AddEntityFrameworkStores<IdentityServiceDbContext>()
|
||||
.AddClientInfoBinding();
|
||||
|
||||
services
|
||||
.AddWebApplicationAuthentication()
|
||||
.WithIntegratedWebClient();
|
||||
services.AddAuthentication(sharedOptions =>
|
||||
{
|
||||
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddOpenIdConnect()
|
||||
.AddCookie();
|
||||
|
||||
services.WithIntegratedWebClient();
|
||||
|
||||
services.AddTransient<IEmailSender, AuthMessageSender>();
|
||||
services.AddTransient<ISmsSender, AuthMessageSender>();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using System.Linq;
|
|||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity.Service;
|
||||
|
|
@ -84,7 +83,7 @@ namespace Microsoft.AspNetCore.Diagnostics.Identity.Service
|
|||
using (var rsa = RSA.Create(2048))
|
||||
{
|
||||
var signingRequest = new CertificateRequest(
|
||||
new X500DistinguishedName("CN=IdentityService.Development"), rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
new X500DistinguishedName("CN=Identity.Development"), rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
var enhacedKeyUsage = new OidCollection();
|
||||
enhacedKeyUsage.Add(new Oid("1.3.6.1.5.5.7.3.1", "Server Authentication"));
|
||||
signingRequest.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(enhacedKeyUsage, critical: true));
|
||||
|
|
@ -120,7 +119,7 @@ namespace Microsoft.AspNetCore.Diagnostics.Identity.Service
|
|||
store.Open(OpenFlags.ReadOnly);
|
||||
var developmentCertificate = store.Certificates.Find(
|
||||
X509FindType.FindBySubjectName,
|
||||
"IdentityService.Development",
|
||||
"Identity.Development",
|
||||
validOnly: false);
|
||||
|
||||
store.Close();
|
||||
|
|
@ -134,7 +133,7 @@ namespace Microsoft.AspNetCore.Diagnostics.Identity.Service
|
|||
return certificates.Any(
|
||||
c => _timeStampManager.IsValidPeriod(c.NotBefore, c.Expires) &&
|
||||
c.Credentials.Key is X509SecurityKey key &&
|
||||
key.Certificate.Subject.Equals("CN=IdentityService.Development"));
|
||||
key.Certificate.Subject.Equals("CN=Identity.Development"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Identity.Service
|
|||
var finalList = new List<SigningCredentialsDescriptor>();
|
||||
foreach (var credential in credentialsFromSources.SelectMany(c => c))
|
||||
{
|
||||
if (!_environment.IsDevelopment() && credential.Id.StartsWith("IdentityService.Development"))
|
||||
if (!_environment.IsDevelopment() && credential.Id.StartsWith("Identity.Development"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ namespace Microsoft.AspNetCore.Identity.Service.Core
|
|||
{
|
||||
public class DefaultSigningCredentialsSource : ISigningCredentialsSource
|
||||
{
|
||||
private readonly IOptionsSnapshot<IdentityServiceOptions> _options;
|
||||
private readonly IOptions<IdentityServiceOptions> _options;
|
||||
private readonly ITimeStampManager _timeStampManager;
|
||||
|
||||
public DefaultSigningCredentialsSource(
|
||||
IOptionsSnapshot<IdentityServiceOptions> options,
|
||||
IOptions<IdentityServiceOptions> options,
|
||||
ITimeStampManager timeStampManager)
|
||||
{
|
||||
_options = options;
|
||||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Identity.Service.Core
|
|||
|
||||
public Task<IEnumerable<SigningCredentialsDescriptor>> GetCredentials()
|
||||
{
|
||||
var descriptors = GetDescriptors(_options.Get(Options.DefaultName));
|
||||
var descriptors = GetDescriptors(_options.Value);
|
||||
return Task.FromResult(descriptors);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Identity.Service
|
|||
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
|
||||
{
|
||||
store.Open(OpenFlags.ReadOnly);
|
||||
var cert = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, "CN=IdentityService.Development", validOnly: false);
|
||||
var cert = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, "CN=Identity.Development", validOnly: false);
|
||||
var valid = cert.OfType<X509Certificate2>().FirstOrDefault(c => _timeStampManager.IsValidPeriod(c.NotBefore, c.NotAfter));
|
||||
store.Close();
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Identity.Service.IntegratedWebClient
|
|||
configurationContext.AuthorizationEndpoint = MakeAbsolute(authorizationUri);
|
||||
}
|
||||
|
||||
if (!Uri.TryCreate(configurationContext.AuthorizationEndpoint, UriKind.RelativeOrAbsolute, out var tokenUri))
|
||||
if (!Uri.TryCreate(configurationContext.TokenEndpoint, UriKind.RelativeOrAbsolute, out var tokenUri))
|
||||
{
|
||||
configurationContext.TokenEndpoint = $"{baseUrl}/tfp/IdentityService/signinsignup/oauth2/v2.0/token";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Identity.Service.IntegratedWebClient
|
|||
Action<IntegratedWebClientOptions> action)
|
||||
{
|
||||
services.Configure(action);
|
||||
services.TryAddEnumerable(ServiceDescriptor.Scoped<IConfigureOptions<OpenIdConnectOptions>, IntegratedWebClientOpenIdConnectOptionsSetup>());
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<OpenIdConnectOptions>, IntegratedWebClientOpenIdConnectOptionsSetup>());
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<MvcOptions>, IntegratedWebclientMvcOptionsSetup>());
|
||||
|
||||
return services;
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
services.AddSingleton<DeveloperCertificateSigningCredentialsSource>();
|
||||
|
||||
services.AddSingleton<IPasswordHasher<TApplication>, PasswordHasher<TApplication>>();
|
||||
services.AddScoped<ISigningCredentialsPolicyProvider, DefaultSigningCredentialsPolicyProvider>();
|
||||
services.AddScoped<ISigningCredentialsSource, DefaultSigningCredentialsSource>();
|
||||
services.AddSingleton<ISigningCredentialsPolicyProvider, DefaultSigningCredentialsPolicyProvider>();
|
||||
services.AddSingleton<ISigningCredentialsSource, DefaultSigningCredentialsSource>();
|
||||
services.AddSingleton<IApplicationValidator<TApplication>, ApplicationValidator<TApplication>>();
|
||||
services.AddSingleton<ApplicationErrorDescriber>();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Testing
|
||||
{
|
||||
[Flags]
|
||||
public enum CookieComparison
|
||||
{
|
||||
NameStartsWith = 1,
|
||||
NameEquals = 2,
|
||||
DomainEquals = 4,
|
||||
PathEquals = 8,
|
||||
ExpiresEquals = 16,
|
||||
MaxAgeEquals = 32,
|
||||
HttpOnly = 64,
|
||||
SameSite = 128,
|
||||
Secure = 256,
|
||||
ValueStartsWith = 512,
|
||||
Default = NameStartsWith | DomainEquals | PathEquals | ExpiresEquals | MaxAgeEquals | HttpOnly | SameSite | Secure | ValueStartsWith,
|
||||
ValueEquals = 1024,
|
||||
StrictNoTime = NameEquals | DomainEquals | PathEquals | HttpOnly | SameSite | Secure | ValueEquals,
|
||||
Strict = NameEquals | DomainEquals | PathEquals | ExpiresEquals | MaxAgeEquals | HttpOnly | SameSite | Secure | ValueEquals,
|
||||
Delete = NameStartsWith | DomainEquals | PathEquals | ExpiresEquals | MaxAgeEquals,
|
||||
DeleteStrict = NameEquals | DomainEquals | PathEquals | ExpiresEquals | MaxAgeEquals,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Testing
|
||||
{
|
||||
public static class ResponseAssert
|
||||
{
|
||||
public static Uri IsRedirect(HttpResponseMessage responseMessage)
|
||||
{
|
||||
Assert.Equal(HttpStatusCode.Redirect, responseMessage.StatusCode);
|
||||
return responseMessage.Headers.Location;
|
||||
}
|
||||
|
||||
public static void IsOK(HttpResponseMessage responseMessage)
|
||||
{
|
||||
Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);
|
||||
}
|
||||
|
||||
public static SetCookieHeaderValue HasCookie(string name, HttpResponseMessage response, CookieComparison comparison)
|
||||
{
|
||||
var setCookieHeaderValue = new SetCookieHeaderValue(new StringSegment(name));
|
||||
var foundCookie = HasCookieCore(setCookieHeaderValue, response, new SetCookieComparer(comparison));
|
||||
|
||||
if (foundCookie != null)
|
||||
{
|
||||
return foundCookie;
|
||||
}
|
||||
|
||||
var suffix = comparison.HasFlag(CookieComparison.NameStartsWith) ? "starting with" : "";
|
||||
Assert.True(false, $"Couldn't find a cookie with a name {suffix} '{name}'");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static SetCookieHeaderValue HasCookie(
|
||||
SetCookieHeaderValue expectedSetCookieHeader,
|
||||
HttpResponseMessage response)
|
||||
{
|
||||
return HasCookie(expectedSetCookieHeader, response, SetCookieComparer.Default);
|
||||
}
|
||||
|
||||
public static SetCookieHeaderValue HasCookie(
|
||||
SetCookieHeaderValue expectedSetCookieHeader,
|
||||
HttpResponseMessage response,
|
||||
params CookieComparison[] criteria)
|
||||
{
|
||||
return HasCookie(expectedSetCookieHeader, response, new SetCookieComparer(criteria.Aggregate((l, r) => l | r)));
|
||||
}
|
||||
|
||||
public static TCaptured LocationHasQueryParameters<TCaptured>(HttpResponseMessage response, params ValueSpecification[] values)
|
||||
where TCaptured : new()
|
||||
{
|
||||
var queryParameters = LocationHasQueryParameters(response, values);
|
||||
|
||||
var result = new TCaptured();
|
||||
|
||||
return SimpleBind(result, queryParameters.ToDictionary(kvp => kvp.Key, kvp => (string[])kvp.Value, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static TCaptured SimpleBind<TCaptured>(TCaptured result, IDictionary<string, string[]> values)
|
||||
{
|
||||
foreach (var property in result.GetType().GetProperties())
|
||||
{
|
||||
if (values.TryGetValue(property.Name, out var value))
|
||||
{
|
||||
if (property.PropertyType == typeof(string))
|
||||
{
|
||||
property.SetValue(result, value.FirstOrDefault());
|
||||
}
|
||||
else if (property.PropertyType == typeof(string[]))
|
||||
{
|
||||
property.SetValue(result, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static IDictionary<string, StringValues> LocationHasQueryParameters(HttpResponseMessage response, params ValueSpecification[] values)
|
||||
{
|
||||
var location = IsRedirect(response);
|
||||
|
||||
var queryParameters = QueryHelpers.ParseNullableQuery(location.Query);
|
||||
foreach (var parameter in values)
|
||||
{
|
||||
if (!queryParameters.TryGetValue(parameter.Name, out var parameterValues))
|
||||
{
|
||||
Assert.True(false, $"Missing parameter '{parameter}'");
|
||||
}
|
||||
|
||||
if (!parameter.MatchValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var expectedValue in parameter.Values)
|
||||
{
|
||||
Assert.Contains(expectedValue, parameterValues, parameter.ValueComparer);
|
||||
}
|
||||
}
|
||||
|
||||
return queryParameters;
|
||||
}
|
||||
|
||||
public class ValueSpecification
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public bool MatchValue { get; set; } = true;
|
||||
public string[] Values { get; set; }
|
||||
public IEqualityComparer<string> ValueComparer { get; set; }
|
||||
|
||||
public static implicit operator ValueSpecification(string name)
|
||||
{
|
||||
return new ValueSpecification
|
||||
{
|
||||
Name = name,
|
||||
MatchValue = false
|
||||
};
|
||||
}
|
||||
|
||||
public static implicit operator ValueSpecification((string name, string value) tuple) => new ValueSpecification()
|
||||
{
|
||||
Name = tuple.name,
|
||||
Values = new string[] { tuple.value },
|
||||
ValueComparer = StringComparer.Ordinal
|
||||
};
|
||||
|
||||
public static implicit operator ValueSpecification((string name, string[] values) tuple) => new ValueSpecification()
|
||||
{
|
||||
Name = tuple.name,
|
||||
Values = tuple.values,
|
||||
ValueComparer = StringComparer.Ordinal
|
||||
};
|
||||
}
|
||||
|
||||
public static void IsHtmlDocument(HttpResponseMessage response)
|
||||
{
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
Assert.Equal("text/html", response.Content.Headers.ContentType.MediaType);
|
||||
}
|
||||
|
||||
public static SetCookieHeaderValue HasCookie(
|
||||
SetCookieHeaderValue expectedCookieHeader,
|
||||
HttpResponseMessage response,
|
||||
IEqualityComparer<SetCookieHeaderValue> equalityComparer)
|
||||
{
|
||||
var foundValue = HasCookieCore(expectedCookieHeader, response, equalityComparer);
|
||||
Assert.True(null != foundValue, $"Couldn't find a matching cookie.");
|
||||
return foundValue;
|
||||
}
|
||||
|
||||
private static SetCookieHeaderValue HasCookieCore(
|
||||
SetCookieHeaderValue expectedCookieHeader,
|
||||
HttpResponseMessage response,
|
||||
IEqualityComparer<SetCookieHeaderValue> equalityComparer)
|
||||
{
|
||||
var values = SetCookieHeaderValue.ParseList(response.Headers.GetValues(HeaderNames.SetCookie).ToList());
|
||||
foreach (var setCookieValue in values)
|
||||
{
|
||||
if (equalityComparer.Equals(expectedCookieHeader, setCookieValue))
|
||||
{
|
||||
return setCookieValue;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class SetCookieComparer : IEqualityComparer<SetCookieHeaderValue>
|
||||
{
|
||||
public static SetCookieComparer Default = new SetCookieComparer(CookieComparison.Default);
|
||||
private readonly CookieComparison _comparisonCriteria;
|
||||
private readonly TimeSpan _skewAllowance;
|
||||
|
||||
public SetCookieComparer(CookieComparison comparisonCriteria, TimeSpan skewAllowance)
|
||||
{
|
||||
_comparisonCriteria = comparisonCriteria;
|
||||
_skewAllowance = skewAllowance;
|
||||
}
|
||||
|
||||
public SetCookieComparer(CookieComparison comparisonCriteria)
|
||||
: this(comparisonCriteria, TimeSpan.FromMinutes(1))
|
||||
{
|
||||
}
|
||||
|
||||
public bool Equals(SetCookieHeaderValue expected, SetCookieHeaderValue candidate)
|
||||
{
|
||||
var matchesAllCriteria = true;
|
||||
if (_comparisonCriteria.HasFlag(CookieComparison.NameStartsWith))
|
||||
{
|
||||
matchesAllCriteria = matchesAllCriteria && candidate.Name.StartsWith(expected.Name.ToString(), StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
if (_comparisonCriteria.HasFlag(CookieComparison.NameEquals))
|
||||
{
|
||||
matchesAllCriteria = matchesAllCriteria && candidate.Name.Equals(expected.Name, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
if (_comparisonCriteria.HasFlag(CookieComparison.PathEquals))
|
||||
{
|
||||
matchesAllCriteria = matchesAllCriteria && candidate.Path.Equals(expected.Path, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
if (_comparisonCriteria.HasFlag(CookieComparison.DomainEquals))
|
||||
{
|
||||
matchesAllCriteria = matchesAllCriteria && candidate.Domain.Equals(expected.Domain, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
if (_comparisonCriteria.HasFlag(CookieComparison.ExpiresEquals))
|
||||
{
|
||||
matchesAllCriteria = matchesAllCriteria &&
|
||||
((expected.Expires.HasValue &&
|
||||
candidate.Expires.HasValue &&
|
||||
expected.Expires - _skewAllowance <= candidate.Expires &&
|
||||
candidate.Expires <= expected.Expires + _skewAllowance) ||
|
||||
expected.Expires == candidate.Expires);
|
||||
}
|
||||
|
||||
if (_comparisonCriteria.HasFlag(CookieComparison.MaxAgeEquals))
|
||||
{
|
||||
matchesAllCriteria = matchesAllCriteria &&
|
||||
((expected.MaxAge.HasValue &&
|
||||
candidate.MaxAge.HasValue &&
|
||||
expected.MaxAge - _skewAllowance <= candidate.MaxAge &&
|
||||
candidate.MaxAge <= expected.MaxAge + _skewAllowance) ||
|
||||
expected.MaxAge == candidate.MaxAge);
|
||||
}
|
||||
|
||||
if (_comparisonCriteria.HasFlag(CookieComparison.HttpOnly))
|
||||
{
|
||||
matchesAllCriteria = matchesAllCriteria && expected.HttpOnly == candidate.HttpOnly;
|
||||
}
|
||||
|
||||
if (_comparisonCriteria.HasFlag(CookieComparison.SameSite))
|
||||
{
|
||||
matchesAllCriteria = matchesAllCriteria && expected.SameSite == candidate.SameSite;
|
||||
}
|
||||
|
||||
if (_comparisonCriteria.HasFlag(CookieComparison.Secure))
|
||||
{
|
||||
matchesAllCriteria = matchesAllCriteria && expected.Secure == candidate.Secure;
|
||||
}
|
||||
|
||||
if (_comparisonCriteria.HasFlag(CookieComparison.ValueEquals))
|
||||
{
|
||||
matchesAllCriteria = matchesAllCriteria && expected.Value.Equals(candidate.Value, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
if (_comparisonCriteria.HasFlag(CookieComparison.ValueStartsWith))
|
||||
{
|
||||
matchesAllCriteria = matchesAllCriteria && candidate.Value.StartsWith(expected.Value.ToString(), StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
return matchesAllCriteria;
|
||||
}
|
||||
|
||||
public int GetHashCode(SetCookieHeaderValue obj)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Models;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspnetCore.Identity.Service.FunctionalTests
|
||||
{
|
||||
public class AutoSignInFilter : IAsyncActionFilter
|
||||
{
|
||||
private readonly string _loginPath;
|
||||
|
||||
public AutoSignInFilter(string loginPath = "/tfp/IdentityService/Account/Login")
|
||||
{
|
||||
_loginPath = loginPath;
|
||||
}
|
||||
|
||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||
{
|
||||
var request = context.HttpContext.Request;
|
||||
var services = context.HttpContext.RequestServices;
|
||||
|
||||
if (request.Path.StartsWithSegments(
|
||||
_loginPath,
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var referenceData = services.GetRequiredService<ReferenceData>();
|
||||
var signInManager = services.GetRequiredService<SignInManager<ApplicationUser>>();
|
||||
var (user, password) = request.Headers.TryGetValue("X-Identity-Test-User-Hint", out var userName) ?
|
||||
referenceData.GetUser(userName) :
|
||||
referenceData.GetDefaultUser();
|
||||
|
||||
var result = await signInManager.PasswordSignInAsync(user.UserName, password, false, false);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (context.ActionArguments.TryGetValue("returnUrl", out var redirect))
|
||||
{
|
||||
context.Result = new RedirectResult((string)redirect);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspnetCore.Identity.Service.FunctionalTests
|
||||
{
|
||||
public class CookieContainerHandler : DelegatingHandler
|
||||
{
|
||||
public CookieContainerHandler(HttpMessageHandler innerHandler)
|
||||
: base(innerHandler)
|
||||
{
|
||||
}
|
||||
|
||||
public CookieContainer Container { get; } = new CookieContainer();
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
var cookieHeader = Container.GetCookieHeader(request.RequestUri);
|
||||
request.Headers.Add("Cookie", cookieHeader);
|
||||
|
||||
var response = await base.SendAsync(request, cancellationToken);
|
||||
|
||||
if (response.Headers.TryGetValues("Set-Cookie", out var setCookieHeaders))
|
||||
{
|
||||
foreach (var header in setCookieHeaders)
|
||||
{
|
||||
Container.SetCookies(response.RequestMessage.RequestUri, header);
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using Identity.OpenIdConnect.WebSite;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Data;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Identity.Service.IntegratedWebClient;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace Microsoft.AspnetCore.Identity.Service.FunctionalTests
|
||||
{
|
||||
public class CredentialsServerBuilder
|
||||
{
|
||||
private readonly DelegatingHandler _loopBackHandler = new LoopBackHandler();
|
||||
|
||||
public CredentialsServerBuilder()
|
||||
{
|
||||
Server = new MvcWebApplicationBuilder<Startup>()
|
||||
.UseSolutionRelativeContentRoot(@".\test\WebSites\Identity.OpenIdConnect.WebSite")
|
||||
.UseApplicationAssemblies();
|
||||
}
|
||||
|
||||
public CredentialsServerBuilder ConfigureReferenceData(Action<ReferenceData> action)
|
||||
{
|
||||
var referenceData = new ReferenceData();
|
||||
action(referenceData);
|
||||
Server.ConfigureBeforeStartup(s => s.TryAddSingleton(referenceData));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CredentialsServerBuilder ConfigureInMemoryEntityFrameworkStorage(string dbName = "test")
|
||||
{
|
||||
Server.ConfigureBeforeStartup(services =>
|
||||
{
|
||||
services.TryAddEnumerable(ServiceDescriptor.Transient<IStartupFilter, EntityFrameworkSeedReferenceData>());
|
||||
services.AddDbContext<IdentityServiceDbContext>(options =>
|
||||
options.UseInMemoryDatabase("test", memoryOptions => { }));
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CredentialsServerBuilder ConfigureMvcAutomaticSignIn()
|
||||
{
|
||||
Server.ConfigureBeforeStartup(s => s.Configure<MvcOptions>(o => o.Filters.Add(new AutoSignInFilter())));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CredentialsServerBuilder ConfigureOpenIdConnectClient(Action<OpenIdConnectOptions> action)
|
||||
{
|
||||
Server.ConfigureAfterStartup(services =>
|
||||
{
|
||||
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
|
||||
{
|
||||
options.BackchannelHttpHandler = _loopBackHandler;
|
||||
options.CorrelationCookie.Path = "/";
|
||||
options.NonceCookie.Path = "/";
|
||||
});
|
||||
|
||||
services.Configure(OpenIdConnectDefaults.AuthenticationScheme, action);
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CredentialsServerBuilder ConfigureIntegratedClient(string clientId)
|
||||
{
|
||||
Server.ConfigureAfterStartup(services =>
|
||||
{
|
||||
services.Configure<IntegratedWebClientOptions>(options => options.ClientId = clientId);
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MvcWebApplicationBuilder<Startup> Server { get; }
|
||||
|
||||
public HttpClient Build()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
|
||||
|
||||
var host = Server.Build();
|
||||
host.BaseAddress = new Uri("https://localhost");
|
||||
|
||||
var clientHandler = host.CreateHandler();
|
||||
_loopBackHandler.InnerHandler = clientHandler;
|
||||
|
||||
var cookieHandler = new CookieContainerHandler(clientHandler);
|
||||
|
||||
var client = new HttpClient(cookieHandler);
|
||||
client.BaseAddress = new Uri("https://localhost");
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Data;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Models;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Microsoft.AspnetCore.Identity.Service.FunctionalTests
|
||||
{
|
||||
public class EntityFrameworkSeedReferenceData : IStartupFilter
|
||||
{
|
||||
public EntityFrameworkSeedReferenceData(
|
||||
IdentityServiceDbContext dbContext,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
ReferenceData seedData)
|
||||
{
|
||||
SeedContext(dbContext, userManager, seedData);
|
||||
}
|
||||
|
||||
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
|
||||
{
|
||||
return next;
|
||||
}
|
||||
|
||||
private void SeedContext(IdentityServiceDbContext dbContext,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
ReferenceData seedData)
|
||||
{
|
||||
foreach (var userAndPassword in seedData.UsersAndPasswords)
|
||||
{
|
||||
userManager
|
||||
.CreateAsync(userAndPassword.user, userAndPassword.password)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
dbContext.Applications.AddRange(seedData.ClientApplications);
|
||||
dbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using System.Net.Http;
|
||||
|
||||
namespace Microsoft.AspnetCore.Identity.Service.FunctionalTests
|
||||
{
|
||||
/// <summary>
|
||||
/// A handler used to create a loop back into TestServer from the open ID Connect handler.
|
||||
/// </summary>
|
||||
public class LoopBackHandler : DelegatingHandler
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Models;
|
||||
using Microsoft.AspNetCore.Identity.Service;
|
||||
|
||||
namespace Microsoft.AspnetCore.Identity.Service.FunctionalTests
|
||||
{
|
||||
public class ReferenceData
|
||||
{
|
||||
public IList<IdentityServiceApplication> ClientApplications { get; set; } =
|
||||
new List<IdentityServiceApplication>();
|
||||
|
||||
public IList<(ApplicationUser user, string password)> UsersAndPasswords { get; set; } =
|
||||
new List<(ApplicationUser, string)>();
|
||||
|
||||
public string DefaultUserName { get; private set; }
|
||||
|
||||
public ReferenceData SetDefaultUserName(string name)
|
||||
{
|
||||
DefaultUserName = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReferenceData CreateUser(string name, string password)
|
||||
{
|
||||
var user = new ApplicationUser()
|
||||
{
|
||||
UserName = name,
|
||||
};
|
||||
|
||||
UsersAndPasswords.Add((user, password));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public (ApplicationUser user, string password) GetUser(string name) =>
|
||||
UsersAndPasswords.Single(u => u.user.UserName == name);
|
||||
|
||||
public (ApplicationUser user, string password) GetDefaultUser() =>
|
||||
DefaultUserName != null ? GetUser(DefaultUserName) : UsersAndPasswords.First();
|
||||
|
||||
public ReferenceData CreateIntegratedWebClientApplication(string clientId)
|
||||
{
|
||||
return CreateApplication(
|
||||
"IntegratedWebClient",
|
||||
clientId,
|
||||
"openid",
|
||||
"urn:self:aspnet:identity:integrated",
|
||||
"urn:self:aspnet:identity:integrated");
|
||||
}
|
||||
|
||||
public ReferenceData CreateResourceApplication(string clientId, string name, params string[] scopes)
|
||||
{
|
||||
return CreateApplication(
|
||||
name,
|
||||
clientId,
|
||||
scopes,
|
||||
Array.Empty<string>(),
|
||||
Array.Empty<string>());
|
||||
}
|
||||
|
||||
public ReferenceData CreateApplication(
|
||||
string name,
|
||||
string clientId,
|
||||
string scopes,
|
||||
string redirectUri,
|
||||
string logoutRedirectUri)
|
||||
{
|
||||
var app = CreateApplicationCore(name, clientId, scopes, redirectUri, logoutRedirectUri);
|
||||
ClientApplications.Add(app);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private static IdentityServiceApplication CreateApplicationCore(
|
||||
string name,
|
||||
string clientId,
|
||||
string scopes,
|
||||
string redirectUri,
|
||||
string logoutRedirectUris) =>
|
||||
CreateApplicationCore(
|
||||
name,
|
||||
clientId,
|
||||
scopes.Split(' '),
|
||||
new[] { redirectUri },
|
||||
new[] { logoutRedirectUris });
|
||||
|
||||
public ReferenceData CreateApplication(string name, string clientId, IEnumerable<string> scopes, IEnumerable<string> redirectUris, IEnumerable<string> logoutRedirectUris)
|
||||
{
|
||||
var app = CreateApplicationCore(name, clientId, scopes, redirectUris, logoutRedirectUris);
|
||||
ClientApplications.Add(app);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private static IdentityServiceApplication CreateApplicationCore(string name, string clientId, IEnumerable<string> scopes, IEnumerable<string> redirectUris, IEnumerable<string> logoutRedirectUris)
|
||||
{
|
||||
var applicationId = Guid.NewGuid().ToString();
|
||||
return new IdentityServiceApplication()
|
||||
{
|
||||
Id = applicationId,
|
||||
ClientId = clientId,
|
||||
Name = name,
|
||||
RedirectUris = redirectUris
|
||||
.Select(ru =>
|
||||
new IdentityServiceRedirectUri<string>
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
ApplicationId = applicationId,
|
||||
IsLogout = false,
|
||||
Value = ru
|
||||
}).Concat(logoutRedirectUris.Select(lu =>
|
||||
new IdentityServiceRedirectUri<string>
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
ApplicationId = applicationId,
|
||||
IsLogout = false,
|
||||
Value = lu
|
||||
})).ToList(),
|
||||
Scopes = scopes.Select(s =>
|
||||
new IdentityServiceScope<string>
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
ApplicationId = applicationId,
|
||||
Value = s
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\build\common.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netcoreapp2.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WebSites\Identity.OpenIdConnect.WebSite\Identity.OpenIdConnect.WebSite.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(AspNetCoreVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="$(AspNetCoreVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(AspNetCoreVersion)" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="$(AspNetCoreVersion)" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
|
||||
<PackageReference Include="xunit" Version="$(XunitVersion)" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Xunit;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Microsoft.AspnetCore.Identity.Service.FunctionalTests
|
||||
{
|
||||
public class TraditionalWebApplicationTests
|
||||
{
|
||||
[ConditionalFact]
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.CLR, SkipReason = "https://github.com/aspnet/Identity/issues/1346")]
|
||||
public async Task CanPerform_AuthorizationCode_Flow()
|
||||
{
|
||||
// Arrange
|
||||
var clientId = Guid.NewGuid().ToString();
|
||||
var resourceId = Guid.NewGuid().ToString();
|
||||
|
||||
var appBuilder = new CredentialsServerBuilder()
|
||||
.ConfigureReferenceData(data => data
|
||||
.CreateIntegratedWebClientApplication(clientId)
|
||||
.CreateResourceApplication(resourceId, "ResourceApplication", "read")
|
||||
.CreateUser("testUser", "Pa$$w0rd"))
|
||||
.ConfigureInMemoryEntityFrameworkStorage()
|
||||
.ConfigureMvcAutomaticSignIn()
|
||||
.ConfigureOpenIdConnectClient(options =>
|
||||
{
|
||||
options.ClientId = clientId;
|
||||
options.ResponseType = OpenIdConnectResponseType.Code;
|
||||
options.ResponseMode = OpenIdConnectResponseMode.Query;
|
||||
options.Scope.Add("https://localhost/DFC7191F-FF74-42B9-A292-08FEA80F5B20/v2.0/ResourceApplication/read");
|
||||
})
|
||||
.ConfigureIntegratedClient(clientId);
|
||||
|
||||
var client = appBuilder.Build();
|
||||
|
||||
// Act & Assert
|
||||
|
||||
// Navigate to protected resource.
|
||||
var goToAuthorizeResponse = await client.GetAsync("https://localhost/Home/About");
|
||||
|
||||
// Redirected to authorize
|
||||
var location = ResponseAssert.IsRedirect(goToAuthorizeResponse);
|
||||
var oidcCookiesComparisonCriteria = CookieComparison.Strict & ~CookieComparison.NameEquals | CookieComparison.NameStartsWith;
|
||||
ResponseAssert.HasCookie(CreateExpectedSetNonceCookie(), goToAuthorizeResponse, oidcCookiesComparisonCriteria);
|
||||
ResponseAssert.HasCookie(CreateExpectedSetCorrelationIdCookie(), goToAuthorizeResponse, oidcCookiesComparisonCriteria);
|
||||
var authorizeParameters = ResponseAssert.LocationHasQueryParameters<OpenIdConnectMessage>(
|
||||
goToAuthorizeResponse,
|
||||
"state");
|
||||
|
||||
// Navigate to authorize
|
||||
var goToLoginResponse = await client.GetAsync(location);
|
||||
|
||||
// Redirected to login
|
||||
location = ResponseAssert.IsRedirect(goToLoginResponse);
|
||||
|
||||
// Navigate to login
|
||||
var goToAuthorizeWithCookie = await client.GetAsync(location);
|
||||
|
||||
// Stamp a login cookie and redirect back to authorize.
|
||||
location = ResponseAssert.IsRedirect(goToAuthorizeWithCookie);
|
||||
ResponseAssert.HasCookie(".AspNetCore.Identity.Application", goToAuthorizeWithCookie, CookieComparison.NameEquals);
|
||||
|
||||
// Navigate to authorize with a login cookie.
|
||||
var goToSignInOidcCallback = await client.GetAsync(location);
|
||||
|
||||
// Stamp an application session cookie and redirect to relying party callback with an authorization code on the query string.
|
||||
location = ResponseAssert.IsRedirect(goToSignInOidcCallback);
|
||||
ResponseAssert.HasCookie("Microsoft.AspNetCore.Identity.Service", goToSignInOidcCallback, CookieComparison.NameEquals);
|
||||
var callBackQueryParameters = ResponseAssert.LocationHasQueryParameters<OpenIdConnectMessage>(goToSignInOidcCallback, "code", ("state", authorizeParameters.State));
|
||||
|
||||
// Navigate to relying party callback.
|
||||
var goToProtectedResource = await client.GetAsync(location);
|
||||
|
||||
// Stamp a session cookie and redirect to the protected resource.
|
||||
location = ResponseAssert.IsRedirect(goToProtectedResource);
|
||||
ResponseAssert.HasCookie(".AspNetCore.Cookies", goToProtectedResource, CookieComparison.NameEquals);
|
||||
ResponseAssert.HasCookie(CreateExpectedSetCorrelationIdCookie(DateTime.Parse("1/1/1970 12:00:00 AM +00:00")), goToProtectedResource, CookieComparison.Delete);
|
||||
ResponseAssert.HasCookie(CreateExpectedSetNonceCookie(DateTime.Parse("1/1/1970 12:00:00 AM +00:00")), goToProtectedResource, CookieComparison.Delete);
|
||||
|
||||
var protectedResourceResponse = await client.GetAsync(location);
|
||||
ResponseAssert.IsOK(protectedResourceResponse);
|
||||
ResponseAssert.IsHtmlDocument(protectedResourceResponse);
|
||||
}
|
||||
|
||||
private SetCookieHeaderValue CreateExpectedSetCorrelationIdCookie(DateTime expires = default(DateTime))
|
||||
{
|
||||
return new SetCookieHeaderValue(new StringSegment(".AspNetCore.Correlation.OpenIdConnect."), new StringSegment("N"))
|
||||
{
|
||||
Expires = expires == default(DateTime) ? DateTime.UtcNow.AddMinutes(15) : expires,
|
||||
Path = "/",
|
||||
Secure = true,
|
||||
HttpOnly = true
|
||||
};
|
||||
}
|
||||
|
||||
private static SetCookieHeaderValue CreateExpectedSetNonceCookie(DateTime expires = default(DateTime))
|
||||
{
|
||||
return new SetCookieHeaderValue(new StringSegment(".AspNetCore.OpenIdConnect.Nonce."), new StringSegment("N"))
|
||||
{
|
||||
Expires = expires == default(DateTime) ? DateTime.UtcNow.AddMinutes(15) : expires,
|
||||
Path = "/",
|
||||
Secure = true,
|
||||
HttpOnly = true
|
||||
};
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.CLR, SkipReason = "https://github.com/aspnet/Identity/issues/1346")]
|
||||
public async Task CanPerform_IdToken_Flow()
|
||||
{
|
||||
// Arrange
|
||||
var clientId = Guid.NewGuid().ToString();
|
||||
var resourceId = Guid.NewGuid().ToString();
|
||||
|
||||
var appBuilder = new CredentialsServerBuilder()
|
||||
.ConfigureReferenceData(data => data
|
||||
.CreateIntegratedWebClientApplication(clientId)
|
||||
.CreateUser("testUser", "Pa$$w0rd"))
|
||||
.ConfigureInMemoryEntityFrameworkStorage()
|
||||
.ConfigureMvcAutomaticSignIn()
|
||||
.ConfigureOpenIdConnectClient(options =>
|
||||
{
|
||||
options.ClientId = clientId;
|
||||
})
|
||||
.ConfigureIntegratedClient(clientId);
|
||||
|
||||
var client = appBuilder.Build();
|
||||
|
||||
// Act
|
||||
var goToAuthorizeResponse = await client.GetAsync("https://localhost/Home/About");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.Redirect, goToAuthorizeResponse.StatusCode);
|
||||
|
||||
// Act
|
||||
var goToLoginResponse = await client.GetAsync(goToAuthorizeResponse.Headers.Location);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.Redirect, goToLoginResponse.StatusCode);
|
||||
|
||||
// Act
|
||||
var goToAuthorizeWithCookie = await client.GetAsync(goToLoginResponse.Headers.Location);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.Redirect, goToAuthorizeWithCookie.StatusCode);
|
||||
|
||||
// Act
|
||||
var goToSignInOidcCallback = await client.GetAsync(goToAuthorizeWithCookie.Headers.Location);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, goToSignInOidcCallback.StatusCode);
|
||||
ResponseAssert.IsHtmlDocument(goToSignInOidcCallback);
|
||||
var form = GetForm(await goToSignInOidcCallback.Content.ReadAsStringAsync());
|
||||
var formRequest = new HttpRequestMessage(new HttpMethod(form.Method), form.Action)
|
||||
{
|
||||
Content = new FormUrlEncodedContent(form.Values)
|
||||
};
|
||||
|
||||
// Act
|
||||
var goToProtectedResource = await client.SendAsync(formRequest);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.Redirect, goToProtectedResource.StatusCode);
|
||||
|
||||
// Act
|
||||
var protectedResourceResponse = await client.GetAsync(goToProtectedResource.Headers.Location);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, protectedResourceResponse.StatusCode);
|
||||
ResponseAssert.IsHtmlDocument(protectedResourceResponse);
|
||||
}
|
||||
|
||||
|
||||
public class Form
|
||||
{
|
||||
public string Action { get; set; }
|
||||
public string Method { get; set; }
|
||||
public IList<KeyValuePair<string, string>> Values { get; set; } = new List<KeyValuePair<string, string>>();
|
||||
}
|
||||
|
||||
private Form GetForm(string html)
|
||||
{
|
||||
var formHeader = Regex.Match(html, @"<form name=""form"" method=""post"" action=""(?<action>[^""]+)"">");
|
||||
var formValues = Regex.Matches(html, @"<input type=""hidden"" name=""(?<name>[^""]+)"" value=""(?<value>[^""]+)"" />",RegexOptions.Multiline)
|
||||
.OfType<Match>()
|
||||
.ToList();
|
||||
|
||||
return new Form
|
||||
{
|
||||
Method = "POST",
|
||||
Action = formHeader.Groups["action"].Captures[0].Value,
|
||||
Values = formValues.Select(m => new KeyValuePair<string, string>(m.Groups["name"].Captures[0].Value, m.Groups["value"].Captures[0].Value)).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"shadowCopy": false
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"directory": "wwwroot/lib"
|
||||
}
|
||||
|
|
@ -0,0 +1,420 @@
|
|||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Models;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Models.AccountViewModels;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Services;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.Service;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Controllers
|
||||
{
|
||||
[Area("IdentityService")]
|
||||
[Route("tfp/IdentityService/[controller]/[action]")]
|
||||
[Authorize(IdentityServiceOptions.LoginPolicyName)]
|
||||
[AllowAnonymous]
|
||||
public class AccountController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly ISmsSender _smsSender;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public AccountController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
IEmailSender emailSender,
|
||||
ISmsSender smsSender,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_emailSender = emailSender;
|
||||
_smsSender = smsSender;
|
||||
_logger = loggerFactory.CreateLogger<AccountController>();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Login(string returnUrl = null)
|
||||
{
|
||||
// Clear the existing external cookie to ensure a clean login process
|
||||
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
|
||||
|
||||
ViewData["ReturnUrl"] = returnUrl;
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
|
||||
{
|
||||
ViewData["ReturnUrl"] = returnUrl;
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
// This doesn't count login failures towards account lockout
|
||||
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
|
||||
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
_logger.LogInformation(1, "User logged in.");
|
||||
return RedirectToLocal(returnUrl);
|
||||
}
|
||||
if (result.RequiresTwoFactor)
|
||||
{
|
||||
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
_logger.LogWarning(2, "User account locked out.");
|
||||
return View("Lockout");
|
||||
}
|
||||
else
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Register(string returnUrl = null)
|
||||
{
|
||||
ViewData["ReturnUrl"] = returnUrl;
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[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 };
|
||||
var result = await _userManager.CreateAsync(user, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
// For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=532713
|
||||
// Send an email with this link
|
||||
//var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
//var callbackUrl = Url.Action(nameof(ConfirmEmail), "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
|
||||
//await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
|
||||
// $"Please confirm your account by clicking this link: <a href='{callbackUrl}'>link</a>");
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(3, "User created a new account with password.");
|
||||
return RedirectToLocal(returnUrl);
|
||||
}
|
||||
AddErrors(result);
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
await _signInManager.SignOutAsync();
|
||||
_logger.LogInformation(4, "User logged out.");
|
||||
return Redirect("/");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public IActionResult ExternalLogin(string provider, string returnUrl = null)
|
||||
{
|
||||
// Request a redirect to the external login provider.
|
||||
var redirectUrl = Url.Action(nameof(ExternalLoginCallback), "Account", new { ReturnUrl = returnUrl });
|
||||
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
|
||||
return Challenge(properties, provider);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
|
||||
{
|
||||
if (remoteError != null)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
|
||||
return View(nameof(Login));
|
||||
}
|
||||
var info = await _signInManager.GetExternalLoginInfoAsync();
|
||||
if (info == null)
|
||||
{
|
||||
return RedirectToAction(nameof(Login));
|
||||
}
|
||||
|
||||
// Sign in the user with this external login provider if the user already has a login.
|
||||
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
_logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
|
||||
return RedirectToLocal(returnUrl);
|
||||
}
|
||||
if (result.RequiresTwoFactor)
|
||||
{
|
||||
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
return View("Lockout");
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the user does not have an account, then ask the user to create an account.
|
||||
ViewData["ReturnUrl"] = returnUrl;
|
||||
ViewData["LoginProvider"] = info.LoginProvider;
|
||||
var email = info.Principal.FindFirstValue(ClaimTypes.Email);
|
||||
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
// Get the information about the user from the external login provider
|
||||
var info = await _signInManager.GetExternalLoginInfoAsync();
|
||||
if (info == null)
|
||||
{
|
||||
return View("ExternalLoginFailure");
|
||||
}
|
||||
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
|
||||
var result = await _userManager.CreateAsync(user);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
result = await _userManager.AddLoginAsync(user, info);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
|
||||
return RedirectToLocal(returnUrl);
|
||||
}
|
||||
}
|
||||
AddErrors(result);
|
||||
}
|
||||
|
||||
ViewData["ReturnUrl"] = returnUrl;
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> ConfirmEmail(string userId, string code)
|
||||
{
|
||||
if (userId == null || code == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var user = await _userManager.FindByIdAsync(userId);
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var result = await _userManager.ConfirmEmailAsync(user, code);
|
||||
return View(result.Succeeded ? "ConfirmEmail" : "Error");
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult ForgotPassword()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = await _userManager.FindByEmailAsync(model.Email);
|
||||
if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
|
||||
{
|
||||
// Don't reveal that the user does not exist or is not confirmed
|
||||
return View("ForgotPasswordConfirmation");
|
||||
}
|
||||
|
||||
// For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=532713
|
||||
// Send an email with this link
|
||||
//var code = await _userManager.GeneratePasswordResetTokenAsync(user);
|
||||
//var callbackUrl = Url.Action(nameof(ResetPassword), "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
|
||||
//await _emailSender.SendEmailAsync(model.Email, "Reset Password",
|
||||
// $"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
|
||||
//return View("ForgotPasswordConfirmation");
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult ForgotPasswordConfirmation()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult ResetPassword(string code = null)
|
||||
{
|
||||
return code == null ? View("Error") : View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await _userManager.FindByEmailAsync(model.Email);
|
||||
if (user == null)
|
||||
{
|
||||
// Don't reveal that the user does not exist
|
||||
return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
|
||||
}
|
||||
var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
|
||||
}
|
||||
AddErrors(result);
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult ResetPasswordConfirmation()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> SendCode(string returnUrl = null, bool rememberMe = false)
|
||||
{
|
||||
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user);
|
||||
var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList();
|
||||
return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> SendCode(SendCodeViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
|
||||
// Generate the token and send it
|
||||
var code = await _userManager.GenerateTwoFactorTokenAsync(user, model.SelectedProvider);
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
|
||||
var message = "Your security code is: " + code;
|
||||
if (model.SelectedProvider == "Email")
|
||||
{
|
||||
await _emailSender.SendEmailAsync(await _userManager.GetEmailAsync(user), "Security Code", message);
|
||||
}
|
||||
else if (model.SelectedProvider == "Phone")
|
||||
{
|
||||
await _smsSender.SendSmsAsync(await _userManager.GetPhoneNumberAsync(user), message);
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(VerifyCode), new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe });
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> VerifyCode(string provider, bool rememberMe, string returnUrl = null)
|
||||
{
|
||||
// Require that the user has already logged in via username/password or external login
|
||||
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> VerifyCode(VerifyCodeViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
// The following code protects for brute force attacks against the two factor codes.
|
||||
// If a user enters incorrect codes for a specified amount of time then the user account
|
||||
// will be locked out for a specified amount of time.
|
||||
var result = await _signInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, model.RememberBrowser);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
return RedirectToLocal(model.ReturnUrl);
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
_logger.LogWarning(7, "User account locked out.");
|
||||
return View("Lockout");
|
||||
}
|
||||
else
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, "Invalid code.");
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult AccessDenied()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void AddErrors(IdentityResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, error.Description);
|
||||
}
|
||||
}
|
||||
|
||||
private IActionResult RedirectToLocal(string returnUrl)
|
||||
{
|
||||
if (Url.IsLocalUrl(returnUrl))
|
||||
{
|
||||
return Redirect(returnUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Redirect("/");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,628 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Models;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.Service;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Controllers
|
||||
{
|
||||
[Authorize(IdentityServiceOptions.ManagementPolicyName)]
|
||||
[Area("IdentityService")]
|
||||
public class ApplicationsController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly ApplicationManager<IdentityServiceApplication> _applicationManager;
|
||||
|
||||
public ApplicationsController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
ApplicationManager<IdentityServiceApplication> applicationManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_applicationManager = applicationManager;
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications")]
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
var id = _userManager.GetUserId(User);
|
||||
var applications = await _applicationManager.Applications.ToListAsync();
|
||||
return View(applications);
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/Create")]
|
||||
public IActionResult Create()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/Create")]
|
||||
public async Task<IActionResult> Create(CreateApplicationViewModel model)
|
||||
{
|
||||
var application = new IdentityServiceApplication
|
||||
{
|
||||
Name = model.Name,
|
||||
ClientId = Guid.NewGuid().ToString()
|
||||
};
|
||||
|
||||
await _applicationManager.CreateAsync(application);
|
||||
await _applicationManager.AddScopeAsync(application, OpenIdConnectScope.OpenId);
|
||||
await _applicationManager.AddScopeAsync(application, "offline_access");
|
||||
|
||||
return RedirectToAction(nameof(CreateScope), new { id = application.Id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/Scopes/Create")]
|
||||
public async Task<IActionResult> CreateScope([FromRoute] string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
var scopes = await _applicationManager.FindScopesAsync(application);
|
||||
|
||||
return View(new CreateScopeViewModel(applicationName, scopes));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/Scopes/Create")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> CreateScope(
|
||||
[FromRoute] string id,
|
||||
[FromForm] CreateScopeViewModel model)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
var scopes = await _applicationManager.FindScopesAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new CreateScopeViewModel(applicationName, scopes));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.AddScopeAsync(application, model.NewScope);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new CreateScopeViewModel(applicationName, scopes));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(CreateScope), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/RedirectUris/Create")]
|
||||
public async Task<IActionResult> CreateRedirectUri([FromRoute] string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
var redirectUris = await _applicationManager.FindRegisteredUrisAsync(application);
|
||||
|
||||
return View(new CreateRedirectUriViewModel(applicationName, redirectUris));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/RedirectUris/Create")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> CreateRedirectUri(
|
||||
[FromRoute] string id,
|
||||
[FromForm] CreateRedirectUriViewModel model)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
var redirectUris = await _applicationManager.FindRegisteredUrisAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new CreateRedirectUriViewModel(applicationName, redirectUris));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.RegisterRedirectUriAsync(application, model.NewRedirectUri);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new CreateRedirectUriViewModel(applicationName, redirectUris));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(CreateRedirectUri), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/LogoutUris/Create")]
|
||||
public async Task<IActionResult> CreateLogoutUri([FromRoute] string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
var logoutUris = await _applicationManager.FindRegisteredLogoutUrisAsync(application);
|
||||
|
||||
return View(new CreateLogoutUriViewModel(id, applicationName, logoutUris));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/LogoutUris/Create")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> CreateLogoutUri(
|
||||
[FromRoute] string id,
|
||||
[FromForm] CreateLogoutUriViewModel model)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
var logoutUris = await _applicationManager.FindRegisteredLogoutUrisAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new CreateLogoutUriViewModel(id, applicationName, logoutUris));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.RegisterLogoutUriAsync(application, model.NewLogoutUri);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new CreateLogoutUriViewModel(id, applicationName, logoutUris));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(CreateLogoutUri), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/Remove")]
|
||||
public async Task<IActionResult> RemoveApplication([FromRoute] string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
return View(new RemoveApplicationViewModel(applicationName));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/Remove")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[ActionName(nameof(RemoveApplicationViewModel))]
|
||||
public async Task<IActionResult> RemoveApplicationConfirmed([FromRoute] string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new RemoveApplicationViewModel(applicationName));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.DeleteAsync(application);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new RemoveApplicationViewModel(applicationName));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}")]
|
||||
public async Task<IActionResult> Details([FromRoute]string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
var applicationClientId = await _applicationManager.GetApplicationClientIdAsync(application);
|
||||
var hasClientSecret = await _applicationManager.HasClientSecretAsync(application);
|
||||
var redirectUris = await _applicationManager.FindRegisteredUrisAsync(application);
|
||||
var logoutUris = await _applicationManager.FindRegisteredLogoutUrisAsync(application);
|
||||
var scopes = await _applicationManager.FindScopesAsync(application);
|
||||
|
||||
return View(new ApplicationDetailsViewModel
|
||||
{
|
||||
Name = applicationName,
|
||||
ClientId = applicationClientId,
|
||||
HasClientSecret = hasClientSecret,
|
||||
RedirectUris = redirectUris,
|
||||
LogoutUris = logoutUris,
|
||||
Scopes = scopes
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/ChangeName")]
|
||||
public async Task<IActionResult> ChangeName([FromRoute]string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
return View(new ChangeApplicationNameViewModel(applicationName));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/ChangeName")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> ChangeName([FromRoute]string id, [FromForm] ChangeApplicationNameViewModel model)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new ChangeApplicationNameViewModel(applicationName));
|
||||
}
|
||||
|
||||
var changeNameResult = await _applicationManager.SetApplicationNameAsync(application, model.Name);
|
||||
if (!changeNameResult.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", changeNameResult);
|
||||
return View(new ChangeApplicationNameViewModel(applicationName));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(Details), new { id });
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/GenerateClientSecret")]
|
||||
public async Task<IActionResult> GenerateClientSecret([FromRoute]string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var name = await _applicationManager.GetApplicationNameAsync(application);
|
||||
return View(model: name);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/GenerateClientSecret")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[ActionName(nameof(GenerateClientSecret))]
|
||||
public async Task<IActionResult> GenerateClientSecretConfirmed([FromRoute]string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var name = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
var clientSecret = await _applicationManager.GenerateClientSecretAsync();
|
||||
var addSecretResult = await _applicationManager.AddClientSecretAsync(application, clientSecret);
|
||||
if (!addSecretResult.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", addSecretResult);
|
||||
return View(model: name);
|
||||
}
|
||||
|
||||
return View("GeneratedClientSecret", new GeneratedClientSecretViewModel(name, clientSecret));
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/RemoveClientSecret")]
|
||||
public async Task<IActionResult> RemoveClientSecret([FromRoute]string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var name = await _applicationManager.GetApplicationNameAsync(application);
|
||||
return View(model: name);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/RemoveClientSecret")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[ActionName(nameof(RemoveClientSecret))]
|
||||
public async Task<IActionResult> RemoveClientSecretConfirmed([FromRoute]string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var name = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
var removeSecretResult = await _applicationManager.RemoveClientSecretAsync(application);
|
||||
if (!removeSecretResult.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", removeSecretResult);
|
||||
return View(model: name);
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(Details), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/RegenerateClientSecret")]
|
||||
public async Task<IActionResult> RegenerateClientSecret([FromRoute]string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var name = await _applicationManager.GetApplicationNameAsync(application);
|
||||
return View(model: name);
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/RegenerateClientSecret")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[ActionName(nameof(RegenerateClientSecret))]
|
||||
public async Task<IActionResult> RegenerateClientSecretConfirmed([FromRoute]string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var name = await _applicationManager.GetApplicationNameAsync(application);
|
||||
var clientSecret = await _applicationManager.GenerateClientSecretAsync();
|
||||
var changeSecretResult = await _applicationManager.ChangeClientSecretAsync(application, clientSecret);
|
||||
if (!changeSecretResult.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", changeSecretResult);
|
||||
return View(model: name);
|
||||
}
|
||||
|
||||
return View("GeneratedClientSecret", new GeneratedClientSecretViewModel(name, clientSecret));
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/Scopes/Add")]
|
||||
public async Task<IActionResult> AddScope([FromRoute] string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var scopes = await _applicationManager.FindScopesAsync(application);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
return View(new CreateScopeViewModel(applicationName, scopes));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/Scopes/Add")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> AddScope(
|
||||
[FromRoute] string id,
|
||||
[FromForm] CreateScopeViewModel model)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var scopes = await _applicationManager.FindScopesAsync(application);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new CreateScopeViewModel(applicationName, scopes));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.AddScopeAsync(application, model.NewScope);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new CreateScopeViewModel(applicationName, scopes));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(AddScope), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/Scopes/Edit/{scope}")]
|
||||
public async Task<IActionResult> EditScope([FromRoute] string id, [FromRoute] string scope)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
return View(new EditScopeViewModel(applicationName, scope));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/Scopes/Edit/{scope}")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> EditScope(
|
||||
[FromRoute] string id,
|
||||
[FromRoute] string scope,
|
||||
[FromForm] EditScopeViewModel model)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new EditScopeViewModel(applicationName, scope));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.UpdateScopeAsync(application, scope, model.Scope);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new EditScopeViewModel(applicationName, scope));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(Details), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/RedirectUri/Edit")]
|
||||
public async Task<IActionResult> EditRedirectUri([FromRoute] string id, [FromQuery] string redirectUri)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
return View(new EditRedirectUriViewModel(applicationName, redirectUri));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/RedirectUri/Edit")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> EditRedirectUri(
|
||||
[FromRoute] string id,
|
||||
[FromQuery] string redirectUri,
|
||||
[FromForm] EditRedirectUriViewModel model)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new EditRedirectUriViewModel(applicationName, redirectUri));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.UpdateRedirectUriAsync(application, redirectUri, model.RedirectUri);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new EditRedirectUriViewModel(applicationName, redirectUri));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(Details), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/LogoutUri/Edit")]
|
||||
public async Task<IActionResult> EditLogoutUri([FromRoute] string id, [FromQuery] string logoutUri)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
return View(new EditLogoutUriViewModel(applicationName, logoutUri));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/LogoutUri/Edit")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> EditLogoutUri(
|
||||
[FromRoute] string id,
|
||||
[FromQuery] string logoutUri,
|
||||
[FromForm] EditLogoutUriViewModel model)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new EditLogoutUriViewModel(applicationName, logoutUri));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.UpdateLogoutUriAsync(application, logoutUri, model.LogoutUri);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new EditLogoutUriViewModel(applicationName, logoutUri));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(Details), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/Scopes/Remove/{scope}")]
|
||||
public async Task<IActionResult> RemoveScope([FromRoute] string id, [FromRoute] string scope)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
return View(new RemoveScopeViewModel(applicationName, scope));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/Scopes/Remove/{scope}")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[ActionName(nameof(RemoveScope))]
|
||||
public async Task<IActionResult> RemoveScopeConfirmed([FromRoute] string id, [FromRoute] string scope)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new RemoveScopeViewModel(applicationName, scope));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.RemoveScopeAsync(application, scope);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new RemoveScopeViewModel(applicationName, scope));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(Details), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/RedirectUri/Remove")]
|
||||
public async Task<IActionResult> RemoveRedirectUri([FromRoute] string id, [FromQuery] string redirectUri)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
return View(new RemoveRedirectUriViewModel(applicationName, redirectUri));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/RedirectUri/Remove")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[ActionName(nameof(RemoveRedirectUri))]
|
||||
public async Task<IActionResult> RemoveRedirectUriConfirmed([FromRoute] string id, [FromQuery] string redirectUri)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new RemoveRedirectUriViewModel(applicationName, redirectUri));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.UnregisterRedirectUriAsync(application, redirectUri);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new RemoveRedirectUriViewModel(applicationName, redirectUri));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(Details), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/LogoutUri/Remove")]
|
||||
public async Task<IActionResult> RemoveLogoutUri([FromRoute] string id, [FromQuery] string logoutUri)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
return View(new RemoveLogoutUriViewModel(applicationName, logoutUri));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/LogoutUri/Remove")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[ActionName(nameof(RemoveLogoutUri))]
|
||||
public async Task<IActionResult> RemoveLogoutUriConfirmed([FromRoute] string id, [FromQuery] string logoutUri)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new RemoveLogoutUriViewModel(applicationName, logoutUri));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.UnregisterLogoutUriAsync(application, logoutUri);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new RemoveLogoutUriViewModel(applicationName, logoutUri));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(Details), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/RedirectUris/Add")]
|
||||
public async Task<IActionResult> AddRedirectUri([FromRoute] string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var redirectUris = await _applicationManager.FindRegisteredUrisAsync(application);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
return View(new CreateRedirectUriViewModel(applicationName, redirectUris));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/RedirectUris/Add")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> AddRedirectUri(
|
||||
[FromRoute] string id,
|
||||
[FromForm] CreateRedirectUriViewModel model)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var redirectUris = await _applicationManager.FindRegisteredUrisAsync(application);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new CreateRedirectUriViewModel(applicationName, redirectUris));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.RegisterRedirectUriAsync(application, model.NewRedirectUri);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new CreateRedirectUriViewModel(applicationName, redirectUris));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(AddRedirectUri), new { id });
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/Applications/{id}/LogoutUris/Add")]
|
||||
public async Task<IActionResult> AddLogoutUri([FromRoute] string id)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var logoutUris = await _applicationManager.FindRegisteredLogoutUrisAsync(application);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
|
||||
return View(new CreateLogoutUriViewModel(id, applicationName, logoutUris));
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/Applications/{id}/LogoutUris/Add")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> AddLogoutUri(
|
||||
[FromRoute] string id,
|
||||
[FromForm] CreateLogoutUriViewModel model)
|
||||
{
|
||||
var application = await _applicationManager.FindByIdAsync(id);
|
||||
var logoutUris = await _applicationManager.FindRegisteredLogoutUrisAsync(application);
|
||||
var applicationName = await _applicationManager.GetApplicationNameAsync(application);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(new CreateLogoutUriViewModel(id, applicationName, logoutUris));
|
||||
}
|
||||
|
||||
var result = await _applicationManager.RegisterLogoutUriAsync(application, model.NewLogoutUri);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
MapErrorsToModelState("", result);
|
||||
return View(new CreateLogoutUriViewModel(id, applicationName, logoutUris));
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(AddLogoutUri), new { id });
|
||||
}
|
||||
|
||||
private void MapErrorsToModelState(string key, IdentityServiceResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError(key, error.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.Service;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Controllers
|
||||
{
|
||||
[Area("IdentityService")]
|
||||
public class IdentityServiceConfigurationController : Controller
|
||||
{
|
||||
private readonly IConfigurationManager _configurationProvider;
|
||||
private readonly IKeySetMetadataProvider _keySetProvider;
|
||||
|
||||
public IdentityServiceConfigurationController(
|
||||
IConfigurationManager configurationProvider,
|
||||
IKeySetMetadataProvider keySetProvider)
|
||||
{
|
||||
_configurationProvider = configurationProvider;
|
||||
_keySetProvider = keySetProvider;
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/v2.0/.well-known/openid-configuration")]
|
||||
[Produces("application/json")]
|
||||
public async Task<IActionResult> Metadata()
|
||||
{
|
||||
var configurationContext = new ConfigurationContext
|
||||
{
|
||||
Id = "IdentityService:signinsignup",
|
||||
HttpContext = HttpContext,
|
||||
AuthorizationEndpoint = EndpointLink("Authorize", "IdentityService"),
|
||||
TokenEndpoint = EndpointLink("Token", "IdentityService"),
|
||||
JwksUriEndpoint = EndpointLink("Keys", "IdentityServiceConfiguration"),
|
||||
EndSessionEndpoint = EndpointLink("Logout", "IdentityService"),
|
||||
};
|
||||
|
||||
return Ok(await _configurationProvider.GetConfigurationAsync(configurationContext));
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/discovery/v2.0/keys")]
|
||||
[Produces("application/json")]
|
||||
public async Task<IActionResult> Keys()
|
||||
{
|
||||
return Ok(await _keySetProvider.GetKeysAsync());
|
||||
}
|
||||
|
||||
private string EndpointLink(string action, string controller) =>
|
||||
Url.Action(action, controller, null, Request.Scheme, Request.Host.Value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Models;
|
||||
using Microsoft.AspNetCore.Identity.Service;
|
||||
using Microsoft.AspNetCore.Identity.Service.IntegratedWebClient;
|
||||
using Microsoft.AspNetCore.Identity.Service.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Controllers
|
||||
{
|
||||
[Area("IdentityService")]
|
||||
public class IdentityServiceController : Controller
|
||||
{
|
||||
private readonly IOptions<IdentityServiceOptions> _options;
|
||||
private readonly ITokenManager _tokenManager;
|
||||
private readonly SessionManager<ApplicationUser, IdentityServiceApplication> _sessionManager;
|
||||
private readonly IAuthorizationResponseFactory _authorizationResponseFactory;
|
||||
private readonly ITokenResponseFactory _tokenResponseFactory;
|
||||
|
||||
public IdentityServiceController(
|
||||
IOptions<IdentityServiceOptions> options,
|
||||
ITokenManager tokenManager,
|
||||
SessionManager<ApplicationUser, IdentityServiceApplication> sessionManager,
|
||||
IAuthorizationResponseFactory authorizationResponseFactory,
|
||||
ITokenResponseFactory tokenResponseFactory)
|
||||
{
|
||||
_options = options;
|
||||
_tokenManager = tokenManager;
|
||||
_sessionManager = sessionManager;
|
||||
_authorizationResponseFactory = authorizationResponseFactory;
|
||||
_tokenResponseFactory = tokenResponseFactory;
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/oauth2/v2.0/authorize/")]
|
||||
public async Task<IActionResult> Authorize(
|
||||
[EnableIntegratedWebClient, ModelBinder(typeof(AuthorizationRequestModelBinder))] AuthorizationRequest authorization)
|
||||
{
|
||||
if (!authorization.IsValid)
|
||||
{
|
||||
return this.InvalidAuthorization(authorization.Error);
|
||||
}
|
||||
|
||||
var authorizationResult = await _sessionManager.IsAuthorizedAsync(authorization);
|
||||
if (authorizationResult.Status == AuthorizationStatus.Forbidden)
|
||||
{
|
||||
return this.InvalidAuthorization(authorizationResult.Error);
|
||||
}
|
||||
|
||||
if (authorizationResult.Status == AuthorizationStatus.LoginRequired)
|
||||
{
|
||||
return RedirectToLogin(nameof(AccountController.Login), "Account", authorization.Message);
|
||||
}
|
||||
|
||||
var context = authorization.CreateTokenGeneratingContext(
|
||||
authorizationResult.User,
|
||||
authorizationResult.Application);
|
||||
|
||||
context.AmbientClaims.Add(new Claim("policy", "signinsignup"));
|
||||
context.AmbientClaims.Add(new Claim("version", "1.0"));
|
||||
context.AmbientClaims.Add(new Claim("tenantId", "CDF07358 -BA97-470F-93CD-FC46E1B57F99"));
|
||||
|
||||
await _tokenManager.IssueTokensAsync(context);
|
||||
var response = await _authorizationResponseFactory.CreateAuthorizationResponseAsync(context);
|
||||
|
||||
await _sessionManager.StartSessionAsync(authorizationResult.User, authorizationResult.Application);
|
||||
|
||||
return this.ValidAuthorization(response);
|
||||
}
|
||||
|
||||
[HttpPost("tfp/IdentityService/signinsignup/oauth2/v2.0/token")]
|
||||
[Produces("application/json")]
|
||||
public async Task<IActionResult> Token(
|
||||
[ModelBinder(typeof(TokenRequestModelBinder))] TokenRequest request)
|
||||
{
|
||||
if (!request.IsValid)
|
||||
{
|
||||
return BadRequest(request.Error.Parameters);
|
||||
}
|
||||
|
||||
var session = await _sessionManager.CreateSessionAsync(request.UserId, request.ClientId);
|
||||
|
||||
var context = request.CreateTokenGeneratingContext(session.User, session.Application);
|
||||
|
||||
context.AmbientClaims.Add(new Claim("policy", "signinsignup"));
|
||||
context.AmbientClaims.Add(new Claim("version", "1.0"));
|
||||
context.AmbientClaims.Add(new Claim("tenantId", "CDF07358 -BA97-470F-93CD-FC46E1B57F99"));
|
||||
|
||||
await _tokenManager.IssueTokensAsync(context);
|
||||
var response = await _tokenResponseFactory.CreateTokenResponseAsync(context);
|
||||
return Ok(response.Parameters);
|
||||
}
|
||||
|
||||
[HttpGet("tfp/IdentityService/signinsignup/oauth2/v2.0/logout")]
|
||||
public async Task<IActionResult> Logout(
|
||||
[EnableIntegratedWebClient, ModelBinder(typeof(LogoutRequestModelBinder))] LogoutRequest request)
|
||||
{
|
||||
if (!request.IsValid)
|
||||
{
|
||||
return View("InvalidLogoutRedirect", request.Message);
|
||||
}
|
||||
|
||||
var endSessionResult = await _sessionManager.EndSessionAsync(request);
|
||||
if (endSessionResult.Status == LogoutStatus.RedirectToLogoutUri)
|
||||
{
|
||||
return Redirect(endSessionResult.LogoutRedirect);
|
||||
}
|
||||
else
|
||||
{
|
||||
return View("LoggedOut", request);
|
||||
}
|
||||
}
|
||||
|
||||
private IActionResult RedirectToLogin(string action, string controller, OpenIdConnectMessage message)
|
||||
{
|
||||
var messageCopy = message.Clone();
|
||||
messageCopy.Prompt = null;
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
ReturnUrl = Url.Action("Authorize", "IdentityService", messageCopy.Parameters)
|
||||
};
|
||||
|
||||
return RedirectToAction(action, controller, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,342 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Models;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Models.ManageViewModels;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Services;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.Service;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Controllers
|
||||
{
|
||||
[Authorize(IdentityServiceOptions.LoginPolicyName)]
|
||||
[Area("IdentityService")]
|
||||
[Route("tfp/IdentityService/[controller]/[action]")]
|
||||
public class ManageController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly ISmsSender _smsSender;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public ManageController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
IEmailSender emailSender,
|
||||
ISmsSender smsSender,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_emailSender = emailSender;
|
||||
_smsSender = smsSender;
|
||||
_logger = loggerFactory.CreateLogger<ManageController>();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Index(ManageMessageId? message = null)
|
||||
{
|
||||
ViewData["StatusMessage"] =
|
||||
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
|
||||
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
|
||||
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
|
||||
: message == ManageMessageId.Error ? "An error has occurred."
|
||||
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
|
||||
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
|
||||
: "";
|
||||
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var model = new IndexViewModel
|
||||
{
|
||||
HasPassword = await _userManager.HasPasswordAsync(user),
|
||||
PhoneNumber = await _userManager.GetPhoneNumberAsync(user),
|
||||
TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user),
|
||||
Logins = await _userManager.GetLoginsAsync(user),
|
||||
BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user)
|
||||
};
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
|
||||
{
|
||||
ManageMessageId? message = ManageMessageId.Error;
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
message = ManageMessageId.RemoveLoginSuccess;
|
||||
}
|
||||
}
|
||||
return RedirectToAction(nameof(ManageLogins), new { Message = message });
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult AddPhoneNumber()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
// Generate the token and send it
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber);
|
||||
await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code);
|
||||
return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> EnableTwoFactorAuthentication()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
await _userManager.SetTwoFactorEnabledAsync(user, true);
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(1, "User enabled two-factor authentication.");
|
||||
}
|
||||
return RedirectToAction(nameof(Index), "Manage");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> DisableTwoFactorAuthentication()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
await _userManager.SetTwoFactorEnabledAsync(user, false);
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(2, "User disabled two-factor authentication.");
|
||||
}
|
||||
return RedirectToAction(nameof(Index), "Manage");
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> VerifyPhoneNumber(string phoneNumber)
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, phoneNumber);
|
||||
// Send an SMS to verify the phone number
|
||||
return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess });
|
||||
}
|
||||
}
|
||||
// If we got this far, something failed, redisplay the form
|
||||
ModelState.AddModelError(string.Empty, "Failed to verify phone number");
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> RemovePhoneNumber()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.SetPhoneNumberAsync(user, null);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess });
|
||||
}
|
||||
}
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult ChangePassword()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(3, "User changed their password successfully.");
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess });
|
||||
}
|
||||
AddErrors(result);
|
||||
return View(model);
|
||||
}
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult SetPassword()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> SetPassword(SetPasswordViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.AddPasswordAsync(user, model.NewPassword);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess });
|
||||
}
|
||||
AddErrors(result);
|
||||
return View(model);
|
||||
}
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> ManageLogins(ManageMessageId? message = null)
|
||||
{
|
||||
ViewData["StatusMessage"] =
|
||||
message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
|
||||
: message == ManageMessageId.AddLoginSuccess ? "The external login was added."
|
||||
: message == ManageMessageId.Error ? "An error has occurred."
|
||||
: "";
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var userLogins = await _userManager.GetLoginsAsync(user);
|
||||
var schemes = await _signInManager.GetExternalAuthenticationSchemesAsync();
|
||||
var otherLogins = schemes.Where(auth => userLogins.All(ul => auth.Name != ul.LoginProvider)).ToList();
|
||||
ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1;
|
||||
return View(new ManageLoginsViewModel
|
||||
{
|
||||
CurrentLogins = userLogins,
|
||||
OtherLogins = otherLogins
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> LinkLogin(string provider)
|
||||
{
|
||||
// Clear the existing external cookie to ensure a clean login process
|
||||
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
|
||||
|
||||
// Request a redirect to the external login provider to link a login for the current user
|
||||
var redirectUrl = Url.Action(nameof(LinkLoginCallback), "Manage");
|
||||
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User));
|
||||
return Challenge(properties, provider);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> LinkLoginCallback()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user));
|
||||
if (info == null)
|
||||
{
|
||||
return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
var result = await _userManager.AddLoginAsync(user, info);
|
||||
var message = ManageMessageId.Error;
|
||||
if (result.Succeeded)
|
||||
{
|
||||
message = ManageMessageId.AddLoginSuccess;
|
||||
// Clear the existing external cookie to ensure a clean login process
|
||||
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
|
||||
}
|
||||
return RedirectToAction(nameof(ManageLogins), new { Message = message });
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void AddErrors(IdentityResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, error.Description);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ManageMessageId
|
||||
{
|
||||
AddPhoneSuccess,
|
||||
AddLoginSuccess,
|
||||
ChangePasswordSuccess,
|
||||
SetTwoFactorSuccess,
|
||||
SetPasswordSuccess,
|
||||
RemoveLoginSuccess,
|
||||
RemovePhoneSuccess,
|
||||
Error
|
||||
}
|
||||
|
||||
private Task<ApplicationUser> GetCurrentUserAsync()
|
||||
{
|
||||
return _userManager.GetUserAsync(HttpContext.User);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Identity.Service;
|
||||
using Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Models;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Data
|
||||
{
|
||||
public class IdentityServiceDbContext : IdentityServiceDbContext<ApplicationUser, IdentityServiceApplication>
|
||||
{
|
||||
public IdentityServiceDbContext(DbContextOptions<IdentityServiceDbContext> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
using Microsoft.EntityFrameworkCore.Design;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Data
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,353 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Data;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(IdentityServiceDbContext))]
|
||||
[Migration("00000000000000_CreateIdentitySchema")]
|
||||
partial class CreateIdentitySchema
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.0-preview1-24567");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplication", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("ClientSecretHash");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClientId")
|
||||
.IsUnique()
|
||||
.HasName("ClientIdIndex");
|
||||
|
||||
b.HasIndex("Name")
|
||||
.IsUnique()
|
||||
.HasName("NameIndex");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetApplications");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplicationClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApplicationId");
|
||||
|
||||
b.ToTable("AspNetApplicationClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceRedirectUri<string>", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<bool>("IsLogout");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApplicationId");
|
||||
|
||||
b.ToTable("AspNetRedirectUris");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceScope<string>", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApplicationId");
|
||||
|
||||
b.ToTable("AspNetScopes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
|
||||
.HasName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
|
||||
.WithMany("Claims")
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser")
|
||||
.WithMany("Claims")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser")
|
||||
.WithMany("Roles")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser")
|
||||
.WithMany("Tokens")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplication", b =>
|
||||
{
|
||||
b.HasOne("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplicationClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplication")
|
||||
.WithMany("Claims")
|
||||
.HasForeignKey("ApplicationId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceRedirectUri<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplication")
|
||||
.WithMany("RedirectUris")
|
||||
.HasForeignKey("ApplicationId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceScope<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplication")
|
||||
.WithMany("Scopes")
|
||||
.HasForeignKey("ApplicationId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Identity.Service;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Data.Migrations
|
||||
{
|
||||
public partial class CreateIdentitySchema : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoles",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(nullable: false),
|
||||
ConcurrencyStamp = table.Column<string>(nullable: true),
|
||||
Name = table.Column<string>(maxLength: 256, nullable: true),
|
||||
NormalizedName = table.Column<string>(maxLength: 256, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUsers",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(nullable: false),
|
||||
AccessFailedCount = table.Column<int>(nullable: false),
|
||||
ConcurrencyStamp = table.Column<string>(nullable: true),
|
||||
Email = table.Column<string>(maxLength: 256, nullable: true),
|
||||
EmailConfirmed = table.Column<bool>(nullable: false),
|
||||
LockoutEnabled = table.Column<bool>(nullable: false),
|
||||
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
|
||||
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
|
||||
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
|
||||
PasswordHash = table.Column<string>(nullable: true),
|
||||
PhoneNumber = table.Column<string>(nullable: true),
|
||||
PhoneNumberConfirmed = table.Column<bool>(nullable: false),
|
||||
SecurityStamp = table.Column<string>(nullable: true),
|
||||
TwoFactorEnabled = table.Column<bool>(nullable: false),
|
||||
UserName = table.Column<string>(maxLength: 256, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoleClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
ClaimType = table.Column<string>(nullable: true),
|
||||
ClaimValue = table.Column<string>(nullable: true),
|
||||
RoleId = table.Column<string>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
ClaimType = table.Column<string>(nullable: true),
|
||||
ClaimValue = table.Column<string>(nullable: true),
|
||||
UserId = table.Column<string>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserLogins",
|
||||
columns: table => new
|
||||
{
|
||||
LoginProvider = table.Column<string>(nullable: false),
|
||||
ProviderKey = table.Column<string>(nullable: false),
|
||||
ProviderDisplayName = table.Column<string>(nullable: true),
|
||||
UserId = table.Column<string>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserRoles",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<string>(nullable: false),
|
||||
RoleId = table.Column<string>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserTokens",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<string>(nullable: false),
|
||||
LoginProvider = table.Column<string>(nullable: false),
|
||||
Name = table.Column<string>(nullable: false),
|
||||
Value = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetApplications",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(nullable: false),
|
||||
ClientId = table.Column<string>(maxLength: 256, nullable: false),
|
||||
ClientSecretHash = table.Column<string>(nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(nullable: true),
|
||||
Name = table.Column<string>(maxLength: 256, nullable: false),
|
||||
UserId = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetApplications", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetApplications_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetApplicationClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
ApplicationId = table.Column<string>(nullable: false),
|
||||
ClaimType = table.Column<string>(maxLength: 256, nullable: false),
|
||||
ClaimValue = table.Column<string>(maxLength: 256, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetApplicationClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetApplicationClaims_AspNetApplications_ApplicationId",
|
||||
column: x => x.ApplicationId,
|
||||
principalTable: "AspNetApplications",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRedirectUris",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(nullable: false),
|
||||
ApplicationId = table.Column<string>(nullable: false),
|
||||
IsLogout = table.Column<bool>(nullable: false),
|
||||
Value = table.Column<string>(maxLength: 256, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRedirectUris", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetRedirectUris_AspNetApplications_ApplicationId",
|
||||
column: x => x.ApplicationId,
|
||||
principalTable: "AspNetApplications",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetScopes",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(nullable: false),
|
||||
ApplicationId = table.Column<string>(nullable: false),
|
||||
Value = table.Column<string>(maxLength: 256, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetScopes", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetScopes_AspNetApplications_ApplicationId",
|
||||
column: x => x.ApplicationId,
|
||||
principalTable: "AspNetApplications",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "RoleNameIndex",
|
||||
table: "AspNetRoles",
|
||||
column: "NormalizedName",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetRoleClaims_RoleId",
|
||||
table: "AspNetRoleClaims",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserClaims_UserId",
|
||||
table: "AspNetUserClaims",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserLogins_UserId",
|
||||
table: "AspNetUserLogins",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserRoles_RoleId",
|
||||
table: "AspNetUserRoles",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ClientIdIndex",
|
||||
table: "AspNetApplications",
|
||||
column: "ClientId",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "NameIndex",
|
||||
table: "AspNetApplications",
|
||||
column: "Name",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetApplications_UserId",
|
||||
table: "AspNetApplications",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetApplicationClaims_ApplicationId",
|
||||
table: "AspNetApplicationClaims",
|
||||
column: "ApplicationId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetRedirectUris_ApplicationId",
|
||||
table: "AspNetRedirectUris",
|
||||
column: "ApplicationId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetScopes_ApplicationId",
|
||||
table: "AspNetScopes",
|
||||
column: "ApplicationId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "EmailIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedEmail");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "UserNameIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedUserName",
|
||||
unique: true);
|
||||
|
||||
// Seed client application
|
||||
var clientAppId = "4122031F-D3A2-4C1A-B25E-2A55B2A32FAC";
|
||||
var clientId = "56A33E6A-ADFE-47EA-BBFE-40F4AE4C55BA";
|
||||
migrationBuilder.Sql($@"INSERT INTO AspNetApplications (Id,ClientId,Name)
|
||||
VALUES (N'{clientAppId}',N'{clientId}',N'Identity.OpenIdConnect.WebSite')");
|
||||
//migrationBuilder.InsertData(
|
||||
// table: "AspNetApplications",
|
||||
// columns: new[] { "Id", "ClientId", "Name" },
|
||||
// values: new object[,]
|
||||
// {
|
||||
// { clientAppId, clientId, "Identity.OpenIdConnect.WebSite" }
|
||||
// });
|
||||
|
||||
var clientOpenIdScopeId = "7F4F91FE-87F5-41DC-B111-3DC5FC186E35";
|
||||
migrationBuilder.Sql($@"INSERT INTO AspNetScopes (Id,ApplicationId,Value)
|
||||
VALUES (N'{clientOpenIdScopeId}',N'{clientAppId}',N'{ApplicationScope.OpenId.Scope}')");
|
||||
//migrationBuilder.InsertData(
|
||||
// table: "AspNetScopes",
|
||||
// columns: new[] { "Id", "ApplicationId", "Value" },
|
||||
// values: new object[,]
|
||||
// {
|
||||
// { clientOpenIdScopeId, clientAppId, ApplicationScope.OpenId.Scope },
|
||||
// });
|
||||
|
||||
var clientRedirectUriId = "849B8050-0DEC-4A96-B234-8A08695A1526";
|
||||
var clientLogoutRedirectUriId = "9F24EA98-4375-4CE2-A37C-95832F19D75D";
|
||||
migrationBuilder.Sql($@"INSERT INTO AspNetRedirectUris (Id, ApplicationId, IsLogout, Value)
|
||||
VALUES (N'{clientRedirectUriId}',N'{clientAppId}','false',N'urn:self:aspnet:identity:integrated')");
|
||||
migrationBuilder.Sql($@"INSERT INTO AspNetRedirectUris (Id, ApplicationId, IsLogout, Value)
|
||||
VALUES (N'{clientLogoutRedirectUriId}',N'{clientAppId}','true',N'urn:self:aspnet:identity:integrated')");
|
||||
//migrationBuilder.InsertData(
|
||||
// table: "AspNetRedirectUris",
|
||||
// columns: new[] { "Id", "ApplicationId", "IsLogout", "Value" },
|
||||
// values: new object[,]
|
||||
// {
|
||||
// { clientRedirectUriId, clientAppId, false, "urn:self:aspnet:identity:integrated"},
|
||||
// { clientLogoutRedirectUriId, clientAppId, true, "urn:self:aspnet:identity:integrated" }
|
||||
// });
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoleClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserLogins");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetApplicationClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRedirectUris");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetScopes");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetApplications");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUsers");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,351 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Identity.OpenIdConnect.WebSite.Identity.Data;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(IdentityServiceDbContext))]
|
||||
partial class IdentityServiceDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.0-preview1");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplication", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("ClientSecretHash");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClientId")
|
||||
.IsUnique()
|
||||
.HasName("ClientIdIndex");
|
||||
|
||||
b.HasIndex("Name")
|
||||
.IsUnique()
|
||||
.HasName("NameIndex");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetApplications");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplicationClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApplicationId");
|
||||
|
||||
b.ToTable("AspNetApplicationClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceRedirectUri<string>", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<bool>("IsLogout");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApplicationId");
|
||||
|
||||
b.ToTable("AspNetRedirectUris");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceScope<string>", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApplicationId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApplicationId");
|
||||
|
||||
b.ToTable("AspNetScopes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
|
||||
.WithMany("Claims")
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser")
|
||||
.WithMany("Claims")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser")
|
||||
.WithMany("Roles")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser")
|
||||
.WithMany("Tokens")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplication", b =>
|
||||
{
|
||||
b.HasOne("Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplicationClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplication")
|
||||
.WithMany("Claims")
|
||||
.HasForeignKey("ApplicationId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceRedirectUri<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplication")
|
||||
.WithMany("RedirectUris")
|
||||
.HasForeignKey("ApplicationId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.Service.IdentityServiceScope<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.Service.IdentityServiceApplication")
|
||||
.WithMany("Scopes")
|
||||
.HasForeignKey("ApplicationId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Certificates.Configuration;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Service.Extensions
|
||||
{
|
||||
public static class IdentityServiceExtensions
|
||||
{
|
||||
public static IIdentityServiceBuilder AddClientInfoBinding(this IIdentityServiceBuilder builder)
|
||||
{
|
||||
builder.Services.AddSingleton<IAuthorizationResponseParameterProvider, ClientInfoProvider>();
|
||||
builder.Services.AddSingleton<ITokenResponseParameterProvider, ClientInfoProvider>();
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IIdentityServiceBuilder AddApplications<TUser, TApplication>(this IdentityBuilder builder)
|
||||
where TUser : class
|
||||
where TApplication : class
|
||||
{
|
||||
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<IdentityServiceOptions>, DefaultSetup>());
|
||||
return builder.AddApplications<TUser, TApplication>(options =>
|
||||
{
|
||||
options.Issuer = "https://localhost/DFC7191F-FF74-42B9-A292-08FEA80F5B20/v2.0/";
|
||||
options.IdTokenOptions.ContextClaims.AddSingle("tfp", "policy");
|
||||
options.IdTokenOptions.ContextClaims.AddSingle("ver", "version");
|
||||
options.AccessTokenOptions.ContextClaims.AddSingle("tfp", "policy");
|
||||
options.AccessTokenOptions.ContextClaims.AddSingle("ver", "version");
|
||||
});
|
||||
}
|
||||
|
||||
private class DefaultSetup : ConfigureOptions<IdentityServiceOptions>
|
||||
{
|
||||
public DefaultSetup(IConfiguration configuration) : base(options => configuration.GetSection("Identity:Protocol").Bind(options))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class ClientInfoProvider : IAuthorizationResponseParameterProvider, ITokenResponseParameterProvider
|
||||
{
|
||||
public const string ClientInfo = "client_info";
|
||||
|
||||
private readonly IdentityOptions _options;
|
||||
|
||||
public int Order => 100;
|
||||
|
||||
public ClientInfoProvider(IOptions<IdentityOptions> options)
|
||||
{
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
public Task AddParameters(TokenGeneratingContext context, AuthorizationResponse response)
|
||||
{
|
||||
return AddParameters(context, response.Message);
|
||||
}
|
||||
|
||||
public Task AddParameters(TokenGeneratingContext context, OpenIdConnectMessage response)
|
||||
{
|
||||
var clientInfo = CreateClientInfo(context);
|
||||
response.Parameters.Add(ClientInfo, clientInfo);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string CreateClientInfo(TokenGeneratingContext context)
|
||||
{
|
||||
var userId = context.User.Claims.Single(c => string.Equals(c.Type, _options.ClaimsIdentity.UserIdClaimType, StringComparison.Ordinal)).Value;
|
||||
var tentantId = context.AmbientClaims.Single(c => string.Equals(c.Type, "tenantId", StringComparison.Ordinal)).Value;
|
||||
|
||||
var json = JsonConvert.SerializeObject(new ClientInfoModel { UserId = userId, TenantId = tentantId });
|
||||
return WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(json));
|
||||
}
|
||||
|
||||
private class ClientInfoModel
|
||||
{
|
||||
[JsonProperty(PropertyName = "uid")]
|
||||
public string UserId { get; set; }
|
||||
[JsonProperty(PropertyName = "utid")]
|
||||
public string TenantId { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.AccountViewModels
|
||||
{
|
||||
public class ExternalLoginConfirmationViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.AccountViewModels
|
||||
{
|
||||
public class ForgotPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.AccountViewModels
|
||||
{
|
||||
public class LoginViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[Display(Name = "Remember me?")]
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.AccountViewModels
|
||||
{
|
||||
public class RegisterViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at most {1} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm password")]
|
||||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.AccountViewModels
|
||||
{
|
||||
public class ResetPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at most {1} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm password")]
|
||||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
public string Code { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.AccountViewModels
|
||||
{
|
||||
public class SendCodeViewModel
|
||||
{
|
||||
public string SelectedProvider { get; set; }
|
||||
|
||||
public ICollection<SelectListItem> Providers { get; set; }
|
||||
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.AccountViewModels
|
||||
{
|
||||
public class VerifyCodeViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Provider { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Code { get; set; }
|
||||
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
[Display(Name = "Remember this browser?")]
|
||||
public bool RememberBrowser { get; set; }
|
||||
|
||||
[Display(Name = "Remember me?")]
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models
|
||||
{
|
||||
// Add profile data for application users by adding properties to the ApplicationUser class
|
||||
public class ApplicationUser : IdentityUser
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class ApplicationDetailsViewModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string ClientId { get; set; }
|
||||
public bool HasClientSecret { get; set; }
|
||||
public IEnumerable<string> RedirectUris { get; set; } = Enumerable.Empty<string>();
|
||||
public IEnumerable<string> LogoutUris { get; set; } = Enumerable.Empty<string>();
|
||||
public IEnumerable<string> Scopes { get; set; } = Enumerable.Empty<string>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class ChangeApplicationNameViewModel
|
||||
{
|
||||
public ChangeApplicationNameViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public ChangeApplicationNameViewModel(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class CreateApplicationViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class CreateLogoutUriViewModel
|
||||
{
|
||||
public CreateLogoutUriViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public CreateLogoutUriViewModel(string id, string applicationName, IEnumerable<string> logoutUris)
|
||||
{
|
||||
Id = id;
|
||||
Name = applicationName;
|
||||
LogoutUris = logoutUris;
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
public string Name { get; }
|
||||
public IEnumerable<string> LogoutUris { get; }
|
||||
public string NewLogoutUri { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class CreateRedirectUriViewModel
|
||||
{
|
||||
public CreateRedirectUriViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public CreateRedirectUriViewModel(string applicationName, IEnumerable<string> redirectUris)
|
||||
{
|
||||
Name = applicationName;
|
||||
RedirectUris = redirectUris;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public IEnumerable<string> RedirectUris { get; }
|
||||
public string NewRedirectUri { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class CreateScopeViewModel
|
||||
{
|
||||
public CreateScopeViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public CreateScopeViewModel(string applicationName, IEnumerable<string> scopes)
|
||||
{
|
||||
Name = applicationName;
|
||||
Scopes = scopes;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public IEnumerable<string> Scopes { get; }
|
||||
public string NewScope { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class EditLogoutUriViewModel
|
||||
{
|
||||
public EditLogoutUriViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public EditLogoutUriViewModel(string applicationName, string logoutUri)
|
||||
{
|
||||
Name = applicationName;
|
||||
LogoutUri = logoutUri;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string LogoutUri { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class EditRedirectUriViewModel
|
||||
{
|
||||
public EditRedirectUriViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public EditRedirectUriViewModel(string applicationName, string redirectUri)
|
||||
{
|
||||
Name = applicationName;
|
||||
RedirectUri = redirectUri;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string RedirectUri { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class EditScopeViewModel
|
||||
{
|
||||
public EditScopeViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public EditScopeViewModel(string applicationName, string scope)
|
||||
{
|
||||
Name = applicationName;
|
||||
Scope = scope;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string Scope { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class GeneratedClientSecretViewModel
|
||||
{
|
||||
public GeneratedClientSecretViewModel(string name, string clientSecret)
|
||||
{
|
||||
Name = name;
|
||||
ClientSecret = clientSecret;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string ClientSecret { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class RemoveApplicationViewModel
|
||||
{
|
||||
public RemoveApplicationViewModel(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class RemoveLogoutUriViewModel
|
||||
{
|
||||
public RemoveLogoutUriViewModel(string name, string logoutUri)
|
||||
{
|
||||
Name = name;
|
||||
LogoutUri = logoutUri;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string LogoutUri { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class RemoveRedirectUriViewModel
|
||||
{
|
||||
public RemoveRedirectUriViewModel(string name, string redirectUri)
|
||||
{
|
||||
Name = name;
|
||||
RedirectUri = redirectUri;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string RedirectUri { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
{
|
||||
public class RemoveScopeViewModel
|
||||
{
|
||||
public RemoveScopeViewModel(string name, string scope)
|
||||
{
|
||||
Name = name;
|
||||
Scope = scope;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string Scope { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ManageViewModels
|
||||
{
|
||||
public class AddPhoneNumberViewModel
|
||||
{
|
||||
[Required]
|
||||
[Phone]
|
||||
[Display(Name = "Phone number")]
|
||||
public string PhoneNumber { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ManageViewModels
|
||||
{
|
||||
public class ChangePasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Current password")]
|
||||
public string OldPassword { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at most {1} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "New password")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm new password")]
|
||||
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ManageViewModels
|
||||
{
|
||||
public class ConfigureTwoFactorViewModel
|
||||
{
|
||||
public string SelectedProvider { get; set; }
|
||||
|
||||
public IEnumerable<SelectListItem> Providers { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ManageViewModels
|
||||
{
|
||||
public class FactorViewModel
|
||||
{
|
||||
public string Purpose { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ManageViewModels
|
||||
{
|
||||
public class IndexViewModel
|
||||
{
|
||||
public bool HasPassword { get; set; }
|
||||
|
||||
public IList<UserLoginInfo> Logins { get; set; }
|
||||
|
||||
public string PhoneNumber { get; set; }
|
||||
|
||||
public bool TwoFactor { get; set; }
|
||||
|
||||
public bool BrowserRemembered { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ManageViewModels
|
||||
{
|
||||
public class ManageLoginsViewModel
|
||||
{
|
||||
public IList<UserLoginInfo> CurrentLogins { get; set; }
|
||||
|
||||
public IList<AuthenticationScheme> OtherLogins { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ManageViewModels
|
||||
{
|
||||
public class RemoveLoginViewModel
|
||||
{
|
||||
public string LoginProvider { get; set; }
|
||||
|
||||
public string ProviderKey { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ManageViewModels
|
||||
{
|
||||
public class SetPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at most {1} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "New password")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm new password")]
|
||||
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Models.ManageViewModels
|
||||
{
|
||||
public class VerifyPhoneNumberViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Code { get; set; }
|
||||
|
||||
[Required]
|
||||
[Phone]
|
||||
[Display(Name = "Phone number")]
|
||||
public string PhoneNumber { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Services
|
||||
{
|
||||
public interface IEmailSender
|
||||
{
|
||||
Task SendEmailAsync(string email, string subject, string message);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Services
|
||||
{
|
||||
public interface ISmsSender
|
||||
{
|
||||
Task SendSmsAsync(string number, string message);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.OpenIdConnect.WebSite.Identity.Services
|
||||
{
|
||||
// This class is used by the application to send Email and SMS
|
||||
// when you turn on two-factor authentication in ASP.NET Identity.
|
||||
// For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713
|
||||
public class AuthMessageSender : IEmailSender, ISmsSender
|
||||
{
|
||||
public Task SendEmailAsync(string email, string subject, string message)
|
||||
{
|
||||
// Plug in your email service here to send an email.
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SendSmsAsync(string number, string message)
|
||||
{
|
||||
// Plug in your SMS service here to send a text message.
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
@{
|
||||
ViewData["Title"] = "Access Denied";
|
||||
}
|
||||
|
||||
<header>
|
||||
<h1 class="text-danger">Access Denied.</h1>
|
||||
<p class="text-danger">You do not have access to this resource.</p>
|
||||
</header>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
@{
|
||||
ViewData["Title"] = "Confirm Email";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<div>
|
||||
<p>
|
||||
Thank you for confirming your email. Please <a asp-controller="Account" asp-action="Login">click here to log in</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
@model ExternalLoginConfirmationViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Register";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<h3>Associate your @ViewData["LoginProvider"] account.</h3>
|
||||
|
||||
<form asp-controller="Account" asp-action="ExternalLoginConfirmation" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
|
||||
<h4>Associate</h4>
|
||||
<hr />
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
|
||||
<p class="text-info">
|
||||
You've successfully authenticated with <strong>@ViewData["LoginProvider"]</strong>.
|
||||
Please enter an email address for this site below and click the Register button to finish
|
||||
logging in.
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<label asp-for="Email" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="Email" class="form-control" />
|
||||
<span asp-validation-for="Email" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<button type="submit" class="btn btn-default">Register</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
@{
|
||||
ViewData["Title"] = "Login Failure";
|
||||
}
|
||||
|
||||
<header>
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<p class="text-danger">Unsuccessful login with service.</p>
|
||||
</header>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
@model ForgotPasswordViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Forgot your password?";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
<p>
|
||||
For more information on how to enable reset password please see this <a href="https://go.microsoft.com/fwlink/?LinkID=532713">article</a>.
|
||||
</p>
|
||||
|
||||
@*<form asp-controller="Account" asp-action="ForgotPassword" method="post" class="form-horizontal">
|
||||
<h4>Enter your email.</h4>
|
||||
<hr />
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Email" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="Email" class="form-control" />
|
||||
<span asp-validation-for="Email" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<button type="submit" class="btn btn-default">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>*@
|
||||
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
@{
|
||||
ViewData["Title"] = "Forgot Password Confirmation";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<p>
|
||||
Please check your email to reset your password.
|
||||
</p>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
@{
|
||||
ViewData["Title"] = "Locked out";
|
||||
}
|
||||
|
||||
<header>
|
||||
<h1 class="text-danger">Locked out.</h1>
|
||||
<p class="text-danger">This account has been locked out, please try again later.</p>
|
||||
</header>
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
@using System.Collections.Generic
|
||||
@using System.Linq
|
||||
@using Microsoft.AspNetCore.Http
|
||||
@using Microsoft.AspNetCore.Authentication
|
||||
@using Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||
@model LoginViewModel
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Log in";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<section>
|
||||
<form asp-controller="Account" asp-action="Login" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
|
||||
<h4>Use a local account to log in.</h4>
|
||||
<hr />
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Email" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="Email" class="form-control" />
|
||||
<span asp-validation-for="Email" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Password" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="Password" class="form-control" />
|
||||
<span asp-validation-for="Password" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<div class="checkbox">
|
||||
<label asp-for="RememberMe">
|
||||
<input asp-for="RememberMe" />
|
||||
@Html.DisplayNameFor(m => m.RememberMe)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<button type="submit" class="btn btn-default">Log in</button>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<a asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]">Register as a new user?</a>
|
||||
</p>
|
||||
<p>
|
||||
<a asp-action="ForgotPassword">Forgot your password?</a>
|
||||
</p>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<section>
|
||||
<h4>Use another service to log in.</h4>
|
||||
<hr />
|
||||
@{
|
||||
var schemes = await SignInManager.GetExternalAuthenticationSchemesAsync();
|
||||
var loginProviders = schemes.Where(scheme => scheme.DisplayName != OpenIdConnectDefaults.AuthenticationScheme).ToList();
|
||||
if (loginProviders.Count == 0)
|
||||
{
|
||||
<div>
|
||||
<p>
|
||||
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
|
||||
for details on setting up this ASP.NET application to support logging in via external services.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form asp-controller="Account" asp-action="ExternalLogin" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
|
||||
<div>
|
||||
<p>
|
||||
@foreach (var provider in loginProviders)
|
||||
{
|
||||
<button type="submit" class="btn btn-default" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.Name</button>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
@model RegisterViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Register";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
|
||||
<form asp-controller="Account" asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
|
||||
<h4>Create a new account.</h4>
|
||||
<hr />
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Email" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="Email" class="form-control" />
|
||||
<span asp-validation-for="Email" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Password" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="Password" class="form-control" />
|
||||
<span asp-validation-for="Password" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="ConfirmPassword" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="ConfirmPassword" class="form-control" />
|
||||
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<button type="submit" class="btn btn-default">Register</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
@model ResetPasswordViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Reset password";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
|
||||
<form asp-controller="Account" asp-action="ResetPassword" method="post" class="form-horizontal">
|
||||
<h4>Reset your password.</h4>
|
||||
<hr />
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<input asp-for="Code" type="hidden" />
|
||||
<div class="form-group">
|
||||
<label asp-for="Email" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="Email" class="form-control" />
|
||||
<span asp-validation-for="Email" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Password" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="Password" class="form-control" />
|
||||
<span asp-validation-for="Password" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="ConfirmPassword" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="ConfirmPassword" class="form-control" />
|
||||
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<button type="submit" class="btn btn-default">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
@{
|
||||
ViewData["Title"] = "Reset password confirmation";
|
||||
}
|
||||
|
||||
<h1>@ViewData["Title"].</h1>
|
||||
<p>
|
||||
Your password has been reset. Please <a asp-controller="Account" asp-action="Login">click here to log in</a>.
|
||||
</p>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
@model SendCodeViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Send Verification Code";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
|
||||
<form asp-controller="Account" asp-action="SendCode" asp-route-returnurl="@Model.ReturnUrl" method="post" class="form-horizontal">
|
||||
<input asp-for="RememberMe" type="hidden" />
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
Select two-factor authentication provider:
|
||||
<select asp-for="SelectedProvider" asp-items="Model.Providers"></select>
|
||||
<button type="submit" class="btn btn-default">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
@model VerifyCodeViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Verify";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
|
||||
<form asp-controller="Account" asp-action="VerifyCode" asp-route-returnurl="@Model.ReturnUrl" method="post" class="form-horizontal">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<input asp-for="Provider" type="hidden" />
|
||||
<input asp-for="RememberMe" type="hidden" />
|
||||
<h4>@ViewData["Status"]</h4>
|
||||
<hr />
|
||||
<div class="form-group">
|
||||
<label asp-for="Code" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="Code" class="form-control" />
|
||||
<span asp-validation-for="Code" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<div class="checkbox">
|
||||
<input asp-for="RememberBrowser" />
|
||||
<label asp-for="RememberBrowser"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<button type="submit" class="btn btn-default">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model CreateLogoutUriViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Add a logout uri to your application";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<div>
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li><a asp-action="Details">@Model.Name</a></li>
|
||||
<li class="h4">Logout uris</li>
|
||||
|
||||
@foreach (var logoutUri in Model.LogoutUris)
|
||||
{
|
||||
<li>@logoutUri</li>
|
||||
}
|
||||
</ul>
|
||||
<hr />
|
||||
<form asp-action="AddLogoutUri" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="NewLogoutUri">New scope</label>
|
||||
<input asp-for="NewLogoutUri" class="form-control" placeholder="New scope">
|
||||
<span asp-validation-for="NewLogoutUri" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Add</button>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model CreateRedirectUriViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Add a redirect uri to your application";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<div>
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li><a asp-action="Details">@Model.Name</a></li>
|
||||
<li class="h4">Redirect uris</li>
|
||||
|
||||
@foreach (var redirectUri in Model.RedirectUris)
|
||||
{
|
||||
<li>@redirectUri</li>
|
||||
}
|
||||
</ul>
|
||||
<hr />
|
||||
<form asp-action="AddRedirectUri" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="NewRedirectUri">New scope</label>
|
||||
<input asp-for="NewRedirectUri" class="form-control" placeholder="New scope">
|
||||
<span asp-validation-for="NewRedirectUri" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Add</button>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model CreateScopeViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Add a scope to your application";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<hr />
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li><a asp-action="Details">@Model.Name</a></li>
|
||||
<li class="h4">Scopes</li>
|
||||
<li>
|
||||
<ul class="list-unstyled list-inline">
|
||||
@foreach (var scope in Model.Scopes)
|
||||
{
|
||||
<li>@scope</li>
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div>
|
||||
<hr />
|
||||
<form asp-action="AddScope" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="NewScope">New scope</label>
|
||||
<input asp-for="NewScope" class="form-control" placeholder="New scope">
|
||||
<span asp-validation-for="NewScope" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Add</button>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model ChangeApplicationNameViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Change name";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
<div>
|
||||
<hr />
|
||||
<form asp-action="ChangeName" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Name">Name</label>
|
||||
<input asp-for="Name" class="form-control" placeholder="Name">
|
||||
<span asp-validation-for="Name" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Update</button>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model CredentialsViewModel
|
||||
<div>
|
||||
<h4>Your application credentials</h4>
|
||||
<hr />
|
||||
<p>
|
||||
</p>
|
||||
<p>Client Id: <a asp-action="Details" asp-controller="Applications" asp-route-id="@Model.Id">@Model.ClientId</a></p>
|
||||
<p>Client secret: @Model.ClientSecret</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model CreateApplicationViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Create your application";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<div>
|
||||
<hr />
|
||||
<form asp-action="Create" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Name">Name</label>
|
||||
<input asp-for="Name" class="form-control" placeholder="Name">
|
||||
<span asp-validation-for="Name" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model CreateLogoutUriViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Add a logout uri to your application";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<div>
|
||||
<hr />
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li>@Model.Name</li>
|
||||
<li class="h4">Logout uris</li>
|
||||
<li>
|
||||
<ul class="list-unstyled">
|
||||
@foreach (var logoutUris in Model.LogoutUris)
|
||||
{
|
||||
<li>@logoutUris</li>
|
||||
}
|
||||
@if (Model.LogoutUris.Count() == 0)
|
||||
{
|
||||
<li>(none)</li>
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<form asp-action="CreateLogoutUri" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="NewLogoutUri">New logout uri</label>
|
||||
<input asp-for="NewLogoutUri" class="form-control large" placeholder="New logout uri">
|
||||
<span asp-validation-for="NewLogoutUri" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
<hr />
|
||||
<a asp-action="Details" class="btn btn-success">Continue to the application details</a>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model CreateRedirectUriViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Add a redirect uri to your application";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<div>
|
||||
<hr />
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li>@Model.Name</li>
|
||||
<li class="h4">Redirect uris</li>
|
||||
<li>
|
||||
<ul class="list-unstyled">
|
||||
@foreach (var redirectUris in Model.RedirectUris)
|
||||
{
|
||||
<li>@redirectUris</li>
|
||||
}
|
||||
@if (Model.RedirectUris.Count() == 0)
|
||||
{
|
||||
<li>(none)</li>
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<form asp-action="CreateRedirectUri" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="NewRedirectUri">New redirect uri</label>
|
||||
<input asp-for="NewRedirectUri" class="form-control large" placeholder="New redirect uri">
|
||||
<span asp-validation-for="NewRedirectUri" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
<hr />
|
||||
<a asp-action="CreateLogoutUri" class="btn btn-default">Continue to add logout uris</a>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model CreateScopeViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Add a scope to your application";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<div>
|
||||
<hr />
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li>@Model.Name</li>
|
||||
<li class="h4">Scopes</li>
|
||||
<li>
|
||||
<ul class="list-unstyled list-inline">
|
||||
@foreach (var scope in Model.Scopes)
|
||||
{
|
||||
<li>@scope</li>
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<form asp-action="CreateScope" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="NewScope">New scope</label>
|
||||
<input asp-for="NewScope" class="form-control" placeholder="New scope">
|
||||
<span asp-validation-for="NewScope" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
<hr />
|
||||
<a asp-action="CreateRedirectUri" class="btn btn-default">Continue to add redirect uris</a>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model ApplicationDetailsViewModel
|
||||
<div>
|
||||
<h4>View your application settings</h4>
|
||||
<hr />
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li><a asp-action="ChangeName">@Model.Name</a></li>
|
||||
<li class="h4">Application ID</li>
|
||||
<li>@Model.ClientId</li>
|
||||
<li class="h4">Keys</li>
|
||||
<li>
|
||||
@if (Model.HasClientSecret)
|
||||
{
|
||||
<a asp-action="RegenerateClientSecret" class="btn btn-default">Regenerate key</a>
|
||||
<a asp-action="RemoveClientSecret" class="btn btn-default">Remove key</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a asp-action="GenerateClientSecret" class="btn btn-default">Create key</a>
|
||||
}
|
||||
</li>
|
||||
<li class="h4">Scopes</li>
|
||||
<li>
|
||||
<ul class="list-inline">
|
||||
@foreach (var scope in @Model.Scopes)
|
||||
{
|
||||
<li><a asp-action="EditScope" asp-route-scope="@scope">@scope</a></li>
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
<li class="h4">Redirect uris</li>
|
||||
@foreach (var redirectUri in @Model.RedirectUris)
|
||||
{
|
||||
<li><a asp-action="EditRedirectUri" asp-route-redirectUri="@redirectUri">@redirectUri</a></li>
|
||||
}
|
||||
<li class="h4">Logout uris</li>
|
||||
@foreach (var logoutUri in @Model.LogoutUris)
|
||||
{
|
||||
<li><a asp-action="EditLogoutUri" asp-route-logoutUri="@logoutUri">@logoutUri</a></li>
|
||||
}
|
||||
</ul>
|
||||
<hr />
|
||||
<a asp-action="RemoveApplication" class="btn btn-danger">Delete application</a>
|
||||
<a asp-action="AddScope" class="btn btn-default">Add scope</a>
|
||||
<a asp-action="AddRedirectUri" class="btn btn-default">Add redirect uri</a>
|
||||
<a asp-action="AddLogoutUri" class="btn btn-default">Add logout uri</a>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model UpdateApplicationViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Edit application details";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<section>
|
||||
<form asp-controller="Applications" asp-action="ChangeName" method="post" class="form-horizontal">
|
||||
<h4>Edit your application details.</h4>
|
||||
<hr />
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<input type="hidden" asp-for="Id" class="form-control" />
|
||||
<div class="form-group">
|
||||
<label asp-for="Name" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="Name" class="form-control" />
|
||||
<span asp-validation-for="Name" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input class="btn btn-default" type="submit" value="Save" />
|
||||
</div>
|
||||
</form>
|
||||
<div class="form-group">
|
||||
<label asp-for="ClientId" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-8">
|
||||
<input asp-for="ClientId" class="form-control" disabled />
|
||||
</div>
|
||||
</div>
|
||||
@if (Model.HasClientSecret)
|
||||
{
|
||||
<form asp-controller="Applications" asp-action="RegenerateClientSecret" asp-route-id="@Model.Id">
|
||||
<div class="form-group">
|
||||
<label asp-for="HasClientSecret" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-8">
|
||||
<input type="password" value="........." class="form-control" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input type="submit" class="btn btn-default" value="Regenerate credentials" />
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form asp-controller="Applications" asp-action="GenerateClientSecret" asp-route-id="@Model.Id">
|
||||
<div class="col-md-2">
|
||||
<input type="submit" class="btn btn-default" value="Add client secret" />
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
@for (int i = 0; i < Model.Scopes.Count; i++)
|
||||
{
|
||||
<form asp-controller="Applications" asp-action="RemoveScope" asp-route-id="@Model.Id" method="post" class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-md-10">
|
||||
<input type="hidden" asp-for="@Model.RemoveScope[i].Index" />
|
||||
<input asp-for="@Model.RemoveScope[i].Scope" readonly />
|
||||
<span asp-validation-for="@Model.RemoveScope[i].Scope" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input class="btn btn-default" type="submit" value="Update" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
<form asp-controller="Applications" asp-action="AddScope" asp-route-id="@Model.Id" method="post" class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-md-10">
|
||||
<input asp-for="@Model.AddScope.NewScope" />
|
||||
<span asp-validation-for="@Model.AddScope.NewScope" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input class="btn btn-default" type="submit" value="Add" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@for (int i = 0; i < Model.RedirectUris.Count; i++)
|
||||
{
|
||||
<form asp-controller="Applications" asp-action="UpdateRegisteredUri" asp-route-id="@Model.Id" method="post" class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<input type="hidden" name="UpdateRegisteredUri[@i].Index" value="@Model.UpdateRegisteredUri[i].Index" />
|
||||
<input type="hidden" name="UpdateRegisteredUri[@i].RegisteredRedirectUri" value="@Model.UpdateRegisteredUri[i].RegisteredRedirectUri" />
|
||||
<div class="col-md-10">
|
||||
<input name="UpdateRegisteredUri[@i].UpdatedRedirectUri" class="form-control" value="@Model.UpdateRegisteredUri[i].RegisteredRedirectUri" />
|
||||
<span name="UpdateRegisteredUri[@i].UpdatedRedirectUri" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input class="btn btn-default" type="submit" value="Update" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<form asp-controller="Applications" asp-action="UnregisterRedirectUri" asp-route-id="@Model.Id" method="post" class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<input type="hidden" name="UnregisterRedirectUri[@i].Index" value="@Model.UnregisterRedirectUri[i].Index" />
|
||||
<input type="hidden" name="UnregisterRedirectUri[@i].RegisteredRedirectUri" value="@Model.UnregisterRedirectUri[i].RegisteredRedirectUri" />
|
||||
<input class="btn btn-default" type="submit" value="Unregister" />
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
<form asp-controller="Applications" asp-action="RegisterRedirecturi" asp-route-id="@Model.Id" method="post" class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-md-10">
|
||||
<input name="RegisterRedirectUri.NewRedirectUri" class="form-control" value="@Model.RegisterRedirectUri.NewRedirectUri" />
|
||||
<span name="RegisterRedirectUri.NewRedirectUri" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input class="btn btn-default" type="submit" value="Add" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model EditLogoutUriViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Edit logout uri";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
<hr />
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li><a asp-action="Details">@Model.Name</a></li>
|
||||
</ul>
|
||||
<div>
|
||||
<hr />
|
||||
<form asp-action="EditLogoutUri" asp-route-logoutUri="@Model.LogoutUri" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="LogoutUri">Logout uri</label>
|
||||
<input asp-for="LogoutUri" class="form-control large" placeholder="LogoutUri">
|
||||
<span asp-validation-for="LogoutUri" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Update</button>
|
||||
<a asp-action="RemoveLogoutUri" asp-route-logoutUri="@Model.LogoutUri" class="btn btn-danger">Remove</a>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model EditRedirectUriViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Edit redirect uri";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
<hr />
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li><a asp-action="Details">@Model.Name</a></li>
|
||||
</ul>
|
||||
<div>
|
||||
<hr />
|
||||
<form asp-action="EditRedirectUri" asp-route-redirectUri="@Model.RedirectUri" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="RedirectUri">Redirect uri</label>
|
||||
<input asp-for="RedirectUri" class="form-control large" placeholder="RedirectUri">
|
||||
<span asp-validation-for="RedirectUri" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Update</button>
|
||||
<a asp-action="RemoveRedirectUri" asp-route-redirectUri="@Model.RedirectUri" class="btn btn-danger">Remove</a>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model EditScopeViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Edit scope";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<hr />
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li><a asp-action="Details">@Model.Name</a></li>
|
||||
</ul>
|
||||
<div>
|
||||
<hr />
|
||||
<form asp-action="EditScope" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Scope">Scope</label>
|
||||
<input asp-for="Scope" class="form-control" placeholder="Scope">
|
||||
<span asp-validation-for="Scope" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Update</button>
|
||||
<a asp-action="RemoveScope" class="btn btn-danger">Remove</a>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model string
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Generate an application key";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<hr />
|
||||
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li>@Model</li>
|
||||
</ul>
|
||||
|
||||
<div>
|
||||
<hr />
|
||||
<form asp-action="GenerateClientSecret" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<button type="submit" class="btn btn-default">Confirm</button>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model GeneratedClientSecretViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Application key successfully generated";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<div>
|
||||
<hr />
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li><a asp-action="Details">@Model.Name</a></li>
|
||||
<li class="h4">Application key</li>
|
||||
<li>@Model.ClientSecret</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
@model IEnumerable<IdentityServiceApplication>
|
||||
@{
|
||||
ViewData["Title"] = "Manage your applications";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<p class="text-success">@ViewData["StatusMessage"]</p>
|
||||
|
||||
<div>
|
||||
<h4>Applications</h4>
|
||||
<hr />
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Client ID</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var application in Model)
|
||||
{
|
||||
<tr>
|
||||
<td><a asp-action="Details" asp-route-id="@application.Id">@application.Name</a> </td>
|
||||
<td>@application.ClientId</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
<a asp-action="Create" class="btn btn-default">Create new application</a>
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model string
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Regenerate an application key";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<hr />
|
||||
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li>@Model</li>
|
||||
</ul>
|
||||
|
||||
<div>
|
||||
<hr />
|
||||
<form asp-action="RegenerateClientSecret" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<button type="submit" class="btn btn-default">Confirm</button>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model RemoveApplicationViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Remove application";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
<div>
|
||||
<hr />
|
||||
<form asp-action="RemoveApplication" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<p>Are you sure you want to remove the application <strong>@Model.Name</strong>?</p>
|
||||
<button type="submit" class="btn btn-default">Confirm</button>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
@using Identity.OpenIdConnect.WebSite.Identity.Models.ApplicationViewModels
|
||||
@model string
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Remove the application key";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"].</h2>
|
||||
<hr />
|
||||
|
||||
<ul class="list-unstyled">
|
||||
<li class="h4">Name</li>
|
||||
<li>@Model</li>
|
||||
</ul>
|
||||
|
||||
<div>
|
||||
<hr />
|
||||
<form asp-action="RemoveClientSecret" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<button type="submit" class="btn btn-default">Confirm</button>
|
||||
</form>
|
||||
</div>
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue