Skip to content

Commit

Permalink
(feat) user rate-limiting support for all SOGo requests
Browse files Browse the repository at this point in the history
  • Loading branch information
extrafu committed Mar 18, 2016
1 parent bb04ce3 commit 9d6ab2d
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 0 deletions.
15 changes: 15 additions & 0 deletions Documentation/SOGoInstallationGuide.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
58 changes: 58 additions & 0 deletions Main/SOGo.m
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,8 @@ - (WOResponse *) dispatchRequest: (WORequest *) _request
static BOOL debugOn = NO;
WOResponse *resp;
NSDate *startDate;
NSString *path;

NSTimeInterval timeDelta;

if (debugRequests)
Expand All @@ -499,6 +501,62 @@ - (WOResponse *) dispatchRequest: (WORequest *) _request
}
#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];

Expand Down
9 changes: 9 additions & 0 deletions SoObjects/SOGo/SOGoCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
53 changes: 53 additions & 0 deletions SoObjects/SOGo/SOGoCache.m
Original file line number Diff line number Diff line change
Expand Up @@ -727,5 +727,58 @@ - (NSMutableDictionary *) aclsForPath: (NSString *) thePath
}


//
// 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
5 changes: 5 additions & 0 deletions SoObjects/SOGo/SOGoSystemDefaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@
- (int) maximumSubmissionInterval;
- (int) messageSubmissionBlockInterval;

- (int) maximumRequestCount;
- (int) maximumRequestInterval;
- (int) requestBlockInterval;


- (int) maximumPingInterval;
- (int) maximumSyncInterval;
- (int) internalSyncInterval;
Expand Down
36 changes: 36 additions & 0 deletions SoObjects/SOGo/SOGoSystemDefaults.m
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,42 @@ - (int) messageSubmissionBlockInterval
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;
Expand Down

0 comments on commit 9d6ab2d

Please sign in to comment.