Skip to content

Commit

Permalink
Merge pull request #36 from georgimanov/master
Browse files Browse the repository at this point in the history
GDPR compliance implementation
  • Loading branch information
NikolayIT committed Oct 7, 2018
2 parents d249a5e + a9c8cac commit 6952aef
Show file tree
Hide file tree
Showing 107 changed files with 2,954 additions and 1,405 deletions.
Expand Up @@ -13,6 +13,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="2.1.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta009" PrivateAssets="all">
Expand Down

This file was deleted.

Expand Up @@ -2,6 +2,8 @@
{
using System.Threading.Tasks;

using Microsoft.AspNetCore.Identity.UI.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
Expand Down
Expand Up @@ -8,6 +8,7 @@

using AspNetCoreTemplate.Services.Messaging.SendGrid;

using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Logging;

using Newtonsoft.Json;
Expand Down
@@ -0,0 +1,10 @@
@page
@model AccessDeniedModel
@{
ViewData["Title"] = "Access denied";
}

<header>
<h1 class="text-danger">@ViewData["Title"]</h1>
<p class="text-danger">You do not have access to this resource.</p>
</header>
@@ -0,0 +1,13 @@
namespace AspNetCoreTemplate.Web.Areas.Identity.Pages.Account
{
using Microsoft.AspNetCore.Mvc.RazorPages;

#pragma warning disable SA1649 // File name should match first type name
public class AccessDeniedModel : PageModel
#pragma warning restore SA1649 // File name should match first type name
{
public void OnGet()
{
}
}
}
@@ -0,0 +1,12 @@
@page
@model ConfirmEmailModel
@{
ViewData["Title"] = "Confirm email";
}

<h2>@ViewData["Title"]</h2>
<div>
<p>
Thank you for confirming your email.
</p>
</div>
@@ -0,0 +1,47 @@
namespace AspNetCoreTemplate.Web.Areas.Identity.Pages.Account
{
using System;
using System.Threading.Tasks;

using AspNetCoreTemplate.Data.Models;

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

[AllowAnonymous]
#pragma warning disable SA1649 // File name should match first type name
public class ConfirmEmailModel : PageModel
#pragma warning restore SA1649 // File name should match first type name
{
private readonly UserManager<ApplicationUser> userManager;

public ConfirmEmailModel(UserManager<ApplicationUser> userManager)
{
this.userManager = userManager;
}

public async Task<IActionResult> OnGetAsync(string userId, string code)
{
if (userId == null || code == null)
{
return this.RedirectToPage("/Index");
}

var user = await this.userManager.FindByIdAsync(userId);
if (user == null)
{
return this.NotFound($"Unable to load user with ID '{userId}'.");
}

var result = await this.userManager.ConfirmEmailAsync(user, code);
if (!result.Succeeded)
{
throw new InvalidOperationException($"Error confirming email for user with ID '{userId}':");
}

return this.Page();
}
}
}
@@ -0,0 +1,34 @@
@page
@model ExternalLoginModel
@{
ViewData["Title"] = "Register";
}

<h2>@ViewData["Title"]</h2>
<h4>Associate your @Model.LoginProvider account.</h4>
<hr />

<p class="text-info">
You've successfully authenticated with <strong>@Model.LoginProvider</strong>.
Please enter an email address for this site below and click the Register button to finish
logging in.
</p>

<div class="row">
<div class="col-md-4">
<form asp-page-handler="Confirmation" asp-route-returnUrl="@Model.ReturnUrl" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-default">Register</button>
</form>
</div>
</div>

@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

@@ -0,0 +1,139 @@
namespace AspNetCoreTemplate.Web.Areas.Identity.Pages.Account
{
using System.Security.Claims;
using System.Threading.Tasks;

using AspNetCoreTemplate.Data.Models;

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

[AllowAnonymous]
#pragma warning disable SA1649 // File name should match first type name
public class ExternalLoginModel : PageModel
#pragma warning restore SA1649 // File name should match first type name
{
private readonly SignInManager<ApplicationUser> signInManager;
private readonly UserManager<ApplicationUser> userManager;
private readonly ILogger<ExternalLoginModel> logger;

public ExternalLoginModel(
SignInManager<ApplicationUser> signInManager,
UserManager<ApplicationUser> userManager,
ILogger<ExternalLoginModel> logger)
{
this.signInManager = signInManager;
this.userManager = userManager;
this.logger = logger;
}

[BindProperty]
public ErrorLoginInputModel Input { get; set; }

public string LoginProvider { get; set; }

public string ReturnUrl { get; set; }

[TempData]
public string ErrorMessage { get; set; }

public IActionResult OnGetAsync()
{
return this.RedirectToPage("./Login");
}

public IActionResult OnPost(string provider, string returnUrl = null)
{
// Request a redirect to the external login provider.
var redirectUrl = this.Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl });
var properties = this.signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return new ChallengeResult(provider, properties);
}

public async Task<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
{
returnUrl = returnUrl ?? this.Url.Content("~/");
if (remoteError != null)
{
this.ErrorMessage = $"Error from external provider: {remoteError}";
return this.RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}

var info = await this.signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
this.ErrorMessage = "Error loading external login information.";
return this.RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}

// Sign in the user with this external login provider if the user already has a login.
var result = await this.signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
if (result.Succeeded)
{
this.logger.LogInformation("{Name} logged in with {LoginProvider} provider.", info.Principal.Identity.Name, info.LoginProvider);
return this.LocalRedirect(returnUrl);
}

if (result.IsLockedOut)
{
return this.RedirectToPage("./Lockout");
}
else
{
// If the user does not have an account, then ask the user to create an account.
this.ReturnUrl = returnUrl;
this.LoginProvider = info.LoginProvider;
if (info.Principal.HasClaim(c => c.Type == ClaimTypes.Email))
{
this.Input = new ErrorLoginInputModel
{
Email = info.Principal.FindFirstValue(ClaimTypes.Email)
};
}

return this.Page();
}
}

public async Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? this.Url.Content("~/");

// Get the information about the user from the external login provider
var info = await this.signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
this.ErrorMessage = "Error loading external login information during confirmation.";
return this.RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}

if (this.ModelState.IsValid)
{
var user = new ApplicationUser { UserName = this.Input.Email, Email = this.Input.Email };
var result = await this.userManager.CreateAsync(user);
if (result.Succeeded)
{
result = await this.userManager.AddLoginAsync(user, info);
if (result.Succeeded)
{
await this.signInManager.SignInAsync(user, isPersistent: false);
this.logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider);
return this.LocalRedirect(returnUrl);
}
}

foreach (var error in result.Errors)
{
this.ModelState.AddModelError(string.Empty, error.Description);
}
}

this.LoginProvider = info.LoginProvider;
this.ReturnUrl = returnUrl;
return this.Page();
}
}
}
@@ -0,0 +1,26 @@
@page
@model ForgotPasswordModel
@{
ViewData["Title"] = "Forgot your password?";
}

<h2>@ViewData["Title"]</h2>
<h4>Enter your email.</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>

@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,63 @@
namespace AspNetCoreTemplate.Web.Areas.Identity.Pages.Account
{
using System.Text.Encodings.Web;
using System.Threading.Tasks;

using AspNetCoreTemplate.Data.Models;
using AspNetCoreTemplate.Web.Areas.Identity.Pages.Account.InputModels;

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

[AllowAnonymous]
#pragma warning disable SA1649 // File name should match first type name
public class ForgotPasswordModel : PageModel
#pragma warning restore SA1649 // File name should match first type name
{
private readonly UserManager<ApplicationUser> userManager;
private readonly IEmailSender emailSender;

public ForgotPasswordModel(UserManager<ApplicationUser> userManager, IEmailSender emailSender)
{
this.userManager = userManager;
this.emailSender = emailSender;
}

[BindProperty]
public ForgotPasswordInputModel Input { get; set; }

public async Task<IActionResult> OnPostAsync()
{
if (this.ModelState.IsValid)
{
var user = await this.userManager.FindByEmailAsync(this.Input.Email);
if (user == null || !(await this.userManager.IsEmailConfirmedAsync(user)))
{
// Don't reveal that the user does not exist or is not confirmed
return this.RedirectToPage("./ForgotPasswordConfirmation");
}

// For more information on how to enable account confirmation and password reset please
// visit https://go.microsoft.com/fwlink/?LinkID=532713
var code = await this.userManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = this.Url.Page(
"/Account/ResetPassword",
pageHandler: null,
values: new { code },
protocol: this.Request.Scheme);

await this.emailSender.SendEmailAsync(
this.Input.Email,
"Reset Password",
$"Please reset your password by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

return this.RedirectToPage("./ForgotPasswordConfirmation");
}

return this.Page();
}
}
}
@@ -0,0 +1,11 @@
@page
@model ForgotPasswordConfirmation
@{
ViewData["Title"] = "Forgot password confirmation";
}

<h2>@ViewData["Title"]</h2>
<p>
Please check your email to reset your password.
</p>

0 comments on commit 6952aef

Please sign in to comment.