From: <de...@de...> - 2008-01-30 16:26:35
|
Author: MichaelDaum Date: 2008-01-30 10:26:37 -0600 (Wed, 30 Jan 2008) New Revision: 16315 Trac url: http://develop.twiki.org/trac/changeset/16315 Modified: twiki/branches/MAIN/twikiplugins/LdapContrib/data/TWiki/LdapContrib.txt twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Contrib/LdapContrib.pm twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Users/LdapUser.pm twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Users/LdapUserMapping.pm Log: Item5303: first beta porting LdapContrib to TWiki-4.2 Modified: twiki/branches/MAIN/twikiplugins/LdapContrib/data/TWiki/LdapContrib.txt =================================================================== --- twiki/branches/MAIN/twikiplugins/LdapContrib/data/TWiki/LdapContrib.txt 2008-01-30 10:48:55 UTC (rev 16314) +++ twiki/branches/MAIN/twikiplugins/LdapContrib/data/TWiki/LdapContrib.txt 2008-01-30 16:26:37 UTC (rev 16315) @@ -402,8 +402,9 @@ This work was partly funded by [[http://www.spanlink.com][Spanlink Communications]] and \ [[http://www.trivadis.com][Trivadis]] | | License: | GPL ([[http://www.gnu.org/copyleft/gpl.html][GNU General Public License]]) | -| Version: | v2.1.1 | +| Version: | v2.99.1 | | Change History: | | +| 30 Jan 2008: | first beta towards TWiki-4.2 | | 07 Jan 2008: | fixed initializing the cache | | 21 Dec 2007: | added <nop>LdapApacheLogin, \ made updating the cache quasi atomic | @@ -458,7 +459,7 @@ | Appraisal: | TWiki:Plugins/%TOPIC%Appraisal | --- TWiki:Main/MichaelDaum - 07 Jan 2008 +-- TWiki:Main/MichaelDaum - 30 Jan 2008 %META:FILEATTACHMENT{name="TWikiDotPm-4.1.2.patch" attr="" autoattached="0" comment="" date="1191603621" path="TWikiDotPm-4.1.2.patch" size="1538" user="TWikiContributor" version="1"}% %META:FILEATTACHMENT{name="wikiringlogo40x40.png" attr="h" autoattached="0" comment="" date="1190996093" path="wikiringlogo40x40.png" size="2571" user="TWikiContributor" version="1"}% Modified: twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Contrib/LdapContrib.pm =================================================================== --- twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Contrib/LdapContrib.pm 2008-01-30 10:48:55 UTC (rev 16314) +++ twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Contrib/LdapContrib.pm 2008-01-30 16:26:37 UTC (rev 16315) @@ -28,7 +28,7 @@ use vars qw($VERSION $RELEASE %sharedLdapContrib); $VERSION = '$Rev: 15691 (17 Dec 2007) $'; -$RELEASE = 'v2.1.1'; +$RELEASE = 'v2.99.1'; =begin text @@ -555,9 +555,9 @@ $cacheAge = $now - $lastUpdate if $lastUpdate; # don't refresh within 60 seconds - if ($cacheAge < 60) { + if ($cacheAge < 10) { $refresh = 0; - $this->writeDebug("suppressing cache refresh within 60 seconds"); + $this->writeDebug("suppressing cache refresh within 10 seconds"); } #$this->writeDebug("cacheAge=$cacheAge, lastUpdate=$lastUpdate"); @@ -658,6 +658,7 @@ # read pages my $nrRecords = 0; my %wikiNames = (); + my %loginNames = (); my $gotError = 0; while (1) { @@ -673,7 +674,7 @@ # process each entry on a page while (my $entry = $mesg->pop_entry()) { - $this->cacheUserFromEntry($entry, $data, \%wikiNames) && $nrRecords++; + $this->cacheUserFromEntry($entry, $data, \%wikiNames, \%loginNames) && $nrRecords++; } # get cookie from paged control to remember the offset @@ -700,8 +701,9 @@ # check for error return undef if $gotError; - # remember list of all groups - $data->{USERS} = join(',', keys %wikiNames); + # remember list of all user names + $data->{WIKINAMES} = join(',', keys %wikiNames); + $data->{LOGINNAMES} = join(',', keys %loginNames); $this->writeDebug("got $nrRecords keys in cache"); @@ -781,7 +783,7 @@ =pod ----++++ cacheUserFromEntry($entry, $data, $seen) -> $boolean +---++++ cacheUserFromEntry($entry, $data, $wikiNames, $loginNames) -> $boolean store a user LDAP::Entry to our internal cache @@ -790,12 +792,13 @@ =cut sub cacheUserFromEntry { - my ($this, $entry, $data, $seen) = @_; + my ($this, $entry, $data, $wikiNames, $loginNames) = @_; #$this->writeDebug("called cacheUserFromEntry()"); $data ||= $this->{data}; - $seen ||= {}; + $wikiNames ||= {}; + $loginNames ||= {}; my $dn = $entry->dn(); my $loginName = $entry->get_value($this->{loginAttribute}); @@ -830,11 +833,16 @@ } } $wikiName ||= $loginName; - if (defined($seen->{$wikiName})) { - $this->writeDebug("WARNING: $dn clashes with $seen->{$wikiName} on $wikiName"); + if (defined($wikiNames->{$wikiName})) { + $this->writeDebug("WARNING: $dn clashes with wikiName $wikiNames->{$wikiName} on $wikiName"); return 0; } - $seen->{$wikiName} = $dn; + $wikiNames->{$wikiName} = $dn; + if (defined($loginNames->{$loginName})) { + $this->writeDebug("WARNING: $dn clashes with loginName $loginName->{$loginName} on $loginName"); + return 0; + } + $loginNames->{$loginName} = $dn; # get email addrs my $emails; @@ -853,7 +861,7 @@ =pod ----++++ cacheGroupFromEntry($entry, $data, $seen) -> $boolean +---++++ cacheGroupFromEntry($entry, $data, $groupNames) -> $boolean store a group LDAP::Entry to our internal cache @@ -862,10 +870,10 @@ =cut sub cacheGroupFromEntry { - my ($this, $entry, $data, $seen) = @_; + my ($this, $entry, $data, $groupNames) = @_; $data ||= $this->{data}; - $seen ||= {}; + $groupNames ||= {}; my $dn = $entry->dn(); @@ -882,8 +890,8 @@ $groupName = $this->normalizeWikiName($groupName); } - if (defined($seen->{$groupName})) { - $this->writeDebug("WARNING: $dn clashes with $seen->{$groupName} on $groupName"); + if (defined($groupNames->{$groupName})) { + $this->writeDebug("WARNING: $dn clashes with $groupNames->{$groupName} on $groupName"); return 0; } @@ -909,7 +917,7 @@ # store it $this->writeDebug("adding groupName='$groupName', dn=$dn"); $data->{"GROUPS::$groupName"} = join(',', keys %members); - $seen->{$groupName} = 1; + $groupNames->{$groupName} = 1; return 1; } @@ -1085,13 +1093,29 @@ sub getAllWikiNames { my $this = shift; - my $wikiNames = TWiki::Sandbox::untaintUnchecked($this->{data}{USERS}); + my $wikiNames = TWiki::Sandbox::untaintUnchecked($this->{data}{WIKINAMES}); my @wikiNames = split(/,/,$wikiNames); return \@wikiNames; } =pod +---++++ getAllLoginNames() -> \@array + +returns a list of all known loginNames + +=cut + +sub getAllLoginNames { + my $this = shift; + + my $loginNames = TWiki::Sandbox::untaintUnchecked($this->{data}{LOGINNAMES}); + my @loginNames = split(/,/,$loginNames); + return \@loginNames; +} + +=pod + ---++++ getDnOfLogin($loginName) -> $dn returns the Distinguished Name of the LDAP record of the given name @@ -1164,7 +1188,14 @@ unless ($entry) { $this->writeDebug("oops, no result"); } else { - $this->cacheUserFromEntry($entry); + # merge this user record + + my %wikiNames = map {$_ => 1} @{$this->getAllWikiNames()}; + my %loginNames = map {$_ => 1} @{$this->getAllLoginNames()}; + $this->cacheUserFromEntry($entry, $this->{data}, \%wikiNames, \%loginNames); + + $this->{data}{WIKINAMES} = join(',', keys %wikiNames); + $this->{data}{LOGINNAMES} = join(',', keys %loginNames); } return 0; Modified: twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Users/LdapUser.pm =================================================================== --- twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Users/LdapUser.pm 2008-01-30 10:48:55 UTC (rev 16314) +++ twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Users/LdapUser.pm 2008-01-30 16:26:37 UTC (rev 16315) @@ -76,7 +76,8 @@ sub error { my $this = shift; - return $this->{ldap}->getError(); + $this->{error} = $this->{ldap}->getError(); + return return $this->{error}; } =pod @@ -134,6 +135,20 @@ return 0; } +=pod + +---++ isManagingEmails() -> $boolean + +we aare managing emails, but don't allow setting emails. alas the +core does not distinguish this case, e.g. by using readOnly() + +=cut + +sub isManagingEmails { + return 1; +} + + =pod ---++++ getEmails($login) -> @emails @@ -220,7 +235,7 @@ if ($this->{ldap}->{allowChangePassword} && defined($oldPassword) && $oldPassword ne '1') { if ($this->{ldap}->getDnOfLogin($user)) { return 1 if $this->{ldap}->changePassword($user, $newPassword, $oldPassword); - $this->{error} = $this->{ldap}->getError(); + $this->error(); return undef; } } @@ -259,6 +274,36 @@ =pod +---++++ setPassword( $login, $newPassU, $oldPassU ) -> $boolean + +If the $oldPassU matches matches the user's password, then it will +replace it with $newPassU. + +If $oldPassU is not correct and not 1, will return 0. + +If $oldPassU is 1, will force the change irrespective of +the existing password, adding the user if necessary. + +Otherwise returns 1 on success, undef on failure. + +=cut + +sub setPassword { + my ($this, $login, $newUserPassword, $oldUserPassword) = @_; + + my $isOk = $this->{ldap}->changePassword($login, $newUserPassword, $oldUserPassword); + + if ($isOk) { + $this->{error} = undef; + return 1; + } else { + $this->error(); + return undef; + } +} + +=pod + ---++++ setEmails($user, @emails) Set the email address(es) for the given username. @@ -290,15 +335,15 @@ sub findUserByEmail { my $this = shift; - my $users = $this->SUPER::findUserByEmail(@_); - return $users unless $this->{secondaryPasswordManager}; + return undef unless $this->{secondaryPasswordManager}; # add those from the secondary - push @$users, $this->{secondaryPasswordManager}->findUserByEmail(@_); + my @users; + push @users, $this->{secondaryPasswordManager}->findUserByEmail(@_); # remove duplicates - my %users = map {$_ => 1} @$users; - my @users = keys %users; + my %users = map {$_ => 1} @users; + @users = keys %users; return \@users; } Modified: twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Users/LdapUserMapping.pm =================================================================== --- twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Users/LdapUserMapping.pm 2008-01-30 10:48:55 UTC (rev 16314) +++ twiki/branches/MAIN/twikiplugins/LdapContrib/lib/TWiki/Users/LdapUserMapping.pm 2008-01-30 16:26:37 UTC (rev 16315) @@ -20,6 +20,8 @@ use strict; use TWiki::Users::TWikiUserMapping; use TWiki::Contrib::LdapContrib; +use TWiki::ListIterator; +use TWiki::Plugins; use vars qw($isLoadedMapping); @@ -54,8 +56,26 @@ return $this; } + =pod +---++++ finish() + +Complete processing after the client's HTTP request has been responded +to. I.e. it disconnects the LDAP database connection. + +=cut + +sub finish { + my $this = shift; + + $this->{ldap}->finish() if $this->{ldap}; + $this->{ldap} = undef; + $this->SUPER::finish(); +} + +=pod + ---++++ getListOfGroups( ) -> @listOfUserObjects Get a list of groups defined in the LDAP database. If @@ -67,27 +87,46 @@ sub getListOfGroups { my $this = shift; - $this->{ldap}->writeDebug("called getListOfGroups()"); + #$this->{ldap}->writeDebug("called getListOfGroups()"); - return $this->SUPER::getListOfGroups() - unless $this->{ldap}{mapGroups}; + my %groups; + - my %groups; - if ($this->{ldap}{twikiGroupsBackoff}) { - %groups = map { $_->wikiName() => $_ } $this->SUPER::getListOfGroups(); + if ($TWiki::Plugins::VERSION < 1.2) { + # pre TWiki 4.2 + return $this->SUPER::getListOfGroups() + unless $this->{ldap}{mapGroups}; + + if ($this->{ldap}{twikiGroupsBackoff}) { + %groups = map { $_->wikiName() => $_ } $this->SUPER::getListOfGroups(); + } else { + %groups = (); + } + my $groupNames = $this->{ldap}->getGroupNames(); + if ($groupNames) { + foreach my $groupName (@$groupNames) { + $groups{$groupName} = $this->{session}->{users}->findUser($groupName, $groupName); + } + } + return values %groups; + } else { - %groups = (); - } - my $groupNames = $this->{ldap}->getGroupNames(); - if ($groupNames) { - foreach my $groupName (@$groupNames) { - $groups{$groupName} = $this->{session}->{users}->findUser($groupName, $groupName); + # TWiki 4.2 + + if ($this->{ldap}{twikiGroupsBackoff}) { + %groups = map { $_ => 1 } @{$this->SUPER::_getListOfGroups()}; + } else { + %groups = (); } + my $groupNames = $this->{ldap}->getGroupNames(); + if ($groupNames) { + foreach my $groupName (@$groupNames) { + $groups{$groupName} = 1; + } + } + #$this->{ldap}->writeDebug("got " . (scalar keys %groups) . " overall groups=".join(',',keys %groups)); + return keys %groups; } - - #$this->{ldap}->writeDebug("got " . (scalar keys %groups) . " overall groups=".join(',',keys %groups)); - - return values %groups; } =pod @@ -108,7 +147,7 @@ my $groupName = $group->wikiName; - #$this->{ldap}->writeDebug("called groupMembers for $groupName"); + $this->{ldap}->writeDebug("called groupMembers for $groupName"); my $ldapMembers; $ldapMembers = $this->{ldap}->getGroupMembers($groupName) @@ -204,7 +243,11 @@ # fallback #$this->{ldap}->writeDebug("asking SUPER"); - $wikiName = $this->SUPER::lookupLoginName($thisName); + if ($TWiki::Plugins::VERSION < 1.2) { + $wikiName = $this->SUPER::lookupLoginName(@_) + } else { + $wikiName = $this->SUPER::getWikiName(@_); + } return undef unless $wikiName; @@ -248,7 +291,11 @@ # fallback #$this->{ldap}->writeDebug("asking SUPER"); - $loginName = $this->SUPER::lookupWikiName($wikiName) || '_unknown_'; + if ($TWiki::Plugins::VERSION < 1.2) { + $loginName = $this->SUPER::lookupWikiName(@_) + } else { + $loginName = $this->SUPER::getLoginName(@_); + } return undef if $loginName eq '_unknown_'; return $loginName; @@ -311,34 +358,157 @@ =pod ----++++ getGroupMembers($name) -> \@members +---++++ getCanonicalUserID ($login) -> cUID -Returns a list of user ids that are in a given group, undef if the group does -not exist. +Convert a login name to the corresponding canonical user name. +Caution: we don't distinguish cUIDs and login names. + =cut -sub getGroupMembers { - my ($this, $groupName) = @_; +sub getCanonicalUserID { + my ($this, $login) = @_; + return $login; } +=pod +---++++ getLoginName ($user) -> login + +Converts an internal cUID to that user's login. + +Caution: we don't distinguish cUIDs and login names. + +=cut + +sub getLoginName { + my ($this, $user) = @_; + + return $this->lookupWikiName($user) || $user; +} + =pod ----++++ finish() +---++++ getWikiName ($cUID) -> wikiname -Complete processing after the client's HTTP request has been responded -to. I.e. it disconnects the LDAP database connection. +Maps a canonical user name to a wikiname =cut -sub finish { - my $this = shift; +sub getWikiName { + my ($this, $cUID) = @_; - $this->{ldap}->finish() if $this->{ldap}; - $this->{ldap} = undef; - $this->SUPER::finish(); + return $this->lookupLoginName($cUID) || $cUID; } +=pod + +---++++ userExists($cUID) -> $boolean + +Determines if the user already exists or not. + +=cut + +sub userExists { + my ($this, $cUID) = @_; + + my $wikiName = $this->{ldap}->getWikiNameOfLogin($cUID); + + return 1 if $wikiName; + + if ($this->{ldap}{twikiGroupsBackoff}) { + return $this->SUPER::userExists($cUID); + } + + return 0; +} + +=pod + +---++++ eachUser () -> listIterator of cUIDs + +returns a list iterator for all known users + +=cut + +sub eachUser { + my $this = shift; + + my @allLoginNames = $this->{ldap}->getAllLoginNames(); + my $ldapIter = new TWiki::ListIterator(@allLoginNames); + + return $ldapIter unless $this->{ldap}{twikiGroupsBackoff}; + + my $backOffIter = $this->SUPER::eachUser(@_); + my @list = ($ldapIter, $backOffIter); + + return new TWiki::AggregateIterator(\@list, 1); +} + +=pod + +---++++ eachGroup () -> listIterator of groupnames + +returns a list iterator for all known groups + +=cut + +sub eachGroup { + my ($this) = @_; + + my @groups = $this->getListOfGroups(); + + return new TWiki::ListIterator(\@groups ); +} + +=pod + +---++++ eachGroupMember ($groupName) -> listIterator of cUIDs + +returns a list iterator for all groups members + +=cut + +sub eachGroupMember { + my ($this, $groupName) = @_; + + return $this->SUPER::eachGroupMember($groupName) + unless $this->{ldap}{mapGroups}; + + my $members = $this->{ldap}->getGroupMembers($groupName) || []; + + unless (@$members) { + # fallback to twiki groups, + # try also to find the SuperAdminGroup + if ($this->{ldap}{twikiGroupsBackoff} + || $groupName eq $TWiki::cfg{SuperAdminGroup}) { + return $this->SUPER::eachGroupMember($groupName); + } + } + + return new TWiki::ListIterator($members); +} + +=pod + +---++++ eachMembership ($cUID) -> listIterator of groups this user is in + +returns a list iterator for all groups a user is in. + +=cut + +sub eachMembership { + my ($this, $user) = @_; + + my @groups = $this->getListOfGroups(); + + my $it = new TWiki::ListIterator( \@groups ); + $it->{filter} = sub { + $this->isInGroup($user, $_[0]); + }; + + return $it; +} + 1; |