* [DEV] New LDAP implementation

This commit is contained in:
nuxsmin
2016-11-16 14:58:17 +01:00
parent 22c9045d05
commit 6e5bc79e05
12 changed files with 130 additions and 86 deletions

View File

@@ -23,6 +23,7 @@
*
*/
use SP\Auth\Ldap\LdapMsAds;
use SP\Auth\Ldap\LdapStd;
use SP\Core\Init;
use SP\Core\SessionUtil;
@@ -55,23 +56,28 @@ if (!$sk || !SessionUtil::checkSessionKey($sk)) {
$frmType = Request::analyze('type');
if ($frmType === 'ldap') {
$frmLdapServer = Request::analyze('ldap_server');
$frmLdapBase = Request::analyze('ldap_base');
$frmLdapGroup = Request::analyze('ldap_group');
$frmLdapBindUser = Request::analyze('ldap_binduser');
$frmLdapBindPass = Request::analyzeEncrypted('ldap_bindpass');
$ldapServer = Request::analyze('ldap_server');
$ldapBase = Request::analyze('ldap_base');
$ldapGroup = Request::analyze('ldap_group');
$ldapBindUser = Request::analyze('ldap_binduser');
$ldapBindPass = Request::analyzeEncrypted('ldap_bindpass');
if (!$frmLdapServer || !$frmLdapBase || !$frmLdapBindUser || !$frmLdapBindPass) {
if (!$ldapServer || !$ldapBase || !$ldapBindUser || !$ldapBindPass) {
$Json->setDescription(_('Los parámetros de LDAP no están configurados'));
Json::returnJson($Json);
}
$Ldap = new LdapStd();
$Ldap->setServer($frmLdapServer);
$Ldap->setSearchBase($frmLdapBase);
$Ldap->setGroup($frmLdapGroup);
$Ldap->setBindDn($frmLdapBindUser);
$Ldap->setBindPass($frmLdapBindPass);
if (Request::analyze('ldap_enabled', false, false, true)) {
$Ldap = new LdapMsAds();
} else {
$Ldap = new LdapStd();
}
$Ldap->setServer($ldapServer);
$Ldap->setSearchBase($ldapBase);
$Ldap->setGroup($ldapGroup);
$Ldap->setBindDn($ldapBindUser);
$Ldap->setBindPass($ldapBindPass);
$resCheckLdap = $Ldap->checkConnection();

View File

@@ -134,7 +134,7 @@ if ($resLdap !== false) {
$Log->addDetails(_('Tipo'), 'MySQL');
// Autentificamos con la BBDD
if (!Auth::authUserMySQL($UserData->getUserLogin(), $UserData->getUserPass())) {
if (!Auth::authUserMySQL($UserData)) {
$Log->addDescription(_('Login incorrecto'));
$Log->addDetails(_('Usuario'), $UserData->getUserLogin());
$Log->writeLog();

View File

@@ -389,8 +389,6 @@ class AccountHistory extends AccountBase implements AccountInterface
*/
public function getAccountPassData()
{
debugLog($this->getId());
$query = /** @lang SQL */
'SELECT acchistory_name AS account_name,'
. 'acchistory_userId AS account_userId,'

View File

@@ -103,7 +103,7 @@ abstract class ApiBase
$UserPass = UserPass::getItem($UserData);
if (!$UserData->isUserIsDisabled()
&& Auth::authUserMySQL($UserData->getUserLogin(), $UserData->getUserPass())
&& Auth::authUserMySQL($UserData)
&& $UserPass->loadUserMPass()
&& UserPass::checkUserUpdateMPass($UserData->getUserId())
) {

View File

@@ -26,7 +26,7 @@
namespace SP\Auth;
use SP\Auth\Ldap\LdapMads;
use SP\Auth\Ldap\LdapMsAds;
use SP\Auth\Ldap\LdapStd;
use SP\Config\Config;
use SP\Core\Exceptions\SPException;
@@ -63,7 +63,7 @@ class Auth
public static function authUserLDAP(UserData $UserData)
{
if (Config::getConfig()->isLdapAds()) {
$Ldap = new LdapMads();
$Ldap = new LdapMsAds();
} else {
$Ldap = new LdapStd();
}
@@ -83,7 +83,7 @@ class Auth
self::$status = 701;
return false;
} elseif ($LdapAuthData->isInGroup()) {
} elseif (!$LdapAuthData->isInGroup()) {
self::$status = 702;
return false;
@@ -98,19 +98,18 @@ class Auth
* Esta función comprueba la clave del usuario. Si el usuario necesita ser migrado desde phpPMS,
* se ejecuta el proceso para actualizar la clave.
*
* @param string $userLogin con el login del usuario
* @param string $userPass con la clave del usuario
* @param UserData $UserData
* @return bool
*/
public static function authUserMySQL($userLogin, $userPass)
public static function authUserMySQL(UserData $UserData)
{
if (UserMigrate::checkUserIsMigrate($userLogin)) {
if (UserMigrate::checkUserIsMigrate($UserData->getUserLogin())) {
try {
UserMigrate::migrateUser($userLogin, $userPass);
UserMigrate::migrateUser($UserData->getUserLogin(), $UserData->getUserPass());
} catch (SPException $e) {
$Log = new Log(__FUNCTION__);
$Log->addDescription($e->getMessage());
$Log->addDetails(_('Login'), $userLogin);
$Log->addDetails(_('Login'), $UserData->getUserLogin());
$Log->writeLog();
return false;
@@ -126,14 +125,14 @@ class Auth
$Data = new QueryData();
$Data->setMapClassName('SP\DataModel\UserPassData');
$Data->setQuery($query);
$Data->addParam($userLogin);
$Data->addParam($UserData->getUserLogin());
/** @var UserPassData $queryRes */
$queryRes = DB::getResults($Data);
return ($queryRes !== false
&& $Data->getQueryNumRows() === 1
&& $queryRes->getUserPass() === crypt($userPass, $queryRes->getUserHashSalt()));
&& $queryRes->getUserPass() === crypt($UserData->getUserPass(), $queryRes->getUserHashSalt()));
}
/**

View File

@@ -35,6 +35,10 @@ class LdapAuthData
* @var string
*/
protected $dn;
/**
* @var string
*/
protected $groupDn;
/**
* @var string
*/
@@ -191,4 +195,20 @@ class LdapAuthData
{
$this->ldapStatus = $ldapStatus;
}
/**
* @return string
*/
public function getGroupDn()
{
return $this->groupDn;
}
/**
* @param string $groupDn
*/
public function setGroupDn($groupDn)
{
$this->groupDn = $groupDn;
}
}

View File

@@ -144,8 +144,8 @@ abstract class LdapBase implements LdapInterface, AuthInterface
throw new SPException(SPException::SP_ERROR, $Log->getDescription());
}
@ldap_set_option($this->ldapHandler, LDAP_OPT_NETWORK_TIMEOUT, 10); // Set timeout
@ldap_set_option($this->ldapHandler, LDAP_OPT_PROTOCOL_VERSION, 3); // Set LDAP version
@ldap_set_option($this->ldapHandler, LDAP_OPT_NETWORK_TIMEOUT, 10);
@ldap_set_option($this->ldapHandler, LDAP_OPT_PROTOCOL_VERSION, 3);
return true;
}
@@ -315,7 +315,7 @@ abstract class LdapBase implements LdapInterface, AuthInterface
*/
public function setUserLogin($userLogin)
{
$this->userLogin = $userLogin;
$this->userLogin = strtolower($userLogin);
}
/**
@@ -331,7 +331,7 @@ abstract class LdapBase implements LdapInterface, AuthInterface
}
try {
$this->userLogin = $UserData->getUserLogin();
$this->setUserLogin($UserData->getUserLogin());
$this->connect();
$this->bind();
@@ -407,6 +407,8 @@ abstract class LdapBase implements LdapInterface, AuthInterface
$count = (int)$values['count'];
if ($count > 1) {
unset($values['count']);
$res[$validAttributes[$normalizedAttribute]] = $values;
} else {
// Almacenamos 1 solo valor
@@ -422,6 +424,14 @@ abstract class LdapBase implements LdapInterface, AuthInterface
$this->LdapUserData->setEmail($res['mail']);
$this->LdapUserData->setExpire($res['expire']);
$this->LdapUserData->setGroups($res['group']);
if ($this->group !== null
&& $this->group !== ''
&& $this->group !== '*'
) {
$this->LdapUserData->setGroupDn($this->searchGroupDN());
}
$this->LdapUserData->setInGroup($this->searchUserInGroup());
return $this->LdapUserData;
@@ -514,7 +524,19 @@ abstract class LdapBase implements LdapInterface, AuthInterface
*/
protected function escapeLdapDN($dn)
{
$chars = ['/(,)(?!uid|cn|ou|dc)/i', '/(?<!uid|cn|ou|dc)(=)/i', '/(")/', '/(;)/', '/(>)/', '/(<)/', '/(\+)/', '/(#)/', '/\G(\s)/', '/(\s)(?=\s*$)/', '/(\/)/'];
$chars = [
'/(,)(?!uid|cn|ou|dc)/i',
'/(?<!uid|cn|ou|dc)(=)/i',
'/(")/',
'/(;)/',
'/(>)/',
'/(<)/',
'/(\+)/',
'/(#)/',
'/\G(\s)/',
'/(\s)(?=\s*$)/',
'/(\/)/'
];
return preg_replace($chars, '\\\$1', $dn);
}
@@ -527,8 +549,8 @@ abstract class LdapBase implements LdapInterface, AuthInterface
protected function searchGroupDN()
{
$Log = new Log(__FUNCTION__);
$filter = $this->getGroupName() ?: $this->group;
$filter = '(cn=' . $filter . ')';
$group = $this->getGroupName() ?: $this->group;
$filter = '(cn=' . $group . ')';
$searchRes = @ldap_search($this->ldapHandler, $this->searchBase, $filter, ['dn', 'cn']);

View File

@@ -24,7 +24,7 @@
namespace SP\Auth\Ldap;
use Auth\Ldap\LdapBase;
use SP\Config\Config;
use SP\Core\Exceptions\SPException;
use SP\Log\Log;
@@ -33,7 +33,7 @@ use SP\Log\Log;
*
* @package SP\Auth\Ldap
*/
class LdapMads extends LdapBase
class LdapMsAds extends LdapBase
{
/**
@@ -45,7 +45,6 @@ class LdapMads extends LdapBase
{
$groupDN = (!empty($this->group)) ? $this->searchGroupDN() : '*';
return '(&(|(memberOf=' . $groupDN . ')(groupMembership=' . $groupDN . ')(memberof:1.2.840.113556.1.4.1941:=' . $groupDN . '))(|(objectClass=inetOrgPerson)(objectClass=person)(objectClass=simpleSecurityObject)))';
}
@@ -56,12 +55,14 @@ class LdapMads extends LdapBase
*/
protected function pickServer()
{
if (preg_match('/[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}/', $this->server)) {
return $this->server;
$server = Config::getConfig()->getLdapServer();
if (preg_match('/[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}/', $server)) {
return $server;
}
$serverDomain = '';
$serverFQDN = explode('.', $this->server);
$serverFQDN = explode('.', $server);
for ($i = 1; $i <= count($serverFQDN) - 1; $i++) {
$serverDomain .= $serverFQDN[$i] . '.';
@@ -71,7 +72,7 @@ class LdapMads extends LdapBase
$records = dns_get_record($dnsServerQuery, DNS_NS);
if (count($records) === 0) {
return $this->server;
return $server;
}
$ads = [];
@@ -80,7 +81,9 @@ class LdapMads extends LdapBase
$ads[] = $record['target'];
};
return count($ads) > 0 ? $ads[mt_rand(0, count($ads) - 1)] : $this->server;
$nAds = count($ads);
return $nAds > 0 ? $ads[mt_rand(0, $nAds)] : $server;
}
/**
@@ -103,13 +106,11 @@ class LdapMads extends LdapBase
{
$Log = new Log(__FUNCTION__);
$groupDN = $this->getGroupName() ?: $this->group;
// Comprobar si está establecido el filtro de grupo o el grupo coincide con
// los grupos del usuario
if (!$this->group
|| $this->group === '*'
|| in_array($groupDN, $this->LdapUserData->getGroups())
|| in_array($this->LdapUserData->getGroupDn(), $this->LdapUserData->getGroups())
) {
$Log->addDescription(_('Usuario verificado en grupo'));
$Log->writeLog();
@@ -117,6 +118,7 @@ class LdapMads extends LdapBase
return true;
}
$groupDN = $this->LdapUserData->getGroupDn();
$filter = '(memberof:1.2.840.113556.1.4.1941:=' . $groupDN . ')';
$searchRes = @ldap_search($this->ldapHandler, $this->searchBase, $filter, ['sAMAccountName']);
@@ -143,12 +145,17 @@ class LdapMads extends LdapBase
throw new SPException(SPException::SP_ERROR, $Log->getDescription());
}
foreach (ldap_get_entries($this->ldapHandler, $searchRes) as $entry) {
if ($this->userLogin === $entry['samaccountname'][0]) {
$Log->addDescription(_('Usuario verificado en grupo'));
$Log->writeLog();
$entries = ldap_get_entries($this->ldapHandler, $searchRes);
return true;
foreach ($entries as $entry) {
if (is_array($entry)) {
if ($this->userLogin === strtolower($entry['samaccountname'][0])) {
$Log->addDescription(_('Usuario verificado en grupo'));
$Log->addDetails(_('Grupo'), $groupDN);
$Log->writeLog();
return true;
}
}
}
@@ -158,4 +165,16 @@ class LdapMads extends LdapBase
return false;
}
/**
* @return bool
*/
protected function connect()
{
parent::connect();
@ldap_set_option($this->ldapHandler, LDAP_OPT_REFERRALS, 0);
return true;
}
}

View File

@@ -77,14 +77,11 @@ class LdapStd extends LdapBase
{
$Log = new Log(__FUNCTION__);
$groupDN = $this->getGroupName() ?: $this->group;
$userDN = $this->escapeLdapDN($this->LdapUserData->getDn());
// Comprobar si está establecido el filtro de grupo o el grupo coincide con
// los grupos del usuario
if (!$this->group
|| $this->group === '*'
|| in_array($groupDN, $this->LdapUserData->getGroups())
|| in_array($this->LdapUserData->getGroupDn(), $this->LdapUserData->getGroups())
) {
$Log->addDescription(_('Usuario verificado en grupo'));
$Log->writeLog();
@@ -92,15 +89,18 @@ class LdapStd extends LdapBase
return true;
}
$filter = '(&(cn=' . $groupDN . ')(|(member=' . $userDN . ')(uniqueMember=' . $userDN . '))(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=group)))';
$userDN = $this->LdapUserData->getDn();
$groupName = $this->getGroupName() ?: $this->group;
$filter = '(&(cn=' . $groupName . ')(|(member=' . $userDN . ')(uniqueMember=' . $userDN . '))(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=group)))';
$searchRes = @ldap_search($this->ldapHandler, $this->searchBase, $filter, ['member', 'uniqueMember']);
if (!$searchRes) {
$Log->setLogLevel(Log::ERROR);
$Log->addDescription(_('Error al buscar el grupo de usuarios'));
$Log->addDetails(_('Grupo'), $groupDN);
$Log->addDetails(_('Usuario'), $this->LdapUserData->getDn());
$Log->addDetails(_('Grupo'), $groupName);
$Log->addDetails(_('Usuario'), $userDN);
$Log->addDetails('LDAP ERROR', sprintf('%s (%d)', ldap_error($this->ldapHandler), ldap_errno($this->ldapHandler)));
$Log->addDetails('LDAP FILTER', $filter);
$Log->writeLog();
@@ -110,15 +110,14 @@ class LdapStd extends LdapBase
if (@ldap_count_entries($this->ldapHandler, $searchRes) === 0) {
$Log->addDescription(_('Usuario no pertenece al grupo'));
$Log->addDetails(_('Usuario'), $this->LdapUserData->getDn());
$Log->addDetails(_('Grupo'), $groupDN);
$Log->addDetails(_('Usuario'), $userDN);
$Log->addDetails(_('Grupo'), $groupName);
return false;
}
$Log->addDescription(_('Usuario verificado en grupo'));
$Log->addDescription($groupDN);
$Log->addDescription($filter);
$Log->addDescription($groupName);
$Log->writeLog();
return true;

View File

@@ -254,6 +254,7 @@
<input type="hidden" name="ldap_enabled" value="0"/>
<?php endif; ?>
<input type="hidden" name="type" value="ldap"/>
<input type="hidden" name="activeTab" value="<?php echo $ldap_tabIndex; ?>"/>
<input type="hidden" name="actionId" value="<?php echo $ldap_actionId; ?>"/>
<input type="hidden" name="sk" value="">

View File

@@ -261,6 +261,7 @@
<input type="hidden" name="wiki_enabled" value="1"/>
<?php endif; ?>
<input type="hidden" name="type" value="dokuwiki"/>
<input type="hidden" name="activeTab" value="<?php echo $wiki_tabIndex; ?>"/>
<input type="hidden" name="actionId" value="<?php echo $wiki_actionId; ?>"/>
<input type="hidden" name="sk" value="">

View File

@@ -317,46 +317,25 @@ sysPass.Actions = function (Common) {
log.info("checks:ldap");
var $form = $($obj.data("src"));
var ldapBindPass = $form.find("[name='ldap_bindpass']").val();
var data = {
type: "ldap",
ldap_server: $form.find("[name='ldap_server']").val(),
ldap_base: $form.find("[name='ldap_base']").val(),
ldap_group: $form.find("[name='ldap_group']").val(),
ldap_binduser: $form.find("[name='ldap_binduser']").val(),
ldap_bindpass: Common.config().PK !== "" ? Common.config().CRYPT.encrypt(ldapBindPass) : ldapBindPass,
sk: Common.sk.get(),
isAjax: 1
};
$form.find("[name='sk']").val(Common.sk.get());
var opts = Common.appRequests().getRequestOpts();
opts.url = ajaxUrl.checks;
opts.data = data;
opts.data = $form.serialize();
Common.appRequests().getActionCall(opts, function (json) {
Common.msg.out(json);
});
},
wiki: function ($obj) {
log.info("checks:wiki");
var $form = $($obj.data("src"));
var data = {
type: "dokuwiki",
dokuwiki_url: $form.find("[name='dokuwiki_url']").val(),
dokuwiki_user: $form.find("[name='dokuwiki_user']").val(),
dokuwiki_pass: $form.find("[name='dokuwiki_pass']").val(),
isAjax: 1,
sk: Common.sk.get()
};
$form.find("[name='sk']").val(Common.sk.get());
var opts = Common.appRequests().getRequestOpts();
opts.url = ajaxUrl.checks;
opts.data = data;
opts.data = $form.serialize();
Common.appRequests().getActionCall(opts, function (json) {
Common.msg.out(json);