diff --git a/apps/user_ldap/ajax/clearMappings.php b/apps/user_ldap/ajax/clearMappings.php
index 4e713c59f964830c326bcaf7bc3cf91f67b28e44..e6f3d32e84f3ce3f4d21540ce54c751076b012e0 100644
--- a/apps/user_ldap/ajax/clearMappings.php
+++ b/apps/user_ldap/ajax/clearMappings.php
@@ -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()));
 }
diff --git a/apps/user_ldap/appinfo/app.php b/apps/user_ldap/appinfo/app.php
index 8f9fbc5129b05b5419bcb9bdc4e9398180c0eda1..98d5fb601834136ec340d2aa59bc5e0ffa2255ec 100644
--- a/apps/user_ldap/appinfo/app.php
+++ b/apps/user_ldap/appinfo/app.php
@@ -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) {
diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php
index 22510302061bc50f777b9fb62560a835cef91bbd..5d0910320bf701d055e54d0c5b4ac215faccff6b 100644
--- a/apps/user_ldap/lib/access.php
+++ b/apps/user_ldap/lib/access.php
@@ -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) {
diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php
index 336ea7b3bbc424f7b1a1e6cd9e557fa689e2ee85..54aafb9341043d6582ec0de219ee41a657936c03 100644
--- a/apps/user_ldap/lib/connection.php
+++ b/apps/user_ldap/lib/connection.php
@@ -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;
diff --git a/apps/user_ldap/lib/helper.php b/apps/user_ldap/lib/helper.php
index 282f4549e3b68137b0e0751e47cf7e6f8fa96a17..fa36e3041714498359bd5fd97d52fb79afd008d6 100644
--- a/apps/user_ldap/lib/helper.php
+++ b/apps/user_ldap/lib/helper.php
@@ -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
diff --git a/apps/user_ldap/lib/mapping/abstractmapping.php b/apps/user_ldap/lib/mapping/abstractmapping.php
new file mode 100644
index 0000000000000000000000000000000000000000..2c45c6bb1c153c47f2e61aecc903d7229f13d78b
--- /dev/null
+++ b/apps/user_ldap/lib/mapping/abstractmapping.php
@@ -0,0 +1,201 @@
+<?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) {
+		$query = $this->dbc->prepare('
+			UPDATE `' . $this->getTableName() . '`
+			SET `ldap_dn` = ?
+			WHERE `directory_uuid` = ?
+		');
+
+		return $this->modify($query, array($fdn, $uuid));
+	}
+
+	/**
+	 * Gets the name based on the provided LDAP DN.
+	 * @param string $fdn
+	 * @return string|false
+	 */
+	public function getNameByDN($fdn) {
+		return $this->getXbyY('owncloud_name', 'ldap_dn', $fdn);
+	}
+
+	/**
+	 * Searches mapped names by the giving string in the name column
+	 * @param string $search
+	 * @return string[]
+	 */
+	public function getNamesBySearch($search) {
+		$query = $this->dbc->prepare('
+			SELECT `owncloud_name`
+			FROM `'. $this->getTableName() .'`
+			WHERE `owncloud_name` LIKE ?
+		');
+
+		$res = $query->execute(array($search));
+		$names = array();
+		if($res !== false) {
+			while($row = $query->fetch()) {
+				$names[] = $row['owncloud_name'];
+			}
+		}
+		return $names;
+	}
+
+	/**
+	 * Gets the name based on the provided LDAP DN.
+	 * @param string $uuid
+	 * @return string|false
+	 */
+	public function getNameByUUID($uuid) {
+		return $this->getXbyY('owncloud_name', 'directory_uuid', $uuid);
+	}
+
+	/**
+	 * attempts to map the given entry
+	 * @param string $fdn fully distinguished name (from LDAP)
+	 * @param string $name
+	 * @param string $uuid a unique identifier as used in LDAP
+	 * @return bool
+	 */
+	public function map($fdn, $name, $uuid) {
+		$row = array(
+			'ldap_dn'        => $fdn,
+			'owncloud_name'  => $name,
+			'directory_uuid' => $uuid
+		);
+
+		try {
+			$result = $this->dbc->insertIfNotExist($this->getTableName(), $row);
+			// insertIfNotExist returns values as int
+			return (bool)$result;
+		} catch (\Exception $e) {
+			return false;
+		}
+	}
+
+	/**
+	 * removes a mapping based on the owncloud_name of the entry
+	 * @param string $name
+	 * @return bool
+	 */
+	public function unmap($name) {
+		$query = $this->dbc->prepare('
+			DELETE FROM `'. $this->getTableName() .'`
+			WHERE `owncloud_name` = ?');
+
+		return $this->modify($query, array($name));
+	}
+
+	/**
+	 * Truncate's the mapping table
+	 * @return bool
+	 */
+	public function clear() {
+		$sql = $this->dbc
+			->getDatabasePlatform()
+			->getTruncateTableSQL('`' . $this->getTableName() . '`');
+		return $this->dbc->prepare($sql)->execute();
+	}
+}
diff --git a/apps/user_ldap/lib/mapping/groupmapping.php b/apps/user_ldap/lib/mapping/groupmapping.php
new file mode 100644
index 0000000000000000000000000000000000000000..af8a4bb4623a1ee4ebe24a78e2e2fe3141c7b99a
--- /dev/null
+++ b/apps/user_ldap/lib/mapping/groupmapping.php
@@ -0,0 +1,25 @@
+<?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 UserMapping
+* @package OCA\User_LDAP\Mapping
+*/
+class GroupMapping extends AbstractMapping {
+
+	/**
+	* returns the DB table name which holds the mappings
+	* @return string
+	*/
+	protected function getTableName() {
+		return '*PREFIX*ldap_group_mapping';
+	}
+
+}
diff --git a/apps/user_ldap/lib/mapping/usermapping.php b/apps/user_ldap/lib/mapping/usermapping.php
new file mode 100644
index 0000000000000000000000000000000000000000..dd24f338b9686f8a40bb9b9221f0f4576afb5889
--- /dev/null
+++ b/apps/user_ldap/lib/mapping/usermapping.php
@@ -0,0 +1,25 @@
+<?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 UserMapping
+* @package OCA\User_LDAP\Mapping
+*/
+class UserMapping extends AbstractMapping {
+
+	/**
+	 * returns the DB table name which holds the mappings
+	 * @return string
+	 */
+	protected function getTableName() {
+		return '*PREFIX*ldap_user_mapping';
+	}
+
+}
diff --git a/apps/user_ldap/lib/proxy.php b/apps/user_ldap/lib/proxy.php
index 73a52a7ddd9040eb75f593e9828292ed8d65684f..39d4b36c8bb536d5a7280a4db64a1ccc40fb5dd7 100644
--- a/apps/user_ldap/lib/proxy.php
+++ b/apps/user_ldap/lib/proxy.php
@@ -24,6 +24,8 @@
 namespace OCA\user_ldap\lib;
 
 use OCA\user_ldap\lib\Access;
+use OCA\User_LDAP\Mapping\UserMapping;
+use OCA\User_LDAP\Mapping\GroupMapping;
 
 abstract class Proxy {
 	static private $accesses = array();
@@ -45,17 +47,23 @@ abstract class Proxy {
 		static $fs;
 		static $log;
 		static $avatarM;
+		static $userMap;
+		static $groupMap;
 		if(is_null($fs)) {
 			$ocConfig = \OC::$server->getConfig();
 			$fs       = new FilesystemHelper();
 			$log      = new LogWrapper();
 			$avatarM  = \OC::$server->getAvatarManager();
+			$userMap  = new UserMapping(\OC::$server->getDatabaseConnection());
+			$groupMap = new GroupMapping(\OC::$server->getDatabaseConnection());
 		}
 		$userManager =
 			new user\Manager($ocConfig, $fs, $log, $avatarM, new \OCP\Image());
 		$connector = new Connection($this->ldap, $configPrefix);
-		self::$accesses[$configPrefix] =
-			new Access($connector, $this->ldap, $userManager);
+		$access = new Access($connector, $this->ldap, $userManager);
+		$access->setUserMapper($userMap);
+		$access->setGroupMapper($groupMap);
+		self::$accesses[$configPrefix] = $access;
 	}
 
 	/**
diff --git a/apps/user_ldap/tests/helper.php b/apps/user_ldap/tests/helper.php
deleted file mode 100644
index a70a57051c8248349b0c543f6dd65311a1c053fb..0000000000000000000000000000000000000000
--- a/apps/user_ldap/tests/helper.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-/**
-* ownCloud
-*
-* @author Thomas Müller
-* @copyright 2014 Thomas Müller deepdiver@owncloud.com
-*
-*/
-
-namespace OCA\user_ldap\tests;
-
-use OCA\user_ldap\lib\Helper;
-
-class Test_Helper extends \Test\TestCase {
-
-	public function testTableTruncate() {
-
-		$statement = \OCP\DB::prepare('INSERT INTO `*PREFIX*ldap_user_mapping` (`ldap_dn`, `owncloud_name`, `directory_uuid`) VALUES (?, ?, ?)');
-		$statement->execute(array('db01', 'oc1', '000-0000-0000'));
-		$statement->execute(array('db02', 'oc2', '000-0000-0001'));
-
-		$statement = \OCP\DB::prepare('SELECT count(*) FROM `*PREFIX*ldap_user_mapping`');
-		$result = $statement->execute();
-		$this->assertEquals(2, $result->fetchOne());
-
-		Helper::clearMapping('user');
-
-		$result = $statement->execute();
-		$this->assertEquals(0, $result->fetchOne());
-	}
-}
diff --git a/apps/user_ldap/tests/mapping/abstractmappingtest.php b/apps/user_ldap/tests/mapping/abstractmappingtest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a5cb62253aff53132ec180100cb279511f09ef19
--- /dev/null
+++ b/apps/user_ldap/tests/mapping/abstractmappingtest.php
@@ -0,0 +1,194 @@
+<?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\tests\mapping;
+
+abstract class AbstractMappingTest extends \Test\TestCase {
+	abstract public function getMapper(\OCP\IDBConnection $dbMock);
+
+	/**
+	 * kiss test on isColNameValid
+	 */
+	public function testIsColNameValid() {
+		$dbMock = $this->getMock('\OCP\IDBConnection');
+		$mapper = $this->getMapper($dbMock);
+
+		$this->assertTrue($mapper->isColNameValid('ldap_dn'));
+		$this->assertFalse($mapper->isColNameValid('foobar'));
+	}
+
+	/**
+	 * returns an array of test entries with dn, name and uuid as keys
+	 * @return array
+	 */
+	protected function getTestData() {
+		$data = array(
+			array(
+				'dn' => 'uid=foobar,dc=example,dc=org',
+				'name' => 'Foobar',
+				'uuid' => '1111-AAAA-1234-CDEF',
+			),
+			array(
+				'dn' => 'uid=barfoo,dc=example,dc=org',
+				'name' => 'Barfoo',
+				'uuid' => '2222-BBBB-1234-CDEF',
+			),
+			array(
+				'dn' => 'uid=barabara,dc=example,dc=org',
+				'name' => 'BaraBara',
+				'uuid' => '3333-CCCC-1234-CDEF',
+			)
+		);
+
+		return $data;
+	}
+
+	/**
+	 * calls map() on the given mapper and asserts result for true
+	 * @param \OCA\User_LDAP\Mapping\AbstractMapping $mapper
+	 * @param array $data
+	 */
+	protected function mapEntries($mapper, $data) {
+		foreach($data as $entry) {
+			$done = $mapper->map($entry['dn'], $entry['name'], $entry['uuid']);
+			$this->assertTrue($done);
+		}
+	}
+
+	/**
+	 * initalizes environment for a test run and returns an array with
+	 * test objects. Preparing environment means that all mappings are cleared
+	 * first and then filled with test entries.
+	 * @return array 0 = \OCA\User_LDAP\Mapping\AbstractMapping, 1 = array of
+	 * users or groups
+	 */
+	private function initTest() {
+		$dbc = \OC::$server->getDatabaseConnection();
+		$mapper = $this->getMapper($dbc);
+		$data = $this->getTestData();
+		// make sure DB is pristine, then fill it with test entries
+		$mapper->clear();
+		$this->mapEntries($mapper, $data);
+
+		return array($mapper, $data);
+	}
+
+	/**
+	 * tests map() method with input that should result in not-mapping.
+	 * Hint: successful mapping is tested inherently with mapEntries().
+	 */
+	public function testMap() {
+		list($mapper, $data) = $this->initTest();
+
+		// test that mapping will not happen when it shall not
+		$paramKeys = array('', 'dn', 'name', 'uuid');
+		foreach($paramKeys as $key) {
+			$failEntry = $data[0];
+			if(!empty($key)) {
+				$failEntry[$key] = 'do-not-get-mapped';
+			}
+			$isMapped = $mapper->map($failEntry['dn'], $failEntry['name'], $failEntry['uuid']);
+			$this->assertFalse($isMapped);
+		}
+	}
+
+	/**
+	 * tests unmap() for both successfuly and not successful removing of
+	 * mapping entries
+	 */
+	public function testUnmap() {
+		list($mapper, $data) = $this->initTest();
+
+		foreach($data as $entry) {
+			$result = $mapper->unmap($entry['name']);
+			$this->assertTrue($result);
+		}
+
+		$result = $mapper->unmap('notAnEntry');
+		$this->assertFalse($result);
+	}
+
+	/**
+	 * tests getDNByName(), getNameByDN() and getNameByUUID() for successful
+	 * and unsuccessful requests.
+	 */
+	public function testGetMethods() {
+		list($mapper, $data) = $this->initTest();
+
+		foreach($data as $entry) {
+			$fdn = $mapper->getDNByName($entry['name']);
+			$this->assertSame($fdn, $entry['dn']);
+		}
+		$fdn = $mapper->getDNByName('nosuchname');
+		$this->assertFalse($fdn);
+
+		foreach($data as $entry) {
+			$name = $mapper->getNameByDN($entry['dn']);
+			$this->assertSame($name, $entry['name']);
+		}
+		$name = $mapper->getNameByDN('nosuchdn');
+		$this->assertFalse($name);
+
+		foreach($data as $entry) {
+			$name = $mapper->getNameByUUID($entry['uuid']);
+			$this->assertSame($name, $entry['name']);
+		}
+		$name = $mapper->getNameByUUID('nosuchuuid');
+		$this->assertFalse($name);
+	}
+
+	/**
+	 * tests getNamesBySearch() for successful and unsuccessful requests.
+	 */
+	public function testSearch() {
+		list($mapper,) = $this->initTest();
+
+		$names = $mapper->getNamesBySearch('%oo%');
+		$this->assertTrue(is_array($names));
+		$this->assertSame(2, count($names));
+		$this->assertTrue(in_array('Foobar', $names));
+		$this->assertTrue(in_array('Barfoo', $names));
+		$names = $mapper->getNamesBySearch('nada');
+		$this->assertTrue(is_array($names));
+		$this->assertSame(0, count($names));
+	}
+
+	/**
+	 * tests setDNbyUUID() for successful and unsuccessful update.
+	 */
+	public function testSetMethod() {
+		list($mapper, $data) = $this->initTest();
+
+		$newDN = 'uid=modified,dc=example,dc=org';
+		$done = $mapper->setDNbyUUID($newDN, $data[0]['uuid']);
+		$this->assertTrue($done);
+		$fdn = $mapper->getDNByName($data[0]['name']);
+		$this->assertSame($fdn, $newDN);
+
+		$newDN = 'uid=notme,dc=example,dc=org';
+		$done = $mapper->setDNbyUUID($newDN, 'iamnothere');
+		$this->assertFalse($done);
+		$name = $mapper->getNameByDN($newDN);
+		$this->assertFalse($name);
+
+	}
+
+	/**
+	 * tests clear() for successful update.
+	 */
+	public function testClear() {
+		list($mapper, $data) = $this->initTest();
+
+		$done = $mapper->clear();
+		$this->assertTrue($done);
+		foreach($data as $entry) {
+			$name = $mapper->getNameByUUID($entry['uuid']);
+			$this->assertFalse($name);
+		}
+	}
+}
diff --git a/apps/user_ldap/tests/mapping/groupmapping.php b/apps/user_ldap/tests/mapping/groupmapping.php
new file mode 100644
index 0000000000000000000000000000000000000000..11bb3f40e3a4b474da5de35f37473050ad5797f0
--- /dev/null
+++ b/apps/user_ldap/tests/mapping/groupmapping.php
@@ -0,0 +1,17 @@
+<?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\tests\mapping;
+
+use OCA\User_LDAP\Mapping\GroupMapping;
+
+class Test_GroupMapping extends AbstractMappingTest {
+	public function getMapper(\OCP\IDBConnection $dbMock) {
+		return new GroupMapping($dbMock);
+	}
+}
diff --git a/apps/user_ldap/tests/mapping/usermapping.php b/apps/user_ldap/tests/mapping/usermapping.php
new file mode 100644
index 0000000000000000000000000000000000000000..2debcecf3977a5c8902b7a5331a46b7d34a4578d
--- /dev/null
+++ b/apps/user_ldap/tests/mapping/usermapping.php
@@ -0,0 +1,17 @@
+<?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\tests\mapping;
+
+use OCA\User_LDAP\Mapping\UserMapping;
+
+class Test_UserMapping extends AbstractMappingTest {
+	public function getMapper(\OCP\IDBConnection $dbMock) {
+		return new UserMapping($dbMock);
+	}
+}
diff --git a/lib/private/db/connection.php b/lib/private/db/connection.php
index 9de7a719ff59250d1c77e4137a4bce482e1aa639..d10adee558c747c2c830eabab054efeac8c99dd7 100644
--- a/lib/private/db/connection.php
+++ b/lib/private/db/connection.php
@@ -142,6 +142,7 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
 	 * Insert a row if a matching row doesn't exists.
 	 * @param string $table. The table to insert into in the form '*PREFIX*tableName'
 	 * @param array $input. An array of fieldname/value pairs
+	 * @throws \OC\HintException
 	 * @return bool The return value from execute()
 	 */
 	public function insertIfNotExist($table, $input) {
diff --git a/lib/public/idbconnection.php b/lib/public/idbconnection.php
index 32310fe755f0e980fa7fca7dc1a7981e39ba58d2..0d19b2cc71e2f51507afe91d62bf1bd7a917e9e3 100644
--- a/lib/public/idbconnection.php
+++ b/lib/public/idbconnection.php
@@ -80,6 +80,7 @@ interface IDBConnection {
 	 * Insert a row if a matching row doesn't exists.
 	 * @param string $table The table name (will replace *PREFIX*) to perform the replace on.
 	 * @param array $input
+	 * @throws \OC\HintException
 	 *
 	 * The input array if in the form:
 	 *