1
0
mirror of https://github.com/bitwarden/server synced 2026-01-05 10:03:23 +00:00

passwordless signin for billing portal

This commit is contained in:
Kyle Spearrin
2018-03-20 15:00:56 -04:00
parent 9ed1ae9567
commit 3d9d193bda
16 changed files with 486 additions and 7 deletions

View File

@@ -5,8 +5,6 @@
<TargetFramework>netcoreapp2.0</TargetFramework>
<RootNamespace>Bit.Billing</RootNamespace>
<UserSecretsId>bitwarden-Billing</UserSecretsId>
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
</PropertyGroup>
<ItemGroup>
@@ -15,6 +13,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.0.2" />
</ItemGroup>
<ItemGroup>
@@ -22,4 +21,9 @@
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\images\" />
<Folder Include="wwwroot\scripts\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,15 @@
using System;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Billing.Controllers
{
public class HomeController : Controller
{
[Authorize]
public IActionResult Index()
{
return View();
}
}
}

View File

@@ -0,0 +1,48 @@
using System.Threading.Tasks;
using Bit.Billing.Models;
using Bit.Core.Identity;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
namespace Billing.Controllers
{
public class LoginController : Controller
{
private readonly PasswordlessSignInManager<IdentityUser> _signInManager;
public LoginController(
PasswordlessSignInManager<IdentityUser> signInManager)
{
_signInManager = signInManager;
}
public IActionResult Index()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Index(LoginModel model)
{
var result = await _signInManager.PasswordlessSignInAsync(model.Email);
if(!result.Succeeded)
{
return View("Error");
}
return RedirectToAction("Index", "Home");
}
public async Task<IActionResult> Confirm(string email, string token)
{
var result = await _signInManager.PasswordlessSignInAsync(email, token, false);
if(!result.Succeeded)
{
return View("Error");
}
return RedirectToAction("Index", "Home");
}
}
}

View File

@@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Billing.Models
{
public class LoginModel
{
[Required]
[EmailAddress]
public string Email { get; set; }
}
}

View File

@@ -11,6 +11,10 @@ using Serilog.Events;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Bit.Billing.Utilities;
using Bit.Core.Identity;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Routing;
namespace Bit.Billing
{
@@ -42,7 +46,28 @@ namespace Bit.Billing
services.AddScoped<CurrentContext>();
// Identity
services.AddCustomIdentityServices(globalSettings);
services.AddTransient<ILookupNormalizer, LowerInvariantLookupNormalizer>();
services.AddIdentity<IdentityUser, Core.Models.Table.Role>()
.AddUserStore<ReadOnlyIdentityUserStore>()
.AddRoleStore<RoleStore>()
.AddDefaultTokenProviders();
services.TryAddScoped<PasswordlessSignInManager<IdentityUser>, PasswordlessSignInManager<IdentityUser>>();
services.Configure<DataProtectionTokenProviderOptions>(options =>
{
options.TokenLifespan = TimeSpan.FromMinutes(15);
});
services.ConfigureApplicationCookie(options =>
{
options.LoginPath = "/login";
options.LogoutPath = "/";
options.AccessDeniedPath = "/login";
options.Cookie.Name = "BitwardenBilling";
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
options.ReturnUrlParameter = "returnUrl";
options.SlidingExpiration = true;
});
// Services
services.AddBaseServices();
@@ -55,6 +80,7 @@ namespace Bit.Billing
{
config.Filters.Add(new ExceptionHandlerFilterAttribute());
});
services.Configure<RouteOptions>(options => options.LowercaseUrls = true);
}
public void Configure(
@@ -71,10 +97,9 @@ namespace Bit.Billing
app.UseDeveloperExceptionPage();
}
// Default Middleware
app.UseDefaultMiddleware(env);
app.UseMvc();
app.UseAuthentication();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
}
}

View File

@@ -0,0 +1,6 @@
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>

View File

@@ -0,0 +1,21 @@
@{
ViewData["Title"] = "Login";
}
@model LoginModel
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<h1 class="text-center">Login</h1>
<form asp-action="" method="post" class="form-horizontal">
<div class="form-group">
<label asp-for="Email" class="col-sm-3">Email Address: </label>
<div class="col-sm-9">
<input asp-for="Email" class="form-control" />
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
<div asp-validation-summary="All"></div>
</form>
</div>
</div>

View File

@@ -0,0 +1,15 @@
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
</p>

View File

@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] | Bitwarden Billing Portal</title>
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="~/styles/site.css">
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">Bitwarden Billing</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-area="" asp-controller="Login" asp-action="Index">Login</a></li>
</ul>
</div>
</div>
</nav>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>&copy; 2018 - 8bit Solutions LLC</p>
</footer>
</div>
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"></script>
</body>
</html>

View File

@@ -0,0 +1,3 @@
@using Bit.Billing
@using Bit.Billing.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

View File

@@ -0,0 +1,35 @@
body {
padding-top: 50px;
padding-bottom: 20px;
}
/* Wrapping element */
/* Set some basic padding to keep content from hitting the edges */
.body-content {
padding-left: 15px;
padding-right: 15px;
}
/* Carousel */
.carousel-caption p {
font-size: 20px;
line-height: 1.4;
}
/* Make .svg files in the carousel display properly in older browsers */
.carousel-inner .item img[src$=".svg"] {
width: 100%;
}
/* QR code generator */
#qrCode {
margin: 15px;
}
/* Hide/rearrange for smaller screens */
@media screen and (max-width: 767px) {
/* Hide captions */
.carousel-caption {
display: none;
}
}