Browse Source

setup authentication and read userid from principal

pull/2/head
Kyle Spearrin 4 years ago
parent
commit
f9bed31d11
  1. 33
      src/CryptoAgent/Controllers/UserKeysController.cs
  2. 1
      src/CryptoAgent/CryptoAgent.csproj
  3. 2
      src/CryptoAgent/CryptoAgentSettings.cs
  4. 103
      src/CryptoAgent/Startup.cs
  5. 3
      src/CryptoAgent/appsettings.Development.json
  6. 1
      src/CryptoAgent/appsettings.json

33
src/CryptoAgent/Controllers/UserKeysController.cs

@ -1,33 +1,42 @@
using Bit.CryptoAgent.Models; using Bit.CryptoAgent.Models;
using Bit.CryptoAgent.Repositories; using Bit.CryptoAgent.Repositories;
using Bit.CryptoAgent.Services; using Bit.CryptoAgent.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System; using System;
using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Bit.CryptoAgent.Controllers namespace Bit.CryptoAgent.Controllers
{ {
[Authorize("Application")]
[Route("user-keys")] [Route("user-keys")]
public class UserKeysController : Controller public class UserKeysController : Controller
{ {
private readonly ILogger<UserKeysController> _logger; private readonly ILogger<UserKeysController> _logger;
private readonly ICryptoService _cryptoService; private readonly ICryptoService _cryptoService;
private readonly IUserKeyRepository _userKeyRepository; private readonly IUserKeyRepository _userKeyRepository;
private readonly IdentityOptions _identityOptions;
public UserKeysController( public UserKeysController(
IOptions<IdentityOptions> optionsAccessor,
ILogger<UserKeysController> logger, ILogger<UserKeysController> logger,
IUserKeyRepository userKeyRepository, IUserKeyRepository userKeyRepository,
ICryptoService cryptoService) ICryptoService cryptoService)
{ {
_identityOptions = optionsAccessor?.Value ?? new IdentityOptions();
_logger = logger; _logger = logger;
_cryptoService = cryptoService; _cryptoService = cryptoService;
_userKeyRepository = userKeyRepository; _userKeyRepository = userKeyRepository;
} }
[HttpPost("{userId}/get")] [HttpPost("get")]
public async Task<IActionResult> Get(Guid userId, [FromBody] UserKeyGetRequestModel model) public async Task<IActionResult> Get([FromBody] UserKeyGetRequestModel model)
{ {
var userId = GetProperUserId().Value;
var publicKey = Convert.FromBase64String(model.PublicKey); var publicKey = Convert.FromBase64String(model.PublicKey);
var user = await _userKeyRepository.ReadAsync(userId); var user = await _userKeyRepository.ReadAsync(userId);
if (user == null) if (user == null)
@ -45,9 +54,10 @@ namespace Bit.CryptoAgent.Controllers
return new JsonResult(response); return new JsonResult(response);
} }
[HttpPost("{userId}")] [HttpPost]
public async Task<IActionResult> Post(Guid userId, [FromBody] UserKeyRequestModel model) public async Task<IActionResult> Post([FromBody] UserKeyRequestModel model)
{ {
var userId = GetProperUserId().Value;
var user = await _userKeyRepository.ReadAsync(userId); var user = await _userKeyRepository.ReadAsync(userId);
if (user != null) if (user != null)
{ {
@ -63,9 +73,10 @@ namespace Bit.CryptoAgent.Controllers
return new OkResult(); return new OkResult();
} }
[HttpPut("{userId}")] [HttpPut]
public async Task<IActionResult> Put(Guid userId, [FromBody] UserKeyRequestModel model) public async Task<IActionResult> Put([FromBody] UserKeyRequestModel model)
{ {
var userId = GetProperUserId().Value;
var user = await _userKeyRepository.ReadAsync(userId); var user = await _userKeyRepository.ReadAsync(userId);
if (user != null) if (user != null)
{ {
@ -80,5 +91,15 @@ namespace Bit.CryptoAgent.Controllers
await _userKeyRepository.UpdateAsync(user); await _userKeyRepository.UpdateAsync(user);
return new OkResult(); return new OkResult();
} }
public Guid? GetProperUserId()
{
var userId = User.FindFirstValue(_identityOptions.ClaimsIdentity.UserIdClaimType);
if (!Guid.TryParse(userId, out var userIdGuid))
{
return null;
}
return userIdGuid;
}
} }
} }

1
src/CryptoAgent/CryptoAgent.csproj

@ -14,6 +14,7 @@
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.2.0" /> <PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.2.0" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.9.1" /> <PackageReference Include="Azure.Storage.Blobs" Version="12.9.1" />
<PackageReference Include="Google.Cloud.Kms.V1" Version="2.4.0" /> <PackageReference Include="Google.Cloud.Kms.V1" Version="2.4.0" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
<PackageReference Include="JsonFlatFileDataStore" Version="2.2.3" /> <PackageReference Include="JsonFlatFileDataStore" Version="2.2.3" />
<PackageReference Include="VaultSharp" Version="1.6.5.1" /> <PackageReference Include="VaultSharp" Version="1.6.5.1" />
</ItemGroup> </ItemGroup>

2
src/CryptoAgent/CryptoAgentSettings.cs

@ -2,6 +2,8 @@
{ {
public class CryptoAgentSettings public class CryptoAgentSettings
{ {
public string IdentityServerUri { get; set; }
public DatabaseSettings Database { get; set; } public DatabaseSettings Database { get; set; }
public CertificateSettings Certificate { get; set; } public CertificateSettings Certificate { get; set; }
public RsaKeySettings RsaKey { get; set; } public RsaKeySettings RsaKey { get; set; }

103
src/CryptoAgent/Startup.cs

@ -1,13 +1,17 @@
using Bit.CryptoAgent.Repositories; using Bit.CryptoAgent.Repositories;
using Bit.CryptoAgent.Services; using Bit.CryptoAgent.Services;
using IdentityModel;
using IdentityServer4.AccessTokenValidation;
using JsonFlatFileDataStore; using JsonFlatFileDataStore;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using System; using System;
using System.Globalization; using System.Globalization;
using System.Security.Claims;
namespace Bit.CryptoAgent namespace Bit.CryptoAgent
{ {
@ -29,6 +33,51 @@ namespace Bit.CryptoAgent
ConfigurationBinder.Bind(Configuration.GetSection("CryptoAgentSettings"), settings); ConfigurationBinder.Bind(Configuration.GetSection("CryptoAgentSettings"), settings);
services.AddSingleton(s => settings); services.AddSingleton(s => settings);
AddAuthentication(services, settings);
AddRsaKeyProvider(services, settings);
services.AddSingleton<ICryptoFunctionService, CryptoFunctionService>();
services.AddSingleton<ICryptoService, CryptoService>();
AddDatabase(services, settings);
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
}
private void AddDatabase(IServiceCollection services, CryptoAgentSettings settings)
{
var databaseProvider = settings.Database.Provider?.ToLowerInvariant();
if (databaseProvider == "json")
{
// Assign foobar to keyProperty in order to not use incrementing Id functionality
services.AddSingleton<IDataStore>(
new DataStore(settings.Database.JsonFilePath, keyProperty: "--foobar--"));
services.AddSingleton<IApplicationDataRepository, Repositories.JsonFile.ApplicationDataRepository>();
services.AddSingleton<IUserKeyRepository, Repositories.JsonFile.UserKeyRepository>();
}
else
{
throw new Exception("No database configured.");
}
}
private void AddRsaKeyProvider(IServiceCollection services, CryptoAgentSettings settings)
{
var rsaKeyProvider = settings.RsaKey.Provider?.ToLowerInvariant(); var rsaKeyProvider = settings.RsaKey.Provider?.ToLowerInvariant();
if (rsaKeyProvider == "certificate") if (rsaKeyProvider == "certificate")
{ {
@ -76,36 +125,44 @@ namespace Bit.CryptoAgent
{ {
throw new Exception("Unknown rsa key provider configured."); throw new Exception("Unknown rsa key provider configured.");
} }
}
services.AddSingleton<ICryptoFunctionService, CryptoFunctionService>(); private void AddAuthentication(IServiceCollection services, CryptoAgentSettings settings)
services.AddSingleton<ICryptoService, CryptoService>(); {
services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity = new ClaimsIdentityOptions
{
UserNameClaimType = JwtClaimTypes.Email,
UserIdClaimType = JwtClaimTypes.Subject
};
});
services
.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = settings.IdentityServerUri;
options.RequireHttpsMetadata = !Environment.IsDevelopment() &&
settings.IdentityServerUri.StartsWith("https");
options.NameClaimType = ClaimTypes.Email;
options.SupportedTokens = SupportedTokens.Jwt;
});
var databaseProvider = settings.Database.Provider?.ToLowerInvariant(); services
if (databaseProvider == "json") .AddAuthorization(config =>
{ {
// Assign foobar to keyProperty in order to not use incrementing Id functionality config.AddPolicy("Application", policy =>
services.AddSingleton<IDataStore>(
new DataStore(settings.Database.JsonFilePath, keyProperty: "--foobar--"));
services.AddSingleton<IApplicationDataRepository, Repositories.JsonFile.ApplicationDataRepository>();
services.AddSingleton<IUserKeyRepository, Repositories.JsonFile.UserKeyRepository>();
}
else
{ {
throw new Exception("No database configured."); policy.RequireAuthenticatedUser();
} policy.RequireClaim(JwtClaimTypes.AuthenticationMethod, "Application", "external");
policy.RequireClaim(JwtClaimTypes.Scope, "api");
services.AddControllers(); });
} });
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) if (Environment.IsDevelopment())
{
if (env.IsDevelopment())
{ {
app.UseDeveloperExceptionPage(); Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
} }
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
} }
} }
} }

3
src/CryptoAgent/appsettings.Development.json

@ -5,5 +5,8 @@
"Microsoft": "Warning", "Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
} }
},
"cryptoAgentSettings": {
"identityServerUri": "http://localhost:33656/"
} }
} }

1
src/CryptoAgent/appsettings.json

@ -8,6 +8,7 @@
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"cryptoAgentSettings": { "cryptoAgentSettings": {
"identityServerUri": "https://identity.bitwarden.com/",
"database": { "database": {
"provider": "json", "provider": "json",
"jsonFilePath": "/etc/bitwarden/data.json" "jsonFilePath": "/etc/bitwarden/data.json"

Loading…
Cancel
Save