From 34c1fee3c68afe8f4094f5601efa98179936f03d Mon Sep 17 00:00:00 2001 From: Rob Ostensen Date: Sun, 21 Mar 2010 02:50:14 -0500 Subject: [PATCH] first run at ldap group support --- config/example-config.php | 9 ++- htdocs/tools.php | 13 ++++ inc/drivers_ldap.php | 140 +++++++++++++++++++++++++++++++++++++- 3 files changed, 158 insertions(+), 4 deletions(-) diff --git a/config/example-config.php b/config/example-config.php index def1bbd1..223bd14a 100644 --- a/config/example-config.php +++ b/config/example-config.php @@ -221,14 +221,19 @@ $c->collections_always_exist = false; // 'protocolVersion' => '3', //Version of LDAP protocol to use // 'baseDNUsers'=> 'dc=tennaxia,dc=net', //where to look at valid user // 'filterUsers' => 'objectClass=kolabInetOrgPerson', //filter which must validate a user according to RFC4515, i.e. surrounded by brackets -// 'baseDNGroups' => 'ou=divisions,dc=tennaxia,dc=net', //not used ATM -// 'filterGroups' => 'objectClass=groupOfUniqueNames', //not used ATM +// 'baseDNGroups' => 'ou=divisions,dc=tennaxia,dc=net', //where to look for groups +// 'filterGroups' => 'objectClass=groupOfUniqueNames', //filter with same rules as filterUsers /** /!\ "username" should be set and "updated" must be set **/ // 'mapping_field' => array("username" => "uid", // "updated" => "modifyTimestamp", // "fullname" => "cn" , // "email" =>"mail" // ), //used to create the user based on his ldap properties +// 'group_mapping_field' => array("username" => "cn", +// "updated" => "modifyTimestamp", +// "fullname" => "cn" , +// "members" =>"memberUid" +// ), //used to create the group based on the ldap properties /** used to set default value for all users, will be overcharged by ldap if defined also in mapping_field **/ // 'default_value' => array("date_format_type" => "E","locale" => "fr_FR"), /** foreach key set start and length in the string provided by ldap diff --git a/htdocs/tools.php b/htdocs/tools.php index f1b24470..d343bd8a 100644 --- a/htdocs/tools.php +++ b/htdocs/tools.php @@ -24,6 +24,10 @@ if( function_exists("sync_LDAP") && isset($_POST['Sync_LDAP'])){ sync_LDAP(); } +if( function_exists("sync_LDAP_groups") && isset($_POST['Sync_LDAP_groups'])){ + sync_LDAP_groups(); +} + if(isset($_POST['import_from_directory'])){ Tools::importFromDirectory(); } @@ -52,6 +56,15 @@ class Tools { $html .= "\n"; $html .= $ef->SubmitButton( "Sync_LDAP", translate('Submit')); + + $html .= '

'.translate('Sync LDAP Groups with RSCDS') .'

'; + $html .= "\n"; + $html .= $ef->StartForm( array("autocomplete" => "off" ) ); + $html .= sprintf( "\n", + translate("This operation does the following: then ")); + $html .= "
%s
\n"; + + $html .= $ef->SubmitButton( "Sync_LDAP_groups", translate('Submit')); $html .= $ef->EndForm(); $html .= ""; diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php index 58853230..94c58f07 100644 --- a/inc/drivers_ldap.php +++ b/inc/drivers_ldap.php @@ -114,7 +114,7 @@ class ldapDrivers //root to start search $this->baseDNUsers = is_string($config['baseDNUsers']) ? array($config['baseDNUsers']) : $config['baseDNUsers']; $this->filterUsers = (isset($config['filterUsers']) ? $config['filterUsers'] : null); - $this->baseDNGroups = (isset($config['baseDNGroups']) ? $config['baseDNGroups'] : null); + $this->baseDNGroups = is_string($config['baseDNGroups']) ? array($config['baseDNGroups']) : $config['baseDNGroups']; $this->filterGroups = (isset($config['filterGroups']) ? $config['filterGroups'] : null); } @@ -147,6 +147,36 @@ class ldapDrivers } return $ret; } + + /** + * Retrieve all groups from the LDAP directory + */ + function getAllGroups($attributes){ + global $c; + + $query = $this->ldap_query_all; + + foreach($this->baseDNGroups as $baseDNGroups) { + $entry = $query($this->connect,$baseDNGroups,$this->filterGroups,$attributes); + + if (!ldap_first_entry($this->connect,$entry)) { + $c->messages[] = sprintf(translate('Error NoGroupFound with filter >%s<, attributes >%s< , dn >%s<'), + $this->filterUsers, + join(', ', $attributes), + $baseDNGroups); + } + $row = array(); + for($i = ldap_first_entry($this->connect,$entry); + $i && $arr = ldap_get_attributes($this->connect,$i); + $i = ldap_next_entry($this->connect,$i) ) { + for ($j=0; $j < $arr['count']; $j++) { + $row[$arr[$j]] = count($arr[$arr[$j]])>2?$arr[$arr[$j]]:$arr[$arr[$j]][0]; + } + $ret[]=$row; + } + } + return $ret; + } /** * Returns the result of the LDAP query @@ -322,6 +352,112 @@ function LDAP_check($username, $password ){ } +/** +* sync LDAP Groups against the DB +*/ +function sync_LDAP_groups(){ + global $c; + $ldapDriver = getStaticLdap(); + if($ldapDriver->valid){ + $mapping = $c->authenticate_hook['config']['group_mapping_field']; + //$attributes = array('cn','modifyTimestamp','memberUid'); + $attributes = array_values($mapping); + $ldap_groups_tmp = $ldapDriver->getAllGroups($attributes); + + if ( sizeof($ldap_groups_tmp) == 0 ) + return; + + foreach($ldap_groups_tmp as $key => $ldap_group){ + $ldap_groups_info[$ldap_group[$mapping['username']]] = $ldap_group; + unset ( $ldap_groups_info[$ldap_group[$mapping['username']]][$mapping['members']]['count'] ); + unset($ldap_groups_tmp[$key]); + } + $db_groups = array (); + $db_group_members = array (); + $qry = new AwlQuery( "SELECT g.username AS group_name, member.username AS member_name FROM dav_principal g JOIN group_member ON (g.principal_id=group_member.group_id) JOIN dav_principal member ON (member.principal_id=group_member.member_id) WHERE g.type_id = 3"); + $qry->Exec('sync_LDAP',__LINE__,__FILE__); + while($db_group = $qry->Fetch()) { + $db_groups[$db_group->group_name] = $db_group->group_name; + $db_group_members[$db_group->group_name][] = $db_group->member_name; + } + + $ldap_groups = array_keys($ldap_groups_info); + // users only in ldap + $groups_to_create = array_diff($ldap_groups,$db_groups); + // users only in db + $groups_to_deactivate = array_diff($db_groups,$ldap_groups); + // users present in ldap and in the db + $groups_to_update = array_intersect($db_groups,$ldap_groups); + + if ( sizeof ( $groups_to_create ) ){ + $c->messages[] = sprintf(i18n('- creating groups : %s'),join(', ',$groups_to_create)); + $validUserFields = get_fields('usr'); + foreach ( $groups_to_create as $k => $group ){ + $user = (object) array( 'user_no' => 0, 'username' => '' ); + + if ( isset($c->authenticate_hook['config']['default_value']) && is_array($c->authenticate_hook['config']['default_value']) ) { + foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) { + if ( isset($validUserFields[$field]) ) { + $usr->{$field} = $value; + dbg_error_log( "LDAP", "Setting usr->%s to %s from configured defaults", $field, $value ); + } + } + } + $user->user_no = 0; + foreach ( $mapping as $field => $value ) { + dbg_error_log( "LDAP", "Considering copying %s", $field ); + if ( isset($validUserFields[$field]) ) { + $user->{$field} = $ldap_values[$value]; + dbg_error_log( "LDAP", "Setting usr->%s to %s from LDAP field %s", $field, $ldap_values[$value], $value ); + } + } + $user->fullname = $group; + $user->displayname = $group; + $user->username = $group; + UpdateUserFromExternal( $user ); + $qry = new AwlQuery( "UPDATE dav_principal set type_id = 3 WHERE username=:group ",array(':group'=>$group) ); + $qry->Exec('sync_LDAP',__LINE__,__FILE__); + $c->messages[] = sprintf(i18n('- adding users %s to group : %s'),join(',',$ldap_groups_info[$group][$mapping['members']]),$group); + foreach ( $ldap_groups_info[$group][$mapping['members']] as $member ){ + $qry = new AwlQuery( "INSERT INTO group_member SELECT g.principal_id AS group_id,u.principal_id AS member_id FROM dav_principal g, dav_principal u WHERE g.username=:group AND u.username=:member;",array (':group'=>$group,':member'=>$member) ); + $qry->Exec('sync_LDAP_groups',__LINE__,__FILE__); + } + } + } + + if ( sizeof ( $groups_to_update ) ){ + $c->messages[] = sprintf(i18n('- updating groups : %s'),join(', ',$groups_to_update)); + foreach ( $groups_to_update as $group ){ + $db_members = array_values ( $db_group_members[$group] ); + $ldap_members = array_values ( $ldap_groups_info[$group][$mapping['members']] ); + $add_users = array_diff ( $ldap_members, $db_members ); + if ( sizeof ( $add_users ) ){ + $c->messages[] = sprintf(i18n('- adding %s to group : %s'),join(', ', $add_users ), $group); + foreach ( $add_users as $member ){ + $qry = new AwlQuery( "INSERT INTO group_member SELECT g.principal_id AS group_id,u.principal_id AS member_id FROM dav_principal g, dav_principal u WHERE g.username=:group AND u.username=:member",array (':group'=>$group,':member'=>$member) ); + $qry->Exec('sync_LDAP_groups',__LINE__,__FILE__); + } + } + $remove_users = array_diff ( $db_members, $ldap_members ); + if ( sizeof ( $remove_users ) ){ + $c->messages[] = sprintf(i18n('- removing %s from group : %s'),join(', ', $remove_users ), $group); + foreach ( $remove_users as $member ){ + $qry = new AwlQuery( "DELETE FROM group_member USING dav_principal g,dav_principal m WHERE group_id=g.principal_id AND member_id=m.principal_id AND g.username=:group AND m.username=:member",array (':group'=>$group,':member'=>$member) ); + $qry->Exec('sync_LDAP_groups',__LINE__,__FILE__); + } + } + } + } + + if ( sizeof ( $groups_to_deactivate ) ){ + $c->messages[] = sprintf(i18n('- deactivate groups : %s'),join(', ',$groups_to_deactivate)); + foreach ( $groups_to_deactivate as $group ){ + $qry = new AwlQuery( "UPDATE dav_principal set active='f'::bool WHERE username=:group AND type_id = 3",array(':group'=>$group) ); + $qry->Exec('sync_LDAP',__LINE__,__FILE__); + } + } + } +} /** * sync LDAP against the DB @@ -341,7 +477,7 @@ function sync_LDAP(){ $ldap_users_info[$ldap_user[$mapping["username"]]] = $ldap_user; unset($ldap_users_tmp[$key]); } - $qry = new AwlQuery( "SELECT username, user_no, updated FROM usr "); + $qry = new AwlQuery( "SELECT username, user_no, modified as updated FROM dav_principal where type_id=1"); $qry->Exec('sync_LDAP',__LINE__,__FILE__); while($db_user = $qry->Fetch()) { $db_users[] = $db_user->username;