Commit ad6814f9 authored by blizzz's avatar blizzz
Browse files

Merge pull request #12101 from owncloud/ldap_split_mapping

Ldap split mapping from Access superclass
parents f671b232 ec0f80fe
......@@ -21,15 +21,27 @@
*
*/
use OCA\User_LDAP\Mapping\UserMapping;
use OCA\User_LDAP\Mapping\GroupMapping;
// Check user and app status
OCP\JSON::checkAdminUser();
OCP\JSON::checkAppEnabled('user_ldap');
OCP\JSON::callCheck();
$subject = $_POST['ldap_clear_mapping'];
if(\OCA\user_ldap\lib\Helper::clearMapping($subject)) {
$mapping = null;
if($subject === 'user') {
$mapping = new UserMapping(\OC::$server->getDatabaseConnection());
} else if($subject === 'group') {
$mapping = new GroupMapping(\OC::$server->getDatabaseConnection());
}
try {
if(is_null($mapping) || !$mapping->clear()) {
$l = \OC::$server->getL10N('user_ldap');
throw new \Exception($l->t('Failed to clear the mappings.'));
}
OCP\JSON::success();
} else {
$l = \OC::$server->getL10N('user_ldap');
OCP\JSON::error(array('message' => $l->t('Failed to clear the mappings.')));
} catch (\Exception $e) {
OCP\JSON::error(array('message' => $e->getMessage()));
}
......@@ -34,6 +34,9 @@ if(count($configPrefixes) === 1) {
new \OCP\Image());
$connector = new OCA\user_ldap\lib\Connection($ldapWrapper, $configPrefixes[0]);
$ldapAccess = new OCA\user_ldap\lib\Access($connector, $ldapWrapper, $userManager);
$dbc = \OC::$server->getDatabaseConnection();
$ldapAccess->setUserMapper(new OCA\User_LDAP\Mapping\UserMapping($dbc));
$ldapAccess->setGroupMapper(new OCA\User_LDAP\Mapping\GroupMapping($dbc));
$userBackend = new OCA\user_ldap\USER_LDAP($ldapAccess);
$groupBackend = new OCA\user_ldap\GROUP_LDAP($ldapAccess);
} else if(count($configPrefixes) > 1) {
......
......@@ -23,6 +23,8 @@
namespace OCA\user_ldap\lib;
use OCA\User_LDAP\Mapping\AbstractMapping;
/**
* Class Access
* @package OCA\user_ldap\lib
......@@ -47,6 +49,16 @@ class Access extends LDAPUtility implements user\IUserTools {
*/
protected $lastCookie = '';
/**
* @var AbstractMapping $userMapper
*/
protected $userMapper;
/**
* @var AbstractMapping $userMapper
*/
protected $groupMapper;
public function __construct(Connection $connection, ILDAPWrapper $ldap,
user\Manager $userManager) {
parent::__construct($ldap);
......@@ -55,6 +67,22 @@ class Access extends LDAPUtility implements user\IUserTools {
$this->userManager->setLdapAccess($this);
}
/**
* sets the User Mapper
* @param AbstractMapping $mapper
*/
public function setUserMapper(AbstractMapping $mapper) {
$this->userMapper = $mapper;
}
/**
* sets the Group Mapper
* @param AbstractMapping $mapper
*/
public function setGroupMapper(AbstractMapping $mapper) {
$this->groupMapper = $mapper;
}
/**
* @return bool
*/
......@@ -235,32 +263,13 @@ class Access extends LDAPUtility implements user\IUserTools {
return $domainDN;
}
/**
* gives back the database table for the query
* @param bool $isUser
* @return string
*/
private function getMapTable($isUser) {
if($isUser) {
return '*PREFIX*ldap_user_mapping';
} else {
return '*PREFIX*ldap_group_mapping';
}
}
/**
* returns the LDAP DN for the given internal ownCloud name of the group
* @param string $name the ownCloud name in question
* @return string with the LDAP DN on success, otherwise false
* @return string|false LDAP DN on success, otherwise false
*/
public function groupname2dn($name) {
$dn = $this->ocname2dn($name, false);
if($dn) {
return $dn;
}
return false;
return $this->groupMapper->getDNbyName($name);
}
/**
......@@ -269,50 +278,32 @@ class Access extends LDAPUtility implements user\IUserTools {
* @return string with the LDAP DN on success, otherwise false
*/
public function username2dn($name) {
$dn = $this->ocname2dn($name, true);
$fdn = $this->userMapper->getDNbyName($name);
//Check whether the DN belongs to the Base, to avoid issues on multi-
//server setups
if($dn && $this->isDNPartOfBase($dn, $this->connection->ldapBaseUsers)) {
return $dn;
if(is_string($fdn) && $this->isDNPartOfBase($fdn, $this->connection->ldapBaseUsers)) {
return $fdn;
}
return false;
}
/**
* returns the LDAP DN for the given internal ownCloud name
* @param string $name the ownCloud name in question
* @param boolean $isUser is it a user? otherwise group
* @return string with the LDAP DN on success, otherwise false
*/
private function ocname2dn($name, $isUser) {
$table = $this->getMapTable($isUser);
$query = \OCP\DB::prepare('
SELECT `ldap_dn`
FROM `'.$table.'`
WHERE `owncloud_name` = ?
');
$record = $query->execute(array($name))->fetchOne();
return $record;
}
/**
* returns the internal ownCloud name for the given LDAP DN of the group, false on DN outside of search DN or failure
* @param string $dn the dn of the group object
* @param string $fdn the dn of the group object
* @param string $ldapName optional, the display name of the object
* @return string with the name to use in ownCloud, false on DN outside of search DN
*/
public function dn2groupname($dn, $ldapName = null) {
public function dn2groupname($fdn, $ldapName = null) {
//To avoid bypassing the base DN settings under certain circumstances
//with the group support, check whether the provided DN matches one of
//the given Bases
if(!$this->isDNPartOfBase($dn, $this->connection->ldapBaseGroups)) {
if(!$this->isDNPartOfBase($fdn, $this->connection->ldapBaseGroups)) {
return false;
}
return $this->dn2ocname($dn, $ldapName, false);
return $this->dn2ocname($fdn, $ldapName, false);
}
/**
......@@ -321,15 +312,15 @@ class Access extends LDAPUtility implements user\IUserTools {
* @param string $ldapName optional, the display name of the object
* @return string with with the name to use in ownCloud
*/
public function dn2username($dn, $ldapName = null) {
public function dn2username($fdn, $ldapName = null) {
//To avoid bypassing the base DN settings under certain circumstances
//with the group support, check whether the provided DN matches one of
//the given Bases
if(!$this->isDNPartOfBase($dn, $this->connection->ldapBaseUsers)) {
if(!$this->isDNPartOfBase($fdn, $this->connection->ldapBaseUsers)) {
return false;
}
return $this->dn2ocname($dn, $ldapName, true);
return $this->dn2ocname($fdn, $ldapName, true);
}
/**
......@@ -339,50 +330,39 @@ class Access extends LDAPUtility implements user\IUserTools {
* @param bool $isUser optional, whether it is a user object (otherwise group assumed)
* @return string with with the name to use in ownCloud
*/
public function dn2ocname($dn, $ldapName = null, $isUser = true) {
$table = $this->getMapTable($isUser);
public function dn2ocname($fdn, $ldapName = null, $isUser = true) {
if($isUser) {
$fncFindMappedName = 'findMappedUser';
$mapper = $this->userMapper;
$nameAttribute = $this->connection->ldapUserDisplayName;
} else {
$fncFindMappedName = 'findMappedGroup';
$mapper = $this->groupMapper;
$nameAttribute = $this->connection->ldapGroupDisplayName;
}
//let's try to retrieve the ownCloud name from the mappings table
$ocName = $this->$fncFindMappedName($dn);
if($ocName) {
$ocName = $mapper->getNameByDN($fdn);
if(is_string($ocName)) {
return $ocName;
}
//second try: get the UUID and check if it is known. Then, update the DN and return the name.
$uuid = $this->getUUID($dn, $isUser);
if($uuid) {
$query = \OCP\DB::prepare('
SELECT `owncloud_name`
FROM `'.$table.'`
WHERE `directory_uuid` = ?
');
$component = $query->execute(array($uuid))->fetchOne();
if($component) {
$query = \OCP\DB::prepare('
UPDATE `'.$table.'`
SET `ldap_dn` = ?
WHERE `directory_uuid` = ?
');
$query->execute(array($dn, $uuid));
return $component;
$uuid = $this->getUUID($fdn, $isUser);
if(is_string($uuid)) {
$ocName = $mapper->getNameByUUID($uuid);
if(is_string($ocName)) {
$mapper->setDNbyUUID($fdn, $uuid);
return $ocName;
}
} else {
//If the UUID can't be detected something is foul.
\OCP\Util::writeLog('user_ldap', 'Cannot determine UUID for '.$dn.'. Skipping.', \OCP\Util::INFO);
\OCP\Util::writeLog('user_ldap', 'Cannot determine UUID for '.$fdn.'. Skipping.', \OCP\Util::INFO);
return false;
}
if(is_null($ldapName)) {
$ldapName = $this->readAttribute($dn, $nameAttribute);
$ldapName = $this->readAttribute($fdn, $nameAttribute);
if(!isset($ldapName[0]) && empty($ldapName[0])) {
\OCP\Util::writeLog('user_ldap', 'No or empty name for '.$dn.'.', \OCP\Util::INFO);
\OCP\Util::writeLog('user_ldap', 'No or empty name for '.$fdn.'.', \OCP\Util::INFO);
return false;
}
$ldapName = $ldapName[0];
......@@ -390,8 +370,8 @@ class Access extends LDAPUtility implements user\IUserTools {
if($isUser) {
$usernameAttribute = $this->connection->ldapExpertUsernameAttr;
if(!emptY($usernameAttribute)) {
$username = $this->readAttribute($dn, $usernameAttribute);
if(!empty($usernameAttribute)) {
$username = $this->readAttribute($fdn, $usernameAttribute);
$username = $username[0];
} else {
$username = $uuid;
......@@ -409,7 +389,7 @@ class Access extends LDAPUtility implements user\IUserTools {
$this->connection->setConfiguration(array('ldapCacheTTL' => 0));
if(($isUser && !\OCP\User::userExists($intName))
|| (!$isUser && !\OC_Group::groupExists($intName))) {
if($this->mapComponent($dn, $intName, $isUser)) {
if($mapper->map($fdn, $intName, $uuid)) {
$this->connection->setConfiguration(array('ldapCacheTTL' => $originalTTL));
return $intName;
}
......@@ -417,12 +397,12 @@ class Access extends LDAPUtility implements user\IUserTools {
$this->connection->setConfiguration(array('ldapCacheTTL' => $originalTTL));
$altName = $this->createAltInternalOwnCloudName($intName, $isUser);
if($this->mapComponent($dn, $altName, $isUser)) {
if(is_string($altName) && $mapper->map($fdn, $altName, $uuid)) {
return $altName;
}
//if everything else did not help..
\OCP\Util::writeLog('user_ldap', 'Could not create unique name for '.$dn.'.', \OCP\Util::INFO);
\OCP\Util::writeLog('user_ldap', 'Could not create unique name for '.$fdn.'.', \OCP\Util::INFO);
return false;
}
......@@ -448,46 +428,6 @@ class Access extends LDAPUtility implements user\IUserTools {
return $this->ldap2ownCloudNames($ldapGroups, false);
}
/**
* @param string $dn
* @return bool|string
*/
private function findMappedUser($dn) {
static $query = null;
if(is_null($query)) {
$query = \OCP\DB::prepare('
SELECT `owncloud_name`
FROM `'.$this->getMapTable(true).'`
WHERE `ldap_dn` = ?'
);
}
$res = $query->execute(array($dn))->fetchOne();
if($res) {
return $res;
}
return false;
}
/**
* @param string $dn
* @return bool|string
*/
private function findMappedGroup($dn) {
static $query = null;
if(is_null($query)) {
$query = \OCP\DB::prepare('
SELECT `owncloud_name`
FROM `'.$this->getMapTable(false).'`
WHERE `ldap_dn` = ?'
);
}
$res = $query->execute(array($dn))->fetchOne();
if($res) {
return $res;
}
return false;
}
/**
* @param array $ldapObjects
* @param bool $isUsers
......@@ -571,17 +511,7 @@ class Access extends LDAPUtility implements user\IUserTools {
* "Developers"
*/
private function _createAltInternalOwnCloudNameForGroups($name) {
$query = \OCP\DB::prepare('
SELECT `owncloud_name`
FROM `'.$this->getMapTable(false).'`
WHERE `owncloud_name` LIKE ?
');
$usedNames = array();
$res = $query->execute(array($name.'_%'));
while($row = $res->fetchRow()) {
$usedNames[] = $row['owncloud_name'];
}
$usedNames = $this->groupMapper->getNamesBySearch($name.'_%');
if(!($usedNames) || count($usedNames) === 0) {
$lastNo = 1; //will become name_2
} else {
......@@ -625,92 +555,6 @@ class Access extends LDAPUtility implements user\IUserTools {
return $altName;
}
/**
* retrieves all known groups from the mappings table
* @return array with the results
*
* retrieves all known groups from the mappings table
*/
private function mappedGroups() {
return $this->mappedComponents(false);
}
/**
* retrieves all known users from the mappings table
* @return array with the results
*
* retrieves all known users from the mappings table
*/
private function mappedUsers() {
return $this->mappedComponents(true);
}
/**
* @param boolean $isUsers
* @return array
*/
private function mappedComponents($isUsers) {
$table = $this->getMapTable($isUsers);
$query = \OCP\DB::prepare('
SELECT `ldap_dn`, `owncloud_name`
FROM `'. $table . '`'
);
return $query->execute()->fetchAll();
}
/**
* inserts a new user or group into the mappings table
* @param string $dn the record in question
* @param string $ocName the name to use in ownCloud
* @param bool $isUser is it a user or a group?
* @return bool true on success, false otherwise
*
* inserts a new user or group into the mappings table
*/
private function mapComponent($dn, $ocName, $isUser = true) {
$table = $this->getMapTable($isUser);
$sqlAdjustment = '';
$dbType = \OC::$server->getConfig()->getSystemValue('dbtype', null);
if($dbType === 'mysql' || $dbType == 'oci') {
$sqlAdjustment = 'FROM DUAL';
}
$insert = \OCP\DB::prepare('
INSERT INTO `'.$table.'` (`ldap_dn`, `owncloud_name`, `directory_uuid`)
SELECT ?,?,?
'.$sqlAdjustment.'
WHERE NOT EXISTS (
SELECT 1
FROM `'.$table.'`
WHERE `ldap_dn` = ?
OR `owncloud_name` = ?)
');
//feed the DB
$insRows = $insert->execute(array($dn, $ocName,
$this->getUUID($dn, $isUser), $dn,
$ocName));
if(\OCP\DB::isError($insRows)) {
return false;
}
if($insRows === 0) {
return false;
}
if($isUser) {
//make sure that email address is retrieved prior to login, so user
//will be notified when something is shared with him
$this->userManager->get($ocName)->update();
}
return true;
}
/**
* @param string $filter
* @param string|string[] $attr
......@@ -1305,7 +1149,7 @@ class Access extends LDAPUtility implements user\IUserTools {
/**
* @param string $dn
* @param bool $isUser
* @return array|bool|false
* @return string|bool
*/
public function getUUID($dn, $isUser = true) {
if($isUser) {
......
......@@ -29,6 +29,7 @@ namespace OCA\user_ldap\lib;
* @property string ldapUserFilter
* @property string ldapUserDisplayName
* @property boolean hasPagedResultSupport
* @property string[] ldapBaseUsers
*/
class Connection extends LDAPUtility {
private $ldapConnectionRes = null;
......
......@@ -141,33 +141,6 @@ class Helper {
return true;
}
/**
* Truncate's the given mapping table
*
* @param string $mapping either 'user' or 'group'
* @return bool true on success, false otherwise
*/
static public function clearMapping($mapping) {
if($mapping === 'user') {
$table = '`*PREFIX*ldap_user_mapping`';
} else if ($mapping === 'group') {
$table = '`*PREFIX*ldap_group_mapping`';
} else {
return false;
}
$connection = \OC_DB::getConnection();
$sql = $connection->getDatabasePlatform()->getTruncateTableSQL($table);
$query = \OCP\DB::prepare($sql);
$res = $query->execute();
if(\OCP\DB::isError($res)) {
return false;
}
return true;
}
/**
* extracts the domain from a given URL
* @param string $url the URL
......
<?php
/**
* Copyright (c) 2014 Arthur Schiwon <blizzz@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\User_LDAP\Mapping;
/**
* Class AbstractMapping
* @package OCA\User_LDAP\Mapping
*/
abstract class AbstractMapping {
/**
* @var \OCP\IDBConnection $dbc
*/
protected $dbc;
/**
* returns the DB table name which holds the mappings
* @return string
*/
abstract protected function getTableName();
/**
* @param \OCP\IDBConnection $dbc
*/
public function __construct(\OCP\IDBConnection $dbc) {
$this->dbc = $dbc;
}
/**
* checks whether a provided string represents an exisiting table col
* @param string $col
* @return bool
*/
public function isColNameValid($col) {
switch($col) {
case 'ldap_dn':
case 'owncloud_name':
case 'directory_uuid':
return true;
default:
return false;
}
}
/**
* Gets the value of one column based on a provided value of another column
* @param string $fetchCol
* @param string $compareCol
* @param string $search
* @throws \Exception
* @return string|false
*/
protected function getXbyY($fetchCol, $compareCol, $search) {
if(!$this->isColNameValid($fetchCol)) {
//this is used internally only, but we don't want to risk
//having SQL injection at all.
throw new \Exception('Invalid Column Name');
}
$query = $this->dbc->prepare('
SELECT `' . $fetchCol . '`
FROM `'. $this->getTableName() .'`
WHERE `' . $compareCol . '` = ?
');
$res = $query->execute(array($search));
if($res !== false) {
return $query->fetchColumn();
}
return false;
}
/**
* Performs a DELETE or UPDATE query to the database.
* @param \Doctrine\DBAL\Driver\Statement $query
* @param array $parameters
* @return bool true if at least one row was modified, false otherwise
*/
protected function modify($query, $parameters) {
$result = $query->execute($parameters);
return ($result === true && $query->rowCount() > 0);
}
/**
* Gets the LDAP DN based on the provided name.
* Replaces Access::ocname2dn
* @param string $name
* @return string|false
*/
public function getDNByName($name) {
return $this->getXbyY('ldap_dn', 'owncloud_name', $name);
}
/**
* Updates the DN based on the given UUID
* @param string $fdn
* @param string $uuid
* @return bool
*/
public function setDNbyUUID($fdn, $uuid) {