ModulesConstraints and listRequiresDot for SQL

SQL sources used for authentication can now have module constraints.
Entries of SQL sources used as address books can now be displayed
automatically.
This commit is contained in:
Francis Lachapelle 2017-11-16 21:33:29 -05:00
parent 08ec68c07c
commit a2129f3e4a
5 changed files with 168 additions and 108 deletions

View file

@ -1612,7 +1612,7 @@ SQL source:
[cols="3,47a,50"] [cols="3,47a,50"]
|======================================================================= |=======================================================================
.18+^|D |SOGoUserSources .20+^|D |SOGoUserSources
|Parameter used to set the SQL and/or LDAP sources used for |Parameter used to set the SQL and/or LDAP sources used for
authentication and global address books. Multiple sources can be authentication and global address books. Multiple sources can be
specified as an array of dictionaries. A dictionary that defines a SQL specified as an array of dictionaries. A dictionary that defines a SQL
@ -1719,6 +1719,23 @@ to the user.
See the _Multi-domains Configuration_ section in this document for more See the _Multi-domains Configuration_ section in this document for more
information. information.
|listRequiresDot (optional)
|If set to `YES`, listing of this SQL source is only possible when performing a search (respecting the SOGoSearchMinimumWordLength parameter) or when explicitely typing a single dot.
Defaults to `YES` when unset.
|ModulesConstraints (optional)
|Limits the access of any module through a constraint based on a SQL
column; must be a dictionary with keys `Mail`, and/or `Calendar`,
and/or `ActiveSync` for example:
----
ModulesConstraints = {
Calendar = {
c_ou = employees;
};
};
----
|======================================================================= |=======================================================================
Here is an example of an SQL-based authentication and address book Here is an example of an SQL-based authentication and address book

2
NEWS
View file

@ -3,6 +3,8 @@
New features New features
- [core] can now invite attendees to exceptions only (#2561) - [core] can now invite attendees to exceptions only (#2561)
- [core] add support for module constraints in SQL sources
- [core] add support for listRequiresDot in SQL sources
- [web] display freebusy information of owner in appointment editor - [web] display freebusy information of owner in appointment editor
- [web] register SOGo as a handler for the mailto scheme (#1223) - [web] register SOGo as a handler for the mailto scheme (#1223)
- [web] new events list view where events are grouped by day - [web] new events list view where events are grouped by day

View file

@ -229,8 +229,7 @@ static Class NSStringK;
else else
queryTimeout = [dd ldapQueryTimeout]; queryTimeout = [dd ldapQueryTimeout];
ASSIGN(modulesConstraints, ASSIGN(modulesConstraints, [udSource objectForKey: @"ModulesConstraints"]);
[udSource objectForKey: @"ModulesConstraints"]);
ASSIGN(_filter, [udSource objectForKey: @"filter"]); ASSIGN(_filter, [udSource objectForKey: @"filter"]);
ASSIGN(_userPasswordAlgorithm, [udSource objectForKey: @"userPasswordAlgorithm"]); ASSIGN(_userPasswordAlgorithm, [udSource objectForKey: @"userPasswordAlgorithm"]);
ASSIGN(_scope, ([udSource objectForKey: @"scope"] ASSIGN(_scope, ([udSource objectForKey: @"scope"]

View file

@ -1,6 +1,6 @@
/* SQLSource.h - this file is part of SOGo /* SQLSource.h - this file is part of SOGo
* *
* Copyright (C) 2009-2011 Inverse inc. * Copyright (C) 2009-2017 Inverse inc.
* *
* Authors: Ludovic Marcotte <lmarcotte@inverse.ca> * Authors: Ludovic Marcotte <lmarcotte@inverse.ca>
* Francis Lachapelle <flachapelle@invers.ca> * Francis Lachapelle <flachapelle@invers.ca>
@ -50,6 +50,10 @@
/* resources handling */ /* resources handling */
NSString *_kindField; NSString *_kindField;
NSString *_multipleBookingsField; NSString *_multipleBookingsField;
BOOL _listRequiresDot;
NSDictionary *_modulesConstraints;
} }
@end @end

View file

@ -96,6 +96,8 @@
_multipleBookingsField = nil; _multipleBookingsField = nil;
_imapHostField = nil; _imapHostField = nil;
_sieveHostField = nil; _sieveHostField = nil;
_listRequiresDot = YES;
_modulesConstraints = nil;
} }
return self; return self;
@ -114,6 +116,7 @@
[_domainField release]; [_domainField release];
[_imapHostField release]; [_imapHostField release];
[_sieveHostField release]; [_sieveHostField release];
[_modulesConstraints release];
[super dealloc]; [super dealloc];
} }
@ -121,6 +124,8 @@
- (id) initFromUDSource: (NSDictionary *) udSource - (id) initFromUDSource: (NSDictionary *) udSource
inDomain: (NSString *) sourceDomain inDomain: (NSString *) sourceDomain
{ {
NSNumber *dotValue;
self = [self init]; self = [self init];
ASSIGN(_sourceID, [udSource objectForKey: @"id"]); ASSIGN(_sourceID, [udSource objectForKey: @"id"]);
@ -134,6 +139,7 @@
ASSIGN(_kindField, [udSource objectForKey: @"KindFieldName"]); ASSIGN(_kindField, [udSource objectForKey: @"KindFieldName"]);
ASSIGN(_multipleBookingsField, [udSource objectForKey: @"MultipleBookingsFieldName"]); ASSIGN(_multipleBookingsField, [udSource objectForKey: @"MultipleBookingsFieldName"]);
ASSIGN(_domainField, [udSource objectForKey: @"DomainFieldName"]); ASSIGN(_domainField, [udSource objectForKey: @"DomainFieldName"]);
ASSIGN(_modulesConstraints, [udSource objectForKey: @"ModulesConstraints"]);
if ([udSource objectForKey: @"prependPasswordScheme"]) if ([udSource objectForKey: @"prependPasswordScheme"])
_prependPasswordScheme = [[udSource objectForKey: @"prependPasswordScheme"] boolValue]; _prependPasswordScheme = [[udSource objectForKey: @"prependPasswordScheme"] boolValue];
else else
@ -145,6 +151,10 @@
if ([udSource objectForKey: @"viewURL"]) if ([udSource objectForKey: @"viewURL"])
_viewURL = [[NSURL alloc] initWithString: [udSource objectForKey: @"viewURL"]]; _viewURL = [[NSURL alloc] initWithString: [udSource objectForKey: @"viewURL"]];
dotValue = [udSource objectForKey: @"listRequiresDot"];
if (dotValue)
[self setListRequiresDot: [dotValue boolValue]];
#warning this domain code has no effect yet #warning this domain code has no effect yet
if ([sourceDomain length]) if ([sourceDomain length])
ASSIGN (_domain, sourceDomain); ASSIGN (_domain, sourceDomain);
@ -379,6 +389,35 @@
return s; return s;
} }
- (void) _fillConstraintsForModule: (NSString *) module
intoRecord: (NSMutableDictionary *) record
{
NSDictionary *constraints;
NSEnumerator *matches;
NSString *currentMatch, *currentValue, *recordValue;
BOOL result;
result = YES;
constraints = [_modulesConstraints objectForKey: module];
if (constraints)
{
matches = [[constraints allKeys] objectEnumerator];
while (result == YES && (currentMatch = [matches nextObject]))
{
currentValue = [constraints objectForKey: currentMatch];
recordValue = [record objectForKey: currentMatch];
result = NO;
if ([recordValue caseInsensitiveMatches: currentValue])
result = YES;
}
}
[record setObject: [NSNumber numberWithBool: result]
forKey: [NSString stringWithFormat: @"%@Access", module]];
}
- (NSDictionary *) _lookupContactEntry: (NSString *) theID - (NSDictionary *) _lookupContactEntry: (NSString *) theID
considerEmail: (BOOL) b considerEmail: (BOOL) b
inDomain: (NSString *) domain inDomain: (NSString *) domain
@ -491,12 +530,9 @@
forKey: [field substringFromIndex: 2]]; forKey: [field substringFromIndex: 2]];
} }
// FIXME [self _fillConstraintsForModule: @"Calendar" intoRecord: response];
// We have to do this here since we do not manage modules [self _fillConstraintsForModule: @"Mail" intoRecord: response];
// constraints right now over a SQL backend. [self _fillConstraintsForModule: @"ActiveSync" intoRecord: response];
[response setObject: [NSNumber numberWithBool: YES] forKey: @"CalendarAccess"];
[response setObject: [NSNumber numberWithBool: YES] forKey: @"MailAccess"];
[response setObject: [NSNumber numberWithBool: YES] forKey: @"ActiveSyncAccess"];
// We set the domain, if any // We set the domain, if any
value = nil; value = nil;
@ -767,6 +803,8 @@
results = [NSMutableArray array]; results = [NSMutableArray array];
if ([filter length] > 0 || !_listRequiresDot)
{
cm = [GCSChannelManager defaultChannelManager]; cm = [GCSChannelManager defaultChannelManager];
channel = [cm acquireOpenChannelForURL: _viewURL]; channel = [cm acquireOpenChannelForURL: _viewURL];
if (channel) if (channel)
@ -830,6 +868,7 @@
else else
[self errorWithFormat:@"failed to acquire channel for URL: %@", [self errorWithFormat:@"failed to acquire channel for URL: %@",
[_viewURL absoluteString]]; [_viewURL absoluteString]];
}
return results; return results;
} }
@ -856,13 +895,12 @@
- (void) setListRequiresDot: (BOOL) newListRequiresDot - (void) setListRequiresDot: (BOOL) newListRequiresDot
{ {
_listRequiresDot = newListRequiresDot;
} }
- (BOOL) listRequiresDot - (BOOL) listRequiresDot
{ {
/* This method is not implemented for SQLSource. It must enable a mechanism return _listRequiresDot;
where using "." is not required to list the content of addressbooks. */
return YES;
} }
/* card editing */ /* card editing */