BAOBAB
CO_Security_Login Class Reference
Inheritance diagram for CO_Security_Login:
Collaboration diagram for CO_Security_Login:

Public Member Functions

 __construct ( $in_db_object=NULL, $in_db_result=NULL, $in_login_id=NULL, $in_ids=NULL, $in_personal_ids=NULL)
 
 load_from_db ($in_db_result)
 
 set_ids ( $in_ids_array)
 
 add_id ( $in_id)
 
 remove_id ( $in_id)
 
 ids ()
 
 user_can_edit_ids ()
 
 set_personal_ids ( $in_personal_ids=[])
 
 personal_ids ()
 
 get_crypted_password ( $in_password_to_crypt=NULL)
 
 is_login_valid ( $in_login_id, $in_hashed_password=NULL, $in_raw_password=NULL, $in_dont_create_new_api_key=false)
 
 i_am_a_god ()
 
 is_god ()
 
 is_manager ()
 
 get_lang ()
 
 set_lang ( $in_lang_id=NULL)
 
 get_user_object ()
 
 set_password_from_cleartext ( $in_cleartext_password)
 
 is_api_key_valid ( $in_api_key)
 
 get_remaining_time ()
 
 get_api_key ()
 
 get_api_key_age_in_seconds ()
 
 clear_api_key ()
 
 add_personal_token_from_current_login ( $in_id)
 
 remove_personal_token_from_this_login ( $in_id)
 
 get_logins_that_have_any_of_my_ids ()
 
 user_can_write ()
 
 delete_from_db ()
 
- Public Member Functions inherited from CO_Security_Node
 __construct ( $in_db_object=NULL, $in_db_result=NULL)
 
- Public Member Functions inherited from A_CO_DB_Table_Base
 set_batch_mode ()
 
 clear_batch_mode ()
 
 id ()
 
 lock ()
 
 locked ()
 
 danger_will_robinson_danger_clear_id ()
 
 user_can_read ()
 
 set_read_security_id ($in_new_id)
 
 set_write_security_id ($in_new_id)
 
 set_name ($in_new_value)
 
 update_db ()
 
 reload_from_db ()
 
 get_access_object ()
 

Public Attributes

 $login_id
 
- Public Attributes inherited from A_CO_DB_Table_Base
 $class_description
 This is a description of the class (not the instance). More...
 
 $instance_description
 This is a description that describes the instance. More...
 
 $last_access
 This is a UNIX epoch date that describes the last modification. The default is UNIX Day Two (in case of UTC timezone issues). More...
 
 $name
 This is the "object_name" string field. More...
 
 $read_security_id
 This is a single integer, defining the security ID required to view the record. If it is 0, then it is "open.". More...
 
 $write_security_id
 This is a single integer, defining the required security token to modify the record. If it is 0, then any logged-in user can modify. More...
 
 $context
 This is a mixed associative array, containing fields for the object. More...
 
 $error
 If there is an error, it is contained here, in a LGV_Error instance. More...
 

Protected Member Functions

 _set_up_api_key ( $key_length)
 
 _default_setup ()
 
 _build_parameter_array ()
 
- Protected Member Functions inherited from A_CO_DB_Table_Base
 _badger_serialize ( $in_data)
 
 _badger_unserialize ( $in_data)
 
 _write_to_db ()
 
 _seppuku ()
 

Static Protected Member Functions

static _random_str ($length, $keyspace='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
 

Protected Attributes

 $_api_key
 This is an API key for REST. More...
 
 $_personal_ids
 These are personal IDs (special IDs, unique to the login). More...
 
 $_ids
 These are security tokens, available to this ID. More...
 
- Protected Attributes inherited from CO_Security_Node
 $_ids
 
- Protected Attributes inherited from A_CO_DB_Table_Base
 $_db_object
 This is the actual database object that "owns" this instance. It should not be exposed beyond this class or subclasses, thereof. More...
 
 $_id
 This is the within-table unique ID of this record. More...
 
 $_batch_mode
 If this is true, then the write_record call will not be made in update_db. It will be done when clear_batch_mode() is called, instead. More...
 

Private Attributes

 $_override_access_class
 This is a special "one-shot" semaphore telling the save to override the access class. More...
 

Detailed Description

This is the specializing class for the login ID record type.

Definition at line 38 of file co_security_login.class.php.

Constructor & Destructor Documentation

◆ __construct()

CO_Security_Login::__construct (   $in_db_object = NULL,
  $in_db_result = NULL,
  $in_login_id = NULL,
  $in_ids = NULL,
  $in_personal_ids = NULL 
)

Constructor

Parameters
$in_db_objectThis is the database instance that "owns" this record.
$in_db_resultThis is a database-format associative array that is used to initialize this instance.
$in_login_idThe login ID
$in_idsAn array of integers, representing the permissions this ID has.
$in_personal_idsThis is a preset array of integers, containing personal security IDs for the row.

Definition at line 164 of file co_security_login.class.php.

169  {
170  $this->login_id = $in_login_id;
171  $this->_override_access_class = false;
172  parent::__construct($in_db_object, $in_db_result, $in_ids);
173  $this->class_description = 'This is a security class for individual logins.';
174 
175  // If explicit IDs are passed in, then that overrides the DB.
176  if (isset($in_ids) && is_array($in_ids) && count($in_ids)) {
177  $in_db_result['ids'] = implode(',', $in_ids);
178  }
179 
180  if (CO_Config::use_personal_tokens() && isset($in_personal_ids) && is_array($in_personal_ids) && count($in_personal_ids)) {
181  $in_db_result['personal_ids'] = implode(',', $in_ids);
182  }
183 
184  if (!isset($this->context)) {
185  $this->context = Array();
186  }
187 
188  if (!isset($this->context['lang'])) {
189  $this->context['lang'] = CO_Config::$lang;
190  }
191 
192  if (isset($in_db_result['api_key'])) {
193  $this->_api_key = $in_db_result['api_key'];
194  }
195 
196  if (intval($this->id()) == intval(CO_Config::god_mode_id())) {
197  // God Mode is always forced to use the config password.
198  $this->instance_description = 'GOD MODE: '.(isset($this->name) && $this->name ? "$this->name (".$this->login_id.")" : "Unnamed Login Node (".$this->login_id.")");
199  } else {
200  $this->instance_description = isset($this->name) && $this->name ? "$this->name (".$this->login_id.")" : "Unnamed Login Node (".$this->login_id.")";
201  }
202 
203  $access_object = $this->get_access_object();
204 
205  // By now, we have enough read, so we know if cogito ergo sum, so we can see if we can look at the IDs.
206  if (isset($access_object) && ($access_object->god_mode() || ($access_object->get_login_id() == $this->_id))) {
207  $this->_ids = Array($this->id());
208 
209  if (isset($in_db_result['ids']) && $in_db_result['ids']) {
210  $temp = $in_db_result['ids'];
211  if (isset ($temp) && $temp) {
212  $tempAr = explode(',', $temp);
213  if (is_array($tempAr) && count($tempAr)) {
214  $tempAr = array_unique(array_map('intval', $tempAr));
215  $tempAr = array_merge($this->_ids, $tempAr);
216  sort($tempAr);
217  // Our original login just gets all the IDs. However, subsequent access requires that only "known" IDs are read.
218  if (isset($tempAr) && is_array($tempAr) && count($tempAr)) {
219  $access_ids = $access_object->get_security_ids();
220  if ($access_object->god_mode() || (isset($access_ids) && is_array($access_ids) && count($access_ids))) {
221  foreach($tempAr as $id) {
222  if (($access_object->god_mode() || (in_array($id, $access_ids))) && !in_array($id, $this->_ids)) {
223  $this->_ids[] = $id;
224  }
225  }
226  } else {
227  $this->_ids = $tempAr;
228  }
229  }
230  }
231  }
232  }
233 
234  $this->_personal_ids = NULL;
235 
236  if (CO_Config::use_personal_tokens() && isset($in_db_result['personal_ids']) && $in_db_result['personal_ids']) {
237  $temp = $in_db_result['personal_ids'];
238  if (isset ($temp) && $temp) {
239  $tempAr = explode(',', $temp);
240  if (is_array($tempAr) && count($tempAr)) {
241  $tempAr = array_unique(array_map('intval', $tempAr));
242  sort($tempAr);
243  if (isset($tempAr) && is_array($tempAr) && count($tempAr)) {
244  $this->_personal_ids = $tempAr;
245  }
246  }
247  }
248  }
249  }
250  }

References $lang, and A_CO_DB_Table_Base\get_access_object().

Here is the call graph for this function:

Member Function Documentation

◆ _build_parameter_array()

CO_Security_Login::_build_parameter_array ( )
protected

This builds up the basic section of the instance database record. It should be overloaded, and the parent called before adding new fields.

This method overloads (and calls) the base class method.

Returns
an associative array, in database record form.

Reimplemented from CO_Security_Node.

Definition at line 110 of file co_security_login.class.php.

110  {
111  $ret = parent::_build_parameter_array();
112 
113  if (NULL == $this->_personal_ids) {
114  $this->_personal_ids = [];
115  }
116 
117  $ret['api_key'] = $this->_api_key;
118  $ret['login_id'] = $this->login_id;
119  $personal_ids_as_string_array = Array();
120  if (CO_Config::use_personal_tokens()) {
121  $personal_ids_as_int = array_map('intval', $this->_personal_ids);
122  sort($personal_ids_as_int);
123 
124  foreach ($this->_personal_ids as $id) {
125  array_push($personal_ids_as_string_array, strval($id));
126  }
127 
128  $personal_id_list_string = trim(implode(',', $personal_ids_as_string_array));
129  $ret['personal_ids'] = $personal_id_list_string ? $personal_id_list_string : NULL;
130  }
131 
132  $ids_as_int = array_map('intval', $this->_ids);
133  sort($ids_as_int);
134 
135  $ids_as_string_array = Array();
136  foreach ($this->_ids as $id) {
137  if ($id != $this->id() && (isset($personal_ids_as_int) && !in_array($id, $personal_ids_as_int))) {
138  array_push($ids_as_string_array, strval($id));
139  } elseif ($id != $this->id()) {
140  array_push($ids_as_string_array, strval($id));
141  }
142  }
143 
144  $id_list_string = trim(implode(',', $ids_as_string_array));
145 
146  $ret['ids'] = $id_list_string ? $id_list_string : NULL;
147 
148  if ($this->_override_access_class) {
149  $ret['access_class'] = 'CO_Security_ID';
150  $ret['object_name'] = NULL;
151  $ret['ids'] = NULL;
152  $this->context = NULL;
153  $this->_override_access_class = false;
154  }
155 
156  return $ret;
157  }
$_api_key
This is an API key for REST.

References $_api_key, and $login_id.

◆ _default_setup()

CO_Security_Login::_default_setup ( )
protected

This is called to populate the object fields for this class with default values. These use the SQL table tags.

This should be subclassed, and the parent should be called before applying specific instance properties.

This method overloads (and calls) the base class method.

Returns
An associative array, simulating a database read.

Reimplemented from CO_Security_Node.

Definition at line 91 of file co_security_login.class.php.

91  {
92  $default_setup = parent::_default_setup();
93  $default_setup['login_id'] = $this->login_id;
94  $default_setup['object_name'] = $this->login_id;
95  $default_setup['api_key'] = $this->_api_key;
96  $default_setup['personal_ids'] = (CO_Config::use_personal_tokens() && (NULL != $this->_personal_ids)) ? $this->_personal_ids : '';
97  $default_setup['ids'] = (NULL != $this->_ids) ? $this->_ids : '';
98 
99  return $default_setup;
100  }
$_personal_ids
These are personal IDs (special IDs, unique to the login).
$_ids
These are security tokens, available to this ID.

References $_api_key, $_ids, $_personal_ids, and $login_id.

◆ _random_str()

static CO_Security_Login::_random_str (   $length,
  $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' 
)
staticprotected

Generates a cryptographically secure string.

Returns
a randome string.

Definition at line 52 of file co_security_login.class.php.

53  {
54  $pieces = [];
55  $max = mb_strlen($keyspace, '8bit') - 1;
56  for ($i = 0; $i < $length; ++$i) {
57  $pieces []= $keyspace[random_int(0, $max)];
58  }
59  return implode('', $pieces);
60  }

Referenced by _set_up_api_key().

Here is the caller graph for this function:

◆ _set_up_api_key()

CO_Security_Login::_set_up_api_key (   $key_length)
protected

This sets up a new API key after the login has been successfully verified.

Parameters
$key_lengthThe length (in bytes) of the key.

Definition at line 66 of file co_security_login.class.php.

67  {
68  $temp_api_key = self::_random_str($key_length);
69 
70  $temp_api_key .= ' - '.strval(microtime(true)); // Add the current generation microtime, for key timeout.
71 
72  // If we are taking the IP address into consideration, then we store that, as well.
73  if (isset(CO_Config::$api_key_includes_ip_address) && CO_Config::$api_key_includes_ip_address) {
74  $temp_api_key .= ' - '.strtolower(strval($_SERVER['REMOTE_ADDR']));
75  }
76 
77  $this->_api_key = strval($temp_api_key);
78  }
static _random_str($length, $keyspace='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')

References _random_str().

Referenced by is_login_valid().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_id()

CO_Security_Login::add_id (   $in_id)

This is a setter, allowing you to add an ID.

Returns
true, if successful.
Parameters
$in_idA single integer. The new ID to add.

Definition at line 396 of file co_security_login.class.php.

397  {
398  $ret = false;
399  $in_id = intval($in_id);
400  if ($this->user_can_edit_ids() || ($this->_added_new_id == $in_id)) {
401  $id_pool = $this->get_access_object()->get_security_ids(true);
402 
403  if ($this->get_access_object()->god_mode() || (isset($id_pool) && is_array($id_pool) && count($id_pool))) {
404  // We can add an ID to the user, as long as it is one we own. We don't have to have full access to all user IDs.
405  if (($this->get_access_object()->god_mode() || (in_array($in_id, $id_pool)) || ($this->_added_new_id == $in_id)) && ($in_id != $this->id())) {
406  if (!isset($this->_ids) || !is_array($this->_ids) || !count($this->_ids)) {
407  $this->_ids = Array(intval($in_id));
408  } else {
409  $this->_ids[] = $in_id;
410  $this->_ids = array_unique($this->_ids);
411  }
412  sort($this->_ids);
413  $ret = $this->update_db();
414  } else {
415  if ($in_id != $this->id()) {
419  __LINE__,
420  __FILE__,
421  __METHOD__
422  );
423  } else { // If we tried to add our own ID, then we don't add it, but it's not an error.
424  $ret = true;
425  }
426  }
427  }
428  } else {
432  __LINE__,
433  __FILE__,
434  __METHOD__
435  );
436  }
437 
438  return $ret;
439  }
static $db_error_code_user_not_authorized
Definition: common.inc.php:51
static $db_error_name_user_not_authorized
Definition: en.php:55
static $db_error_desc_user_not_authorized
Definition: en.php:56
This class provides a general error report, with file, method and error information.
Definition: error.class.php:32

References CO_Lang_Common\$db_error_code_user_not_authorized, CO_Lang\$db_error_desc_user_not_authorized, CO_Lang\$db_error_name_user_not_authorized, A_CO_DB_Table_Base\get_access_object(), A_CO_DB_Table_Base\update_db(), and user_can_edit_ids().

Here is the call graph for this function:

◆ add_personal_token_from_current_login()

CO_Security_Login::add_personal_token_from_current_login (   $in_id)

This adds a personal token from the current logged-in ID's pool, to the regular ID pool of another ID.

Returns
true, if the operation was successful.
Parameters
$in_idThe ID (personal token) to be added.

Definition at line 870 of file co_security_login.class.php.

871  {
872  $ret = $this->get_access_object()->add_personal_token_from_current_login($this->_id, $in_id);
873 
874  if ($this->get_access_object()->error) {
875  $this->error = $this->get_access_object()->error;
876  } else {
877  $this->reload_from_db();
878  return $ret;
879  }
880 
881  return false;
882  }

References A_CO_DB_Table_Base\get_access_object(), and A_CO_DB_Table_Base\reload_from_db().

Here is the call graph for this function:

◆ clear_api_key()

CO_Security_Login::clear_api_key ( )

Removes the API Key.

Returns
true, if the operation was successful (even if there was no previous key).

Definition at line 858 of file co_security_login.class.php.

858  {
859  $this->_api_key = NULL;
860 
861  return $this->update_db();
862  }

References A_CO_DB_Table_Base\update_db().

Here is the call graph for this function:

◆ delete_from_db()

CO_Security_Login::delete_from_db ( )

We override this, because logins never die. They just become security placeholders.

Returns
true, if the conversion was successful.

Reimplemented from A_CO_DB_Table_Base.

Definition at line 949 of file co_security_login.class.php.

949  {
950  if ($this->id() != CO_Config::god_mode_id()) {
951  if ($this->user_can_write()) {
952  $user_object = $this->get_user_object();
953 
954  if (isset($user_object) && ($user_object instanceof CO_User_Collection)) {
955  $user_object->set_login(NULL);
956  }
957 
958  $this->read_security_id = 0;
959  $this->write_security_id = -1;
960  $this->api_key = NULL;
961  $this->context = NULL;
962  $this->name = NULL;
963  $this->login_id = NULL;
964  $this->_ids = Array();
965  $this->_override_access_class = true;
966  $ret = $this->_write_to_db();
967  return $ret;
968  } else {
969  return false;
970  }
971  } else {
975  );
976  }
977  }
static $login_error_code_attempt_to_delete_god
Definition: common.inc.php:60
static $login_error_name_attempt_to_delete_god
Definition: en.php:70
static $login_error_desc_attempt_to_delete_god
Definition: en.php:71

References CO_Lang_Common\$login_error_code_attempt_to_delete_god, CO_Lang\$login_error_desc_attempt_to_delete_god, CO_Lang\$login_error_name_attempt_to_delete_god, A_CO_DB_Table_Base\_write_to_db(), get_user_object(), and user_can_write().

Here is the call graph for this function:

◆ get_api_key()

CO_Security_Login::get_api_key ( )
Returns
a string, with the API key, if the key is still valid. NULL, otherwise.

Definition at line 793 of file co_security_login.class.php.

793  {
794  $ret = NULL;
795 
796  if (isset($this->_api_key) && $this->_api_key) {
797  $api_expl = explode(' - ', trim($this->_api_key));
798  $my_ip = NULL;
799 
800  // God Mode gets a different timeout.
801  $timeout = floatval($this->i_am_a_god() ? CO_Config::$god_session_timeout_in_seconds : CO_Config::$session_timeout_in_seconds);
802 
803  // We first check to make sure that we are still within the time window. If not, then all bets are off.
804  // <0 as a $timeout value means no timeout.
805  if (isset($api_expl[1]) && ((0 > $timeout) || ((microtime(true) - floatval($api_expl[1])) <= $timeout))) {
806  if (isset(CO_Config::$api_key_includes_ip_address) && CO_Config::$api_key_includes_ip_address) { // See if we are also checking the IP address.
807  $my_ip = strtolower(strval($_SERVER['REMOTE_ADDR']));
808  if (isset($api_expl[2])) {
809  if ($api_expl[2] == $my_ip) {
810  $ret = $api_expl[0];
811  } else {
815  );
816  }
817  } else {
821  );
822  }
823  } else {
824  $ret = $api_expl[0];
825  }
826  } elseif ($api_expl[0]) {
830  );
831  }
832  }
833 
834  return $ret;
835  }
static $login_error_code_api_key_invalid
Definition: common.inc.php:57
static $login_error_name_api_key_invalid
Definition: en.php:65
static $login_error_desc_api_key_invalid
Definition: en.php:66

References CO_Lang_Common\$login_error_code_api_key_invalid, CO_Lang\$login_error_desc_api_key_invalid, CO_Lang\$login_error_name_api_key_invalid, and i_am_a_god().

Referenced by get_remaining_time(), is_api_key_valid(), and is_login_valid().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_api_key_age_in_seconds()

CO_Security_Login::get_api_key_age_in_seconds ( )
Returns
an integer, with the number of seconds since the API key was created. -1 if there is no API key. This will return a value, even if the API key is present, but expired.

Definition at line 841 of file co_security_login.class.php.

841  {
842  $ret = -1;
843 
844  if (isset($this->_api_key) && $this->_api_key) {
845  list($api_key, $api_time) = explode(' - ', trim($this->_api_key));
846  $ret = ceil(microtime(true) - floatval($api_time));
847  }
848 
849  return $ret;
850  }

◆ get_crypted_password()

CO_Security_Login::get_crypted_password (   $in_password_to_crypt = NULL)
Returns
the crypted password, as a string.
Parameters
$in_password_to_cryptIf this is not-NULL, then, instead of returning the instance's crypted PW, the given password is crypted and returned.

Definition at line 601 of file co_security_login.class.php.

602  {
603 
604  $ret = $this->context['hashed_password'];
605 
606  if ($in_password_to_crypt) {
607  if (strlen($in_password_to_crypt) >= CO_Config::$min_pw_len) {
608  $ret = password_hash($in_password_to_crypt, PASSWORD_DEFAULT);
609  } else {
610  $ret = false;
611  }
612  }
613 
614  return $ret;
615  }

Referenced by is_login_valid(), and set_password_from_cleartext().

Here is the caller graph for this function:

◆ get_lang()

CO_Security_Login::get_lang ( )
Returns
a string, with the language ID for this login.

Reimplemented from A_CO_DB_Table_Base.

Definition at line 691 of file co_security_login.class.php.

691  {
692  return $this->context['lang'];
693  }

◆ get_logins_that_have_any_of_my_ids()

CO_Security_Login::get_logins_that_have_any_of_my_ids ( )

This returns IDs that have our personal IDs.

Returns
an associative array of arrays of integer, keyed by integer. The key is the ID of the login, and the value is an array of integer, with the IDs that match. NULL, if an error.

Definition at line 910 of file co_security_login.class.php.

910  {
911  return $this->get_access_object()->get_logins_that_have_any_of_my_ids();
912  }

References A_CO_DB_Table_Base\get_access_object().

Here is the call graph for this function:

◆ get_remaining_time()

CO_Security_Login::get_remaining_time ( )
Returns
a floating-point number, with the remaining login time, in seconds. -1 means no timeout. 0 means time's up.

Definition at line 769 of file co_security_login.class.php.

769  {
770  $ret = 0;
771 
772  // Unless we are legally logged in, we will always get 0.
773  if ( $this->get_api_key() ) {
774  $timeout = floatval($this->i_am_a_god() ? CO_Config::$god_session_timeout_in_seconds : CO_Config::$session_timeout_in_seconds);
775 
776  if ( 0 < $timeout ) {
777  if (isset($this->_api_key) && $this->_api_key) {
778  list($api_key, $api_time) = explode(' - ', trim($this->_api_key));
779  $ret = $timeout - ceil((microtime(true) - floatval($api_time)) * 10000) / 10000;
780  }
781  } else {
782  $ret = -1;
783  }
784  }
785 
786  return $ret;
787  }

References get_api_key(), and i_am_a_god().

Here is the call graph for this function:

◆ get_user_object()

CO_Security_Login::get_user_object ( )
Returns
The associated User object, if it exists. NULL, otherwise.

Definition at line 715 of file co_security_login.class.php.

715  {
716  $ret = NULL;
717  $access_instance = $this->get_access_object();
718 
719  // If we have a user, we also clear the user from knowing about us.
720  if ($access_instance && method_exists($access_instance, 'get_user_from_login')) {
721  $ret = $access_instance->get_user_from_login($this->id());
722  }
723 
724  return $ret;
725  }

References A_CO_DB_Table_Base\get_access_object().

Referenced by delete_from_db().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ i_am_a_god()

CO_Security_Login::i_am_a_god ( )
Returns
true, if this object represents the database "God" object.

Definition at line 667 of file co_security_login.class.php.

667  {
668  return intval(CO_Config::god_mode_id()) == intval($this->id());
669  }

Referenced by get_api_key(), get_remaining_time(), and user_can_write().

Here is the caller graph for this function:

◆ ids()

CO_Security_Login::ids ( )

This does a security vetting. If logged in as God, then all IDs are returned. Otherwise, only IDs that our login can see are returned, whether or not they are in the object.

Returns
The current IDs.

Definition at line 499 of file co_security_login.class.php.

499  {
500  if ($this->get_access_object()->god_mode()) {
501  return $this->_ids;
502  } else {
503  $my_ids = $this->get_access_object()->get_security_ids();
504  $ret = Array();
505  foreach ($this->_ids as $id) {
506  if (in_array($id, $my_ids)) {
507  array_push($ret, $id);
508  }
509  }
510  return $ret;
511  }
512  }

References $_ids, and A_CO_DB_Table_Base\get_access_object().

Here is the call graph for this function:

◆ is_api_key_valid()

CO_Security_Login::is_api_key_valid (   $in_api_key)

This tests a given API key against the stored value. It also checks time elapsed, to ensure that we are still within the login window.

Returns
true, if the API key is valid, and we are still within the allotted timespan for the key.
Parameters
$in_api_keyThe API key that we're testing.

Definition at line 751 of file co_security_login.class.php.

752  {
753  $ret = ($this->get_api_key() == $in_api_key);
754 
755  if ($ret && !$this->error) {
759  );
760  }
761 
762  return $ret;
763  }
static $login_error_code_api_key_mismatch
Definition: common.inc.php:58
static $login_error_desc_api_key_mismatch
Definition: en.php:68
static $login_error_name_api_key_mismatch
Definition: en.php:67

References CO_Lang_Common\$login_error_code_api_key_mismatch, CO_Lang\$login_error_desc_api_key_mismatch, CO_Lang\$login_error_name_api_key_mismatch, and get_api_key().

Here is the call graph for this function:

◆ is_god()

CO_Security_Login::is_god ( )
Returns
true, if we are the "God" login.

Definition at line 675 of file co_security_login.class.php.

675  {
676  return $this->id() == CO_Config::god_mode_id();
677  }

References A_CO_DB_Table_Base\id().

Referenced by CO_Cobra\_convert_login(), CO_Cobra\_create_new_login(), and is_manager().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_login_valid()

CO_Security_Login::is_login_valid (   $in_login_id,
  $in_hashed_password = NULL,
  $in_raw_password = NULL,
  $in_dont_create_new_api_key = false 
)
Returns
true, if the presented credentials are good.
Parameters
$in_login_idThe login ID
$in_hashed_passwordThe password, crypt-hashed
$in_raw_passwordThe password, cleartext.
$in_dont_create_new_api_keyIf true, then we don't create a new API key.

Definition at line 621 of file co_security_login.class.php.

625  {
626  $ret = false;
627  if (isset($this->login_id) && $this->login_id && ($this->login_id == $in_login_id)) {
628  $api_key = $this->get_api_key();
629  if ($this->id() == CO_Config::god_mode_id()) {
630  if (("" != $in_hashed_password) && ($in_hashed_password == $api_key)) { // We have a special provision that allows the God hashed password to use the API key.
631  $ret = true;
632  } else { // God mode uses the cleartext password in the config file.
633  if ($in_raw_password && !$in_dont_create_new_api_key && isset(CO_Config::$block_logins_for_valid_api_key) && CO_Config::$block_logins_for_valid_api_key && $api_key) {
634  return false;
635  } else {
636  $ret = ($in_raw_password == CO_Config::god_mode_password());
637  }
638  }
639  } else {
640  // The server can be set up to prevent users from logging in while another login is still active.
641  if ($in_raw_password && !$in_dont_create_new_api_key && isset(CO_Config::$block_logins_for_valid_api_key) && CO_Config::$block_logins_for_valid_api_key && $api_key) {
642  return false;
643  } elseif (isset($this->context['hashed_password']) && $this->context['hashed_password']) {
644  // First, see if this is in the hashed password.
645  if ($in_hashed_password) {
646  $ret = hash_equals($this->get_crypted_password(), $in_hashed_password);
647  } else { // If not, see if it's the raw password.
648  $ret = password_verify($in_raw_password, $this->get_crypted_password());
649  }
650  }
651  }
652  }
653 
654  // Generate an API key. We can't save it yet, as we're probably not actually logged in.
655  if ($ret && !$in_dont_create_new_api_key) {
656  // God mode gets a longer key. It's not actually more secure, but we can use that to determine different treatment, later on.
657  $this->_set_up_api_key($this->id() == CO_Config::god_mode_id() ? 40 : 32);
658  }
659 
660  return $ret;
661  }
get_crypted_password( $in_password_to_crypt=NULL)

References _set_up_api_key(), get_api_key(), and get_crypted_password().

Here is the call graph for this function:

◆ is_manager()

CO_Security_Login::is_manager ( )
Returns
false, as we are not a manager.

Reimplemented in CO_Login_Manager.

Definition at line 683 of file co_security_login.class.php.

683  {
684  return $this->is_god();
685  }

References is_god().

Here is the call graph for this function:

◆ load_from_db()

CO_Security_Login::load_from_db (   $in_db_result)

This function sets up this instance, according to the DB-formatted associative array passed in.

Returns
true, if the instance was able to set itself up to the provided array.

Reimplemented from A_CO_DB_Table_Base.

Reimplemented in CO_Login_Manager, and CO_Cobra_Login.

Definition at line 258 of file co_security_login.class.php.

258  {
259  $ret = parent::load_from_db($in_db_result);
260  $this->_personal_ids = NULL;
261  $this->_ids = Array($this->id());
262 
263  if ($ret) {
264  if (!isset($this->context)) {
265  $this->context = Array();
266  }
267 
268  if (!isset($this->context['lang'])) {
269  $this->context['lang'] = CO_Config::$lang;
270  }
271 
272  $this->class_description = 'This is a security class for individual logins.';
273 
274  if (isset($in_db_result['login_id'])) {
275  $this->login_id = $in_db_result['login_id'];
276  $this->instance_description = isset($this->name) && $this->name ? "$this->name (".$this->login_id.")" : "Unnamed Login Node (".$this->login_id.")";
277  }
278 
279  if (isset($in_db_result['api_key'])) {
280  $this->_api_key = $in_db_result['api_key'];
281  }
282 
283  if (isset($in_db_result['ids']) && $in_db_result['ids']) {
284  if ($this->_db_object) {
285  if (isset($in_db_result['ids']) && $in_db_result['ids']) {
286  $temp = $in_db_result['ids'];
287  if (isset ($temp) && $temp) {
288  $tempAr = explode(',', $temp);
289  if (is_array($tempAr) && count($tempAr)) {
290  $tempAr = array_map('intval', $tempAr);
291  sort($tempAr);
292  $tempAr = array_unique(array_merge($this->_ids, $tempAr));
293  if (isset($tempAr) && is_array($tempAr) && count($tempAr)) {
294  $this->_ids = $tempAr;
295  }
296  }
297  }
298  }
299  }
300  }
301 
302  if (CO_Config::use_personal_tokens() && isset($in_db_result['personal_ids']) || isset($in_db_result['personal_ids'])) {
303  $temp = $in_db_result['personal_ids'];
304  if (isset ($temp) && $temp) {
305  $tempAr = explode(',', $temp);
306  if (is_array($tempAr) && count($tempAr)) {
307  $tempAr = array_unique(array_map('intval', $tempAr));
308  sort($tempAr);
309  if (isset($tempAr) && is_array($tempAr) && count($tempAr)) {
310  $this->_personal_ids = $tempAr;
311  }
312  }
313  }
314  }
315  }
316 
317  return $ret;
318  }

References $lang.

◆ personal_ids()

CO_Security_Login::personal_ids ( )

This does a security vetting. If logged in as God, then all IDs are returned. Otherwise, only IDs that our login can see are returned, whether or not they are in the object.

Returns
The current personal IDs.

Definition at line 576 of file co_security_login.class.php.

576  {
577  if (!CO_Config::use_personal_tokens()) {
578  return [];
579  }
580 
581  if ($this->get_access_object()->god_mode()) {
582  return $this->_personal_ids;
583  } else {
584  $my_ids = $this->get_access_object()->get_security_ids();
585  $ret = [];
586  if (isset($this->_personal_ids) && is_array($this->_personal_ids) && count($this->_personal_ids)) {
587  foreach ($this->_personal_ids as $id) {
588  if (in_array($id, $my_ids)) {
589  array_push($ret, $id);
590  }
591  }
592  }
593  return $ret;
594  }
595  }

References $_personal_ids, and A_CO_DB_Table_Base\get_access_object().

Here is the call graph for this function:

◆ remove_id()

CO_Security_Login::remove_id (   $in_id)

This allows you to remove a single ID. We can remove one of our IDs from a user that may have other IDs.

Returns
true, if successful.
Parameters
$in_idA single integer. The ID to remove.

Definition at line 448 of file co_security_login.class.php.

449  {
450  $ret = false;
451 
452  if ($this->user_can_edit_ids()) {
453  $id_pool = $this->get_access_object()->get_security_ids();
454 
455  if ($this->get_access_object()->god_mode() || (isset($id_pool) && is_array($id_pool) && count($id_pool) && in_array($in_id, $id_pool))) {
456  if (isset($this->_ids) && is_array($this->_ids) && count($this->_ids) && $this->user_can_edit_ids()) {
457  $new_array = Array();
458 
459  foreach($this->_ids as $id) {
460  if ($id != $in_id) {
461  array_push($new_array, $id);
462  } else {
463  $ret = true;
464  }
465 
466  if ($ret) {
467  $ret = $this->set_ids($new_array);
468  }
469  }
470  }
471  } else {
475  __LINE__,
476  __FILE__,
477  __METHOD__
478  );
479  }
480  } else {
484  __LINE__,
485  __FILE__,
486  __METHOD__
487  );
488  }
489 
490  return $ret;
491  }

References CO_Lang_Common\$db_error_code_user_not_authorized, CO_Lang\$db_error_desc_user_not_authorized, CO_Lang\$db_error_name_user_not_authorized, A_CO_DB_Table_Base\get_access_object(), set_ids(), and user_can_edit_ids().

Here is the call graph for this function:

◆ remove_personal_token_from_this_login()

CO_Security_Login::remove_personal_token_from_this_login (   $in_id)

This removes a personal token from the current logged-in ID's pool, from the regular ID pool of another ID.

Returns
true, if the operation was successful.
Parameters
$in_idThe ID (personal token) to be added.

Definition at line 890 of file co_security_login.class.php.

891  {
892  $ret = $this->get_access_object()->remove_personal_token_from_this_login($this->_id, $in_id);
893 
894  if ($this->get_access_object()->error) {
895  $this->error = $this->get_access_object()->error;
896  } else {
897  $this->reload_from_db();
898  return $ret;
899  }
900 
901  return false;
902  }

References A_CO_DB_Table_Base\get_access_object(), and A_CO_DB_Table_Base\reload_from_db().

Here is the call graph for this function:

◆ set_ids()

CO_Security_Login::set_ids (   $in_ids_array)

This is a setter for the ID array. It can delete the array by sending in NULL, or an empty array. No user can set IDs for which they do not have access. Since this is a "whole hog" operation, we need to be able to access every single ID in the current object before we can replace or delete them.

Returns
true, if successful.
Parameters
$in_ids_arrayThis is a preset array of integers, containing security IDs for the row. NULL/Empty to delete all IDs.

Definition at line 328 of file co_security_login.class.php.

329  {
330  $ret = false;
331  $in_ids_array = array_map('intval', $in_ids_array);
332  if ($this->user_can_edit_ids()) {
333  $id_pool = $this->get_access_object()->get_security_ids(true); // We get just our regular IDs. No personal ones.
334  if ($this->get_access_object()->god_mode() || (isset($id_pool) && is_array($id_pool) && count($id_pool))) {
335  // First thing we do, is ensure that EVERY SINGLE ID in the current user are ones we have in our own set.
336  // An empty set is fine.
337  foreach($this->_ids as $id) {
338  if (!$this->get_access_object()->god_mode() && (isset($id) && (0 < $id) && !in_array($id, $id_pool))) {
339  // Even one failure scrags the operation.
343  __LINE__,
344  __FILE__,
345  __METHOD__
346  );
347  return false;
348  }
349  }
350 
351  // Next, if there is an existing array, we check our input, and add only the IDs we own.
352  if ($this->get_access_object()->god_mode() || (isset($in_ids_array) && is_array($in_ids_array) && count($in_ids_array))) {
353  $temp_ids = array_map('intval', $in_ids_array);
354  $new_ids = Array();
355  foreach($temp_ids as $in_id) {
356  if (($in_id != $this->id()) && ($this->get_access_object()->god_mode() || in_array($in_id, $id_pool))) {
357  $new_ids[] = $in_id;
358  }
359  }
360 
361  $this->_ids = $new_ids;
362  // Otherwise, we are clearing the array.
363  } else {
364  $this->_ids = Array();
365  }
366 
367  $ret = $this->update_db();
368  } else {
372  __LINE__,
373  __FILE__,
374  __METHOD__
375  );
376  }
377  } else {
381  __LINE__,
382  __FILE__,
383  __METHOD__
384  );
385  }
386 
387  return $ret;
388  }

References CO_Lang_Common\$db_error_code_user_not_authorized, CO_Lang\$db_error_desc_user_not_authorized, CO_Lang\$db_error_name_user_not_authorized, A_CO_DB_Table_Base\get_access_object(), A_CO_DB_Table_Base\update_db(), and user_can_edit_ids().

Referenced by remove_id().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_lang()

CO_Security_Login::set_lang (   $in_lang_id = NULL)
Returns
true, if the set was successful.
Parameters
$in_lang_idThe lang ID. This is not used for the low-level error handlers (which use the server setting). It is used to determine higher-level strings.

Reimplemented from A_CO_DB_Table_Base.

Definition at line 699 of file co_security_login.class.php.

700  {
701  $ret = false;
702 
703  if ($this->user_can_write()) {
704  $this->context['lang'] = strtolower(trim(strval($in_lang_id)));
705  $ret = $this->update_db();
706  }
707 
708  return $ret;
709  }

References A_CO_DB_Table_Base\update_db(), and user_can_write().

Here is the call graph for this function:

◆ set_password_from_cleartext()

CO_Security_Login::set_password_from_cleartext (   $in_cleartext_password)

This encrypts a cleartext password, and sets it into the record.

Returns
true, if the set was successful.
Parameters
$in_cleartext_passwordThe cleartext password. It will not be saved. Instead, the hashed password will be saved.

Definition at line 733 of file co_security_login.class.php.

734  {
735  $ret = false;
736 
737  if ($this->user_can_write()) {
738  $this->context['hashed_password'] = $this->get_crypted_password($in_cleartext_password);
739  $ret = $this->update_db();
740  }
741 
742  return $ret;
743  }

References get_crypted_password(), A_CO_DB_Table_Base\update_db(), and user_can_write().

Here is the call graph for this function:

◆ set_personal_ids()

CO_Security_Login::set_personal_ids (   $in_personal_ids = [])

This sets just the "personal" IDs for the given ID.

This should only be called by the "God" admin, and will fail, otherwise (returns empty array).

This is not an atomic operation. If any of the given IDs are also in the regular ID list, they will be removed from the personal IDs.

Returns
an array of integers, with the new personal security IDs (usually a copy of the input Array). It will be empty, if the procedure fails.
Parameters
$in_personal_idsAn Array of Integers, with the new personal IDs. This replaces any previous ones. If empty, then the IDs are removed.

Reimplemented in CO_Cobra_Login.

Definition at line 538 of file co_security_login.class.php.

539  {
540  $personal_ids_temp = array_unique(array_map('intval', $in_personal_ids));
541  $this->_personal_ids = [];
542  $access_object = $this->get_access_object();
543 
544  if (CO_Config::use_personal_tokens() && isset($access_object) && $access_object->god_mode()) {
545  if (0 < count($personal_ids_temp)) {
546  $personal_ids = [];
547  $my_ids = $this->_ids;
548  // None of the ids can be in the regular IDs, and will be removed from the set, if so.
549  // They also cannot be anyone else's personal ID, or anyone's login ID. Personal IDs can ONLY be regular (non-login) security objects.
550  foreach($personal_ids_temp as $id) {
551  // Make sure that we don't have this personal token in our regular ID array.
552  if (($key = array_search($id, $my_ids)) !== false) {
553  unset($my_ids[$key]);
554  }
555  if (!$this->get_access_object()->is_this_a_login_id($id) || in_array($id, $this->_personal_ids)) {
556  array_push($personal_ids, $id);
557  }
558  }
559  $this->_ids = $my_ids;
560  sort($personal_ids);
561  $this->_personal_ids = $personal_ids;
562  }
563  }
564 
565  $this->update_db();
566 
567  return $this->_personal_ids;
568  }

References $_ids, $_personal_ids, A_CO_DB_Table_Base\get_access_object(), and A_CO_DB_Table_Base\update_db().

Here is the call graph for this function:

◆ user_can_edit_ids()

CO_Security_Login::user_can_edit_ids ( )

We check to see if we can edit the IDs for this record. We cannot edit our own IDs, and have to own all of the IDs in the object in order to be able to change them. Of course, God can do whatever God wants...

Returns
true, if the current logged-in user can edit IDs for this login.

Definition at line 522 of file co_security_login.class.php.

522  {
523  $ret = ($this->get_access_object()->get_login_id() != $this->_id) && ($this->get_access_object()->god_mode() || $this->_db_object->i_have_all_ids($this->_id));
524 
525  return $ret;
526  }
$_id
This is the within-table unique ID of this record.

References A_CO_DB_Table_Base\$_id, and A_CO_DB_Table_Base\get_access_object().

Referenced by add_id(), remove_id(), and set_ids().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ user_can_write()

CO_Security_Login::user_can_write ( )

We override this, because the God login can only be modified by itself. No one else.

Returns
true, if the current logged-in user has write permission on this record.

Reimplemented from A_CO_DB_Table_Base.

Definition at line 920 of file co_security_login.class.php.

920  {
921  $ret = false;
922 
923  // Only God can edit God.
924  if ($this->i_am_a_god() && !$this->get_access_object()->god_mode()) {
925  return false;
926  } else {
927  $ids = $this->get_access_object()->get_security_ids();
928 
929  $my_write_item = intval($this->write_security_id);
930 
931  if ((0 == $my_write_item) || $this->get_access_object()->god_mode()) {
932  $ret = true;
933  } else {
934  if (isset($ids) && is_array($ids) && count($ids)) {
935  $ret = in_array($my_write_item, $ids);
936  }
937  }
938 
939  return $ret;
940  }
941  }

References A_CO_DB_Table_Base\get_access_object(), and i_am_a_god().

Referenced by delete_from_db(), set_lang(), and set_password_from_cleartext().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ $_api_key

CO_Security_Login::$_api_key
protected

This is an API key for REST.

Definition at line 40 of file co_security_login.class.php.

Referenced by _build_parameter_array(), and _default_setup().

◆ $_ids

CO_Security_Login::$_ids
protected

These are security tokens, available to this ID.

Definition at line 42 of file co_security_login.class.php.

Referenced by _default_setup(), ids(), and set_personal_ids().

◆ $_override_access_class

CO_Security_Login::$_override_access_class
private

This is a special "one-shot" semaphore telling the save to override the access class.

Definition at line 39 of file co_security_login.class.php.

◆ $_personal_ids

CO_Security_Login::$_personal_ids
protected

These are personal IDs (special IDs, unique to the login).

Definition at line 41 of file co_security_login.class.php.

Referenced by _default_setup(), personal_ids(), and set_personal_ids().

◆ $login_id

CO_Security_Login::$login_id

Definition at line 44 of file co_security_login.class.php.

Referenced by _build_parameter_array(), and _default_setup().