1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-10 07:38:13 -05:00

allow org user reg. when reg. is disabled

This commit is contained in:
Kyle Spearrin 2018-05-24 16:53:07 -04:00
parent 1b1ec7629b
commit 72e95e2a98
6 changed files with 49 additions and 26 deletions

View File

@ -45,7 +45,8 @@ namespace Bit.Api.Controllers
[AllowAnonymous] [AllowAnonymous]
public async Task PostRegister([FromBody]RegisterRequestModel model) public async Task PostRegister([FromBody]RegisterRequestModel model)
{ {
var result = await _userService.RegisterUserAsync(model.ToUser(), model.MasterPasswordHash); var result = await _userService.RegisterUserAsync(model.ToUser(), model.MasterPasswordHash,
model.Token, model.OrganizationUserId);
if(result.Succeeded) if(result.Succeeded)
{ {
return; return;

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Table; using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api namespace Bit.Core.Models.Api
@ -18,6 +19,8 @@ namespace Bit.Core.Models.Api
public string MasterPasswordHint { get; set; } public string MasterPasswordHint { get; set; }
public string Key { get; set; } public string Key { get; set; }
public KeysRequestModel Keys { get; set; } public KeysRequestModel Keys { get; set; }
public string Token { get; set; }
public Guid? OrganizationUserId { get; set; }
public User ToUser() public User ToUser()
{ {

View File

@ -18,7 +18,7 @@ namespace Bit.Core.Services
Task<User> GetUserByPrincipalAsync(ClaimsPrincipal principal); Task<User> GetUserByPrincipalAsync(ClaimsPrincipal principal);
Task<DateTime> GetAccountRevisionDateByIdAsync(Guid userId); Task<DateTime> GetAccountRevisionDateByIdAsync(Guid userId);
Task SaveUserAsync(User user, bool push = false); Task SaveUserAsync(User user, bool push = false);
Task<IdentityResult> RegisterUserAsync(User user, string masterPassword); Task<IdentityResult> RegisterUserAsync(User user, string masterPassword, string token, Guid? orgUserId);
Task SendMasterPasswordHintAsync(string email); Task SendMasterPasswordHintAsync(string email);
Task SendTwoFactorEmailAsync(User user); Task SendTwoFactorEmailAsync(User user);
Task<bool> VerifyTwoFactorEmailAsync(User user, string token); Task<bool> VerifyTwoFactorEmailAsync(User user, string token);

View File

@ -1012,26 +1012,7 @@ namespace Bit.Core.Services
throw new BadRequestException("You are already part of this organization."); throw new BadRequestException("You are already part of this organization.");
} }
var tokenValidationFailed = true; if(!CoreHelpers.UserInviteTokenIsValid(_dataProtector, token, user.Email, orgUser.Id))
try
{
var unprotectedData = _dataProtector.Unprotect(token);
var dataParts = unprotectedData.Split(' ');
if(dataParts.Length == 4 &&
dataParts[0] == "OrganizationUserInvite" &&
new Guid(dataParts[1]) == orgUser.Id &&
dataParts[2].Equals(user.Email, StringComparison.InvariantCultureIgnoreCase))
{
var creationTime = CoreHelpers.FromEpocMilliseconds(Convert.ToInt64(dataParts[3]));
tokenValidationFailed = creationTime.AddDays(5) < DateTime.UtcNow;
}
}
catch
{
tokenValidationFailed = true;
}
if(tokenValidationFailed)
{ {
throw new BadRequestException("Invalid token."); throw new BadRequestException("Invalid token.");
} }

View File

@ -18,6 +18,7 @@ using Bit.Core.Exceptions;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using System.IO; using System.IO;
using Newtonsoft.Json; using Newtonsoft.Json;
using Microsoft.AspNetCore.DataProtection;
namespace Bit.Core.Services namespace Bit.Core.Services
{ {
@ -38,6 +39,7 @@ namespace Bit.Core.Services
private readonly IEnumerable<IPasswordValidator<User>> _passwordValidators; private readonly IEnumerable<IPasswordValidator<User>> _passwordValidators;
private readonly ILicensingService _licenseService; private readonly ILicensingService _licenseService;
private readonly IEventService _eventService; private readonly IEventService _eventService;
private readonly IDataProtector _organizationServiceDataProtector;
private readonly CurrentContext _currentContext; private readonly CurrentContext _currentContext;
private readonly GlobalSettings _globalSettings; private readonly GlobalSettings _globalSettings;
@ -59,6 +61,7 @@ namespace Bit.Core.Services
ILogger<UserManager<User>> logger, ILogger<UserManager<User>> logger,
ILicensingService licenseService, ILicensingService licenseService,
IEventService eventService, IEventService eventService,
IDataProtectionProvider dataProtectionProvider,
CurrentContext currentContext, CurrentContext currentContext,
GlobalSettings globalSettings) GlobalSettings globalSettings)
: base( : base(
@ -84,6 +87,8 @@ namespace Bit.Core.Services
_passwordValidators = passwordValidators; _passwordValidators = passwordValidators;
_licenseService = licenseService; _licenseService = licenseService;
_eventService = eventService; _eventService = eventService;
_organizationServiceDataProtector = dataProtectionProvider.CreateProtector(
"OrganizationServiceDataProtector");
_currentContext = currentContext; _currentContext = currentContext;
_globalSettings = globalSettings; _globalSettings = globalSettings;
} }
@ -204,11 +209,19 @@ namespace Bit.Core.Services
await _mailService.SendVerifyDeleteEmailAsync(user.Email, user.Id, token); await _mailService.SendVerifyDeleteEmailAsync(user.Email, user.Id, token);
} }
public async Task<IdentityResult> RegisterUserAsync(User user, string masterPassword) public async Task<IdentityResult> RegisterUserAsync(User user, string masterPassword,
string token, Guid? orgUserId)
{ {
if(_globalSettings.DisableUserRegistration) var tokenValid = false;
if(!string.IsNullOrWhiteSpace(token) && orgUserId.HasValue)
{ {
throw new BadRequestException("Registration has been disabled by the system administrator."); tokenValid = CoreHelpers.UserInviteTokenIsValid(_organizationServiceDataProtector, token,
user.Email, orgUserId.Value);
}
if(_globalSettings.DisableUserRegistration && !tokenValid)
{
throw new BadRequestException("Open registration has been disabled by the system administrator.");
} }
var result = await base.CreateAsync(user, masterPassword); var result = await base.CreateAsync(user, masterPassword);

View File

@ -13,6 +13,7 @@ using System.Text.RegularExpressions;
using Dapper; using Dapper;
using System.Globalization; using System.Globalization;
using System.Web; using System.Web;
using Microsoft.AspNetCore.DataProtection;
namespace Bit.Core.Utilities namespace Bit.Core.Utilities
{ {
@ -452,5 +453,29 @@ namespace Bit.Core.Utilities
} }
return new Uri(string.Format("{0}?{1}", baseUri, queryCollection), uriKind); return new Uri(string.Format("{0}?{1}", baseUri, queryCollection), uriKind);
} }
public static bool UserInviteTokenIsValid(IDataProtector protector, string token,
string userEmail, Guid orgUserId)
{
var invalid = true;
try
{
var unprotectedData = protector.Unprotect(token);
var dataParts = unprotectedData.Split(' ');
if(dataParts.Length == 4 && dataParts[0] == "OrganizationUserInvite" &&
new Guid(dataParts[1]) == orgUserId &&
dataParts[2].Equals(userEmail, StringComparison.InvariantCultureIgnoreCase))
{
var creationTime = FromEpocMilliseconds(Convert.ToInt64(dataParts[3]));
invalid = creationTime.AddDays(5) < DateTime.UtcNow;
}
}
catch
{
invalid = true;
}
return !invalid;
}
} }
} }