mirror of
https://github.com/ditkrg/AuthorizationServerDemos.git
synced 2026-01-22 21:46:58 +00:00
We now support TOTP for logging in :D
This commit is contained in:
parent
516177f433
commit
f993d6f0d0
@ -8,6 +8,8 @@
|
||||
<PackageReference Include="IdentityServer4" Version="4.0.0" />
|
||||
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
|
||||
|
||||
<PackageReference Include="TwoStepsAuthenticator" Version="1.4.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ProjectExtensions><VisualStudio><UserProperties properties_4launchsettings_1json__JsonSchema="https://json.schemastore.org/local.settings" /></VisualStudio></ProjectExtensions>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
|
||||
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||
|
||||
|
||||
@ -14,8 +14,12 @@ using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OidcSamples.AuthorizationServer.Quickstart.Account;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IdentityServerHost.Quickstart.UI
|
||||
@ -109,8 +113,21 @@ namespace IdentityServerHost.Quickstart.UI
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
bool isValid = false;
|
||||
if (model.UseTotp)
|
||||
{
|
||||
var user = _users.FindByUsername(model.Username);
|
||||
var authenticator = new TwoStepsAuthenticator.TimeAuthenticator();
|
||||
string secret = Convert.ToBase64String(Encoding.ASCII.GetBytes(user.Password));
|
||||
isValid = authenticator.CheckCode(secret, model.Totp, user);
|
||||
}
|
||||
else
|
||||
{
|
||||
isValid = _users.ValidateCredentials(model.Username, model.Password);
|
||||
}
|
||||
|
||||
// validate username/password against in-memory store
|
||||
if (_users.ValidateCredentials(model.Username, model.Password))
|
||||
if (isValid)
|
||||
{
|
||||
var user = _users.FindByUsername(model.Username);
|
||||
await _events.RaiseAsync(new UserLoginSuccessEvent(user.Username, user.SubjectId, user.Username, clientId: context?.Client.ClientId));
|
||||
@ -164,7 +181,7 @@ namespace IdentityServerHost.Quickstart.UI
|
||||
}
|
||||
}
|
||||
|
||||
await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials", clientId:context?.Client.ClientId));
|
||||
await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials", clientId: context?.Client.ClientId));
|
||||
ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
|
||||
}
|
||||
|
||||
@ -173,7 +190,7 @@ namespace IdentityServerHost.Quickstart.UI
|
||||
return View(vm);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Show logout page
|
||||
/// </summary>
|
||||
@ -233,6 +250,30 @@ namespace IdentityServerHost.Quickstart.UI
|
||||
return View();
|
||||
}
|
||||
|
||||
private readonly char[] _chars =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult RegisterMobileDevice()
|
||||
{
|
||||
// NOTE: This is a dummy implemenatation and should NOT NEVER BE USED IN PROD!!!
|
||||
var subject = User.FindFirst(JwtClaimTypes.Subject)?.Value;
|
||||
var user = _users.FindBySubjectId(subject);
|
||||
|
||||
string secret = Convert.ToBase64String(Encoding.ASCII.GetBytes(user.Password));
|
||||
|
||||
var keyUri = string.Format(
|
||||
"otpauth://totp/{0}:{1}?secret={2}&issuer={0}",
|
||||
WebUtility.UrlEncode("KRG"),
|
||||
WebUtility.UrlEncode(user.SubjectId),
|
||||
secret);
|
||||
|
||||
return View(new TotpViewModel
|
||||
{
|
||||
Secret = secret,
|
||||
KeyUri = keyUri
|
||||
});
|
||||
}
|
||||
|
||||
/*****************************************/
|
||||
/* helper APIs for the AccountController */
|
||||
|
||||
@ -10,8 +10,10 @@ namespace IdentityServerHost.Quickstart.UI
|
||||
{
|
||||
[Required]
|
||||
public string Username { get; set; }
|
||||
[Required]
|
||||
public string Password { get; set; }
|
||||
public string Totp { get; set; }
|
||||
[Required]
|
||||
public bool UseTotp { get; set; }
|
||||
public bool RememberLogin { get; set; }
|
||||
public string ReturnUrl { get; set; }
|
||||
}
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
namespace OidcSamples.AuthorizationServer.Quickstart.Account
|
||||
{
|
||||
public class TotpViewModel
|
||||
{
|
||||
public string KeyUri { get; set; }
|
||||
public string Secret { get; set; }
|
||||
}
|
||||
}
|
||||
@ -29,7 +29,7 @@ namespace IdentityServerHost.Quickstart.UI
|
||||
new Claim(JwtClaimTypes.FamilyName, "Azeez"),
|
||||
new Claim(JwtClaimTypes.Email, "muhammad-azeez@outlook.com"),
|
||||
new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -67,6 +67,12 @@ namespace OidcSamples.AuthorizationServer
|
||||
MinimumSameSitePolicy = SameSiteMode.Lax
|
||||
});
|
||||
|
||||
app.Use(async (ctx, next) =>
|
||||
{
|
||||
ctx.Response.Headers.Add("Content-Security-Policy", new Microsoft.Extensions.Primitives.StringValues("default-src *; style-src 'self' http://* 'unsafe-inline'; script-src 'self' 'unsafe-inline' http://* 'unsafe-inline' 'unsafe-eval'"));
|
||||
await next();
|
||||
});
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
|
||||
|
||||
@ -26,21 +26,30 @@
|
||||
<label asp-for="Username"></label>
|
||||
<input class="form-control" placeholder="Username" asp-for="Username" autofocus>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="UseTotp">Use Your mobile phone for authentication?</label>
|
||||
<input asp-for="UseTotp" />
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="Password"></label>
|
||||
<input type="password" class="form-control" placeholder="Password" asp-for="Password" autocomplete="off">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Totp">TOTP</label>
|
||||
<input type="password" class="form-control" placeholder="Type in the one-time-password from your authenticator app" asp-for="Totp" autocomplete="off">
|
||||
</div>
|
||||
@if (Model.AllowRememberLogin)
|
||||
{
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" asp-for="RememberLogin">
|
||||
<label class="form-check-label" asp-for="RememberLogin">
|
||||
Remember My Login
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" asp-for="RememberLogin">
|
||||
<label class="form-check-label" asp-for="RememberLogin">
|
||||
Remember My Login
|
||||
</label>
|
||||
</div>
|
||||
</div>}
|
||||
<button class="btn btn-primary" name="button" value="login">Login</button>
|
||||
<button class="btn btn-secondary" name="button" value="cancel">Cancel</button>
|
||||
</form>
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
@model OidcSamples.AuthorizationServer.Quickstart.Account.TotpViewModel
|
||||
|
||||
<div>
|
||||
<div class="page-header">
|
||||
<h1>Register for MFA</h1>
|
||||
</div>
|
||||
|
||||
<partial name="_ValidationSummary" />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Scan the QR code with your authenticator application</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form asp-route="RegisterForMfa">
|
||||
<fieldset>
|
||||
<input type="hidden" asp-for="Secret" />
|
||||
<div class="form-group">
|
||||
<div id="qrCode"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button class="btn btn-primary">Registration successful</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script src="~/lib/qrcodejs/qrcode.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
new QRCode(document.getElementById("qrCode"),
|
||||
{
|
||||
text: "@Html.Raw(Model.KeyUri)",
|
||||
width: 150,
|
||||
height: 150
|
||||
});
|
||||
</script>
|
||||
}
|
||||
@ -1,15 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' http://* 'unsafe-inline'; script-src 'self' 'unsafe-inline' http://* 'unsafe-inline' 'unsafe-eval'" />
|
||||
|
||||
<title>IdentityServer4</title>
|
||||
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="~/favicon.ico" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="~/favicon.ico" />
|
||||
|
||||
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" />
|
||||
</head>
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">@name <b class="caret"></b></a>
|
||||
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" asp-action="RegisterMobileDevice" asp-controller="Account">RegisterMobileDevice</a>
|
||||
<a class="dropdown-item" asp-action="Logout" asp-controller="Account">Logout</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
1
CSharp/OidcSamples/OidcSamples.AuthorizationServer/wwwroot/lib/qrcodejs/qrcode.min.js
vendored
Normal file
1
CSharp/OidcSamples/OidcSamples.AuthorizationServer/wwwroot/lib/qrcodejs/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user