1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 23:52:50 -05:00

[PM-1188] Server owner auth migration (#2825)

* [PM-1188] add sso project to auth

* [PM-1188] move sso api models to auth

* [PM-1188] fix sso api model namespace & imports

* [PM-1188] move core files to auth

* [PM-1188] fix core sso namespace & models

* [PM-1188] move sso repository files to auth

* [PM-1188] fix sso repo files namespace & imports

* [PM-1188] move sso sql files to auth folder

* [PM-1188] move sso test files to auth folders

* [PM-1188] fix sso tests namespace & imports

* [PM-1188] move auth api files to auth folder

* [PM-1188] fix auth api files namespace & imports

* [PM-1188] move auth core files to auth folder

* [PM-1188] fix auth core files namespace & imports

* [PM-1188] move auth email templates to auth folder

* [PM-1188] move auth email folder back into shared directory

* [PM-1188] fix auth email names

* [PM-1188] move auth core models to auth folder

* [PM-1188] fix auth model namespace & imports

* [PM-1188] add entire Identity project to auth codeowners

* [PM-1188] fix auth orm files namespace & imports

* [PM-1188] move auth orm files to auth folder

* [PM-1188] move auth sql files to auth folder

* [PM-1188] move auth tests to auth folder

* [PM-1188] fix auth test files namespace & imports

* [PM-1188] move emergency access api files to auth folder

* [PM-1188] fix emergencyaccess api files namespace & imports

* [PM-1188] move emergency access core files to auth folder

* [PM-1188] fix emergency access core files namespace & imports

* [PM-1188] move emergency access orm files to auth folder

* [PM-1188] fix emergency access orm files namespace & imports

* [PM-1188] move emergency access sql files to auth folder

* [PM-1188] move emergencyaccess test files to auth folder

* [PM-1188] fix emergency access test files namespace & imports

* [PM-1188] move captcha files to auth folder

* [PM-1188] fix captcha files namespace & imports

* [PM-1188] move auth admin files into auth folder

* [PM-1188] fix admin auth files namespace & imports
- configure mvc to look in auth folders for views

* [PM-1188] remove extra imports and formatting

* [PM-1188] fix ef auth model imports

* [PM-1188] fix DatabaseContextModelSnapshot paths

* [PM-1188] fix grant import in ef

* [PM-1188] update sqlproj

* [PM-1188] move missed sqlproj files

* [PM-1188] move auth ef models out of auth folder

* [PM-1188] fix auth ef models namespace

* [PM-1188] remove auth ef models unused imports

* [PM-1188] fix imports for auth ef models

* [PM-1188] fix more ef model imports

* [PM-1188] fix file encodings
This commit is contained in:
Jake Fink
2023-04-14 13:25:56 -04:00
committed by GitHub
parent 2529c5b36f
commit 88dd745070
332 changed files with 704 additions and 522 deletions

View File

@ -1,18 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Api.Models.Public;
public abstract class AssociationWithPermissionsBaseModel
{
/// <summary>
/// The associated object's unique identifier.
/// </summary>
/// <example>bfbc8338-e329-4dc0-b0c9-317c2ebf1a09</example>
[Required]
public Guid? Id { get; set; }
/// <summary>
/// When true, the read only permission will not allow the user or group to make changes to items.
/// </summary>
[Required]
public bool? ReadOnly { get; set; }
}

View File

@ -1,15 +0,0 @@
using Bit.Core.Models.Data;
namespace Bit.Api.Models.Public.Request;
public class AssociationWithPermissionsRequestModel : AssociationWithPermissionsBaseModel
{
public CollectionAccessSelection ToSelectionReadOnly()
{
return new CollectionAccessSelection
{
Id = Id.Value,
ReadOnly = ReadOnly.Value
};
}
}

View File

@ -1,4 +1,5 @@
using Bit.Core.Entities;
using Bit.Api.Auth.Models.Public.Request;
using Bit.Core.Entities;
namespace Bit.Api.Models.Public.Request;

View File

@ -1,4 +1,5 @@
using Bit.Core.Entities;
using Bit.Api.Auth.Models.Public.Request;
using Bit.Core.Entities;
namespace Bit.Api.Models.Public.Request;

View File

@ -1,4 +1,5 @@
using Bit.Core.Entities;
using Bit.Api.Auth.Models.Public.Request;
using Bit.Core.Entities;
namespace Bit.Api.Models.Public.Request;

View File

@ -1,16 +0,0 @@
using Bit.Core.Models.Data;
namespace Bit.Api.Models.Public.Response;
public class AssociationWithPermissionsResponseModel : AssociationWithPermissionsBaseModel
{
public AssociationWithPermissionsResponseModel(CollectionAccessSelection selection)
{
if (selection == null)
{
throw new ArgumentNullException(nameof(selection));
}
Id = selection.Id;
ReadOnly = selection.ReadOnly;
}
}

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using Bit.Api.Auth.Models.Public.Response;
using Bit.Core.Entities;
using Bit.Core.Models.Data;

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using Bit.Api.Auth.Models.Public.Response;
using Bit.Core.Entities;
using Bit.Core.Models.Data;

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using Bit.Api.Auth.Models.Public.Response;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Data;

View File

@ -1,11 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Api.Models.Request.Accounts;
public class DeleteRecoverRequestModel
{
[Required]
[EmailAddress]
[StringLength(256)]
public string Email { get; set; }
}

View File

@ -1,19 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
namespace Bit.Api.Models.Request.Accounts;
public class EmailRequestModel : SecretVerificationRequestModel
{
[Required]
[StrictEmailAddress]
[StringLength(256)]
public string NewEmail { get; set; }
[Required]
[StringLength(300)]
public string NewMasterPasswordHash { get; set; }
[Required]
public string Token { get; set; }
[Required]
public string Key { get; set; }
}

View File

@ -1,12 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
namespace Bit.Api.Models.Request.Accounts;
public class EmailTokenRequestModel : SecretVerificationRequestModel
{
[Required]
[StrictEmailAddress]
[StringLength(256)]
public string NewEmail { get; set; }
}

View File

@ -1,25 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Utilities;
namespace Bit.Api.Models.Request.Accounts;
public class KdfRequestModel : PasswordRequestModel, IValidatableObject
{
[Required]
public KdfType? Kdf { get; set; }
[Required]
public int? KdfIterations { get; set; }
public int? KdfMemory { get; set; }
public int? KdfParallelism { get; set; }
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Kdf.HasValue && KdfIterations.HasValue)
{
return KdfSettingsValidator.Validate(Kdf.Value, KdfIterations.Value, KdfMemory, KdfParallelism);
}
return Enumerable.Empty<ValidationResult>();
}
}

View File

@ -1,4 +1,5 @@
using Bit.Core.Enums;
using Bit.Api.Auth.Models.Request.Accounts;
using Bit.Core.Enums;
namespace Bit.Api.Models.Request.Accounts;

View File

@ -1,11 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Api.Models.Request.Accounts;
public class PasswordHintRequestModel
{
[Required]
[EmailAddress]
[StringLength(256)]
public string Email { get; set; }
}

View File

@ -1,14 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Api.Models.Request.Accounts;
public class PasswordRequestModel : SecretVerificationRequestModel
{
[Required]
[StringLength(300)]
public string NewMasterPasswordHash { get; set; }
[StringLength(50)]
public string MasterPasswordHint { get; set; }
[Required]
public string Key { get; set; }
}

View File

@ -1,12 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Api.Models.Request.Accounts;
public class RegenerateTwoFactorRequestModel
{
[Required]
public string MasterPasswordHash { get; set; }
[Required]
[StringLength(50)]
public string Token { get; set; }
}

View File

@ -1,20 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Api.Models.Request.Accounts;
public class SecretVerificationRequestModel : IValidatableObject
{
[StringLength(300)]
public string MasterPasswordHash { get; set; }
public string OTP { get; set; }
public string AuthRequestAccessCode { get; set; }
public string Secret => !string.IsNullOrEmpty(MasterPasswordHash) ? MasterPasswordHash : OTP;
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrEmpty(Secret) && string.IsNullOrEmpty(AuthRequestAccessCode))
{
yield return new ValidationResult("MasterPasswordHash, OTP or AccessCode must be supplied.");
}
}
}

View File

@ -1,39 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api.Request.Accounts;
using Bit.Core.Utilities;
namespace Bit.Api.Models.Request.Accounts;
public class SetKeyConnectorKeyRequestModel : IValidatableObject
{
[Required]
public string Key { get; set; }
[Required]
public KeysRequestModel Keys { get; set; }
[Required]
public KdfType Kdf { get; set; }
[Required]
public int KdfIterations { get; set; }
public int? KdfMemory { get; set; }
public int? KdfParallelism { get; set; }
[Required]
public string OrgIdentifier { get; set; }
public User ToUser(User existingUser)
{
existingUser.Kdf = Kdf;
existingUser.KdfIterations = KdfIterations;
existingUser.KdfMemory = KdfMemory;
existingUser.KdfParallelism = KdfParallelism;
existingUser.Key = Key;
Keys.ToUser(existingUser);
return existingUser;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return KdfSettingsValidator.Validate(Kdf, KdfIterations, KdfMemory, KdfParallelism);
}
}

View File

@ -1,44 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api.Request.Accounts;
using Bit.Core.Utilities;
namespace Bit.Api.Models.Request.Accounts;
public class SetPasswordRequestModel : IValidatableObject
{
[Required]
[StringLength(300)]
public string MasterPasswordHash { get; set; }
[Required]
public string Key { get; set; }
[StringLength(50)]
public string MasterPasswordHint { get; set; }
[Required]
public KeysRequestModel Keys { get; set; }
[Required]
public KdfType Kdf { get; set; }
[Required]
public int KdfIterations { get; set; }
public int? KdfMemory { get; set; }
public int? KdfParallelism { get; set; }
public string OrgIdentifier { get; set; }
public User ToUser(User existingUser)
{
existingUser.MasterPasswordHint = MasterPasswordHint;
existingUser.Kdf = Kdf;
existingUser.KdfIterations = KdfIterations;
existingUser.KdfMemory = KdfMemory;
existingUser.KdfParallelism = KdfParallelism;
existingUser.Key = Key;
Keys.ToUser(existingUser);
return existingUser;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return KdfSettingsValidator.Validate(Kdf, KdfIterations, KdfMemory, KdfParallelism);
}
}

View File

@ -1,20 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Api.Vault.Models.Request;
namespace Bit.Api.Models.Request.Accounts;
public class UpdateKeyRequestModel
{
[Required]
[StringLength(300)]
public string MasterPasswordHash { get; set; }
[Required]
public IEnumerable<CipherWithIdRequestModel> Ciphers { get; set; }
[Required]
public IEnumerable<FolderWithIdRequestModel> Folders { get; set; }
public IEnumerable<SendWithIdRequestModel> Sends { get; set; }
[Required]
public string PrivateKey { get; set; }
[Required]
public string Key { get; set; }
}

View File

@ -1,20 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Entities;
namespace Bit.Api.Models.Request.Accounts;
public class UpdateProfileRequestModel
{
[StringLength(50)]
public string Name { get; set; }
[StringLength(50)]
[Obsolete("Changes will be made via the 'password' endpoint going forward.")]
public string MasterPasswordHint { get; set; }
public User ToUser(User existingUser)
{
existingUser.Name = Name;
existingUser.MasterPasswordHint = string.IsNullOrWhiteSpace(MasterPasswordHint) ? null : MasterPasswordHint;
return existingUser;
}
}

View File

@ -1,10 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Api.Models.Request.Organizations;
namespace Bit.Api.Models.Request.Accounts;
public class UpdateTempPasswordRequestModel : OrganizationUserResetPasswordRequestModel
{
[StringLength(50)]
public string MasterPasswordHint { get; set; }
}

View File

@ -1,11 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Api.Models.Request.Accounts;
public class VerifyDeleteRecoverRequestModel
{
[Required]
public string UserId { get; set; }
[Required]
public string Token { get; set; }
}

View File

@ -1,11 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Api.Models.Request.Accounts;
public class VerifyEmailRequestModel
{
[Required]
public string UserId { get; set; }
[Required]
public string Token { get; set; }
}

View File

@ -1,9 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Api.Models.Request.Accounts;
public class VerifyOTPRequestModel
{
[Required]
public string OTP { get; set; }
}

View File

@ -1,30 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Newtonsoft.Json;
namespace Bit.Api.Models.Request;
public class AuthRequestCreateRequestModel
{
[Required]
public string Email { get; set; }
[Required]
public string PublicKey { get; set; }
[Required]
public string DeviceIdentifier { get; set; }
[Required]
[StringLength(25)]
public string AccessCode { get; set; }
[Required]
public AuthRequestType? Type { get; set; }
}
public class AuthRequestUpdateRequestModel
{
public string Key { get; set; }
public string MasterPasswordHash { get; set; }
[Required]
public string DeviceIdentifier { get; set; }
[Required]
public bool RequestApproved { get; set; }
}

View File

@ -1,48 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Utilities;
namespace Bit.Api.Models.Request;
public class EmergencyAccessInviteRequestModel
{
[Required]
[StrictEmailAddress]
[StringLength(256)]
public string Email { get; set; }
[Required]
public EmergencyAccessType? Type { get; set; }
[Required]
public int WaitTimeDays { get; set; }
}
public class EmergencyAccessUpdateRequestModel
{
[Required]
public EmergencyAccessType Type { get; set; }
[Required]
public int WaitTimeDays { get; set; }
public string KeyEncrypted { get; set; }
public EmergencyAccess ToEmergencyAccess(EmergencyAccess existingEmergencyAccess)
{
// Ensure we only set keys for a confirmed emergency access.
if (!string.IsNullOrWhiteSpace(existingEmergencyAccess.KeyEncrypted) && !string.IsNullOrWhiteSpace(KeyEncrypted))
{
existingEmergencyAccess.KeyEncrypted = KeyEncrypted;
}
existingEmergencyAccess.Type = Type;
existingEmergencyAccess.WaitTimeDays = WaitTimeDays;
return existingEmergencyAccess;
}
}
public class EmergencyAccessPasswordRequestModel
{
[Required]
[StringLength(300)]
public string NewMasterPasswordHash { get; set; }
[Required]
public string Key { get; set; }
}

View File

@ -1,226 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Services;
using Bit.Core.Sso;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
namespace Bit.Api.Models.Request.Organizations;
public class OrganizationSsoRequestModel
{
[Required]
public bool Enabled { get; set; }
[StringLength(50)]
public string Identifier { get; set; }
[Required]
public SsoConfigurationDataRequest Data { get; set; }
public SsoConfig ToSsoConfig(Guid organizationId)
{
return ToSsoConfig(new SsoConfig { OrganizationId = organizationId });
}
public SsoConfig ToSsoConfig(SsoConfig existingConfig)
{
existingConfig.Enabled = Enabled;
var configurationData = Data.ToConfigurationData();
existingConfig.SetData(configurationData);
return existingConfig;
}
}
public class SsoConfigurationDataRequest : IValidatableObject
{
public SsoConfigurationDataRequest() { }
[Required]
public SsoType ConfigType { get; set; }
public bool KeyConnectorEnabled { get; set; }
public string KeyConnectorUrl { get; set; }
// OIDC
public string Authority { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string MetadataAddress { get; set; }
public OpenIdConnectRedirectBehavior RedirectBehavior { get; set; }
public bool? GetClaimsFromUserInfoEndpoint { get; set; }
public string AdditionalScopes { get; set; }
public string AdditionalUserIdClaimTypes { get; set; }
public string AdditionalEmailClaimTypes { get; set; }
public string AdditionalNameClaimTypes { get; set; }
public string AcrValues { get; set; }
public string ExpectedReturnAcrValue { get; set; }
// SAML2 SP
public Saml2NameIdFormat SpNameIdFormat { get; set; }
public string SpOutboundSigningAlgorithm { get; set; }
public Saml2SigningBehavior SpSigningBehavior { get; set; }
public bool? SpWantAssertionsSigned { get; set; }
public bool? SpValidateCertificates { get; set; }
public string SpMinIncomingSigningAlgorithm { get; set; }
// SAML2 IDP
public string IdpEntityId { get; set; }
public Saml2BindingType IdpBindingType { get; set; }
public string IdpSingleSignOnServiceUrl { get; set; }
public string IdpSingleLogoutServiceUrl { get; set; }
public string IdpArtifactResolutionServiceUrl { get => null; set { /*IGNORE*/ } }
public string IdpX509PublicCert { get; set; }
public string IdpOutboundSigningAlgorithm { get; set; }
public bool? IdpAllowUnsolicitedAuthnResponse { get; set; }
public bool? IdpDisableOutboundLogoutRequests { get; set; }
public bool? IdpWantAuthnRequestsSigned { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext context)
{
var i18nService = context.GetService(typeof(II18nService)) as I18nService;
if (ConfigType == SsoType.OpenIdConnect)
{
if (string.IsNullOrWhiteSpace(Authority))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("AuthorityValidationError"),
new[] { nameof(Authority) });
}
if (string.IsNullOrWhiteSpace(ClientId))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("ClientIdValidationError"),
new[] { nameof(ClientId) });
}
if (string.IsNullOrWhiteSpace(ClientSecret))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("ClientSecretValidationError"),
new[] { nameof(ClientSecret) });
}
}
else if (ConfigType == SsoType.Saml2)
{
if (string.IsNullOrWhiteSpace(IdpEntityId))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("IdpEntityIdValidationError"),
new[] { nameof(IdpEntityId) });
}
if (!Uri.IsWellFormedUriString(IdpEntityId, UriKind.Absolute) && string.IsNullOrWhiteSpace(IdpSingleSignOnServiceUrl))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("IdpSingleSignOnServiceUrlValidationError"),
new[] { nameof(IdpSingleSignOnServiceUrl) });
}
if (InvalidServiceUrl(IdpSingleSignOnServiceUrl))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("IdpSingleSignOnServiceUrlInvalid"),
new[] { nameof(IdpSingleSignOnServiceUrl) });
}
if (InvalidServiceUrl(IdpSingleLogoutServiceUrl))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("IdpSingleLogoutServiceUrlInvalid"),
new[] { nameof(IdpSingleLogoutServiceUrl) });
}
if (!string.IsNullOrWhiteSpace(IdpX509PublicCert))
{
// Validate the certificate is in a valid format
ValidationResult failedResult = null;
try
{
var certData = CoreHelpers.Base64UrlDecode(StripPemCertificateElements(IdpX509PublicCert));
new X509Certificate2(certData);
}
catch (FormatException)
{
failedResult = new ValidationResult(i18nService.GetLocalizedHtmlString("IdpX509PublicCertInvalidFormatValidationError"),
new[] { nameof(IdpX509PublicCert) });
}
catch (CryptographicException cryptoEx)
{
failedResult = new ValidationResult(i18nService.GetLocalizedHtmlString("IdpX509PublicCertCryptographicExceptionValidationError", cryptoEx.Message),
new[] { nameof(IdpX509PublicCert) });
}
catch (Exception ex)
{
failedResult = new ValidationResult(i18nService.GetLocalizedHtmlString("IdpX509PublicCertValidationError", ex.Message),
new[] { nameof(IdpX509PublicCert) });
}
if (failedResult != null)
{
yield return failedResult;
}
}
}
}
public SsoConfigurationData ToConfigurationData()
{
return new SsoConfigurationData
{
ConfigType = ConfigType,
KeyConnectorEnabled = KeyConnectorEnabled,
KeyConnectorUrl = KeyConnectorUrl,
Authority = Authority,
ClientId = ClientId,
ClientSecret = ClientSecret,
MetadataAddress = MetadataAddress,
GetClaimsFromUserInfoEndpoint = GetClaimsFromUserInfoEndpoint.GetValueOrDefault(),
RedirectBehavior = RedirectBehavior,
IdpEntityId = IdpEntityId,
IdpBindingType = IdpBindingType,
IdpSingleSignOnServiceUrl = IdpSingleSignOnServiceUrl,
IdpSingleLogoutServiceUrl = IdpSingleLogoutServiceUrl,
IdpArtifactResolutionServiceUrl = null,
IdpX509PublicCert = StripPemCertificateElements(IdpX509PublicCert),
IdpOutboundSigningAlgorithm = IdpOutboundSigningAlgorithm,
IdpAllowUnsolicitedAuthnResponse = IdpAllowUnsolicitedAuthnResponse.GetValueOrDefault(),
IdpDisableOutboundLogoutRequests = IdpDisableOutboundLogoutRequests.GetValueOrDefault(),
IdpWantAuthnRequestsSigned = IdpWantAuthnRequestsSigned.GetValueOrDefault(),
SpNameIdFormat = SpNameIdFormat,
SpOutboundSigningAlgorithm = SpOutboundSigningAlgorithm ?? SamlSigningAlgorithms.Sha256,
SpSigningBehavior = SpSigningBehavior,
SpWantAssertionsSigned = SpWantAssertionsSigned.GetValueOrDefault(),
SpValidateCertificates = SpValidateCertificates.GetValueOrDefault(),
SpMinIncomingSigningAlgorithm = SpMinIncomingSigningAlgorithm,
AdditionalScopes = AdditionalScopes,
AdditionalUserIdClaimTypes = AdditionalUserIdClaimTypes,
AdditionalEmailClaimTypes = AdditionalEmailClaimTypes,
AdditionalNameClaimTypes = AdditionalNameClaimTypes,
AcrValues = AcrValues,
ExpectedReturnAcrValue = ExpectedReturnAcrValue,
};
}
private string StripPemCertificateElements(string certificateText)
{
if (string.IsNullOrWhiteSpace(certificateText))
{
return null;
}
return Regex.Replace(certificateText,
@"(((BEGIN|END) CERTIFICATE)|([\-\n\r\t\s\f]))",
string.Empty,
RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
}
private bool InvalidServiceUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return false;
}
if (!url.StartsWith("http://") && !url.StartsWith("https://"))
{
return true;
}
return Regex.IsMatch(url, "[<>\"]");
}
}

View File

@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Bit.Api.Models.Request.Accounts;
using Bit.Api.Auth.Models.Request.Accounts;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Data;

View File

@ -1,274 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Api.Models.Request.Accounts;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Utilities;
using Fido2NetLib;
namespace Bit.Api.Models.Request;
public class UpdateTwoFactorAuthenticatorRequestModel : SecretVerificationRequestModel
{
[Required]
[StringLength(50)]
public string Token { get; set; }
[Required]
[StringLength(50)]
public string Key { get; set; }
public User ToUser(User extistingUser)
{
var providers = extistingUser.GetTwoFactorProviders();
if (providers == null)
{
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
}
else if (providers.ContainsKey(TwoFactorProviderType.Authenticator))
{
providers.Remove(TwoFactorProviderType.Authenticator);
}
providers.Add(TwoFactorProviderType.Authenticator, new TwoFactorProvider
{
MetaData = new Dictionary<string, object> { ["Key"] = Key },
Enabled = true
});
extistingUser.SetTwoFactorProviders(providers);
return extistingUser;
}
}
public class UpdateTwoFactorDuoRequestModel : SecretVerificationRequestModel, IValidatableObject
{
[Required]
[StringLength(50)]
public string IntegrationKey { get; set; }
[Required]
[StringLength(50)]
public string SecretKey { get; set; }
[Required]
[StringLength(50)]
public string Host { get; set; }
public User ToUser(User extistingUser)
{
var providers = extistingUser.GetTwoFactorProviders();
if (providers == null)
{
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
}
else if (providers.ContainsKey(TwoFactorProviderType.Duo))
{
providers.Remove(TwoFactorProviderType.Duo);
}
providers.Add(TwoFactorProviderType.Duo, new TwoFactorProvider
{
MetaData = new Dictionary<string, object>
{
["SKey"] = SecretKey,
["IKey"] = IntegrationKey,
["Host"] = Host
},
Enabled = true
});
extistingUser.SetTwoFactorProviders(providers);
return extistingUser;
}
public Organization ToOrganization(Organization extistingOrg)
{
var providers = extistingOrg.GetTwoFactorProviders();
if (providers == null)
{
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
}
else if (providers.ContainsKey(TwoFactorProviderType.OrganizationDuo))
{
providers.Remove(TwoFactorProviderType.OrganizationDuo);
}
providers.Add(TwoFactorProviderType.OrganizationDuo, new TwoFactorProvider
{
MetaData = new Dictionary<string, object>
{
["SKey"] = SecretKey,
["IKey"] = IntegrationKey,
["Host"] = Host
},
Enabled = true
});
extistingOrg.SetTwoFactorProviders(providers);
return extistingOrg;
}
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!DuoApi.ValidHost(Host))
{
yield return new ValidationResult("Host is invalid.", new string[] { nameof(Host) });
}
}
}
public class UpdateTwoFactorYubicoOtpRequestModel : SecretVerificationRequestModel, IValidatableObject
{
public string Key1 { get; set; }
public string Key2 { get; set; }
public string Key3 { get; set; }
public string Key4 { get; set; }
public string Key5 { get; set; }
[Required]
public bool? Nfc { get; set; }
public User ToUser(User extistingUser)
{
var providers = extistingUser.GetTwoFactorProviders();
if (providers == null)
{
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
}
else if (providers.ContainsKey(TwoFactorProviderType.YubiKey))
{
providers.Remove(TwoFactorProviderType.YubiKey);
}
providers.Add(TwoFactorProviderType.YubiKey, new TwoFactorProvider
{
MetaData = new Dictionary<string, object>
{
["Key1"] = FormatKey(Key1),
["Key2"] = FormatKey(Key2),
["Key3"] = FormatKey(Key3),
["Key4"] = FormatKey(Key4),
["Key5"] = FormatKey(Key5),
["Nfc"] = Nfc.Value
},
Enabled = true
});
extistingUser.SetTwoFactorProviders(providers);
return extistingUser;
}
private string FormatKey(string keyValue)
{
if (string.IsNullOrWhiteSpace(keyValue))
{
return null;
}
return keyValue.Substring(0, 12);
}
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(Key1) && string.IsNullOrWhiteSpace(Key2) && string.IsNullOrWhiteSpace(Key3) &&
string.IsNullOrWhiteSpace(Key4) && string.IsNullOrWhiteSpace(Key5))
{
yield return new ValidationResult("A key is required.", new string[] { nameof(Key1) });
}
if (!string.IsNullOrWhiteSpace(Key1) && Key1.Length < 12)
{
yield return new ValidationResult("Key 1 in invalid.", new string[] { nameof(Key1) });
}
if (!string.IsNullOrWhiteSpace(Key2) && Key2.Length < 12)
{
yield return new ValidationResult("Key 2 in invalid.", new string[] { nameof(Key2) });
}
if (!string.IsNullOrWhiteSpace(Key3) && Key3.Length < 12)
{
yield return new ValidationResult("Key 3 in invalid.", new string[] { nameof(Key3) });
}
if (!string.IsNullOrWhiteSpace(Key4) && Key4.Length < 12)
{
yield return new ValidationResult("Key 4 in invalid.", new string[] { nameof(Key4) });
}
if (!string.IsNullOrWhiteSpace(Key5) && Key5.Length < 12)
{
yield return new ValidationResult("Key 5 in invalid.", new string[] { nameof(Key5) });
}
}
}
public class TwoFactorEmailRequestModel : SecretVerificationRequestModel
{
[Required]
[EmailAddress]
[StringLength(256)]
public string Email { get; set; }
public string AuthRequestId { get; set; }
public User ToUser(User extistingUser)
{
var providers = extistingUser.GetTwoFactorProviders();
if (providers == null)
{
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
}
else if (providers.ContainsKey(TwoFactorProviderType.Email))
{
providers.Remove(TwoFactorProviderType.Email);
}
providers.Add(TwoFactorProviderType.Email, new TwoFactorProvider
{
MetaData = new Dictionary<string, object> { ["Email"] = Email.ToLowerInvariant() },
Enabled = true
});
extistingUser.SetTwoFactorProviders(providers);
return extistingUser;
}
}
public class TwoFactorWebAuthnRequestModel : TwoFactorWebAuthnDeleteRequestModel
{
[Required]
public AuthenticatorAttestationRawResponse DeviceResponse { get; set; }
public string Name { get; set; }
}
public class TwoFactorWebAuthnDeleteRequestModel : SecretVerificationRequestModel, IValidatableObject
{
[Required]
public int? Id { get; set; }
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
foreach (var validationResult in base.Validate(validationContext))
{
yield return validationResult;
}
if (!Id.HasValue || Id < 0 || Id > 5)
{
yield return new ValidationResult("Invalid Key Id", new string[] { nameof(Id) });
}
}
}
public class UpdateTwoFactorEmailRequestModel : TwoFactorEmailRequestModel
{
[Required]
[StringLength(50)]
public string Token { get; set; }
}
public class TwoFactorProviderRequestModel : SecretVerificationRequestModel
{
[Required]
public TwoFactorProviderType? Type { get; set; }
}
public class TwoFactorRecoveryRequestModel : TwoFactorEmailRequestModel
{
[Required]
[StringLength(32)]
public string RecoveryCode { get; set; }
}

View File

@ -1,41 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Bit.Core.Entities;
using Bit.Core.Models.Api;
namespace Bit.Api.Models.Response;
public class AuthRequestResponseModel : ResponseModel
{
public AuthRequestResponseModel(AuthRequest authRequest, string vaultUri, string obj = "auth-request")
: base(obj)
{
if (authRequest == null)
{
throw new ArgumentNullException(nameof(authRequest));
}
Id = authRequest.Id.ToString();
PublicKey = authRequest.PublicKey;
RequestDeviceType = authRequest.RequestDeviceType.GetType().GetMember(authRequest.RequestDeviceType.ToString())
.FirstOrDefault()?.GetCustomAttribute<DisplayAttribute>()?.GetName();
RequestIpAddress = authRequest.RequestIpAddress;
Key = authRequest.Key;
MasterPasswordHash = authRequest.MasterPasswordHash;
CreationDate = authRequest.CreationDate;
RequestApproved = authRequest.Approved ?? false;
Origin = new Uri(vaultUri).Host;
ResponseDate = authRequest.ResponseDate;
}
public string Id { get; set; }
public string PublicKey { get; set; }
public string RequestDeviceType { get; set; }
public string RequestIpAddress { get; set; }
public string Key { get; set; }
public string MasterPasswordHash { get; set; }
public DateTime CreationDate { get; set; }
public DateTime? ResponseDate { get; set; }
public bool RequestApproved { get; set; }
public string Origin { get; set; }
}

View File

@ -1,126 +0,0 @@
using Bit.Api.Vault.Models.Response;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
using Bit.Core.Models.Data;
using Bit.Core.Settings;
using Bit.Core.Vault.Models.Data;
namespace Bit.Api.Models.Response;
public class EmergencyAccessResponseModel : ResponseModel
{
public EmergencyAccessResponseModel(EmergencyAccess emergencyAccess, string obj = "emergencyAccess") : base(obj)
{
if (emergencyAccess == null)
{
throw new ArgumentNullException(nameof(emergencyAccess));
}
Id = emergencyAccess.Id.ToString();
Status = emergencyAccess.Status;
Type = emergencyAccess.Type;
WaitTimeDays = emergencyAccess.WaitTimeDays;
}
public EmergencyAccessResponseModel(EmergencyAccessDetails emergencyAccess, string obj = "emergencyAccess") : base(obj)
{
if (emergencyAccess == null)
{
throw new ArgumentNullException(nameof(emergencyAccess));
}
Id = emergencyAccess.Id.ToString();
Status = emergencyAccess.Status;
Type = emergencyAccess.Type;
WaitTimeDays = emergencyAccess.WaitTimeDays;
}
public string Id { get; private set; }
public EmergencyAccessStatusType Status { get; private set; }
public EmergencyAccessType Type { get; private set; }
public int WaitTimeDays { get; private set; }
}
public class EmergencyAccessGranteeDetailsResponseModel : EmergencyAccessResponseModel
{
public EmergencyAccessGranteeDetailsResponseModel(EmergencyAccessDetails emergencyAccess)
: base(emergencyAccess, "emergencyAccessGranteeDetails")
{
if (emergencyAccess == null)
{
throw new ArgumentNullException(nameof(emergencyAccess));
}
GranteeId = emergencyAccess.GranteeId.ToString();
Email = emergencyAccess.GranteeEmail;
Name = emergencyAccess.GranteeName;
AvatarColor = emergencyAccess.GranteeAvatarColor;
}
public string GranteeId { get; private set; }
public string Name { get; private set; }
public string Email { get; private set; }
public string AvatarColor { get; private set; }
}
public class EmergencyAccessGrantorDetailsResponseModel : EmergencyAccessResponseModel
{
public EmergencyAccessGrantorDetailsResponseModel(EmergencyAccessDetails emergencyAccess)
: base(emergencyAccess, "emergencyAccessGrantorDetails")
{
if (emergencyAccess == null)
{
throw new ArgumentNullException(nameof(emergencyAccess));
}
GrantorId = emergencyAccess.GrantorId.ToString();
Email = emergencyAccess.GrantorEmail;
Name = emergencyAccess.GrantorName;
AvatarColor = emergencyAccess.GrantorAvatarColor;
}
public string GrantorId { get; private set; }
public string Name { get; private set; }
public string Email { get; private set; }
public string AvatarColor { get; private set; }
}
public class EmergencyAccessTakeoverResponseModel : ResponseModel
{
public EmergencyAccessTakeoverResponseModel(EmergencyAccess emergencyAccess, User grantor, string obj = "emergencyAccessTakeover") : base(obj)
{
if (emergencyAccess == null)
{
throw new ArgumentNullException(nameof(emergencyAccess));
}
KeyEncrypted = emergencyAccess.KeyEncrypted;
Kdf = grantor.Kdf;
KdfIterations = grantor.KdfIterations;
KdfMemory = grantor.KdfMemory;
KdfParallelism = grantor.KdfParallelism;
}
public int KdfIterations { get; private set; }
public int? KdfMemory { get; private set; }
public int? KdfParallelism { get; private set; }
public KdfType Kdf { get; private set; }
public string KeyEncrypted { get; private set; }
}
public class EmergencyAccessViewResponseModel : ResponseModel
{
public EmergencyAccessViewResponseModel(
IGlobalSettings globalSettings,
EmergencyAccess emergencyAccess,
IEnumerable<CipherDetails> ciphers)
: base("emergencyAccessView")
{
KeyEncrypted = emergencyAccess.KeyEncrypted;
Ciphers = ciphers.Select(c => new CipherResponseModel(c, globalSettings));
}
public string KeyEncrypted { get; set; }
public IEnumerable<CipherResponseModel> Ciphers { get; set; }
}

View File

@ -1,45 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Models.Api;
using Bit.Core.Models.Data;
using Bit.Core.Settings;
namespace Bit.Api.Models.Response.Organizations;
public class OrganizationSsoResponseModel : ResponseModel
{
public OrganizationSsoResponseModel(Organization organization, GlobalSettings globalSettings,
SsoConfig config = null) : base("organizationSso")
{
if (config != null)
{
Enabled = config.Enabled;
Data = config.GetData();
}
Identifier = organization.Identifier;
Urls = new SsoUrls(organization.Id.ToString(), globalSettings);
}
public bool Enabled { get; set; }
public string Identifier { get; set; }
public SsoConfigurationData Data { get; set; }
public SsoUrls Urls { get; set; }
}
public class SsoUrls
{
public SsoUrls(string organizationId, GlobalSettings globalSettings)
{
CallbackPath = SsoConfigurationData.BuildCallbackPath(globalSettings.BaseServiceUri.Sso);
SignedOutCallbackPath = SsoConfigurationData.BuildSignedOutCallbackPath(globalSettings.BaseServiceUri.Sso);
SpEntityId = SsoConfigurationData.BuildSaml2ModulePath(globalSettings.BaseServiceUri.Sso);
SpMetadataUrl = SsoConfigurationData.BuildSaml2MetadataUrl(globalSettings.BaseServiceUri.Sso, organizationId);
SpAcsUrl = SsoConfigurationData.BuildSaml2AcsUrl(globalSettings.BaseServiceUri.Sso, organizationId);
}
public string CallbackPath { get; set; }
public string SignedOutCallbackPath { get; set; }
public string SpEntityId { get; set; }
public string SpMetadataUrl { get; set; }
public string SpAcsUrl { get; set; }
}

View File

@ -1,4 +1,5 @@
using Bit.Core.Enums;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Enums;
using Bit.Core.Enums.Provider;
using Bit.Core.Models.Api;
using Bit.Core.Models.Data;

View File

@ -1,34 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
using OtpNet;
namespace Bit.Api.Models.Response.TwoFactor;
public class TwoFactorAuthenticatorResponseModel : ResponseModel
{
public TwoFactorAuthenticatorResponseModel(User user)
: base("twoFactorAuthenticator")
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Authenticator);
if (provider?.MetaData?.ContainsKey("Key") ?? false)
{
Key = (string)provider.MetaData["Key"];
Enabled = provider.Enabled;
}
else
{
var key = KeyGeneration.GenerateRandomKey(20);
Key = Base32Encoding.ToString(key);
Enabled = false;
}
}
public bool Enabled { get; set; }
public string Key { get; set; }
}

View File

@ -1,65 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Models.Api;
namespace Bit.Api.Models.Response.TwoFactor;
public class TwoFactorDuoResponseModel : ResponseModel
{
private const string ResponseObj = "twoFactorDuo";
public TwoFactorDuoResponseModel(User user)
: base(ResponseObj)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo);
Build(provider);
}
public TwoFactorDuoResponseModel(Organization org)
: base(ResponseObj)
{
if (org == null)
{
throw new ArgumentNullException(nameof(org));
}
var provider = org.GetTwoFactorProvider(TwoFactorProviderType.OrganizationDuo);
Build(provider);
}
public bool Enabled { get; set; }
public string Host { get; set; }
public string SecretKey { get; set; }
public string IntegrationKey { get; set; }
private void Build(TwoFactorProvider provider)
{
if (provider?.MetaData != null && provider.MetaData.Count > 0)
{
Enabled = provider.Enabled;
if (provider.MetaData.ContainsKey("Host"))
{
Host = (string)provider.MetaData["Host"];
}
if (provider.MetaData.ContainsKey("SKey"))
{
SecretKey = (string)provider.MetaData["SKey"];
}
if (provider.MetaData.ContainsKey("IKey"))
{
IntegrationKey = (string)provider.MetaData["IKey"];
}
}
else
{
Enabled = false;
}
}
}

View File

@ -1,31 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
namespace Bit.Api.Models.Response.TwoFactor;
public class TwoFactorEmailResponseModel : ResponseModel
{
public TwoFactorEmailResponseModel(User user)
: base("twoFactorEmail")
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Email);
if (provider?.MetaData?.ContainsKey("Email") ?? false)
{
Email = (string)provider.MetaData["Email"];
Enabled = provider.Enabled;
}
else
{
Enabled = false;
}
}
public bool Enabled { get; set; }
public string Email { get; set; }
}

View File

@ -1,52 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Models.Api;
namespace Bit.Api.Models.Response.TwoFactor;
public class TwoFactorProviderResponseModel : ResponseModel
{
private const string ResponseObj = "twoFactorProvider";
public TwoFactorProviderResponseModel(TwoFactorProviderType type, TwoFactorProvider provider)
: base(ResponseObj)
{
if (provider == null)
{
throw new ArgumentNullException(nameof(provider));
}
Enabled = provider.Enabled;
Type = type;
}
public TwoFactorProviderResponseModel(TwoFactorProviderType type, User user)
: base(ResponseObj)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var provider = user.GetTwoFactorProvider(type);
Enabled = provider?.Enabled ?? false;
Type = type;
}
public TwoFactorProviderResponseModel(TwoFactorProviderType type, Organization organization)
: base(ResponseObj)
{
if (organization == null)
{
throw new ArgumentNullException(nameof(organization));
}
var provider = organization.GetTwoFactorProvider(type);
Enabled = provider?.Enabled ?? false;
Type = type;
}
public bool Enabled { get; set; }
public TwoFactorProviderType Type { get; set; }
}

View File

@ -1,20 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Models.Api;
namespace Bit.Api.Models.Response.TwoFactor;
public class TwoFactorRecoverResponseModel : ResponseModel
{
public TwoFactorRecoverResponseModel(User user)
: base("twoFactorRecover")
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
Code = user.TwoFactorRecoveryCode;
}
public string Code { get; set; }
}

View File

@ -1,41 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Models.Api;
namespace Bit.Api.Models.Response.TwoFactor;
public class TwoFactorWebAuthnResponseModel : ResponseModel
{
public TwoFactorWebAuthnResponseModel(User user)
: base("twoFactorWebAuthn")
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.WebAuthn);
Enabled = provider?.Enabled ?? false;
Keys = provider?.MetaData?
.Where(k => k.Key.StartsWith("Key"))
.Select(k => new KeyModel(k.Key, new TwoFactorProvider.WebAuthnData((dynamic)k.Value)));
}
public bool Enabled { get; set; }
public IEnumerable<KeyModel> Keys { get; set; }
public class KeyModel
{
public KeyModel(string id, TwoFactorProvider.WebAuthnData data)
{
Name = data.Name;
Id = Convert.ToInt32(id.Replace("Key", string.Empty));
Migrated = data.Migrated;
}
public string Name { get; set; }
public int Id { get; set; }
public bool Migrated { get; set; }
}
}

View File

@ -1,60 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
namespace Bit.Api.Models.Response.TwoFactor;
public class TwoFactorYubiKeyResponseModel : ResponseModel
{
public TwoFactorYubiKeyResponseModel(User user)
: base("twoFactorYubiKey")
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.YubiKey);
if (provider?.MetaData != null && provider.MetaData.Count > 0)
{
Enabled = provider.Enabled;
if (provider.MetaData.ContainsKey("Key1"))
{
Key1 = (string)provider.MetaData["Key1"];
}
if (provider.MetaData.ContainsKey("Key2"))
{
Key2 = (string)provider.MetaData["Key2"];
}
if (provider.MetaData.ContainsKey("Key3"))
{
Key3 = (string)provider.MetaData["Key3"];
}
if (provider.MetaData.ContainsKey("Key4"))
{
Key4 = (string)provider.MetaData["Key4"];
}
if (provider.MetaData.ContainsKey("Key5"))
{
Key5 = (string)provider.MetaData["Key5"];
}
if (provider.MetaData.ContainsKey("Nfc"))
{
Nfc = (bool)provider.MetaData["Nfc"];
}
}
else
{
Enabled = false;
}
}
public bool Enabled { get; set; }
public string Key1 { get; set; }
public string Key2 { get; set; }
public string Key3 { get; set; }
public string Key4 { get; set; }
public string Key5 { get; set; }
public bool Nfc { get; set; }
}