programming:1c-bitrix:ntlm-fake-auth
NTLM псевдо авторизация
<? # # Description: http://dev.1c-bitrix.ru/community/blogs/howto/2535.php # AddEventHandler("main", "OnAfterUserLogin", "BX_StoreNTLMHash"); function BX_StoreNTLMHash($arFields) { if ($arFields['USER_ID'] > 0) { $rsUser = CUser::GetList(($by="ID"), ($order="desc"), array("ID"=>$arFields['USER_ID']),array("SELECT"=>array("UF_*"))); if ($f = $rsUser->Fetch()) { $NTLM = new BX_NTLM(); if (!array_key_exists($NTLM->uf, $f)) { $obUserField = new CUserTypeEntity; $obUserField->Add(array( 'ENTITY_ID' => 'USER', 'FIELD_NAME' => $NTLM->uf, 'USER_TYPE_ID' => 'string', 'SORT' => 100, 'SHOW_FILTER' => 'N', 'SHOW_IN_LIST' => 'N', 'EDIT_IN_LIST' => 'N' ) ); $obUserField->Add(array( 'ENTITY_ID' => 'USER', 'FIELD_NAME' => $NTLM->uf_time, 'USER_TYPE_ID' => 'datetime', 'SORT' => 150, 'SHOW_FILTER' => 'N', 'SHOW_IN_LIST' => 'N', 'EDIT_IN_LIST' => 'Y' ) ); } $pw_hash = $NTLM->pw_hash($arFields['PASSWORD']); $ob = new CUser(); $ob->Update($arFields['USER_ID'], array( $NTLM->uf => $pw_hash, $NTLM->uf_time => GetTime(time(), 'FULL') ) ); } } } AddEventHandler("main", "OnBeforeProlog", "BX_NTLMAuth", 1); function BX_NTLMAuth() { global $USER; if (!$USER->IsAuthorized()) { $NTLM = new BX_NTLM(); if ($NTLM->init()) { $u = $NTLM->Header['user']; $d = $NTLM->Header['domain']; $rsUser = CUser::GetList(($by="ID"), ($order="desc"), array("LOGIN" => $u, "LOGIN_EXACT_MATCH" => 'Y'),array("SELECT"=>array($NTLM->uf))); if ($f = $rsUser->Fetch()) { $lm_resp = $NTLM->lm_resp($NTLM->_chr($f[$NTLM->uf])); if ($lm_resp == $NTLM->Header['LM_resp'] && !BX_PasswordExpired($f, $d, $u)) $_SERVER[COption::GetOptionString('ldap', 'ntlm_varname', 'REMOTE_USER')] = ($d ? $d . '\\' : '') . $u; } } } } function BX_PasswordExpired($arParams, $d, $u) { if (!CModule::IncludeModule('ldap')) return; if (!class_exists('BX_CLDAP')) { class BX_CLDAP extends CLDAP { function GetUserFields($arLdapUser, &$departmentCache=FALSE) { return $arLdapUser; } } } $bExpired = false; $NTLM = new BX_NTLM(); $rsUser = CUser::GetList(($by="ID"), ($order="desc"), array("=LOGIN"=>$u),array("SELECT"=>array("UF_*"))); if (($f = $rsUser->Fetch()) && $f[$NTLM->uf]) { $UF_TIMESTAMP = MakeTimeStamp($f[$NTLM->uf_time]); $arFilter = array('ACTIVE' => 'Y'); if ($d) $arFilter['CODE'] = $d; $db_ldap_serv = CLdapServer::GetList(Array(), $arFilter); while($r = $db_ldap_serv->GetNext()) { $xLDAP = new BX_CLDAP(); $xLDAP->arFields = $r; if($xLDAP->Connect()) { if ($arLdapUser = $xLDAP->FindUser($u, false)) { $dateLargeInt = $arLdapUser['pwdlastset']; $secsAfterADEpoch = $dateLargeInt / 10000000; $ADToUnixConvertor= (1970-1601) * (365 * 86400 + 5 * 3600 + 48 * 60 + 46); $AD_TIMESTAMP = intval($secsAfterADEpoch - $ADToUnixConvertor); if ($bExpired = $AD_TIMESTAMP > $UF_TIMESTAMP) { $ob = new CUser(); $ob->Update($arParams['ID'], array( $NTLM->uf => '', $NTLM->uf_time => GetTime(time(), 'FULL') ) ); } break; } $xLDAP->Disconnect(); } } } return $bExpired; } class BX_NTLM { function __construct() { $this->nonce = self::bin_substr(md5($_SERVER['REMOTE_ADDR']),0,8); $this->uf = 'UF_NTLM_HASH'; $this->uf_time = 'UF_NTLM_TIMESTAMP'; } function init() { if (!function_exists('hash')) { print ('<h3>`hash` function is not available, PHP 5.1.2 or above required</h3>'); return false; } if (!function_exists('mcrypt_encrypt')) { print ('<h3>`mcrypt` extension is not available</h3>'); return false; } if (function_exists('apache_request_headers')) { $tmp = apache_request_headers(); $auth = $tmp['Authorization']; } else $auth = $_SERVER['HTTP_AUTHORIZATION']; if (isset($auth)) { if ($this->bin_substr($auth,0,5) != 'NTLM ') return false; $chain = base64_decode($this->bin_substr($auth, 5)); if(1 == $o = ord($chain[8])) { if (ord($chain[13]) == 130) { $chain = "NTLMSSP\x00". "\x02" ."\x00\x00\x00\x00\x00\x00\x00". "\x28\x00" ."\x00\x00". "\x01\x82" ."\x00\x00". $this->nonce . "\x00\x00\x00\x00\x00\x00\x00\x00"; CHTTP::SetStatus('401 Unauthorized'); header('WWW-Authenticate: NTLM '.base64_encode($chain)); die(); } else return false; } elseif (3 == $o) { foreach (array('LM_resp','NT_resp','domain','user','host') as $k=>$v) { extract(unpack('vlength/voffset',$this->bin_substr($chain,$k*8+14,4))); $val = $this->bin_substr($chain,$offset,$length); $this->Header[$v] = $k < 2 ? $this->_ord($val) : $GLOBALS['APPLICATION']->ConvertCharset($val, 'UTF-16LE', SITE_CHARSET); } return true; } else return false; } $this->auth(); } function auth() { CHTTP::SetStatus('401 Unauthorized'); header('WWW-Authenticate: NTLM'); echo '<h1>Authentication required!</h1>'; die(); } function _ord($val) { $l = function_exists('mb_strlen') ? mb_strlen($val, 'ISO-8859-1') : strlen($val); for($i=0;$i<$l;$i++) { $c = $this->bin_substr($val,$i,1); $res .= sprintf("%02x",ord($c)); } return $res; } function _chr($val) { $l = function_exists('mb_strlen') ? mb_strlen($val, 'ISO-8859-1') : strlen($val); for($i=0;$i<$l;$i+=2) $res .= chr(hexdec($this->bin_substr($val,$i,2))); return $res; } function set_odd_parity($byte) { $parity = 0; $ordbyte = ord($byte); for ($i = 0; $i < 8; ++$i) { if ($ordbyte & 0x01) ++$parity; $ordbyte >>= 1; } $ordbyte = ord($byte); if ($parity % 2 == 0) { if ($ordbyte & 0x01) $ordbyte &= 0xFE; else $ordbyte |= 0x01; } return chr($ordbyte); } function convert_key($in_key) { $byte = array(); $result = ""; $byte[0] = $this->bin_substr($in_key, 0, 1); $byte[1] = chr(((ord($this->bin_substr($in_key, 0, 1)) << 7) & 0xFF) | (ord($this->bin_substr($in_key, 1, 1)) >> 1)); $byte[2] = chr(((ord($this->bin_substr($in_key, 1, 1)) << 6) & 0xFF) | (ord($this->bin_substr($in_key, 2, 1)) >> 2)); $byte[3] = chr(((ord($this->bin_substr($in_key, 2, 1)) << 5) & 0xFF) | (ord($this->bin_substr($in_key, 3, 1)) >> 3)); $byte[4] = chr(((ord($this->bin_substr($in_key, 3, 1)) << 4) & 0xFF) | (ord($this->bin_substr($in_key, 4, 1)) >> 4)); $byte[5] = chr(((ord($this->bin_substr($in_key, 4, 1)) << 3) & 0xFF) | (ord($this->bin_substr($in_key, 5, 1)) >> 5)); $byte[6] = chr(((ord($this->bin_substr($in_key, 5, 1)) << 2) & 0xFF) | (ord($this->bin_substr($in_key, 6, 1)) >> 6)); $byte[7] = chr((ord($this->bin_substr($in_key, 6, 1)) << 1) & 0xFF); for ($i = 0; $i < 8; ++$i) { $byte[$i] = $this->set_odd_parity($byte[$i]); $result .= $byte[$i]; } return $result; } function des_crypt($key, $data, $iv = "\x00\x00\x00\x00\x00\x00\x00\x00") { return mcrypt_encrypt(MCRYPT_DES, $key, $data, MCRYPT_MODE_CBC, $iv); } function pw_hash($pw, $raw = false) { $pw = preg_replace('#.#s','$0'.chr(0),$pw); $r = hash('md4', $pw, true) . pack("H10", "0000000000"); return $raw ? $r : $this->_ord($r); } function lm_resp($key, $raw = false) { $cipher1 = $this->des_crypt($this->convert_key($this->bin_substr($key, 0, 7)),$this->nonce); $cipher2 = $this->des_crypt($this->convert_key($this->bin_substr($key, 7, 7)),$this->nonce); $cipher3 = $this->des_crypt($this->convert_key($this->bin_substr($key, 14, 7)),$this->nonce); $r = $cipher1 . $cipher2 . $cipher3; return $raw ? $r : $this->_ord($r); } function bin_substr($a, $b, $c = 9999) { return function_exists('mb_substr') ? mb_substr($a, $b, $c, 'ISO-8859-1') : substr($a, $b, $c); } } ?>
programming/1c-bitrix/ntlm-fake-auth.txt · Последнее изменение: 2017/03/27 11:26 — artur