From 79f507fe688e3f319bd63907eb55b640f5c7e064 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Thu, 19 May 2016 19:10:24 -0400 Subject: [PATCH] Upgrade to ASP.NET Core RC2 release. --- global.json | 2 +- src/Api/Api.xproj | 9 +-- src/Api/Controllers/AccountsController.cs | 14 ++-- src/Api/Controllers/AliveController.cs | 2 +- src/Api/Controllers/AuthController.cs | 4 +- src/Api/Controllers/FoldersController.cs | 21 +++--- src/Api/Controllers/SitesController.cs | 23 ++++--- src/Api/Models/Response/ErrorResponseModel.cs | 2 +- src/Api/Program.cs | 20 ++++++ src/Api/Properties/launchSettings.json | 46 +++++++------ src/Api/Startup.cs | 45 ++++++------- .../ExceptionHandlerFilterAttribute.cs | 10 +-- .../ModelStateValidationFilterAttribute.cs | 4 +- src/Api/project.json | 67 ++++++++++++------- src/Api/settings.json | 1 + src/Api/web.config | 9 +++ src/Api/wwwroot/web.config | 9 --- src/Core/Core.xproj | 9 +-- src/Core/Exceptions/BadRequestException.cs | 2 +- src/Core/GlobalSettings.cs | 1 + .../Identity/AuthenticatorTokenProvider.cs | 4 +- .../Identity/JwtBearerAppBuilderExtensions.cs | 60 +++++++++++++++++ .../Identity/JwtBearerBuilderExtensions.cs | 59 ---------------- .../Identity/JwtBearerEventImplementations.cs | 21 +++--- src/Core/Identity/JwtBearerIdentityOptions.cs | 2 +- ...arerIdentityServiceCollectionExtensions.cs | 8 ++- src/Core/Identity/JwtBearerSignInManager.cs | 25 ++++--- .../LowerInvariantLookupNormalizer.cs | 2 +- src/Core/Identity/RoleStore.cs | 2 +- src/Core/Identity/UserStore.cs | 2 +- src/Core/Services/IUserService.cs | 2 +- src/Core/Services/UserService.cs | 13 ++-- src/Core/project.json | 20 +++--- 33 files changed, 289 insertions(+), 231 deletions(-) create mode 100644 src/Api/Program.cs create mode 100644 src/Api/web.config delete mode 100644 src/Api/wwwroot/web.config create mode 100644 src/Core/Identity/JwtBearerAppBuilderExtensions.cs delete mode 100644 src/Core/Identity/JwtBearerBuilderExtensions.cs diff --git a/global.json b/global.json index 38c762a32..281c9c59b 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "projects": [ "src", "test" ], "sdk": { - "version": "1.0.0-rc1-final" + "version": "1.0.0-preview1-002702" } } diff --git a/src/Api/Api.xproj b/src/Api/Api.xproj index 21b540470..687ab808a 100644 --- a/src/Api/Api.xproj +++ b/src/Api/Api.xproj @@ -4,16 +4,17 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + e8548ad6-7fb0-439a-8eb5-549a10336d2d Bit.Api - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + .\obj + .\bin\ + v4.6 2.0 4000 - + \ No newline at end of file diff --git a/src/Api/Controllers/AccountsController.cs b/src/Api/Controllers/AccountsController.cs index c1f651c29..7b92432e0 100644 --- a/src/Api/Controllers/AccountsController.cs +++ b/src/Api/Controllers/AccountsController.cs @@ -1,11 +1,11 @@ using System; using System.Threading.Tasks; -using Microsoft.AspNet.Authorization; -using Microsoft.AspNet.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Bit.Api.Models; using Bit.Core.Exceptions; using Bit.Core.Services; -using Microsoft.AspNet.Identity; +using Microsoft.AspNetCore.Identity; using Bit.Core.Domains; using Bit.Core.Enums; using Bit.Core; @@ -78,7 +78,7 @@ namespace Bit.Api.Controllers { // NOTE: It is assumed that the eventual repository call will make sure the updated // ciphers belong to user making this call. Therefore, no check is done here. - var ciphers = CipherRequestModel.ToDynamicCiphers(model.Ciphers, User.GetUserId()); + var ciphers = CipherRequestModel.ToDynamicCiphers(model.Ciphers, _userManager.GetUserId(User)); var result = await _userService.ChangeEmailAsync( _currentContext.User, @@ -107,7 +107,7 @@ namespace Bit.Api.Controllers { // NOTE: It is assumed that the eventual repository call will make sure the updated // ciphers belong to user making this call. Therefore, no check is done here. - var ciphers = CipherRequestModel.ToDynamicCiphers(model.Ciphers, User.GetUserId()); + var ciphers = CipherRequestModel.ToDynamicCiphers(model.Ciphers, _userManager.GetUserId(User)); var result = await _userService.ChangePasswordAsync( _currentContext.User, @@ -206,8 +206,8 @@ namespace Bit.Api.Controllers public async Task PostImport([FromBody]ImportRequestModel model) { await _cipherService.ImportCiphersAsync( - model.Folders.Select(f => f.ToFolder(User.GetUserId())).ToList(), - model.Sites.Select(s => s.ToSite(User.GetUserId())).ToList(), + model.Folders.Select(f => f.ToFolder(_userManager.GetUserId(User))).ToList(), + model.Sites.Select(s => s.ToSite(_userManager.GetUserId(User))).ToList(), model.SiteRelationships); } diff --git a/src/Api/Controllers/AliveController.cs b/src/Api/Controllers/AliveController.cs index 678ed7976..17914bd89 100644 --- a/src/Api/Controllers/AliveController.cs +++ b/src/Api/Controllers/AliveController.cs @@ -1,5 +1,5 @@ using System; -using Microsoft.AspNet.Mvc; +using Microsoft.AspNetCore.Mvc; namespace Bit.Api.Controllers { diff --git a/src/Api/Controllers/AuthController.cs b/src/Api/Controllers/AuthController.cs index cdcd156e4..c1bc14c6d 100644 --- a/src/Api/Controllers/AuthController.cs +++ b/src/Api/Controllers/AuthController.cs @@ -1,9 +1,9 @@ using System; using System.Threading.Tasks; -using Microsoft.AspNet.Mvc; +using Microsoft.AspNetCore.Mvc; using Bit.Core.Identity; using Bit.Api.Models; -using Microsoft.AspNet.Authorization; +using Microsoft.AspNetCore.Authorization; using Bit.Core.Exceptions; using Bit.Core; diff --git a/src/Api/Controllers/FoldersController.cs b/src/Api/Controllers/FoldersController.cs index 912003df6..d20ba8ff2 100644 --- a/src/Api/Controllers/FoldersController.cs +++ b/src/Api/Controllers/FoldersController.cs @@ -2,13 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNet.Mvc; +using Microsoft.AspNetCore.Mvc; using Bit.Core.Repositories; -using System.Security.Claims; -using Microsoft.AspNet.Authorization; +using Microsoft.AspNetCore.Authorization; using Bit.Api.Models; using Bit.Core.Exceptions; using Bit.Core.Domains; +using Microsoft.AspNetCore.Identity; namespace Bit.Api.Controllers { @@ -17,17 +17,20 @@ namespace Bit.Api.Controllers public class FoldersController : Controller { private readonly IFolderRepository _folderRepository; + private readonly UserManager _userManager; public FoldersController( - IFolderRepository folderRepository) + IFolderRepository folderRepository, + UserManager userManager) { _folderRepository = folderRepository; + _userManager = userManager; } [HttpGet("{id}")] public async Task Get(string id) { - var folder = await _folderRepository.GetByIdAsync(id, User.GetUserId()); + var folder = await _folderRepository.GetByIdAsync(id, _userManager.GetUserId(User)); if(folder == null) { throw new NotFoundException(); @@ -39,7 +42,7 @@ namespace Bit.Api.Controllers [HttpGet("")] public async Task> Get() { - ICollection folders = await _folderRepository.GetManyByUserIdAsync(User.GetUserId()); + ICollection folders = await _folderRepository.GetManyByUserIdAsync(_userManager.GetUserId(User)); var responses = folders.Select(f => new FolderResponseModel(f)); return new ListResponseModel(responses); } @@ -47,7 +50,7 @@ namespace Bit.Api.Controllers [HttpPost("")] public async Task Post([FromBody]FolderRequestModel model) { - var folder = model.ToFolder(User.GetUserId()); + var folder = model.ToFolder(_userManager.GetUserId(User)); await _folderRepository.CreateAsync(folder); return new FolderResponseModel(folder); } @@ -55,7 +58,7 @@ namespace Bit.Api.Controllers [HttpPut("{id}")] public async Task Put(string id, [FromBody]FolderRequestModel model) { - var folder = await _folderRepository.GetByIdAsync(id, User.GetUserId()); + var folder = await _folderRepository.GetByIdAsync(id, _userManager.GetUserId(User)); if(folder == null) { throw new NotFoundException(); @@ -68,7 +71,7 @@ namespace Bit.Api.Controllers [HttpDelete("{id}")] public async Task Delete(string id) { - var folder = await _folderRepository.GetByIdAsync(id, User.GetUserId()); + var folder = await _folderRepository.GetByIdAsync(id, _userManager.GetUserId(User)); if(folder == null) { throw new NotFoundException(); diff --git a/src/Api/Controllers/SitesController.cs b/src/Api/Controllers/SitesController.cs index 11b2ba75f..5b9cb6ecb 100644 --- a/src/Api/Controllers/SitesController.cs +++ b/src/Api/Controllers/SitesController.cs @@ -2,13 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNet.Mvc; +using Microsoft.AspNetCore.Mvc; using Bit.Core.Repositories; -using System.Security.Claims; -using Microsoft.AspNet.Authorization; +using Microsoft.AspNetCore.Authorization; using Bit.Api.Models; using Bit.Core.Exceptions; using Bit.Core.Domains; +using Microsoft.AspNetCore.Identity; namespace Bit.Api.Controllers { @@ -18,19 +18,22 @@ namespace Bit.Api.Controllers { private readonly ISiteRepository _siteRepository; private readonly IFolderRepository _folderRepository; + private readonly UserManager _userManager; public SitesController( ISiteRepository siteRepository, - IFolderRepository folderRepository) + IFolderRepository folderRepository, + UserManager userManager) { _siteRepository = siteRepository; _folderRepository = folderRepository; + _userManager = userManager; } [HttpGet("{id}")] public async Task Get(string id, string[] expand = null) { - var site = await _siteRepository.GetByIdAsync(id, User.GetUserId()); + var site = await _siteRepository.GetByIdAsync(id, _userManager.GetUserId(User)); if(site == null) { throw new NotFoundException(); @@ -44,7 +47,7 @@ namespace Bit.Api.Controllers [HttpGet("")] public async Task> Get(string[] expand = null) { - ICollection sites = await _siteRepository.GetManyByUserIdAsync(User.GetUserId()); + ICollection sites = await _siteRepository.GetManyByUserIdAsync(_userManager.GetUserId(User)); var responses = sites.Select(s => new SiteResponseModel(s)).ToList(); await ExpandManyAsync(sites, responses, expand, null); return new ListResponseModel(responses); @@ -53,7 +56,7 @@ namespace Bit.Api.Controllers [HttpPost("")] public async Task Post([FromBody]SiteRequestModel model, string[] expand = null) { - var site = model.ToSite(User.GetUserId()); + var site = model.ToSite(_userManager.GetUserId(User)); await _siteRepository.CreateAsync(site); var response = new SiteResponseModel(site); @@ -64,7 +67,7 @@ namespace Bit.Api.Controllers [HttpPut("{id}")] public async Task Put(string id, [FromBody]SiteRequestModel model, string[] expand = null) { - var site = await _siteRepository.GetByIdAsync(id, User.GetUserId()); + var site = await _siteRepository.GetByIdAsync(id, _userManager.GetUserId(User)); if(site == null) { throw new NotFoundException(); @@ -80,7 +83,7 @@ namespace Bit.Api.Controllers [HttpDelete("{id}")] public async Task Delete(string id) { - var site = await _siteRepository.GetByIdAsync(id, User.GetUserId()); + var site = await _siteRepository.GetByIdAsync(id, _userManager.GetUserId(User)); if(site == null) { throw new NotFoundException(); @@ -118,7 +121,7 @@ namespace Bit.Api.Controllers { if(folders == null) { - folders = await _folderRepository.GetManyByUserIdAsync(User.GetUserId()); + folders = await _folderRepository.GetManyByUserIdAsync(_userManager.GetUserId(User)); } if(folders != null && folders.Count() > 0) diff --git a/src/Api/Models/Response/ErrorResponseModel.cs b/src/Api/Models/Response/ErrorResponseModel.cs index 0a00718b1..b43557b17 100644 --- a/src/Api/Models/Response/ErrorResponseModel.cs +++ b/src/Api/Models/Response/ErrorResponseModel.cs @@ -1,6 +1,6 @@ using System.Linq; using System.Collections.Generic; -using Microsoft.AspNet.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding; namespace Bit.Api.Models.Response { diff --git a/src/Api/Program.cs b/src/Api/Program.cs new file mode 100644 index 000000000..69d6f0bb8 --- /dev/null +++ b/src/Api/Program.cs @@ -0,0 +1,20 @@ +using System.IO; +using Microsoft.AspNetCore.Hosting; + +namespace Bit.Api +{ + public class Program + { + public static void Main(string[] args) + { + var host = new WebHostBuilder() + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/src/Api/Properties/launchSettings.json b/src/Api/Properties/launchSettings.json index fdfa9a059..bd36404d3 100644 --- a/src/Api/Properties/launchSettings.json +++ b/src/Api/Properties/launchSettings.json @@ -1,25 +1,27 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:4000", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "Hosting:Environment": "Development" - } + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:4000", + "sslPort": 0 + } }, - "web": { - "commandName": "web", - "environmentVariables": { - "Hosting:Environment": "Development" - } + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + }, + "Web": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } } - } -} \ No newline at end of file +} diff --git a/src/Api/Startup.cs b/src/Api/Startup.cs index 77bfd4a1e..1b9ca1459 100644 --- a/src/Api/Startup.cs +++ b/src/Api/Startup.cs @@ -1,14 +1,15 @@ using System; using System.Security.Claims; -using Microsoft.AspNet.Authentication.JwtBearer; -using Microsoft.AspNet.Authorization; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.Identity; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.OptionsModel; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; using Bit.Api.Utilities; using Bit.Core; using Bit.Core.Domains; @@ -16,7 +17,8 @@ using Bit.Core.Identity; using Bit.Core.Repositories; using Bit.Core.Services; using Repos = Bit.Core.Repositories.SqlServer; -using Loggr.Extensions.Logging; +using System.Text; +//using Loggr.Extensions.Logging; namespace Bit.Api { @@ -25,6 +27,7 @@ namespace Bit.Api public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) .AddJsonFile("settings.json") .AddJsonFile($"settings.{env.EnvironmentName}.json", optional: true); @@ -42,14 +45,14 @@ namespace Bit.Api public void ConfigureServices(IServiceCollection services) { - services.Configure(Configuration.GetSection("globalSettings")); + var provider = services.BuildServiceProvider(); // Options services.AddOptions(); // Settings - var provider = services.BuildServiceProvider(); - var globalSettings = provider.GetRequiredService>().Value; + var globalSettings = new GlobalSettings(); + ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), globalSettings); services.AddSingleton(s => globalSettings); // Repositories @@ -75,7 +78,7 @@ namespace Bit.Api RequireDigit = false, RequireLowercase = false, RequiredLength = 8, - RequireNonLetterOrDigit = false, + RequireNonAlphanumeric = false, RequireUppercase = false }; options.ClaimsIdentity = new ClaimsIdentityOptions @@ -90,9 +93,8 @@ namespace Bit.Api jwtBearerOptions.Issuer = "bitwarden"; jwtBearerOptions.TokenLifetime = TimeSpan.FromDays(10 * 365); jwtBearerOptions.TwoFactorTokenLifetime = TimeSpan.FromMinutes(10); - // TODO: Symmetric key - // waiting on https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/250 - jwtBearerOptions.SigningCredentials = null; + var keyBytes = Encoding.ASCII.GetBytes(globalSettings.JwtSigningKey); + jwtBearerOptions.SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(keyBytes), SecurityAlgorithms.HmacSha256); }) .AddUserStore() .AddRoleStore() @@ -138,21 +140,17 @@ namespace Bit.Api ILoggerFactory loggerFactory, GlobalSettings globalSettings) { - loggerFactory.MinimumLevel = LogLevel.Information; loggerFactory.AddConsole(); loggerFactory.AddDebug(); if(!env.IsDevelopment()) { - loggerFactory.AddLoggr( - LogLevel.Error, - globalSettings.Loggr.LogKey, - globalSettings.Loggr.ApiKey); + //loggerFactory.AddLoggr( + // LogLevel.Error, + // globalSettings.Loggr.LogKey, + // globalSettings.Loggr.ApiKey); } - // Add the platform handler to the request pipeline. - app.UseIISPlatformHandler(); - // Add static files to the request pipeline. app.UseStaticFiles(); @@ -165,8 +163,5 @@ namespace Bit.Api // Add MVC to the request pipeline. app.UseMvc(); } - - // Entry point for the application. - public static void Main(string[] args) => WebApplication.Run(args); } } diff --git a/src/Api/Utilities/ExceptionHandlerFilterAttribute.cs b/src/Api/Utilities/ExceptionHandlerFilterAttribute.cs index 587041c4c..55254df8f 100644 --- a/src/Api/Utilities/ExceptionHandlerFilterAttribute.cs +++ b/src/Api/Utilities/ExceptionHandlerFilterAttribute.cs @@ -2,9 +2,9 @@ using System.IdentityModel.Tokens; using Bit.Api.Models.Response; using Bit.Core.Exceptions; -using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.Mvc; -using Microsoft.AspNet.Mvc.Filters; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -48,14 +48,14 @@ namespace Bit.Api.Utilities } else { - var logger = context.HttpContext.ApplicationServices.GetRequiredService>(); + var logger = context.HttpContext.RequestServices.GetRequiredService>(); logger.LogError(exception.Message, exception); errorModel.Message = "An unhandled server error has occured."; context.HttpContext.Response.StatusCode = 500; } - var env = context.HttpContext.ApplicationServices.GetRequiredService(); + var env = context.HttpContext.RequestServices.GetRequiredService(); if(env.IsDevelopment()) { errorModel.ExceptionMessage = exception.Message; diff --git a/src/Api/Utilities/ModelStateValidationFilterAttribute.cs b/src/Api/Utilities/ModelStateValidationFilterAttribute.cs index 13091229d..1a8ab38b4 100644 --- a/src/Api/Utilities/ModelStateValidationFilterAttribute.cs +++ b/src/Api/Utilities/ModelStateValidationFilterAttribute.cs @@ -1,5 +1,5 @@ -using Microsoft.AspNet.Mvc; -using Microsoft.AspNet.Mvc.Filters; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; using Bit.Api.Models.Response; using System.Linq; diff --git a/src/Api/project.json b/src/Api/project.json index dd8f2268d..9c642acde 100644 --- a/src/Api/project.json +++ b/src/Api/project.json @@ -1,42 +1,59 @@ { "userSecretsId": "aspnet5-bitwarden-Api", "version": "0.0.1-*", - "compilationOptions": { - "emitEntryPoint": true - }, "dependencies": { "Core": { "version": "0.0.1", "target": "project" }, - "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final", - "Microsoft.AspNet.Mvc": "6.0.0-rc1-final", - "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final", - "Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final", - "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0-rc1-final", - "Microsoft.Extensions.Logging": "1.0.0-rc1-final", - "Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final", - "Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final", - "Microsoft.AspNet.Cors": "6.0.0-rc1-final", - "Microsoft.AspNet.Diagnostics": "1.0.0-rc1-final", - "Loggr.Extensions.Logging": "1.0.1-rc1-final" + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final", + "Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final", + "Microsoft.AspNetCore.StaticFiles": "1.0.0-rc2-final", + "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0-rc2-final", + "Microsoft.Extensions.Logging": "1.0.0-rc2-final", + "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-final", + "Microsoft.Extensions.Logging.Debug": "1.0.0-rc2-final", + "Microsoft.AspNetCore.Cors": "1.0.0-rc2-final", + "Microsoft.AspNetCore.Diagnostics": "1.0.0-rc2-final", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc2-final", + "Microsoft.Extensions.Configuration.Binder": "1.0.0-rc2-final" }, - "commands": { - "web": "Microsoft.AspNet.Server.Kestrel" + "tools": { + "Microsoft.AspNetCore.Server.IISIntegration.Tools": { + "version": "1.0.0-preview1-final", + "imports": "portable-net45+win8+dnxcore50" + } }, "frameworks": { - "dnx451": { } + "net46": { } }, - "exclude": [ - "wwwroot", - "node_modules" - ], - "publishExclude": [ - "**.user", - "**.vspscc" - ] + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + + "runtimeOptions": { + "gcServer": false, + "gcConcurrent": true + }, + + "publishOptions": { + "include": [ + "wwwroot", + "Views", + "settings.json", + "settings.Production.json", + "settings.Staging.json", + "web.config" + ] + }, + + "scripts": { + "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] + } } diff --git a/src/Api/settings.json b/src/Api/settings.json index de8a1cef9..f9fe224f0 100644 --- a/src/Api/settings.json +++ b/src/Api/settings.json @@ -2,6 +2,7 @@ "globalSettings": { "siteName": "bitwarden", "baseVaultUri": "http://localhost:4001", + "jwtSigningKey": "THIS IS A SECRET. IT KEEPS YOUR TOKEN SAFE. :)", "documentDB": { "uri": "SECRET", "key": "SECRET", diff --git a/src/Api/web.config b/src/Api/web.config new file mode 100644 index 000000000..7b3cb2073 --- /dev/null +++ b/src/Api/web.config @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/Api/wwwroot/web.config b/src/Api/wwwroot/web.config deleted file mode 100644 index c18776115..000000000 --- a/src/Api/wwwroot/web.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/Core/Core.xproj b/src/Core/Core.xproj index f5180cb36..428cf0e84 100644 --- a/src/Core/Core.xproj +++ b/src/Core/Core.xproj @@ -4,15 +4,16 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 3973d21b-a692-4b60-9b70-3631c057423a Bit.Core - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + .\obj + .\bin\ + v4.6 2.0 - + \ No newline at end of file diff --git a/src/Core/Exceptions/BadRequestException.cs b/src/Core/Exceptions/BadRequestException.cs index 260e0723c..5a1ee2d04 100644 --- a/src/Core/Exceptions/BadRequestException.cs +++ b/src/Core/Exceptions/BadRequestException.cs @@ -1,5 +1,5 @@ using System; -using Microsoft.AspNet.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding; namespace Bit.Core.Exceptions { diff --git a/src/Core/GlobalSettings.cs b/src/Core/GlobalSettings.cs index bd1718a39..63e4a0fe4 100644 --- a/src/Core/GlobalSettings.cs +++ b/src/Core/GlobalSettings.cs @@ -7,6 +7,7 @@ namespace Bit.Core { public virtual string SiteName { get; set; } public virtual string BaseVaultUri { get; set; } + public virtual string JwtSigningKey { get; set; } public virtual DocumentDBSettings DocumentDB { get; set; } = new DocumentDBSettings(); public virtual SqlServerSettings SqlServer { get; set; } = new SqlServerSettings(); public virtual MailSettings Mail { get; set; } = new MailSettings(); diff --git a/src/Core/Identity/AuthenticatorTokenProvider.cs b/src/Core/Identity/AuthenticatorTokenProvider.cs index f259f784a..09a4796e5 100644 --- a/src/Core/Identity/AuthenticatorTokenProvider.cs +++ b/src/Core/Identity/AuthenticatorTokenProvider.cs @@ -1,14 +1,14 @@ using System; using System.Threading.Tasks; using Base32; -using Microsoft.AspNet.Identity; +using Microsoft.AspNetCore.Identity; using Bit.Core.Domains; using Bit.Core.Enums; using OtpSharp; namespace Bit.Core.Identity { - public class AuthenticatorTokenProvider : IUserTokenProvider + public class AuthenticatorTokenProvider : IUserTwoFactorTokenProvider { public Task CanGenerateTwoFactorTokenAsync(UserManager manager, User user) { diff --git a/src/Core/Identity/JwtBearerAppBuilderExtensions.cs b/src/Core/Identity/JwtBearerAppBuilderExtensions.cs new file mode 100644 index 000000000..21d5ff7a8 --- /dev/null +++ b/src/Core/Identity/JwtBearerAppBuilderExtensions.cs @@ -0,0 +1,60 @@ +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Authentication.JwtBearer; + +namespace Bit.Core.Identity +{ + public static class JwtBearerAppBuilderExtensions + { + public static IApplicationBuilder UseJwtBearerIdentity(this IApplicationBuilder app) + { + if(app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + var marker = app.ApplicationServices.GetService(); + if(marker == null) + { + throw new InvalidOperationException("Must Call AddJwtBearerIdentity"); + } + + var jwtOptions = app.ApplicationServices.GetRequiredService>().Value; + + var options = new JwtBearerOptions(); + + // Basic settings - signing key to validate with, audience and issuer. + options.TokenValidationParameters.IssuerSigningKey = jwtOptions.SigningCredentials.Key; + options.TokenValidationParameters.ValidAudience = jwtOptions.Audience; + options.TokenValidationParameters.ValidIssuer = jwtOptions.Issuer; + + options.TokenValidationParameters.RequireExpirationTime = true; + options.TokenValidationParameters.RequireSignedTokens = false; + + // When receiving a token, check that we've signed it. + options.TokenValidationParameters.RequireSignedTokens = false; + + //// When receiving a token, check that it is still valid. + options.TokenValidationParameters.ValidateLifetime = true; + + // This defines the maximum allowable clock skew - i.e. provides a tolerance on the token expiry time + // when validating the lifetime. As we're creating the tokens locally and validating them on the same + // machines which should have synchronised time, this can be set to zero. Where external tokens are + // used, some leeway here could be useful. + options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(0); + + options.Events = new JwtBearerEvents + { + OnTokenValidated = JwtBearerEventImplementations.ValidatedTokenAsync, + OnAuthenticationFailed = JwtBearerEventImplementations.AuthenticationFailedAsync + }; + + app.UseJwtBearerAuthentication(options); + + return app; + } + } +} diff --git a/src/Core/Identity/JwtBearerBuilderExtensions.cs b/src/Core/Identity/JwtBearerBuilderExtensions.cs deleted file mode 100644 index acca33944..000000000 --- a/src/Core/Identity/JwtBearerBuilderExtensions.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Identity; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.OptionsModel; -using Microsoft.AspNet.Authentication.JwtBearer; - -namespace Bit.Core.Identity -{ - public static class JwtBearerBuilderExtensions - { - public static IApplicationBuilder UseJwtBearerIdentity(this IApplicationBuilder app) - { - if(app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - var marker = app.ApplicationServices.GetService(); - if(marker == null) - { - throw new InvalidOperationException("Must Call AddJwtBearerIdentity"); - } - - var jwtOptions = app.ApplicationServices.GetRequiredService>().Value; - var jwtSignInManager = app.ApplicationServices.GetRequiredService(); - app.UseJwtBearerAuthentication(options => - { - // Basic settings - signing key to validate with, audience and issuer. - //options.TokenValidationParameters.IssuerSigningKey = key; - options.TokenValidationParameters.ValidAudience = jwtOptions.Audience; - options.TokenValidationParameters.ValidIssuer = jwtOptions.Issuer; - - options.TokenValidationParameters.RequireExpirationTime = true; - options.TokenValidationParameters.RequireSignedTokens = false; - - // When receiving a token, check that we've signed it. - options.TokenValidationParameters.ValidateSignature = false; - - //// When receiving a token, check that it is still valid. - options.TokenValidationParameters.ValidateLifetime = true; - - // This defines the maximum allowable clock skew - i.e. provides a tolerance on the token expiry time - // when validating the lifetime. As we're creating the tokens locally and validating them on the same - // machines which should have synchronised time, this can be set to zero. Where external tokens are - // used, some leeway here could be useful. - options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(0); - - options.Events = new JwtBearerEvents - { - OnValidatedToken = JwtBearerEventImplementations.ValidatedTokenAsync, - OnAuthenticationFailed = JwtBearerEventImplementations.AuthenticationFailedAsync - }; - }); - - return app; - } - } -} diff --git a/src/Core/Identity/JwtBearerEventImplementations.cs b/src/Core/Identity/JwtBearerEventImplementations.cs index 42b6d4a99..3ac80112e 100644 --- a/src/Core/Identity/JwtBearerEventImplementations.cs +++ b/src/Core/Identity/JwtBearerEventImplementations.cs @@ -1,18 +1,20 @@ using System; using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.AspNet.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.DependencyInjection; -using System.IdentityModel.Tokens; using Bit.Core.Repositories; -using Microsoft.AspNet.Authentication; -using Microsoft.AspNet.Http.Authentication; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http.Authentication; +using Microsoft.IdentityModel.Tokens; +using Microsoft.AspNetCore.Identity; +using Bit.Core.Domains; namespace Bit.Core.Identity { public static class JwtBearerEventImplementations { - public async static Task ValidatedTokenAsync(ValidatedTokenContext context) + public async static Task ValidatedTokenAsync(TokenValidatedContext context) { if(context.HttpContext.RequestServices == null) { @@ -20,13 +22,14 @@ namespace Bit.Core.Identity } var userRepository = context.HttpContext.RequestServices.GetRequiredService(); - var manager = context.HttpContext.RequestServices.GetRequiredService(); + var userManager = context.HttpContext.RequestServices.GetRequiredService>(); + var signInManager = context.HttpContext.RequestServices.GetRequiredService(); - var userId = context.AuthenticationTicket.Principal.GetUserId(); + var userId = userManager.GetUserId(context.Ticket.Principal); var user = await userRepository.GetByIdAsync(userId); // validate security token - if(!await manager.ValidateSecurityStampAsync(user, context.AuthenticationTicket.Principal)) + if(!await signInManager.ValidateSecurityStampAsync(user, context.Ticket.Principal)) { throw new SecurityTokenValidationException("Bad security stamp."); } @@ -41,7 +44,7 @@ namespace Bit.Core.Identity if(!context.HttpContext.User.Identity.IsAuthenticated) { context.State = EventResultState.HandledResponse; - context.AuthenticationTicket = new AuthenticationTicket(context.HttpContext.User, new AuthenticationProperties(), context.Options.AuthenticationScheme); + context.Ticket = new AuthenticationTicket(context.HttpContext.User, new AuthenticationProperties(), context.Options.AuthenticationScheme); } return Task.FromResult(0); diff --git a/src/Core/Identity/JwtBearerIdentityOptions.cs b/src/Core/Identity/JwtBearerIdentityOptions.cs index c8d8ac523..bb6430c19 100644 --- a/src/Core/Identity/JwtBearerIdentityOptions.cs +++ b/src/Core/Identity/JwtBearerIdentityOptions.cs @@ -1,5 +1,5 @@ using System; -using System.IdentityModel.Tokens; +using Microsoft.IdentityModel.Tokens; namespace Bit.Core.Identity { diff --git a/src/Core/Identity/JwtBearerIdentityServiceCollectionExtensions.cs b/src/Core/Identity/JwtBearerIdentityServiceCollectionExtensions.cs index c6200c9c8..29ac18fde 100644 --- a/src/Core/Identity/JwtBearerIdentityServiceCollectionExtensions.cs +++ b/src/Core/Identity/JwtBearerIdentityServiceCollectionExtensions.cs @@ -1,14 +1,16 @@ using System; -using Microsoft.AspNet.Identity; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Bit.Core.Domains; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; namespace Bit.Core.Identity { public static class JwtBearerIdentityServiceCollectionExtensions { - public static IdentityBuilder AddJwtBearerIdentit( + public static IdentityBuilder AddJwtBearerIdentity( this IServiceCollection services) { return services.AddJwtBearerIdentity(setupAction: null, jwtBearerSetupAction: null); @@ -23,6 +25,8 @@ namespace Bit.Core.Identity services.AddOptions(); services.AddAuthentication(); + // Hosting doesn't add IHttpContextAccessor by default + services.TryAddSingleton(); // Identity services services.TryAddSingleton(); services.TryAddScoped, UserValidator>(); diff --git a/src/Core/Identity/JwtBearerSignInManager.cs b/src/Core/Identity/JwtBearerSignInManager.cs index 1edc46a2e..400362f41 100644 --- a/src/Core/Identity/JwtBearerSignInManager.cs +++ b/src/Core/Identity/JwtBearerSignInManager.cs @@ -2,12 +2,13 @@ using System.Linq; using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.AspNet.Authentication.JwtBearer; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Identity; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.OptionsModel; +using Microsoft.Extensions.Options; using Bit.Core.Domains; +using Microsoft.AspNetCore.Builder; +using Microsoft.IdentityModel.Tokens; namespace Bit.Core.Identity { @@ -123,12 +124,16 @@ namespace Bit.Core.Identity } } - var securityToken = handler.CreateToken( - issuer: JwtIdentityOptions.Issuer, - audience: JwtIdentityOptions.Audience, - signingCredentials: JwtIdentityOptions.SigningCredentials, - subject: userPrincipal.Identities.First(), - expires: tokenExpiration); + var descriptor = new SecurityTokenDescriptor + { + Issuer = JwtIdentityOptions.Issuer, + SigningCredentials = JwtIdentityOptions.SigningCredentials, + Audience = JwtIdentityOptions.Audience, + Subject = userPrincipal.Identities.First(), + Expires = tokenExpiration + }; + + var securityToken = handler.CreateToken(descriptor); return handler.WriteToken(securityToken); } diff --git a/src/Core/Identity/LowerInvariantLookupNormalizer.cs b/src/Core/Identity/LowerInvariantLookupNormalizer.cs index 3abacaba7..98189b1b5 100644 --- a/src/Core/Identity/LowerInvariantLookupNormalizer.cs +++ b/src/Core/Identity/LowerInvariantLookupNormalizer.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNet.Identity; +using Microsoft.AspNetCore.Identity; namespace Bit.Core.Identity { diff --git a/src/Core/Identity/RoleStore.cs b/src/Core/Identity/RoleStore.cs index ebb29e56e..610ac4b2e 100644 --- a/src/Core/Identity/RoleStore.cs +++ b/src/Core/Identity/RoleStore.cs @@ -1,7 +1,7 @@ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Identity; +using Microsoft.AspNetCore.Identity; using Bit.Core.Domains; namespace Bit.Core.Identity diff --git a/src/Core/Identity/UserStore.cs b/src/Core/Identity/UserStore.cs index b0e6aa846..60220bf8e 100644 --- a/src/Core/Identity/UserStore.cs +++ b/src/Core/Identity/UserStore.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Identity; +using Microsoft.AspNetCore.Identity; using Bit.Core.Domains; using Bit.Core.Repositories; using Bit.Core.Services; diff --git a/src/Core/Services/IUserService.cs b/src/Core/Services/IUserService.cs index fcedff43d..0c86f32a9 100644 --- a/src/Core/Services/IUserService.cs +++ b/src/Core/Services/IUserService.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Microsoft.AspNet.Identity; +using Microsoft.AspNetCore.Identity; using Bit.Core.Domains; namespace Bit.Core.Services diff --git a/src/Core/Services/UserService.cs b/src/Core/Services/UserService.cs index 477f20d4c..15c2fe7d6 100644 --- a/src/Core/Services/UserService.cs +++ b/src/Core/Services/UserService.cs @@ -1,15 +1,16 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Identity; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.OptionsModel; +using Microsoft.Extensions.Options; using Bit.Core.Domains; using Bit.Core.Repositories; using OtpSharp; using Base32; using System.Linq; +using Microsoft.AspNetCore.Builder; namespace Bit.Core.Services { @@ -35,8 +36,7 @@ namespace Bit.Core.Services ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider services, - ILogger> logger, - IHttpContextAccessor contextAccessor) + ILogger> logger) : base( store, optionsAccessor, @@ -46,8 +46,7 @@ namespace Bit.Core.Services keyNormalizer, errors, services, - logger, - contextAccessor) + logger) { _userRepository = userRepository; _cipherRepository = cipherRepository; diff --git a/src/Core/project.json b/src/Core/project.json index 13b431966..14b700438 100644 --- a/src/Core/project.json +++ b/src/Core/project.json @@ -2,21 +2,23 @@ "version": "0.0.1-*", "description": "bitwarden Core Library", "authors": [ "Kyle Spearrin" ], - "tags": [ "" ], - "projectUrl": "", - "licenseUrl": "", "dependencies": { - "Microsoft.AspNet.Identity": "3.0.0-rc1-final", - "Microsoft.AspNet.Authentication.JwtBearer": "1.0.0-rc1-final", + "Microsoft.AspNetCore.Identity": "1.0.0-rc2-final", + "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0-rc2-final", "OtpSharp": "1.3.0.4", - "Microsoft.AspNet.Mvc.Abstractions": "6.0.0-rc1-final", - "Sendgrid": "6.3.4", + "Microsoft.AspNetCore.Mvc.Abstractions": "1.0.0-rc2-final", "Dapper": "1.42.0", - "DataTableProxy": "1.2.0" + "DataTableProxy": "1.2.0", + "Sendgrid": "6.3.4" }, "frameworks": { - "dnx451": { } + "net46": { + "frameworkAssemblies": { + "System.ComponentModel.DataAnnotations": "4.0.0.0", + "System.Data": "4.0.0.0" + } + } } }