1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343:
<?php
class PHPBoostAuthenticationMethod extends AuthenticationMethod
{
const AUTHENTICATION_METHOD = 'internal';
private static $MAX_AUTHORIZED_ATTEMPTS = 5;
private static $MAX_AUTHORIZED_ATTEMPTS_RESET_DELAY = 600;
private static $MAX_AUTHORIZED_ATTEMPTS_RESET_ATTEMPS = 0;
private static $MAX_AUTHORIZED_ATTEMPTS_PARTIAL_RESET_DELAY = 300;
private static $MAX_AUTHORIZED_ATTEMPTS_PARTIAL_RESET_ATTEMPS = 3;
private $querier;
private $login;
private $password;
private $approved = true;
private $registration_pass = '';
private $connection_attempts = 0;
private $last_connection_date;
public function __construct($login, $password)
{
$this->login = $login;
$this->password = KeyGenerator::string_hash($password);
$this->querier = PersistenceContext::get_querier();
}
public function set_association_parameters($approved = true, $registration_pass = '')
{
$this->approved = $approved;
$this->registration_pass = $registration_pass;
}
public function get_remaining_attemps()
{
return self::$MAX_AUTHORIZED_ATTEMPTS - $this->connection_attempts;
}
public function associate($user_id)
{
$internal_authentication_columns = array(
'user_id' => $user_id,
'login' => $this->login,
'password' => $this->password,
'registration_pass' => $this->registration_pass,
'last_connection' => time(),
'approved' => (int)$this->approved
);
$authentication_method_columns = array(
'user_id' => $user_id,
'method' => self::AUTHENTICATION_METHOD,
'identifier' => $user_id
);
try {
$this->querier->insert(DB_TABLE_INTERNAL_AUTHENTICATION, $internal_authentication_columns);
$this->querier->insert(DB_TABLE_AUTHENTICATION_METHOD, $authentication_method_columns);
} catch (SQLQuerierException $ex) {
throw new IllegalArgumentException('User Id ' . $user_id .
' is already associated with an authentication method [' . $ex->getMessage() . ']');
}
}
public function dissociate($user_id)
{
try {
$this->querier->delete(DB_TABLE_AUTHENTICATION_METHOD, 'WHERE user_id=:user_id AND method=:method', array(
'user_id' => $user_id,
'method' => self::AUTHENTICATION_METHOD
));
} catch (SQLQuerierException $ex) {
throw new IllegalArgumentException('User Id ' . $user_id .
' is already dissociated with an authentication method [' . $ex->getMessage() . ']');
}
}
public function authenticate()
{
if ($this->login)
return $this->try2authenticate();
return false;
}
private function try2authenticate()
{
$user_id = 0;
try
{
$user_id = $this->find_user_id_by_username();
}
catch (RowNotFoundException $ex) { }
if (!empty($user_id))
{
$this->check_max_authorized_attempts();
$match = $this->check_user_password($user_id);
$this->update_user_info($user_id);
}
else
{
$failure_id = 0;
try
{
$failure_id = $this->find_failure_login_tried_id_by_username();
}
catch (RowNotFoundException $ex) { }
$this->check_max_authorized_attempts();
$this->connection_attempts++;
$this->last_connection_date = time();
$this->delete_too_old_failure_attemps();
if (!empty($failure_id))
$this->update_failure_info($failure_id);
else
$this->insert_failure_info();
$match = false;
}
$auth_infos = array();
try {
$auth_infos = self::get_auth_infos($user_id);
} catch (RowNotFoundException $e) {
}
if (!empty($auth_infos) && !$auth_infos['approved'])
$this->error_msg = LangLoader::get_message('registration.not-approved', 'user-common');
if (!$match)
{
$remaining_attempts = $this->get_remaining_attemps();
if ($remaining_attempts > 0)
{
$this->error_msg = StringVars::replace_vars(LangLoader::get_message('user.auth.passwd_flood', 'status-messages-common'), array('remaining_tries' => $remaining_attempts));
}
else
{
$this->error_msg = LangLoader::get_message('user.auth.passwd_flood_max', 'status-messages-common');
}
}
$this->check_user_bannishment($user_id);
if ($match && !$this->error_msg)
{
$this->update_user_last_connection_date($user_id);
return $user_id;
}
}
private function find_user_id_by_username()
{
$columns = array('user_id', 'last_connection', 'connection_attemps');
$condition = 'WHERE login=:login AND approved=1';
$parameters = array('login' => $this->login);
$row = $this->querier->select_single_row(DB_TABLE_INTERNAL_AUTHENTICATION, $columns, $condition, $parameters);
$this->connection_attempts = $row['connection_attemps'];
$this->last_connection_date = $row['last_connection'];
return $row['user_id'];
}
private function check_max_authorized_attempts()
{
$delay_since_last_attempt = time() - $this->last_connection_date;
if ($delay_since_last_attempt >= self::$MAX_AUTHORIZED_ATTEMPTS_RESET_DELAY)
{
$this->connection_attempts = self::$MAX_AUTHORIZED_ATTEMPTS_RESET_ATTEMPS;
}
elseif ($delay_since_last_attempt >= self::$MAX_AUTHORIZED_ATTEMPTS_PARTIAL_RESET_DELAY)
{
$this->connection_attempts = min($this->connection_attempts, self::$MAX_AUTHORIZED_ATTEMPTS_PARTIAL_RESET_ATTEMPS);
}
elseif ($this->connection_attempts >= self::$MAX_AUTHORIZED_ATTEMPTS)
{
$controller = new UserErrorController(LangLoader::get_message('error', 'status-messages-common'), LangLoader::get_message('user.auth.passwd_flood_max', 'status-messages-common'));
DispatchManager::redirect($controller);
}
}
private function check_user_password($user_id)
{
$condition = 'WHERE user_id=:user_id and password=:password';
$parameters = array('user_id' => $user_id, 'password' => $this->password);
$match = $this->querier->row_exists(DB_TABLE_INTERNAL_AUTHENTICATION, $condition, $parameters, '*');
if ($match)
{
$this->connection_attempts = 0;
}
else
{
$this->connection_attempts++;
}
return $match;
}
private function update_user_info($user_id)
{
$this->last_connection_date = time();
$columns = array(
'last_connection' => $this->last_connection_date,
'connection_attemps' => $this->connection_attempts,
);
$condition = 'WHERE user_id=:user_id';
$parameters = array('user_id' => $user_id);
$this->querier->update(DB_TABLE_INTERNAL_AUTHENTICATION, $columns, $condition, $parameters);
}
public static function get_auth_infos($user_id)
{
$columns = array('login', 'password', 'approved');
$condition = 'WHERE user_id=:user_id';
$parameters = array('user_id' => $user_id);
return PersistenceContext::get_querier()->select_single_row(DB_TABLE_INTERNAL_AUTHENTICATION, $columns, $condition, $parameters);
}
public static function update_auth_infos($user_id, $login = null, $approved = null, $password = null, $registration_pass = null, $change_password_pass = null)
{
if (!empty($login))
$columns['login'] = $login;
if ($approved !== null)
$columns['approved'] = (int)$approved;
if (!empty($password))
$columns['password'] = $password;
if ($registration_pass !== null)
$columns['registration_pass'] = $registration_pass;
if ($change_password_pass !== null)
$columns['change_password_pass'] = $change_password_pass;
$condition = 'WHERE user_id=:user_id';
$parameters = array('user_id' => $user_id);
PersistenceContext::get_querier()->update(DB_TABLE_INTERNAL_AUTHENTICATION, $columns, $condition, $parameters);
UserService::regenerate_cache();
if ($approved !== null && !$approved)
{
PersistenceContext::get_querier()->delete(DB_TABLE_SESSIONS, $condition, $parameters);
AutoConnectData::change_key($user_id);
}
}
public static function registration_pass_exists($registration_pass)
{
try {
$condition = 'WHERE registration_pass=:registration_pass';
$parameters = array('registration_pass' => $registration_pass);
return PersistenceContext::get_querier()->get_column_value(DB_TABLE_INTERNAL_AUTHENTICATION, 'user_id', $condition, $parameters);
} catch (RowNotFoundException $e) {
return false;
}
}
public static function change_password_pass_exists($change_password_pass)
{
try {
$condition = 'WHERE change_password_pass=:change_password_pass';
$parameters = array('change_password_pass' => $change_password_pass);
return PersistenceContext::get_querier()->get_column_value(DB_TABLE_INTERNAL_AUTHENTICATION, 'user_id', $condition, $parameters);
} catch (RowNotFoundException $e) {
return false;
}
}
private function delete_too_old_failure_attemps()
{
$condition = 'WHERE last_connection < :reset_delay';
$parameters = array('reset_delay' => time() - self::$MAX_AUTHORIZED_ATTEMPTS_RESET_DELAY);
$this->querier->delete(DB_TABLE_INTERNAL_AUTHENTICATION_FAILURES, $condition, $parameters);
}
private function find_failure_login_tried_id_by_username()
{
$columns = array('id', 'last_connection', 'connection_attemps');
$condition = 'WHERE login=:login AND session_id=:session_id';
$parameters = array('login' => $this->login, 'session_id' => AppContext::get_session()->get_session_id());
$row = $this->querier->select_single_row(DB_TABLE_INTERNAL_AUTHENTICATION_FAILURES, $columns, $condition, $parameters);
$this->connection_attempts = $row['connection_attemps'];
$this->last_connection_date = $row['last_connection'];
return $row['id'];
}
private function insert_failure_info()
{
$columns = array(
'session_id' => AppContext::get_session()->get_session_id(),
'login' => $this->login,
'last_connection' => $this->last_connection_date,
'connection_attemps' => $this->connection_attempts,
);
$this->querier->insert(DB_TABLE_INTERNAL_AUTHENTICATION_FAILURES, $columns);
}
private function update_failure_info($failure_id)
{
$columns = array(
'last_connection' => $this->last_connection_date,
'connection_attemps' => $this->connection_attempts
);
$condition = 'WHERE id=:id';
$parameters = array('id' => $failure_id);
$this->querier->update(DB_TABLE_INTERNAL_AUTHENTICATION_FAILURES, $columns, $condition, $parameters);
}
}
?>