mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 07:36:14 -05:00
Revert filescoped (#2227)
* Revert "Add git blame entry (#2226)" This reverts commit239286737d
. * Revert "Turn on file scoped namespaces (#2225)" This reverts commit34fb4cca2a
.
This commit is contained in:
@ -7,39 +7,40 @@ using Bit.Identity;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Bit.IntegrationTestCommon.Factories;
|
||||
|
||||
public class IdentityApplicationFactory : WebApplicationFactoryBase<Startup>
|
||||
namespace Bit.IntegrationTestCommon.Factories
|
||||
{
|
||||
public const string DefaultDeviceIdentifier = "92b9d953-b9b6-4eaf-9d3e-11d57144dfeb";
|
||||
|
||||
public async Task<HttpContext> RegisterAsync(RegisterRequestModel model)
|
||||
public class IdentityApplicationFactory : WebApplicationFactoryBase<Startup>
|
||||
{
|
||||
return await Server.PostAsync("/accounts/register", JsonContent.Create(model));
|
||||
}
|
||||
public const string DefaultDeviceIdentifier = "92b9d953-b9b6-4eaf-9d3e-11d57144dfeb";
|
||||
|
||||
public async Task<(string Token, string RefreshToken)> TokenFromPasswordAsync(string username,
|
||||
string password,
|
||||
string deviceIdentifier = DefaultDeviceIdentifier,
|
||||
string clientId = "web",
|
||||
DeviceType deviceType = DeviceType.FirefoxBrowser,
|
||||
string deviceName = "firefox")
|
||||
{
|
||||
var context = await Server.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
|
||||
public async Task<HttpContext> RegisterAsync(RegisterRequestModel model)
|
||||
{
|
||||
{ "scope", "api offline_access" },
|
||||
{ "client_id", clientId },
|
||||
{ "deviceType", ((int)deviceType).ToString() },
|
||||
{ "deviceIdentifier", deviceIdentifier },
|
||||
{ "deviceName", deviceName },
|
||||
{ "grant_type", "password" },
|
||||
{ "username", username },
|
||||
{ "password", password },
|
||||
}), context => context.Request.Headers.Add("Auth-Email", CoreHelpers.Base64UrlEncodeString(username)));
|
||||
return await Server.PostAsync("/accounts/register", JsonContent.Create(model));
|
||||
}
|
||||
|
||||
using var body = await AssertHelper.AssertResponseTypeIs<JsonDocument>(context);
|
||||
var root = body.RootElement;
|
||||
public async Task<(string Token, string RefreshToken)> TokenFromPasswordAsync(string username,
|
||||
string password,
|
||||
string deviceIdentifier = DefaultDeviceIdentifier,
|
||||
string clientId = "web",
|
||||
DeviceType deviceType = DeviceType.FirefoxBrowser,
|
||||
string deviceName = "firefox")
|
||||
{
|
||||
var context = await Server.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
|
||||
{
|
||||
{ "scope", "api offline_access" },
|
||||
{ "client_id", clientId },
|
||||
{ "deviceType", ((int)deviceType).ToString() },
|
||||
{ "deviceIdentifier", deviceIdentifier },
|
||||
{ "deviceName", deviceName },
|
||||
{ "grant_type", "password" },
|
||||
{ "username", username },
|
||||
{ "password", password },
|
||||
}), context => context.Request.Headers.Add("Auth-Email", CoreHelpers.Base64UrlEncodeString(username)));
|
||||
|
||||
return (root.GetProperty("access_token").GetString(), root.GetProperty("refresh_token").GetString());
|
||||
using var body = await AssertHelper.AssertResponseTypeIs<JsonDocument>(context);
|
||||
var root = body.RootElement;
|
||||
|
||||
return (root.GetProperty("access_token").GetString(), root.GetProperty("refresh_token").GetString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,102 +9,103 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Bit.IntegrationTestCommon.Factories;
|
||||
|
||||
public static class FactoryConstants
|
||||
namespace Bit.IntegrationTestCommon.Factories
|
||||
{
|
||||
public const string DefaultDatabaseName = "test_database";
|
||||
public const string WhitelistedIp = "1.1.1.1";
|
||||
}
|
||||
|
||||
public abstract class WebApplicationFactoryBase<T> : WebApplicationFactory<T>
|
||||
where T : class
|
||||
{
|
||||
/// <summary>
|
||||
/// The database name to use for this instance of the factory. By default it will use a shared database name so all instances will connect to the same database during it's lifetime.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will need to be set BEFORE using the <c>Server</c> property
|
||||
/// </remarks>
|
||||
public string DatabaseName { get; set; } = FactoryConstants.DefaultDatabaseName;
|
||||
|
||||
/// <summary>
|
||||
/// Configure the web host to use an EF in memory database
|
||||
/// </summary>
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
public static class FactoryConstants
|
||||
{
|
||||
builder.ConfigureAppConfiguration(c =>
|
||||
public const string DefaultDatabaseName = "test_database";
|
||||
public const string WhitelistedIp = "1.1.1.1";
|
||||
}
|
||||
|
||||
public abstract class WebApplicationFactoryBase<T> : WebApplicationFactory<T>
|
||||
where T : class
|
||||
{
|
||||
/// <summary>
|
||||
/// The database name to use for this instance of the factory. By default it will use a shared database name so all instances will connect to the same database during it's lifetime.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will need to be set BEFORE using the <c>Server</c> property
|
||||
/// </remarks>
|
||||
public string DatabaseName { get; set; } = FactoryConstants.DefaultDatabaseName;
|
||||
|
||||
/// <summary>
|
||||
/// Configure the web host to use an EF in memory database
|
||||
/// </summary>
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
c.SetBasePath(AppContext.BaseDirectory)
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddJsonFile("appsettings.Development.json");
|
||||
|
||||
c.AddUserSecrets(typeof(Identity.Startup).Assembly, optional: true);
|
||||
c.AddInMemoryCollection(new Dictionary<string, string>
|
||||
builder.ConfigureAppConfiguration(c =>
|
||||
{
|
||||
// Manually insert a EF provider so that ConfigureServices will add EF repositories but we will override
|
||||
// DbContextOptions to use an in memory database
|
||||
{ "globalSettings:databaseProvider", "postgres" },
|
||||
{ "globalSettings:postgreSql:connectionString", "Host=localhost;Username=test;Password=test;Database=test" },
|
||||
c.SetBasePath(AppContext.BaseDirectory)
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddJsonFile("appsettings.Development.json");
|
||||
|
||||
// Clear the redis connection string for distributed caching, forcing an in-memory implementation
|
||||
{ "globalSettings:redis:connectionString", ""}
|
||||
});
|
||||
});
|
||||
|
||||
builder.ConfigureTestServices(services =>
|
||||
{
|
||||
var dbContextOptions = services.First(sd => sd.ServiceType == typeof(DbContextOptions<DatabaseContext>));
|
||||
services.Remove(dbContextOptions);
|
||||
services.AddScoped(_ =>
|
||||
{
|
||||
return new DbContextOptionsBuilder<DatabaseContext>()
|
||||
.UseInMemoryDatabase(DatabaseName)
|
||||
.Options;
|
||||
});
|
||||
|
||||
// QUESTION: The normal licensing service should run fine on developer machines but not in CI
|
||||
// should we have a fork here to leave the normal service for developers?
|
||||
// TODO: Eventually add the license file to CI
|
||||
var licensingService = services.First(sd => sd.ServiceType == typeof(ILicensingService));
|
||||
services.Remove(licensingService);
|
||||
services.AddSingleton<ILicensingService, NoopLicensingService>();
|
||||
|
||||
// FUTURE CONSIDERATION: Add way to run this self hosted/cloud, for now it is cloud only
|
||||
var pushRegistrationService = services.First(sd => sd.ServiceType == typeof(IPushRegistrationService));
|
||||
services.Remove(pushRegistrationService);
|
||||
services.AddSingleton<IPushRegistrationService, NoopPushRegistrationService>();
|
||||
|
||||
// Even though we are cloud we currently set this up as cloud, we can use the EF/selfhosted service
|
||||
// instead of using Noop for this service
|
||||
// TODO: Install and use azurite in CI pipeline
|
||||
var eventWriteService = services.First(sd => sd.ServiceType == typeof(IEventWriteService));
|
||||
services.Remove(eventWriteService);
|
||||
services.AddSingleton<IEventWriteService, RepositoryEventWriteService>();
|
||||
|
||||
var eventRepositoryService = services.First(sd => sd.ServiceType == typeof(IEventRepository));
|
||||
services.Remove(eventRepositoryService);
|
||||
services.AddSingleton<IEventRepository, EventRepository>();
|
||||
|
||||
// Our Rate limiter works so well that it begins to fail tests unless we carve out
|
||||
// one whitelisted ip. We should still test the rate limiter though and they should change the Ip
|
||||
// to something that is NOT whitelisted
|
||||
services.Configure<IpRateLimitOptions>(options =>
|
||||
{
|
||||
options.IpWhitelist = new List<string>
|
||||
c.AddUserSecrets(typeof(Identity.Startup).Assembly, optional: true);
|
||||
c.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
FactoryConstants.WhitelistedIp,
|
||||
};
|
||||
// Manually insert a EF provider so that ConfigureServices will add EF repositories but we will override
|
||||
// DbContextOptions to use an in memory database
|
||||
{ "globalSettings:databaseProvider", "postgres" },
|
||||
{ "globalSettings:postgreSql:connectionString", "Host=localhost;Username=test;Password=test;Database=test" },
|
||||
|
||||
// Clear the redis connection string for distributed caching, forcing an in-memory implementation
|
||||
{ "globalSettings:redis:connectionString", ""}
|
||||
});
|
||||
});
|
||||
|
||||
// Fix IP Rate Limiting
|
||||
services.AddSingleton<IStartupFilter, CustomStartupFilter>();
|
||||
});
|
||||
}
|
||||
builder.ConfigureTestServices(services =>
|
||||
{
|
||||
var dbContextOptions = services.First(sd => sd.ServiceType == typeof(DbContextOptions<DatabaseContext>));
|
||||
services.Remove(dbContextOptions);
|
||||
services.AddScoped(_ =>
|
||||
{
|
||||
return new DbContextOptionsBuilder<DatabaseContext>()
|
||||
.UseInMemoryDatabase(DatabaseName)
|
||||
.Options;
|
||||
});
|
||||
|
||||
public DatabaseContext GetDatabaseContext()
|
||||
{
|
||||
var scope = Services.CreateScope();
|
||||
return scope.ServiceProvider.GetRequiredService<DatabaseContext>();
|
||||
// QUESTION: The normal licensing service should run fine on developer machines but not in CI
|
||||
// should we have a fork here to leave the normal service for developers?
|
||||
// TODO: Eventually add the license file to CI
|
||||
var licensingService = services.First(sd => sd.ServiceType == typeof(ILicensingService));
|
||||
services.Remove(licensingService);
|
||||
services.AddSingleton<ILicensingService, NoopLicensingService>();
|
||||
|
||||
// FUTURE CONSIDERATION: Add way to run this self hosted/cloud, for now it is cloud only
|
||||
var pushRegistrationService = services.First(sd => sd.ServiceType == typeof(IPushRegistrationService));
|
||||
services.Remove(pushRegistrationService);
|
||||
services.AddSingleton<IPushRegistrationService, NoopPushRegistrationService>();
|
||||
|
||||
// Even though we are cloud we currently set this up as cloud, we can use the EF/selfhosted service
|
||||
// instead of using Noop for this service
|
||||
// TODO: Install and use azurite in CI pipeline
|
||||
var eventWriteService = services.First(sd => sd.ServiceType == typeof(IEventWriteService));
|
||||
services.Remove(eventWriteService);
|
||||
services.AddSingleton<IEventWriteService, RepositoryEventWriteService>();
|
||||
|
||||
var eventRepositoryService = services.First(sd => sd.ServiceType == typeof(IEventRepository));
|
||||
services.Remove(eventRepositoryService);
|
||||
services.AddSingleton<IEventRepository, EventRepository>();
|
||||
|
||||
// Our Rate limiter works so well that it begins to fail tests unless we carve out
|
||||
// one whitelisted ip. We should still test the rate limiter though and they should change the Ip
|
||||
// to something that is NOT whitelisted
|
||||
services.Configure<IpRateLimitOptions>(options =>
|
||||
{
|
||||
options.IpWhitelist = new List<string>
|
||||
{
|
||||
FactoryConstants.WhitelistedIp,
|
||||
};
|
||||
});
|
||||
|
||||
// Fix IP Rate Limiting
|
||||
services.AddSingleton<IStartupFilter, CustomStartupFilter>();
|
||||
});
|
||||
}
|
||||
|
||||
public DatabaseContext GetDatabaseContext()
|
||||
{
|
||||
var scope = Services.CreateScope();
|
||||
return scope.ServiceProvider.GetRequiredService<DatabaseContext>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,64 +4,65 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Bit.IntegrationTestCommon.Factories;
|
||||
|
||||
public static class WebApplicationFactoryExtensions
|
||||
namespace Bit.IntegrationTestCommon.Factories
|
||||
{
|
||||
private static async Task<HttpContext> SendAsync(this TestServer server,
|
||||
HttpMethod method,
|
||||
string requestUri,
|
||||
HttpContent content = null,
|
||||
Action<HttpContext> extraConfiguration = null)
|
||||
public static class WebApplicationFactoryExtensions
|
||||
{
|
||||
return await server.SendAsync(httpContext =>
|
||||
private static async Task<HttpContext> SendAsync(this TestServer server,
|
||||
HttpMethod method,
|
||||
string requestUri,
|
||||
HttpContent content = null,
|
||||
Action<HttpContext> extraConfiguration = null)
|
||||
{
|
||||
// Automatically set the whitelisted IP so normal tests do not run into rate limit issues
|
||||
// to test rate limiter, use the extraConfiguration parameter to set Connection.RemoteIpAddress
|
||||
// it runs after this so it will take precedence.
|
||||
httpContext.Connection.RemoteIpAddress = IPAddress.Parse(FactoryConstants.WhitelistedIp);
|
||||
|
||||
httpContext.Request.Path = new PathString(requestUri);
|
||||
httpContext.Request.Method = method.Method;
|
||||
|
||||
if (content != null)
|
||||
return await server.SendAsync(httpContext =>
|
||||
{
|
||||
foreach (var header in content.Headers)
|
||||
// Automatically set the whitelisted IP so normal tests do not run into rate limit issues
|
||||
// to test rate limiter, use the extraConfiguration parameter to set Connection.RemoteIpAddress
|
||||
// it runs after this so it will take precedence.
|
||||
httpContext.Connection.RemoteIpAddress = IPAddress.Parse(FactoryConstants.WhitelistedIp);
|
||||
|
||||
httpContext.Request.Path = new PathString(requestUri);
|
||||
httpContext.Request.Method = method.Method;
|
||||
|
||||
if (content != null)
|
||||
{
|
||||
httpContext.Request.Headers.Add(header.Key, new StringValues(header.Value.ToArray()));
|
||||
foreach (var header in content.Headers)
|
||||
{
|
||||
httpContext.Request.Headers.Add(header.Key, new StringValues(header.Value.ToArray()));
|
||||
}
|
||||
|
||||
httpContext.Request.Body = content.ReadAsStream();
|
||||
}
|
||||
|
||||
httpContext.Request.Body = content.ReadAsStream();
|
||||
}
|
||||
extraConfiguration?.Invoke(httpContext);
|
||||
});
|
||||
}
|
||||
public static Task<HttpContext> PostAsync(this TestServer server,
|
||||
string requestUri,
|
||||
HttpContent content,
|
||||
Action<HttpContext> extraConfiguration = null)
|
||||
=> SendAsync(server, HttpMethod.Post, requestUri, content, extraConfiguration);
|
||||
public static Task<HttpContext> GetAsync(this TestServer server,
|
||||
string requestUri,
|
||||
Action<HttpContext> extraConfiguration = null)
|
||||
=> SendAsync(server, HttpMethod.Get, requestUri, content: null, extraConfiguration);
|
||||
|
||||
extraConfiguration?.Invoke(httpContext);
|
||||
});
|
||||
}
|
||||
public static Task<HttpContext> PostAsync(this TestServer server,
|
||||
string requestUri,
|
||||
HttpContent content,
|
||||
Action<HttpContext> extraConfiguration = null)
|
||||
=> SendAsync(server, HttpMethod.Post, requestUri, content, extraConfiguration);
|
||||
public static Task<HttpContext> GetAsync(this TestServer server,
|
||||
string requestUri,
|
||||
Action<HttpContext> extraConfiguration = null)
|
||||
=> SendAsync(server, HttpMethod.Get, requestUri, content: null, extraConfiguration);
|
||||
public static HttpContext SetAuthEmail(this HttpContext context, string username)
|
||||
{
|
||||
context.Request.Headers.Add("Auth-Email", CoreHelpers.Base64UrlEncodeString(username));
|
||||
return context;
|
||||
}
|
||||
|
||||
public static HttpContext SetAuthEmail(this HttpContext context, string username)
|
||||
{
|
||||
context.Request.Headers.Add("Auth-Email", CoreHelpers.Base64UrlEncodeString(username));
|
||||
return context;
|
||||
}
|
||||
public static HttpContext SetIp(this HttpContext context, string ip)
|
||||
{
|
||||
context.Connection.RemoteIpAddress = IPAddress.Parse(ip);
|
||||
return context;
|
||||
}
|
||||
|
||||
public static HttpContext SetIp(this HttpContext context, string ip)
|
||||
{
|
||||
context.Connection.RemoteIpAddress = IPAddress.Parse(ip);
|
||||
return context;
|
||||
}
|
||||
|
||||
public static async Task<string> ReadBodyAsStringAsync(this HttpContext context)
|
||||
{
|
||||
using var sr = new StreamReader(context.Response.Body);
|
||||
return await sr.ReadToEndAsync();
|
||||
public static async Task<string> ReadBodyAsStringAsync(this HttpContext context)
|
||||
{
|
||||
using var sr = new StreamReader(context.Response.Body);
|
||||
return await sr.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user