2012-04-14 16:05:29 +00:00
< ? php
/**
* ownCloud – LDAP lib
*
* @ author Arthur Schiwon
* @ copyright 2012 Arthur Schiwon blizzz @ owncloud . com
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details .
*
* You should have received a copy of the GNU Affero General Public
* License along with this library . If not , see < http :// www . gnu . org / licenses />.
*
*/
2012-04-25 18:34:58 +00:00
define ( 'LDAP_GROUP_MEMBER_ASSOC_ATTR' , 'uniqueMember' );
define ( 'LDAP_GROUP_DISPLAY_NAME_ATTR' , 'cn' );
2012-04-15 11:37:35 +00:00
2012-04-16 16:03:02 +00:00
//needed to unbind, because we use OC_LDAP only statically
class OC_LDAP_DESTRUCTOR {
public function __destruct () {
OC_LDAP :: destruct ();
}
}
2012-04-15 11:37:35 +00:00
class OC_LDAP {
2012-04-14 16:05:29 +00:00
static protected $ldapConnectionRes = false ;
static protected $configured = false ;
//cached settings
static protected $ldapHost ;
static protected $ldapPort ;
static protected $ldapBase ;
2012-04-23 11:04:58 +00:00
static protected $ldapBaseUsers ;
static protected $ldapBaseGroups ;
2012-04-14 16:05:29 +00:00
static protected $ldapAgentName ;
static protected $ldapAgentPassword ;
static protected $ldapTLS ;
static protected $ldapNoCase ;
2012-05-17 17:33:38 +00:00
static protected $ldapIgnoreNamingRules ;
2012-04-15 12:21:38 +00:00
// user and group settings, that are needed in both backends
2012-04-25 18:34:58 +00:00
static protected $ldapUserDisplayName ;
static protected $ldapUserFilter ;
static protected $ldapGroupDisplayName ;
2012-05-08 21:47:23 +00:00
static protected $ldapLoginFilter ;
2012-04-15 12:21:38 +00:00
2012-06-07 16:13:41 +00:00
static protected $__d ;
2012-05-17 17:33:38 +00:00
/**
* @ brief initializes the LDAP backend
* @ param $force read the config settings no matter what
*
* initializes the LDAP backend
*/
static public function init ( $force = false ) {
2012-06-07 16:13:41 +00:00
if ( is_null ( self :: $__d )) {
self :: $__d = new OC_LDAP_DESTRUCTOR ();
}
2012-05-17 17:33:38 +00:00
self :: readConfiguration ( $force );
2012-04-14 16:05:29 +00:00
self :: establishConnection ();
}
2012-04-16 16:03:02 +00:00
static public function destruct () {
@ ldap_unbind ( self :: $ldapConnectionRes );
}
2012-04-25 18:34:58 +00:00
/**
* @ brief returns a read - only configuration value
* @ param $key the name of the configuration value
* @ returns the value on success , otherwise null
*
* returns a read - only configuration values
*
* we cannot work with getters , because it is a static class
*/
2012-04-15 12:47:33 +00:00
static public function conf ( $key ) {
2012-04-25 18:34:58 +00:00
if ( ! self :: $configured ) {
self :: init ();
}
2012-04-16 11:27:20 +00:00
$availableProperties = array (
'ldapUserDisplayName' ,
2012-04-25 18:34:58 +00:00
'ldapGroupDisplayName' ,
2012-05-08 21:47:23 +00:00
'ldapLoginFilter'
2012-04-16 11:27:20 +00:00
);
2012-04-15 12:47:33 +00:00
if ( in_array ( $key , $availableProperties )) {
return self :: $$key ;
}
2012-04-25 18:34:58 +00:00
return null ;
}
/**
* gives back the database table for the query
*/
static private function getMapTable ( $isUser ) {
if ( $isUser ) {
return '*PREFIX*ldap_user_mapping' ;
} else {
return '*PREFIX*ldap_group_mapping' ;
}
}
/**
* @ brief returns the LDAP DN for the given internal ownCloud name of the group
* @ param $name the ownCloud name in question
* @ returns string with the LDAP DN on success , otherwise false
*
* returns the LDAP DN for the given internal ownCloud name of the group
*/
static public function groupname2dn ( $name ) {
return self :: ocname2dn ( $name , false );
}
/**
* @ brief returns the LDAP DN for the given internal ownCloud name of the user
* @ param $name the ownCloud name in question
* @ returns string with the LDAP DN on success , otherwise false
*
* returns the LDAP DN for the given internal ownCloud name of the user
*/
static public function username2dn ( $name ) {
$dn = self :: ocname2dn ( $name , true );
if ( $dn ) {
return $dn ;
} else {
//fallback: user is not mapped
2012-05-08 12:02:16 +00:00
self :: init ();
2012-04-25 18:34:58 +00:00
$filter = self :: combineFilterWithAnd ( array (
self :: $ldapUserFilter ,
self :: $ldapUserDisplayName . '=' . $name ,
));
$result = self :: searchUsers ( $filter , 'dn' );
if ( isset ( $result [ 0 ][ 'dn' ])) {
self :: mapUser ( $result [ 0 ], $name );
return $result [ 0 ];
}
}
return false ;
}
static private function ocname2dn ( $name , $isUser ) {
$table = self :: getMapTable ( $isUser );
2012-05-03 11:06:08 +00:00
$query = OCP\DB :: prepare ( '
2012-04-25 18:34:58 +00:00
SELECT ldap_dn
FROM '.$table.'
WHERE owncloud_name = ?
' );
$record = $query -> execute ( array ( $name )) -> fetchOne ();
return $record ;
}
/**
* @ brief returns the internal ownCloud name for the given LDAP DN of the group
* @ param $dn the dn of the group object
* @ param $ldapname optional , the display name of the object
2012-06-18 23:15:58 +00:00
* @ returns string with with the name to use in ownCloud , false on DN outside of search DN
2012-04-25 18:34:58 +00:00
*
* returns the internal ownCloud name for the given LDAP DN of the group
*/
static public function dn2groupname ( $dn , $ldapname = null ) {
2012-06-20 10:41:30 +00:00
if ( strrpos ( $dn , self :: $ldapBaseGroups ) !== ( strlen ( $dn ) - strlen ( self :: $ldapBaseGroups ))) {
2012-06-18 23:15:58 +00:00
return false ;
}
2012-04-25 18:34:58 +00:00
return self :: dn2ocname ( $dn , $ldapname , false );
}
/**
* @ brief returns the internal ownCloud name for the given LDAP DN of the user
* @ param $dn the dn of the user object
* @ param $ldapname optional , the display name of the object
* @ returns string with with the name to use in ownCloud
*
2012-06-18 23:15:58 +00:00
* returns the internal ownCloud name for the given LDAP DN of the user , false on DN outside of search DN
2012-04-25 18:34:58 +00:00
*/
static public function dn2username ( $dn , $ldapname = null ) {
2012-06-20 10:41:30 +00:00
if ( strrpos ( $dn , self :: $ldapBaseUsers ) !== ( strlen ( $dn ) - strlen ( self :: $ldapBaseUsers ))) {
2012-06-18 23:15:58 +00:00
return false ;
}
2012-04-25 18:34:58 +00:00
return self :: dn2ocname ( $dn , $ldapname , true );
}
static public function dn2ocname ( $dn , $ldapname = null , $isUser = true ) {
2012-05-14 10:25:10 +00:00
$dn = self :: sanitizeDN ( $dn );
2012-04-25 18:34:58 +00:00
$table = self :: getMapTable ( $isUser );
if ( $isUser ) {
$nameAttribute = self :: conf ( 'ldapUserDisplayName' );
} else {
$nameAttribute = self :: conf ( 'ldapGroupDisplayName' );
}
2012-05-03 11:06:08 +00:00
$query = OCP\DB :: prepare ( '
2012-04-25 18:34:58 +00:00
SELECT owncloud_name
FROM '.$table.'
WHERE ldap_dn = ?
' );
$component = $query -> execute ( array ( $dn )) -> fetchOne ();
if ( $component ) {
return $component ;
}
if ( is_null ( $ldapname )) {
$ldapname = self :: readAttribute ( $dn , $nameAttribute );
$ldapname = $ldapname [ 0 ];
}
2012-05-17 13:14:47 +00:00
$ldapname = self :: sanitizeUsername ( $ldapname );
2012-04-25 18:34:58 +00:00
//a new user/group! Then let's try to add it. We're shooting into the blue with the user/group name, assuming that in most cases there will not be a conflict. Otherwise an error will occur and we will continue with our second shot.
if ( self :: mapComponent ( $dn , $ldapname , $isUser )) {
return $ldapname ;
}
//doh! There is a conflict. We need to distinguish between users/groups. Adding indexes is an idea, but not much of a help for the user. The DN is ugly, but for now the only reasonable way. But we transform it to a readable format and remove the first part to only give the path where this object is located.
$oc_name = self :: alternateOwnCloudName ( $ldapname , $dn );
if ( self :: mapComponent ( $dn , $oc_name , $isUser )) {
return $oc_name ;
}
//and this of course should never been thrown :)
throw new Exception ( 'LDAP backend: unexpected collision of DN and ownCloud Name.' );
}
/**
* @ brief gives back the user names as they are used ownClod internally
* @ param $ldapGroups an array with the ldap Users result in style of array ( array ( 'dn' => foo , 'uid' => bar ), ... )
* @ returns an array with the user names to use in ownCloud
*
* gives back the user names as they are used ownClod internally
*/
static public function ownCloudUserNames ( $ldapUsers ) {
return self :: ldap2ownCloudNames ( $ldapUsers , true );
}
/**
* @ brief gives back the group names as they are used ownClod internally
* @ param $ldapGroups an array with the ldap Groups result in style of array ( array ( 'dn' => foo , 'cn' => bar ), ... )
* @ returns an array with the group names to use in ownCloud
*
* gives back the group names as they are used ownClod internally
*/
static public function ownCloudGroupNames ( $ldapGroups ) {
return self :: ldap2ownCloudNames ( $ldapGroups , false );
}
static private function ldap2ownCloudNames ( $ldapObjects , $isUsers ) {
if ( $isUsers ) {
$knownObjects = self :: mappedUsers ();
$nameAttribute = self :: conf ( 'ldapUserDisplayName' );
} else {
$knownObjects = self :: mappedGroups ();
$nameAttribute = self :: conf ( 'ldapGroupDisplayName' );
}
$ownCloudNames = array ();
foreach ( $ldapObjects as $ldapObject ) {
$key = self :: recursiveArraySearch ( $knownObjects , $ldapObject [ 'dn' ]);
//everything is fine when we know the group
2012-06-07 10:44:59 +00:00
if ( $key !== false ) {
2012-04-25 18:34:58 +00:00
$ownCloudNames [] = $knownObjects [ $key ][ 'owncloud_name' ];
continue ;
}
2012-05-17 13:14:47 +00:00
//a new group! Then let's try to add it. We're shooting into the blue with the group name, assuming that in most cases there will not be a conflict. But first make sure, that the display name contains only allowed characters.
$ocname = self :: sanitizeUsername ( $ldapObject [ $nameAttribute ]);
if ( self :: mapComponent ( $ldapObject [ 'dn' ], $ocname , $isUsers )) {
$ownCloudNames [] = $ocname ;
2012-04-25 18:34:58 +00:00
continue ;
}
//doh! There is a conflict. We need to distinguish between groups. Adding indexes is an idea, but not much of a help for the user. The DN is ugly, but for now the only reasonable way. But we transform it to a readable format and remove the first part to only give the path where this entry is located.
2012-05-17 13:14:47 +00:00
$ocname = self :: alternateOwnCloudName ( $ocname , $ldapObject [ 'dn' ]);
if ( self :: mapComponent ( $ldapObject [ 'dn' ], $ocname , $isUsers )) {
$ownCloudNames [] = $ocname ;
2012-04-25 18:34:58 +00:00
continue ;
}
//and this of course should never been thrown :)
throw new Exception ( 'LDAP backend: unexpected collision of DN and ownCloud Name.' );
}
return $ownCloudNames ;
}
/**
* @ brief creates a hopefully unique name for owncloud based on the display name and the dn of the LDAP object
* @ param $name the display name of the object
* @ param $dn the dn of the object
* @ returns string with with the name to use in ownCloud
*
* creates a hopefully unique name for owncloud based on the display name and the dn of the LDAP object
*/
static private function alternateOwnCloudName ( $name , $dn ) {
$ufn = ldap_dn2ufn ( $dn );
2012-05-17 13:14:47 +00:00
$name = $name . '@' . trim ( substr_replace ( $ufn , '' , 0 , strpos ( $ufn , ',' )));
$name = self :: sanitizeUsername ( $name );
return $name ;
2012-04-25 18:34:58 +00:00
}
/**
* @ brief retrieves all known groups from the mappings table
* @ returns array with the results
*
* retrieves all known groups from the mappings table
*/
static private function mappedGroups () {
return self :: mappedComponents ( false );
}
/**
* @ brief retrieves all known users from the mappings table
* @ returns array with the results
*
* retrieves all known users from the mappings table
*/
static private function mappedUsers () {
return self :: mappedComponents ( true );
}
static private function mappedComponents ( $isUsers ) {
$table = self :: getMapTable ( $isUsers );
2012-05-03 11:06:08 +00:00
$query = OCP\DB :: prepare ( '
2012-04-25 18:34:58 +00:00
SELECT ldap_dn , owncloud_name
FROM ' . $table
);
return $query -> execute () -> fetchAll ();
}
/**
* @ brief inserts a new user or group into the mappings table
* @ param $dn the record in question
* @ param $ocname the name to use in ownCloud
* @ param $isUser is it a user or a group ?
* @ returns true on success , false otherwise
*
* inserts a new user or group into the mappings table
*/
static private function mapComponent ( $dn , $ocname , $isUser = true ) {
$table = self :: getMapTable ( $isUser );
2012-05-14 10:25:10 +00:00
$dn = self :: sanitizeDN ( $dn );
2012-04-25 18:34:58 +00:00
2012-05-31 11:06:27 +00:00
$sqlAdjustment = '' ;
2012-05-08 11:56:07 +00:00
$dbtype = OCP\Config :: getSystemValue ( 'dbtype' );
2012-05-31 11:06:27 +00:00
if ( $dbtype == 'mysql' ) {
$sqlAdjustment = 'FROM dual' ;
2012-05-08 11:56:07 +00:00
}
2012-05-03 11:06:08 +00:00
$insert = OCP\DB :: prepare ( '
2012-05-31 11:06:27 +00:00
INSERT INTO '.$table.' ( ldap_dn , owncloud_name )
SELECT ? , ?
'.$sqlAdjustment.'
WHERE NOT EXISTS (
SELECT 1
FROM '.$table.'
WHERE ldap_dn = ?
2012-06-07 11:36:34 +00:00
OR owncloud_name = ? )
2012-04-25 18:34:58 +00:00
' );
2012-05-31 11:06:27 +00:00
$res = $insert -> execute ( array ( $dn , $ocname , $dn , $ocname ));
2012-04-25 18:34:58 +00:00
2012-06-07 11:36:34 +00:00
if ( OCP\DB :: isError ( $res )) {
return false ;
}
$insRows = $res -> numRows ();
if ( $insRows == 0 ) {
return false ;
}
return true ;
2012-04-15 12:47:33 +00:00
}
2012-05-03 21:38:55 +00:00
static public function fetchListOfUsers ( $filter , $attr ) {
return self :: fetchList ( OC_LDAP :: searchUsers ( $filter , $attr ), ( count ( $attr ) > 1 ));
}
static public function fetchListOfGroups ( $filter , $attr ) {
return self :: fetchList ( OC_LDAP :: searchGroups ( $filter , $attr ), ( count ( $attr ) > 1 ));
}
static private function fetchList ( $list , $manyAttributes ) {
if ( is_array ( $list )) {
if ( $manyAttributes ) {
return $list ;
} else {
return array_unique ( $list , SORT_LOCALE_STRING );
}
}
//error cause actually, maybe throw an exception in future.
return array ();
}
2012-04-23 19:11:54 +00:00
/**
* @ brief reads a given attribute for an LDAP record identified by a DN
* @ param $dn the record in question
* @ param $attr the attribute that shall be retrieved
2012-04-25 18:34:58 +00:00
* @ returns the values in an array on success , false otherwise
2012-04-23 19:11:54 +00:00
*
* Reads an attribute from an LDAP entry
*/
static public function readAttribute ( $dn , $attr ) {
$cr = self :: getConnectionResource ();
$rr = ldap_read ( $cr , $dn , 'objectClass=*' , array ( $attr ));
$er = ldap_first_entry ( $cr , $rr );
2012-05-11 13:42:05 +00:00
//LDAP attributes are not case sensitive
$result = array_change_key_case ( ldap_get_attributes ( $cr , $er ));
$attr = strtolower ( $attr );
2012-04-25 18:34:58 +00:00
2012-05-04 12:13:23 +00:00
if ( isset ( $result [ $attr ]) && $result [ $attr ][ 'count' ] > 0 ){
2012-04-25 18:34:58 +00:00
$values = array ();
for ( $i = 0 ; $i < $result [ $attr ][ 'count' ]; $i ++ ) {
2012-06-25 11:16:35 +00:00
$values [] = self :: resemblesDN ( $attr ) ? self :: sanitizeDN ( $result [ $attr ][ $i ]) : $result [ $attr ][ $i ];
2012-04-25 18:34:58 +00:00
}
return $values ;
2012-04-23 19:11:54 +00:00
}
return false ;
}
2012-04-23 11:04:58 +00:00
/**
* @ brief executes an LDAP search , optimized for Users
* @ param $filter the LDAP filter for the search
* @ param $attr optional , when a certain attribute shall be filtered out
* @ returns array with the search result
*
* Executes an LDAP search
*/
static public function searchUsers ( $filter , $attr = null ) {
2012-05-08 12:02:16 +00:00
self :: init ();
2012-04-23 11:04:58 +00:00
return self :: search ( $filter , self :: $ldapBaseUsers , $attr );
}
/**
* @ brief executes an LDAP search , optimized for Groups
* @ param $filter the LDAP filter for the search
* @ param $attr optional , when a certain attribute shall be filtered out
* @ returns array with the search result
*
* Executes an LDAP search
*/
static public function searchGroups ( $filter , $attr = null ) {
2012-05-08 12:02:16 +00:00
self :: init ();
2012-04-23 11:04:58 +00:00
return self :: search ( $filter , self :: $ldapBaseGroups , $attr );
}
2012-04-14 16:26:46 +00:00
/**
* @ brief executes an LDAP search
* @ param $filter the LDAP filter for the search
2012-04-23 11:04:58 +00:00
* @ param $base the LDAP subtree that shall be searched
2012-04-14 16:26:46 +00:00
* @ param $attr optional , when a certain attribute shall be filtered out
* @ returns array with the search result
*
* Executes an LDAP search
*/
2012-04-23 11:04:58 +00:00
static private function search ( $filter , $base , $attr = null ) {
2012-04-25 18:34:58 +00:00
if ( ! is_null ( $attr ) && ! is_array ( $attr )) {
$attr = array ( strtolower ( $attr ));
}
2012-05-28 13:54:38 +00:00
2012-06-22 20:57:35 +00:00
// See if we have a resource
2012-05-28 13:54:38 +00:00
$link_resource = self :: getConnectionResource ();
if ( $link_resource )
{
$sr = ldap_search ( $link_resource , $base , $filter , $attr );
$findings = ldap_get_entries ( $link_resource , $sr );
2012-06-22 20:57:35 +00:00
// if we're here, probably no connection resource is returned.
2012-05-28 13:54:38 +00:00
// to make ownCloud behave nicely, we simply give back an empty array.
if ( is_null ( $findings )) {
return array ();
}
} else
{
// Seems like we didn't find any resource.
// Return an empty array just like before.
2012-05-01 10:17:33 +00:00
return array ();
}
2012-04-14 16:05:29 +00:00
if ( ! is_null ( $attr )) {
$selection = array ();
2012-04-25 18:34:58 +00:00
$multiarray = false ;
if ( count ( $attr ) > 1 ) {
$multiarray = true ;
$i = 0 ;
}
2012-04-14 16:05:29 +00:00
foreach ( $findings as $item ) {
2012-05-17 11:15:26 +00:00
if ( ! is_array ( $item )) {
continue ;
}
$item = array_change_key_case ( $item );
2012-04-25 18:34:58 +00:00
if ( $multiarray ) {
foreach ( $attr as $key ) {
2012-05-17 11:15:26 +00:00
$key = strtolower ( $key );
2012-04-25 18:34:58 +00:00
if ( isset ( $item [ $key ])) {
if ( $key != 'dn' ){
2012-06-25 11:16:35 +00:00
$selection [ $i ][ $key ] = self :: resemblesDN ( $key ) ? self :: sanitizeDN ( $item [ $key ][ 0 ]) : $item [ $key ][ 0 ];
2012-04-25 18:34:58 +00:00
} else {
2012-05-14 10:25:10 +00:00
$selection [ $i ][ $key ] = self :: sanitizeDN ( $item [ $key ]);
2012-04-25 18:34:58 +00:00
}
}
}
$i ++ ;
} else {
2012-05-11 13:42:05 +00:00
//tribute to case insensitivity
$key = strtolower ( $attr [ 0 ]);
if ( isset ( $item [ $key ])) {
2012-06-25 11:16:35 +00:00
if ( self :: resemblesDN ( $key )) {
2012-05-14 10:25:10 +00:00
$selection [] = self :: sanitizeDN ( $item [ $key ]);
} else {
$selection [] = $item [ $key ];
}
2012-04-25 18:34:58 +00:00
}
2012-04-14 16:05:29 +00:00
}
2012-04-25 18:34:58 +00:00
2012-04-14 16:05:29 +00:00
}
return $selection ;
}
return $findings ;
}
2012-06-25 11:16:35 +00:00
static private function resemblesDN ( $attr ) {
$resemblingAttributes = array (
'dn' ,
'uniquemember' ,
'member'
);
return in_array ( $attr , $resemblingAttributes );
}
2012-05-14 10:25:10 +00:00
static private function sanitizeDN ( $dn ) {
//OID sometimes gives back DNs with whitespace after the comma a la "uid=foo, cn=bar, dn=..." We need to tackle this!
2012-06-06 10:29:48 +00:00
$dn = preg_replace ( '/([^\\\]),(\s+)/' , '\1,' , $dn );
2012-05-14 10:25:10 +00:00
2012-05-15 09:12:29 +00:00
//make comparisons and everything work
$dn = strtolower ( $dn );
2012-05-14 10:25:10 +00:00
return $dn ;
}
2012-05-17 13:14:47 +00:00
static private function sanitizeUsername ( $name ) {
2012-05-17 17:33:38 +00:00
if ( self :: $ldapIgnoreNamingRules ) {
return $name ;
}
2012-05-17 13:14:47 +00:00
//REPLACEMENTS
$name = str_replace ( ' ' , '_' , $name );
//every remaining unallowed characters will be removed
$name = preg_replace ( '/[^a-zA-Z0-9_.@-]/' , '' , $name );
return $name ;
}
2012-04-15 11:37:35 +00:00
/**
* @ brief combines the input filters with AND
* @ param $filters array , the filters to connect
* @ returns the combined filter
*
* Combines Filter arguments with AND
*/
static public function combineFilterWithAnd ( $filters ) {
return self :: combineFilter ( $filters , '&' );
}
/**
* @ brief combines the input filters with AND
* @ param $filters array , the filters to connect
* @ returns the combined filter
*
* Combines Filter arguments with AND
*/
static public function combineFilterWithOr ( $filters ) {
return self :: combineFilter ( $filters , '|' );
}
/**
* @ brief combines the input filters with given operator
* @ param $filters array , the filters to connect
* @ param $operator either & or |
* @ returns the combined filter
*
* Combines Filter arguments with AND
*/
static private function combineFilter ( $filters , $operator ) {
$combinedFilter = '(' . $operator ;
foreach ( $filters as $filter ) {
2012-06-08 19:23:25 +00:00
if ( $filter [ 0 ] != '(' ) {
2012-04-15 11:37:35 +00:00
$filter = '(' . $filter . ')' ;
}
$combinedFilter .= $filter ;
}
$combinedFilter .= ')' ;
return $combinedFilter ;
}
2012-04-14 16:26:46 +00:00
/**
* Returns the LDAP handler
*/
2012-04-14 16:05:29 +00:00
static private function getConnectionResource () {
if ( ! self :: $ldapConnectionRes ) {
self :: init ();
}
2012-05-01 10:17:33 +00:00
if ( is_null ( self :: $ldapConnectionRes )) {
2012-05-01 15:38:27 +00:00
OCP\Util :: writeLog ( 'ldap' , 'Connection could not be established' , OCP\Util :: INFO );
2012-05-01 10:17:33 +00:00
}
2012-04-14 16:05:29 +00:00
return self :: $ldapConnectionRes ;
}
2012-04-14 16:26:46 +00:00
/**
* Caches the general LDAP configuration .
*/
2012-05-17 17:33:38 +00:00
static private function readConfiguration ( $force = false ) {
if ( ! self :: $configured || $force ) {
self :: $ldapHost = OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_host' , '' );
self :: $ldapPort = OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_port' , 389 );
self :: $ldapAgentName = OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_dn' , '' );
self :: $ldapAgentPassword = base64_decode ( OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_agent_password' , '' ));
self :: $ldapBase = OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_base' , '' );
self :: $ldapBaseUsers = OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_base_users' , self :: $ldapBase );
self :: $ldapBaseGroups = OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_base_groups' , self :: $ldapBase );
self :: $ldapTLS = OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_tls' , 0 );
self :: $ldapNoCase = OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_nocase' , 0 );
self :: $ldapUserDisplayName = strtolower ( OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_display_name' , 'uid' ));
self :: $ldapUserFilter = OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_userlist_filter' , 'objectClass=person' );
self :: $ldapLoginFilter = OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_login_filter' , '(uid=%uid)' );
self :: $ldapGroupDisplayName = strtolower ( OCP\Config :: getAppValue ( 'user_ldap' , 'ldap_group_display_name' , LDAP_GROUP_DISPLAY_NAME_ATTR ));
self :: $ldapIgnoreNamingRules = OCP\Config :: getSystemValue ( 'ldapIgnoreNamingRules' , false );
2012-04-14 16:05:29 +00:00
2012-05-07 16:37:44 +00:00
if ( empty ( self :: $ldapBaseUsers )) {
OCP\Util :: writeLog ( 'ldap' , 'Base for Users is empty, using Base DN' , OCP\Util :: INFO );
self :: $ldapBaseUsers = self :: $ldapBase ;
}
if ( empty ( self :: $ldapBaseGroups )) {
OCP\Util :: writeLog ( 'ldap' , 'Base for Groups is empty, using Base DN' , OCP\Util :: INFO );
self :: $ldapBaseGroups = self :: $ldapBase ;
}
2012-04-16 15:28:58 +00:00
if (
! empty ( self :: $ldapHost )
&& ! empty ( self :: $ldapPort )
&& (
( ! empty ( self :: $ldapAgentName ) && ! empty ( self :: $ldapAgentPassword ))
|| ( empty ( self :: $ldapAgentName ) && empty ( self :: $ldapAgentPassword ))
)
&& ! empty ( self :: $ldapBase )
&& ! empty ( self :: $ldapUserDisplayName )
)
{
self :: $configured = true ;
}
2012-04-14 16:05:29 +00:00
}
}
2012-04-14 16:26:46 +00:00
/**
* Connects and Binds to LDAP
*/
2012-04-14 16:05:29 +00:00
static private function establishConnection () {
2012-04-16 15:28:58 +00:00
if ( ! self :: $configured ) {
2012-05-07 16:37:44 +00:00
OCP\Util :: writeLog ( 'ldap' , 'Configuration is invalid, cannot connect' , OCP\Util :: INFO );
2012-04-16 15:28:58 +00:00
return false ;
}
2012-04-14 16:05:29 +00:00
if ( ! self :: $ldapConnectionRes ) {
self :: $ldapConnectionRes = ldap_connect ( self :: $ldapHost , self :: $ldapPort );
if ( ldap_set_option ( self :: $ldapConnectionRes , LDAP_OPT_PROTOCOL_VERSION , 3 )) {
if ( ldap_set_option ( self :: $ldapConnectionRes , LDAP_OPT_REFERRALS , 0 )) {
if ( self :: $ldapTLS ) {
ldap_start_tls ( self :: $ldapConnectionRes );
}
}
}
$ldapLogin = @ ldap_bind ( self :: $ldapConnectionRes , self :: $ldapAgentName , self :: $ldapAgentPassword );
if ( ! $ldapLogin ) {
2012-05-08 10:04:52 +00:00
OCP\Util :: writeLog ( 'ldap' , 'Bind failed: ' . ldap_errno ( self :: $ldapConnectionRes ) . ': ' . ldap_error ( self :: $ldapConnectionRes ), OCP\Util :: ERROR );
2012-04-14 16:05:29 +00:00
return false ;
}
}
}
2012-05-04 11:02:20 +00:00
static public function areCredentialsValid ( $name , $password ) {
return @ ldap_bind ( self :: getConnectionResource (), $name , $password );
}
2012-04-25 18:34:58 +00:00
/**
* taken from http :// www . php . net / manual / en / function . array - search . php #97645
* TODO : move somewhere , where its better placed since it is not LDAP specific . OC_Helper maybe ?
*/
static public function recursiveArraySearch ( $haystack , $needle , $index = null ) {
$aIt = new RecursiveArrayIterator ( $haystack );
$it = new RecursiveIteratorIterator ( $aIt );
while ( $it -> valid ()) {
if ((( isset ( $index ) AND ( $it -> key () == $index )) OR ( ! isset ( $index ))) AND ( $it -> current () == $needle )) {
return $aIt -> key ();
}
$it -> next ();
}
return false ;
}
2012-04-14 16:05:29 +00:00
2012-06-08 19:23:25 +00:00
}