From 21b6ca3115f8cea7e96a2bfb76a3125753cd0f7b Mon Sep 17 00:00:00 2001 From: Roy Kaldung Date: Mon, 11 Jun 2012 14:23:44 +0200 Subject: [PATCH 1/7] changed to PHP_OS to prevent PHP Notice when running cli.php --- include/ifcorelib/IF_SVNBaseC.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ifcorelib/IF_SVNBaseC.class.php b/include/ifcorelib/IF_SVNBaseC.class.php index da989f0..9db1b42 100644 --- a/include/ifcorelib/IF_SVNBaseC.class.php +++ b/include/ifcorelib/IF_SVNBaseC.class.php @@ -87,7 +87,7 @@ class IF_SVNBaseC public function __construct() { // Find out whether the system is based on MS Windows. - $soft = $_SERVER["SERVER_SOFTWARE"]; + $soft = PHP_OS; $soft = strtoupper($soft); if (strpos($soft, "WIN") !== FALSE) From c17f9b3305ed283dee7cdc0441dea6e6c6df79cd Mon Sep 17 00:00:00 2001 From: rkaldung Date: Tue, 21 Aug 2012 13:06:20 +0200 Subject: [PATCH 2/7] reorganized for Active Directory provider via adLDAP --- grouplist.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/grouplist.php b/grouplist.php index 7bed525..4321542 100644 --- a/grouplist.php +++ b/grouplist.php @@ -4,6 +4,8 @@ * Copyright (c) 2010 by Manuel Freiholz * http://www.insanefactory.com/ * + * Copyright (c) 2012 by Roy Kaldung + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; version 2 From 5a1d8c48ee9cb31ca74551992119e579b224bee3 Mon Sep 17 00:00:00 2001 From: rkaldung Date: Tue, 21 Aug 2012 13:10:46 +0200 Subject: [PATCH 3/7] - reorganized for Active Directory provider via adLDAP --- .../providers/ad/AdUserViewProvider.class.php | 829 ++++++++++++++++++ .../ad/CachedAdUserViewProvider.class.php | 203 +++++ 2 files changed, 1032 insertions(+) create mode 100644 classes/providers/ad/AdUserViewProvider.class.php create mode 100644 classes/providers/ad/CachedAdUserViewProvider.class.php diff --git a/classes/providers/ad/AdUserViewProvider.class.php b/classes/providers/ad/AdUserViewProvider.class.php new file mode 100644 index 0000000..5477290 --- /dev/null +++ b/classes/providers/ad/AdUserViewProvider.class.php @@ -0,0 +1,829 @@ + + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. + */ +namespace svnadmin\providers\ad; + +class AdUserViewProvider + implements \svnadmin\core\interfaces\IUserViewProvider, + \svnadmin\core\interfaces\IGroupViewProvider +{ + /** + * Indicates whether the "init()" method has been called. + * @var bool + */ + private $m_init_done = false; + + /** + * Indicates whether the "update()" method has been called. + * @var bool + */ + private $m_update_done = false; + + /** + * LDAP service account, which is used for all requests to the LDAP server. + * @var string + */ + protected $bind_dn; + + /** + * LDAP service account password for the "$bind_dn". + * @var string + */ + protected $bind_password; + + /** + * Host address of the LDAP server. + * Format: ldap[s]://
[:getConfig(); + + $this->host_address = $cfg->getValue("Ldap", "HostAddress"); + $this->host_protocol_version = $cfg->getValue("Ldap", "ProtocolVersion"); + $this->bind_dn = $cfg->getValue("Ldap", "BindDN"); + $this->bind_password = $cfg->getValue("Ldap", "BindPassword"); + + $this->users_base_dn = $cfg->getValue("Users:ldap", "BaseDN"); + $this->users_search_filter = $cfg->getValue("Users:ldap", "SearchFilter"); + $this->users_attributes = $cfg->getValue("Users:ldap", "Attributes"); + $this->users_attributes = explode(",", $this->users_attributes); + + $this->groups_base_dn = $cfg->getValue("Groups:ldap", "BaseDN"); + $this->groups_search_filter = $cfg->getValue("Groups:ldap", "SearchFilter"); + $this->groups_attributes = $cfg->getValue("Groups:ldap", "Attributes"); + $this->groups_attributes = explode(",", $this->groups_attributes); + $this->groups_to_users_attribute = $cfg->getValue("Groups:ldap", "GroupsToUserAttribute"); + $this->groups_to_users_attribute_value = $cfg->getValue("Groups:ldap", "GroupsToUserAttributeValue"); + } + + /** + * Gets the "singelton" instance of this class. + * + * @return \svnadmin\providers\ldap\LdapUserViewProvider + */ + public static function getInstance() + { + if (self::$m_instance == null) + self::$m_instance = new LdapUserViewProvider(); + return self::$m_instance; + } + + // Required to execute tests on settings page. + public function setConnectionInformation($hostAddress, $hostPort, $hostProtocol, $bindDn, $bindPassword) + { + $this->host_address = $hostAddress; + $this->host_port = $hostPort; + $this->host_protocol_version = $hostProtocol; + $this->bind_dn = $bindDn; + $this->bind_password = $bindPassword; + } + + // Required to execute tests on settings page. + public function setUserViewInformation($usersBaseDn, $usersSearchFilter, $usersAttributes) + { + $this->users_base_dn = $usersBaseDn; + $this->users_search_filter = $usersSearchFilter; + $this->users_attributes = explode(",", $usersAttributes); + } + + // Required to execute tests on settings page. + public function setGroupViewInformation($groupsBaseDn, $groupsSearchFilter, $groupsAttributes, $groupsMemberAttribute, $groupsMemberAttributeValueAttribute) + { + $this->groups_base_dn = $groupsBaseDn; + $this->groups_search_filter = $groupsSearchFilter; + $this->groups_attributes = explode(",", $groupsAttributes); + $this->groups_to_users_attribute = $groupsMemberAttribute; + $this->groups_to_users_attribute_value = $groupsMemberAttributeValueAttribute; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IProvider::init() + */ + public function init() + { + if (!$this->m_init_done) + { + $this->m_init_done = true; + + if (parent::connect($this->host_address, $this->host_port, $this->host_protocol_version) === false) + return false; + + if (parent::bind($this->bind_dn, $this->bind_password) === false) + return false; + } + return true; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IViewProvider::isUpdateable() + */ + public function isUpdateable() + { + return true; + } + + /** + * Update the SVNAuthFile with data from LDAP server. + * @see svnadmin\core\interfaces.IViewProvider::update() + */ + public function update() + { + // This class is responsible for users and groups. + // On update this function should only be called one-times. + if (!$this->m_update_done) + { + $this->m_update_done = true; + + $E = \svnadmin\core\Engine::getInstance(); + $autoRemoveUsers = $E->getConfig()->getValueAsBoolean("Update:ldap", "AutoRemoveUsers", true); + $autoRemoveGroups = $E->getConfig()->getValueAsBoolean("Update:ldap", "AutoRemoveGroups", true); + + $this->updateSvnAuthFile($autoRemoveUsers, $autoRemoveGroups); + } + return true; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IUserViewProvider::getUsers() + */ + public function getUsers($withStarUser=true) + { + $ret = array(); + $up_name = strtolower($this->users_attributes[0]); + + // Search users in LDAP. + $ldapUsers = $this->p_getUserEntries(); + $ldapUsersLen = count($ldapUsers); + + for ($i = 0; $i < $ldapUsersLen; ++$i) + { + $u = new \svnadmin\core\entities\User; + $u->id = $ldapUsers[$i]->dn; + $u->name = $ldapUsers[$i]->$up_name; + $ret[] = $u; + } + + // Staticly get the '*' user. + if ($withStarUser) + { + $oUAll = new \svnadmin\core\entities\User; + $oUAll->id = '*'; + $oUAll->name = '*'; + $ret[] = $oUAll; + } + return $ret; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IUserViewProvider::userExists() + */ + public function userExists($objUser) + { + // Create filter. Example: sAMAccountName=ifmanuel + $user_name_filter = $this->users_attributes[0] . '=' . $objUser->name; + $final_filter = '(&('.$user_name_filter.')'.$this->users_search_filter.')'; + + // Search for a user, where the 'users_attributes' equals the $objUser->name. + $found = parent::objectSearch($this->connection, $this->users_base_dn, $final_filter, $this->users_attributes, 1); + + if (!is_array($found) || count($found) <= 0) + return false; + + return true; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IUserViewProvider::authenticate() + */ + public function authenticate($objUser, $password) + { + // Create filter. Example: sAMAccountName=ifmanuel + $user_name_filter = $this->users_attributes[0] . '=' . $objUser->name; + $final_filter = '(&('.$user_name_filter.')'.$this->users_search_filter.')'; + + // Search for a user, where the 'users_attributes' equals the $objUser->name. + $found = parent::objectSearch( $this->connection, $this->users_base_dn, $final_filter, $this->users_attributes, 1 ); + + if (!is_array($found) || count($found) <= 0) + return false; // User not found. + + // The user has been found. + // Get the dn of the user and authenticate him/her now. + return \IF_AbstractLdapConnector::authenticateUser($this->host_address, $this->host_port, $found[0]->dn, $password, $this->host_protocol_version); + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IGroupViewProvider::getGroups() + */ + public function getGroups() + { + $ret = array(); + $group_name_property = strtolower($this->groups_attributes[0]); + + // Get groups from LDAP server. + $ldapGroups = $this->p_getGroupEntries(); + $ldapGroupsLen = count($ldapGroups); + + for ($i = 0; $i < $ldapGroupsLen; $i++) + { + $o = new \svnadmin\core\entities\Group; + $o->id = $ldapGroups[$i]->dn; + $o->name = $ldapGroups[$i]->$group_name_property; + $ret[] = $o; + } + return $ret; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IGroupViewProvider::groupExists() + */ + public function groupExists($objGroup) + { + // Create filter. Example: sAMAccountName=_ISVNADMIN + $group_name_filter = $this->groups_attributes[0] . '=' . $objGroup->name; + $final_filter = '(&('.$group_name_filter.')'.$this->groups_search_filter.')'; + + // Search for a group, where the 'groups_attributes' equals the $objGroup->name. + $found = parent::objectSearch($this->connection, $this->groups_base_dn, $final_filter, $this->groups_attributes, 1); + + if (!is_array($found) || count($found) <= 0) + return false; + + return true; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IGroupViewProvider::getGroupsOfUser() + */ + public function getGroupsOfUser($objUser) + { + $ret = array(); + + // First, we have to find the user entry in the LDAP. + $userEntry = $this->p_findUserEntry($objUser); + $propUserId = strtolower($this->groups_to_users_attribute_value); + + // Create filter to find all group CNs which contains the usersEntry DN as 'member'. + $filter = $this->groups_to_users_attribute.'='.$userEntry->$propUserId; + $filter = '(&('.$filter.')'.$this->groups_search_filter.')'; + + // Execute search. + $found = parent::objectSearch($this->connection, $this->groups_base_dn, $filter, $this->groups_attributes, 0); + + if (!is_array($found) || count($found) <= 0) + return $ret; + + $propGroupName = strtolower($this->groups_attributes[0]); + + foreach ($found as $stdObj) + { + $o = new \svnadmin\core\entities\Group; + $o->name = $stdObj->$propGroupName; + $ret[] = $o; + } + return $ret; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IGroupViewProvider::getUsersOfGroup() + */ + public function getUsersOfGroup($objGroup) + { + $ret = array(); + + // Create filter to find all members of the given group. + $filter = $this->groups_attributes[0].'='.$objGroup->name; + $filter = '(&('.$filter.')'.$this->groups_search_filter.')'; + + // We need the 'groups_to_users_attribute'. + $att = array(); + $att[] = $this->groups_to_users_attribute; + + // Execute search. + $found = parent::objectSearch($this->connection, $this->groups_base_dn, $filter, $att, 1); + + if (!is_array($found) || count($found) <= 0) + return $ret; + + // Now we have to match the value which is saved in member to the user entry. + $propName = strtolower($this->groups_to_users_attribute); + $propName2 = strtolower($this->users_attributes[0]); + + if (!property_exists($found[0], $propName)) + { + // The group has no members. + // ... + } + else if (is_array($found[0]->$propName)) + { + // Multiple members. + foreach ($found[0]->$propName as $value) + { + // Find the user entry. + $userEntry = self::p_resolveGroupMemberId($value); + + if ($userEntry != null) + { + // Create User-object from the entry. + $u = new \svnadmin\core\entities\User; + $u->name = $userEntry->$propName2; + $ret[] = $u; + } + } + } + else if ($found[0]->$propName != null) + { + // Its a single member. + // Find the user entry. + $userEntry = self::p_resolveGroupMemberId($found[0]->$propName); + + if ($userEntry != null) + { + // Create User-object from the entry. + $u = new \svnadmin\core\entities\User; + $u->name = $userEntry->$propName2; + $ret[] = $u; + } + } + return $ret; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IGroupViewProvider::isUserInGroup() + * + * @todo Test me + */ + public function isUserInGroup($objUser, $objGroup) + { + // Get the user and group entry. + $userEntry = $this->p_findUserEntry($objUser); + $groupEntry = $this->p_findGroupEntry($objGroup); + + $propGroupName = strtolower($this->groups_attributes[0]); + + // Create filter to find the user as attribute inside the group. + $filter_user = $this->groups_to_users_attribute.'='.$userEntry->dn; + $filter_group = $this->groups_attributes[0].'='.$groupEntry->$propGroupName; + $filter = '(&('.$filter_user.')('.$filter_group.')'.$this->groups_search_filter.')'; + + // Execute search. + $found = parent::objectSearch($this->connection, $this->groups_base_dn, $filter, $this->groups_attributes, 1); + + if (!is_array($found) || count($found) <= 0) + return false; + + return true; + } + + /************************************************************************** + * Protected helper methods. + *************************************************************************/ + + /** + * Gets all user LDAP entries from server. + * + * @return array + */ + protected function p_getUserEntries() + { + // The standard attributes. + $attributes = $this->users_attributes; + + // Include the attribute which is used in the "member" attribute of a group-entry. + $attributes[] = $this->groups_to_users_attribute_value; + + return parent::objectSearch($this->connection, $this->users_base_dn, $this->users_search_filter, $attributes, 0); + } + + /** + * Gets all group LDAP entries from server. + * + * @return array + */ + protected function p_getGroupEntries($includeMembers = false) + { + $attributes = $this->groups_attributes; + + if ($includeMembers) + $attributes[] = $this->groups_to_users_attribute; + + return parent::objectSearch($this->connection, $this->groups_base_dn, $this->groups_search_filter, $attributes, 0); + } + + /** + * Searches the LDAP entry of the given user. + * + * @param \svnadmin\core\entities\User $objUser + * + * @return stdClass or NULL + */ + protected function p_findUserEntry(\svnadmin\core\entities\User $objUser) + { + // Create filter. Example: sAMAccountName=ifmanuel + $user_name_filter = $this->users_attributes[0] . '=' . $objUser->name; + $final_filter = '(&('.$user_name_filter.')'.$this->users_search_filter.')'; + + $attributes = $this->users_attributes; + $attributes[] = $this->groups_to_users_attribute_value; + + $found = parent::objectSearch($this->connection, $this->users_base_dn, $final_filter, $attributes, 1); + + if (!is_array($found) || count($found) <= 0) + return NULL; + + return $found[0]; + } + + /** + * Searches the LDAP entry of the given group. + * + * @param \svnadmin\core\entities\Group + * + * @return stdClass or NULL + */ + protected function p_findGroupEntry(\svnadmin\core\entities\Group $objGroup) + { + // Create filter. Example: sAMAccountName=_ISVNADMIN + $filter = $this->groups_attributes[0] .'=' . $objGroup->name; + $filter = '(&('.$filter.')'.$this->groups_search_filter.')'; + + $attributes = $this->groups_attributes; + $attributes[] = $this->groups_to_users_attribute; + + // Execute search. + $found = parent::objectSearch($this->connection, $this->groups_base_dn, $filter, $att, 1); + + if (!is_array($found) || count($found) <= 0) + return NULL; + + return $found[0]; + } + + /** + * Searches for a user-entry based on the member-id from the group. + * + * @param string The member id which is associated to a group (mostyl the DN) + * + * @return stdClass User-entry or NULL + */ + protected function p_resolveGroupMemberId($memberId) + { + // Create filter. + $filter = $this->groups_to_users_attribute_value.'='.$memberId; + $filter = '(&('.$filter.')'.$this->users_search_filter.')'; + + // Execute search. + $found = parent::objectSearch($this->connection, $this->users_base_dn, $filter, $this->users_attributes, 1); + + if (!is_array($found) || count($found) <= 0) + { + error_log("Can not resolve member ID. member-id=$memberId; filter=$filter;"); + return null; + } + + return $found[0]; + } + + /** + * Updates the SVNAuthFile with Users and Groups from LDAP server. + */ + public function updateSvnAuthFile($autoRemoveUsers=true, $autoRemoveGroups=true) + { + $this->init(); + $E = \svnadmin\core\Engine::getInstance(); + + // Increase max_execution_time for big LDAP structures. + $maxTime = intval(ini_get('max_execution_time')); + if ($maxTime != 0 && $maxTime < 300) { + @ini_set('max_execution_time', 300); + } + + try { + // @todo Backup file. + + // Step 1 + // Load the current SVNAuthFile and remove/reset all existing groups. + + // Load file. + $svnAuthFilePath = $E->getConfig()->getValue("Subversion", "SVNAuthFile"); + $svnAuthFile = new \IF_SVNAuthFileC($svnAuthFilePath); + $svnAuthFileOld = new \IF_SVNAuthFileC($svnAuthFilePath); + + // Remove groups. + $svnAuthFileGroups = $svnAuthFile->groups(); + foreach ($svnAuthFileGroups as $g) + { + $svnAuthFile->deleteGroup($g); + } + + // Step 2 + // Get all users and groups from LDAP server. + + // Users. + $users = array(); + $users = $this->p_getUserEntries(); + + // Groups. + $groups = array(); + $groups = $this->p_getGroupEntries(true); + + // Step 3 + // Iterate all groups which has been fetched from LDAP server + // and create them in the SVNAuthFile. Addionally associate + // all users to a group which are defined as member of a it. + // + // @todo Add the Realname or DN of a user as Alias to the SVNAuthFile. + + // Property name of a Group-Entry which holds the group's name. + $gp_name = strtolower($this->groups_attributes[0]); + + // Property name of a Group-Entry which holds the member-id (DN). + $gp_member_id = strtolower($this->groups_to_users_attribute); + + // Property name of a User-Entry which holds the user's name. + $up_name = strtolower($this->users_attributes[0]); + + // Property name of a User-Entry which holds the value which is assigned in a Group-Entry as Member-ID. + $up_id = strtolower($this->groups_to_users_attribute_value); + + foreach ($groups as $g) + { + if (!property_exists($g, $gp_name)) + continue; // The group-name property doesn't exist. + + try { + // Create group in SVNAuthFile. (throws Exception) + $svnAuthFile->createGroup($g->$gp_name); + } + catch (\Exception $except) { + $E->addException($except); + continue; + } + + // Find members. + if (!property_exists($g, $gp_member_id)) + { + // No members. + // @todo Should we delete empty groups from overview? + } + elseif (is_array($g->$gp_member_id)) + { + // Multiple members. + foreach ($g->$gp_member_id as $member_id) + { + // Get name of the member. + foreach ($users as $u) + { + if ($u->$up_id == $member_id) + { + // Add user to SVNAuthFile-Group. + $svnAuthFile->addUserToGroup($g->$gp_name, $u->$up_name); + break; + } + } + } + } + elseif (is_string($g->$gp_member_id)) + { + // One member. + $member_id = $g->$gp_member_id; + + // Get name of the member. + foreach ($users as $u) + { + if ($u->$up_id == $member_id) + { + // Add user to SVNAuthFile-Group. + $svnAuthFile->addUserToGroup($g->$gp_name, $u->$up_name); + break; + } + } + } + } // foreach($groups) + + // Step 4 + // Save new SVNAuthFile to disk. + $svnAuthFile->save(); + + + // Step 5 + // Compare with previous file to revoke AccessPath permissions of + // deleted groups and users. + // + // We need to reset the Provider object, because it holds the + // SVNAuthFile and should be reloaded, because of the cahnges + // above. + $apEditProvider = $E->getProvider(PROVIDER_ACCESSPATH_EDIT); + $apEditProvider->reset(); + + $removedUsers = array(); + $removedGroups = array(); + + // Collect removed groups. + // Groups which are in the old file but not in the new one. + foreach ($svnAuthFileOld->groups() as $g) + { + if (!$svnAuthFile->groupExists($g)) + { + // The group $g is not in the new configuration (Removed from LDAP). + $removedGroups[] = $g; + + if ($autoRemoveGroups) + { + try { + $apEditProvider->removeGroupFromAllAccessPaths( + new \svnadmin\core\entities\Group($g, $g) + ); + $E->addMessage(tr("The group %0 has been removed from LDAP. Removed all assigned permissions.", array($g))); + } + catch (\Exception $e) { + $E->addException($e); + } + } + } + } + + // Collect removed users and groups with direct associated + // Access-Path permissions and revoke the permissions. + foreach ($svnAuthFile->repositories() as $r) + { + // Users. + foreach ($svnAuthFile->usersOfRepository($r) as $u) + { + if (!$this->userExists(new \svnadmin\core\entities\User($u, $u))) + { + // The user has direct AccessPath permissions but does + // not exist on LDAP server. + $removedUsers[] = $u; + + if ($autoRemoveUsers) + { + // Revoke permissions. + try { + $apEditProvider->removeUserFromAccessPath( + new \svnadmin\core\entities\User($u, $u), + new \svnadmin\core\entities\AccessPath($r) + ); + $E->addMessage(tr("The user %0 doesn't exist anymore. Removed direct Access-Path permission to %1", array($u, $r))); + } + catch (\Exception $e) { + $E->addException($e); + } + } + } + } // foreach (users) + + // Groups. + foreach ($svnAuthFile->groupsOfRepository($r) as $g) + { + // We can check against the new SVNAuthFile, because the + // containing groups are updated from LDAP. + //if (!$this->groupExists(new \svnadmin\core\entities\Group($g, $g))) + if (!$svnAuthFile->groupExists($g)) + { + $removedGroups[] = $g; + + if ($autoRemoveGroups) + { + // Revoke permissions. + try { + $apEditProvider->removeGroupFromAccessPath( + new \svnadmin\core\entities\Group($g, $g), + new \svnadmin\core\entities\AccessPath($r) + ); + $E->addMessage(tr("The group %0 doesn't exist anymore. Removed direct Access-Path permission to %1", array($g, $r))); + } + catch (\Exception $e) { + $E->addException($e); + } + } + } + } // foreach (groups) + + } // foreach (repositories) + + // Save changes made to "$apEditProvider". + $apEditProvider->save(); + } + catch (\Exception $ex) { + throw $ex; + } + } +} +?> \ No newline at end of file diff --git a/classes/providers/ad/CachedAdUserViewProvider.class.php b/classes/providers/ad/CachedAdUserViewProvider.class.php new file mode 100644 index 0000000..c10776b --- /dev/null +++ b/classes/providers/ad/CachedAdUserViewProvider.class.php @@ -0,0 +1,203 @@ + + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. + */ +namespace svnadmin\providers\ad; + +/** + * The CachedLdapUserViewProvider class provides fast access for data which + * comes from the LdapUserViewProvider. It only accesses the LDAP server inside + * the "update()" method implementation. + * + * @author Manuel Freiholz, insaneFactory.com + */ +class CachedAdUserViewProvider + extends \svnadmin\providers\ad\AdUserViewProvider +{ + /** + * Cache file for users. + * @var \IF_JsonObjectStorage + */ + private $_cache; + + /** + * Holds the singleton instance of this class. + * @var \svnadmin\providers\ldap\CachedLdapUserViewProvider + */ + private static $_instance; + + /** + * Indicates whether the + * @var type + */ + private $_update_done = false; + + /** + * Indicates whether the 'init()' method has been called. + * @var type + */ + private $_init_done = false; + + /** + * Constructor. + * Loads cache file. + */ + public function __construct() + { + parent::__construct(); + $this->_cache = new \IF_JsonObjectStorage( + \svnadmin\core\Engine::getInstance()->getConfig() + ->getValue('Ldap', 'CacheFile', './data/ldap.cache.json') + ); + } + + /** + * Gets the singleton instance of this class. + * + * @return \svnadmin\providers\ldap\CachedLdapUserViewProvider + */ + public static function getInstance() + { + if (self::$_instance == null) { + self::$_instance = new CachedLdapUserViewProvider(); + } + return self::$_instance; + } + + public function init() + { + if (!$this->_init_done) { + $this->_init_done = true; + \svnadmin\providers\AuthFileGroupAndPathProvider::getInstance()->init(); + } + return parent::init(); + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IViewProvider::isUpdateable() + */ + public function isUpdateable() + { + return true; + } + + /** + * Update the SVNAuthFile with data from LDAP server. + * @see svnadmin\core\interfaces.IViewProvider::update() + */ + public function update() + { + if (!$this->_update_done) { + $this->_update_done = true; + + // Get all users from LDAP and save them to cache. + $users = parent::getUsers(false); + $this->_cache->setData("users", $users); + $this->_cache->save(); + + return parent::update(); + } + return true; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IUserViewProvider::getUsers() + */ + public function getUsers($withStarUser=true) + { + $cached_users = $this->_cache->getData("users"); + $users = array(); + + for ($i = 0; $i < count($cached_users); ++$i) { + $o = $this->_cache->objectCast($cached_users[$i], '\svnadmin\core\entities\User'); + $users[] = $o; + } + + if ($withStarUser) { + $o = new \svnadmin\core\entities\User; + $o->id = '*'; + $o->name = '*'; + $users[] = $o; + } + + return $users; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IUserViewProvider::userExists() + */ + public function userExists($user) + { + foreach ($this->getUsers() as $o) { + if ($o->name == $user->name) { + return true; + } + } + return false; + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IGroupViewProvider::getGroups() + */ + public function getGroups() + { + return \svnadmin\providers\AuthFileGroupAndPathProvider::getInstance()->getGroups(); + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IGroupViewProvider::groupExists() + */ + public function groupExists($objGroup) + { + return \svnadmin\providers\AuthFileGroupAndPathProvider::getInstance()->groupExists($objGroup); + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IGroupViewProvider::getGroupsOfUser() + */ + public function getGroupsOfUser($objUser) + { + return \svnadmin\providers\AuthFileGroupAndPathProvider::getInstance()->getGroupsOfUser($objUser); + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IGroupViewProvider::getUsersOfGroup() + */ + public function getUsersOfGroup($objGroup) + { + return \svnadmin\providers\AuthFileGroupAndPathProvider::getInstance()->getUsersOfGroup($objGroup); + } + + /** + * (non-PHPdoc) + * @see svnadmin\core\interfaces.IGroupViewProvider::isUserInGroup() + */ + public function isUserInGroup($objUser, $objGroup) + { + return \svnadmin\providers\AuthFileGroupAndPathProvider::getInstance()->isUserInGroup($objUser, $objGroup); + } +} \ No newline at end of file From 8404d5dc780b3b90eb6a4e19cce7b018adf272ef Mon Sep 17 00:00:00 2001 From: rkaldung Date: Tue, 21 Aug 2012 13:12:06 +0200 Subject: [PATCH 4/7] changed class comment --- classes/providers/ad/CachedAdUserViewProvider.class.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/classes/providers/ad/CachedAdUserViewProvider.class.php b/classes/providers/ad/CachedAdUserViewProvider.class.php index c10776b..a731a81 100644 --- a/classes/providers/ad/CachedAdUserViewProvider.class.php +++ b/classes/providers/ad/CachedAdUserViewProvider.class.php @@ -22,11 +22,11 @@ namespace svnadmin\providers\ad; /** - * The CachedLdapUserViewProvider class provides fast access for data which - * comes from the LdapUserViewProvider. It only accesses the LDAP server inside - * the "update()" method implementation. + * The CachedAdUserViewProvider class provides fast access for data which + * comes from the AdUserViewProvider. It's based on th original + * CachedLdapUserViewProvider implementation. * - * @author Manuel Freiholz, insaneFactory.com + * @author Roy Kaldung */ class CachedAdUserViewProvider extends \svnadmin\providers\ad\AdUserViewProvider From 56bd472870befac769d2c536f324afda34224fac Mon Sep 17 00:00:00 2001 From: rkaldung Date: Tue, 21 Aug 2012 15:16:46 +0200 Subject: [PATCH 5/7] changed class comment --- classes/providers/ad/AdUserViewProvider.class.php | 11 +++++++++-- .../providers/ad/CachedAdUserViewProvider.class.php | 12 ++++++------ data/config.tpl.ini | 9 +++++---- include/config.inc.php | 2 ++ settings.php | 4 ++-- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/classes/providers/ad/AdUserViewProvider.class.php b/classes/providers/ad/AdUserViewProvider.class.php index 5477290..36a88b5 100644 --- a/classes/providers/ad/AdUserViewProvider.class.php +++ b/classes/providers/ad/AdUserViewProvider.class.php @@ -129,6 +129,11 @@ class AdUserViewProvider */ protected $groups_to_users_attribute_value; + /** + * @var adLDAP + */ + protected $adLDAP; + /** * Holds the singelton instance of this class. * @var \svnadmin\providers\ldap\LdapUserViewProvider @@ -144,6 +149,8 @@ public function __construct() $E = \svnadmin\core\Engine::getInstance(); $cfg = $E->getConfig(); + $this->adLDAP = new \\adLDAP(); + $this->host_address = $cfg->getValue("Ldap", "HostAddress"); $this->host_protocol_version = $cfg->getValue("Ldap", "ProtocolVersion"); $this->bind_dn = $cfg->getValue("Ldap", "BindDN"); @@ -165,12 +172,12 @@ public function __construct() /** * Gets the "singelton" instance of this class. * - * @return \svnadmin\providers\ldap\LdapUserViewProvider + * @return \svnadmin\providers\ad\AdUserViewProvider */ public static function getInstance() { if (self::$m_instance == null) - self::$m_instance = new LdapUserViewProvider(); + self::$m_instance = new ADUserViewProvider(); return self::$m_instance; } diff --git a/classes/providers/ad/CachedAdUserViewProvider.class.php b/classes/providers/ad/CachedAdUserViewProvider.class.php index a731a81..9a7ff6c 100644 --- a/classes/providers/ad/CachedAdUserViewProvider.class.php +++ b/classes/providers/ad/CachedAdUserViewProvider.class.php @@ -23,10 +23,10 @@ /** * The CachedAdUserViewProvider class provides fast access for data which - * comes from the AdUserViewProvider. It's based on th original - * CachedLdapUserViewProvider implementation. + * comes from the AdUserViewProvider. It only accesses the LDAP server inside + * the "update()" method implementation. * - * @author Roy Kaldung + * @author Manuel Freiholz, insaneFactory.com */ class CachedAdUserViewProvider extends \svnadmin\providers\ad\AdUserViewProvider @@ -36,7 +36,7 @@ class CachedAdUserViewProvider * @var \IF_JsonObjectStorage */ private $_cache; - + /** * Holds the singleton instance of this class. * @var \svnadmin\providers\ldap\CachedLdapUserViewProvider @@ -54,7 +54,7 @@ class CachedAdUserViewProvider * @var type */ private $_init_done = false; - + /** * Constructor. * Loads cache file. @@ -98,7 +98,7 @@ public function isUpdateable() { return true; } - + /** * Update the SVNAuthFile with data from LDAP server. * @see svnadmin\core\interfaces.IViewProvider::update() diff --git a/data/config.tpl.ini b/data/config.tpl.ini index a446a0b..87bfa60 100644 --- a/data/config.tpl.ini +++ b/data/config.tpl.ini @@ -16,20 +16,21 @@ Directory=./translations/ AuthenticationStatus=basic # User view provider. -# Types: off, passwd, ldap +# Types: off, passwd, ldap, ad UserViewProviderType=passwd # User edit provider. -# Types: off, passwd (no ldap here!) +# Types: off, passwd (no ldap or ad here!) UserEditProviderType=passwd # Group view provider. # The type 'ldap' can only be used here, if the 'UserViewProviderType' is 'ldap', too. -# Types: off, svnauthfile, ldap +# With ad you can set the 'UserViewProviderType' to 'off' if needed to support only groups. +# Types: off, svnauthfile, ldap, ad GroupViewProviderType=svnauthfile # Group edit provider. -# Types: off, svnauthfile (no ldap here!) +# Types: off, svnauthfile (no ldap or ad here!) GroupEditProviderType=svnauthfile # Access-Path view provider. diff --git a/include/config.inc.php b/include/config.inc.php index 2c38079..b35c8d3 100644 --- a/include/config.inc.php +++ b/include/config.inc.php @@ -93,6 +93,8 @@ include_once( "./classes/core/Engine.class.php" ); include_once( "./classes/core/Exceptions.class.php" ); +include_once("src/adLDAP.php"); + /** * iF.SVNAdmin version. */ diff --git a/settings.php b/settings.php index eb1b6ca..af405b0 100644 --- a/settings.php +++ b/settings.php @@ -471,7 +471,7 @@ SetValue("SVNAuthFileEx", $svnAuthFileEx); // UserViewProviderType -$userViewProviderTypes = array(/*"off",*/ "passwd", "digest", "ldap"); +$userViewProviderTypes = array("off", "passwd", "digest", "ldap", "ad"); array_unshift($userViewProviderTypes, $cfgEngine->getValue("Engine:Providers","UserViewProviderType")); SetValue("userViewProviderTypes", $userViewProviderTypes); @@ -481,7 +481,7 @@ SetValue("userEditProviderTypes", $userEditProviderTypes); // GroupViewProviderType -$groupViewProviderTypes = array("off", "svnauthfile", "ldap"); +$groupViewProviderTypes = array("off", "svnauthfile", "ldap", "ad"); array_unshift($groupViewProviderTypes, $cfgEngine->getValue("Engine:Providers","GroupViewProviderType")); SetValue("groupViewProviderTypes", $groupViewProviderTypes); From 9e6a05df3344142c022adcbf5602bc4a2686049f Mon Sep 17 00:00:00 2001 From: rkaldung Date: Wed, 22 Aug 2012 15:12:05 +0200 Subject: [PATCH 6/7] configuration settings for Active Directory --- data/config.tpl.ini | 19 ++++++ pages/settings/backend.html.php | 76 +++++++++++++++++++++++ readme.md | 7 ++- settings.php | 72 ++++++++++++++++++++++ templates/script.js | 106 +++++++++++++++++++++++++++++++- 5 files changed, 277 insertions(+), 3 deletions(-) diff --git a/data/config.tpl.ini b/data/config.tpl.ini index 87bfa60..0afa58e 100644 --- a/data/config.tpl.ini +++ b/data/config.tpl.ini @@ -101,6 +101,25 @@ CacheEnabled=false # Storage file of LDAP user and group cache. CacheFile=./data/ldap.cache.json + +[Ad] +# your Domain name, DCs will be detected automatically +DomainName=example.com + +# User to bind, you can use the userPrincipalName or DN or samAccountName +BindUser=ldap@example.com + +BindPassword=secret +# where to cache the Domain Controller URLs + +# List of your Domaincontroller, separated by , +DomainController=dc1.example.com,dc2.example.com + +[Groups:ad] +Filter=SVN-* +StrictMode=false + + [Users:ldap] # The organisation unit, where all other users takes place. BaseDN=DC=insanefactory,DC=com diff --git a/pages/settings/backend.html.php b/pages/settings/backend.html.php index 3433144..7dd639d 100644 --- a/pages/settings/backend.html.php +++ b/pages/settings/backend.html.php @@ -56,6 +56,17 @@ "#LdapGroupTestResult"); }); + $('#AdDomainControllerDetect').click(function(){ + getSettings("AdDomainControllerDetect", {AdDomainName: $("#AdDomainName").val()}, "#AdDomainController"); + }); + + $('#AdConnectionTest').click(function() { + testSettings("AdConnection", + {AdDomainController: $("#AdDomainController").val(), + AdBindUser: $("#AdBindUser").val(), AdBindPassword: $("#AdBindPassword").val()}, + "#AdConnectionTestResult"); + }); + }); @@ -364,6 +375,71 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

:
">

:
+ "> + "> + +

:
">

:
+ "> + "> + +
+
+ + + + + + + + + + + + + + + + + + + + + + + +

:
">
>
+
+ "> diff --git a/readme.md b/readme.md index c44f7f2..5fe3f65 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,9 @@ The iF.SVNAdmin application is a web based GUI to your Subversion authorization file. It is based on PHP 5.3 and requires a web server (Apache) to be installed. The application doesn’t need a database back end or anything similar, it completely based on the Subversion authorization- and user authentication file. -(+Inludes LDAP support for users and groups) +(+Includes LDAP support for users and groups) +Now with direct Active Directory support (provider: ad) including nested groups. +This feature needs the adLDAP library. Documentation @@ -15,4 +17,5 @@ Documentation about installation and configuration can be found on the project h Who is responsible for this crap? --------------------------------- -© 2009-2012 Manuel Freiholz, [insaneFactory.com](http://www.insanefactory.com/) \ No newline at end of file +© 2009-2012 Manuel Freiholz, [insaneFactory.com](http://www.insanefactory.com/) +© 2012 Roy Kaldung for the Active Directory Stuff \ No newline at end of file diff --git a/settings.php b/settings.php index af405b0..aa75ea7 100644 --- a/settings.php +++ b/settings.php @@ -78,6 +78,13 @@ $pLdapGroupAttributes = get_request_var("LdapGroupAttributes"); $pLdapGroupsToUserAttribute = get_request_var("LdapGroupsToUserAttribute"); $pLdapGroupsToUserAttributeValue = get_request_var("LdapGroupsToUserAttributeValue"); +$pAdDomainName = get_request_var("AdDomainName"); +$pAdDomainController = get_request_var("AdDomainController"); +$pAdBindUser = get_request_var("AdBindUser"); +$pAdBindPassword = get_request_var("AdBindPassword"); +$pAdGroupFilter = get_request_var("AdGroupFilter"); +$pAdGroupStrictMode = get_request_var("AdGroupStrictMode"); + //////////////////////////////////////////////////////////////////////////////// // Reset first start up value. @@ -123,6 +130,12 @@ $cfgEngine->setValue("Groups:ldap", "Attributes", $pLdapGroupAttributes); $cfgEngine->setValue("Groups:ldap", "GroupsToUserAttribute", $pLdapGroupsToUserAttribute); $cfgEngine->setValue("Groups:ldap", "GroupsToUserAttributeValue", $pLdapGroupsToUserAttributeValue); + $cfgEngine->setValue('Ad', 'DomainName', $pAdDomainName); + $cfgEngine->setValue('Ad', 'DomainController', $pAdDomainController); + $cfgEngine->setValue('Ad', 'BindUser', $pAdBindUser); + $cfgEngine->setValue('Ad', 'BindPassword', $pAdBindPassword); + $cfgEngine->setValue('Groups:ad', 'Filter', $pAdGroupFilter); + $cfgEngine->setValue('Groups:ad', 'StrictMode', $pAdGroupStrictMode ? 'true' : 'false'); $cfgEngine->setValue("Common", "FirstStart", 0); // Save configuration now. @@ -328,6 +341,49 @@ } break; + case "AdDomainControllerDetect": + if (IF_AbstractLdapConnector::isLdapExtensionEnabled()) + { + $dcs = dns_get_record('_ldap._tcp.dc._msdcs.' . $pAdDomainName, DNS_SRV); + if (is_array($dcs)) { + $msgOk = ''; + foreach($dcs as $dc) { + $msgOk .= $dc['target'] . ','; + } + $msgOk = substr($msgOk, 0, -1); + } + if (!$dcs) { + $msgErr = tr('No Domain Controller found.'); + } + } + else + { + $msgErr = tr("PHP LDAP extension is not available."); + } + break; + + case 'AdConnection': + if (IF_AbstractLdapConnector::isLdapExtensionEnabled()) + { + try { + $test = new adLDAP(array( + 'domain_controllers' => explode(',', $pAdDomainController), + 'admin_username' => $pAdBindUser, + 'admin_password' => $pAdBindPassword, + 'base_dn' => null, + 'account_suffix' => '', + )); + $msgOk = "OK, BaseDN is " . $test->findBaseDn(); + } catch (Exception $e) { + $msgErr = $e->getMessage(); + } + } + else + { + $msgErr = tr("PHP LDAP extension is not available."); + } + break; + default: $msgErr = "Invalid request."; } @@ -585,6 +641,22 @@ SetValue("LdapGroupsToUserAttributeValue", $ldapGroupsToUserAttributeValue); SetValue("LdapGroupsToUserAttributeValueEx", $ldapGroupsToUserAttributeValueEx); +// AD connection +$adDomainName = $cfg->getValue('Ad', 'DomainName'); +$adBindUser = $cfg->getValue('Ad', 'BindUser'); +$adBindPassword = $cfg->getValue('Ad', 'BindPassword'); +$adDomainController = $cfg->getValue('Ad', 'DomainController'); +$adGroupFilter = $cfg->getValue('Groups:ad', 'Filter'); +$adGroupStrictMode = $cfg->getValueAsBoolean('Groups:ad', 'StrictMode'); +SetValue('AdDomainName', $adDomainName); +SetValue('AdBindUser', $adBindUser); +SetValue('AdBindPassword', $adBindPassword); +SetValue('AdDomainController', $adDomainController); +SetValue('AdGroupFilter', $adGroupFilter); +SetValue('AdGroupStrictMode', $adGroupStrictMode); + + + // Process template. ProcessTemplate("settings/backend.html.php"); ?> \ No newline at end of file diff --git a/templates/script.js b/templates/script.js index a53158c..753955c 100644 --- a/templates/script.js +++ b/templates/script.js @@ -287,6 +287,74 @@ function testSettings(testSection, params, resultContainer) }); } +/** + * Executes an XHR request an put the result into a textfield + * + * @param testSection The section to test. + * @param requestVars The variables which are required for an successful test. + * @param resultContainer The id of the container, which will contain the result. + * @param errorContainer The id of the cotainer where errors will be displayed. + */ +function getSettings(testSection, params, resultContainer, errorContainer) +{ + // Append static control parameters. + params.dotest = 1; + params.dotestsec = testSection; + + var C = $(errorContainer); + var D = $(resultContainer); + + $.ajax({ + type: "post", + url: "settings.php", + data: params, + cache: false, + dataType: "json", + + beforeSend: function(jqXHR, settings) { + // Hide old result element. + C.removeClass(); + C.html(HtmlData.ajaxLoadingImage()); + C.show(); + }, + + error: function(jqXHR, textStatus, errorThrown) { + var s = + "AJAX Error:
" + + "jqXHR=" + jqXHR + "
" + + "textStatus=" + textStatus + ";
" + + "errorThrown=" + errorThrown + ";
"; + C.addClass("errormsg"); + C.html(s).show(); + }, + + success: function(data, textStatus, jqXHR) { + // Get response text. + var msg = data.message; + + if (typeof data.php_error !== "undefined") { + msg += "
An PHP error occured!
"; + msg += data.php_error.message; + } + + // Set style class of container. + if (data.type == "error") { + C.addClass("errormsg"); + C.html(data.message); + } + else { + C.addClass("okmsg"); + C.html('OK'); + D.val(data.message); + } + }, + + complete: function(jqXHR, textStatus) { + // Show result. + C.show(); + } + }); +} /** * This function should be called with any change of the provider types. * It handles the logic of possible combinations and updates the user interface. @@ -310,7 +378,6 @@ function updateSettingsSelection() else if($("#UserViewProviderType").val() == "passwd") { $("#tbl_ldapconnection").hide(speed); - $("#tbl_ldapuser").hide(speed); $("#tbl_userdigestfile").hide(speed); $("#tbl_userfile").show(speed); $("#UserEditProviderType").removeAttr("disabled"); @@ -321,6 +388,7 @@ function updateSettingsSelection() { $("#tbl_ldapconnection").hide(speed); $("#tbl_ldapuser").hide(speed); + $("#tbl_adconnection").hide(speed); $("#tbl_userfile").hide(speed); $("#tbl_userdigestfile").show(speed); $("#UserEditProviderType").removeAttr("disabled"); @@ -332,10 +400,25 @@ function updateSettingsSelection() $("#tbl_userfile").hide(speed); $("#tbl_userdigestfile").hide(speed); $("#tbl_ldapconnection").show(speed); + $("#tbl_adconnection").hide(speed); $("#tbl_ldapuser").show(speed); $("#UserEditProviderType").val("off"); $("#UserEditProviderType").attr("disabled", "disabled"); } + else if($("#UserViewProviderType").val() == "ad") + { + $("#tbl_userfile").hide(speed); + $("#tbl_userdigestfile").hide(speed); + $("#tbl_ldapconnection").hide(speed); + $("#tbl_adconnection").show(speed); + $("#tbl_ldapuser").hide(speed); + if ($("#GroupViewProviderType").val() == 'ldap') { + alert("Can't combine LDAP and Active Directory provider x"); + $("#GroupViewProviderType").val("ad"); + } + $("#UserEditProviderType").val("off"); + $("#UserEditProviderType").attr("disabled", "disabled"); + } // Group view if ($("#GroupViewProviderType").val() == "off") @@ -343,7 +426,11 @@ function updateSettingsSelection() if ($("#UserViewProviderType").val() != "ldap"){ $("#tbl_ldapconnection").hide(speed); } + if ($("#UserViewProviderType").val() != "ad"){ + $("#tbl_adconnection").hide(speed); + } $("#tbl_ldapgroup").hide(speed); + $("#tbl_adgroup").hide(speed); $("#GroupEditProviderType").val("off"); $("#GroupEditProviderType").attr("disabled", "disabled"); } @@ -355,12 +442,28 @@ function updateSettingsSelection() $("#tbl_ldapgroup").hide(speed); $("#GroupEditProviderType").removeAttr("disabled"); } + else if ($("#GroupViewProviderType").val() == "ad") + { + $("#tbl_ldapconnection").hide(speed); + $("#tbl_ldapgroup").hide(speed); + $("#tbl_ldapgroup").hide(speed); + $("#tbl_adconnection").show(speed); + $("#tbl_adgroup").show(speed); + if ($("#UserViewProviderType").val() == "ldap") { + alert("Can't combine LDAP and Active Directory provider"); + $("#UserViewProviderType").val("off"); + $("#tbl_ldapuser").hide(speed); + } + $("#GroupEditProviderType").val("off"); + $("#GroupEditProviderType").attr("disabled", "disabled"); + } else if ($("#GroupViewProviderType").val() == "ldap") { if ($("#UserViewProviderType").val() == "ldap") { $("#tbl_ldapconnection").show(speed); $("#tbl_ldapgroup").show(speed); + $("#tbl_adgroup").hide(speed); $("#GroupEditProviderType").val("off"); $("#GroupEditProviderType").attr("disabled", "disabled"); } @@ -368,6 +471,7 @@ function updateSettingsSelection() { $("#GroupViewProviderType").val("off"); $("#tbl_ldapgroup").hide(speed); + $("#tbl_adgroup").hide(speed); $("#GroupEditProviderType").val("off"); $("#GroupEditProviderType").attr("disabled", "disabled"); alert("The users must be fetched from LDAP, if you want to use the groups from your LDAP server."); From af25da2eefaccabfbcd99b4f20aa229595240845 Mon Sep 17 00:00:00 2001 From: rkaldung Date: Wed, 22 Aug 2012 16:06:08 +0200 Subject: [PATCH 7/7] modified content --- readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 5fe3f65..8505c34 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,8 @@ The iF.SVNAdmin application is a web based GUI to your Subversion authorization file. It is based on PHP 5.3 and requires a web server (Apache) to be installed. The application doesn’t need a database back end or anything similar, it completely based on the Subversion authorization- and user authentication file. -(+Includes LDAP support for users and groups) +(+Includes LDAP support for users and groups). + Now with direct Active Directory support (provider: ad) including nested groups. This feature needs the adLDAP library. @@ -18,4 +19,5 @@ Documentation about installation and configuration can be found on the project h Who is responsible for this crap? --------------------------------- © 2009-2012 Manuel Freiholz, [insaneFactory.com](http://www.insanefactory.com/) + © 2012 Roy Kaldung for the Active Directory Stuff \ No newline at end of file