From 10ca793452e75ecd276589f8ad916f3090ecb441 Mon Sep 17 00:00:00 2001
From: Vinicius Cubas Brand <viniciuscb@gmail.com>
Date: Thu, 2 Nov 2017 10:40:38 -0200
Subject: [PATCH] Plugins infrastructure in User_LDAP

Signed-off-by: Vinicius Cubas Brand <viniciuscb@gmail.com>
---
 apps/user_ldap/appinfo/app.php                |  20 +-
 apps/user_ldap/appinfo/register_command.php   |   3 +-
 apps/user_ldap/lib/Command/Search.php         |   5 +-
 apps/user_ldap/lib/GroupPluginManager.php     | 169 ++++++++
 apps/user_ldap/lib/Group_LDAP.php             | 116 ++++-
 apps/user_ldap/lib/Group_Proxy.php            |  76 +++-
 apps/user_ldap/lib/Helper.php                 |   4 +-
 apps/user_ldap/lib/IGroupLDAP.php             |  45 ++
 apps/user_ldap/lib/ILDAPGroupPlugin.php       |  88 ++++
 apps/user_ldap/lib/ILDAPUserPlugin.php        |  93 ++++
 apps/user_ldap/lib/ILDAPWrapper.php           |   2 +-
 apps/user_ldap/lib/Jobs/CleanUp.php           |   3 +-
 apps/user_ldap/lib/Jobs/UpdateGroups.php      |   4 +-
 apps/user_ldap/lib/LDAPProvider.php           | 139 +++++-
 apps/user_ldap/lib/Migration/UUIDFixGroup.php |   3 +-
 apps/user_ldap/lib/Migration/UUIDFixUser.php  |   3 +-
 apps/user_ldap/lib/UserPluginManager.php      | 208 +++++++++
 apps/user_ldap/lib/User_LDAP.php              |  62 ++-
 apps/user_ldap/lib/User_Proxy.php             |  31 +-
 apps/user_ldap/tests/GroupLDAPPluginTest.php  | 247 +++++++++++
 apps/user_ldap/tests/Group_LDAPTest.php       | 340 ++++++++++++++-
 .../Lib/IntegrationTestAttributeDetection.php |   4 +-
 .../IntegrationTestFetchUsersByLoginName.php  |   2 +-
 .../Integration/Lib/IntegrationTestPaging.php |   2 +-
 .../Lib/IntegrationTestUserHome.php           |   2 +-
 .../Lib/User/IntegrationTestUserAvatar.php    |   2 +-
 .../User/IntegrationTestUserDisplayName.php   |   2 +-
 apps/user_ldap/tests/LDAPGroupPluginDummy.php |  59 +++
 apps/user_ldap/tests/LDAPProviderTest.php     | 374 +++++++++++++---
 apps/user_ldap/tests/LDAPUserPluginDummy.php  |  63 +++
 apps/user_ldap/tests/UserLDAPPluginTest.php   | 310 ++++++++++++++
 apps/user_ldap/tests/User_LDAPTest.php        | 399 ++++++++++++++++--
 apps/user_ldap/tests/User_ProxyTest.php       |  28 ++
 lib/private/Group/Manager.php                 |  13 +-
 lib/public/IGroupManager.php                  |   7 +
 lib/public/LDAP/ILDAPProvider.php             |  50 ++-
 36 files changed, 2803 insertions(+), 175 deletions(-)
 create mode 100644 apps/user_ldap/lib/GroupPluginManager.php
 create mode 100644 apps/user_ldap/lib/IGroupLDAP.php
 create mode 100644 apps/user_ldap/lib/ILDAPGroupPlugin.php
 create mode 100644 apps/user_ldap/lib/ILDAPUserPlugin.php
 create mode 100644 apps/user_ldap/lib/UserPluginManager.php
 create mode 100644 apps/user_ldap/tests/GroupLDAPPluginTest.php
 create mode 100644 apps/user_ldap/tests/LDAPGroupPluginDummy.php
 create mode 100644 apps/user_ldap/tests/LDAPUserPluginDummy.php
 create mode 100644 apps/user_ldap/tests/UserLDAPPluginTest.php

diff --git a/apps/user_ldap/appinfo/app.php b/apps/user_ldap/appinfo/app.php
index 5239e52234a..7ea578ab9ca 100644
--- a/apps/user_ldap/appinfo/app.php
+++ b/apps/user_ldap/appinfo/app.php
@@ -10,6 +10,8 @@
  * @author Morris Jobke <hey@morrisjobke.de>
  * @author Robin Appelman <robin@icewind.nl>
  * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ * @author Daniel Tygel <dtygel@eita.org.br>
  *
  * @license AGPL-3.0
  *
@@ -27,6 +29,13 @@
  *
  */
 
+\OC::$server->registerService('LDAPUserPluginManager', function() {
+	return new OCA\User_LDAP\UserPluginManager();
+});
+\OC::$server->registerService('LDAPGroupPluginManager', function() {
+	return new OCA\User_LDAP\GroupPluginManager();
+});
+
 $helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig());
 $configPrefixes = $helper->getServerConfigurationPrefixes(true);
 if(count($configPrefixes) > 0) {
@@ -46,12 +55,19 @@ if(count($configPrefixes) > 0) {
 	});
 	$userSession = \OC::$server->getUserSession();
 
+	$userPluginManager = \OC::$server->query('LDAPUserPluginManager');
+	$groupPluginManager = \OC::$server->query('LDAPGroupPluginManager');
+
 	$userBackend  = new OCA\User_LDAP\User_Proxy(
-		$configPrefixes, $ldapWrapper, $ocConfig, $notificationManager, $userSession
+		$configPrefixes, $ldapWrapper, $ocConfig, $notificationManager, $userSession, $userPluginManager
 	);
-	$groupBackend  = new OCA\User_LDAP\Group_Proxy($configPrefixes, $ldapWrapper);
+	$groupBackend  = new OCA\User_LDAP\Group_Proxy($configPrefixes, $ldapWrapper, $groupPluginManager);
 	// register user backend
 	OC_User::useBackend($userBackend);
+
+	// Hook to allow plugins to work on registered backends
+	OC::$server->getEventDispatcher()->dispatch('OCA\\User_LDAP\\User\\User::postLDAPBackendAdded');
+
 	\OC::$server->getGroupManager()->addBackend($groupBackend);
 }
 
diff --git a/apps/user_ldap/appinfo/register_command.php b/apps/user_ldap/appinfo/register_command.php
index bd706e61f22..495445b3fa4 100644
--- a/apps/user_ldap/appinfo/register_command.php
+++ b/apps/user_ldap/appinfo/register_command.php
@@ -37,7 +37,8 @@ $uBackend = new User_Proxy(
 	new LDAP(),
 	$ocConfig,
 	\OC::$server->getNotificationManager(),
-	\OC::$server->getUserSession()
+	\OC::$server->getUserSession(),
+	\OC::$server->query('LDAPUserPluginManager')
 );
 $deletedUsersIndex = new DeletedUsersIndex(
 	$ocConfig, $dbConnection, $userMapping
diff --git a/apps/user_ldap/lib/Command/Search.php b/apps/user_ldap/lib/Command/Search.php
index d348d5b31c9..4b2212a43c9 100644
--- a/apps/user_ldap/lib/Command/Search.php
+++ b/apps/user_ldap/lib/Command/Search.php
@@ -111,7 +111,7 @@ class Search extends Command {
 		$this->validateOffsetAndLimit($offset, $limit);
 
 		if($input->getOption('group')) {
-			$proxy = new Group_Proxy($configPrefixes, $ldapWrapper);
+			$proxy = new Group_Proxy($configPrefixes, $ldapWrapper, \OC::$server->query('LDAPGroupPluginManager'));
 			$getMethod = 'getGroups';
 			$printID = false;
 			// convert the limit of groups to null. This will show all the groups available instead of
@@ -125,7 +125,8 @@ class Search extends Command {
 				$ldapWrapper,
 				$this->ocConfig,
 				\OC::$server->getNotificationManager(),
-				\OC::$server->getUserSession()
+				\OC::$server->getUserSession(),
+				\OC::$server->query('LDAPUserPluginManager')
 			);
 			$getMethod = 'getDisplayNames';
 			$printID = true;
diff --git a/apps/user_ldap/lib/GroupPluginManager.php b/apps/user_ldap/lib/GroupPluginManager.php
new file mode 100644
index 00000000000..6250ae6be04
--- /dev/null
+++ b/apps/user_ldap/lib/GroupPluginManager.php
@@ -0,0 +1,169 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br)
+ *
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ * @author Daniel Tygel <dtygel@eita.org.br>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP;
+
+use OC\Group\Backend;
+
+class GroupPluginManager {
+
+	private $respondToActions = 0;
+
+	private $which = array(
+		Backend::CREATE_GROUP => null,
+		Backend::DELETE_GROUP => null,
+		Backend::ADD_TO_GROUP => null,
+		Backend::REMOVE_FROM_GROUP => null,
+		Backend::COUNT_USERS => null,
+		Backend::GROUP_DETAILS => null
+	);
+
+	/**
+	 * @return int All implemented actions
+	 */
+	public function getImplementedActions() {
+		return $this->respondToActions;
+	}
+
+	/**
+	 * Registers a group plugin that may implement some actions, overriding User_LDAP's group actions.
+	 * @param ILDAPGroupPlugin $plugin
+	 */
+	public function register(ILDAPGroupPlugin $plugin) {
+		$respondToActions = $plugin->respondToActions();
+		$this->respondToActions |= $respondToActions;
+
+		foreach($this->which as $action => $v) {
+			if ((bool)($respondToActions & $action)) {
+				$this->which[$action] = $plugin;
+				\OC::$server->getLogger()->debug("Registered action ".$action." to plugin ".get_class($plugin), ['app' => 'user_ldap']);
+			}
+		}
+	}
+
+	/**
+	 * Signal if there is a registered plugin that implements some given actions
+	 * @param int $action Actions defined in \OC\Group\Backend, like Backend::REMOVE_FROM_GROUP
+	 * @return bool
+	 */
+	public function implementsActions($actions) {
+		return ($actions & $this->respondToActions) == $actions;
+	}
+
+	/**
+	 * Create a group
+	 * @param string $gid Group Id
+	 * @return string | null The group DN if group creation was successful.
+	 * @throws \Exception
+	 */
+	public function createGroup($gid) {
+		$plugin = $this->which[Backend::CREATE_GROUP];
+
+		if ($plugin) {
+			return $plugin->createGroup($gid);
+		}
+		throw new \Exception('No plugin implements createGroup in this LDAP Backend.');
+	}
+
+	/**
+	 * Delete a group
+	 * @param string $gid Group Id of the group to delete
+	 * @return bool
+	 * @throws \Exception
+	 */
+	public function deleteGroup($gid) {
+		$plugin = $this->which[Backend::DELETE_GROUP];
+
+		if ($plugin) {
+			return $plugin->deleteGroup($gid);
+		}
+		throw new \Exception('No plugin implements deleteGroup in this LDAP Backend.');
+	}
+
+	/**
+	 * Add a user to a group
+	 * @param string $uid ID of the user to add to group
+	 * @param string $gid ID of the group in which add the user
+	 * @return bool
+	 * @throws \Exception
+	 *
+	 * Adds a user to a group.
+	 */
+	public function addToGroup($uid, $gid) {
+		$plugin = $this->which[Backend::ADD_TO_GROUP];
+
+		if ($plugin) {
+			return $plugin->addToGroup($uid, $gid);
+		}
+		throw new \Exception('No plugin implements addToGroup in this LDAP Backend.');
+	}
+
+	/**
+	 * Removes a user from a group
+	 * @param string $uid ID of the user to remove from group
+	 * @param string $gid ID of the group from which remove the user
+	 * @return bool
+	 * @throws \Exception
+	 *
+	 * removes the user from a group.
+	 */
+	public function removeFromGroup($uid, $gid) {
+		$plugin = $this->which[Backend::REMOVE_FROM_GROUP];
+
+		if ($plugin) {
+			return $plugin->removeFromGroup($uid, $gid);
+		}
+		throw new \Exception('No plugin implements removeFromGroup in this LDAP Backend.');
+	}
+
+	/**
+	 * get the number of all users matching the search string in a group
+	 * @param string $gid ID of the group
+	 * @param string $search query string
+	 * @return int|false
+	 * @throws \Exception
+	 */
+	public function countUsersInGroup($gid, $search = '') {
+		$plugin = $this->which[Backend::COUNT_USERS];
+
+		if ($plugin) {
+			return $plugin->countUsersInGroup($gid,$search);
+		}
+		throw new \Exception('No plugin implements countUsersInGroup in this LDAP Backend.');
+	}
+
+	/**
+	 * get an array with group details
+	 * @param string $gid
+	 * @return array|false
+	 * @throws \Exception
+	 */
+	public function getGroupDetails($gid) {
+		$plugin = $this->which[Backend::GROUP_DETAILS];
+
+		if ($plugin) {
+			return $plugin->getGroupDetails($gid);
+		}
+		throw new \Exception('No plugin implements getGroupDetails in this LDAP Backend.');
+	}
+}
diff --git a/apps/user_ldap/lib/Group_LDAP.php b/apps/user_ldap/lib/Group_LDAP.php
index 55d31649f10..39519cc462a 100644
--- a/apps/user_ldap/lib/Group_LDAP.php
+++ b/apps/user_ldap/lib/Group_LDAP.php
@@ -39,8 +39,9 @@
 namespace OCA\User_LDAP;
 
 use OC\Cache\CappedMemoryCache;
+use OC\Group\Backend;
 
-class Group_LDAP extends BackendUtility implements \OCP\GroupInterface {
+class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLDAP {
 	protected $enabled = false;
 
 	/**
@@ -53,7 +54,10 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface {
 	 */
 	protected $cachedGroupsByMember;
 
-	public function __construct(Access $access) {
+	/** @var GroupPluginManager */
+	protected $groupPluginManager;
+
+	public function __construct(Access $access, GroupPluginManager $groupPluginManager) {
 		parent::__construct($access);
 		$filter = $this->access->connection->ldapGroupFilter;
 		$gassoc = $this->access->connection->ldapGroupMemberAssocAttr;
@@ -63,6 +67,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface {
 
 		$this->cachedGroupMembers = new CappedMemoryCache();
 		$this->cachedGroupsByMember = new CappedMemoryCache();
+		$this->groupPluginManager = $groupPluginManager;
 	}
 
 	/**
@@ -860,6 +865,10 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface {
 	 * @return int|bool
 	 */
 	public function countUsersInGroup($gid, $search = '') {
+		if ($this->groupPluginManager->implementsActions(Backend::COUNT_USERS)) {
+			return $this->groupPluginManager->countUsersInGroup($gid, $search);
+		}
+
 		$cacheKey = 'countUsersInGroup-'.$gid.'-'.$search;
 		if(!$this->enabled || !$this->groupExists($gid)) {
 			return false;
@@ -1067,17 +1076,114 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface {
 	* @return boolean
 	*
 	* Returns the supported actions as int to be
-	* compared with \OC\User\Backend::CREATE_USER etc.
+	* compared with \OC\Group\Backend::CREATE_GROUP etc.
 	*/
 	public function implementsActions($actions) {
-		return (bool)(\OC\Group\Backend::COUNT_USERS & $actions);
+		return (bool)((\OC\Group\Backend::COUNT_USERS |
+				$this->groupPluginManager->getImplementedActions()) & $actions);
 	}
 
 	/**
 	 * Return access for LDAP interaction.
 	 * @return Access instance of Access for LDAP interaction
 	 */
-	public function getLDAPAccess() {
+	public function getLDAPAccess($gid) {
 		return $this->access;
 	}
+
+	/**
+	 * create a group
+	 * @param string $gid
+	 * @return bool
+	 * @throws \Exception
+	 */
+	public function createGroup($gid) {
+		if ($this->groupPluginManager->implementsActions(Backend::CREATE_GROUP)) {
+			if ($dn = $this->groupPluginManager->createGroup($gid)) {
+				//updates group mapping
+				$this->access->dn2ocname($dn, $gid, false);
+				$this->access->connection->writeToCache("groupExists".$gid, true);
+			}
+			return $dn != null;
+		}
+		throw new \Exception('Could not create group in LDAP backend.');
+	}
+
+	/**
+	 * delete a group
+	 * @param string $gid gid of the group to delete
+	 * @return bool
+	 * @throws \Exception
+	 */
+	public function deleteGroup($gid) {
+		if ($this->groupPluginManager->implementsActions(Backend::DELETE_GROUP)) {
+			if ($ret = $this->groupPluginManager->deleteGroup($gid)) {
+				#delete group in nextcloud internal db
+				$this->access->getGroupMapper()->unmap($gid);
+				$this->access->connection->writeToCache("groupExists".$gid, false);
+			}
+			return $ret;
+		}
+		throw new \Exception('Could not delete group in LDAP backend.');
+	}
+
+	/**
+	 * Add a user to a group
+	 * @param string $uid Name of the user to add to group
+	 * @param string $gid Name of the group in which add the user
+	 * @return bool
+	 * @throws \Exception
+	 */
+	public function addToGroup($uid, $gid) {
+		if ($this->groupPluginManager->implementsActions(Backend::ADD_TO_GROUP)) {
+			if ($ret = $this->groupPluginManager->addToGroup($uid, $gid)) {
+				#$this->access->connection->clearCache();
+			}
+			return $ret;
+		}
+		throw new \Exception('Could not add user to group in LDAP backend.');
+	}
+
+	/**
+	 * Removes a user from a group
+	 * @param string $uid Name of the user to remove from group
+	 * @param string $gid Name of the group from which remove the user
+	 * @return bool
+	 * @throws \Exception
+	 */
+	public function removeFromGroup($uid, $gid) {
+		if ($this->groupPluginManager->implementsActions(Backend::REMOVE_FROM_GROUP)) {
+			if ($ret = $this->groupPluginManager->removeFromGroup($uid, $gid)) {
+				#$this->access->connection->clearCache();
+			}
+			return $ret;
+		}
+		throw new \Exception('Could not remove user from group in LDAP backend.');
+	}
+
+	/**
+	 * Gets group details
+	 * @param string $gid Name of the group
+	 * @return array | false
+	 * @throws \Exception
+	 */
+	public function getGroupDetails($gid) {
+		if ($this->groupPluginManager->implementsActions(Backend::GROUP_DETAILS)) {
+			return $this->groupPluginManager->getGroupDetails($gid);
+		}
+		throw new \Exception('Could not get group details in LDAP backend.');
+	}
+
+	/**
+	 * Return LDAP connection resource from a cloned connection.
+	 * The cloned connection needs to be closed manually.
+	 * of the current access.
+	 * @param string $gid
+	 * @return resource of the LDAP connection
+	 */
+	public function getNewLDAPConnection($gid) {
+		$connection = clone $this->access->getConnection();
+		return $connection->getConnectionResource();
+	}
+
 }
diff --git a/apps/user_ldap/lib/Group_Proxy.php b/apps/user_ldap/lib/Group_Proxy.php
index e546c84a90c..9902035faf0 100644
--- a/apps/user_ldap/lib/Group_Proxy.php
+++ b/apps/user_ldap/lib/Group_Proxy.php
@@ -26,7 +26,7 @@
 
 namespace OCA\User_LDAP;
 
-class Group_Proxy extends Proxy implements \OCP\GroupInterface {
+class Group_Proxy extends Proxy implements \OCP\GroupInterface, IGroupLDAP {
 	private $backends = array();
 	private $refBackend = null;
 
@@ -34,11 +34,11 @@ class Group_Proxy extends Proxy implements \OCP\GroupInterface {
 	 * Constructor
 	 * @param string[] $serverConfigPrefixes array containing the config Prefixes
 	 */
-	public function __construct($serverConfigPrefixes, ILDAPWrapper $ldap) {
+	public function __construct($serverConfigPrefixes, ILDAPWrapper $ldap, GroupPluginManager $groupPluginManager) {
 		parent::__construct($ldap);
 		foreach($serverConfigPrefixes as $configPrefix) {
 			$this->backends[$configPrefix] =
-				new \OCA\User_LDAP\Group_LDAP($this->getAccess($configPrefix));
+				new \OCA\User_LDAP\Group_LDAP($this->getAccess($configPrefix), $groupPluginManager);
 			if(is_null($this->refBackend)) {
 				$this->refBackend = &$this->backends[$configPrefix];
 			}
@@ -145,6 +145,51 @@ class Group_Proxy extends Proxy implements \OCP\GroupInterface {
 		return $users;
 	}
 
+	/**
+	 * @param string $gid
+	 * @return bool
+	 */
+	public function createGroup($gid) {
+		return $this->handleRequest(
+			$gid, 'createGroup', array($gid));
+	}
+
+	/**
+	 * delete a group
+	 * @param string $gid gid of the group to delete
+	 * @return bool
+	 */
+	public function deleteGroup($gid) {
+		return $this->handleRequest(
+			$gid, 'deleteGroup', array($gid));
+	}
+
+	/**
+	 * Add a user to a group
+	 * @param string $uid Name of the user to add to group
+	 * @param string $gid Name of the group in which add the user
+	 * @return bool
+	 *
+	 * Adds a user to a group.
+	 */
+	public function addToGroup($uid, $gid) {
+		return $this->handleRequest(
+			$gid, 'addToGroup', array($uid, $gid));
+	}
+
+	/**
+	 * Removes a user from a group
+	 * @param string $uid Name of the user to remove from group
+	 * @param string $gid Name of the group from which remove the user
+	 * @return bool
+	 *
+	 * removes the user from a group.
+	 */
+	public function removeFromGroup($uid, $gid) {
+		return $this->handleRequest(
+			$gid, 'removeFromGroup', array($uid, $gid));
+	}
+
 	/**
 	 * returns the number of users in a group, who match the search term
 	 * @param string $gid the internal group name
@@ -156,6 +201,16 @@ class Group_Proxy extends Proxy implements \OCP\GroupInterface {
 			$gid, 'countUsersInGroup', array($gid, $search));
 	}
 
+	/**
+	 * get an array with group details
+	 * @param string $gid
+	 * @return array|false
+	 */
+	public function getGroupDetails($gid) {
+		return $this->handleRequest(
+			$gid, 'getGroupDetails', array($gid));
+	}
+
 	/**
 	 * get a list of all groups
 	 * @return string[] with group names
@@ -190,7 +245,7 @@ class Group_Proxy extends Proxy implements \OCP\GroupInterface {
 	 * @return boolean
 	 *
 	 * Returns the supported actions as int to be
-	 * compared with \OC\User\Backend::CREATE_USER etc.
+	 * compared with \OC\Group\Backend::CREATE_GROUP etc.
 	 */
 	public function implementsActions($actions) {
 		//it's the same across all our user backends obviously
@@ -203,6 +258,17 @@ class Group_Proxy extends Proxy implements \OCP\GroupInterface {
 	 * @return Access instance of Access for LDAP interaction
 	 */
 	public function getLDAPAccess($gid) {
-		return $this->handleRequest($gid, 'getLDAPAccess', []);
+		return $this->handleRequest($gid, 'getLDAPAccess', [$gid]);
 	}
+
+	/**
+	 * Return a new LDAP connection for the specified group.
+	 * The connection needs to be closed manually.
+	 * @param string $gid
+	 * @return resource of the LDAP connection
+	 */
+	public function getNewLDAPConnection($gid) {
+		return $this->handleRequest($gid, 'getNewLDAPConnection', array($gid));
+	}
+
 }
diff --git a/apps/user_ldap/lib/Helper.php b/apps/user_ldap/lib/Helper.php
index 891ab7f0a3a..ce65ee29099 100644
--- a/apps/user_ldap/lib/Helper.php
+++ b/apps/user_ldap/lib/Helper.php
@@ -294,10 +294,12 @@ class Helper {
 		$ldapWrapper = new LDAP();
 		$ocConfig = \OC::$server->getConfig();
 		$notificationManager = \OC::$server->getNotificationManager();
+
 		$userSession = \OC::$server->getUserSession();
+		$userPluginManager = \OC::$server->query('LDAPUserPluginManager');
 
 		$userBackend  = new User_Proxy(
-			$configPrefixes, $ldapWrapper, $ocConfig, $notificationManager, $userSession
+			$configPrefixes, $ldapWrapper, $ocConfig, $notificationManager, $userSession, $userPluginManager
 		);
 		$uid = $userBackend->loginName2UserName($param['uid'] );
 		if($uid !== false) {
diff --git a/apps/user_ldap/lib/IGroupLDAP.php b/apps/user_ldap/lib/IGroupLDAP.php
new file mode 100644
index 00000000000..378e182fb68
--- /dev/null
+++ b/apps/user_ldap/lib/IGroupLDAP.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ *
+ * @copyright Copyright (c) 2017, EITA Cooperative (eita.org.br)
+ *
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\User_LDAP;
+
+interface IGroupLDAP {
+
+	//Used by LDAPProvider
+
+	/**
+	 * Return access for LDAP interaction.
+	 * @param string $gid
+	 * @return Access instance of Access for LDAP interaction
+	 */
+	public function getLDAPAccess($gid);
+
+	/**
+	 * Return a new LDAP connection for the specified group.
+	 * @param string $gid
+	 * @return resource of the LDAP connection
+	 */
+	public function getNewLDAPConnection($gid);
+
+}
diff --git a/apps/user_ldap/lib/ILDAPGroupPlugin.php b/apps/user_ldap/lib/ILDAPGroupPlugin.php
new file mode 100644
index 00000000000..468424a560d
--- /dev/null
+++ b/apps/user_ldap/lib/ILDAPGroupPlugin.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br)
+ *
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ * @author Daniel Tygel <dtygel@eita.org.br>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP;
+
+
+interface ILDAPGroupPlugin {
+
+	/**
+	 * Check if plugin implements actions
+	 * @return int
+	 *
+	 * Returns the supported actions as int to be
+	 * compared with OC_GROUP_BACKEND_CREATE_GROUP etc.
+	 */
+	public function respondToActions();
+
+	/**
+	 * @param string $gid
+	 * @return string|null The group DN if group creation was successful.
+	 */
+    public function createGroup($gid);
+
+	/**
+	 * delete a group
+	 * @param string $gid gid of the group to delete
+	 * @return bool
+	 */
+    public function deleteGroup($gid);
+
+	/**
+	 * Add a user to a group
+	 * @param string $uid Name of the user to add to group
+	 * @param string $gid Name of the group in which add the user
+	 * @return bool
+	 *
+	 * Adds a user to a group.
+	 */
+    public function addToGroup($uid, $gid);
+
+	/**
+	 * Removes a user from a group
+	 * @param string $uid Name of the user to remove from group
+	 * @param string $gid Name of the group from which remove the user
+	 * @return bool
+	 *
+	 * removes the user from a group.
+	 */
+    public function removeFromGroup($uid, $gid);
+
+	/**
+	 * get the number of all users matching the search string in a group
+	 * @param string $gid
+	 * @param string $search
+	 * @return int|false
+	 */
+    public function countUsersInGroup($gid, $search = '');
+
+	/**
+	 * get an array with group details
+	 * @param string $gid
+	 * @return array|false
+	 */
+    public function getGroupDetails($gid);
+
+
+
+}
diff --git a/apps/user_ldap/lib/ILDAPUserPlugin.php b/apps/user_ldap/lib/ILDAPUserPlugin.php
new file mode 100644
index 00000000000..d2e8544c8a5
--- /dev/null
+++ b/apps/user_ldap/lib/ILDAPUserPlugin.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br)
+ *
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ * @author Daniel Tygel <dtygel@eita.org.br>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP;
+
+
+interface ILDAPUserPlugin {
+
+	/**
+	 * Check if plugin implements actions
+	 * @return int
+	 *
+	 * Returns the supported actions as int to be
+	 * compared with OC_USER_BACKEND_CREATE_USER etc.
+	 */
+	public function respondToActions();
+
+	/**
+	 * Create a new user in LDAP Backend
+	 *
+	 * @param string $uid The UID of the user to create
+	 * @param string $password The password of the new user
+	 * @return bool
+	 */
+	public function createUser($uid, $password);
+
+	/**
+	 * Set password
+	 *
+	 * @param string $uid The username
+	 * @param string $password The new password
+	 * @return bool
+	 *
+	 * Change the password of a user
+	 */
+	public function setPassword($uid, $password);
+
+	/**
+	 * get the user's home directory
+	 * @param string $uid the username
+	 * @return boolean
+	 */
+	public function getHome($uid);
+
+	/**
+	 * get display name of the user
+	 * @param string $uid user ID of the user
+	 * @return string display name
+	 */
+	public function getDisplayName($uid);
+
+	/**
+	 * set display name of the user
+	 * @param string $uid user ID of the user
+	 * @param string $displayName new user's display name
+	 * @return string display name
+	 */
+	public function setDisplayName($uid, $displayName);
+
+	/**
+	 * checks whether the user is allowed to change his avatar in Nextcloud
+	 * @param string $uid the Nextcloud user name
+	 * @return boolean either the user can or cannot
+	 */
+	public function canChangeAvatar($uid);
+
+	/**
+	 * Count the number of users
+	 * @return int|bool
+	 */
+	public function countUsers();
+
+}
diff --git a/apps/user_ldap/lib/ILDAPWrapper.php b/apps/user_ldap/lib/ILDAPWrapper.php
index 71dd60c3725..e5969cc2986 100644
--- a/apps/user_ldap/lib/ILDAPWrapper.php
+++ b/apps/user_ldap/lib/ILDAPWrapper.php
@@ -163,7 +163,7 @@ interface ILDAPWrapper {
 	 * @return resource|false an LDAP search result resource, false on error
 	 */
 	public function search($link, $baseDN, $filter, $attr, $attrsOnly = 0, $limit = 0);
-	
+
 	/**
 	 * Replace the value of a userPassword by $password
 	 * @param resource $link LDAP link resource
diff --git a/apps/user_ldap/lib/Jobs/CleanUp.php b/apps/user_ldap/lib/Jobs/CleanUp.php
index 44e8f5469f1..92bca036b2e 100644
--- a/apps/user_ldap/lib/Jobs/CleanUp.php
+++ b/apps/user_ldap/lib/Jobs/CleanUp.php
@@ -100,7 +100,8 @@ class CleanUp extends TimedJob {
 				new LDAP(),
 				$this->ocConfig,
 				\OC::$server->getNotificationManager(),
-				\OC::$server->getUserSession()
+				\OC::$server->getUserSession(),
+				\OC::$server->query('LDAPUserPluginManager')
 			);
 		}
 
diff --git a/apps/user_ldap/lib/Jobs/UpdateGroups.php b/apps/user_ldap/lib/Jobs/UpdateGroups.php
index 4c9a06a5f68..7e4f0c0c1be 100644
--- a/apps/user_ldap/lib/Jobs/UpdateGroups.php
+++ b/apps/user_ldap/lib/Jobs/UpdateGroups.php
@@ -193,9 +193,9 @@ class UpdateGroups extends \OC\BackgroundJob\TimedJob {
 			$userMapper  = new UserMapping($dbc);
 			$ldapAccess->setGroupMapper($groupMapper);
 			$ldapAccess->setUserMapper($userMapper);
-			self::$groupBE = new \OCA\User_LDAP\Group_LDAP($ldapAccess);
+			self::$groupBE = new \OCA\User_LDAP\Group_LDAP($ldapAccess, \OC::$server->query('LDAPGroupPluginManager'));
 		} else {
-			self::$groupBE = new \OCA\User_LDAP\Group_Proxy($configPrefixes, $ldapWrapper);
+			self::$groupBE = new \OCA\User_LDAP\Group_Proxy($configPrefixes, $ldapWrapper, \OC::$server->query('LDAPGroupPluginManager'));
 		}
 
 		return self::$groupBE;
diff --git a/apps/user_ldap/lib/LDAPProvider.php b/apps/user_ldap/lib/LDAPProvider.php
index bf8691006c6..060c478ae38 100644
--- a/apps/user_ldap/lib/LDAPProvider.php
+++ b/apps/user_ldap/lib/LDAPProvider.php
@@ -3,6 +3,10 @@
  *
  * @copyright Copyright (c) 2016, Roger Szabo (roger.szabo@web.de)
  *
+ * @author Roger Szabo <roger.szabo@web.de>
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ * @author Daniel Tygel <dtygel@eita.org.br>
+ *
  * @license GNU AGPL version 3 or any later version
  *
  * This program is free software: you can redistribute it and/or modify
@@ -33,7 +37,8 @@ use OCA\User_LDAP\User\DeletedUsersIndex;
  */
 class LDAPProvider implements ILDAPProvider, IDeletionFlagSupport {
 
-	private $backend;
+	private $userBackend;
+	private $groupBackend;
 	private $logger;
 	private $helper;
 	private $deletedUsersIndex;
@@ -47,14 +52,28 @@ class LDAPProvider implements ILDAPProvider, IDeletionFlagSupport {
 		$this->logger = $serverContainer->getLogger();
 		$this->helper = $helper;
 		$this->deletedUsersIndex = $deletedUsersIndex;
+		$userBackendFound = false;
+		$groupBackendFound = false;
 		foreach ($serverContainer->getUserManager()->getBackends() as $backend){
-			$this->logger->debug('instance '.get_class($backend).' backend.', ['app' => 'user_ldap']);
+			$this->logger->debug('instance '.get_class($backend).' user backend.', ['app' => 'user_ldap']);
 			if ($backend instanceof IUserLDAP) {
-				$this->backend = $backend;
-				return;
+				$this->userBackend = $backend;
+				$userBackendFound = true;
+				break;
 			}
         }
-		throw new \Exception('To use the LDAPProvider, user_ldap app must be enabled');
+		foreach ($serverContainer->getGroupManager()->getBackends() as $backend){
+			$this->logger->debug('instance '.get_class($backend).' group backend.', ['app' => 'user_ldap']);
+			if ($backend instanceof IGroupLDAP) {
+				$this->groupBackend = $backend;
+				$groupBackendFound = true;
+				break;
+			}
+		}
+
+        if (!$userBackendFound or !$groupBackendFound) {
+			throw new \Exception('To use the LDAPProvider, user_ldap app must be enabled');
+		}
 	}
 	
 	/**
@@ -64,16 +83,33 @@ class LDAPProvider implements ILDAPProvider, IDeletionFlagSupport {
 	 * @throws \Exception if translation was unsuccessful
 	 */
 	public function getUserDN($uid) {
-		if(!$this->backend->userExists($uid)){
+		if(!$this->userBackend->userExists($uid)){
 			throw new \Exception('User id not found in LDAP');
 		}
-		$result = $this->backend->getLDAPAccess($uid)->username2dn($uid);
+		$result = $this->userBackend->getLDAPAccess($uid)->username2dn($uid);
 		if(!$result){
 			throw new \Exception('Translation to LDAP DN unsuccessful');
 		}
 		return $result;
 	}
-	
+
+	/**
+	 * Translate a group id to LDAP DN.
+	 * @param string $gid group id
+	 * @return string
+	 * @throws \Exception
+	 */
+	public function getGroupDN($gid) {
+		if(!$this->groupBackend->groupExists($gid)){
+			throw new \Exception('Group id not found in LDAP');
+		}
+		$result = $this->groupBackend->getLDAPAccess($gid)->groupname2dn($gid);
+		if(!$result){
+			throw new \Exception('Translation to LDAP DN unsuccessful');
+		}
+		return $result;	
+	}
+
 	/**
 	 * Translate a LDAP DN to an internal user name. If there is no mapping between 
 	 * the DN and the user name, a new one will be created.
@@ -82,7 +118,7 @@ class LDAPProvider implements ILDAPProvider, IDeletionFlagSupport {
 	 * @throws \Exception if translation was unsuccessful
 	 */
 	public function getUserName($dn) {
-		$result = $this->backend->dn2UserName($dn);
+		$result = $this->userBackend->dn2UserName($dn);
 		if(!$result){
 			throw new \Exception('Translation to internal user name unsuccessful');
 		}
@@ -115,10 +151,24 @@ class LDAPProvider implements ILDAPProvider, IDeletionFlagSupport {
 	 * @throws \Exception if user id was not found in LDAP
 	 */
 	public function getLDAPConnection($uid) {
-		if(!$this->backend->userExists($uid)){
+		if(!$this->userBackend->userExists($uid)){
 			throw new \Exception('User id not found in LDAP');
 		}
-		return $this->backend->getNewLDAPConnection($uid);
+		return $this->userBackend->getNewLDAPConnection($uid);
+	}
+
+	/**
+	 * Return a new LDAP connection resource for the specified user.
+	 * The connection must be closed manually.
+	 * @param string $gid group id
+	 * @return resource of the LDAP connection
+	 * @throws \Exception if group id was not found in LDAP
+	 */
+	public function getGroupLDAPConnection($gid) {
+		if(!$this->groupBackend->groupExists($gid)){
+			throw new \Exception('Group id not found in LDAP');
+		}
+		return $this->groupBackend->getNewLDAPConnection($gid);
 	}
 	
 	/**
@@ -128,10 +178,10 @@ class LDAPProvider implements ILDAPProvider, IDeletionFlagSupport {
 	 * @throws \Exception if user id was not found in LDAP
 	 */
 	public function getLDAPBaseUsers($uid) {
-		if(!$this->backend->userExists($uid)){
+		if(!$this->userBackend->userExists($uid)){
 			throw new \Exception('User id not found in LDAP');
 		}	
-		return $this->backend->getLDAPAccess($uid)->getConnection()->getConfiguration()['ldap_base_users'];
+		return $this->userBackend->getLDAPAccess($uid)->getConnection()->getConfiguration()['ldap_base_users'];
 	}
 	
 	/**
@@ -141,10 +191,10 @@ class LDAPProvider implements ILDAPProvider, IDeletionFlagSupport {
 	 * @throws \Exception if user id was not found in LDAP
 	 */
 	public function getLDAPBaseGroups($uid) {
-		if(!$this->backend->userExists($uid)){
+		if(!$this->userBackend->userExists($uid)){
 			throw new \Exception('User id not found in LDAP');
 		}
-		return $this->backend->getLDAPAccess($uid)->getConnection()->getConfiguration()['ldap_base_groups'];
+		return $this->userBackend->getLDAPAccess($uid)->getConnection()->getConfiguration()['ldap_base_groups'];
 	}
 	
 	/**
@@ -153,10 +203,23 @@ class LDAPProvider implements ILDAPProvider, IDeletionFlagSupport {
 	 * @throws \Exception if user id was not found in LDAP
 	 */
 	public function clearCache($uid) {
-		if(!$this->backend->userExists($uid)){
+		if(!$this->userBackend->userExists($uid)){
 			throw new \Exception('User id not found in LDAP');
 		}
-		$this->backend->getLDAPAccess($uid)->getConnection()->clearCache();
+		$this->userBackend->getLDAPAccess($uid)->getConnection()->clearCache();
+	}
+
+	/**
+	 * Clear the cache if a cache is used, otherwise do nothing.
+	 * Acts on the LDAP connection of a group
+	 * @param string $gid group id
+	 * @throws \Exception if user id was not found in LDAP
+	 */
+	public function clearGroupCache($gid) {
+		if(!$this->groupBackend->groupExists($gid)){
+			throw new \Exception('Group id not found in LDAP');
+		}
+		$this->groupBackend->getLDAPAccess($gid)->getConnection()->clearCache();
 	}
 	
 	/**
@@ -165,7 +228,7 @@ class LDAPProvider implements ILDAPProvider, IDeletionFlagSupport {
 	 * @return bool whether the DN exists
 	 */
 	public function dnExists($dn) {
-		$result = $this->backend->dn2UserName($dn);
+		$result = $this->userBackend->dn2UserName($dn);
 		return !$result ? false : true;
 	}
 	
@@ -184,4 +247,44 @@ class LDAPProvider implements ILDAPProvider, IDeletionFlagSupport {
 	public function unflagRecord($uid) {
 		//do nothing
 	}
+
+	/**
+	 * Get the LDAP attribute name for the user's display name
+	 * @param string $uid user id
+	 * @return string the display name field
+	 * @throws \Exception if user id was not found in LDAP
+	 */
+	public function getLDAPDisplayNameField($uid) {
+		if(!$this->userBackend->userExists($uid)){
+			throw new \Exception('User id not found in LDAP');
+		}
+		return $this->userBackend->getLDAPAccess($uid)->getConnection()->getConfiguration()['ldap_display_name'];
+	}
+
+	/**
+	 * Get the LDAP attribute name for the email
+	 * @param string $uid user id
+	 * @return string the email field
+	 * @throws \Exception if user id was not found in LDAP
+	 */
+	public function getLDAPEmailField($uid) {
+		if(!$this->userBackend->userExists($uid)){
+			throw new \Exception('User id not found in LDAP');
+		}
+		return $this->userBackend->getLDAPAccess($uid)->getConnection()->getConfiguration()['ldap_email_attr'];
+	}
+
+	/**
+	 * Get the LDAP type of association between users and groups
+	 * @param string $gid group id
+	 * @return string the configuration, one of: 'memberUid', 'uniqueMember', 'member', 'gidNumber'
+	 * @throws \Exception if group id was not found in LDAP
+	 */
+	public function getLDAPGroupMemberAssoc($gid) {
+		if(!$this->groupBackend->groupExists($gid)){
+			throw new \Exception('Group id not found in LDAP');
+		}
+		return $this->groupBackend->getLDAPAccess($gid)->getConnection()->getConfiguration()['ldap_group_member_assoc_attribute'];
+	}
+
 }
diff --git a/apps/user_ldap/lib/Migration/UUIDFixGroup.php b/apps/user_ldap/lib/Migration/UUIDFixGroup.php
index 9ea406efadf..94e0778b9a9 100644
--- a/apps/user_ldap/lib/Migration/UUIDFixGroup.php
+++ b/apps/user_ldap/lib/Migration/UUIDFixGroup.php
@@ -33,6 +33,7 @@ class UUIDFixGroup extends UUIDFix {
 	public function __construct(GroupMapping $mapper, LDAP $ldap, IConfig $config, Helper $helper) {
 		$this->mapper = $mapper;
 		$this->proxy = new User_Proxy($helper->getServerConfigurationPrefixes(true), $ldap, $config, 
-			\OC::$server->getNotificationManager(), \OC::$server->getUserSession());
+			\OC::$server->getNotificationManager(), \OC::$server->getUserSession(),
+			\OC::$server->query('LDAPUserPluginManager'));
 	}
 }
diff --git a/apps/user_ldap/lib/Migration/UUIDFixUser.php b/apps/user_ldap/lib/Migration/UUIDFixUser.php
index ee1457dcccb..68003fd118f 100644
--- a/apps/user_ldap/lib/Migration/UUIDFixUser.php
+++ b/apps/user_ldap/lib/Migration/UUIDFixUser.php
@@ -32,6 +32,7 @@ use OCP\IConfig;
 class UUIDFixUser extends UUIDFix {
 	public function __construct(UserMapping $mapper, LDAP $ldap, IConfig $config, Helper $helper) {
 		$this->mapper = $mapper;
-		$this->proxy = new Group_Proxy($helper->getServerConfigurationPrefixes(true), $ldap, $config);
+		$groupPluginManager = \OC::$server->query('LDAPGroupPluginManager');
+		$this->proxy = new Group_Proxy($helper->getServerConfigurationPrefixes(true), $ldap, $groupPluginManager);
 	}
 }
diff --git a/apps/user_ldap/lib/UserPluginManager.php b/apps/user_ldap/lib/UserPluginManager.php
new file mode 100644
index 00000000000..374e545f4fd
--- /dev/null
+++ b/apps/user_ldap/lib/UserPluginManager.php
@@ -0,0 +1,208 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br)
+ *
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ * @author Daniel Tygel <dtygel@eita.org.br>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP;
+
+use OC\User\Backend;
+
+class UserPluginManager {
+
+	public $test = false;
+
+	private $respondToActions = 0;
+
+	private $which = array(
+		Backend::CREATE_USER => null,
+		Backend::SET_PASSWORD => null,
+		Backend::GET_HOME => null,
+		Backend::GET_DISPLAYNAME => null,
+		Backend::SET_DISPLAYNAME => null,
+		Backend::PROVIDE_AVATAR => null,
+		Backend::COUNT_USERS => null,
+		'deleteUser' => null
+	);
+
+	/**
+	 * @return int All implemented actions, except for 'deleteUser'
+	 */
+	public function getImplementedActions() {
+		return $this->respondToActions;
+	}
+
+	/**
+	 * Registers a group plugin that may implement some actions, overriding User_LDAP's user actions.
+	 * @param ILDAPGroupPlugin $plugin
+	 */
+	public function register(ILDAPUserPlugin $plugin) {
+		$respondToActions = $plugin->respondToActions();
+		$this->respondToActions |= $respondToActions;
+
+		foreach($this->which as $action => $v) {
+			if ((bool)($respondToActions & $action)) {
+				$this->which[$action] = $plugin;
+				\OC::$server->getLogger()->debug("Registered action ".$action." to plugin ".get_class($plugin), ['app' => 'user_ldap']);
+			}
+		}
+		if (method_exists($plugin,'deleteUser')) {
+			$this->which['deleteUser'] = $plugin;
+		}
+	}
+
+	/**
+	 * Signal if there is a registered plugin that implements some given actions
+	 * @param int $action Actions defined in \OC\User\Backend, like Backend::CREATE_USER
+	 * @return bool
+	 */
+	public function implementsActions($actions) {
+		return ($actions & $this->respondToActions) == $actions;
+	}
+
+	/**
+	 * Create a new user in LDAP Backend
+	 *
+	 * @param string $uid The username of the user to create
+	 * @param string $password The password of the new user
+	 * @return bool
+	 * @throws \Exception
+	 */
+	public function createUser($username, $password) {
+		$plugin = $this->which[Backend::CREATE_USER];
+
+		if ($plugin) {
+			return $plugin->createUser($username,$password);
+		}
+		throw new \Exception('No plugin implements createUser in this LDAP Backend.');
+	}
+
+	/**
+	 * Change the password of a user*
+	 * @param string $uid The username
+	 * @param string $password The new password
+	 * @return bool
+	 * @throws \Exception
+	 */
+	public function setPassword($uid, $password) {
+		$plugin = $this->which[Backend::SET_PASSWORD];
+
+		if ($plugin) {
+			return $plugin->setPassword($uid,$password);
+		}
+		throw new \Exception('No plugin implements setPassword in this LDAP Backend.');
+	}
+
+	/**
+	 * checks whether the user is allowed to change his avatar in Nextcloud
+	 * @param string $uid the Nextcloud user name
+	 * @return boolean either the user can or cannot
+	 * @throws \Exception
+	 */
+	public function canChangeAvatar($uid) {
+		$plugin = $this->which[Backend::PROVIDE_AVATAR];
+
+		if ($plugin) {
+			return $plugin->canChangeAvatar($uid);
+		}
+		throw new \Exception('No plugin implements canChangeAvatar in this LDAP Backend.');
+	}
+
+	/**
+	 * Get the user's home directory
+	 * @param string $uid the username
+	 * @return boolean
+	 * @throws \Exception
+	 */
+	public function getHome($uid) {
+		$plugin = $this->which[Backend::GET_HOME];
+
+		if ($plugin) {
+			return $plugin->getHome($uid);
+		}
+		throw new \Exception('No plugin implements getHome in this LDAP Backend.');
+	}
+
+	/**
+	 * Get display name of the user
+	 * @param string $uid user ID of the user
+	 * @return string display name
+	 * @throws \Exception
+	 */
+	public function getDisplayName($uid) {
+		$plugin = $this->which[Backend::GET_DISPLAYNAME];
+
+		if ($plugin) {
+			return $plugin->getDisplayName($uid);
+		}
+		throw new \Exception('No plugin implements getDisplayName in this LDAP Backend.');
+	}
+
+	/**
+	 * Set display name of the user
+	 * @param string $uid user ID of the user
+	 * @param string $displayName new user's display name
+	 * @return string display name
+	 * @throws \Exception
+	 */
+	public function setDisplayName($uid, $displayName) {
+		$plugin = $this->which[Backend::SET_DISPLAYNAME];
+
+		if ($plugin) {
+			return $plugin->setDisplayName($uid, $displayName);
+		}
+		throw new \Exception('No plugin implements setDisplayName in this LDAP Backend.');
+	}
+
+	/**
+	 * Count the number of users
+	 * @return int|bool
+	 * @throws \Exception
+	 */
+	public function countUsers() {
+		$plugin = $this->which[Backend::COUNT_USERS];
+
+		if ($plugin) {
+			return $plugin->countUsers();
+		}
+		throw new \Exception('No plugin implements countUsers in this LDAP Backend.');
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function canDeleteUser() {
+		return $this->which['deleteUser'] !== null;
+	}
+
+	/**
+	 * @param $uid
+	 * @return bool
+	 * @throws \Exception
+	 */
+	public function deleteUser($uid) {
+		$plugin = $this->which['deleteUser'];
+		if ($plugin) {
+			return $plugin->deleteUser($uid);
+		}
+		throw new \Exception('No plugin implements deleteUser in this LDAP Backend.');
+	}
+}
+
diff --git a/apps/user_ldap/lib/User_LDAP.php b/apps/user_ldap/lib/User_LDAP.php
index 0a9a1cfe4c2..87706dcfe8b 100644
--- a/apps/user_ldap/lib/User_LDAP.php
+++ b/apps/user_ldap/lib/User_LDAP.php
@@ -16,6 +16,8 @@
  * @author Thomas Müller <thomas.mueller@tmit.eu>
  * @author Tom Needham <tom@owncloud.com>
  * @author Roger Szabo <roger.szabo@web.de>
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ * @author Daniel Tygel <dtygel@eita.org.br>
  *
  * @license AGPL-3.0
  *
@@ -56,16 +58,20 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
 	/** @var string */
 	protected $currentUserInDeletionProcess;
 
+	/** @var UserPluginManager */
+	protected $userPluginManager;
+
 	/**
 	 * @param Access $access
 	 * @param \OCP\IConfig $ocConfig
 	 * @param \OCP\Notification\IManager $notificationManager
 	 * @param IUserSession $userSession
 	 */
-	public function __construct(Access $access, IConfig $ocConfig, INotificationManager $notificationManager, IUserSession $userSession) {
+	public function __construct(Access $access, IConfig $ocConfig, INotificationManager $notificationManager, IUserSession $userSession, UserPluginManager $userPluginManager) {
 		parent::__construct($access);
 		$this->ocConfig = $ocConfig;
 		$this->notificationManager = $notificationManager;
+		$this->userPluginManager = $userPluginManager;
 		$this->registerHooks($userSession);
 	}
 
@@ -88,6 +94,10 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
 	 * @return boolean either the user can or cannot
 	 */
 	public function canChangeAvatar($uid) {
+		if ($this->userPluginManager->implementsActions(Backend::PROVIDE_AVATAR)) {
+			return $this->userPluginManager->canChangeAvatar($uid);
+		}
+
 		$user = $this->access->userManager->get($uid);
 		if(!$user instanceof User) {
 			return false;
@@ -207,6 +217,10 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
 	 * @return bool
 	 */
 	public function setPassword($uid, $password) {
+		if ($this->userPluginManager->implementsActions(Backend::SET_PASSWORD)) {
+			return $this->userPluginManager->setPassword($uid, $password);
+		}
+
 		$user = $this->access->userManager->get($uid);
 
 		if(!$user instanceof User) {
@@ -364,6 +378,10 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
 	* @return bool
 	*/
 	public function deleteUser($uid) {
+		if ($this->userPluginManager->canDeleteUser()) {
+			return $this->userPluginManager->deleteUser($uid);
+		}
+
 		$marked = $this->ocConfig->getUserValue($uid, 'user_ldap', 'isDeleted', 0);
 		if(intval($marked) === 0) {
 			\OC::$server->getLogger()->notice(
@@ -393,6 +411,10 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
 			return false;
 		}
 
+		if ($this->userPluginManager->implementsActions(Backend::GET_HOME)) {
+			return $this->userPluginManager->getHome($uid);
+		}
+
 		$cacheKey = 'getHome'.$uid;
 		$path = $this->access->connection->getFromCache($cacheKey);
 		if(!is_null($path)) {
@@ -425,6 +447,10 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
 	 * @return string|false display name
 	 */
 	public function getDisplayName($uid) {
+		if ($this->userPluginManager->implementsActions(Backend::GET_DISPLAYNAME)) {
+			return $this->userPluginManager->getDisplayName($uid);
+		}
+
 		if(!$this->userExists($uid)) {
 			return false;
 		}
@@ -469,6 +495,19 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
 		return null;
 	}
 
+	/**
+	 * set display name of the user
+	 * @param string $uid user ID of the user
+	 * @param string $displayName new display name of the user
+	 * @return string|false display name
+	 */
+	public function setDisplayName($uid, $displayName) {
+		if ($this->userPluginManager->implementsActions(Backend::SET_DISPLAYNAME)) {
+			return $this->userPluginManager->setDisplayName($uid, $displayName);
+		}
+		return false;
+	}
+
 	/**
 	 * Get a list of all display names
 	 *
@@ -506,7 +545,8 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
 			| Backend::GET_DISPLAYNAME
 			| Backend::PROVIDE_AVATAR
 			| Backend::COUNT_USERS
-			| ((intval($this->access->connection->turnOnPasswordChange) === 1)?(Backend::SET_PASSWORD):0))
+			| ((intval($this->access->connection->turnOnPasswordChange) === 1)?(Backend::SET_PASSWORD):0)
+			| $this->userPluginManager->getImplementedActions())
 			& $actions);
 	}
 
@@ -523,6 +563,10 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
 	 * @return int|bool
 	 */
 	public function countUsers() {
+		if ($this->userPluginManager->implementsActions(Backend::COUNT_USERS)) {
+			return $this->userPluginManager->countUsers();
+		}
+
 		$filter = $this->access->getFilterForUserCount();
 		$cacheKey = 'countUsers-'.$filter;
 		if(!is_null($entries = $this->access->connection->getFromCache($cacheKey))) {
@@ -561,4 +605,18 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
 		$connection = clone $this->access->getConnection();
 		return $connection->getConnectionResource();
 	}
+
+	/**
+	 * create new user
+	 * @param string $username username of the new user
+	 * @param string $password password of the new user
+	 * @return bool was the user created?
+	 */
+	public function createUser($username, $password) {
+		if ($this->userPluginManager->implementsActions(Backend::CREATE_USER)) {
+			return $this->userPluginManager->createUser($username, $password);
+		}
+		return false;
+	}
+
 }
diff --git a/apps/user_ldap/lib/User_Proxy.php b/apps/user_ldap/lib/User_Proxy.php
index a25eb1bc621..c65999e3fde 100644
--- a/apps/user_ldap/lib/User_Proxy.php
+++ b/apps/user_ldap/lib/User_Proxy.php
@@ -10,6 +10,8 @@
  * @author Robin McCorkell <robin@mccorkell.me.uk>
  * @author Thomas Müller <thomas.mueller@tmit.eu>
  * @author Roger Szabo <roger.szabo@web.de>
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ * @author Daniel Tygel <dtygel@eita.org.br>
  *
  * @license AGPL-3.0
  *
@@ -48,11 +50,13 @@ class User_Proxy extends Proxy implements \OCP\IUserBackend, \OCP\UserInterface,
 	 * @param IUserSession $userSession
 	 */
 	public function __construct(array $serverConfigPrefixes, ILDAPWrapper $ldap, IConfig $ocConfig,
-		INotificationManager $notificationManager, IUserSession $userSession) {
+		INotificationManager $notificationManager, IUserSession $userSession,
+								UserPluginManager $userPluginManager) {
 		parent::__construct($ldap);
 		foreach($serverConfigPrefixes as $configPrefix) {
 			$this->backends[$configPrefix] =
-				new User_LDAP($this->getAccess($configPrefix), $ocConfig, $notificationManager, $userSession);
+				new User_LDAP($this->getAccess($configPrefix), $ocConfig, $notificationManager, $userSession, $userPluginManager);
+
 			if(is_null($this->refBackend)) {
 				$this->refBackend = &$this->backends[$configPrefix];
 			}
@@ -232,13 +236,24 @@ class User_Proxy extends Proxy implements \OCP\IUserBackend, \OCP\UserInterface,
 		return $this->handleRequest($uid, 'getDisplayName', array($uid));
 	}
 
+	/**
+	 * set display name of the user
+	 *
+	 * @param string $uid user ID of the user
+	 * @param string $displayName new display name
+	 * @return string display name
+	 */
+	public function setDisplayName($uid, $displayName) {
+		return $this->handleRequest($uid, 'setDisplayName', array($uid, $displayName));
+	}
+
 	/**
 	 * checks whether the user is allowed to change his avatar in Nextcloud
 	 * @param string $uid the Nextcloud user name
 	 * @return boolean either the user can or cannot
 	 */
 	public function canChangeAvatar($uid) {
-		return $this->handleRequest($uid, 'canChangeAvatar', array($uid), true);
+		return $this->handleRequest($uid, 'canChangeAvatar', array($uid));
 	}
 
 	/**
@@ -322,4 +337,14 @@ class User_Proxy extends Proxy implements \OCP\IUserBackend, \OCP\UserInterface,
 	public function getNewLDAPConnection($uid) {
 		return $this->handleRequest($uid, 'getNewLDAPConnection', array($uid));
 	}
+
+	/**
+	 * Creates a new user in LDAP
+	 * @param $username
+	 * @param $password
+	 * @return bool
+	 */
+	public function createUser($username, $password) {
+		return $this->handleRequest($username, 'createUser', array($username,$password));
+	}
 }
diff --git a/apps/user_ldap/tests/GroupLDAPPluginTest.php b/apps/user_ldap/tests/GroupLDAPPluginTest.php
new file mode 100644
index 00000000000..5f89da95105
--- /dev/null
+++ b/apps/user_ldap/tests/GroupLDAPPluginTest.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br)
+ *
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP\Tests;
+
+
+use OC\Group\Backend;
+use OCA\User_LDAP\GroupPluginManager;
+
+class GroupLDAPPluginTest extends \Test\TestCase {
+
+	/**
+	 * @return GroupPluginManager
+	 */
+	private function getGroupPluginManager() {
+		return new GroupPluginManager();
+	}
+
+	public function testImplementsActions() {
+		$pluginManager = $this->getGroupPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy')
+			->setMethods(['respondToActions'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::CREATE_GROUP);
+
+		$plugin2 = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy')
+			->setMethods(['respondToActions'])
+			->getMock();
+
+		$plugin2->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::ADD_TO_GROUP);
+
+		$pluginManager->register($plugin);
+		$pluginManager->register($plugin2);
+
+		$this->assertEquals($pluginManager->getImplementedActions(), Backend::CREATE_GROUP | Backend::ADD_TO_GROUP);
+		$this->assertTrue($pluginManager->implementsActions(Backend::CREATE_GROUP));
+		$this->assertTrue($pluginManager->implementsActions(Backend::ADD_TO_GROUP));
+	}
+
+	public function testCreateGroup() {
+		$pluginManager = $this->getGroupPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy')
+			->setMethods(['respondToActions', 'createGroup'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::CREATE_GROUP);
+
+		$plugin->expects($this->once())
+			->method('createGroup')
+			->with(
+				$this->equalTo('group')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->createGroup('group');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements createGroup in this LDAP Backend.
+	 */
+	public function testCreateGroupNotRegistered() {
+		$pluginManager = $this->getGroupPluginManager();
+		$pluginManager->createGroup('foo');
+	}
+
+	public function testDeleteGroup() {
+		$pluginManager = $this->getGroupPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy')
+			->setMethods(['respondToActions', 'deleteGroup'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::DELETE_GROUP);
+
+		$plugin->expects($this->once())
+			->method('deleteGroup')
+			->with(
+				$this->equalTo('group')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->deleteGroup('group');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements deleteGroup in this LDAP Backend.
+	 */
+	public function testDeleteGroupNotRegistered() {
+		$pluginManager = $this->getGroupPluginManager();
+		$pluginManager->deleteGroup('foo');
+	}
+
+	public function testAddToGroup() {
+		$pluginManager = $this->getGroupPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy')
+			->setMethods(['respondToActions', 'addToGroup'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::ADD_TO_GROUP);
+
+		$plugin->expects($this->once())
+			->method('addToGroup')
+			->with(
+				$this->equalTo('uid'),
+				$this->equalTo('gid')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->addToGroup('uid', 'gid');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements addToGroup in this LDAP Backend.
+	 */
+	public function testAddToGroupNotRegistered() {
+		$pluginManager = $this->getGroupPluginManager();
+		$pluginManager->addToGroup('foo', 'bar');
+	}	
+
+	public function testRemoveFromGroup() {
+		$pluginManager = $this->getGroupPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy')
+			->setMethods(['respondToActions', 'removeFromGroup'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::REMOVE_FROM_GROUP);
+
+		$plugin->expects($this->once())
+			->method('removeFromGroup')
+			->with(
+				$this->equalTo('uid'),
+				$this->equalTo('gid')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->removeFromGroup('uid', 'gid');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements removeFromGroup in this LDAP Backend.
+	 */
+	public function testRemoveFromGroupNotRegistered() {
+		$pluginManager = $this->getGroupPluginManager();
+		$pluginManager->removeFromGroup('foo', 'bar');
+	}
+
+	public function testCountUsersInGroup() {
+		$pluginManager = $this->getGroupPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy')
+			->setMethods(['respondToActions', 'countUsersInGroup'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::COUNT_USERS);
+
+		$plugin->expects($this->once())
+			->method('countUsersInGroup')
+			->with(
+				$this->equalTo('gid'),
+				$this->equalTo('search')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->countUsersInGroup('gid', 'search');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements countUsersInGroup in this LDAP Backend.
+	 */
+	public function testCountUsersInGroupNotRegistered() {
+		$pluginManager = $this->getGroupPluginManager();
+		$pluginManager->countUsersInGroup('foo', 'bar');
+	}	
+
+	public function testgetGroupDetails() {
+		$pluginManager = $this->getGroupPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy')
+			->setMethods(['respondToActions', 'getGroupDetails'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::GROUP_DETAILS);
+
+		$plugin->expects($this->once())
+			->method('getGroupDetails')
+			->with(
+				$this->equalTo('gid')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->getGroupDetails('gid');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements getGroupDetails in this LDAP Backend.
+	 */
+	public function testgetGroupDetailsNotRegistered() {
+		$pluginManager = $this->getGroupPluginManager();
+		$pluginManager->getGroupDetails('foo');
+	}
+}
diff --git a/apps/user_ldap/tests/Group_LDAPTest.php b/apps/user_ldap/tests/Group_LDAPTest.php
index 9b5216742fe..82372895c29 100644
--- a/apps/user_ldap/tests/Group_LDAPTest.php
+++ b/apps/user_ldap/tests/Group_LDAPTest.php
@@ -29,6 +29,7 @@
 
 namespace OCA\User_LDAP\Tests;
 
+use OC\Group\Backend;
 use OCA\User_LDAP\Group_LDAP as GroupLDAP;
 use OCA\User_LDAP\ILDAPWrapper;
 
@@ -69,6 +70,10 @@ class Group_LDAPTest extends \Test\TestCase {
 		return $access;
 	}
 
+	private function getPluginManagerMock() {
+		return $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')->getMock();
+	}
+
 	private function enableGroups($access) {
 		$access->connection->expects($this->any())
 			->method('__get')
@@ -82,6 +87,7 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testCountEmptySearchString() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
 
 		$this->enableGroups($access);
 
@@ -98,7 +104,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->method('countUsers')
 			->will($this->returnValue(2));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 		$users = $groupBackend->countUsersInGroup('group');
 
 		$this->assertSame(6, $users);
@@ -106,6 +112,7 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testCountWithSearchString() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
 
 		$this->enableGroups($access);
 
@@ -137,14 +144,39 @@ class Group_LDAPTest extends \Test\TestCase {
 				return 'foobar' . \OCP\Util::generateRandomBytes(7);
 			}));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access,$pluginManager);
 		$users = $groupBackend->countUsersInGroup('group', '3');
 
 		$this->assertSame(2, $users);
 	}
 
+	public function testCountUsersWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')
+			->setMethods(['implementsActions','countUsersInGroup'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::COUNT_USERS)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('countUsersInGroup')
+			->with('gid', 'search')
+			->willReturn(42);
+
+		$ldap = new GroupLDAP(
+			$this->getAccessMock(),
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->countUsersInGroup('gid', 'search'),42);
+	}	
+
 	public function testGidNumber2NameSuccess() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
@@ -158,7 +190,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->with('cn=foo,dc=barfoo,dc=bar')
 			->will($this->returnValue('MyGroup'));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 
 		$group = $groupBackend->gidNumber2Name('3117', $userDN);
 
@@ -167,6 +199,8 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testGidNumberID2NameNoGroup() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
@@ -178,7 +212,7 @@ class Group_LDAPTest extends \Test\TestCase {
 		$access->expects($this->never())
 			->method('dn2groupname');
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 
 		$group = $groupBackend->gidNumber2Name('3117', $userDN);
 
@@ -187,6 +221,8 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testGidNumberID2NameNoName() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
@@ -199,7 +235,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->method('dn2groupname')
 			->will($this->returnValue(false));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 
 		$group = $groupBackend->gidNumber2Name('3117', $userDN);
 
@@ -208,6 +244,8 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testGetEntryGidNumberValue() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
@@ -218,7 +256,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->with($dn, $attr)
 			->will($this->returnValue(array('3117')));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 
 		$gid = $groupBackend->getGroupGidNumber($dn);
 
@@ -227,6 +265,8 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testGetEntryGidNumberNoValue() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
@@ -237,7 +277,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->with($dn, $attr)
 			->will($this->returnValue(false));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 
 		$gid = $groupBackend->getGroupGidNumber($dn);
 
@@ -246,6 +286,8 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testPrimaryGroupID2NameSuccess() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
@@ -264,7 +306,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->with('cn=foo,dc=barfoo,dc=bar')
 			->will($this->returnValue('MyGroup'));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 
 		$group = $groupBackend->primaryGroupID2Name('3117', $userDN);
 
@@ -273,6 +315,8 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testPrimaryGroupID2NameNoSID() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
@@ -288,7 +332,7 @@ class Group_LDAPTest extends \Test\TestCase {
 		$access->expects($this->never())
 			->method('dn2groupname');
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 
 		$group = $groupBackend->primaryGroupID2Name('3117', $userDN);
 
@@ -297,6 +341,8 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testPrimaryGroupID2NameNoGroup() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
@@ -313,7 +359,7 @@ class Group_LDAPTest extends \Test\TestCase {
 		$access->expects($this->never())
 			->method('dn2groupname');
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 
 		$group = $groupBackend->primaryGroupID2Name('3117', $userDN);
 
@@ -322,6 +368,8 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testPrimaryGroupID2NameNoName() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
@@ -339,7 +387,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->method('dn2groupname')
 			->will($this->returnValue(false));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 
 		$group = $groupBackend->primaryGroupID2Name('3117', $userDN);
 
@@ -350,6 +398,8 @@ class Group_LDAPTest extends \Test\TestCase {
 		//tests getEntryGroupID via getGroupPrimaryGroupID
 		//which is basically identical to getUserPrimaryGroupIDs
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
@@ -360,7 +410,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->with($dn, $attr)
 			->will($this->returnValue(array('3117')));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 
 		$gid = $groupBackend->getGroupPrimaryGroupID($dn);
 
@@ -371,6 +421,8 @@ class Group_LDAPTest extends \Test\TestCase {
 		//tests getEntryGroupID via getGroupPrimaryGroupID
 		//which is basically identical to getUserPrimaryGroupIDs
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
@@ -381,7 +433,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->with($dn, $attr)
 			->will($this->returnValue(false));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 
 		$gid = $groupBackend->getGroupPrimaryGroupID($dn);
 
@@ -394,6 +446,8 @@ class Group_LDAPTest extends \Test\TestCase {
 	 */
 	public function testInGroupHitsUidGidCache() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$uid = 'someUser';
@@ -408,19 +462,21 @@ class Group_LDAPTest extends \Test\TestCase {
 		$access->expects($this->never())
 			->method('username2dn');
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 		$groupBackend->inGroup($uid, $gid);
 	}
 
 	public function testGetGroupsWithOffset() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$access->expects($this->once())
 			->method('nextcloudGroupNames')
 			->will($this->returnValue(array('group1', 'group2')));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 		$groups = $groupBackend->getGroups('', 2, 2);
 
 		$this->assertSame(2, count($groups));
@@ -432,6 +488,8 @@ class Group_LDAPTest extends \Test\TestCase {
 	 */
 	public function testUsersInGroupPrimaryMembersOnly() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$access->connection->expects($this->any())
@@ -457,7 +515,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->method('nextcloudUserNames')
 			->willReturnOnConsecutiveCalls(['lisa', 'bart', 'kira', 'brad'], ['walle', 'dino', 'xenia']);
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 		$users = $groupBackend->usersInGroup('foobar');
 
 		$this->assertSame(7, count($users));
@@ -469,6 +527,8 @@ class Group_LDAPTest extends \Test\TestCase {
 	 */
 	public function testUsersInGroupPrimaryAndUnixMembers() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$access->connection->expects($this->any())
@@ -492,7 +552,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->method('nextcloudUserNames')
 			->will($this->returnValue(array('lisa', 'bart', 'kira', 'brad')));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 		$users = $groupBackend->usersInGroup('foobar');
 
 		$this->assertSame(4, count($users));
@@ -504,6 +564,8 @@ class Group_LDAPTest extends \Test\TestCase {
 	 */
 	public function testCountUsersInGroupPrimaryMembersOnly() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$access->connection->expects($this->any())
@@ -527,7 +589,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->method('countUsers')
 			->will($this->returnValue(4));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 		$users = $groupBackend->countUsersInGroup('foobar');
 
 		$this->assertSame(4, $users);
@@ -535,6 +597,8 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testGetUserGroupsMemberOf() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
+
 		$this->enableGroups($access);
 
 		$dn = 'cn=userX,dc=foobar';
@@ -558,7 +622,7 @@ class Group_LDAPTest extends \Test\TestCase {
 			->method('groupsMatchFilter')
 			->will($this->returnArgument(0));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 		$groups = $groupBackend->getUserGroups('userX');
 
 		$this->assertSame(2, count($groups));
@@ -566,6 +630,7 @@ class Group_LDAPTest extends \Test\TestCase {
 
 	public function testGetUserGroupsMemberOfDisabled() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
 
 		$access->connection->expects($this->any())
 			->method('__get')
@@ -595,12 +660,13 @@ class Group_LDAPTest extends \Test\TestCase {
 			->method('nextcloudGroupNames')
 			->will($this->returnValue([]));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 		$groupBackend->getUserGroups('userX');
 	}
 
 	public function testGetGroupsByMember() {
 		$access = $this->getAccessMock();
+		$pluginManager = $this->getPluginManagerMock();
 
 		$access->connection->expects($this->any())
 			->method('__get')
@@ -646,11 +712,243 @@ class Group_LDAPTest extends \Test\TestCase {
 			->method('fetchListOfGroups')
 			->will($this->returnValue([$group1, $group2]));
 
-		$groupBackend = new GroupLDAP($access);
+		$groupBackend = new GroupLDAP($access, $pluginManager);
 		$groups = $groupBackend->getUserGroups('userX');
 		$this->assertEquals(['group1', 'group2'], $groups);
 
 		$groupsAgain = $groupBackend->getUserGroups('userX');
 		$this->assertEquals(['group1', 'group2'], $groupsAgain);
 	}
+
+	public function testCreateGroupWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')
+			->setMethods(['implementsActions','createGroup'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::CREATE_GROUP)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('createGroup')
+			->with('gid')
+			->willReturn('result');
+
+		$ldap = new GroupLDAP(
+			$this->getAccessMock(),
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->createGroup('gid'),true);
+	}
+
+	/**
+	 * @expectedException \Exception
+	 */
+	public function testCreateGroupFailing() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')
+			->setMethods(['implementsActions', 'createGroup'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::CREATE_GROUP)
+			->willReturn(false);
+
+		$ldap = new GroupLDAP(
+			$this->getAccessMock(),
+			$pluginManager
+		);
+
+		$ldap->createGroup('gid');
+	}
+
+	public function testDeleteGroupWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')
+			->setMethods(['implementsActions','deleteGroup'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::DELETE_GROUP)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('deleteGroup')
+			->with('gid')
+			->willReturn('result');
+
+		$access = $this->getAccessMock();
+
+		$mapper = $this->getMockBuilder('\OCA\User_LDAP\Mapping\GroupMapping')
+			->setMethods(['unmap'])
+			->disableOriginalConstructor()
+			->getMock();
+
+		$access->expects($this->any())
+			->method('getGroupMapper')
+			->will($this->returnValue($mapper));
+
+		$ldap = new GroupLDAP(
+			$access,
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->deleteGroup('gid'),'result');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 */
+	public function testDeleteGroupFailing() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')
+			->setMethods(['implementsActions', 'deleteGroup'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::DELETE_GROUP)
+			->willReturn(false);
+
+		$ldap = new GroupLDAP(
+			$this->getAccessMock(),
+			$pluginManager
+		);
+
+		$ldap->deleteGroup('gid');
+	}
+
+	public function testAddToGroupWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')
+			->setMethods(['implementsActions','addToGroup'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::ADD_TO_GROUP)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('addToGroup')
+			->with('uid', 'gid')
+			->willReturn('result');
+
+		$ldap = new GroupLDAP(
+			$this->getAccessMock(),
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->addToGroup('uid', 'gid'),'result');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 */
+	public function testAddToGroupFailing() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')
+			->setMethods(['implementsActions', 'addToGroup'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::ADD_TO_GROUP)
+			->willReturn(false);
+
+		$ldap = new GroupLDAP(
+			$this->getAccessMock(),
+			$pluginManager
+		);
+
+		$ldap->addToGroup('uid', 'gid');
+	}
+
+	public function testRemoveFromGroupWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')
+			->setMethods(['implementsActions','removeFromGroup'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::REMOVE_FROM_GROUP)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('removeFromGroup')
+			->with('uid', 'gid')
+			->willReturn('result');
+
+		$ldap = new GroupLDAP(
+			$this->getAccessMock(),
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->removeFromGroup('uid', 'gid'),'result');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 */
+	public function testRemoveFromGroupFailing() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')
+			->setMethods(['implementsActions', 'removeFromGroup'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::REMOVE_FROM_GROUP)
+			->willReturn(false);
+
+		$ldap = new GroupLDAP(
+			$this->getAccessMock(),
+			$pluginManager
+		);
+
+		$ldap->removeFromGroup('uid', 'gid');
+	}
+
+	public function testGetGroupDetailsWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')
+			->setMethods(['implementsActions','getGroupDetails'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::GROUP_DETAILS)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('getGroupDetails')
+			->with('gid')
+			->willReturn('result');
+
+		$ldap = new GroupLDAP(
+			$this->getAccessMock(),
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->getGroupDetails('gid'),'result');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 */
+	public function testGetGroupDetailsFailing() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')
+			->setMethods(['implementsActions', 'getGroupDetails'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::GROUP_DETAILS)
+			->willReturn(false);
+
+		$ldap = new GroupLDAP(
+			$this->getAccessMock(),
+			$pluginManager
+		);
+
+		$ldap->getGroupDetails('gid');
+	}	
+
 }
diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php
index bd8e4bdd7a2..bc616bfc772 100644
--- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php
+++ b/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php
@@ -49,12 +49,12 @@ class IntegrationTestAttributeDetection extends AbstractIntegrationTest {
 		$groupMapper->clear();
 		$this->access->setGroupMapper($groupMapper);
 
-		$userBackend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession());
+		$userBackend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager'));
 		$userManager = \OC::$server->getUserManager();
 		$userManager->clearBackends();
 		$userManager->registerBackend($userBackend);
 
-		$groupBackend = new Group_LDAP($this->access);
+		$groupBackend = new Group_LDAP($this->access, \OC::$server->query('LDAPGroupPluginManager'));
 		$groupManger = \OC::$server->getGroupManager();
 		$groupManger->clearBackends();
 		$groupManger->addBackend($groupBackend);
diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestFetchUsersByLoginName.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestFetchUsersByLoginName.php
index 95bfb99b65b..e96e44a6858 100644
--- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestFetchUsersByLoginName.php
+++ b/apps/user_ldap/tests/Integration/Lib/IntegrationTestFetchUsersByLoginName.php
@@ -47,7 +47,7 @@ class IntegrationTestFetchUsersByLoginName extends AbstractIntegrationTest {
 		$this->mapping = new UserMapping(\OC::$server->getDatabaseConnection());
 		$this->mapping->clear();
 		$this->access->setUserMapper($this->mapping);
-		$this->backend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession());
+		$this->backend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager'));
 	}
 
 	/**
diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestPaging.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestPaging.php
index 3c8cf22bb5b..c5f74863d9e 100644
--- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestPaging.php
+++ b/apps/user_ldap/tests/Integration/Lib/IntegrationTestPaging.php
@@ -47,7 +47,7 @@ class IntegrationTestPaging extends AbstractIntegrationTest {
 		require(__DIR__ . '/../setup-scripts/createExplicitUsers.php');
 		parent::init();
 
-		$this->backend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession());
+		$this->backend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager'));
 	}
 
 	public function initConnection() {
diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestUserHome.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestUserHome.php
index 765cee00f91..c50baef49f3 100644
--- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestUserHome.php
+++ b/apps/user_ldap/tests/Integration/Lib/IntegrationTestUserHome.php
@@ -51,7 +51,7 @@ class IntegrationTestUserHome extends AbstractIntegrationTest {
 		$this->mapping = new UserMapping(\OC::$server->getDatabaseConnection());
 		$this->mapping->clear();
 		$this->access->setUserMapper($this->mapping);
-		$this->backend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession());
+		$this->backend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager'));
 	}
 
 	/**
diff --git a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserAvatar.php b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserAvatar.php
index 8c9e215edaa..f8a317f0b10 100644
--- a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserAvatar.php
+++ b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserAvatar.php
@@ -50,7 +50,7 @@ class IntegrationTestUserAvatar extends AbstractIntegrationTest {
 		$this->mapping = new UserMapping(\OC::$server->getDatabaseConnection());
 		$this->mapping->clear();
 		$this->access->setUserMapper($this->mapping);
-		$userBackend  = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession());
+		$userBackend  = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager'));
 		\OC_User::useBackend($userBackend);
 	}
 
diff --git a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserDisplayName.php b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserDisplayName.php
index 1f5d16567f7..187d13dfdba 100644
--- a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserDisplayName.php
+++ b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserDisplayName.php
@@ -43,7 +43,7 @@ class IntegrationTestUserDisplayName extends AbstractIntegrationTest {
 		$this->mapping = new UserMapping(\OC::$server->getDatabaseConnection());
 		$this->mapping->clear();
 		$this->access->setUserMapper($this->mapping);
-		$userBackend  = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession());
+		$userBackend  = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager'));
 		\OC_User::useBackend($userBackend);
 	}
 
diff --git a/apps/user_ldap/tests/LDAPGroupPluginDummy.php b/apps/user_ldap/tests/LDAPGroupPluginDummy.php
new file mode 100644
index 00000000000..c2ccf3338a7
--- /dev/null
+++ b/apps/user_ldap/tests/LDAPGroupPluginDummy.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br)
+ *
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ * @author Daniel Tygel <dtygel@eita.org.br>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP\Tests;
+
+
+use OCA\User_LDAP\ILDAPGroupPlugin;
+
+class LDAPGroupPluginDummy implements ILDAPGroupPlugin {
+
+
+	public function respondToActions() {
+		return null;
+	}
+
+	public function createGroup($gid) {
+		return null;
+	}
+
+	public function deleteGroup($gid) {
+		return null;
+	}
+
+	public function addToGroup($uid, $gid) {
+		return null;
+	}
+
+	public function removeFromGroup($uid, $gid) {
+		return null;
+	}
+
+	public function countUsersInGroup($gid, $search = '') {
+		return null;
+	}
+
+	public function getGroupDetails($gid) {
+		return null;
+	}
+}
diff --git a/apps/user_ldap/tests/LDAPProviderTest.php b/apps/user_ldap/tests/LDAPProviderTest.php
index 585e0df662b..d9492d8e77a 100644
--- a/apps/user_ldap/tests/LDAPProviderTest.php
+++ b/apps/user_ldap/tests/LDAPProviderTest.php
@@ -3,6 +3,9 @@
  *
  * @copyright Copyright (c) 2016, Roger Szabo (roger.szabo@web.de)
  *
+ * @author Roger Szabo <roger.szabo@web.de>
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ *
  * @license GNU AGPL version 3 or any later version
  *
  * This program is free software: you can redistribute it and/or modify
@@ -22,6 +25,8 @@
 
 namespace OCA\User_LDAP\Tests;
 
+use OCA\User_LDAP\IGroupLDAP;
+use OCP\IConfig;
 use OCP\IServerContainer;
 use OCA\User_LDAP\IUserLDAP;
 
@@ -38,21 +43,57 @@ class LDAPProviderTest extends \Test\TestCase {
 		parent::setUp();
 	}
 	
-	private function getServerMock(IUserLDAP $backend) {
+	private function getServerMock(IUserLDAP $userBackend, IGroupLDAP $groupBackend) {
 		$server = $this->getMockBuilder('OC\Server')
-			 ->setMethods(['getUserManager', 'getBackends'])
+			 ->setMethods(['getUserManager', 'getBackends', 'getGroupManager'])
 			 ->setConstructorArgs(['', new \OC\Config(\OC::$configDir)])
 			 ->getMock();
 		$server->expects($this->at(1))
             ->method('getBackends')
-            ->willReturn([$backend]);
+            ->willReturn([$userBackend]);
+		$server->expects($this->any())
+			->method('getUserManager')
+			->willReturn($this->getUserManagerMock($userBackend));
+		$server->expects($this->any())
+			->method('getGroupManager')
+			->willReturn($this->getGroupManagerMock($groupBackend));
 		$server->expects($this->any())
             ->method($this->anything())
             ->willReturnSelf();
 			
 		return $server;
 	}
+
+	private function getUserManagerMock(IUserLDAP $userBackend) {
+		$userManager = $this->getMockBuilder('OC\User\Manager')
+			->setMethods(['getBackends'])
+			->setConstructorArgs([$this->createMock(IConfig::class)])
+			->getMock();
+		$userManager->expects($this->any())
+			->method('getBackends')
+			->willReturn([$userBackend]);
+		return $userManager;
+	}
 	
+	private function getGroupManagerMock(IGroupLDAP $groupBackend) {
+		$groupManager = $this->getMockBuilder('OC\Group\Manager')
+			->setMethods(['getBackends'])
+			->disableOriginalConstructor()
+			->getMock();
+		$groupManager->expects($this->any())
+			->method('getBackends')
+			->willReturn([$groupBackend]);
+		return $groupManager;
+	}
+
+	private function getDefaultGroupBackendMock() {
+		$groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP')
+			->disableOriginalConstructor()			
+			->getMock();
+		
+		return $groupBackend;
+	}
+
 	private function getLDAPProvider(IServerContainer $serverContainer) {
 		$factory = new \OCA\User_LDAP\LDAPProviderFactory($serverContainer);
 		return $factory->getLDAPProvider();
@@ -63,50 +104,100 @@ class LDAPProviderTest extends \Test\TestCase {
 	 * @expectedExceptionMessage User id not found in LDAP
 	 */
 	public function testGetUserDNUserIDNotFound() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['userExists'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->any())->method('userExists')->willReturn(false);
+		$userBackend->expects($this->any())->method('userExists')->willReturn(false);
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$ldapProvider->getUserDN('nonexisting_user');
 	}
 	
 	public function testGetUserDN() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['userExists', 'getLDAPAccess', 'username2dn'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->at(0))
+		$userBackend->expects($this->at(0))
             ->method('userExists')
             ->willReturn(true);
-		$backend->expects($this->at(2))
+		$userBackend->expects($this->at(2))
             ->method('username2dn')
             ->willReturn('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org');
-		$backend->expects($this->any())
+		$userBackend->expects($this->any())
             ->method($this->anything())
             ->willReturnSelf();
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$this->assertEquals('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org', 
 			$ldapProvider->getUserDN('existing_user'));
 	}
 
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage Group id not found in LDAP
+	 */
+	public function testGetGroupDNGroupIDNotFound() {
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP')
+			->setMethods(['groupExists'])
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend->expects($this->any())->method('groupExists')->willReturn(false);
+
+		$server = $this->getServerMock($userBackend, $groupBackend);
+
+		$ldapProvider = $this->getLDAPProvider($server);
+		$ldapProvider->getGroupDN('nonexisting_group');
+	}
+
+	public function testGetGroupDN() {
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+			->setMethods(['userExists', 'getLDAPAccess', 'username2dn'])
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP')
+			->setMethods(['groupExists', 'getLDAPAccess', 'groupname2dn'])
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend->expects($this->at(0))
+			->method('groupExists')
+			->willReturn(true);
+		$groupBackend->expects($this->at(2))
+			->method('groupname2dn')
+			->willReturn('cn=existing_group,ou=Are Sufficient To,ou=Test,dc=example,dc=org');
+		$groupBackend->expects($this->any())
+			->method($this->anything())
+			->willReturnSelf();
+
+		$server = $this->getServerMock($userBackend, $groupBackend);
+
+		$ldapProvider = $this->getLDAPProvider($server);
+		$this->assertEquals('cn=existing_group,ou=Are Sufficient To,ou=Test,dc=example,dc=org',
+			$ldapProvider->getGroupDN('existing_group'));
+	}	
+
 	public function testGetUserName() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['dn2UserName'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->any())
+		$userBackend->expects($this->any())
             ->method('dn2UserName')
             ->willReturn('existing_user');
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$this->assertEquals('existing_user', 
@@ -114,12 +205,12 @@ class LDAPProviderTest extends \Test\TestCase {
 	}
 	
 	public function testDNasBaseParameter() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods([])
 			 ->disableOriginalConstructor()
 			 ->getMock();
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 		
 		$helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig());
 			
@@ -130,12 +221,12 @@ class LDAPProviderTest extends \Test\TestCase {
 	}
 
 	public function testSanitizeDN() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods([])
 			 ->disableOriginalConstructor()
 			 ->getMock();
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 		
 		$helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig());
 			
@@ -150,69 +241,115 @@ class LDAPProviderTest extends \Test\TestCase {
 	 * @expectedExceptionMessage User id not found in LDAP
 	 */
 	public function testGetLDAPConnectionUserIDNotFound() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['userExists'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->any())->method('userExists')->willReturn(false);
+		$userBackend->expects($this->any())->method('userExists')->willReturn(false);
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$ldapProvider->getLDAPConnection('nonexisting_user');
 	}
 	
 	public function testGetLDAPConnection() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['userExists', 'getNewLDAPConnection'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->any())
+		$userBackend->expects($this->any())
             ->method('userExists')
             ->willReturn(true);
-		$backend->expects($this->any())
+		$userBackend->expects($this->any())
             ->method('getNewLDAPConnection')
             ->willReturn(true);
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$this->assertTrue($ldapProvider->getLDAPConnection('existing_user'));
 	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage Group id not found in LDAP
+	 */
+	public function testGetGroupLDAPConnectionGroupIDNotFound() {
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP')
+			->setMethods(['groupExists'])
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend->expects($this->any())->method('groupExists')->willReturn(false);
+
+		$server = $this->getServerMock($userBackend, $groupBackend);
+
+		$ldapProvider = $this->getLDAPProvider($server);
+		$ldapProvider->getGroupLDAPConnection('nonexisting_group');
+	}
+
+	public function testGetGroupLDAPConnection() {
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP')
+			->setMethods(['groupExists','getNewLDAPConnection'])
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend->expects($this->any())
+			->method('groupExists')
+			->willReturn(true);
+
+		$groupBackend->expects($this->any())
+			->method('getNewLDAPConnection')
+			->willReturn(true);
+
+		$server = $this->getServerMock($userBackend, $groupBackend);
+
+		$ldapProvider = $this->getLDAPProvider($server);
+		$this->assertTrue($ldapProvider->getGroupLDAPConnection('existing_group'));
+	}
 	
 	/**
 	 * @expectedException \Exception
 	 * @expectedExceptionMessage User id not found in LDAP
 	 */
 	public function testGetLDAPBaseUsersUserIDNotFound() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['userExists'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->any())->method('userExists')->willReturn(false);
+		$userBackend->expects($this->any())->method('userExists')->willReturn(false);
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$ldapProvider->getLDAPBaseUsers('nonexisting_user');
 	}
 	
 	public function testGetLDAPBaseUsers() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->at(0))
+		$userBackend->expects($this->at(0))
             ->method('userExists')
             ->willReturn(true);
-		$backend->expects($this->at(3))
+		$userBackend->expects($this->at(3))
             ->method('getConfiguration')
             ->willReturn(array('ldap_base_users'=>'ou=users,dc=example,dc=org'));
-		$backend->expects($this->any())
+		$userBackend->expects($this->any())
             ->method($this->anything())
             ->willReturnSelf();
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$this->assertEquals('ou=users,dc=example,dc=org', $ldapProvider->getLDAPBaseUsers('existing_user'));
@@ -223,34 +360,34 @@ class LDAPProviderTest extends \Test\TestCase {
 	 * @expectedExceptionMessage User id not found in LDAP
 	 */
 	public function testGetLDAPBaseGroupsUserIDNotFound() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['userExists'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->any())->method('userExists')->willReturn(false);
+		$userBackend->expects($this->any())->method('userExists')->willReturn(false);
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$ldapProvider->getLDAPBaseGroups('nonexisting_user');
 	}
 	
 	public function testGetLDAPBaseGroups() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->at(0))
+		$userBackend->expects($this->at(0))
             ->method('userExists')
             ->willReturn(true);
-		$backend->expects($this->at(3))
+		$userBackend->expects($this->at(3))
             ->method('getConfiguration')
             ->willReturn(array('ldap_base_groups'=>'ou=groups,dc=example,dc=org'));
-		$backend->expects($this->any())
+		$userBackend->expects($this->any())
             ->method($this->anything())
             ->willReturnSelf();
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$this->assertEquals('ou=groups,dc=example,dc=org', $ldapProvider->getLDAPBaseGroups('existing_user'));
@@ -261,34 +398,34 @@ class LDAPProviderTest extends \Test\TestCase {
 	 * @expectedExceptionMessage User id not found in LDAP
 	 */
 	public function testClearCacheUserIDNotFound() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['userExists'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->any())->method('userExists')->willReturn(false);
+		$userBackend->expects($this->any())->method('userExists')->willReturn(false);
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$ldapProvider->clearCache('nonexisting_user');
 	}
 	
 	public function testClearCache() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'clearCache'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->at(0))
+		$userBackend->expects($this->at(0))
             ->method('userExists')
             ->willReturn(true);
-		$backend->expects($this->at(3))
+		$userBackend->expects($this->at(3))
             ->method('clearCache')
             ->willReturn(true);
-		$backend->expects($this->any())
+		$userBackend->expects($this->any())
             ->method($this->anything())
             ->willReturnSelf();
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$ldapProvider->clearCache('existing_user');
@@ -296,27 +433,27 @@ class LDAPProviderTest extends \Test\TestCase {
 	}
 	
 	public function testDnExists() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods(['dn2UserName'])
 			 ->disableOriginalConstructor()
 			 ->getMock();
-		$backend->expects($this->any())
+		$userBackend->expects($this->any())
             ->method('dn2UserName')
             ->willReturn('existing_user');
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$this->assertTrue($ldapProvider->dnExists('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'));
 	}
 	
 	public function testFlagRecord() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods([])
 			 ->disableOriginalConstructor()
 			 ->getMock();
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$ldapProvider->flagRecord('existing_user');
@@ -324,15 +461,140 @@ class LDAPProviderTest extends \Test\TestCase {
 	}
 	
 	public function testUnflagRecord() {
-		$backend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
 			 ->setMethods([])
 			 ->disableOriginalConstructor()
 			 ->getMock();
 		
-		$server = $this->getServerMock($backend);
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
 			
 		$ldapProvider = $this->getLDAPProvider($server);
 		$ldapProvider->unflagRecord('existing_user');
 		$this->assertTrue(TRUE);
 	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage User id not found in LDAP
+	 */
+	public function testGetLDAPDisplayNameFieldUserIDNotFound() {
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+			->setMethods(['userExists'])
+			->disableOriginalConstructor()
+			->getMock();
+		$userBackend->expects($this->any())->method('userExists')->willReturn(false);
+
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
+
+		$ldapProvider = $this->getLDAPProvider($server);
+		$ldapProvider->getLDAPDisplayNameField('nonexisting_user');
+	}
+
+	public function testGetLDAPDisplayNameField() {
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+			->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration'])
+			->disableOriginalConstructor()
+			->getMock();
+		$userBackend->expects($this->at(0))
+			->method('userExists')
+			->willReturn(true);
+		$userBackend->expects($this->at(3))
+			->method('getConfiguration')
+			->willReturn(array('ldap_display_name'=>'displayName'));
+		$userBackend->expects($this->any())
+			->method($this->anything())
+			->willReturnSelf();
+
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
+
+		$ldapProvider = $this->getLDAPProvider($server);
+		$this->assertEquals('displayName', $ldapProvider->getLDAPDisplayNameField('existing_user'));
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage User id not found in LDAP
+	 */
+	public function testGetLDAPEmailFieldUserIDNotFound() {
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+			->setMethods(['userExists'])
+			->disableOriginalConstructor()
+			->getMock();
+		$userBackend->expects($this->any())->method('userExists')->willReturn(false);
+
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
+
+		$ldapProvider = $this->getLDAPProvider($server);
+		$ldapProvider->getLDAPEmailField('nonexisting_user');
+	}
+
+	public function testGetLDAPEmailField() {
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+			->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration'])
+			->disableOriginalConstructor()
+			->getMock();
+		$userBackend->expects($this->at(0))
+			->method('userExists')
+			->willReturn(true);
+		$userBackend->expects($this->at(3))
+			->method('getConfiguration')
+			->willReturn(array('ldap_email_attr'=>'mail'));
+		$userBackend->expects($this->any())
+			->method($this->anything())
+			->willReturnSelf();
+
+		$server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock());
+
+		$ldapProvider = $this->getLDAPProvider($server);
+		$this->assertEquals('mail', $ldapProvider->getLDAPEmailField('existing_user'));
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage Group id not found in LDAP
+	 */
+	public function testGetLDAPGroupMemberAssocUserIDNotFound() {
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP')
+			->setMethods(['groupExists'])
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend->expects($this->any())->method('groupExists')->willReturn(false);
+
+		$server = $this->getServerMock($userBackend, $groupBackend);
+
+		$ldapProvider = $this->getLDAPProvider($server);
+		$ldapProvider->getLDAPGroupMemberAssoc('nonexisting_group');
+	}
+
+	public function testgetLDAPGroupMemberAssoc() {
+		$userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP')
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP')
+			->setMethods(['groupExists', 'getLDAPAccess', 'getConnection', 'getConfiguration'])
+			->disableOriginalConstructor()
+			->getMock();
+
+		$groupBackend->expects($this->at(0))
+			->method('groupExists')
+			->willReturn(true);
+		$groupBackend->expects($this->any())
+			->method('getConfiguration')
+			->willReturn(array('ldap_group_member_assoc_attribute'=>'assoc_type'));
+		$groupBackend->expects($this->any())
+			->method($this->anything())
+			->willReturnSelf();
+
+		$server = $this->getServerMock($userBackend, $groupBackend);
+
+		$ldapProvider = $this->getLDAPProvider($server);
+		$this->assertEquals('assoc_type', $ldapProvider->getLDAPGroupMemberAssoc('existing_group'));
+	}	
+
 }
diff --git a/apps/user_ldap/tests/LDAPUserPluginDummy.php b/apps/user_ldap/tests/LDAPUserPluginDummy.php
new file mode 100644
index 00000000000..8115141b5e2
--- /dev/null
+++ b/apps/user_ldap/tests/LDAPUserPluginDummy.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br)
+ *
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ * @author Daniel Tygel <dtygel@eita.org.br>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP\Tests;
+
+
+use OCA\User_LDAP\ILDAPUserPlugin;
+
+class LDAPUserPluginDummy implements ILDAPUserPlugin {
+
+	public function respondToActions() {
+		return null;
+	}
+
+	public function createUser($username, $password) {
+		return null;
+	}
+
+	public function setPassword($uid, $password) {
+		return null;
+	}
+
+	public function getHome($uid) {
+		return null;
+	}
+
+	public function getDisplayName($uid) {
+		return null;
+	}
+
+	public function setDisplayName($uid, $displayName) {
+		return null;
+	}
+
+	public function canChangeAvatar($uid) {
+		return null;
+	}
+
+	public function countUsers() {
+		return null;
+	}
+
+}
diff --git a/apps/user_ldap/tests/UserLDAPPluginTest.php b/apps/user_ldap/tests/UserLDAPPluginTest.php
new file mode 100644
index 00000000000..2fe9d6f7352
--- /dev/null
+++ b/apps/user_ldap/tests/UserLDAPPluginTest.php
@@ -0,0 +1,310 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br)
+ *
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\User_LDAP\Tests;
+
+
+use OC\User\Backend;
+use OCA\User_LDAP\UserPluginManager;
+
+class UserLDAPPluginTest extends \Test\TestCase {
+
+	/**
+	 * @return UserPluginManager
+	 */
+	private function getUserPluginManager() {
+		return new UserPluginManager();
+	}
+
+	public function testImplementsActions() {
+		$pluginManager = $this->getUserPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy')
+			->setMethods(['respondToActions'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::CREATE_USER);
+
+		$plugin2 = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy')
+			->setMethods(['respondToActions'])
+			->getMock();
+
+		$plugin2->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::PROVIDE_AVATAR);
+
+		$pluginManager->register($plugin);
+		$pluginManager->register($plugin2);
+
+		$this->assertEquals($pluginManager->getImplementedActions(), Backend::CREATE_USER | Backend::PROVIDE_AVATAR);
+		$this->assertTrue($pluginManager->implementsActions(Backend::CREATE_USER));
+		$this->assertTrue($pluginManager->implementsActions(Backend::PROVIDE_AVATAR));
+	}
+
+	public function testCreateUser() {
+		$pluginManager = $this->getUserPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy')
+			->setMethods(['respondToActions', 'createUser'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::CREATE_USER);
+
+		$plugin->expects($this->once())
+			->method('createUser')
+			->with(
+				$this->equalTo('user'),
+				$this->equalTo('password')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->createUser('user', 'password');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements createUser in this LDAP Backend.
+	 */
+	public function testCreateUserNotRegistered() {
+		$pluginManager = $this->getUserPluginManager();
+		$pluginManager->createUser('foo','bar');
+	}
+
+	public function testSetPassword() {
+		$pluginManager = $this->getUserPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy')
+			->setMethods(['respondToActions', 'setPassword'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::SET_PASSWORD);
+
+		$plugin->expects($this->once())
+			->method('setPassword')
+			->with(
+				$this->equalTo('user'),
+				$this->equalTo('password')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->setPassword('user', 'password');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements setPassword in this LDAP Backend.
+	 */
+	public function testSetPasswordNotRegistered() {
+		$pluginManager = $this->getUserPluginManager();
+		$pluginManager->setPassword('foo','bar');
+	}
+
+	public function testGetHome() {
+		$pluginManager = $this->getUserPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy')
+			->setMethods(['respondToActions', 'getHome'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::GET_HOME);
+
+		$plugin->expects($this->once())
+			->method('getHome')
+			->with(
+				$this->equalTo('uid')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->getHome('uid');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements getHome in this LDAP Backend.
+	 */
+	public function testGetHomeNotRegistered() {
+		$pluginManager = $this->getUserPluginManager();
+		$pluginManager->getHome('foo');
+	}	
+
+	public function testGetDisplayName() {
+		$pluginManager = $this->getUserPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy')
+			->setMethods(['respondToActions', 'getDisplayName'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::GET_DISPLAYNAME);
+
+		$plugin->expects($this->once())
+			->method('getDisplayName')
+			->with(
+				$this->equalTo('uid')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->getDisplayName('uid');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements getDisplayName in this LDAP Backend.
+	 */
+	public function testGetDisplayNameNotRegistered() {
+		$pluginManager = $this->getUserPluginManager();
+		$pluginManager->getDisplayName('foo');
+	}
+
+	public function testSetDisplayName() {
+		$pluginManager = $this->getUserPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy')
+			->setMethods(['respondToActions', 'setDisplayName'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::SET_DISPLAYNAME);
+
+		$plugin->expects($this->once())
+			->method('setDisplayName')
+			->with(
+				$this->equalTo('user'),
+				$this->equalTo('password')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->setDisplayName('user', 'password');		
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements setDisplayName in this LDAP Backend.
+	 */
+	public function testSetDisplayNameNotRegistered() {
+		$pluginManager = $this->getUserPluginManager();
+		$pluginManager->setDisplayName('foo', 'bar');
+	}	
+
+	public function testCanChangeAvatar() {
+		$pluginManager = $this->getUserPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy')
+			->setMethods(['respondToActions', 'canChangeAvatar'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::PROVIDE_AVATAR);
+
+		$plugin->expects($this->once())
+			->method('canChangeAvatar')
+			->with(
+				$this->equalTo('uid')
+			);
+
+		$pluginManager->register($plugin);
+		$pluginManager->canChangeAvatar('uid');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements canChangeAvatar in this LDAP Backend.
+	 */
+	public function testCanChangeAvatarNotRegistered() {
+		$pluginManager = $this->getUserPluginManager();
+		$pluginManager->canChangeAvatar('foo');
+	}
+
+	public function testCountUsers() {
+		$pluginManager = $this->getUserPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy')
+			->setMethods(['respondToActions', 'countUsers'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(Backend::COUNT_USERS);
+
+		$plugin->expects($this->once())
+			->method('countUsers');
+
+		$pluginManager->register($plugin);
+		$pluginManager->countUsers();
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements countUsers in this LDAP Backend.
+	 */
+	public function testCountUsersNotRegistered() {
+		$pluginManager = $this->getUserPluginManager();
+		$pluginManager->countUsers();
+	}	
+
+	public function testDeleteUser() {
+		$pluginManager = $this->getUserPluginManager();
+
+		$plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy')
+			->setMethods(['respondToActions', 'canDeleteUser','deleteUser'])
+			->getMock();
+
+		$plugin->expects($this->any())
+			->method('respondToActions')
+			->willReturn(0);
+
+		$plugin->expects($this->any())
+			->method('canDeleteUser')
+			->willReturn(true);
+
+		$plugin->expects($this->once())
+			->method('deleteUser')
+			->with(
+				$this->equalTo('uid')
+			);
+
+		$this->assertFalse($pluginManager->canDeleteUser());
+		$pluginManager->register($plugin);
+		$this->assertTrue($pluginManager->canDeleteUser());
+		$pluginManager->deleteUser('uid');
+	}
+
+	/**
+	 * @expectedException \Exception
+	 * @expectedExceptionMessage No plugin implements deleteUser in this LDAP Backend.
+	 */
+	public function testDeleteUserNotRegistered() {
+		$pluginManager = $this->getUserPluginManager();
+		$pluginManager->deleteUser('foo');
+	}
+}
diff --git a/apps/user_ldap/tests/User_LDAPTest.php b/apps/user_ldap/tests/User_LDAPTest.php
index 44bc55b4148..b6582c816ef 100644
--- a/apps/user_ldap/tests/User_LDAPTest.php
+++ b/apps/user_ldap/tests/User_LDAPTest.php
@@ -10,6 +10,7 @@
  * @author Robin McCorkell <robin@mccorkell.me.uk>
  * @author Thomas Müller <thomas.mueller@tmit.eu>
  * @author Roger Szabo <roger.szabo@web.de>
+ * @author Vinicius Brand <vinicius@eita.org.br>
  *
  * @license AGPL-3.0
  *
@@ -29,6 +30,7 @@
 
 namespace OCA\User_LDAP\Tests;
 
+use OC\User\Backend;
 use OC\User\Session;
 use OCA\User_LDAP\Access;
 use OCA\User_LDAP\Connection;
@@ -119,6 +121,10 @@ class User_LDAPTest extends TestCase {
 		return $access;
 	}
 
+	private function getDefaultPluginManagerMock() {
+		return $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')->getMock();
+	}
+
 	private function prepareMockForUserExists(&$access) {
 		$access->expects($this->any())
 			   ->method('username2dn')
@@ -207,7 +213,8 @@ class User_LDAPTest extends TestCase {
 		$access = $this->getAccessMock();
 
 		$this->prepareAccessForCheckPassword($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = $backend->checkPassword('roland', 'dt19');
@@ -218,7 +225,7 @@ class User_LDAPTest extends TestCase {
 		$access = $this->getAccessMock();
 
 		$this->prepareAccessForCheckPassword($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = $backend->checkPassword('roland', 'wrong');
@@ -229,7 +236,7 @@ class User_LDAPTest extends TestCase {
 		$access = $this->getAccessMock();
 
 		$this->prepareAccessForCheckPassword($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = $backend->checkPassword('mallory', 'evil');
@@ -244,7 +251,7 @@ class User_LDAPTest extends TestCase {
 			->method('username2dn')
 			->will($this->returnValue(false));
 
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = $backend->checkPassword('roland', 'dt19');
@@ -254,7 +261,7 @@ class User_LDAPTest extends TestCase {
 	public function testCheckPasswordPublicAPI() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForCheckPassword($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = \OCP\User::checkPassword('roland', 'dt19');
@@ -264,7 +271,7 @@ class User_LDAPTest extends TestCase {
 	public function testCheckPasswordPublicAPIWrongPassword() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForCheckPassword($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = \OCP\User::checkPassword('roland', 'wrong');
@@ -274,7 +281,7 @@ class User_LDAPTest extends TestCase {
 	public function testCheckPasswordPublicAPIWrongUser() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForCheckPassword($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = \OCP\User::checkPassword('mallory', 'evil');
@@ -283,7 +290,7 @@ class User_LDAPTest extends TestCase {
 
 	public function testDeleteUserCancel() {
 		$access = $this->getAccessMock();
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$result = $backend->deleteUser('notme');
 		$this->assertFalse($result);
 	}
@@ -313,7 +320,7 @@ class User_LDAPTest extends TestCase {
 			->method('getOCName')
 			->willReturn($uid);
 
-		$backend = new UserLDAP($access, $this->configMock, $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->configMock, $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 
 		$user = $this->createMock(IUser::class);
 		$user->expects($this->once())
@@ -326,6 +333,36 @@ class User_LDAPTest extends TestCase {
 		$this->assertSame($backend->getHome($uid), $home);
 	}
 
+	public function testDeleteUserWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')
+			->setMethods(['canDeleteUser','deleteUser'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('canDeleteUser')
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('deleteUser')
+			->with('uid')
+			->willReturn('result');
+
+		$access = $this->createMock(Access::class);
+		$config = $this->createMock(IConfig::class);
+		$noti = $this->createMock(INotificationManager::class);
+		$session = $this->createMock(Session::class);
+
+		$ldap = new User_LDAP(
+			$access,
+			$config,
+			$noti,
+			$session,
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->deleteUser('uid'),'result');
+	}
+
 	/**
 	 * Prepares the Access mock for getUsers tests
 	 * @param Access $access mock
@@ -381,7 +418,7 @@ class User_LDAPTest extends TestCase {
 	public function testGetUsersNoParam() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForGetUsers($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 
 		$result = $backend->getUsers();
 		$this->assertEquals(3, count($result));
@@ -390,7 +427,7 @@ class User_LDAPTest extends TestCase {
 	public function testGetUsersLimitOffset() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForGetUsers($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 
 		$result = $backend->getUsers('', 1, 2);
 		$this->assertEquals(1, count($result));
@@ -399,7 +436,7 @@ class User_LDAPTest extends TestCase {
 	public function testGetUsersLimitOffset2() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForGetUsers($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 
 		$result = $backend->getUsers('', 2, 1);
 		$this->assertEquals(2, count($result));
@@ -408,7 +445,7 @@ class User_LDAPTest extends TestCase {
 	public function testGetUsersSearchWithResult() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForGetUsers($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 
 		$result = $backend->getUsers('yo');
 		$this->assertEquals(2, count($result));
@@ -417,7 +454,7 @@ class User_LDAPTest extends TestCase {
 	public function testGetUsersSearchEmptyResult() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForGetUsers($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 
 		$result = $backend->getUsers('nix');
 		$this->assertEquals(0, count($result));
@@ -426,7 +463,7 @@ class User_LDAPTest extends TestCase {
 	public function testGetUsersViaAPINoParam() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForGetUsers($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = \OCP\User::getUsers();
@@ -436,7 +473,7 @@ class User_LDAPTest extends TestCase {
 	public function testGetUsersViaAPILimitOffset() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForGetUsers($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = \OCP\User::getUsers('', 1, 2);
@@ -446,7 +483,7 @@ class User_LDAPTest extends TestCase {
 	public function testGetUsersViaAPILimitOffset2() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForGetUsers($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = \OCP\User::getUsers('', 2, 1);
@@ -456,7 +493,7 @@ class User_LDAPTest extends TestCase {
 	public function testGetUsersViaAPISearchWithResult() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForGetUsers($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = \OCP\User::getUsers('yo');
@@ -466,7 +503,7 @@ class User_LDAPTest extends TestCase {
 	public function testGetUsersViaAPISearchEmptyResult() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForGetUsers($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$result = \OCP\User::getUsers('nix');
@@ -475,7 +512,7 @@ class User_LDAPTest extends TestCase {
 
 	public function testUserExists() {
 		$access = $this->getAccessMock();
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 
 		$access->expects($this->any())
@@ -497,7 +534,7 @@ class User_LDAPTest extends TestCase {
 	 */
 	public function testUserExistsForDeleted() {
 		$access = $this->getAccessMock();
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 
 		$access->expects($this->any())
@@ -515,7 +552,7 @@ class User_LDAPTest extends TestCase {
 
 	public function testUserExistsForNeverExisting() {
 		$access = $this->getAccessMock();
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 
 		$access->expects($this->any())
@@ -534,7 +571,7 @@ class User_LDAPTest extends TestCase {
 
 	public function testUserExistsPublicAPI() {
 		$access = $this->getAccessMock();
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 		\OC_User::useBackend($backend);
 
@@ -557,7 +594,7 @@ class User_LDAPTest extends TestCase {
 	 */
 	public function testUserExistsPublicAPIForDeleted() {
 		$access = $this->getAccessMock();
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 		\OC_User::useBackend($backend);
 
@@ -576,7 +613,7 @@ class User_LDAPTest extends TestCase {
 
 	public function testUserExistsPublicAPIForNeverExisting() {
 		$access = $this->getAccessMock();
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 		\OC_User::useBackend($backend);
 
@@ -596,7 +633,7 @@ class User_LDAPTest extends TestCase {
 
 	public function testDeleteUserExisting() {
 		$access = $this->getAccessMock();
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 
 		//we do not support deleting existing users at all
 		$result = $backend->deleteUser('gunslinger');
@@ -607,7 +644,7 @@ class User_LDAPTest extends TestCase {
 		$access = $this->getAccessMock();
 		$config = $this->createMock(IConfig::class);
 		$noti = $this->createMock(INotificationManager::class);
-		$backend = new UserLDAP($access, $config, $noti, $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $config, $noti, $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 
 		$access->connection->expects($this->any())
@@ -643,7 +680,7 @@ class User_LDAPTest extends TestCase {
 		$access = $this->getAccessMock();
 		$config = $this->createMock(IConfig::class);
 		$noti = $this->createMock(INotificationManager::class);
-		$backend = new UserLDAP($access, $config, $noti, $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $config, $noti, $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 
 		$dataDir = \OC::$server->getConfig()->getSystemValue(
@@ -686,7 +723,7 @@ class User_LDAPTest extends TestCase {
 	 */
 	public function testGetHomeNoPath() {
 		$access = $this->getAccessMock();
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 
 		$access->connection->expects($this->any())
@@ -719,7 +756,7 @@ class User_LDAPTest extends TestCase {
 		$uid = 'newyorker';
 
 		$access = $this->getAccessMock();
-		$backend = new UserLDAP($access, $this->configMock, $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->configMock, $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 
 		$access->connection->expects($this->any())
@@ -751,6 +788,43 @@ class User_LDAPTest extends TestCase {
 		$backend->getHome($uid);
 	}
 
+	public function testGetHomeWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')
+			->setMethods(['implementsActions','getHome'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::GET_HOME)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('getHome')
+			->with('uid')
+			->willReturn('result');
+
+		$access = $this->getAccessMock();
+		$config = $this->createMock(IConfig::class);
+		$noti = $this->createMock(INotificationManager::class);
+		$session = $this->createMock(Session::class);
+
+		$access->connection->expects($this->any())
+			->method('getFromCache')
+			->will($this->returnCallback(function($uid) {
+				return true;
+			}));
+
+		$ldap = new User_LDAP(
+			$access,
+			$config,
+			$noti,
+			$session,
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->getHome('uid'),'result');
+	}
+
 	private function prepareAccessForGetDisplayName(&$access) {
 		$access->connection->expects($this->any())
 			   ->method('__get')
@@ -792,7 +866,7 @@ class User_LDAPTest extends TestCase {
 	public function testGetDisplayName() {
 		$access = $this->getAccessMock();
 		$this->prepareAccessForGetDisplayName($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 
 		$access->connection->expects($this->any())
@@ -833,7 +907,7 @@ class User_LDAPTest extends TestCase {
 				}
 			}));
 		$this->prepareAccessForGetDisplayName($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$this->prepareMockForUserExists($access);
 
 		$access->connection->expects($this->any())
@@ -853,6 +927,37 @@ class User_LDAPTest extends TestCase {
 		$this->assertEquals('newyorker', $result);
 	}
 
+	public function testGetDisplayNameWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')
+			->setMethods(['implementsActions','getDisplayName'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::GET_DISPLAYNAME)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('getDisplayName')
+			->with('uid')
+			->willReturn('result');
+
+		$access = $this->createMock(Access::class);
+		$config = $this->createMock(IConfig::class);
+		$noti = $this->createMock(INotificationManager::class);
+		$session = $this->createMock(Session::class);
+
+		$ldap = new User_LDAP(
+			$access,
+			$config,
+			$noti,
+			$session,
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->getDisplayName('uid'),'result');
+	}
+
 	//no test for getDisplayNames, because it just invokes getUsers and
 	//getDisplayName
 
@@ -863,7 +968,7 @@ class User_LDAPTest extends TestCase {
 			   ->method('countUsers')
 			   ->will($this->returnValue(5));
 
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 
 		$result = $backend->countUsers();
 		$this->assertEquals(5, $result);
@@ -876,12 +981,42 @@ class User_LDAPTest extends TestCase {
 			   ->method('countUsers')
 			   ->will($this->returnValue(false));
 
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 
 		$result = $backend->countUsers();
 		$this->assertFalse($result);
 	}
 
+	public function testCountUsersWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')
+			->setMethods(['implementsActions','countUsers'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::COUNT_USERS)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('countUsers')
+			->willReturn(42);
+
+		$access = $this->createMock(Access::class);
+		$config = $this->createMock(IConfig::class);
+		$noti = $this->createMock(INotificationManager::class);
+		$session = $this->createMock(Session::class);
+
+		$ldap = new User_LDAP(
+			$access,
+			$config,
+			$noti,
+			$session,
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->countUsers(),42);
+	}	
+
 	public function testLoginName2UserNameSuccess() {
 		$loginName = 'Alice';
 		$username  = 'alice';
@@ -909,7 +1044,7 @@ class User_LDAPTest extends TestCase {
 			->method('writeToCache')
 			->with($this->equalTo('loginName2UserName-'.$loginName), $this->equalTo($username));
 
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$name = $backend->loginName2UserName($loginName);
 		$this->assertSame($username, $name);
 
@@ -938,7 +1073,7 @@ class User_LDAPTest extends TestCase {
 			->method('writeToCache')
 			->with($this->equalTo('loginName2UserName-'.$loginName), false);
 
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$name = $backend->loginName2UserName($loginName);
 		$this->assertSame(false, $name);
 
@@ -985,7 +1120,7 @@ class User_LDAPTest extends TestCase {
 			->method('getUserValue')
 			->willReturn(1);
 
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		$name = $backend->loginName2UserName($loginName);
 		$this->assertSame(false, $name);
 
@@ -1010,7 +1145,7 @@ class User_LDAPTest extends TestCase {
 					}
 					return null;
 			   }));
-			   
+
 		$access->connection->expects($this->any())
 			   ->method('getFromCache')
 			   ->will($this->returnCallback(function($uid) {
@@ -1066,7 +1201,7 @@ class User_LDAPTest extends TestCase {
 		$access = $this->getAccessMock();
 
 		$this->prepareAccessForSetPassword($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$this->assertTrue(\OC_User::setPassword('roland', 'dt'));
@@ -1076,7 +1211,7 @@ class User_LDAPTest extends TestCase {
 		$access = $this->getAccessMock();
 
 		$this->prepareAccessForSetPassword($access);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$this->assertTrue(\OC_User::setPassword('roland', 'dt12234$'));
@@ -1086,7 +1221,7 @@ class User_LDAPTest extends TestCase {
 		$access = $this->getAccessMock();
 
 		$this->prepareAccessForSetPassword($access, false);
-		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class));
+		$backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock());
 		\OC_User::useBackend($backend);
 
 		$this->assertFalse(\OC_User::setPassword('roland', 'dt12234$'));
@@ -1111,7 +1246,8 @@ class User_LDAPTest extends TestCase {
 			$access,
 			$config,
 			$noti,
-			$userSession
+			$userSession,
+			$this->getDefaultPluginManagerMock()
 		);
 		$ldap->setPassword('NotExistingUser', 'Password');
 	}
@@ -1136,8 +1272,185 @@ class User_LDAPTest extends TestCase {
 			$access,
 			$config,
 			$noti,
-			$userSession
+			$userSession,
+			$this->getDefaultPluginManagerMock()
 		);
 		$this->assertFalse($ldap->setPassword('NotExistingUser', 'Password'));
 	}
+
+	public function testSetPasswordWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')
+			->setMethods(['implementsActions','setPassword'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::SET_PASSWORD)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('setPassword')
+			->with('uid','password')
+			->willReturn('result');
+
+		$access = $this->createMock(Access::class);
+		$config = $this->createMock(IConfig::class);
+		$noti = $this->createMock(INotificationManager::class);
+		$session = $this->createMock(Session::class);
+
+		$ldap = new User_LDAP(
+			$access,
+			$config,
+			$noti,
+			$session,
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->setPassword('uid', 'password'),'result');
+	}	
+
+	public function testCanChangeAvatarWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')
+			->setMethods(['implementsActions','canChangeAvatar'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::PROVIDE_AVATAR)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('canChangeAvatar')
+			->with('uid')
+			->willReturn('result');
+
+		$access = $this->createMock(Access::class);
+		$config = $this->createMock(IConfig::class);
+		$noti = $this->createMock(INotificationManager::class);
+		$session = $this->createMock(Session::class);
+
+		$ldap = new User_LDAP(
+			$access,
+			$config,
+			$noti,
+			$session,
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->canChangeAvatar('uid'),'result');
+	}
+
+	public function testSetDisplayNameWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')
+			->setMethods(['implementsActions','setDisplayName'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::SET_DISPLAYNAME)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('setDisplayName')
+			->with('uid','displayName')
+			->willReturn('result');
+
+		$access = $this->createMock(Access::class);
+		$config = $this->createMock(IConfig::class);
+		$noti = $this->createMock(INotificationManager::class);
+		$session = $this->createMock(Session::class);
+
+		$ldap = new User_LDAP(
+			$access,
+			$config,
+			$noti,
+			$session,
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->setDisplayName('uid', 'displayName'),'result');
+	}
+
+	public function testSetDisplayNameFailing() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')
+			->setMethods(['implementsActions','setDisplayName'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::SET_DISPLAYNAME)
+			->willReturn(false);
+
+		$access = $this->createMock(Access::class);
+		$config = $this->createMock(IConfig::class);
+		$noti = $this->createMock(INotificationManager::class);
+		$session = $this->createMock(Session::class);
+
+		$ldap = new User_LDAP(
+			$access,
+			$config,
+			$noti,
+			$session,
+			$pluginManager
+		);
+
+		$this->assertFalse($ldap->setDisplayName('uid', 'displayName'));
+	}
+
+	public function testCreateUserWithPlugin() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')
+			->setMethods(['implementsActions','createUser'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::CREATE_USER)
+			->willReturn(true);
+
+		$pluginManager->expects($this->once())
+			->method('createUser')
+			->with('uid','password')
+			->willReturn('result');
+
+		$access = $this->createMock(Access::class);
+		$config = $this->createMock(IConfig::class);
+		$noti = $this->createMock(INotificationManager::class);
+		$session = $this->createMock(Session::class);
+
+		$ldap = new User_LDAP(
+			$access,
+			$config,
+			$noti,
+			$session,
+			$pluginManager
+		);
+
+		$this->assertEquals($ldap->createUser('uid', 'password'),'result');
+	}
+
+	public function testCreateUserFailing() {
+		$pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')
+			->setMethods(['implementsActions', 'createUser'])
+			->getMock();
+
+		$pluginManager->expects($this->once())
+			->method('implementsActions')
+			->with(Backend::CREATE_USER)
+			->willReturn(false);
+
+		$access = $this->createMock(Access::class);
+		$config = $this->createMock(IConfig::class);
+		$noti = $this->createMock(INotificationManager::class);
+		$session = $this->createMock(Session::class);
+
+		$ldap = new User_LDAP(
+			$access,
+			$config,
+			$noti,
+			$session,
+			$pluginManager
+		);
+
+		$this->assertFalse($ldap->createUser('uid', 'password'));
+	}
 }
diff --git a/apps/user_ldap/tests/User_ProxyTest.php b/apps/user_ldap/tests/User_ProxyTest.php
index 68b1e4428ca..f6aaa01cb8d 100644
--- a/apps/user_ldap/tests/User_ProxyTest.php
+++ b/apps/user_ldap/tests/User_ProxyTest.php
@@ -2,6 +2,9 @@
 /**
  * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
  *
+ * @author Lukas Reschke <lukas@statuscode.ch>
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ *
  * @license GNU AGPL version 3 or any later version
  *
  * This program is free software: you can redistribute it and/or modify
@@ -21,8 +24,10 @@
 
 namespace OCA\User_LDAP\Tests;
 
+use OCA\User_LDAP\ILDAPUserPlugin;
 use OCA\User_LDAP\ILDAPWrapper;
 use OCA\User_LDAP\User_Proxy;
+use OCA\User_LDAP\UserPluginManager;
 use OCP\IConfig;
 use OCP\IUserSession;
 use OCP\Notification\IManager as INotificationManager;
@@ -39,6 +44,8 @@ class User_ProxyTest extends TestCase  {
 	private $userSession;
 	/** @var User_Proxy|\PHPUnit_Framework_MockObject_MockObject */
 	private $proxy;
+	/** @var UserPluginManager|\PHPUnit_Framework_MockObject_MockObject */
+	private $userPluginManager;
 
 	public function setUp() {
 		parent::setUp();
@@ -47,6 +54,7 @@ class User_ProxyTest extends TestCase  {
 		$this->config = $this->createMock(IConfig::class);
 		$this->notificationManager = $this->createMock(INotificationManager::class);
 		$this->userSession = $this->createMock(IUserSession::class);
+		$this->userPluginManager = $this->createMock(UserPluginManager::class);
 		$this->proxy = $this->getMockBuilder(User_Proxy::class)
 			->setConstructorArgs([
 				[],
@@ -54,6 +62,7 @@ class User_ProxyTest extends TestCase  {
 				$this->config,
 				$this->notificationManager,
 				$this->userSession,
+				$this->userPluginManager
 			])
 			->setMethods(['handleRequest'])
 			->getMock();
@@ -68,4 +77,23 @@ class User_ProxyTest extends TestCase  {
 
 		$this->assertTrue($this->proxy->setPassword('MyUid', 'MyPassword'));
 	}
+
+	public function testSetDisplayName() {
+		$this->proxy
+			->expects($this->once())
+			->method('handleRequest')
+			->with('MyUid', 'setDisplayName', ['MyUid', 'MyPassword'])
+			->willReturn(true);
+
+		$this->assertTrue($this->proxy->setDisplayName('MyUid', 'MyPassword'));	}
+
+	public function testCreateUser() {
+		$this->proxy
+			->expects($this->once())
+			->method('handleRequest')
+			->with('MyUid', 'createUser', ['MyUid', 'MyPassword'])
+			->willReturn(true);
+
+		$this->assertTrue($this->proxy->createUser('MyUid', 'MyPassword'));
+	}
 }
diff --git a/lib/private/Group/Manager.php b/lib/private/Group/Manager.php
index 15d83380acf..20d19f106b4 100644
--- a/lib/private/Group/Manager.php
+++ b/lib/private/Group/Manager.php
@@ -74,7 +74,7 @@ class Manager extends PublicEmitter implements IGroupManager {
 	private $cachedGroups = array();
 
 	/**
-	 * @var \OC\Group\Group[][]
+	 * @var \OC\Group\Group[]
 	 */
 	private $cachedUserGroups = array();
 
@@ -144,7 +144,16 @@ class Manager extends PublicEmitter implements IGroupManager {
 		$this->backends = array();
 		$this->clearCaches();
 	}
-	
+
+	/**
+	 * Get the active backends
+	 * @return \OCP\GroupInterface[]
+	 */
+	public function getBackends() {
+		return $this->backends;
+	}
+
+
 	protected function clearCaches() {
 		$this->cachedGroups = array();
 		$this->cachedUserGroups = array();
diff --git a/lib/public/IGroupManager.php b/lib/public/IGroupManager.php
index be322b64325..778a0ef169c 100644
--- a/lib/public/IGroupManager.php
+++ b/lib/public/IGroupManager.php
@@ -65,6 +65,13 @@ interface IGroupManager {
 	 */
 	public function clearBackends();
 
+	/**
+	 * Get the active backends
+	 * @return \OCP\GroupInterface[]
+	 * @since 13.0.0
+	 */
+	public function getBackends();
+
 	/**
 	 * @param string $gid
 	 * @return \OCP\IGroup
diff --git a/lib/public/LDAP/ILDAPProvider.php b/lib/public/LDAP/ILDAPProvider.php
index 3c07dfcbe8e..03ac54d01e3 100644
--- a/lib/public/LDAP/ILDAPProvider.php
+++ b/lib/public/LDAP/ILDAPProvider.php
@@ -3,6 +3,10 @@
  *
  * @copyright Copyright (c) 2016, Roger Szabo (roger.szabo@web.de)
  *
+ * @author Roger Szabo <roger.szabo@web.de>
+ * @author Vinicius Brand <vinicius@eita.org.br>
+ * @author Daniel Tygel <dtygel@eita.org.br>
+ *
  * @license GNU AGPL version 3 or any later version
  *
  * This program is free software: you can redistribute it and/or modify
@@ -36,7 +40,15 @@ interface ILDAPProvider {
 	 * @since 11.0.0
 	 */
 	public function getUserDN($uid);
-	
+
+	/**
+	 * Translate a group id to LDAP DN.
+	 * @param string $gid group id
+	 * @return string
+	 * @since 13.0.0
+	 */
+	public function getGroupDN($gid);
+
 	/**
 	 * Translate a LDAP DN to an internal user name.
 	 * @param string $dn LDAP DN
@@ -69,6 +81,14 @@ interface ILDAPProvider {
 	 * @since 11.0.0
 	 */
 	public function getLDAPConnection($uid);
+
+	/**
+	 * Return a new LDAP connection resource for the specified group.
+	 * @param string $gid group id
+	 * @return resource of the LDAP connection
+	 * @since 13.0.0
+	 */
+	public function getGroupLDAPConnection($gid);
 	
 	/**
 	 * Get the LDAP base for users.
@@ -102,4 +122,32 @@ interface ILDAPProvider {
 	 * @since 11.0.0
 	 */
 	public function clearCache($uid);
+
+	/**
+	 * Get the LDAP attribute name for the user's display name
+	 * @param string $uid user id
+	 * @return string the display name field
+	 * @throws \Exception if user id was not found in LDAP
+	 * @since 12.0.0
+	 */
+	public function getLDAPDisplayNameField($uid);
+
+	/**
+	 * Get the LDAP attribute name for the email
+	 * @param string $uid user id
+	 * @return string the email field
+	 * @throws \Exception if user id was not found in LDAP
+	 * @since 12.0.0
+	 */
+	public function getLDAPEmailField($uid);
+
+	/**
+	 * Get the LDAP attribute name for the type of association betweeen users and groups
+	 * @param string $gid group id
+	 * @return string the configuration, one of: 'memberUid', 'uniqueMember', 'member', 'gidNumber'
+	 * @throws \Exception if group id was not found in LDAP
+	 * @since 13.0.0
+	 */
+	public function getLDAPGroupMemberAssoc($gid);
+
 }
-- 
GitLab