75 lines
3.1 KiB
PHP
75 lines
3.1 KiB
PHP
|
|
<?php
|
||
|
|
namespace Conmed\Authserver;
|
||
|
|
|
||
|
|
use Bitrix\Main\Config\Option;
|
||
|
|
use Bitrix\Main\Context;
|
||
|
|
use Bitrix\Main\Type\DateTime;
|
||
|
|
use Bitrix\Highloadblock\HighloadBlockTable;
|
||
|
|
use Bitrix\Main\Loader;
|
||
|
|
|
||
|
|
trait SecurityTrait {
|
||
|
|
private static $allowedTables = [
|
||
|
|
'sso_codes' => 'SsoCodes', 'sso_tokens' => 'SsoTokens',
|
||
|
|
'sso_audit' => 'SsoAudit', 'sso_security_log' => 'SsoSecurityLog'
|
||
|
|
];
|
||
|
|
|
||
|
|
public static function checkClient($clientId, $clientSecret = false, $redirectUri = false) {
|
||
|
|
$rawList = Option::get("conmed.authserver", "client_list");
|
||
|
|
foreach(explode("\n", str_replace("\r", "", $rawList)) as $line) {
|
||
|
|
$pair = explode(":", trim($line), 3);
|
||
|
|
if($pair[0] === $clientId) {
|
||
|
|
if($clientSecret !== false && !password_verify($clientSecret, $pair[1])) return false;
|
||
|
|
if($redirectUri !== false) {
|
||
|
|
$u = parse_url($redirectUri);
|
||
|
|
if(!$u || empty($u['host'])) return false;
|
||
|
|
$domain = str_replace(['https://','http://'], '', strtolower(trim($pair[2] ?? "")));
|
||
|
|
if(strtolower($u['host']) !== strtolower(trim($domain, " /"))) return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function checkRateLimit($action = 'AUTH') {
|
||
|
|
$ip = Context::getCurrent()->getRequest()->getRemoteAddress();
|
||
|
|
$dc = self::getHlEntity('sso_security_log');
|
||
|
|
$limit = DateTime::createFromTimestamp(time() - 300);
|
||
|
|
$count = $dc::getCount(['=UF_IP' => $ip, '>UF_DATE' => $limit]);
|
||
|
|
if ($count >= 20) {
|
||
|
|
header('HTTP/1.1 429 Too Many Requests');
|
||
|
|
die(json_encode(['error' => 'Rate limit exceeded']));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function registerAttempt() {
|
||
|
|
try {
|
||
|
|
$dc = self::getHlEntity('sso_security_log');
|
||
|
|
$dc::add(['UF_IP' => Context::getCurrent()->getRequest()->getRemoteAddress(), 'UF_DATE' => new DateTime()]);
|
||
|
|
} catch (\Exception $e) {}
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function audit($event, $clientId, $userId = 0, $details = "") {
|
||
|
|
try {
|
||
|
|
$dc = self::getHlEntity('sso_audit');
|
||
|
|
$dc::add([
|
||
|
|
'UF_EVENT' => $event, 'UF_CLIENT_ID' => $clientId, 'UF_USER_ID' => (int)$userId,
|
||
|
|
'UF_IP' => Context::getCurrent()->getRequest()->getRemoteAddress(),
|
||
|
|
'UF_DATE' => new DateTime(), 'UF_DETAILS' => substr($details, 0, 255)
|
||
|
|
]);
|
||
|
|
} catch (\Exception $e) {}
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function validatePassword($pass) {
|
||
|
|
if (strlen($pass) < 6) return "Минимум 6 символов";
|
||
|
|
if (!preg_match("/[a-zA-Z]/", $pass) || !preg_match("/[0-9]/", $pass)) return "Пароль должен содержать буквы и цифры";
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function getHlEntity($tableName) {
|
||
|
|
if (!isset(self::$allowedTables[$tableName])) die("Access denied");
|
||
|
|
Loader::includeModule("highloadblock");
|
||
|
|
$hl = HighloadBlockTable::getList(['filter'=>['=TABLE_NAME'=>$tableName]])->fetch();
|
||
|
|
return HighloadBlockTable::compileEntity($hl)->getDataClass();
|
||
|
|
}
|
||
|
|
}
|