2017-09-13 08:47:34 +02:00
|
|
|
|
using Microsoft.AspNetCore.Hosting;
|
|
|
|
|
using Microsoft.AspNetCore.Builder;
|
|
|
|
|
using System;
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
using BTCPayServer.Filters;
|
|
|
|
|
using BTCPayServer.Models;
|
|
|
|
|
using Microsoft.AspNetCore.Identity;
|
2019-03-04 12:48:19 +01:00
|
|
|
|
using Microsoft.AspNetCore.HttpOverrides;
|
2017-09-13 08:47:34 +02:00
|
|
|
|
using BTCPayServer.Data;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using BTCPayServer.Logging;
|
2017-09-22 18:31:29 +02:00
|
|
|
|
using Microsoft.Extensions.Configuration;
|
2017-09-25 10:18:13 +02:00
|
|
|
|
using BTCPayServer.Configuration;
|
|
|
|
|
using System.IO;
|
2017-09-25 18:31:43 +02:00
|
|
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
2019-05-24 08:17:02 +02:00
|
|
|
|
using AspNet.Security.OpenIdConnect.Primitives;
|
|
|
|
|
using BTCPayServer.Authentication.OpenId.Models;
|
|
|
|
|
using BTCPayServer.Security;
|
2018-02-12 19:27:36 +01:00
|
|
|
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
2019-05-24 08:17:02 +02:00
|
|
|
|
using OpenIddict.Abstractions;
|
|
|
|
|
using OpenIddict.EntityFrameworkCore.Models;
|
2018-02-12 19:27:36 +01:00
|
|
|
|
using System.Net;
|
2019-07-01 05:39:25 +02:00
|
|
|
|
using BTCPayServer.Authentication.OpenId;
|
2019-02-22 11:37:45 +01:00
|
|
|
|
using BTCPayServer.PaymentRequest;
|
2019-02-19 05:18:30 +01:00
|
|
|
|
using BTCPayServer.Services.Apps;
|
2019-04-22 09:41:20 +02:00
|
|
|
|
using BTCPayServer.Storage;
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
|
|
|
|
namespace BTCPayServer.Hosting
|
|
|
|
|
{
|
2017-10-27 10:53:04 +02:00
|
|
|
|
public class Startup
|
|
|
|
|
{
|
2018-11-01 04:52:32 +01:00
|
|
|
|
public Startup(IConfiguration conf, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
2017-10-27 10:53:04 +02:00
|
|
|
|
{
|
|
|
|
|
Configuration = conf;
|
|
|
|
|
_Env = env;
|
2018-11-01 04:52:32 +01:00
|
|
|
|
LoggerFactory = loggerFactory;
|
2017-10-27 10:53:04 +02:00
|
|
|
|
}
|
|
|
|
|
IHostingEnvironment _Env;
|
|
|
|
|
public IConfiguration Configuration
|
|
|
|
|
{
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
2018-11-01 04:52:32 +01:00
|
|
|
|
public ILoggerFactory LoggerFactory { get; }
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
2017-10-27 10:53:04 +02:00
|
|
|
|
public void ConfigureServices(IServiceCollection services)
|
|
|
|
|
{
|
2018-11-01 04:52:32 +01:00
|
|
|
|
Logs.Configure(LoggerFactory);
|
2017-10-27 10:53:04 +02:00
|
|
|
|
services.ConfigureBTCPayServer(Configuration);
|
|
|
|
|
services.AddMemoryCache();
|
|
|
|
|
services.AddIdentity<ApplicationUser, IdentityRole>()
|
|
|
|
|
.AddEntityFrameworkStores<ApplicationDbContext>()
|
2019-05-24 08:17:02 +02:00
|
|
|
|
.AddDefaultTokenProviders();
|
|
|
|
|
|
|
|
|
|
ConfigureOpenIddict(services);
|
|
|
|
|
|
|
|
|
|
services.AddBTCPayServer(Configuration);
|
2019-04-22 09:41:20 +02:00
|
|
|
|
services.AddProviderStorage();
|
2019-04-13 14:00:48 +02:00
|
|
|
|
services.AddSession();
|
2019-05-24 08:17:02 +02:00
|
|
|
|
services.AddSignalR();
|
2017-10-27 10:53:04 +02:00
|
|
|
|
services.AddMvc(o =>
|
|
|
|
|
{
|
|
|
|
|
o.Filters.Add(new XFrameOptionsAttribute("DENY"));
|
2018-07-11 18:43:16 +02:00
|
|
|
|
o.Filters.Add(new XContentTypeOptionsAttribute("nosniff"));
|
2018-07-11 19:23:54 +02:00
|
|
|
|
o.Filters.Add(new XXSSProtectionAttribute());
|
2018-07-11 19:38:08 +02:00
|
|
|
|
o.Filters.Add(new ReferrerPolicyAttribute("same-origin"));
|
2018-07-12 11:19:43 +02:00
|
|
|
|
//o.Filters.Add(new ContentSecurityPolicyAttribute()
|
|
|
|
|
//{
|
|
|
|
|
// FontSrc = "'self' https://fonts.gstatic.com/",
|
|
|
|
|
// ImgSrc = "'self' data:",
|
|
|
|
|
// DefaultSrc = "'none'",
|
|
|
|
|
// StyleSrc = "'self' 'unsafe-inline'",
|
|
|
|
|
// ScriptSrc = "'self' 'unsafe-inline'"
|
|
|
|
|
//});
|
2019-04-11 23:30:23 +02:00
|
|
|
|
}).AddControllersAsServices();
|
2018-07-12 10:38:21 +02:00
|
|
|
|
services.TryAddScoped<ContentSecurityPolicies>();
|
2018-01-04 14:56:49 +01:00
|
|
|
|
services.Configure<IdentityOptions>(options =>
|
|
|
|
|
{
|
|
|
|
|
options.Password.RequireDigit = false;
|
2019-01-09 02:32:07 +01:00
|
|
|
|
options.Password.RequiredLength = 6;
|
2018-01-04 14:56:49 +01:00
|
|
|
|
options.Password.RequireLowercase = false;
|
|
|
|
|
options.Password.RequireNonAlphanumeric = false;
|
|
|
|
|
options.Password.RequireUppercase = false;
|
2018-09-12 13:36:44 +02:00
|
|
|
|
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
|
|
|
|
|
options.Lockout.MaxFailedAccessAttempts = 5;
|
|
|
|
|
options.Lockout.AllowedForNewUsers = true;
|
2019-05-24 08:17:02 +02:00
|
|
|
|
options.Password.RequireUppercase = false;
|
|
|
|
|
// Configure Identity to use the same JWT claims as OpenIddict instead
|
|
|
|
|
// of the legacy WS-Federation claims it uses by default (ClaimTypes),
|
|
|
|
|
// which saves you from doing the mapping in your authorization controller.
|
|
|
|
|
options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
|
|
|
|
|
options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
|
|
|
|
|
options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
|
2018-01-04 14:56:49 +01:00
|
|
|
|
});
|
2018-11-01 04:07:28 +01:00
|
|
|
|
// If the HTTPS certificate path is not set this logic will NOT be used and the default Kestrel binding logic will be.
|
|
|
|
|
string httpsCertificateFilePath = Configuration.GetOrDefault<string>("HttpsCertificateFilePath", null);
|
2018-11-01 04:52:32 +01:00
|
|
|
|
bool useDefaultCertificate = Configuration.GetOrDefault<bool>("HttpsUseDefaultCertificate", false);
|
|
|
|
|
bool hasCertPath = !String.IsNullOrEmpty(httpsCertificateFilePath);
|
|
|
|
|
if (hasCertPath || useDefaultCertificate)
|
2018-11-01 04:07:28 +01:00
|
|
|
|
{
|
|
|
|
|
var bindAddress = Configuration.GetOrDefault<IPAddress>("bind", IPAddress.Any);
|
|
|
|
|
int bindPort = Configuration.GetOrDefault<int>("port", 443);
|
|
|
|
|
|
|
|
|
|
services.Configure<KestrelServerOptions>(kestrel =>
|
|
|
|
|
{
|
2019-07-12 04:47:13 +02:00
|
|
|
|
kestrel.Limits.MaxRequestLineSize = 8_192 * 10 * 5; // Around 500K, transactions passed in URI should not be bigger than this
|
2018-11-01 04:52:32 +01:00
|
|
|
|
if (hasCertPath && !File.Exists(httpsCertificateFilePath))
|
2018-11-01 04:07:28 +01:00
|
|
|
|
{
|
|
|
|
|
// Note that by design this is a fatal error condition that will cause the process to exit.
|
|
|
|
|
throw new ConfigException($"The https certificate file could not be found at {httpsCertificateFilePath}.");
|
|
|
|
|
}
|
2018-11-01 04:52:32 +01:00
|
|
|
|
if(hasCertPath && useDefaultCertificate)
|
|
|
|
|
{
|
|
|
|
|
throw new ConfigException($"Conflicting settings: if HttpsUseDefaultCertificate is true, HttpsCertificateFilePath should not be used");
|
|
|
|
|
}
|
2018-11-01 04:07:28 +01:00
|
|
|
|
|
|
|
|
|
kestrel.Listen(bindAddress, bindPort, l =>
|
|
|
|
|
{
|
2018-11-01 04:52:32 +01:00
|
|
|
|
if (hasCertPath)
|
|
|
|
|
{
|
|
|
|
|
Logs.Configuration.LogInformation($"Using HTTPS with the certificate located in {httpsCertificateFilePath}.");
|
|
|
|
|
l.UseHttps(httpsCertificateFilePath, Configuration.GetOrDefault<string>("HttpsCertificateFilePassword", null));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Logs.Configuration.LogInformation($"Using HTTPS with the default certificate");
|
|
|
|
|
l.UseHttps();
|
|
|
|
|
}
|
2018-11-01 04:07:28 +01:00
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
2017-10-27 10:53:04 +02:00
|
|
|
|
}
|
2017-09-22 18:31:29 +02:00
|
|
|
|
|
2019-05-24 08:17:02 +02:00
|
|
|
|
private void ConfigureOpenIddict(IServiceCollection services)
|
|
|
|
|
{
|
|
|
|
|
// Register the OpenIddict services.
|
|
|
|
|
services.AddOpenIddict()
|
|
|
|
|
.AddCore(options =>
|
|
|
|
|
{
|
|
|
|
|
// Configure OpenIddict to use the Entity Framework Core stores and entities.
|
|
|
|
|
options.UseEntityFrameworkCore()
|
|
|
|
|
.UseDbContext<ApplicationDbContext>()
|
|
|
|
|
.ReplaceDefaultEntities<BTCPayOpenIdClient, BTCPayOpenIdAuthorization, OpenIddictScope<string>,
|
|
|
|
|
BTCPayOpenIdToken, string>();
|
|
|
|
|
})
|
|
|
|
|
.AddServer(options =>
|
|
|
|
|
{
|
2019-07-01 05:39:25 +02:00
|
|
|
|
|
|
|
|
|
//Disabled so that Tor works with OpenIddict too
|
|
|
|
|
options.DisableHttpsRequirement();
|
2019-05-24 08:17:02 +02:00
|
|
|
|
// Register the ASP.NET Core MVC binder used by OpenIddict.
|
|
|
|
|
// Note: if you don't call this method, you won't be able to
|
|
|
|
|
// bind OpenIdConnectRequest or OpenIdConnectResponse parameters.
|
|
|
|
|
options.UseMvc();
|
|
|
|
|
|
|
|
|
|
// Enable the token endpoint (required to use the password flow).
|
|
|
|
|
options.EnableTokenEndpoint("/connect/token");
|
|
|
|
|
options.EnableAuthorizationEndpoint("/connect/authorize");
|
2019-07-01 05:39:25 +02:00
|
|
|
|
options.EnableLogoutEndpoint("/connect/logout");
|
2019-05-24 08:17:02 +02:00
|
|
|
|
|
2019-07-01 05:39:25 +02:00
|
|
|
|
//we do not care about these granular controls for now
|
|
|
|
|
options.DisableScopeValidation();
|
|
|
|
|
options.IgnoreEndpointPermissions();
|
2019-05-24 08:17:02 +02:00
|
|
|
|
// Allow client applications various flows
|
|
|
|
|
options.AllowImplicitFlow();
|
|
|
|
|
options.AllowClientCredentialsFlow();
|
|
|
|
|
options.AllowRefreshTokenFlow();
|
|
|
|
|
options.AllowPasswordFlow();
|
|
|
|
|
options.AllowAuthorizationCodeFlow();
|
|
|
|
|
options.UseRollingTokens();
|
|
|
|
|
options.UseJsonWebTokens();
|
|
|
|
|
|
|
|
|
|
options.RegisterScopes(
|
|
|
|
|
OpenIdConnectConstants.Scopes.OpenId,
|
|
|
|
|
OpenIdConnectConstants.Scopes.OfflineAccess,
|
|
|
|
|
OpenIdConnectConstants.Scopes.Email,
|
|
|
|
|
OpenIdConnectConstants.Scopes.Profile,
|
|
|
|
|
OpenIddictConstants.Scopes.Roles);
|
2019-07-01 05:39:25 +02:00
|
|
|
|
options.AddEventHandler<PasswordGrantTypeEventHandler>();
|
|
|
|
|
options.AddEventHandler<AuthorizationCodeGrantTypeEventHandler>();
|
|
|
|
|
options.AddEventHandler<RefreshTokenGrantTypeEventHandler>();
|
|
|
|
|
options.AddEventHandler<ClientCredentialsGrantTypeEventHandler>();
|
|
|
|
|
options.AddEventHandler<AuthorizationEventHandler>();
|
|
|
|
|
options.AddEventHandler<LogoutEventHandler>();
|
2019-05-24 08:17:02 +02:00
|
|
|
|
|
|
|
|
|
options.ConfigureSigningKey(Configuration);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-27 10:53:04 +02:00
|
|
|
|
public void Configure(
|
|
|
|
|
IApplicationBuilder app,
|
|
|
|
|
IHostingEnvironment env,
|
|
|
|
|
IServiceProvider prov,
|
2018-04-05 08:50:23 +02:00
|
|
|
|
BTCPayServerOptions options,
|
2017-10-27 10:53:04 +02:00
|
|
|
|
ILoggerFactory loggerFactory)
|
2018-04-05 08:50:23 +02:00
|
|
|
|
{
|
|
|
|
|
Logs.Configuration.LogInformation($"Root Path: {options.RootPath}");
|
|
|
|
|
if (options.RootPath.Equals("/", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
2018-04-09 07:41:52 +02:00
|
|
|
|
ConfigureCore(app, env, prov, loggerFactory, options);
|
2018-04-05 08:50:23 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
app.Map(options.RootPath, appChild =>
|
|
|
|
|
{
|
2018-04-09 07:41:52 +02:00
|
|
|
|
ConfigureCore(appChild, env, prov, loggerFactory, options);
|
2018-04-05 08:50:23 +02:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-09 07:41:52 +02:00
|
|
|
|
private static void ConfigureCore(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider prov, ILoggerFactory loggerFactory, BTCPayServerOptions options)
|
2017-10-27 10:53:04 +02:00
|
|
|
|
{
|
|
|
|
|
if (env.IsDevelopment())
|
|
|
|
|
{
|
|
|
|
|
app.UseDeveloperExceptionPage();
|
|
|
|
|
}
|
2019-05-24 08:17:02 +02:00
|
|
|
|
|
|
|
|
|
app.UseCors();
|
2019-03-04 14:34:14 +01:00
|
|
|
|
|
|
|
|
|
var forwardingOptions = new ForwardedHeadersOptions()
|
2019-03-04 12:48:19 +01:00
|
|
|
|
{
|
2019-03-04 14:34:14 +01:00
|
|
|
|
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
|
|
|
|
};
|
|
|
|
|
forwardingOptions.KnownNetworks.Clear();
|
|
|
|
|
forwardingOptions.KnownProxies.Clear();
|
|
|
|
|
forwardingOptions.ForwardedHeaders = ForwardedHeaders.All;
|
|
|
|
|
app.UseForwardedHeaders(forwardingOptions);
|
2018-08-06 05:04:36 +02:00
|
|
|
|
app.UseCors();
|
2017-10-27 10:53:04 +02:00
|
|
|
|
app.UsePayServer();
|
|
|
|
|
app.UseStaticFiles();
|
2019-04-22 09:41:20 +02:00
|
|
|
|
app.UseProviderStorage(options);
|
2017-10-27 10:53:04 +02:00
|
|
|
|
app.UseAuthentication();
|
2019-04-13 14:00:48 +02:00
|
|
|
|
app.UseSession();
|
2018-12-22 15:02:16 +01:00
|
|
|
|
app.UseSignalR(route =>
|
|
|
|
|
{
|
2019-03-09 08:08:31 +01:00
|
|
|
|
AppHub.Register(route);
|
|
|
|
|
PaymentRequestHub.Register(route);
|
2018-12-22 15:02:16 +01:00
|
|
|
|
});
|
2017-12-17 11:58:55 +01:00
|
|
|
|
app.UseWebSockets();
|
2018-08-25 13:28:46 +02:00
|
|
|
|
app.UseStatusCodePages();
|
2017-10-27 10:53:04 +02:00
|
|
|
|
app.UseMvc(routes =>
|
|
|
|
|
{
|
|
|
|
|
routes.MapRoute(
|
|
|
|
|
name: "default",
|
|
|
|
|
template: "{controller=Home}/{action=Index}/{id?}");
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-09-13 08:47:34 +02:00
|
|
|
|
}
|