mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
377 lines
13 KiB
XML
377 lines
13 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
|
|
<classes>
|
|
<class id="UserLDAP" _delta="define">
|
|
<parent>cmdbAbstractObject</parent>
|
|
<php_parent>
|
|
<name>UserInternal</name>
|
|
</php_parent>
|
|
<properties>
|
|
<comment>/**
|
|
* LDAP Authentication
|
|
* User authentication Module, no password at all!
|
|
*
|
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
|
* @license http://opensource.org/licenses/AGPL-3.0
|
|
*/</comment>
|
|
<category>addon/authentication,grant_by_profile,silo</category>
|
|
<abstract>false</abstract>
|
|
<key_type>autoincrement</key_type>
|
|
<db_table>priv_user_ldap</db_table>
|
|
<db_key_field>id</db_key_field>
|
|
<db_final_class_field/>
|
|
<naming>
|
|
<attributes>
|
|
<attribute id="login"/>
|
|
</attributes>
|
|
</naming>
|
|
<style>
|
|
<icon/>
|
|
</style>
|
|
<reconciliation>
|
|
<attributes>
|
|
<attribute id="login"/>
|
|
</attributes>
|
|
</reconciliation>
|
|
</properties>
|
|
<fields>
|
|
<field id="ldap_server" xsi:type="AttributeString">
|
|
<sql>ldap_server</sql>
|
|
<default_value/>
|
|
<is_null_allowed>true</is_null_allowed>
|
|
</field>
|
|
</fields>
|
|
<methods>
|
|
<method id="CheckCredentials">
|
|
<comment><![CDATA[/**
|
|
* Check the user's password against the LDAP server
|
|
* Algorithm:
|
|
* 1) Connect to the LDAP server, using a predefined account (or anonymously)
|
|
* 2) Search for the specified user, based on a specific search query/pattern
|
|
* 3) If exactly one user is found, continue, otherwise return false (wrong user or wrong query configured)
|
|
* 3) Bind again to LDAP using the DN of the found user and the password
|
|
* 4) If the bind is successful return true, otherwise return false (wrong password)
|
|
*
|
|
* @param string $sPassword The user's password to validate against the LDAP server
|
|
*
|
|
* @return boolean True if the password is Ok, false otherwise
|
|
* @throws \ArchivedObjectException
|
|
* @throws \CoreException
|
|
*/]]></comment>
|
|
<static>false</static>
|
|
<access>public</access>
|
|
<type>OQLMenuNode</type>
|
|
<code><![CDATA[ public function CheckCredentials($sPassword)
|
|
{
|
|
$sServer = $this->Get('ldap_server');
|
|
if (empty($sServer))
|
|
{
|
|
$sURI = MetaModel::GetModuleSetting('authent-ldap', 'uri', 'ldap://localhost');
|
|
|
|
$sDefaultLDAPUser = MetaModel::GetModuleSetting('authent-ldap', 'default_user', '');
|
|
$sDefaultLDAPPwd = MetaModel::GetModuleSetting('authent-ldap', 'default_pwd', '');
|
|
$bLDAPStartTLS = MetaModel::GetModuleSetting('authent-ldap', 'start_tls', false);
|
|
|
|
$aOptions = MetaModel::GetModuleSetting('authent-ldap', 'options', array());
|
|
$sLDAPUserQuery = MetaModel::GetModuleSetting('authent-ldap', 'user_query', '');
|
|
$sBaseDN = MetaModel::GetModuleSetting('authent-ldap', 'base_dn', '');
|
|
$bDebug = MetaModel::GetModuleSetting('authent-ldap', 'debug', false);
|
|
}
|
|
else
|
|
{
|
|
$aServers = MetaModel::GetModuleSetting('authent-ldap', 'servers', array());
|
|
if (!array_key_exists($sServer, $aServers))
|
|
{
|
|
$bDebug = MetaModel::GetModuleSetting('authent-ldap', 'debug', false);
|
|
$this->LogIssue($bDebug, "ldap_authentication: bad LDAP server configuration: '$sServer' not found");
|
|
return false;
|
|
}
|
|
$aServerParams = $aServers[$sServer];
|
|
$sURI = $aServerParams['uri'] ?? 'ldap://localhost';
|
|
$sDefaultLDAPUser = isset($aServerParams['default_user']) ? $aServerParams['default_user'] : '';
|
|
$sDefaultLDAPPwd = isset($aServerParams['default_pwd']) ? $aServerParams['default_pwd'] : '';
|
|
$bLDAPStartTLS = isset($aServerParams['start_tls']) ? $aServerParams['start_tls'] : false;
|
|
$aOptions = isset($aServerParams['options']) ? $aServerParams['options'] : array();
|
|
$sLDAPUserQuery = isset($aServerParams['user_query']) ? $aServerParams['user_query'] : '';
|
|
$sBaseDN = isset($aServerParams['base_dn']) ? $aServerParams['base_dn'] : '';
|
|
$bDebug = isset($aServerParams['debug']) ? $aServerParams['debug'] : false;
|
|
}
|
|
|
|
$hDS = @ldap_connect($sURI);
|
|
if ($hDS === false)
|
|
{
|
|
$this->LogIssue($bDebug, "ldap_authentication: can not connect to the LDAP server '$sURI'. Check the configuration file config-itop.php.");
|
|
return false;
|
|
}
|
|
if (array_key_exists(LDAP_OPT_DEBUG_LEVEL, $aOptions))
|
|
{
|
|
// Set debug level before trying to connect, so that debug info appear in the PHP error log if ldap_connect goes wrong
|
|
$bRet = ldap_set_option($hDS, LDAP_OPT_DEBUG_LEVEL, $aOptions[LDAP_OPT_DEBUG_LEVEL]);
|
|
$this->LogInfo($bDebug, "ldap_set_option('LDAP_OPT_DEBUG_LEVEL', '{$aOptions[LDAP_OPT_DEBUG_LEVEL]}') returned ".($bRet ? 'true' : 'false'));
|
|
}
|
|
foreach($aOptions as $name => $value)
|
|
{
|
|
$bRet = ldap_set_option($hDS, $name, $value);
|
|
$this->LogInfo($bDebug, "ldap_set_option('$name', '$value') returned ".($bRet ? 'true' : 'false'));
|
|
}
|
|
if ($bLDAPStartTLS)
|
|
{
|
|
$this->LogInfo($bDebug, "ldap_authentication: start tls required.");
|
|
$hStartTLS = ldap_start_tls($hDS);
|
|
//$this->LogIssue($bDebug, "ldap_authentication: hStartTLS = '$hStartTLS'");
|
|
if (!$hStartTLS)
|
|
{
|
|
$this->LogIssue($bDebug, "ldap_authentication: start tls failed.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if ($bind = @ldap_bind($hDS, $sDefaultLDAPUser, $sDefaultLDAPPwd))
|
|
{
|
|
// Search for the person, using the specified query expression
|
|
$sLogin = $this->Get('login');
|
|
$iContactId = $this->Get('contactid');
|
|
$sFirstName = '';
|
|
$sLastName = '';
|
|
$sEMail = '';
|
|
if ($iContactId > 0)
|
|
{
|
|
$oPerson = MetaModel::GetObject('Person', $iContactId);
|
|
if (is_object($oPerson))
|
|
{
|
|
$sFirstName = $oPerson->Get('first_name');
|
|
$sLastName = $oPerson->Get('name');
|
|
$sEMail = $oPerson->Get('email');
|
|
}
|
|
}
|
|
// %1$s => login
|
|
// %2$s => first name
|
|
// %3$s => last name
|
|
// %4$s => email
|
|
$sQuery = sprintf($sLDAPUserQuery, $sLogin, $sFirstName, $sLastName, $sEMail);
|
|
$hSearchResult = @ldap_search($hDS, $sBaseDN, $sQuery);
|
|
|
|
$iCountEntries = ($hSearchResult !== false) ? @ldap_count_entries($hDS, $hSearchResult) : 0;
|
|
switch($iCountEntries)
|
|
{
|
|
case 1:
|
|
// Exactly one entry found, let's check the password by trying to bind with this user
|
|
$aEntry = @ldap_get_entries($hDS, $hSearchResult);
|
|
$sUserDN = $aEntry[0]['dn'];
|
|
$bUserBind = @ldap_bind($hDS, $sUserDN, $sPassword);
|
|
if (($bUserBind !== false) && !empty($sPassword))
|
|
{
|
|
@ldap_unbind($hDS);
|
|
return true; // Password Ok
|
|
}
|
|
$this->LogIssue($bDebug, "ldap_authentication: wrong password for user: '$sUserDN'.");
|
|
return false; // Wrong password
|
|
break;
|
|
|
|
case 0:
|
|
// User not found...
|
|
$this->LogIssue($bDebug, "ldap_authentication: no entry found with the query '$sQuery', base_dn = '$sBaseDN'. User not found in LDAP.");
|
|
break;
|
|
|
|
default:
|
|
// More than one entry... maybe the query is not specific enough...
|
|
$this->LogIssue($bDebug, "ldap_authentication: several (".@ldap_count_entries($hDS, $hSearchResult).") entries match the query '$sQuery', base_dn = '$sBaseDN', check that the query defined in config-itop.php is specific enough.");
|
|
}
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// Trace: invalid default user for LDAP initial binding
|
|
$this->LogIssue($bDebug, "ldap_authentication: cannot bind to the LDAP server '$sURI', user='$sDefaultLDAPUser', pwd='****'. Error: '".ldap_error($hDS)."'. Check the configuration file config-itop.php.");
|
|
return false;
|
|
}
|
|
}]]></code>
|
|
</method>
|
|
<method id="TrustWebServerContext">
|
|
<static>false</static>
|
|
<access>public</access>
|
|
<type>OQLMenuNode</type>
|
|
<code> public function TrustWebServerContext()
|
|
{
|
|
return false;
|
|
}</code>
|
|
</method>
|
|
<method id="CanChangePassword">
|
|
<static>false</static>
|
|
<access>public</access>
|
|
<type>OQLMenuNode</type>
|
|
<code> public function CanChangePassword()
|
|
{
|
|
return false;
|
|
}</code>
|
|
</method>
|
|
<method id="ChangePassword">
|
|
<static>false</static>
|
|
<access>public</access>
|
|
<type>OQLMenuNode</type>
|
|
<code> public function ChangePassword($sOldPassword, $sNewPassword)
|
|
{
|
|
return false;
|
|
}</code>
|
|
</method>
|
|
<method id="LogIssue">
|
|
<static>false</static>
|
|
<access>protected</access>
|
|
<type>OQLMenuNode</type>
|
|
<code><![CDATA[ protected function LogIssue($bDebug, $sMessage, $aData = array())
|
|
{
|
|
if ($bDebug)
|
|
{
|
|
if (MetaModel::IsLogEnabledIssue() && MetaModel::IsValidClass('EventIssue'))
|
|
{
|
|
$oLog = new EventIssue();
|
|
|
|
$oLog->Set('message', $sMessage);
|
|
$oLog->Set('userinfo', '');
|
|
$oLog->Set('issue', 'LDAP Authentication');
|
|
$oLog->Set('impact', 'User login rejected');
|
|
$oLog->Set('data', $aData);
|
|
$oLog->DBInsertNoReload();
|
|
}
|
|
}
|
|
IssueLog::Error($sMessage);
|
|
}]]></code>
|
|
</method>
|
|
<method id="LogInfo">
|
|
<static>false</static>
|
|
<access>protected</access>
|
|
<type>OQLMenuNode</type>
|
|
<code><![CDATA[ protected function LogInfo($bDebug, $sMessage)
|
|
{
|
|
if ($bDebug)
|
|
{
|
|
IssueLog::Info($sMessage);
|
|
}
|
|
}]]></code>
|
|
</method>
|
|
</methods>
|
|
<presentation>
|
|
<details>
|
|
<items>
|
|
<item id="col:col1">
|
|
<rank>10</rank>
|
|
<items>
|
|
<item id="fieldset:User:info">
|
|
<rank>10</rank>
|
|
<items>
|
|
<item id="contactid">
|
|
<rank>10</rank>
|
|
</item>
|
|
<item id="org_id">
|
|
<rank>20</rank>
|
|
</item>
|
|
<item id="email">
|
|
<rank>30</rank>
|
|
</item>
|
|
<item id="login">
|
|
<rank>40</rank>
|
|
</item>
|
|
<item id="language">
|
|
<rank>50</rank>
|
|
</item>
|
|
<item id="status">
|
|
<rank>60</rank>
|
|
</item>
|
|
</items>
|
|
</item>
|
|
</items>
|
|
</item>
|
|
<item id="col:col2">
|
|
<rank>20</rank>
|
|
<items>
|
|
<item id="fieldset:User:profiles">
|
|
<rank>10</rank>
|
|
<items>
|
|
<item id="profile_list">
|
|
<rank>10</rank>
|
|
</item>
|
|
</items>
|
|
</item>
|
|
<item id="fieldset:UserLDAP:server">
|
|
<rank>20</rank>
|
|
<items>
|
|
<item id="ldap_server">
|
|
<rank>10</rank>
|
|
</item>
|
|
</items>
|
|
</item>
|
|
</items>
|
|
</item>
|
|
<item id="allowed_org_list">
|
|
<rank>80</rank>
|
|
</item>
|
|
<item id="log">
|
|
<rank>90</rank>
|
|
</item>
|
|
</items>
|
|
</details>
|
|
<search>
|
|
<items>
|
|
<item id="login">
|
|
<rank>10</rank>
|
|
</item>
|
|
<item id="contactid">
|
|
<rank>20</rank>
|
|
</item>
|
|
<item id="status">
|
|
<rank>30</rank>
|
|
</item>
|
|
<item id="org_id">
|
|
<rank>40</rank>
|
|
</item>
|
|
<item id="ldap_server">
|
|
<rank>50</rank>
|
|
</item>
|
|
</items>
|
|
</search>
|
|
<list>
|
|
<items>
|
|
<item id="first_name">
|
|
<rank>10</rank>
|
|
</item>
|
|
<item id="last_name">
|
|
<rank>20</rank>
|
|
</item>
|
|
<item id="status">
|
|
<rank>30</rank>
|
|
</item>
|
|
<item id="org_id">
|
|
<rank>40</rank>
|
|
</item>
|
|
<item id="ldap_server">
|
|
<rank>50</rank>
|
|
</item>
|
|
</items>
|
|
</list>
|
|
</presentation>
|
|
</class>
|
|
</classes>
|
|
<meta>
|
|
<classes>
|
|
<class id="UserInternal" _delta="define_if_not_exists">
|
|
<fields>
|
|
<field id="contactid" xsi:type="AttributeExternalKey">
|
|
<target_class>Contact</target_class>
|
|
</field>
|
|
<field id="first_name" xsi:type="AttributeExternalField"/>
|
|
<field id="last_name" xsi:type="AttributeExternalField"/>
|
|
<field id="status" xsi:type="AttributeEnum"/>
|
|
<field id="org_id" xsi:type="AttributeExternalField"/>
|
|
<field id="email" xsi:type="AttributeExternalField"/>
|
|
<field id="login" xsi:type="AttributeString"/>
|
|
<field id="language" xsi:type="AttributeApplicationLanguage"/>
|
|
<field id="status" xsi:type="AttributeEnum"/>
|
|
<field id="allowed_org_list" xsi:type="AttributeLinkedSetIndirect"/>
|
|
<field id="profile_list" xsi:type="AttributeLinkedSetIndirect"/>
|
|
<field id="log" xsi:type="AttributeCaseLog"/>
|
|
</fields>
|
|
</class>
|
|
</classes>
|
|
</meta>
|
|
</itop_design>
|