1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 15:42:48 -05:00

passwordless sign in for admin

This commit is contained in:
Kyle Spearrin
2018-03-21 14:26:49 -04:00
parent 1be7701da0
commit d35d8185ed
16 changed files with 333 additions and 77 deletions

View File

@ -27,4 +27,10 @@
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.0" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.json">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
</Project>

View File

@ -0,0 +1,7 @@
namespace Bit.Admin
{
public class AdminSettings
{
public virtual string Admins { get; set; }
}
}

View File

@ -1,13 +1,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Bit.Admin.Models;
using Microsoft.AspNetCore.Authorization;
namespace Bit.Admin.Controllers
{
public class HomeController : Controller
{
[Authorize]
public IActionResult Index()
{
return View();

View File

@ -0,0 +1,48 @@
using System.Threading.Tasks;
using Bit.Admin.Models;
using Bit.Core.Identity;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
namespace Bit.Admin.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)
{
if(ModelState.IsValid)
{
await _signInManager.PasswordlessSignInAsync(model.Email);
return RedirectToAction("Index", "Home");
}
return View(model);
}
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.Admin.Models
{
public class LoginModel
{
[Required]
[EmailAddress]
public string Email { get; set; }
}
}

View File

@ -1,9 +1,17 @@
using System;
using Bit.Core;
using Bit.Core.Identity;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Serilog.Events;
using Stripe;
namespace Bit.Admin
{
@ -18,22 +26,52 @@ namespace Bit.Admin
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Options
services.AddOptions();
// Settings
var globalSettings = services.AddGlobalSettingsServices(Configuration);
services.Configure<AdminSettings>(Configuration.GetSection("AdminSettings"));
// Stripe Billing
StripeConfiguration.SetApiKey(globalSettings.StripeApiKey);
// Repositories
services.AddSqlServerRepositories(globalSettings);
// Context
services.AddScoped<CurrentContext>();
// Identity
services.AddPasswordlessIdentityServices<ReadOnlyEnvIdentityUserStore>(globalSettings);
// Services
services.AddBaseServices();
services.AddDefaultServices(globalSettings);
// Mvc
services.AddMvc(config =>
{
config.Filters.Add(new LoggingExceptionHandlerFilterAttribute());
});
services.Configure<RouteOptions>(options => options.LowercaseUrls = true);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
IApplicationLifetime appLifetime,
GlobalSettings globalSettings,
ILoggerFactory loggerFactory)
{
loggerFactory.AddSerilog(env, appLifetime, globalSettings, (e) => e.Level >= LogEventLevel.Error);
if(env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/home/error");
}
app.UseAuthentication();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}

View File

@ -0,0 +1,21 @@
@model LoginModel
@{
ViewData["Title"] = "Login";
}
<div class="row justify-content-md-center">
<div class="col-4">
<p>Please enter your email address below to log in.</p>
<form asp-action="" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Email" class="sr-only">Email Address</label>
<input asp-for="Email" type="email" class="form-control" placeholder="ex. john@example.com"
required autofocus>
<span asp-validation-for="Email" class="invalid-feedback"></span>
<small class="form-text text-muted">We'll email you a secure login link.</small>
</div>
<button class="btn btn-primary btn-block" type="submit">Continue</button>
</form>
</div>
</div>

View File

@ -1,10 +0,0 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

View File

@ -0,0 +1,13 @@
{
"globalSettings": {
"baseServiceUri": {
"vault": "https://vault.bitwarden.com",
"api": "https://api.bitwarden.com",
"identity": "https://identity.bitwarden.com",
"internalIdentity": "https://identity.bitwarden.com"
},
"braintree": {
"production": true
}
}
}

View File

@ -1,8 +1,50 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
"globalSettings": {
"selfHosted": false,
"siteName": "Bitwarden",
"projectName": "Admin",
"stripeApiKey": "SECRET",
"baseServiceUri": {
"vault": "http://localhost:4001",
"api": "http://localhost:4000",
"identity": "http://localhost:33656",
"internalIdentity": "http://localhost:33656"
},
"sqlServer": {
"connectionString": "SECRET"
},
"mail": {
"sendGridApiKey": "SECRET",
"replyToEmail": "hello@bitwarden.com"
},
"identityServer": {
"certificateThumbprint": "SECRET"
},
"dataProtection": {
"certificateThumbprint": "SECRET"
},
"storage": {
"connectionString": "SECRET"
},
"events": {
"connectionString": "SECRET"
},
"documentDb": {
"uri": "SECRET",
"key": "SECRET"
},
"notificationHub": {
"connectionString": "SECRET",
"hubName": "SECRET"
}
},
"adminSettings": {
"admins": ""
},
"braintree": {
"production": false,
"merchantId": "SECRET",
"publicKey": "SECRET",
"privateKey": "SECRET"
}
}