SMF 2 и ldap

Автор ops2012, 18 января 2012, 17:13:32

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

ops2012

Добрый день.
Кто-нибудь смог интегрировать smf2 и ldap( active directory )? Необходимая вещь для корпоративных форумов, а нету. Единственный мод был написан psa и только под первую версию. Сейчас я допилил до работоспособности авторизацию на smf2. Взять архив можно тут http://ifolder.ru/28178991 . Там оригинальные файлы от psa, исправленный LdapAuth.php под вторую версию, diff для нескольких файлов форума.
Кто-нибудь может помочь со всем этим делом? php я второй раз в жизни крутил, наверняка ошибся где-то. Если по пунктам, в чём нужна помощь:

  • Посмотреть сам код - он вообще нормальный или нет.
  • Не сохраняются ldap settings из админки почему-то. Что исправлять.
  • Прикрутить кастомные поля в профиль. Так что бы в админке можно было указывать какое поле брать из ldap ( например тот же location, telephone,...).
  • Возможно надо выкинуть кусок отвечающий за возможность из админки завести пользователя ldap?
  • Собрать из этот нормальный мод, как минимум.
По хорошему, конечно, надо интегрировать ldap в smf. Кто-нибудь общался на эту тему с разработчиками?

Это ещё только начальный этап. После нормального решения у меня есть желание сделать авторизацию через керберос - SSO это очень хорошая вещь.

ops2012

Код я допилил и добавил возможность использовать ldap uid ( в MSAD это objetsid). Самый простой вариант - добавил  колонку в таблицу members.
Может кто расскажет как правильней кастомные поля прикрутить? Правильно я понимаю что эти поля хранятся в таблице themes? Почему не сделали отдельную таблицу под это дело, похожую по структуре на таблицу members? Было бы проще, или тут я ошибаюсь? Мне, по хорошему, надо добавлять кастомное поле и где-то указывать из каких атрибутов ldap его собирать. В какую таблицу это засунуть, что бы было правильно?

ops2012

Ok. Сделал поддержку kerberos+MSAD - кривовато похоже, но пойдёт. Если никому не интересно пойду в соседнем "отделе" узнаю надо ли это.

Mavn

выложили бы здесь файлы и инструкцию куда чего писать тогда думаю было бы интересно кому то
SimpleMachines Russian Community Team
п.1 Пройду курсы гадалок для определения исходного кода по скриншоту.

п.2 У вас нет желания читать правила раздела, у меня нет желания одобрять темы, которые не соответствуют этим правилам.

ops2012

Ок. Просто с керберосом были ещё заморочки.
Итак приступим. По LDAP: для начала сам файл LdapAuth.php , который надо кинуть в каталог Source
<?php//	ldapauth_enable -- will prevent anything from being done if not set//	ldapauth_serverurl -- 'ldap://yourldapserver';//	ldapauth_usersuffix -- with MSAD will be set to '@yourdomain.yourtld';//	ldapauth_userprefix -- useful in conjunction with ldapauth_usersuffix to create a dn-based login//	ldapauth_searchdn -- 'OU=Your Users,DC=yourdomain,DC=yourtld';//	ldapauth_searchKey -- for MSAD will be 'sAMAccountName';//	ldapauth_emailuselogin -- set to indicate that ldapauth_emailsuffix should be used //	ldapauth_emailsuffix -- added to the login username to create the users' email addresses//	ldapauth_emailattr -- if not using ldapauth_emailsuffix, the attribute in ldap to be used for the email addresses//	ldapauth_locationuseou -- use the top level ou as the users' locations//	ldapauth_locationattr -- if not using ldapauth_locationuseou, the attribute in ldap to be used for the locations//	ldapauth_updateonlogin -- set to indicate that the user's information should be updated on every login//	ldapauth_fullnameattr -- the attribute in ldap to be used for the fullname (cn for MSAD); required//	ldapauth_regresnames -- set to indicate that ldap auth should autoregister/update users with reserved name logins//	ldapauth_authresnames -- set to indicate that ldap auth should authenticate users with reserved name logins//	ldapauth_passwdindb -- set to indicate that ldap passwords should be stored in the local database//	ldapauth_uidattr -- the attribute in ldap to be used for the UID (objectsid for MSAD)//TODO much error handling, especially where connections and queries fail, or the user has bad or missing settingsfunction smf_ldap_auth($username, $password, $seconds){	global $db_prefix, $user_info, $modSettings, $func, $txt, $sourcedir, $smcFunc;	require_once($sourcedir . '/Subs-Members.php');	if (!isset($modSettings['ldapauth_enable']) || !$modSettings['ldapauth_enable'])		return false;	if ((!isset($modSettings['ldapauth_authresnames']) || !$modSettings['ldapauth_authresnames']) && isReservedName($username))		return false;	// We can use the password passed in since we abandoned the integration hack	$thepasswrd = $password;	$lattributes = explode(',', $modSettings['ldapauth_fullnameattr']);	if (isset($modSettings['ldapauth_emailattr']) && !empty($modSettings['ldapauth_emailattr']))		$lattributes[] = $modSettings['ldapauth_emailattr'];	if (isset($modSettings['ldapauth_locationattr']) && !empty($modSettings['ldapauth_locationattr']))		$lattributes[] = $modSettings['ldapauth_locationattr'];	if (isset($modSettings['ldapauth_uidattr']) && !empty($modSettings['ldapauth_uidattr']))		$lattributes[] = $modSettings['ldapauth_uidattr'];	$sha_passwd = sha1(strtolower($username) . un_htmlspecialchars(stripslashes($thepasswrd)));	if ($lds = ldap_connect($modSettings['ldapauth_serverurl']))	{		// these next two are required for recent versions of MSAD, 		// but may need tweak options for other ldap servers		ldap_set_option($lds, LDAP_OPT_PROTOCOL_VERSION, 3);		ldap_set_option($lds, LDAP_OPT_REFERRALS, 0);		// if using an application account to pre-bind, find the user's DN with the pre-bind account		$userDN = "";		if (isset($modSettings['ldapauth_bindusername']) && $modSettings['ldapauth_bindusername'])		{			if ($bd = ldap_bind($lds, $modSettings['ldapauth_bindusername'], $modSettings['ldapauth_bindpassword']))			{				log_error("Bound with " . $modSettings['ldapauth_bindusername']);				$results=ldap_search($lds, $modSettings['ldapauth_searchdn'], "(|({$modSettings['ldapauth_searchkey']}=$username))");				$lentries = ldap_get_entries($lds, $results);				$found = $lentries['count'];				if(!$found) // if the user was not found in LDAP				{					log_error("Username $username not found in LDAP.");					return false;				}				else // The user was found in LDAP. So get his DN from ldapauth_locationattr.				{					log_error("Username $username found in LDAP. Continuing...");					$userDN = $lentries[0]['dn'];				}				ldap_unbind($lds);				$lds = ldap_connect($modSettings['ldapauth_serverurl']);				ldap_set_option($lds, LDAP_OPT_PROTOCOL_VERSION, 3);				ldap_set_option($lds, LDAP_OPT_REFERRALS, 0);			}		}		if(!$userDN) $userDN = $modSettings['ldapauth_userprefix'] . $username . $modSettings['ldapauth_usersuffix'];		//clear passwd if we're not going to store it in the db		if (isset($modSettings['ldapauth_passwdindb']) && !$modSettings['ldapauth_passwdindb'])			$sha_passwd = "LDAPOnly";		if ($bd = ldap_bind($lds,  $userDN, $thepasswrd))		{		//login success		log_error('Bound with '.$username);			$lentries = ldap_get_entries($lds, ldap_search($lds, $modSettings['ldapauth_searchdn'], "({$modSettings['ldapauth_searchkey']}=$username)", $lattributes));			//verify user exests by ldap uid and update memeber_name if changed			if (isset($modSettings['ldapauth_uidattr']) && !empty($modSettings['ldapauth_uidattr']))			{				$luid = bin_to_str_sid($lentries[0][$modSettings['ldapauth_uidattr']][0]);				$request = $smcFunc['db_query']('', '					SELECT id_member					FROM {db_prefix}members					WHERE ' . 'ldapattr_uid = {string:lid_member}' . '					LIMIT 1',					array(						'lid_member' => $luid,					)				);				if (($smcFunc['db_num_rows']($request) > 0) && !strcmp($username, $cresult['member_name']))				{					$cresult = $smcFunc['db_fetch_assoc']($request);					updateMemberData($cresult['id_member'], array('member_name' => $username));				}				$smcFunc['db_free_result']($request);			}			//verify user exists in forum user database			$request = $smcFunc['db_query']('', '				SELECT id_member				FROM {db_prefix}members				WHERE ' . ($smcFunc['db_case_sensitive'] ? 'LOWER(member_name) = LOWER({string:user_name})' : 'member_name = {string:user_name}') . '				LIMIT 1',				array(					'user_name' => $smcFunc['db_case_sensitive'] ? strtolower($username) : $username,				)			);			//if this isn't set we won't authenticate a reserved name that isn't already registered			if ((!isset($modSettings['ldapauth_regresnames']) || !$modSettings['ldapauth_regresnames']) && isReservedName($username) && $smcFunc['db_num_rows']($request) == 0)				return false;			//Hairy!			// IF 			// (			// 	the user isn't already registered 			// 	OR 			//	(			//		updateonlogin is set 			//		AND 			//		updateonlogin is true			//	)			// )			// AND 			// (			//	(			//		regresnames is set 			//		AND 			//		regresname is true			//	) 			//	OR 			//	the username is NOT reserved			// )			if (($smcFunc['db_num_rows']($request) == 0 || (isset($modSettings['ldapauth_updateonlogin']) && $modSettings['ldapauth_updateonlogin'])) && ((isset($modSettings['ldapauth_regresnames']) && $modSettings['ldapauth_regresnames']) || !isReservedName($username)))			{				// We're going to update or add the user, so setup the data we need				// Get user's full name (and possibly email address & location) from the directory				if (isset($modSettings['ldapauth_locationuseou']) && $modSettings['ldapauth_locationuseou'])				{					// Parse the highest level Organizational Unit as their location					$i1 = strrpos($lentries[0]["dn"],'OU=')+3;					$i2 = strpos($lentries[0]["dn"],',DC=',$i1);					$llocation = substr($lentries[0]["dn"],$i1,$i2-$i1);				}				else if (isset($modSettings['ldapauth_locationattr']) && !empty($modSettings['ldapauth_locationattr'])) {					$llocation = '';					$ldapauth_loc = explode(',', $modSettings['ldapauth_locationattr']);					foreach ($ldapauth_loc as $value) {						$llocation .= $lentries[0][$value][0] . ' ';					}					$llocation = chop ($llocation);				 }				else $llocation = '';				if (isset($modSettings['ldapauth_emailuselogin']) && $modSettings['ldapauth_emailuselogin']) 					$lmail = $username . (isset($modSettings['ldapauth_emailsuffix']) ? $modSettings['ldapauth_emailsuffix'] : '');				else if (isset($modSettings['ldapauth_emailattr']) && !empty($modSettings['ldapauth_emailattr']))					$lmail = $lentries[0][$modSettings['ldapauth_emailattr']][0];				else $lmail = '';				//email checking courtesy of Subs-Members.php				if (empty($lmail) || preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', stripslashes($lmail)) === 0 || strlen(stripslashes($lmail)) > 255)                		{					log_error(sprintf($txt['valid_email_needed'], $username));					$lmail = '';	// we will let this go, although SMF doesn't really like missing email addresses				}				$thelocation = $smcFunc['htmlspecialchars']($llocation);				$lrealname = '';				$ldapauth_rname = explode(',', $modSettings['ldapauth_fullnameattr']);				foreach ($ldapauth_rname as $value) {					$lrealname .= $lentries[0][$value][0] .' ';				}				$lrealname = chop ($lrealname);				$therealname = $smcFunc['htmlspecialchars']($lrealname);				if ($smcFunc['db_num_rows']($request) > 0)				{					// User actually exists, so only update ldap-changeable data					$cresult = $smcFunc['db_fetch_assoc']($request);					updateMemberData($cresult['id_member'], array('passwd' => $sha_passwd, 'email_address' => $lmail,'real_name' => $therealname, 'location' => $thelocation));					ldap_close($lds);					$smcFunc['db_free_result']($request);					// tells LogInOut.php not to check passwd, since we already found it to be good					return true;				} else {			log_error('Not Bound with user ' . $username);}				// User does not exist in SMF database - create				$regOptions = array(					'interface' => 'guest',					'username' => $username,					'email' => $lmail,					'password' => $sha_passwd,					'require' => 'nothing',					'password_check' => $sha_passwd,					'validation_code' => "''",					'check_reserved_name' => true,					'check_password_strength' => false,					'check_email_ban' => true,					'send_welcome_email' => !empty($modSettings['send_welcomeEmail']),				);				$memberID = registerMember($regOptions);				updateMemberData($memberID, array('location' => $thelocation, 'real_name' => $therealname, 'passwd' => $sha_passwd));				if (isset($modSettings['ldapauth_uidattr']) && !empty($modSettings['ldapauth_uidattr']))				{					$luid = bin_to_str_sid($lentries[0][$modSettings['ldapauth_uidattr']][0]);					updateMemberData($memberID, array('ldapattr_uid' => $luid));				}				updateStats('member');				// If it's enabled, increase the registrations for today.				trackStats(array('registers' => '+'));				// Actually, this is the entry, not the results, which are anonymous.  				// Oh well, it'll be freed once the page is served anyway.			}			else				if (!isset($modSettings['ldapauth_passwdindb']) || $modSettings['ldapauth_passwdindb'])				{					// User does exist (or it's reserved and we've set the option not to update data for reserved names, 					// but we'll update the password in case it's changed					$cresult = $smcFunc['db_fetch_assoc']($result);					updateMemberData($cresult['id_member'], array('passwd' => $sha_passwd));				}			ldap_close($lds);			$smcFunc['db_free_result']($request);			// tells LogInOut.php not to check passwd, since we already found it to be good			return true;		}	}	ldap_close($lds);	// allow authentication fallthrough to other methods (local database hashes of various kinds, by default)	return false;}// Returns the textual SIDfunction bin_to_str_sid($binsid) {    $hex_sid = bin2hex($binsid);    $rev = hexdec(substr($hex_sid, 0, 2));    $subcount = hexdec(substr($hex_sid, 2, 2));    $auth = hexdec(substr($hex_sid, 4, 12));    $result    = "$rev-$auth";    for ($x=0;$x < $subcount; $x++) {        $subauth[$x] =             hexdec(little_endian(substr($hex_sid, 16 + ($x * 8), 8)));        $result .= "-" . $subauth[$x];    }    // Cheat by tacking on the S-    return 'S-' . $result;}// Converts a little-endian hex-number to one, that 'hexdec' can convertfunction little_endian($hex) {    for ($x = strlen($hex) - 2; $x >= 0; $x = $x - 2) {        $result .= substr($hex, $x, 2);    }    return $result;}?>


ops2012

Прогнанный diff по оригинальному smf-2.0.2 и изменённому, по всем файлам.
diff -u -r /home/user/temp/smf-2.0.2/index.php /var/www/html/forum/index.php
--- /home/user/temp/smf-2.0.2/index.php 2011-12-22 20:12:36.000000000 +0400
+++ /var/www/html/forum/index.php 2012-02-02 12:50:26.137801421 +0400
@@ -168,6 +169,16 @@
// Load the user's cookie (or set as guest) and load their settings.
loadUserSettings();

+// Kerberos hack - autologin
+if ($modSettings['kerbauth_enable'] && $user_info['is_guest'] && isset($_SERVER['REMOTE_USER'])) {
+ list($kerbuser, $realm) = explode("@", strtolower($_SERVER['REMOTE_USER']));
+ $_POST['user'] = $kerbuser;
+ // Hack for empty password in kerberos
+ $_POST['passwrd'] = "LDAPOnly";
+ require_once($sourcedir . '/LogInOut.php');
+ Login2();
+}
+
// Load the current board's information.
loadBoard();

diff -u -r /home/user/temp/smf-2.0.2/Sources/Admin.php /var/www/html/forum/Sources/Admin.php
--- /home/user/temp/smf-2.0.2/Sources/Admin.php 2011-06-05 06:29:00.000000000 +0400
+++ /var/www/html/forum/Sources/Admin.php 2012-02-02 13:09:41.400143124 +0400
@@ -129,6 +129,7 @@
'subsections' => array(
'basic' => array($txt['mods_cat_features']),
'layout' => array($txt['mods_cat_layout']),
+ 'ldapauth' => array($txt['mods_cat_ldapauth']),
'karma' => array($txt['karma'], 'enabled' => in_array('k', $context['admin_features'])),
'sig' => array($txt['signature_settings_short']),
'profile' => array($txt['custom_profile_shorttitle'], 'enabled' => in_array('cp', $context['admin_features'])),
diff -u -r /home/user/temp/smf-2.0.2/Sources/LogInOut.php /var/www/html/forum/Sources/LogInOut.php
--- /home/user/temp/smf-2.0.2/Sources/LogInOut.php 2011-06-05 06:29:00.000000000 +0400
+++ /var/www/html/forum/Sources/LogInOut.php 2012-02-02 13:07:25.237979347 +0400
@@ -207,6 +204,17 @@
}

// Are we using any sort of integration to validate the login?
+
+ // Call smf_ldap_auth() or smf_kerb_auth() to prepopulate table. Fallback on LDAP authentication if we enter login from form.
+ if ($modSettings['ldapauth_enable'] && $modSettings['kerbauth_enable'] && isset($_SERVER['REMOTE_USER'])) {
+ require_once($sourcedir . '/KerbAuth.php');
+ $ext_auth = smf_kerb_auth($_POST['user'], $_POST['passwrd'], $modSettings['cookieTime']);
+ }
+ else {
+ require_once($sourcedir . '/LdapAuth.php');
+ $ext_auth = smf_ldap_auth($_POST['user'], $_POST['passwrd'], $modSettings['cookieTime']);
+ }
+
if (in_array('retry', call_integration_hook('integrate_validate_login', array($_POST['user'], isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) == 40 ? $_POST['hash_passwrd'] : null, $modSettings['cookieTime'])), true))
{
$context['login_errors'] = array($txt['login_hash_error']);
@@ -289,7 +297,7 @@
$sha_passwd = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd']));

// Bad password!  Thought you could fool the database?!
- if ($user_settings['passwd'] != $sha_passwd)
+ if ($user_settings['passwd'] != $sha_passwd && !$ext_auth)
{
// Let's be cautious, no hacking please. thanx.
validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']);
diff -u -r /home/user/temp/smf-2.0.2/Sources/ManageSettings.php /var/www/html/forum/Sources/ManageSettings.php
--- /home/user/temp/smf-2.0.2/Sources/ManageSettings.php 2011-06-05 06:29:00.000000000 +0400
+++ /var/www/html/forum/Sources/ManageSettings.php 2012-02-02 13:10:55.301317701 +0400
@@ -97,6 +97,7 @@

$subActions = array(
'basic' => 'ModifyBasicSettings',
+ 'ldapauth' => 'ModifyLdapAuthSettings',
'layout' => 'ModifyLayoutSettings',
'karma' => 'ModifyKarmaSettings',
'sig' => 'ModifySignatureSettings',
@@ -114,6 +115,8 @@
'tabs' => array(
'basic' => array(
),
+ 'ldapauth' => array(
+ ),
'layout' => array(
),
'karma' => array(
@@ -2056,4 +2058,51 @@
prepareDBSettingContext($config_vars);
}

-?>
\ В конце файла нет новой строки
+
+// Function to load template/modify Ldap Authentication settings
+function ModifyLdapAuthSettings($return_config = false)
+{
+ global $context, $txt, $scripturl, $settings, $modSettings, $db_prefix, $helptxt;
+
+ $config_vars = array(
+ array('check', 'ldapauth_enable'),
+// array('check', 'kerbauth_enable'),
+ array('text', 'ldapauth_serverurl'),
+ array('text', 'ldapauth_searchdn', '40'),
+ array('text', 'ldapauth_searchkey'),
+ array('text', 'ldapauth_uidattr'),
+ array('check', 'ldapauth_authresnames'),
+ array('check', 'ldapauth_regresnames'),
+ array('text', 'ldapauth_fullnameattr'),
+ array('text', 'ldapauth_uidattr'),
+ array('check', 'ldapauth_emailuselogin'),
+ array('text', 'ldapauth_emailsuffix'),
+ array('text', 'ldapauth_emailattr'),
+ array('check', 'ldapauth_locationuseou'),
+ array('text', 'ldapauth_locationattr'),
+ array('check', 'ldapauth_updateonlogin'),
+ array('check', 'ldapauth_passwdindb'),
+ array('text', 'ldapauth_bindusername'),
+ array('password', 'ldapauth_bindpassword')
+ );
+
+ if ($return_config)
+ return $config_vars;
+
+ // Saving?
+ if (isset($_GET['save']))
+ {
+ checkSession();
+ saveDBSettings($config_vars);
+ writeLog();
+
+ redirectexit('action=admin;area=featuresettings;sa=ldapauth');
+ }
+
+ $context['post_url'] = $scripturl . '?action=admin;area=featuresettings;save;sa=ldapauth';
+ $context['settings_title'] = $txt['ldapauth_Title'];
+
+ prepareDBSettingContext($config_vars);
+
+}
+?>
diff -u -r /home/user/temp/smf-2.0.2/Sources/Profile-Modify.php /var/www/html/forum/Sources/Profile-Modify.php
--- /home/user/temp/smf-2.0.2/Sources/Profile-Modify.php 2011-11-30 04:44:21.000000000 +0400
+++ /var/www/html/forum/Sources/Profile-Modify.php 2012-01-24 11:43:00.085606711 +0400
@@ -273,7 +273,7 @@
'),
),
'email_address' => array(
- 'type' => 'text',
+ 'type' => (isset($modSettings['ldapauth_enable']) || $modSettings['ldapauth_enable']) && !allowedTo('admin_forum') ? 'label' : 'text',
'label' => $txt['email'],
'subtext' => $txt['valid_email'],
'log_change' => true,
@@ -427,7 +427,7 @@
'),
),
'location' => array(
- 'type' => 'text',
+ 'type' => (isset($modSettings['ldapauth_enable']) || $modSettings['ldapauth_enable']) && !allowedTo('admin_forum') ? 'label' : 'text',
'label' => $txt['location'],
'log_change' => true,
'size' => 50,
@@ -489,7 +489,7 @@
'subtext' => $txt['password_strength'],
'size' => 20,
'value' => '',
- 'enabled' => empty($cur_profile['openid_uri']),
+ 'enabled' => empty($cur_profile['openid_uri']) && !((isset($modSettings['ldapauth_enable']) || $modSettings['ldapauth_enable']) && !allowedTo('admin_forum')),
'permission' => 'profile_identity',
'save_key' => 'passwd',
// Note this will only work if passwrd2 also exists!
@@ -520,7 +520,7 @@
'passwrd2' => array(
'type' => 'password',
'label' => $txt['verify_pass'],
- 'enabled' => empty($cur_profile['openid_uri']),
+ 'enabled' => empty($cur_profile['openid_uri']) && !((isset($modSettings['ldapauth_enable']) || $modSettings['ldapauth_enable']) && !allowedTo('admin_forum')),
'size' => 20,
'value' => '',
'permission' => 'profile_identity',
@@ -600,6 +600,7 @@
'secret_question' => array(
'type' => 'text',
'label' => $txt['secret_question'],
+ 'enabled' => !((isset($modSettings['ldapauth_enable']) || $modSettings['ldapauth_enable']) && !allowedTo('admin_forum')),
'subtext' => $txt['secret_desc'],
'size' => 50,
'permission' => 'profile_identity',
@@ -607,6 +608,7 @@
'secret_answer' => array(
'type' => 'text',
'label' => $txt['secret_answer'],
+ 'enabled' => !((isset($modSettings['ldapauth_enable']) || $modSettings['ldapauth_enable']) && !allowedTo('admin_forum')),
'subtext' => $txt['secret_desc2'],
'size' => 20,
'postinput' => '<span class="smalltext" style="margin-left: 4ex;"><a href="' . $scripturl . '?action=helpadmin;help=secret_why_blank" onclick="return reqWin(this.href);">' . $txt['secret_why_blank'] . '</a></span>',
diff -u -r /home/user/temp/smf-2.0.2/Sources/Profile.php /var/www/html/forum/Sources/Profile.php
--- /home/user/temp/smf-2.0.2/Sources/Profile.php 2011-06-05 06:29:00.000000000 +0400
+++ /var/www/html/forum/Sources/Profile.php 2012-01-24 12:48:20.495600311 +0400
@@ -164,7 +164,7 @@
'function' => 'account',
'enabled' => $context['user']['is_admin'] || ($cur_profile['id_group'] != 1 && !in_array(1, explode(',', $cur_profile['additional_groups']))),
'sc' => 'post',
- 'password' => true,
+ 'password' => !(isset($modSettings['ldapauth_enable']) || $modSettings['ldapauth_enable']),
'permission' => array(
'own' => array('profile_identity_any', 'profile_identity_own', 'manage_membergroups'),
'any' => array('profile_identity_any', 'manage_membergroups'),
@@ -469,7 +469,7 @@

// All the subactions that require a user password in order to validate.
$check_password = $context['user']['is_owner'] && in_array($profile_include_data['current_area'], $context['password_areas']);
- $context['require_password'] = $check_password && empty($user_settings['openid_uri']);
+ $context['require_password'] = $check_password && (empty($user_settings['openid_uri'])  && !((isset($modSettings['ldapauth_enable']) || $modSettings['ldapauth_enable']) && !allowedTo('admin_forum')));

// If we're in wireless then we have a cut down template...
if (WIRELESS && $context['sub_template'] == 'summary' && WIRELESS_PROTOCOL != 'wap')

ops2012

Теперь bad news. Не было времени, совершенно, чтобы разбираться с кастомными полями в профиле. Поэтому пришлось поломать таблицу smf_members - для добавления поля UID. Поле текстовое ldapattr_uid. Если кто поможет переделать, так чтобы хранилось в дополнительном поле профиля, но так чтобы никто не мог это поле поправить - тому моё спасибо.
Очень хочется использовать возможность выдёргивать любую информацию из ldap и кидать её в нужное поле профиля. С ходу не нашёл это место. Но идея простая. Если установлена LDAP аутентификация, то показывать дополнительное текстовое поле. В нём можно будет выставить ldap атрибуты. Если поле непустое, то ldap запрос вытаскивает инфу с сервера ldap и кидает в базу и поле запрещено для правки.
Сейчас кину керберос часть. И конечно там опять дублирование функций идёт. Времени на вынос в функции пока нет.

ops2012

Файл KerbAuth.php - кидать опять же в каталог Source.
<?php//	kerbauth_enable -- will prevent anything from being done if not set//	ldapauth_enable -- will prevent anything from being done if not set//	ldapauth_serverurl -- 'ldap://yourldapserver';//	ldapauth_usersuffix -- with MSAD will be set to '@yourdomain.yourtld';//	ldapauth_userprefix -- useful in conjunction with ldapauth_usersuffix to create a dn-based login//	ldapauth_searchdn -- 'OU=Your Users,DC=yourdomain,DC=yourtld';//	ldapauth_searchKey -- for MSAD will be 'sAMAccountName';//	ldapauth_emailuselogin -- set to indicate that ldapauth_emailsuffix should be used //	ldapauth_emailsuffix -- added to the login username to create the users' email addresses//	ldapauth_emailattr -- if not using ldapauth_emailsuffix, the attribute in ldap to be used for the email addresses//	ldapauth_locationuseou -- use the top level ou as the users' locations//	ldapauth_locationattr -- if not using ldapauth_locationuseou, the attribute in ldap to be used for the locations//	ldapauth_updateonlogin -- set to indicate that the user's information should be updated on every login//	ldapauth_fullnameattr -- the attribute in ldap to be used for the fullname (cn for MSAD); required//	ldapauth_regresnames -- set to indicate that ldap auth should autoregister/update users with reserved name logins//	ldapauth_authresnames -- set to indicate that ldap auth should authenticate users with reserved name logins//	ldapauth_passwdindb -- set to indicate that ldap passwords should be stored in the local database//	ldapauth_uidattr -- the attribute in ldap to be used for the UID (objectsid for MSAD)//TODO much error handling, especially where connections and queries fail, or the user has bad or missing settingsfunction smf_kerb_auth($username, $password, $seconds){	global $db_prefix, $user_info, $modSettings, $func, $txt, $sourcedir, $smcFunc;	require_once($sourcedir . '/Subs-Members.php');	if (!isset($modSettings['ldapauth_enable']) || !$modSettings['ldapauth_enable'] || !isset($modSettings['kerbauth_enable']) || !$modSettings['kerbauth_enable'])		return false;	if ((!isset($modSettings['ldapauth_authresnames']) || !$modSettings['ldapauth_authresnames']) && isReservedName($username))		return false;	if (!isset($_SERVER['REMOTE_USER']))	{		log_error("apache don't setup for kerberos");		return false;	}	// Set kerberos username and REALM from apache. kick REALM//	list($kerbuser, $realm) = explode("@", strtolower($_SERVER['REMOTE_USER']));	//	if ($kerbuser !== $username) {//		$user_info['is_guest']=true;//		return false;//	}	// We can use the password passed in since we abandoned the integration hack	$thepasswrd = $password;	$lattributes = explode(',', $modSettings['ldapauth_fullnameattr']);	if (isset($modSettings['ldapauth_emailattr']) && !empty($modSettings['ldapauth_emailattr']))		$lattributes[] = $modSettings['ldapauth_emailattr'];	if (isset($modSettings['ldapauth_locationattr']) && !empty($modSettings['ldapauth_locationattr']))		$lattributes[] = $modSettings['ldapauth_locationattr'];	if (isset($modSettings['ldapauth_uidattr']) && !empty($modSettings['ldapauth_uidattr']))		$lattributes[] = $modSettings['ldapauth_uidattr'];	$sha_passwd = sha1(strtolower($username) . un_htmlspecialchars(stripslashes($thepasswrd)));	if ($lds = ldap_connect($modSettings['ldapauth_serverurl']))	{		// these next two are required for recent versions of MSAD, 		// but may need tweak options for other ldap servers		ldap_set_option($lds, LDAP_OPT_PROTOCOL_VERSION, 3);		ldap_set_option($lds, LDAP_OPT_REFERRALS, 0);		// if using an application account to pre-bind, find the user's DN with the pre-bind account		$userDN = "";		if (isset($modSettings['ldapauth_bindusername']) && $modSettings['ldapauth_bindusername'])		{			if ($bd = ldap_bind($lds, $modSettings['ldapauth_bindusername'], $modSettings['ldapauth_bindpassword']))			{				log_error("Bound with " . $modSettings['ldapauth_bindusername']);				$results=ldap_search($lds, $modSettings['ldapauth_searchdn'], "(|({$modSettings['ldapauth_searchkey']}=$username))");				$lentries = ldap_get_entries($lds, $results);				$found = $lentries['count'];				if(!$found) // if the user was not found in LDAP				{					log_error("Username $username not found in LDAP.");					ldap_unbind($lds);					return false;				}				log_error("Username $username found in LDAP. Continuing...");				$userDN = $lentries[0]['dn'];			}		}		if(!$userDN) $userDN = $modSettings['ldapauth_userprefix'] . $username . $modSettings['ldapauth_usersuffix'];		//clear passwd if we're not going to store it in the db		if (isset($modSettings['ldapauth_passwdindb']) && !$modSettings['ldapauth_passwdindb'])			$sha_passwd = "LDAPOnly";log_error('Bound with '.$username);			$lentries = ldap_get_entries($lds, ldap_search($lds, $modSettings['ldapauth_searchdn'], "({$modSettings['ldapauth_searchkey']}=$username)", $lattributes));			//verify user exests by ldap uid and update memeber_name if changed			if (isset($modSettings['ldapauth_uidattr']) && !empty($modSettings['ldapauth_uidattr']))			{				$luid = bin_to_str_sid($lentries[0][$modSettings['ldapauth_uidattr']][0]);				$request = $smcFunc['db_query']('', '					SELECT id_member					FROM {db_prefix}members					WHERE ' . 'ldapattr_uid = {string:lid_member}' . '					LIMIT 1',					array(						'lid_member' => $luid,					)				);				if (($smcFunc['db_num_rows']($request) > 0) && !strcmp($username, $cresult['member_name']))				{						$cresult = $smcFunc['db_fetch_assoc']($request);						updateMemberData($cresult['id_member'], array('member_name' => $username));				}				$smcFunc['db_free_result']($request);			}			//verify user exists in forum user database			$request = $smcFunc['db_query']('', '				SELECT id_member				FROM {db_prefix}members				WHERE ' . ($smcFunc['db_case_sensitive'] ? 'LOWER(member_name) = LOWER({string:user_name})' : 'member_name = {string:user_name}') . '				LIMIT 1',				array(					'user_name' => $smcFunc['db_case_sensitive'] ? strtolower($username) : $username,				)			);			//if this isn't set we won't authenticate a reserved name that isn't already registered			if ((!isset($modSettings['ldapauth_regresnames']) || !$modSettings['ldapauth_regresnames']) && isReservedName($username) && $smcFunc['db_num_rows']($request) == 0)				return false;			//Hairy!			// IF 			// (			// 	the user isn't already registered 			// 	OR 			//	(			//		updateonlogin is set 			//		AND 			//		updateonlogin is true			//	)			// )			// AND 			// (			//	(			//		regresnames is set 			//		AND 			//		regresname is true			//	) 			//	OR 			//	the username is NOT reserved			// )			if (($smcFunc['db_num_rows']($request) == 0 || (isset($modSettings['ldapauth_updateonlogin']) && $modSettings['ldapauth_updateonlogin'])) && ((isset($modSettings['ldapauth_regresnames']) && $modSettings['ldapauth_regresnames']) || !isReservedName($username)))			{				// We're going to update or add the user, so setup the data we need				// Get user's full name (and possibly email address & location) from the directory//				$lentries = ldap_get_entries($lds, ldap_search($lds, $modSettings['ldapauth_searchdn'], "({$modSettings['ldapauth_searchkey']}=$username)", $lattributes));				if (isset($modSettings['ldapauth_locationuseou']) && $modSettings['ldapauth_locationuseou'])				{					// Parse the highest level Organizational Unit as their location					$i1 = strrpos($lentries[0]["dn"],'OU=')+3;					$i2 = strpos($lentries[0]["dn"],',DC=',$i1);					$llocation = substr($lentries[0]["dn"],$i1,$i2-$i1);				}				else if (isset($modSettings['ldapauth_locationattr']) && !empty($modSettings['ldapauth_locationattr'])) {					$llocation = '';					$ldapauth_loc = explode(',', $modSettings['ldapauth_locationattr']);					foreach ($ldapauth_loc as $value) {						$llocation .= $lentries[0][$value][0] . ' ';					}					$llocation = chop ($llocation);				 }				else $llocation = '';				if (isset($modSettings['ldapauth_emailuselogin']) && $modSettings['ldapauth_emailuselogin']) 					$lmail = $username . (isset($modSettings['ldapauth_emailsuffix']) ? $modSettings['ldapauth_emailsuffix'] : '');				else if (isset($modSettings['ldapauth_emailattr']) && !empty($modSettings['ldapauth_emailattr']))					$lmail = $lentries[0][$modSettings['ldapauth_emailattr']][0];				else $lmail = '';				//email checking courtesy of Subs-Members.php				if (empty($lmail) || preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', stripslashes($lmail)) === 0 || strlen(stripslashes($lmail)) > 255)                		{					log_error(sprintf($txt['valid_email_needed'], $username));					$lmail = '';	// we will let this go, although SMF doesn't really like missing email addresses				}				$thelocation = $smcFunc['htmlspecialchars']($llocation);				$lrealname = '';				$ldapauth_rname = explode(',', $modSettings['ldapauth_fullnameattr']);				foreach ($ldapauth_rname as $value) {					$lrealname .= $lentries[0][$value][0] .' ';				}				$lrealname = chop ($lrealname);				$therealname = $smcFunc['htmlspecialchars']($lrealname);				if ($smcFunc['db_num_rows']($request) > 0)				{					// User actually exists, so only update ldap-changeable data					$cresult = $smcFunc['db_fetch_assoc']($request);					updateMemberData($cresult['id_member'], array('passwd' => $sha_passwd, 'email_address' => $lmail,'real_name' => $therealname, 'location' => $thelocation));					ldap_close($lds);					$smcFunc['db_free_result']($request);					// tells LogInOut.php not to check passwd, since we already found it to be good					return true;				} else {					log_error('Not Bound with user ' . $username);				}				// User does not exist in SMF database - create				$regOptions = array(					'interface' => 'guest',					'username' => $username,					'email' => $lmail,					'password' => $sha_passwd,					'require' => 'nothing',					'password_check' => $sha_passwd,					'validation_code' => "''",					'check_reserved_name' => true,					'check_password_strength' => false,					'check_email_ban' => true,					'send_welcome_email' => !empty($modSettings['send_welcomeEmail']),				);				$memberID = registerMember($regOptions);				updateMemberData($memberID, array('location' => $thelocation, 'real_name' => $therealname, 'passwd' => $sha_passwd));				if (isset($modSettings['ldapauth_uidattr']) && !empty($modSettings['ldapauth_uidattr']))				{					$luid = bin_to_str_sid($lentries[0][$modSettings['ldapauth_uidattr']][0]);					updateMemberData($memberID, array('ldapattr_uid' => $luid));				}				updateStats('member');				// If it's enabled, increase the registrations for today.				trackStats(array('registers' => '+'));				// Actually, this is the entry, not the results, which are anonymous.  				// Oh well, it'll be freed once the page is served anyway.				//ldap_free_result($lentries);			}			else				if (!isset($modSettings['ldapauth_passwdindb']) || $modSettings['ldapauth_passwdindb'])				{					// User does exist (or it's reserved and we've set the option not to update data for reserved names, 					// but we'll update the password in case it's changed					$cresult = $smcFunc['db_fetch_assoc']($result);					updateMemberData($cresult['id_member'], array('passwd' => $sha_passwd));				}			ldap_close($lds);			$smcFunc['db_free_result']($request);			// tells LogInOut.php not to check passwd, since we already found it to be good			return true;	}	ldap_close($lds);	// allow authentication fallthrough to other methods (local database hashes of various kinds, by default)	return false;}// Returns the textual SIDfunction bin_to_str_sid($binsid) {    $hex_sid = bin2hex($binsid);    $rev = hexdec(substr($hex_sid, 0, 2));    $subcount = hexdec(substr($hex_sid, 2, 2));    $auth = hexdec(substr($hex_sid, 4, 12));    $result    = "$rev-$auth";    for ($x=0;$x < $subcount; $x++) {        $subauth[$x] =             hexdec(little_endian(substr($hex_sid, 16 + ($x * 8), 8)));        $result .= "-" . $subauth[$x];    }    // Cheat by tacking on the S-    return 'S-' . $result;}// Converts a little-endian hex-number to one, that 'hexdec' can convertfunction little_endian($hex) {    for ($x = strlen($hex) - 2; $x >= 0; $x = $x - 2) {        $result .= substr($hex, $x, 2);    }    return $result;}?>


ops2012

Теперь собственно настройка апаче. Там всё просто - главное чтобы система была кирберезована и получила тикет  :)
В апаче должен загружаться модуль поддержки кербероса. В конфиге вот это:
<Directory "/var/www/html/forum">
    # Kerberos Auth
    AuthType Kerberos
    AuthName "Kerberos Login"
    KrbAuthRealms AD.COM
    KrbVerifyKDC off
    KrbServiceName HTTP
    Krb5Keytab /etc/krb5.keytab
    KrbMethodNegotiate on
    KrbMethodK5Passwd on
    Require valid-user
</Directory>


Строчка  "KrbMethodK5Passwd on" нужна для запроса имени-пароля если компьютер пользователя не керберезован. Да те же планшетки, либо те же компьютеры не введённые в MSAD. И тут первая проблема - гостю нельзя получить доступ на форум. Керберос его обламывает. Убирание строчки "Require valid-user" частично помогло - позволило зайти гостем. Но начались проблемы автоматического входа. Либо не авторизуется автоматом, либо после разлогина не хочет автоматически авторизоваться.
В итоге я от гостевого входа отказался, пока. Попозже ещё в эту сторону покапаю.
И тут я словил вторую проблему. Через некоторое время нахождения на форуме страничка, при перезагруке, нормально всё отображала. Но пыталась ещё что-то докачать. И этот процесс остановить было нельзя. Хотя по ссылкам ходит, всё показывает. Поковыряв через firebug похоже нашёл причину. Практически всегда это были скрипты sript.js theme.js и т.д. Иногда проскакивают картинки из темы. Судя по всему javascript один раз тыкается за каким-нибудь элементом и почему-то висит в ожидании. Как это отследить и исправить - до сих пор ума не приложу.

vector

Всем привет. Подниму некротемку.  crazy  По сабжу решили путем установки мода отсюда https://github.com/ppschweiz/smf-ldapauth Правда, пришлось допилить пару скриптов под Postgresql, по ссылке похоже под MySQL сделано.

ispanec

vector, каким образом устанавливается данная модификация?
И как данная модификация дружит(или не дружит) с деревом?

P.S. сильно не пинайте, только установил форум, а в readme нет никакой информации.