diff --git a/src/Api/Api.csproj b/src/Api/Api.csproj
index 9e0b33c553..5d199dd6f0 100644
--- a/src/Api/Api.csproj
+++ b/src/Api/Api.csproj
@@ -18,7 +18,6 @@
-
diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj
index 8424cc7734..4c7db6b0ae 100644
--- a/src/Core/Core.csproj
+++ b/src/Core/Core.csproj
@@ -49,6 +49,7 @@
+
diff --git a/src/Api/Middleware/CustomIpRateLimitMiddleware.cs b/src/Core/Utilities/CustomIpRateLimitMiddleware.cs
similarity index 98%
rename from src/Api/Middleware/CustomIpRateLimitMiddleware.cs
rename to src/Core/Utilities/CustomIpRateLimitMiddleware.cs
index 244e3f3b5a..a2fb40b5e8 100644
--- a/src/Api/Middleware/CustomIpRateLimitMiddleware.cs
+++ b/src/Core/Utilities/CustomIpRateLimitMiddleware.cs
@@ -8,7 +8,7 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Threading.Tasks;
-namespace Bit.Api.Middleware
+namespace Bit.Core.Utilities
{
public class CustomIpRateLimitMiddleware : IpRateLimitMiddleware
{
diff --git a/src/Identity/Startup.cs b/src/Identity/Startup.cs
index bb0cd83706..c51fda2fd6 100644
--- a/src/Identity/Startup.cs
+++ b/src/Identity/Startup.cs
@@ -7,6 +7,7 @@ using Microsoft.Extensions.Configuration;
using Bit.Core;
using Bit.Core.Utilities;
using Serilog.Events;
+using AspNetCoreRateLimit;
namespace Bit.Identity
{
@@ -30,6 +31,11 @@ namespace Bit.Identity
// Settings
var globalSettings = services.AddGlobalSettingsServices(Configuration);
+ if(!globalSettings.SelfHosted)
+ {
+ services.Configure(Configuration.GetSection("IpRateLimitOptions"));
+ services.Configure(Configuration.GetSection("IpRateLimitPolicies"));
+ }
// Data Protection
services.AddCustomDataProtectionServices(Environment, globalSettings);
@@ -40,6 +46,16 @@ namespace Bit.Identity
// Context
services.AddScoped();
+ // Caching
+ services.AddMemoryCache();
+
+ if(!globalSettings.SelfHosted)
+ {
+ // Rate limiting
+ services.AddSingleton();
+ services.AddSingleton();
+ }
+
// IdentityServer
services.AddCustomIdentityServerServices(Environment, globalSettings);
@@ -67,6 +83,11 @@ namespace Bit.Identity
return e.Level > LogEventLevel.Error;
}
+ if(context.Contains(typeof(IpRateLimitMiddleware).FullName) && e.Level == LogEventLevel.Information)
+ {
+ return true;
+ }
+
return e.Level >= LogEventLevel.Error;
})
.AddConsole()
@@ -75,6 +96,12 @@ namespace Bit.Identity
// Default Middleware
app.UseDefaultMiddleware(env);
+ if(!globalSettings.SelfHosted)
+ {
+ // Rate limiting
+ app.UseMiddleware();
+ }
+
// Add IdentityServer to the request pipeline.
app.UseIdentityServer();
}
diff --git a/src/Identity/settings.json b/src/Identity/settings.json
index a2f4b590b5..6a53608fd9 100644
--- a/src/Identity/settings.json
+++ b/src/Identity/settings.json
@@ -47,5 +47,35 @@
"publicKey": "SECRET",
"privateKey": "SECRET"
}
+ },
+ "IpRateLimitOptions": {
+ "EnableEndpointRateLimiting": true,
+ "StackBlockedRequests": false,
+ "RealIpHeader": "CF-Connecting-IP",
+ "ClientIdHeader": "X-ClientId",
+ "HttpStatusCode": 429,
+ "IpWhitelist": [],
+ "EndpointWhitelist": [],
+ "ClientWhitelist": [],
+ "GeneralRules": [
+ {
+ "Endpoint": "*",
+ "Period": "1m",
+ "Limit": 60
+ },
+ {
+ "Endpoint": "*",
+ "Period": "1s",
+ "Limit": 5
+ },
+ {
+ "Endpoint": "post:/connect/token",
+ "Period": "1m",
+ "Limit": 10
+ }
+ ]
+ },
+ "IpRateLimitPolicies": {
+ "IpRules": []
}
}