Skip to content

Commit

Permalink
feat: login page register and pwd links
Browse files Browse the repository at this point in the history
* feat: login page register and pwd links

#790 #792

* revert sample change

* remove code smell

* improve localization

Co-authored-by: github-actions <[email protected]>
  • Loading branch information
aguacongas and github-actions authored May 28, 2022
1 parent 610f659 commit d8c61df
Show file tree
Hide file tree
Showing 17 changed files with 460 additions and 5 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,4 @@ override.tf.json
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*
/sample/Aguacongas.TheIdServer.MtlsSample/client.pks
/sample/Aguacongas.TheIdServer.MtlsSample/.dccache
32 changes: 32 additions & 0 deletions src/Aguacongas.TheIdServer.Duende/Localization-fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -2042,5 +2042,37 @@
{
"key": "allowed identity token signing algorithms",
"value": "algorithmes de signature de jeton d'identité autorisés"
},
{
"key": "Reset password",
"value": "Réinitialiser le mot de passe"
},
{
"key": "Reset your password.",
"value": "Réinitialisez votre mot de passe."
},
{
"key": "Reset",
"value": "Réinitialiser"
},
{
"key": "Reset password confirmation",
"value": "Confirmation de la réinitialisation du mot de passe"
},
{
"key": "Your password has been reset.",
"value": "Votre mot de passe a été réinitialisé."
},
{
"key": "Please click here to log in",
"value": "Veuillez cliquer ici pour vous connecter"
},
{
"key": "Resend email confirmation",
"value": "Renvoyer la confirmation par e-mail"
},
{
"key": "Resend",
"value": "Renvoyer"
}
]
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"ConnectionStrings": {
"DefaultConnection": "server=localhost;database=theidserver-duende-debug;user=root;password=mysql"
},
"IdentityServer": {
"Key": {
"KeyRotationOptions": {
Expand All @@ -7,6 +10,7 @@
}
}
},
"DbType": "MySql",
"Serilog": {
"WriteTo": [
{
Expand Down
36 changes: 36 additions & 0 deletions src/Aguacongas.TheIdServer.IS4/Localization-fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1950,5 +1950,41 @@
{
"key": "You've successfully authenticated with <strong>{0}</strong>. Please enter an email address for this site below and click the Register button to finish logging in.",
"value": "Vous vous êtes bien authentifié avec <strong>{0}</strong>. Veuillez entrer une adresse e-mail pour ce site ci-dessous et cliquez sur le bouton S'inscrire pour terminer la connexion."
},
{
"key": "allowed identity token signing algorithms",
"value": "algorithmes de signature de jeton d'identité autorisés"
},
{
"key": "Reset password",
"value": "Réinitialiser le mot de passe"
},
{
"key": "Reset your password.",
"value": "Réinitialisez votre mot de passe."
},
{
"key": "Reset",
"value": "Réinitialiser"
},
{
"key": "Reset password confirmation",
"value": "Confirmation de la réinitialisation du mot de passe"
},
{
"key": "Your password has been reset.",
"value": "Votre mot de passe a été réinitialisé."
},
{
"key": "Please click here to log in",
"value": "Veuillez cliquer ici pour vous connecter"
},
{
"key": "Resend email confirmation",
"value": "Renvoyer la confirmation par e-mail"
},
{
"key": "Resend",
"value": "Renvoyer"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
using System.Threading.Tasks;
using System;
using Microsoft.Extensions.Logging;
using System.Security.Cryptography;

namespace Microsoft.AspNetCore.Builder
{
Expand Down Expand Up @@ -78,7 +79,14 @@ public static IApplicationBuilder UseTheIdServer(this IApplicationBuilder app, I
if (headers.TryGetValue(certificateHeader, out StringValues values))
{
logger.LogInformation("Get certificate from header {ClientCertificateHeader}", certificateHeader);
context.Connection.ClientCertificate = X509Certificate2.CreateFromPem(Uri.UnescapeDataString(values.First()));
try
{
context.Connection.ClientCertificate = X509Certificate2.CreateFromPem(Uri.UnescapeDataString(values.First()));
}
catch(CryptographicException e)
{
logger.LogWarning("Failed to get certificate fron header {ClientCertificateHeader}. Error: {Error}", certificateHeader, e.Message);
}
}
await next();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ public IActionResult AccessDenied()
private async Task<LoginViewModel> BuildLoginViewModelAsync(string returnUrl)
{
var context = await _interaction.GetAuthorizationContextAsync(returnUrl).ConfigureAwait(false);

if (context?.IdP != null && await _schemeProvider.GetSchemeAsync(context.IdP).ConfigureAwait(false) != null)
{
var local = context.IdP == IdentityServerConstants.LocalIdentityProvider;
Expand Down Expand Up @@ -304,7 +305,10 @@ private async Task<LoginViewModel> BuildLoginViewModelAsync(string returnUrl)
EnableLocalLogin = allowLocal && settings.AllowLocalLogin,
ReturnUrl = returnUrl,
Username = context?.LoginHint,
ExternalProviders = providers.ToArray()
ExternalProviders = providers.ToArray(),
ShowForgotPassworLink = settings.ShowForgotPassworLink,
ShowRegisterLink = settings.ShowRegisterLink,
ShowResendEmailConfirmationLink = settings.ShowResendEmailConfirmationLink
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,12 @@ public class AccountOptions
public bool IncludeWindowsGroups { get; set; } = false;

public string InvalidCredentialsErrorMessage { get; set; } = "Invalid username or password";

public bool ShowForgotPassworLink { get; set; } = true;

public bool ShowRegisterLink { get; set; } = true;

public bool ShowResendEmailConfirmationLink { get; set; } = true;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,11 @@ public class LoginViewModel : LoginInputModel

public bool IsExternalLoginOnly => !EnableLocalLogin && ExternalProviders?.Count() == 1;
public string ExternalLoginScheme => IsExternalLoginOnly ? ExternalProviders?.SingleOrDefault()?.AuthenticationScheme : null;

public bool ShowForgotPassworLink { get; set; } = true;

public bool ShowRegisterLink { get; set; } = true;

public bool ShowResendEmailConfirmationLink { get; set; } = true;
}
}
24 changes: 22 additions & 2 deletions src/Aguacongas.TheIdServer.Shared/Views/Account/Login.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,36 @@
<button class="w-100 btn btn-lg btn-primary mb-2" name="button" value="login">
@Localizer["Login"]
</button>
<button class="w-100 btn btn-lg btn btn-secondary mb-2" name="button" value="cancel">@Localizer["Cancel"]</button>
<button class="w-100 btn btn-lg btn btn-secondary mb-3" name="button" value="cancel">@Localizer["Cancel"]</button>
@if (Model.AllowRememberLogin)
{
<div class="login-remember">
<div class="login-remember mb-3">
<label asp-for="RememberLogin">
<input asp-for="RememberLogin">
<strong>@Localizer["Remember My Login"]</strong>
</label>
</div>
}
<div>
@if (Model.ShowForgotPassworLink)
{
<p>
<a asp-area="Identity" asp-page="/Account/ForgotPassword" asp-route-returnUrl="@Model.ReturnUrl">Forgot your password?</a>
</p>
}
@if (Model.ShowRegisterLink)
{
<p>
<a asp-area="Identity" asp-page="/Account/Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
</p>
}
@if (Model.ShowResendEmailConfirmationLink)
{
<p>
<a asp-area="Identity" asp-page="/Account/ResendEmailConfirmation">Resend email confirmation</a>
</p>
}
</div>
</div>
</div>
</fieldset>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Copyright (c) 2022 @Olivier Lefebvre
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<input asp-for="Input.ReturnUrl" type="hidden" />
<div class="form-floating mb-2">
<input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" />
<label asp-for="Input.Email" class="form-label"></label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ public class InputModel
[Required]
[EmailAddress]
public string Email { get; set; }
public string ReturnUrl { get; set; }
}

public void OnGet(string returnUrl = null)
{
Input = new InputModel
{
ReturnUrl = returnUrl
};
}

public async Task<IActionResult> OnPostAsync()
Expand All @@ -59,7 +68,7 @@ public async Task<IActionResult> OnPostAsync()
var callbackUrl = Url.Page(
"/Account/ResetPassword",
pageHandler: null,
values: new { area = "Identity", code },
values: new { area = "Identity", code, returnUrl = Input.ReturnUrl },
protocol: Request.Scheme);

await _emailSender.SendEmailAsync(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@page
@inject IViewLocalizer Localizer
@model ResendEmailConfirmationModel
@{
ViewData["Title"] = Localizer["Resend email confirmation"];
}

<h1>@ViewData["Title"]</h1>
<h2>@Localizer["Enter your email."]</h2>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-floating mb-2">
<input asp-for="Input.Email" class="form-control" aria-required="true" />
<label asp-for="Input.Email" class="form-label"></label>
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<button type="submit" class="w-100 btn btn-lg btn-primary">@Localizer["Resend"]</button>
</form>
</div>
</div>

@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable

using Aguacongas.TheIdServer.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Localization;
using System.ComponentModel.DataAnnotations;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;

namespace Aguacongas.TheIdServer.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class ResendEmailConfirmationModel : PageModel
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly IEmailSender _emailSender;
private readonly IStringLocalizer _localizer;

public ResendEmailConfirmationModel(UserManager<ApplicationUser> userManager, IEmailSender emailSender, IStringLocalizer<ResendEmailConfirmationModel> localizer)
{
_userManager = userManager;
_emailSender = emailSender;
_localizer = localizer;
}

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[BindProperty]
public InputModel Input { get; set; }

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public class InputModel
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[EmailAddress]
public string Email { get; set; }
}

public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}

var user = await _userManager.FindByEmailAsync(Input.Email);
if (user == null)
{
ModelState.AddModelError(string.Empty, _localizer["Verification email sent. Please check your email."]);
return Page();
}

var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = userId, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(
Input.Email,
_localizer["Confirm your email"],
_localizer[$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."]);

ModelState.AddModelError(string.Empty, _localizer["Verification email sent. Please check your email."]);
return Page();
}
}
}
Loading

0 comments on commit d8c61df

Please sign in to comment.