Register first user as admin

This commit is contained in:
Dennis Reimann 2024-07-29 16:44:13 +02:00
parent 0df173b415
commit f61592cb35
No known key found for this signature in database
GPG key ID: 5009E1797F03F8D0
2 changed files with 30 additions and 13 deletions

View file

@ -6,14 +6,12 @@ using System.Threading.Tasks;
using BTCPayApp.CommonServer.Models; using BTCPayApp.CommonServer.Models;
using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Events; using BTCPayServer.Events;
using BTCPayServer.Plugins.PointOfSale; using BTCPayServer.Plugins.PointOfSale;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.BearerToken; using Microsoft.AspNetCore.Authentication.BearerToken;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -37,33 +35,51 @@ public partial class AppApiController
[RateLimitsFilter(ZoneLimits.Login, Scope = RateLimitsScope.RemoteAddress)] [RateLimitsFilter(ZoneLimits.Login, Scope = RateLimitsScope.RemoteAddress)]
public async Task<Results<Ok<AccessTokenResponse>, Ok<SignupResult>, EmptyHttpResult, ProblemHttpResult>> Register(SignupRequest signup) public async Task<Results<Ok<AccessTokenResponse>, Ok<SignupResult>, EmptyHttpResult, ProblemHttpResult>> Register(SignupRequest signup)
{ {
var policiesSettings = await settingsRepository.GetSettingAsync<PoliciesSettings>() ?? new PoliciesSettings(); var policies = await settingsRepository.GetSettingAsync<PoliciesSettings>() ?? new PoliciesSettings();
if (policiesSettings.LockSubscription) if (policies.LockSubscription)
return TypedResults.Problem("This instance does not allow public user registration", statusCode: 401); return TypedResults.Problem("This instance does not allow public user registration", statusCode: 401);
var errorMessage = "Invalid signup attempt."; var errorMessage = "Invalid signup attempt.";
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
var isFirstAdmin = !(await userManager.GetUsersInRoleAsync(Roles.ServerAdmin)).Any();
var user = new ApplicationUser var user = new ApplicationUser
{ {
UserName = signup.Email, UserName = signup.Email,
Email = signup.Email, Email = signup.Email,
RequiresEmailConfirmation = policiesSettings.RequiresConfirmedEmail, RequiresEmailConfirmation = policies.RequiresConfirmedEmail,
RequiresApproval = policiesSettings.RequiresUserApproval, RequiresApproval = policies.RequiresUserApproval,
Created = DateTimeOffset.UtcNow Created = DateTimeOffset.UtcNow,
Approved = isFirstAdmin // auto-approve first admin and users created by an admin
}; };
var result = await userManager.CreateAsync(user, signup.Password); var result = await userManager.CreateAsync(user, signup.Password);
if (result.Succeeded) if (result.Succeeded)
{ {
if (isFirstAdmin)
{
await roleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin));
await userManager.AddToRoleAsync(user, Roles.ServerAdmin);
var settings = await settingsRepository.GetSettingAsync<ThemeSettings>() ?? new ThemeSettings();
if (settings.FirstRun)
{
settings.FirstRun = false;
await settingsRepository.UpdateSetting(settings);
}
await settingsRepository.FirstAdminRegistered(policies, btcpayOptions.UpdateUrl != null, btcpayOptions.DisableRegistration, logs);
}
eventAggregator.Publish(new UserRegisteredEvent eventAggregator.Publish(new UserRegisteredEvent
{ {
RequestUri = Request.GetAbsoluteRootUri(), RequestUri = Request.GetAbsoluteRootUri(),
User = user User = user,
Admin = isFirstAdmin
}); });
SignInResult? signInResult = null; SignInResult? signInResult = null;
var requiresConfirmedEmail = policiesSettings.RequiresConfirmedEmail && !user.EmailConfirmed; var requiresConfirmedEmail = policies.RequiresConfirmedEmail && !user.EmailConfirmed;
var requiresUserApproval = policiesSettings.RequiresUserApproval && !user.Approved; var requiresUserApproval = policies.RequiresUserApproval && !user.Approved;
if (!requiresConfirmedEmail && !requiresUserApproval) if (!requiresConfirmedEmail && !requiresUserApproval)
{ {
signInManager.AuthenticationScheme = Scheme; signInManager.AuthenticationScheme = Scheme;

View file

@ -5,6 +5,7 @@ using BTCPayApp.CommonServer.Models;
using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Configuration;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Fido2; using BTCPayServer.Fido2;
using BTCPayServer.Logging; using BTCPayServer.Logging;
@ -18,7 +19,6 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -33,14 +33,15 @@ public partial class AppApiController(
EventAggregator eventAggregator, EventAggregator eventAggregator,
SignInManager<ApplicationUser> signInManager, SignInManager<ApplicationUser> signInManager,
UserManager<ApplicationUser> userManager, UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager,
TimeProvider timeProvider, TimeProvider timeProvider,
ISettingsRepository settingsRepository, SettingsRepository settingsRepository,
UriResolver uriResolver, UriResolver uriResolver,
DefaultRulesCollection defaultRules, DefaultRulesCollection defaultRules,
RateFetcher rateFactory, RateFetcher rateFactory,
LinkGenerator linkGenerator,
UserLoginCodeService userLoginCodeService, UserLoginCodeService userLoginCodeService,
Logs logs, Logs logs,
BTCPayServerOptions btcpayOptions,
IOptionsMonitor<BearerTokenOptions> bearerTokenOptions) IOptionsMonitor<BearerTokenOptions> bearerTokenOptions)
: Controller : Controller
{ {