diff --git a/ChangeLog b/ChangeLog index c4fd0bfa7..21b0e22da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,43 @@ +2009-05-03 Francis Lachapelle + + * UI/Common/UIxUserRightsEditor.m ([UIxUserRightsEditor + -_initRights:]): add the "@" prefix to groups UID. + + * SoObjects/SOGo/SOGoGroup.m ([SOGoGroup +groupWithIdentifier:]): + returns a SOGoGroup instance matching the specified UID value or + nil if no group is found. + ([+groupWithEmail:]): idem for the specified email address. + ([-members]): now properly search among all LDAP sources for the + members of the group. + + * SoObjects/SOGo/SOGoGCSFolder.m ([SOGoGCSFolder + -_fetchAclsForUser:forObjectAtPath:]): also search for entries + prefixed by a "@" corresponding to group entries. For those + entries, find the members and add the ACLs if the user if part of + the group. + ([-setRoles:forUser:forObjectAtPath:]): prefix the UID with the + "@" character when dealing with a group. + + * SoObjects/SOGo/LDAPUserManager.m ([LDAPUserManager + -getLoginForDN:]): searches among all defined LDAP sources and + returns the UIDFieldName value for the requested DN. + ([-contactInfosForUserWithUIDorEmail:]): prior to perform the + search, removes the "@" prefix used to identified groups in the + ACL tables. + + * SoObjects/SOGo/LDAPSource.m ([LDAPSource -lookupLoginByDN:]): + returns the UIDFieldName value for the requested DN. + ([-lookupGroupEntryByUID:]): returns the LDAP entry corresponding + to a group (ie with an objectClass of member, uniqueMember, + memberUid, or memberOf) for the requested UID. + ([-lookupGroupEntryByEmail]): idem for the requested email address. + ([-lookupGroupEntryByAttribute:andValue:]): idem for the specified + value for the specified attribute. + ([-baseDN]): accessor for the base DN. + + * UI/Common/UIxAclEditor.m ([UIxAclEditor -_displayNameForUID:]): + removes the "@" prefix before looking up for the CN and email address. + 2009-05-01 Ludovic Marcotte * SoObjects/Appointments/SOGoAppointmentObject.m diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index 145a9f06c..9622eda69 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -419,7 +419,7 @@ { SOGoGroup *group; - group = [SOGoGroup groupWithIdentifier: [currentAttendee rfc822Email]]; + group = [SOGoGroup groupWithEmail: [currentAttendee rfc822Email]]; if (group) { @@ -1355,7 +1355,7 @@ enumerator = [[event attendees] objectEnumerator]; while ((currentAttendee = [enumerator nextObject])) { - group = [SOGoGroup groupWithIdentifier: [currentAttendee rfc822Email]]; + group = [SOGoGroup groupWithEmail: [currentAttendee rfc822Email]]; if (group) { diff --git a/SoObjects/SOGo/LDAPSource.h b/SoObjects/SOGo/LDAPSource.h index 0d9f2b084..ea216489d 100644 --- a/SoObjects/SOGo/LDAPSource.h +++ b/SoObjects/SOGo/LDAPSource.h @@ -71,18 +71,23 @@ mailFields: (NSArray *) newMailFields andBindFields: (NSString *) newBindFields; -- (NSString *) loginForDN: (NSString *) theDN; - - (BOOL) checkLogin: (NSString *) login andPassword: (NSString *) password; +- (NSString *) lookupLoginByDN: (NSString *) theDN; + - (NSDictionary *) lookupContactEntry: (NSString *) theID; - (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) entryID; -- (NGLdapEntry *) lookupGroupEntry: (NSString *) theID; + +- (NGLdapEntry *) lookupGroupEntryByUID: (NSString *) theUID; +- (NGLdapEntry *) lookupGroupEntryByEmail: (NSString *) theEmail; +- (NGLdapEntry *) lookupGroupEntryByAttribute: (NSString *) theAttribute + andValue: (NSString *) theValue; - (NSArray *) allEntryIDs; - (NSArray *) fetchContactsMatching: (NSString *) filter; - (NSString *) sourceID; +- (NSString *) baseDN; @end diff --git a/SoObjects/SOGo/LDAPSource.m b/SoObjects/SOGo/LDAPSource.m index c7741c7fc..5b247908e 100644 --- a/SoObjects/SOGo/LDAPSource.m +++ b/SoObjects/SOGo/LDAPSource.m @@ -377,21 +377,6 @@ static NSLock *lock; return userDN; } -- (NSString *) loginForDN: (NSString *) theDN -{ - NGLdapEntry *entry; - - entry = [ldapConnection entryAtDN: theDN - attributes: [NSArray arrayWithObject: IDField]]; - - if (entry) - { - return [[entry attributeWithName: IDField] stringValueAtIndex: 0]; - } - - return nil; -} - - (BOOL) checkLogin: (NSString *) loginToCheck andPassword: (NSString *) passwordToCheck { @@ -662,6 +647,11 @@ static NSLock *lock; value = [[ldapEntry attributeWithName: UIDField] stringValueAtIndex: 0]; if (!value) value = @""; +// else +// { +// Eventually, we could check at this point if the entry is a group +// and prefix the UID with a "@" +// } [contactEntry setObject: value forKey: @"c_uid"]; value = [[ldapEntry attributeWithName: CNField] stringValueAtIndex: 0]; if (!value) @@ -706,7 +696,7 @@ static NSLock *lock; entries = [ldapConnection flatSearchAtBaseDN: baseDN qualifier: qualifier attributes: attributes]; - else /* else we de like it was before */ + else /* we do it like before */ entries = [ldapConnection deepSearchAtBaseDN: baseDN qualifier: qualifier attributes: attributes]; @@ -837,8 +827,38 @@ static NSLock *lock; return contactEntry; } -// Use the email address for now... -- (NGLdapEntry *) lookupGroupEntry: (NSString *) theID +- (NSString *) lookupLoginByDN: (NSString *) theDN +{ + NGLdapEntry *entry; + NSString *login; + + login = nil; + if ([self _initLDAPConnection]) + { + entry = [ldapConnection entryAtDN: theDN + attributes: [NSArray arrayWithObject: UIDField]]; + if (entry) + login = [[entry attributeWithName: UIDField] stringValueAtIndex: 0]; + [ldapConnection autorelease]; + } + + return login; +} + +- (NGLdapEntry *) lookupGroupEntryByUID: (NSString *) theUID +{ + return [self lookupGroupEntryByAttribute: UIDField + andValue: theUID]; +} + +- (NGLdapEntry *) lookupGroupEntryByEmail: (NSString *) theEmail +{ + return [self lookupGroupEntryByAttribute: @"mail" + andValue: theEmail]; +} + +- (NGLdapEntry *) lookupGroupEntryByAttribute: (NSString *) theAttribute + andValue: (NSString *) theValue { NGLdapEntry *ldapEntry; @@ -848,7 +868,7 @@ static NSLock *lock; ldapEntry = nil; - if ([theID length] > 0) + if ([theValue length] > 0) { if ([self _initLDAPConnection]) { @@ -858,12 +878,14 @@ static NSLock *lock; NSString *s; // FIXME - s = [NSString stringWithFormat: @"(mail='%@')", theID]; + s = [NSString stringWithFormat: @"(%@='%@')", theAttribute, theValue]; qualifier = [EOQualifier qualifierWithQualifierFormat: s]; // We look for additional attributes - the ones related to group membership attributes = [NSMutableArray arrayWithArray: [self _searchAttributes]]; [attributes addObject: @"member"]; + [attributes addObject: @"uniqueMember"]; + [attributes addObject: @"memberUid"]; [attributes addObject: @"memberOf"]; if ([_scope caseInsensitiveCompare: @"BASE"] == NSOrderedSame) @@ -897,4 +919,9 @@ static NSLock *lock; return sourceID; } +- (NSString *) baseDN +{ + return baseDN; +} + @end diff --git a/SoObjects/SOGo/LDAPUserManager.h b/SoObjects/SOGo/LDAPUserManager.h index 7e84c4aec..d938b65bb 100644 --- a/SoObjects/SOGo/LDAPUserManager.h +++ b/SoObjects/SOGo/LDAPUserManager.h @@ -60,6 +60,7 @@ - (NSString *) getFullEmailForUID: (NSString *) uid; - (NSString *) getImapLoginForUID: (NSString *) uid; - (NSString *) getUIDForEmail: (NSString *) email; +- (NSString *) getLoginForDN: (NSString *) theDN; - (BOOL) checkLogin: (NSString *) login andPassword: (NSString *) password; diff --git a/SoObjects/SOGo/LDAPUserManager.m b/SoObjects/SOGo/LDAPUserManager.m index 11ccd6588..327c1254f 100644 --- a/SoObjects/SOGo/LDAPUserManager.m +++ b/SoObjects/SOGo/LDAPUserManager.m @@ -441,12 +441,15 @@ static NSLock *lock = nil; - (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid { NSMutableDictionary *currentUser, *contactInfos; + NSString *aUID; BOOL newUser; if ([uid length] > 0) { + // Remove the "@" prefix used to identified groups in the ACL tables. + aUID = [uid hasPrefix: @"@"] ? [uid substringFromIndex: 1] : uid; contactInfos = [NSMutableDictionary dictionary]; - currentUser = [[SOGoCache sharedCache] userAttributesForLogin: uid]; + currentUser = [[SOGoCache sharedCache] userAttributesForLogin: aUID]; #if defined(THREADSAFE) [lock lock]; #endif @@ -461,7 +464,7 @@ static NSLock *lock = nil; else newUser = NO; [self _fillContactInfosForUser: currentUser - withUIDorEmail: uid]; + withUIDorEmail: aUID]; if (newUser) { if ([[currentUser objectForKey: @"c_uid"] length] > 0) @@ -574,4 +577,24 @@ static NSLock *lock = nil; matching: filter]; } +- (NSString *) getLoginForDN: (NSString *) theDN +{ + NSEnumerator *ldapSources; + NSString *login; + LDAPSource *currentSource; + + login = nil; + ldapSources = [[sources allValues] objectEnumerator]; + while ((currentSource = [ldapSources nextObject])) + { + if ([theDN hasSuffix: [currentSource baseDN]]) + { + login = [currentSource lookupLoginByDN: theDN]; + if (login) + break; + } + } + return login; +} + @end diff --git a/SoObjects/SOGo/SOGoGCSFolder.m b/SoObjects/SOGo/SOGoGCSFolder.m index 005408cf1..b7c6c6e28 100644 --- a/SoObjects/SOGo/SOGoGCSFolder.m +++ b/SoObjects/SOGo/SOGoGCSFolder.m @@ -57,6 +57,7 @@ #import "NSString+Utilities.h" #import "SOGoContentObject.h" +#import "SOGoGroup.h" #import "SOGoParentFolder.h" #import "SOGoPermissions.h" #import "SOGoUser.h" @@ -781,15 +782,45 @@ static NSArray *childRecordFields = nil; NSMutableArray *acls; NSString *qs; - qs = [NSString stringWithFormat: @"(c_object = '/%@') AND (c_uid = '%@')", + // We look for the exact uid or any uid that begins with "@" (corresponding to groups) + qs = [NSString stringWithFormat: @"(c_object = '/%@') AND (c_uid = '%@' OR c_uid LIKE '@%%')", objectPath, uid]; qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier]; - acls = [NSMutableArray array]; - if ([records count] > 0) - [acls addObjectsFromArray: [records valueForKey: @"c_role"]]; + unsigned int i, j; + NSArray *members; + NSDictionary *record; + NSString *currentUid; + SOGoGroup *group; + SOGoUser *user; + + for (i = 0; i < [records count]; i ++) + { + record = [records objectAtIndex: i]; + currentUid = [record valueForKey: @"c_uid"]; + if ([currentUid isEqualToString: uid]) + [acls addObject: [record valueForKey: @"c_role"]]; + else + { + group = [SOGoGroup groupWithIdentifier: currentUid]; + if (group) + { + members = [group members]; + for (j = 0; j < [members count]; j++) + { + user = [members objectAtIndex: j]; + if ([[user login] isEqualToString: uid]) + { + [acls addObject: [record valueForKey: @"c_role"]]; + break; + } + } + } + } + } + return [acls uniqueObjects]; } @@ -904,10 +935,19 @@ static NSArray *childRecordFields = nil; forUser: (NSString *) uid forObjectAtPath: (NSArray *) objectPathArray { - NSString *objectPath; + NSString *objectPath, *aUID; NSMutableArray *newRoles; + SOGoGroup *group; - [self removeAclsForUsers: [NSArray arrayWithObject: uid] + aUID = uid; + if (![uid hasPrefix: @"@"]) + { + // Prefix the UID with the character "@" when dealing with a group + group = [SOGoGroup groupWithIdentifier: uid]; + if (group) + aUID = [NSString stringWithFormat: @"@%@", uid]; + } + [self removeAclsForUsers: [NSArray arrayWithObject: aUID] forObjectAtPath: objectPathArray]; newRoles = [NSMutableArray arrayWithArray: roles]; @@ -919,7 +959,7 @@ static NSArray *childRecordFields = nil; if (![newRoles count]) [newRoles addObject: SOGoRole_None]; - [self _commitRoles: newRoles forUID: uid forObject: objectPath]; + [self _commitRoles: newRoles forUID: aUID forObject: objectPath]; } /* acls */ diff --git a/SoObjects/SOGo/SOGoGroup.h b/SoObjects/SOGo/SOGoGroup.h index 1bf5764ff..a1fcb0ab7 100644 --- a/SoObjects/SOGo/SOGoGroup.h +++ b/SoObjects/SOGo/SOGoGroup.h @@ -39,6 +39,9 @@ } + (id) groupWithIdentifier: (NSString *) theID; ++ (id) groupWithEmail: (NSString *) theEmail; ++ (id) groupWithValue: (NSString *) theValue + andSourceSelector: (SEL) theSelector; - (NSArray *) members; diff --git a/SoObjects/SOGo/SOGoGroup.m b/SoObjects/SOGo/SOGoGroup.m index 61c6dd6dd..e1ff24ed4 100644 --- a/SoObjects/SOGo/SOGoGroup.m +++ b/SoObjects/SOGo/SOGoGroup.m @@ -85,11 +85,25 @@ [super dealloc]; } -// -// Returns nil if theID (which is an email address) doesn't -// actually match to a group (so its objectClass isn't really a group) -// + (id) groupWithIdentifier: (NSString *) theID +{ + NSString *uid; + + uid = [theID hasPrefix: @"@"] ? [theID substringFromIndex: 1] : theID; + return [SOGoGroup groupWithValue: uid andSourceSelector: @selector (lookupGroupEntryByUID:)]; +} + ++ (id) groupWithEmail: (NSString *) theEmail +{ + return [SOGoGroup groupWithValue: theEmail andSourceSelector: @selector (lookupGroupEntryByEmail:)]; +} + +// +// Returns nil if theValue doesn't match to a group +// (so its objectClass isn't a group) +// ++ (id) groupWithValue: (NSString *) theValue + andSourceSelector: (SEL) theSelector { NSArray *allSources; NGLdapEntry *entry; @@ -99,8 +113,8 @@ int i; // Don't bother looking in all sources if the - // supplied email address is nil. - if (!theID) + // supplied value is nil. + if (!theValue) return nil; allSources = [[LDAPUserManager sharedUserManager] sourceIDs]; @@ -109,7 +123,8 @@ for (i = 0; i < [allSources count]; i++) { source = [[LDAPUserManager sharedUserManager] sourceWithID: [allSources objectAtIndex: i]]; - entry = [source lookupGroupEntry: theID]; + entry = [source performSelector: theSelector + withObject: theValue]; if (entry) break; @@ -131,7 +146,7 @@ [classes containsObject: @"groupOfUniqueNames"] || [classes containsObject: @"posixGroup"]) { - o = [[self alloc] initWithIdentifier: theID + o = [[self alloc] initWithIdentifier: theValue source: source entry: entry]; AUTORELEASE(o); @@ -149,9 +164,10 @@ { NSMutableArray *dns, *uids; NSMutableArray *array; - NSString *login; + NSString *dn, *login; SOGoUser *user; NSArray *o; + LDAPUserManager *um; int i, c; array = [NSMutableArray array]; @@ -180,13 +196,15 @@ // We deal with a static group, let's add the members if (c) { + um = [LDAPUserManager sharedUserManager]; + // We add members for whom we have their associated DN for (i = 0; i < [dns count]; i++) { - login = [_source loginForDN: [dns objectAtIndex: i]]; + dn = [dns objectAtIndex: i]; + login = [um getLoginForDN: dn]; NSLog(@"member = %@", login); - user = [SOGoUser userWithLogin: login roles: nil]; - + user = [SOGoUser userWithLogin: login roles: nil]; if (user) [array addObject: user]; } diff --git a/UI/Common/UIxAclEditor.m b/UI/Common/UIxAclEditor.m index 1bd6462d0..19de2b33d 100644 --- a/UI/Common/UIxAclEditor.m +++ b/UI/Common/UIxAclEditor.m @@ -75,11 +75,13 @@ - (NSString *) _displayNameForUID: (NSString *) uid { LDAPUserManager *um; + NSString *s; um = [LDAPUserManager sharedUserManager]; + s = [uid hasPrefix: @"@"] ? [uid substringFromIndex: 1] : uid; return [NSString stringWithFormat: @"%@ <%@>", - [um getCNForUID: uid], [um getEmailForUID: uid]]; + [um getCNForUID: s], [um getEmailForUID: s]]; } - (NSString *) ownerName @@ -121,6 +123,9 @@ currentUID = [aclsEnum nextObject]; while (currentUID) { + if ([currentUID hasPrefix: @"@"]) + // NOTE: don't remove the prefix if we want to identify the lists visually + currentUID = [currentUID substringFromIndex: 1]; if (!([currentUID isEqualToString: ownerLogin] || [currentUID isEqualToString: defaultUserID])) [users addObjectUniquely: currentUID]; diff --git a/UI/Common/UIxUserRightsEditor.m b/UI/Common/UIxUserRightsEditor.m index 1c9c53ddb..6c8a80841 100644 --- a/UI/Common/UIxUserRightsEditor.m +++ b/UI/Common/UIxUserRightsEditor.m @@ -27,6 +27,7 @@ #import #import #import +#import #import #import #import @@ -92,9 +93,10 @@ static BOOL sendACLAdvisories = NO; - (BOOL) _initRights { BOOL response; - NSString *newUID; + NSString *newUID, *searchUID; LDAPUserManager *um; SOGoObject *clientObject; + SOGoGroup *group; response = NO; @@ -108,6 +110,13 @@ static BOOL sendACLAdvisories = NO; if ([newUID isEqualToString: defaultUserID] || [[um getEmailForUID: newUID] length] > 0) { + if (![newUID hasPrefix: @"@"]) + { + group = [SOGoGroup groupWithIdentifier: newUID]; + if (group) + newUID = [NSString stringWithFormat: @"@%@", newUID]; + } + ASSIGN (uid, newUID); clientObject = [self clientObject]; [userRights addObjectsFromArray: [clientObject aclsForUser: uid]];