(feat) user rate-limiting support for all SOGo requests
parent
bb04ce39d6
commit
9d6ab2df33
|
@ -715,6 +715,21 @@ Default value is `0`, or disabled.
|
|||
|Number of seconds, default to `300` (or 5 minutes). Note that
|
||||
_SOGoCacheCleanupInterval_ must be set to a value equal or higher than
|
||||
_SOGoFailedLoginBlockInterval_.
|
||||
|
||||
|S |SOGoMaximumRequestCount
|
||||
|Parameter used to control the number of requests a user can send to the SOGo
|
||||
server in _SOGoMaximumRequestInterval_ seconds or more. If conditions are met
|
||||
or exceeded, the user will not be able to perform requests on the SOGo server
|
||||
for _SOGoRequestBlockInterval_ seconds and will receive 429 HTTP responses for
|
||||
any requests being made. Default value is 0, or disabled
|
||||
|
||||
|S |SOGoMaximumRequestInterval
|
||||
|Number of seconds, defaults to `30`.
|
||||
|
||||
|S |SOGoRequestBlockInterval
|
||||
|Number of seconds, defaults to 300 (or 5 minutes). Note that _SOGoCacheCleanupInterval_
|
||||
must be set to a value equal or higher than _SOGoRequestBlockInterval_.
|
||||
|
||||
|=======================================================================
|
||||
|
||||
Authentication using LDAP
|
||||
|
|
58
Main/SOGo.m
58
Main/SOGo.m
|
@ -476,6 +476,8 @@ static BOOL debugLeaks;
|
|||
static BOOL debugOn = NO;
|
||||
WOResponse *resp;
|
||||
NSDate *startDate;
|
||||
NSString *path;
|
||||
|
||||
NSTimeInterval timeDelta;
|
||||
|
||||
if (debugRequests)
|
||||
|
@ -499,6 +501,62 @@ static BOOL debugLeaks;
|
|||
}
|
||||
#endif
|
||||
|
||||
// We check for rate-limiting settings - ignore anything actually
|
||||
// sent to /SOGo/ (so unauthenticated requests).
|
||||
path = [_request requestHandlerPath];
|
||||
if ([path length])
|
||||
{
|
||||
NSDictionary *requestCount;
|
||||
NSString *username;
|
||||
NSRange r;
|
||||
|
||||
r = [path rangeOfString: @"/"];
|
||||
username = [path substringWithRange: NSMakeRange(0, r.location)];
|
||||
requestCount = [cache requestCountForLogin: username];
|
||||
|
||||
if (requestCount)
|
||||
{
|
||||
SOGoSystemDefaults *sd;
|
||||
|
||||
unsigned int current_time, start_time, delta, block_time, request_count;
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
current_time = [[NSCalendarDate date] timeIntervalSince1970];
|
||||
start_time = [[requestCount objectForKey: @"InitialDate"] unsignedIntValue];
|
||||
delta = current_time - start_time;
|
||||
|
||||
block_time = [sd requestBlockInterval];
|
||||
request_count = [[requestCount objectForKey: @"RequestCount"] intValue];
|
||||
|
||||
if ( request_count >= [sd maximumRequestCount] &&
|
||||
delta < [sd maximumRequestInterval] &&
|
||||
delta <= block_time )
|
||||
{
|
||||
resp = [WOResponse responseWithRequest: _request];
|
||||
[resp setStatus: 429];
|
||||
return resp;
|
||||
}
|
||||
|
||||
if (delta > block_time)
|
||||
{
|
||||
[cache setRequestCount: 1
|
||||
forLogin: username
|
||||
interval: current_time];
|
||||
}
|
||||
else
|
||||
[cache setRequestCount: (request_count+1)
|
||||
forLogin: username
|
||||
interval: start_time];
|
||||
}
|
||||
else
|
||||
{
|
||||
[cache setRequestCount: 1
|
||||
forLogin: username
|
||||
interval: 0];
|
||||
}
|
||||
}
|
||||
|
||||
resp = [super dispatchRequest: _request];
|
||||
[cache killCache];
|
||||
|
||||
|
|
|
@ -141,6 +141,15 @@
|
|||
forPath: (NSString *) thePath;
|
||||
- (NSMutableDictionary *) aclsForPath: (NSString *) thePath;
|
||||
|
||||
//
|
||||
// SOGo rate-limiting
|
||||
//
|
||||
- (void) setRequestCount: (int) theCount
|
||||
forLogin: (NSString *) theLogin
|
||||
interval: (unsigned int) theInterval;
|
||||
|
||||
- (NSDictionary *) requestCountForLogin: (NSString *) theLogin;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SOGOCACHE_H */
|
||||
|
|
|
@ -727,5 +727,58 @@ static memcached_st *handle = NULL;
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// SOGo request count for rate-limiting
|
||||
//
|
||||
- (void) setRequestCount: (int) theCount
|
||||
forLogin: (NSString *) theLogin
|
||||
interval: (unsigned int) theInterval
|
||||
{
|
||||
NSMutableDictionary *d;
|
||||
NSNumber *count;
|
||||
|
||||
if (theCount)
|
||||
{
|
||||
count = [NSNumber numberWithInt: theCount];
|
||||
|
||||
d = [NSMutableDictionary dictionaryWithDictionary: [self requestCountForLogin: theLogin]];
|
||||
|
||||
if (![d objectForKey: @"InitialDate"] || theInterval == 0)
|
||||
[d setObject: [NSNumber numberWithUnsignedInt: [[NSCalendarDate date] timeIntervalSince1970]] forKey: @"InitialDate"];
|
||||
else
|
||||
[d setObject: [NSNumber numberWithUnsignedInt: theInterval] forKey: @"InitialDate"];
|
||||
|
||||
[d setObject: count forKey: @"RequestCount"];
|
||||
[self _cacheValues: [d jsonRepresentation]
|
||||
ofType: @"requestcount"
|
||||
forKey: theLogin];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self removeValueForKey: [NSString stringWithFormat: @"%@+failedlogins", theLogin]];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Returns a dictionary with two keys/values
|
||||
//
|
||||
// RequestCount ->
|
||||
// InitialDate ->
|
||||
//
|
||||
- (NSDictionary *) requestCountForLogin: (NSString *) theLogin
|
||||
{
|
||||
NSDictionary *d;
|
||||
NSString *s;
|
||||
|
||||
s = [self _valuesOfType: @"requestcount" forKey: theLogin];
|
||||
d = nil;
|
||||
|
||||
if (s)
|
||||
{
|
||||
d = [s objectFromJSONString];
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -97,6 +97,11 @@
|
|||
- (int) maximumSubmissionInterval;
|
||||
- (int) messageSubmissionBlockInterval;
|
||||
|
||||
- (int) maximumRequestCount;
|
||||
- (int) maximumRequestInterval;
|
||||
- (int) requestBlockInterval;
|
||||
|
||||
|
||||
- (int) maximumPingInterval;
|
||||
- (int) maximumSyncInterval;
|
||||
- (int) internalSyncInterval;
|
||||
|
|
|
@ -598,6 +598,42 @@ _injectConfigurationFromFile (NSMutableDictionary *defaultsDict,
|
|||
return v;
|
||||
}
|
||||
|
||||
//
|
||||
// SOGo rate-limiting
|
||||
//
|
||||
- (int) maximumRequestCount
|
||||
{
|
||||
return [self integerForKey: @"SOGoMaximumRequestCount"];
|
||||
}
|
||||
|
||||
- (int) maximumRequestInterval
|
||||
{
|
||||
int v;
|
||||
|
||||
v = [self integerForKey: @"SOGoMaximumRequestInterval"];
|
||||
|
||||
if (!v)
|
||||
v = 30;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
- (int) requestBlockInterval
|
||||
{
|
||||
int v;
|
||||
|
||||
v = [self integerForKey: @"SOGoRequestBlockInterval"];
|
||||
|
||||
if (!v)
|
||||
v = 300;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SOGo EAS settings
|
||||
//
|
||||
- (int) maximumPingInterval
|
||||
{
|
||||
int v;
|
||||
|
|
Loading…
Reference in New Issue