Part 1: OpenIddict - Minor Changes & Config prep (#566)

* Part 1: OpenIddict - Minor Changes & Config prep

* add missing nuget

* pr changes

* pr fixes

* remove config for openid -- no need for it for now

* remove unused extension

* Add tests

* use pay tester http client

* check redirecturl in tests
This commit is contained in:
Andrew Camilleri
2019-05-14 15:46:43 +00:00
committed by Nicolas Dorier
parent e22b7f74c7
commit cf436e11ae
11 changed files with 136 additions and 53 deletions

View File

@@ -316,6 +316,42 @@ namespace BTCPayServer.Tests
#pragma warning restore CS0618
}
[Fact]
[Trait("Integration", "Integration")]
public async Task GetRedirectedToLoginPathOnChallenge()
{
using (var tester = ServerTester.Create())
{
tester.Start();
var client = tester.PayTester.HttpClient;
//Wallets endpoint is protected
var response = await client.GetAsync("wallets");
var urlPath = response.RequestMessage.RequestUri.ToString()
.Replace(tester.PayTester.ServerUri.ToString(), "");
//Cookie Challenge redirects you to login page
Assert.StartsWith("Account/Login", urlPath, StringComparison.InvariantCultureIgnoreCase);
var queryString = response.RequestMessage.RequestUri.ParseQueryString();
Assert.NotNull(queryString["ReturnUrl"]);
Assert.Equal("/wallets", queryString["ReturnUrl"]);
}
}
[Fact]
[Trait("Integration", "Integration")]
public async Task CanUseTestWebsiteUI()
{
using (var tester = ServerTester.Create())
{
tester.Start();
var http = new HttpClient();
var response = await http.GetAsync(tester.PayTester.ServerUri);
Assert.True(response.IsSuccessStatusCode);
}
}
[Fact]
[Trait("Integration", "Integration")]
public void CanAcceptInvoiceWithTolerance()

View File

@@ -57,6 +57,8 @@
<PackageReference Include="NicolasDorier.RateLimits" Version="1.0.0.3" />
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="1.0.0.18" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.1.2" />
<PackageReference Include="OpenIddict" Version="2.0.0" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="2.0.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.1.2" />
<PackageReference Include="Serilog" Version="2.7.1" />
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />

View File

@@ -6,13 +6,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using StandardConfiguration;
using Microsoft.Extensions.Configuration;
using NBXplorer;
using BTCPayServer.Payments.Lightning;
using Renci.SshNet;
using NBitcoin.DataEncoders;
using BTCPayServer.SSH;
using BTCPayServer.Lightning;
using Serilog.Events;
@@ -75,8 +69,7 @@ namespace BTCPayServer.Configuration
public void LoadArgs(IConfiguration conf)
{
NetworkType = DefaultConfiguration.GetNetworkType(conf);
var defaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType);
DataDir = conf.GetOrDefault<string>("datadir", defaultSettings.DefaultDataDirectory);
DataDir = conf.GetDataDir(NetworkType);
Logs.Configuration.LogInformation("Network: " + NetworkType.ToString());
var supportedChains = conf.GetOrDefault<string>("chains", "btc")

View File

@@ -58,5 +58,17 @@ namespace BTCPayServer.Configuration
throw new NotSupportedException("Configuration value does not support time " + typeof(T).Name);
}
}
public static string GetDataDir(this IConfiguration configuration)
{
var networkType = DefaultConfiguration.GetNetworkType(configuration);
return GetDataDir(configuration, networkType);
}
public static string GetDataDir(this IConfiguration configuration, NetworkType networkType)
{
var defaultSettings = BTCPayDefaultSettings.GetDefaultSettings(networkType);
return configuration.GetOrDefault("datadir", defaultSettings.DefaultDataDirectory);
}
}
}

View File

@@ -54,7 +54,7 @@ namespace BTCPayServer.Hosting
{
public static class BTCPayServerServices
{
public static IServiceCollection AddBTCPayServer(this IServiceCollection services)
public static IServiceCollection AddBTCPayServer(this IServiceCollection services, IConfiguration configuration)
{
services.AddDbContext<ApplicationDbContext>((provider, o) =>
{
@@ -67,7 +67,8 @@ namespace BTCPayServer.Hosting
services.TryAddSingleton<SocketFactory>();
services.TryAddSingleton<LightningClientFactoryService>();
services.TryAddSingleton<InvoicePaymentNotification>();
services.TryAddSingleton<BTCPayServerOptions>(o => o.GetRequiredService<IOptions<BTCPayServerOptions>>().Value);
services.TryAddSingleton<BTCPayServerOptions>(o =>
o.GetRequiredService<IOptions<BTCPayServerOptions>>().Value);
services.TryAddSingleton<InvoiceRepository>(o =>
{
var opts = o.GetRequiredService<BTCPayServerOptions>();
@@ -219,7 +220,7 @@ namespace BTCPayServer.Hosting
// bundling
services.AddAuthorization(o => Policies.AddBTCPayPolicies(o));
BitpayAuthentication.AddAuthentication(services);
services.AddBtcPayServerAuthenticationSchemes(configuration);
services.AddSingleton<IBundleProvider, ResourceBundleProvider>();
services.AddTransient<BundleOptions>(provider =>
@@ -231,9 +232,9 @@ namespace BTCPayServer.Hosting
return bundle;
});
services.AddCors(options=>
services.AddCors(options =>
{
options.AddPolicy(CorsPolicies.All, p=>p.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin());
options.AddPolicy(CorsPolicies.All, p => p.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin());
});
var rateLimits = new RateLimitService();
@@ -242,6 +243,13 @@ namespace BTCPayServer.Hosting
return services;
}
private static void AddBtcPayServerAuthenticationSchemes(this IServiceCollection services, IConfiguration configuration)
{
services.AddAuthentication()
.AddCookie()
.AddBitpayAuthentication();
}
public static IApplicationBuilder UsePayServer(this IApplicationBuilder app)
{
using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())

View File

@@ -67,9 +67,9 @@ namespace BTCPayServer.Hosting
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddSignalR();
services.AddBTCPayServer();
services.AddProviderStorage();
services.AddSession();
services.AddBTCPayServer(Configuration);
services.AddMvc(o =>
{
o.Filters.Add(new XFrameOptionsAttribute("DENY"));

View File

@@ -1,4 +1,5 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace BTCPayServer.Models
{
@@ -7,5 +8,11 @@ namespace BTCPayServer.Models
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
[Display(Name = "Error")]
public string Error { get; set; }
[Display(Name = "Description")]
public string ErrorDescription { get; set; }
}
}

View File

@@ -1,15 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Claims;
using System.Threading.Tasks;
using BTCPayServer.Models;
using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Options;
namespace BTCPayServer.Security
@@ -17,13 +12,13 @@ namespace BTCPayServer.Security
public class BTCPayClaimsFilter : IAsyncAuthorizationFilter, IConfigureOptions<MvcOptions>
{
UserManager<ApplicationUser> _UserManager;
UserManager<ApplicationUser> _userManager;
StoreRepository _StoreRepository;
public BTCPayClaimsFilter(
UserManager<ApplicationUser> userManager,
StoreRepository storeRepository)
{
_UserManager = userManager;
_userManager = userManager;
_StoreRepository = storeRepository;
}
@@ -35,21 +30,28 @@ namespace BTCPayServer.Security
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var principal = context.HttpContext.User;
if (!context.HttpContext.GetIsBitpayAPI())
if (context.HttpContext.GetIsBitpayAPI())
{
return;
}
var identity = ((ClaimsIdentity)principal.Identity);
if (principal.IsInRole(Roles.ServerAdmin))
{
identity.AddClaim(new Claim(Policies.CanModifyServerSettings.Key, "true"));
}
if (context.RouteData.Values.TryGetValue("storeId", out var storeId))
{
var claim = identity.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
if (claim != null)
var userid = _userManager.GetUserId(principal);
if (!string.IsNullOrEmpty(userid))
{
var store = await _StoreRepository.FindStore((string)storeId, claim.Value);
var store = await _StoreRepository.FindStore((string)storeId, userid);
if (store == null)
context.Result = new ChallengeResult(Policies.CookieAuthentication);
{
context.Result = new ChallengeResult();
}
else
{
context.HttpContext.SetStoreData(store);
@@ -62,5 +64,4 @@ namespace BTCPayServer.Security
}
}
}
}
}

View File

@@ -1,7 +1,5 @@
using System;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Http.Extensions;
using System.Collections.Generic;
using System.IO;
@@ -10,13 +8,9 @@ using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using BTCPayServer.Authentication;
using BTCPayServer.Models;
using BTCPayServer.Services;
using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Options;
using NBitcoin;
using NBitcoin.DataEncoders;
@@ -27,7 +21,6 @@ using BTCPayServer.Logging;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Authentication;
using System.Text.Encodings.Web;
using Microsoft.Extensions.DependencyInjection;
namespace BTCPayServer.Security
{
@@ -185,10 +178,10 @@ namespace BTCPayServer.Security
return await _TokenRepository.GetStoreIdFromAPIKey(apiKey);
}
}
internal static void AddAuthentication(IServiceCollection services, Action<BitpayAuthOptions> bitpayAuth = null)
public static void AddAuthentication(AuthenticationBuilder builder, Action<BitpayAuthOptions> bitpayAuth = null)
{
bitpayAuth = bitpayAuth ?? new Action<BitpayAuthOptions>((o) => { });
services.AddAuthentication().AddScheme<BitpayAuthOptions, BitpayAuthHandler>(Policies.BitpayAuthentication, bitpayAuth);
builder.AddScheme<BitpayAuthOptions, BitpayAuthHandler>(Policies.BitpayAuthentication, bitpayAuth);
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
using Microsoft.AspNetCore.Authentication;
namespace BTCPayServer.Security
{
public static class BitpayAuthenticationExtensions
{
public static AuthenticationBuilder AddBitpayAuthentication(this AuthenticationBuilder builder,
Action<BitpayAuthentication.BitpayAuthOptions> bitpayAuth = null)
{
BitpayAuthentication.AddAuthentication(builder,bitpayAuth);
return builder;
}
}
}

View File

@@ -3,8 +3,24 @@
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<h1 class="text-danger">
@if (!string.IsNullOrEmpty(Model.Error)) {
<strong>@Model.Error</strong>
}
else
{
@:Error.
}
</h1>
<h2 class="text-danger">
@if (!string.IsNullOrEmpty(Model.ErrorDescription)) {
<small>@Model.ErrorDescription</small>
}
else
{
@:An error occurred while processing your request.
}
</h2>
@if(Model != null && Model.ShowRequestId)
{