mirror of
https://github.com/netzbegruenung/user_saml.git
synced 2024-05-02 17:14:53 +02:00
Add group backend to separate SAML groups from system/other groups
Signed-off-by: Maximilian Ruta <mr@xtain.net> Rebased by Jonathan Treffler Signed-off-by: Jonathan Treffler <mail@jonathan-treffler.de>
This commit is contained in:
parent
cfad454524
commit
092cdcda26
|
@ -39,7 +39,27 @@ try {
|
|||
return;
|
||||
}
|
||||
|
||||
$samlSettings = \OC::$server->query(\OCA\User_SAML\SAMLSettings::class);
|
||||
\OC::$server->registerService('SAMLGroupDuplicateChecker', function() use($config) {
|
||||
return new OCA\User_SAML\GroupDuplicateChecker(
|
||||
$config,
|
||||
\OC::$server->getGroupManager(),
|
||||
\OC::$server->getLogger()
|
||||
);
|
||||
});
|
||||
|
||||
\OC::$server->registerService('SAMLGroupManager', function() {
|
||||
return new OCA\User_SAML\GroupManager(
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
\OC::$server->query('SAMLGroupDuplicateChecker')
|
||||
);
|
||||
});
|
||||
|
||||
$samlSettings = new \OCA\User_SAML\SAMLSettings(
|
||||
$urlGenerator,
|
||||
$config,
|
||||
$request,
|
||||
$session
|
||||
);
|
||||
|
||||
$userData = new \OCA\User_SAML\UserData(
|
||||
new \OCA\User_SAML\UserResolver(\OC::$server->getUserManager()),
|
||||
|
@ -53,7 +73,7 @@ $userBackend = new \OCA\User_SAML\UserBackend(
|
|||
\OC::$server->getSession(),
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
\OC::$server->getUserManager(),
|
||||
\OC::$server->getGroupManager(),
|
||||
\OC::$server->query('SAMLGroupManager'),
|
||||
$samlSettings,
|
||||
\OC::$server->getLogger(),
|
||||
$userData,
|
||||
|
@ -62,6 +82,9 @@ $userBackend = new \OCA\User_SAML\UserBackend(
|
|||
$userBackend->registerBackends(\OC::$server->getUserManager()->getBackends());
|
||||
OC_User::useBackend($userBackend);
|
||||
|
||||
$groupBackend = new \OCA\User_SAML\GroupBackend($config, \OC::$server->query('SAMLGroupManager'));
|
||||
\OC::$server->getGroupManager()->addBackend($groupBackend);
|
||||
|
||||
$params = [];
|
||||
|
||||
// Setting up the one login config may fail, if so, do not catch the requests later.
|
||||
|
|
129
lib/GroupBackend.php
Normal file
129
lib/GroupBackend.php
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
namespace OCA\User_SAML;
|
||||
|
||||
use OCP\Group\Backend\ABackend;
|
||||
use OCP\IConfig;
|
||||
|
||||
class GroupBackend extends ABackend {
|
||||
/**
|
||||
* @var IConfig
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var GroupManager
|
||||
*/
|
||||
protected $groupManager;
|
||||
|
||||
public function __construct(
|
||||
IConfig $config,
|
||||
GroupManager $groupManager
|
||||
) {
|
||||
$this->config = $config;
|
||||
$this->groupManager = $groupManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getPrefix() {
|
||||
return $this->config->getAppValue('user_saml', 'saml-attribute-mapping-group_mapping_prefix', '');
|
||||
}
|
||||
|
||||
protected function hasPrefix($string) {
|
||||
return mb_substr($string, 0, mb_strlen($this->getPrefix())) === $this->getPrefix();
|
||||
}
|
||||
|
||||
protected function removePrefix($query = null) {
|
||||
if ($query === null || $query === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$pattern = '';
|
||||
foreach (preg_split('//u', $this->getPrefix(), -1, PREG_SPLIT_NO_EMPTY) as $char) {
|
||||
$pattern .= preg_quote($char, '/') . '?';
|
||||
}
|
||||
|
||||
$result = preg_replace('/^' . $pattern . '/', '', $query);
|
||||
|
||||
if ($result === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function prefixedList($items) {
|
||||
$newList = array();
|
||||
|
||||
foreach ($items as $item) {
|
||||
$newList[] = $this->getPrefix() . $item;
|
||||
}
|
||||
|
||||
return $newList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function inGroup($uid, $gid) {
|
||||
if (!$this->hasPrefix($gid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->groupManager->userInGroup($uid, $this->removePrefix($gid));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] Group names
|
||||
*/
|
||||
public function getUserGroups($uid) {
|
||||
return $this->prefixedList($this->groupManager->userGroups($uid));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] Group names
|
||||
*/
|
||||
public function getGroups($search = '', $limit = -1, $offset = 0) {
|
||||
if ($search === '') {
|
||||
$search = null;
|
||||
} else {
|
||||
if (!$this->hasPrefix($search)) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->prefixedList($this->groupManager->findGroups($this->removePrefix($search), $limit, $offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function groupExists($gid) {
|
||||
if (!$this->hasPrefix($gid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->groupManager->hasGroup(
|
||||
$this->removePrefix($gid)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] User ids
|
||||
*/
|
||||
public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
|
||||
if ($search === '') {
|
||||
$search = null;
|
||||
} else {
|
||||
if (!$this->hasPrefix($search)) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->prefixedList(
|
||||
$this->groupManager->findGroups($gid, $this->removePrefix($search), $limit, $offset)
|
||||
);
|
||||
}
|
||||
}
|
67
lib/GroupDuplicateChecker.php
Normal file
67
lib/GroupDuplicateChecker.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace OCA\User_SAML;
|
||||
|
||||
use OCP\IConfig;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\ILogger;
|
||||
|
||||
class GroupDuplicateChecker
|
||||
{
|
||||
/**
|
||||
* @var IConfig
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var IGroupManager
|
||||
*/
|
||||
protected $groupManager;
|
||||
|
||||
/**
|
||||
* @var ILogger
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
public function __construct(
|
||||
IConfig $config,
|
||||
IGroupManager $groupManager,
|
||||
ILogger $logger
|
||||
) {
|
||||
$this->config = $config;
|
||||
$this->groupManager = $groupManager;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getPrefix() {
|
||||
return $this->config->getAppValue('user_saml', 'saml-attribute-mapping-group_mapping_prefix', '');
|
||||
}
|
||||
|
||||
public function checkForDuplicates($group) {
|
||||
$realGroupName = $this->getPrefix() . $group;
|
||||
$existingGroup = $this->groupManager->get($realGroupName);
|
||||
if ($existingGroup !== null) {
|
||||
$reflection = new \ReflectionClass($existingGroup);
|
||||
$property = $reflection->getProperty('backends');
|
||||
$property->setAccessible(true);
|
||||
$backends = $property->getValue($existingGroup);
|
||||
if ($backends) {
|
||||
foreach ($backends as $backend) {
|
||||
if ($backend instanceof GroupBackend) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->warning(
|
||||
'Group {name} already existing in other backend',
|
||||
[
|
||||
'name' => $realGroupName
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
181
lib/GroupManager.php
Normal file
181
lib/GroupManager.php
Normal file
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
|
||||
namespace OCA\User_SAML;
|
||||
|
||||
use OCP\IDBConnection;
|
||||
|
||||
class GroupManager
|
||||
{
|
||||
/**
|
||||
* @var IDBConnection $db
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* @var GroupDuplicateChecker
|
||||
*/
|
||||
protected $duplicateChecker;
|
||||
|
||||
public function __construct(IDBConnection $db, GroupDuplicateChecker $duplicateChecker) {
|
||||
$this->db = $db;
|
||||
$this->duplicateChecker = $duplicateChecker;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function findGroups($query = null, $limit = -1, $offset = 0) {
|
||||
$sql = '
|
||||
SELECT DISTINCT `group`
|
||||
FROM `*PREFIX*user_saml_group_members`
|
||||
';
|
||||
|
||||
$params = array();
|
||||
|
||||
if ($query !== null) {
|
||||
$sql .= ' WHERE `group` LIKE ?';
|
||||
$params = [
|
||||
'%' . $query . '%'
|
||||
];
|
||||
}
|
||||
|
||||
if ($limit === -1) {
|
||||
$limit = null;
|
||||
}
|
||||
|
||||
if ($offset === 0) {
|
||||
$offset = null;
|
||||
}
|
||||
|
||||
$stmt = $this->db->prepare($sql, $limit, $offset);
|
||||
$stmt->execute($params);
|
||||
return $stmt->fetchAll(\PDO::FETCH_COLUMN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasGroup($group) {
|
||||
$sql = '
|
||||
SELECT DISTINCT `group`
|
||||
FROM `*PREFIX*user_saml_group_members`
|
||||
WHERE `group` = ?
|
||||
';
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
$stmt->execute(array($group));
|
||||
return $stmt->rowCount() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function userInGroup($uid, $group) {
|
||||
$sql = '
|
||||
SELECT DISTINCT `group`
|
||||
FROM `*PREFIX*user_saml_group_members`
|
||||
WHERE `uid` = ? AND `group` = ?
|
||||
';
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
$stmt->execute(array($uid, $group));
|
||||
return $stmt->rowCount() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function userGroups($uid) {
|
||||
$sql = '
|
||||
SELECT DISTINCT `group`
|
||||
FROM `*PREFIX*user_saml_group_members`
|
||||
WHERE `uid` = ?
|
||||
';
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
$stmt->execute(array($uid));
|
||||
return $stmt->fetchAll(\PDO::FETCH_COLUMN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function usersInGroup($gid, $query = null, $limit = -1, $offset = 0) {
|
||||
$sql = '
|
||||
SELECT DISTINCT `uid`
|
||||
FROM `*PREFIX*user_saml_group_members`
|
||||
WHERE `group` = ?
|
||||
';
|
||||
|
||||
$params = array($gid);
|
||||
|
||||
if ($query !== null) {
|
||||
$sql .= ' AND `uid` LIKE ?';
|
||||
$params = [
|
||||
'%' . $query . '%'
|
||||
];
|
||||
}
|
||||
|
||||
if ($limit === -1) {
|
||||
$limit = null;
|
||||
}
|
||||
|
||||
if ($offset === 0) {
|
||||
$offset = null;
|
||||
}
|
||||
|
||||
$stmt = $this->db->prepare($sql, $limit, $offset);
|
||||
$stmt->execute($params);
|
||||
return $stmt->fetchAll(\PDO::FETCH_COLUMN);
|
||||
}
|
||||
|
||||
public function replaceGroups($uid, $saml) {
|
||||
$assgined = $this->userGroups($uid);
|
||||
$this->removeGroups($uid, array_diff($assgined, $saml));
|
||||
$this->addGroups($uid, array_diff($saml, $assgined));
|
||||
}
|
||||
|
||||
public function removeGroup($uid, $group) {
|
||||
$this->removeGroups($uid, array($group));
|
||||
}
|
||||
|
||||
public function removeGroups($uid, $groups) {
|
||||
if (count($groups) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$groups = array_values($groups);
|
||||
$inQuery = implode(',', array_fill(0, count($groups), '?'));
|
||||
|
||||
$sql = '
|
||||
DELETE FROM `*PREFIX*user_saml_group_members`
|
||||
WHERE `uid` = ? AND `group` IN (' . $inQuery . ')
|
||||
';
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
$stmt->bindParam(1, $uid);
|
||||
foreach ($groups as $k => $id) {
|
||||
$stmt->bindValue(($k + 2), $id);
|
||||
}
|
||||
return $stmt->execute();
|
||||
}
|
||||
|
||||
public function addGroups($uid, $groups) {
|
||||
foreach ($groups as $group) {
|
||||
$this->addGroup($uid, $group);
|
||||
}
|
||||
}
|
||||
|
||||
public function addGroup($uid, $group) {
|
||||
$this->duplicateChecker->checkForDuplicates($group);
|
||||
|
||||
$sql = '
|
||||
INSERT INTO `*PREFIX*user_saml_group_members`
|
||||
(`uid`, `group`)
|
||||
VALUES (?, ?)
|
||||
';
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
return $stmt->execute(array($uid, $group));
|
||||
}
|
||||
}
|
|
@ -135,7 +135,11 @@ class Admin implements ISettings {
|
|||
'type' => 'line',
|
||||
'required' => true,
|
||||
],
|
||||
|
||||
'group_mapping_prefix' => [
|
||||
'text' => $this->l10n->t('Group Mapping Prefix'),
|
||||
'type' => 'line',
|
||||
'required' => true,
|
||||
],
|
||||
];
|
||||
|
||||
$firstIdPConfig = isset($providers[0]) ? $this->samlSettings->get($providers[0]['id']) : null;
|
||||
|
|
|
@ -24,16 +24,16 @@ namespace OCA\User_SAML;
|
|||
use OCP\Authentication\IApacheBackend;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\Files\NotPermittedException;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\ILogger;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\UserInterface;
|
||||
use OCP\IUserBackend;
|
||||
use OCP\IConfig;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\ILogger;
|
||||
use OCP\ISession;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserBackend;
|
||||
use OCP\IUserManager;
|
||||
use OCP\UserInterface;
|
||||
use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\User\Events\UserChangedEvent;
|
||||
|
@ -49,7 +49,7 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
|
|||
private $db;
|
||||
/** @var IUserManager */
|
||||
private $userManager;
|
||||
/** @var IGroupManager */
|
||||
/** @var GroupManager */
|
||||
private $groupManager;
|
||||
/** @var \OCP\UserInterface[] */
|
||||
private static $backends = [];
|
||||
|
@ -62,6 +62,16 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
|
|||
/** @var IEventDispatcher */
|
||||
private $eventDispatcher;
|
||||
|
||||
/**
|
||||
* @param IConfig $config
|
||||
* @param IURLGenerator $urlGenerator
|
||||
* @param ISession $session
|
||||
* @param IDBConnection $db
|
||||
* @param IUserManager $userManager
|
||||
* @param IGroupManager $groupManager
|
||||
* @param SAMLSettings $settings
|
||||
* @param ILogger $logger
|
||||
*/
|
||||
public function __construct(
|
||||
IConfig $config,
|
||||
IURLGenerator $urlGenerator,
|
||||
|
@ -659,24 +669,10 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
|
|||
$user->setQuota($newQuota);
|
||||
}
|
||||
|
||||
if ($newGroups !== null) {
|
||||
$groupManager = $this->groupManager;
|
||||
$oldGroups = $groupManager->getUserGroupIds($user);
|
||||
|
||||
$groupsToAdd = array_unique(array_diff($newGroups, $oldGroups));
|
||||
$groupsToRemove = array_diff($oldGroups, $newGroups);
|
||||
|
||||
foreach ($groupsToAdd as $group) {
|
||||
if (!($groupManager->groupExists($group))) {
|
||||
$groupManager->createGroup($group);
|
||||
}
|
||||
$groupManager->get($group)->addUser($user);
|
||||
}
|
||||
|
||||
foreach ($groupsToRemove as $group) {
|
||||
$groupManager->get($group)->removeUser($user);
|
||||
}
|
||||
if ($newGroups === null) {
|
||||
$newGroups = [];
|
||||
}
|
||||
$this->groupManager->replaceGroups($user->getUID(), $newGroups);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue