1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-24 12:35:25 +01:00

Enable Nullable In Auth Repositories (#4600)

This commit is contained in:
Justin Baur 2024-08-09 09:31:06 -04:00 committed by GitHub
parent 374ef95656
commit 56d6c91b25
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 76 additions and 30 deletions

View File

@ -2,17 +2,19 @@
using System.Text.Json.Serialization;
using Bit.Core.Utilities;
#nullable enable
namespace Bit.Core.Auth.Repositories.Cosmos;
public class Base64IdStringConverter : JsonConverter<string>
public class Base64IdStringConverter : JsonConverter<string?>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
ToKey(reader.GetString());
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) =>
public override void Write(Utf8JsonWriter writer, string? value, JsonSerializerOptions options) =>
writer.WriteStringValue(ToId(value));
public static string ToId(string key)
public static string? ToId(string? key)
{
if (key == null)
{
@ -21,7 +23,7 @@ public class Base64IdStringConverter : JsonConverter<string>
return CoreHelpers.TransformToBase64Url(key);
}
public static string ToKey(string id)
public static string? ToKey(string? id)
{
if (id == null)
{

View File

@ -6,6 +6,8 @@ using Bit.Core.Settings;
using Bit.Core.Utilities;
using Microsoft.Azure.Cosmos;
#nullable enable
namespace Bit.Core.Auth.Repositories.Cosmos;
public class GrantRepository : IGrantRepository
@ -34,7 +36,7 @@ public class GrantRepository : IGrantRepository
_container = _database.GetContainer("grant");
}
public async Task<IGrant> GetByKeyAsync(string key)
public async Task<IGrant?> GetByKeyAsync(string key)
{
var id = Base64IdStringConverter.ToId(key);
try

View File

@ -1,6 +1,8 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Models.Data;
#nullable enable
namespace Bit.Core.Repositories;
public interface IAuthRequestRepository : IRepository<AuthRequest, Guid>

View File

@ -2,6 +2,8 @@
using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.UserFeatures.UserKey;
#nullable enable
namespace Bit.Core.Repositories;
public interface IEmergencyAccessRepository : IRepository<EmergencyAccess, Guid>
@ -9,7 +11,7 @@ public interface IEmergencyAccessRepository : IRepository<EmergencyAccess, Guid>
Task<int> GetCountByGrantorIdEmailAsync(Guid grantorId, string email, bool onlyRegisteredUsers);
Task<ICollection<EmergencyAccessDetails>> GetManyDetailsByGrantorIdAsync(Guid grantorId);
Task<ICollection<EmergencyAccessDetails>> GetManyDetailsByGranteeIdAsync(Guid granteeId);
Task<EmergencyAccessDetails> GetDetailsByIdGrantorIdAsync(Guid id, Guid grantorId);
Task<EmergencyAccessDetails?> GetDetailsByIdGrantorIdAsync(Guid id, Guid grantorId);
Task<ICollection<EmergencyAccessNotify>> GetManyToNotifyAsync();
Task<ICollection<EmergencyAccessDetails>> GetExpiredRecoveriesAsync();

View File

@ -1,10 +1,12 @@
using Bit.Core.Auth.Models.Data;
#nullable enable
namespace Bit.Core.Auth.Repositories;
public interface IGrantRepository
{
Task<IGrant> GetByKeyAsync(string key);
Task<IGrant?> GetByKeyAsync(string key);
Task<ICollection<IGrant>> GetManyAsync(string subjectId, string sessionId, string clientId, string type);
Task SaveAsync(IGrant obj);
Task DeleteByKeyAsync(string key);

View File

@ -1,11 +1,13 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Repositories;
#nullable enable
namespace Bit.Core.Auth.Repositories;
public interface ISsoConfigRepository : IRepository<SsoConfig, long>
{
Task<SsoConfig> GetByOrganizationIdAsync(Guid organizationId);
Task<SsoConfig> GetByIdentifierAsync(string identifier);
Task<SsoConfig?> GetByOrganizationIdAsync(Guid organizationId);
Task<SsoConfig?> GetByIdentifierAsync(string identifier);
Task<ICollection<SsoConfig>> GetManyByRevisionNotBeforeDate(DateTime? notBefore);
}

View File

@ -1,10 +1,12 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Repositories;
#nullable enable
namespace Bit.Core.Auth.Repositories;
public interface ISsoUserRepository : IRepository<SsoUser, long>
{
Task DeleteAsync(Guid userId, Guid? organizationId);
Task<SsoUser> GetByUserIdOrganizationIdAsync(Guid organizationId, Guid userId);
Task<SsoUser?> GetByUserIdOrganizationIdAsync(Guid organizationId, Guid userId);
}

View File

@ -3,11 +3,13 @@ using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.UserFeatures.UserKey;
using Bit.Core.Repositories;
#nullable enable
namespace Bit.Core.Auth.Repositories;
public interface IWebAuthnCredentialRepository : IRepository<WebAuthnCredential, Guid>
{
Task<WebAuthnCredential> GetByIdAsync(Guid id, Guid userId);
Task<WebAuthnCredential?> GetByIdAsync(Guid id, Guid userId);
Task<ICollection<WebAuthnCredential>> GetManyByUserIdAsync(Guid userId);
Task<bool> UpdateAsync(WebAuthnCredential credential);
UpdateEncryptedDataForKeyRotation UpdateKeysForRotationAsync(Guid userId, IEnumerable<WebAuthnLoginRotateKeyData> credentials);

View File

@ -388,6 +388,8 @@ public static class CoreHelpers
/// <returns>Base64 standard formatted string</returns>
public static string TransformFromBase64Url(string input)
{
// TODO: .NET 9 Ships Base64Url in box, investigate replacing this usage with that
// Ref: https://github.com/dotnet/runtime/pull/102364
var output = input;
// 62nd char of encoding
output = output.Replace('-', '+');

View File

@ -8,6 +8,8 @@ using Bit.Infrastructure.Dapper.Repositories;
using Dapper;
using Microsoft.Data.SqlClient;
#nullable enable
namespace Bit.Infrastructure.Dapper.Auth.Repositories;
public class AuthRequestRepository : Repository<AuthRequest, Guid>, IAuthRequestRepository

View File

@ -9,6 +9,8 @@ using Bit.Infrastructure.Dapper.Repositories;
using Dapper;
using Microsoft.Data.SqlClient;
#nullable enable
namespace Bit.Infrastructure.Dapper.Auth.Repositories;
public class EmergencyAccessRepository : Repository<EmergencyAccess, Guid>, IEmergencyAccessRepository
@ -60,7 +62,7 @@ public class EmergencyAccessRepository : Repository<EmergencyAccess, Guid>, IEme
}
}
public async Task<EmergencyAccessDetails> GetDetailsByIdGrantorIdAsync(Guid id, Guid grantorId)
public async Task<EmergencyAccessDetails?> GetDetailsByIdGrantorIdAsync(Guid id, Guid grantorId)
{
using (var connection = new SqlConnection(ConnectionString))
{

View File

@ -7,6 +7,8 @@ using Bit.Infrastructure.Dapper.Repositories;
using Dapper;
using Microsoft.Data.SqlClient;
#nullable enable
namespace Bit.Infrastructure.Dapper.Auth.Repositories;
public class GrantRepository : BaseRepository, IGrantRepository
@ -19,7 +21,7 @@ public class GrantRepository : BaseRepository, IGrantRepository
: base(connectionString, readOnlyConnectionString)
{ }
public async Task<IGrant> GetByKeyAsync(string key)
public async Task<IGrant?> GetByKeyAsync(string key)
{
using (var connection = new SqlConnection(ConnectionString))
{

View File

@ -6,6 +6,8 @@ using Bit.Infrastructure.Dapper.Repositories;
using Dapper;
using Microsoft.Data.SqlClient;
#nullable enable
namespace Bit.Infrastructure.Dapper.Auth.Repositories;
public class SsoConfigRepository : Repository<SsoConfig, long>, ISsoConfigRepository
@ -18,7 +20,7 @@ public class SsoConfigRepository : Repository<SsoConfig, long>, ISsoConfigReposi
: base(connectionString, readOnlyConnectionString)
{ }
public async Task<SsoConfig> GetByOrganizationIdAsync(Guid organizationId)
public async Task<SsoConfig?> GetByOrganizationIdAsync(Guid organizationId)
{
using (var connection = new SqlConnection(ConnectionString))
{
@ -31,7 +33,7 @@ public class SsoConfigRepository : Repository<SsoConfig, long>, ISsoConfigReposi
}
}
public async Task<SsoConfig> GetByIdentifierAsync(string identifier)
public async Task<SsoConfig?> GetByIdentifierAsync(string identifier)
{
using (var connection = new SqlConnection(ConnectionString))
{

View File

@ -6,6 +6,8 @@ using Bit.Infrastructure.Dapper.Repositories;
using Dapper;
using Microsoft.Data.SqlClient;
#nullable enable
namespace Bit.Infrastructure.Dapper.Auth.Repositories;
public class SsoUserRepository : Repository<SsoUser, long>, ISsoUserRepository
@ -29,7 +31,7 @@ public class SsoUserRepository : Repository<SsoUser, long>, ISsoUserRepository
}
}
public async Task<SsoUser> GetByUserIdOrganizationIdAsync(Guid organizationId, Guid userId)
public async Task<SsoUser?> GetByUserIdOrganizationIdAsync(Guid organizationId, Guid userId)
{
using (var connection = new SqlConnection(ConnectionString))
{

View File

@ -9,6 +9,8 @@ using Bit.Infrastructure.Dapper.Repositories;
using Dapper;
using Microsoft.Data.SqlClient;
#nullable enable
namespace Bit.Infrastructure.Dapper.Auth.Repositories;
@ -22,7 +24,7 @@ public class WebAuthnCredentialRepository : Repository<WebAuthnCredential, Guid>
: base(connectionString, readOnlyConnectionString)
{ }
public async Task<WebAuthnCredential> GetByIdAsync(Guid id, Guid userId)
public async Task<WebAuthnCredential?> GetByIdAsync(Guid id, Guid userId)
{
using (var connection = new SqlConnection(ConnectionString))
{

View File

@ -8,6 +8,8 @@ using Bit.Infrastructure.EntityFramework.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
#nullable enable
namespace Bit.Infrastructure.EntityFramework.Auth.Repositories;
public class AuthRequestRepository : Repository<Core.Auth.Entities.AuthRequest, AuthRequest, Guid>, IAuthRequestRepository
@ -25,7 +27,7 @@ public class AuthRequestRepository : Repository<Core.Auth.Entities.AuthRequest,
var expiredRequests = await dbContext.AuthRequests
.Where(a => (a.Type != AuthRequestType.AdminApproval && a.CreationDate.AddSeconds(userRequestExpiration.TotalSeconds) < DateTime.UtcNow)
|| (a.Type == AuthRequestType.AdminApproval && a.Approved != true && a.CreationDate.AddSeconds(adminRequestExpiration.TotalSeconds) < DateTime.UtcNow)
|| (a.Type == AuthRequestType.AdminApproval && a.Approved == true && a.ResponseDate.Value.AddSeconds(afterAdminApprovalExpiration.TotalSeconds) < DateTime.UtcNow))
|| (a.Type == AuthRequestType.AdminApproval && a.Approved == true && a.ResponseDate!.Value.AddSeconds(afterAdminApprovalExpiration.TotalSeconds) < DateTime.UtcNow))
.ToListAsync();
dbContext.AuthRequests.RemoveRange(expiredRequests);
return await dbContext.SaveChangesAsync();

View File

@ -10,6 +10,8 @@ using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
#nullable enable
namespace Bit.Infrastructure.EntityFramework.Auth.Repositories;
public class EmergencyAccessRepository : Repository<Core.Auth.Entities.EmergencyAccess, EmergencyAccess, Guid>, IEmergencyAccessRepository
@ -35,7 +37,7 @@ public class EmergencyAccessRepository : Repository<Core.Auth.Entities.Emergency
await base.DeleteAsync(emergencyAccess);
}
public async Task<EmergencyAccessDetails> GetDetailsByIdGrantorIdAsync(Guid id, Guid grantorId)
public async Task<EmergencyAccessDetails?> GetDetailsByIdGrantorIdAsync(Guid id, Guid grantorId)
{
using (var scope = ServiceScopeFactory.CreateScope())
{

View File

@ -6,6 +6,8 @@ using Bit.Infrastructure.EntityFramework.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
#nullable enable
namespace Bit.Infrastructure.EntityFramework.Auth.Repositories;
public class GrantRepository : BaseEntityFrameworkRepository, IGrantRepository
@ -36,7 +38,7 @@ public class GrantRepository : BaseEntityFrameworkRepository, IGrantRepository
}
}
public async Task<IGrant> GetByKeyAsync(string key)
public async Task<IGrant?> GetByKeyAsync(string key)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
@ -92,4 +94,3 @@ public class GrantRepository : BaseEntityFrameworkRepository, IGrantRepository
}
}
}

View File

@ -2,6 +2,8 @@
using Bit.Infrastructure.EntityFramework.Repositories;
using Bit.Infrastructure.EntityFramework.Repositories.Queries;
#nullable enable
namespace Bit.Infrastructure.EntityFramework.Auth.Repositories.Queries;
public class EmergencyAccessDetailsViewQuery : IQuery<EmergencyAccessDetails>

View File

@ -2,6 +2,8 @@
using Bit.Infrastructure.EntityFramework.Repositories;
using Bit.Infrastructure.EntityFramework.Repositories.Queries;
#nullable enable
namespace Bit.Infrastructure.EntityFramework.Auth.Repositories.Queries;
public class EmergencyAccessReadCountByGrantorIdEmailQuery : IQuery<EmergencyAccess>

View File

@ -4,6 +4,8 @@ using Bit.Infrastructure.EntityFramework.Auth.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
#nullable enable
namespace Bit.Infrastructure.EntityFramework.Repositories;
public class SsoConfigRepository : Repository<Core.Auth.Entities.SsoConfig, SsoConfig, long>, ISsoConfigRepository
@ -12,7 +14,7 @@ public class SsoConfigRepository : Repository<Core.Auth.Entities.SsoConfig, SsoC
: base(serviceScopeFactory, mapper, (DatabaseContext context) => context.SsoConfigs)
{ }
public async Task<Core.Auth.Entities.SsoConfig> GetByOrganizationIdAsync(Guid organizationId)
public async Task<Core.Auth.Entities.SsoConfig?> GetByOrganizationIdAsync(Guid organizationId)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
@ -22,7 +24,7 @@ public class SsoConfigRepository : Repository<Core.Auth.Entities.SsoConfig, SsoC
}
}
public async Task<Core.Auth.Entities.SsoConfig> GetByIdentifierAsync(string identifier)
public async Task<Core.Auth.Entities.SsoConfig?> GetByIdentifierAsync(string identifier)
{
using (var scope = ServiceScopeFactory.CreateScope())

View File

@ -4,6 +4,8 @@ using Bit.Infrastructure.EntityFramework.Auth.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
#nullable enable
namespace Bit.Infrastructure.EntityFramework.Repositories;
public class SsoUserRepository : Repository<Core.Auth.Entities.SsoUser, SsoUser, long>, ISsoUserRepository
@ -17,13 +19,13 @@ public class SsoUserRepository : Repository<Core.Auth.Entities.SsoUser, SsoUser,
using (var scope = ServiceScopeFactory.CreateScope())
{
var dbContext = GetDatabaseContext(scope);
var entity = await GetDbSet(dbContext).SingleOrDefaultAsync(su => su.UserId == userId && su.OrganizationId == organizationId);
dbContext.Entry(entity).State = EntityState.Deleted;
await dbContext.SaveChangesAsync();
await dbContext.SsoUsers
.Where(su => su.UserId == userId && su.OrganizationId == organizationId)
.ExecuteDeleteAsync();
}
}
public async Task<Core.Auth.Entities.SsoUser> GetByUserIdOrganizationIdAsync(Guid organizationId, Guid userId)
public async Task<Core.Auth.Entities.SsoUser?> GetByUserIdOrganizationIdAsync(Guid organizationId, Guid userId)
{
using (var scope = ServiceScopeFactory.CreateScope())
{

View File

@ -7,6 +7,8 @@ using Bit.Infrastructure.EntityFramework.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
#nullable enable
namespace Bit.Infrastructure.EntityFramework.Auth.Repositories;
public class WebAuthnCredentialRepository : Repository<Core.Auth.Entities.WebAuthnCredential, WebAuthnCredential, Guid>, IWebAuthnCredentialRepository
@ -15,7 +17,7 @@ public class WebAuthnCredentialRepository : Repository<Core.Auth.Entities.WebAut
: base(serviceScopeFactory, mapper, (context) => context.WebAuthnCredentials)
{ }
public async Task<Core.Auth.Entities.WebAuthnCredential> GetByIdAsync(Guid id, Guid userId)
public async Task<Core.Auth.Entities.WebAuthnCredential?> GetByIdAsync(Guid id, Guid userId)
{
using (var scope = ServiceScopeFactory.CreateScope())
{

View File

@ -24,6 +24,7 @@ public class AccountsControllerTest : IClassFixture<ApiApplicationFactory>
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadFromJsonAsync<ProfileResponseModel>();
Assert.NotNull(content);
Assert.Equal("integration-test@bitwarden.com", content.Email);
Assert.Null(content.Name);
Assert.False(content.EmailVerified);

View File

@ -32,6 +32,6 @@ public class LoginHelper
var organizationApiKeyRepository = factory.GetService<IOrganizationApiKeyRepository>();
var apiKeys = await organizationApiKeyRepository.GetManyByOrganizationIdTypeAsync(organizationId);
var clientId = $"organization.{organizationId}";
return (clientId, apiKeys.SingleOrDefault().ApiKey);
return (clientId, apiKeys.Single().ApiKey);
}
}