* Started working on moving user sessions to the new 'sessions' table. This is still a work in progress.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 6 years ago
parent e483d6e9a1
commit b2367bb90b
  1. 83
      Anvil/Tools/Account.pm
  2. 1
      share/words.xml
  3. 3
      tools/anvil-change-password
  4. 4
      tools/anvil-update-system
  5. 60
      tools/anvil.sql

@ -338,12 +338,14 @@ AND
{ {
my $query = " my $query = "
UPDATE UPDATE
users sessions
SET SET
user_session_salt = ".$anvil->data->{sys}{database}{use_handle}->quote($session_salt).", session_salt = ".$anvil->data->{sys}{database}{use_handle}->quote($session_salt).",
modified_date = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{sys}{database}{timestamp})." modified_date = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{sys}{database}{timestamp})."
WHERE WHERE
user_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($user_uuid)." session_user_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($user_uuid)."
AND
session_host_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->Get->host_uuid)."
;"; ;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({debug => $debug, query => $query, source => $THIS_FILE, line => __LINE__}); $anvil->Database->write({debug => $debug, query => $query, source => $THIS_FILE, line => __LINE__});
@ -379,7 +381,17 @@ WHERE
This deletes the user's UUID and hash cookies, which effectively logs them out. This deletes the user's UUID and hash cookies, which effectively logs them out.
This methods takes no parameters and always returns C<< 0 >>. If there is no C<< user_uuid >>, this will return C<< 1 >>. Otherwise, C<< 0 >> is returned.
Parameters;
=head3 user_uuid (optional, default 'cookie::anvil_user_uuid')
This is the user to log out.
=head3 host_uuid (optional, default 'Get->host_uuid')
This is the host to log out of. This takes the special C<< all >> value which logs the user out of all hosts sessions.
=cut =cut
sub logout sub logout
@ -392,23 +404,45 @@ sub logout
# Delete the user's cookie data. Sending nothing to '_write_cookies' does this. # Delete the user's cookie data. Sending nothing to '_write_cookies' does this.
$anvil->Account->_write_cookies({debug => $debug}); $anvil->Account->_write_cookies({debug => $debug});
# Delete the user's session salt. my $user_uuid = defined $parameter->{user_uuid} ? $parameter->{user_uuid} : $anvil->data->{cookie}{anvil_user_uuid};
if ($anvil->data->{cookie}{anvil_user_uuid}) my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
user_uuid => $user_uuid.
host_uuid => $host_uuid,
}});
# If I don't have a user UUID, we can't proceed.
if (not $user_uuid)
{ {
my $query = " # User not found.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "error_0040"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0040"}) }});
return(1);
}
# If the host_uuid is 'all', we're logging out all sessions.
# Delete the user's session salt.
my $query = "
UPDATE UPDATE
users sessions
SET SET
user_session_salt = '', session_salt = '',
modified_date = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{sys}{database}{timestamp})." modified_date = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{sys}{database}{timestamp})."
WHERE WHERE
user_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{cookie}{anvil_user_uuid})." session_user_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($user_uuid)." ";
if ($host_uuid ne "all")
{
$query .= "
AND
session_host_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($host_uuid)." ";
}
$query .= "
;"; ;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({debug => $debug, query => $query, source => $THIS_FILE, line => __LINE__}); $anvil->Database->write({debug => $debug, query => $query, source => $THIS_FILE, line => __LINE__});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0198", variables => { user => $anvil->data->{cgi}{username}{value} }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0198", variables => { user => $anvil->data->{cgi}{username}{value} }});
}
# Log that they're out # Log that they're out
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0179"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0179"});
@ -489,7 +523,16 @@ sub read_cookies
}}); }});
# Validate the cookie if there is a User UUID. Pick the random number up from the database. # Validate the cookie if there is a User UUID. Pick the random number up from the database.
my $query = "SELECT user_session_salt FROM users WHERE user_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{cookie}{anvil_user_uuid}).";"; my $query = "
SELECT
session_salt
FROM
sessions
WHERE
session_user_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{cookie}{anvil_user_uuid})."
AND
session_host_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->Get->host_uuid)."
;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0124", variables => { query => $query }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0124", variables => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results}; my $count = @{$results};
@ -513,21 +556,21 @@ sub read_cookies
} }
# Read in their "rand" value # Read in their "rand" value
$anvil->data->{users}{user_session_salt} = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $anvil->data->{sessions}{session_salt} = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->data->{users}{user_session_salt} = "" if not defined $anvil->data->{users}{user_session_salt}; $anvil->data->{sessions}{session_salt} = "" if not defined $anvil->data->{sessions}{session_salt};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "users::user_session_salt" => $anvil->data->{users}{user_session_salt} }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sessions::session_salt" => $anvil->data->{sessions}{session_salt} }});
# Generate a hash using today and yesterday's date. # Generate a hash using today and yesterday's date.
my ($today_hash) = $anvil->Account->_build_cookie_hash({ my ($today_hash) = $anvil->Account->_build_cookie_hash({
debug => $debug, debug => $debug,
uuid => $anvil->data->{cookie}{anvil_user_uuid}, uuid => $anvil->data->{cookie}{anvil_user_uuid},
salt => $anvil->data->{users}{user_session_salt}, salt => $anvil->data->{sessions}{session_salt},
offset => 0, offset => 0,
}); });
my ($yesterday_hash) = $anvil->Account->_build_cookie_hash({ my ($yesterday_hash) = $anvil->Account->_build_cookie_hash({
debug => $debug, debug => $debug,
uuid => $anvil->data->{cookie}{anvil_user_uuid}, uuid => $anvil->data->{cookie}{anvil_user_uuid},
salt => $anvil->data->{users}{user_session_salt}, salt => $anvil->data->{sessions}{session_salt},
offset => -86400, offset => -86400,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {

@ -576,6 +576,7 @@ The update appears to have not completed successfully. The output was:
<key name="error_0037"><![CDATA[In Words->parse_banged_string(), an infinite loop was detected while processing: [#!variable!message!#].]]></key> <key name="error_0037"><![CDATA[In Words->parse_banged_string(), an infinite loop was detected while processing: [#!variable!message!#].]]></key>
<key name="error_0038">The TCP port: [#!variable!port!#] is not a valid.</key> <key name="error_0038">The TCP port: [#!variable!port!#] is not a valid.</key>
<key name="error_0039"><![CDATA[The password for the host was not provided by '--password-file' or in 'job_data' (as 'password=<secret>').]]></key> <key name="error_0039"><![CDATA[The password for the host was not provided by '--password-file' or in 'job_data' (as 'password=<secret>').]]></key>
<key name="error_0040">Logging out failed. The user's UUID wasn't passed and 'sys::users::user_uuid' wasn't set. Was the user already logged out?</key>
<!-- These are units, words and so on used when displaying information. --> <!-- These are units, words and so on used when displaying information. -->
<key name="unit_0001">Yes</key> <key name="unit_0001">Yes</key>

@ -176,8 +176,9 @@ sub update_local_passwords
user_is_admin => 1, user_is_admin => 1,
user_is_experienced => 1, user_is_experienced => 1,
user_is_trusted => 1, user_is_trusted => 1,
user_session_salt => "", # Logs them out, effectively
}); });
# Log out any Striker sessions.
$anvil->Account->logout{host_uuid => "all"});
print $anvil->Words->string({key => "message_0025"})."\n"; print $anvil->Words->string({key => "message_0025"})."\n";
# Validate # Validate

@ -270,7 +270,7 @@ sub run_os_update
if ($line =~ /Total download size: (.*)$/i) if ($line =~ /Total download size: (.*)$/i)
{ {
my $update_size = $1; my $update_size = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { update_size => $update_size }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_size => $update_size }});
# Ready to install, update to 5%. The next step will count up to 95%. # Ready to install, update to 5%. The next step will count up to 95%.
update_progress($anvil, $progress, "message_0035,!!size!$update_size!!"); update_progress($anvil, $progress, "message_0035,!!size!$update_size!!");
@ -282,7 +282,7 @@ sub run_os_update
$to_update *= 4; $to_update *= 4;
$percent_step = $anvil->Convert->round({number => ($to_update / 90)}); $percent_step = $anvil->Convert->round({number => ($to_update / 90)});
$next_step = $percent_step; $next_step = $percent_step;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
to_update => $to_update, to_update => $to_update,
percent_step => $percent_step, percent_step => $percent_step,
next_step => $next_step, next_step => $next_step,

@ -44,7 +44,6 @@ CREATE TABLE users (
user_uuid uuid not null primary key, -- This is the single most important record in Anvil!. Everything links back to here. user_uuid uuid not null primary key, -- This is the single most important record in Anvil!. Everything links back to here.
user_name text not null, user_name text not null,
user_password_hash text not null, -- A user without a password is disabled. user_password_hash text not null, -- A user without a password is disabled.
user_session_salt text not null, -- This is used when generating a session hash for a user when they log in.
user_salt text not null, -- This is used to enhance the security of the user's password. user_salt text not null, -- This is used to enhance the security of the user's password.
user_algorithm text not null, -- This is the algorithm used to encrypt the password and salt. user_algorithm text not null, -- This is the algorithm used to encrypt the password and salt.
user_hash_count text not null, -- This is the number of times that the password+salt was re-hashed through the algorithm. user_hash_count text not null, -- This is the number of times that the password+salt was re-hashed through the algorithm.
@ -61,7 +60,6 @@ CREATE TABLE history.users (
user_uuid uuid, user_uuid uuid,
user_name text, user_name text,
user_password_hash text, user_password_hash text,
user_session_salt text,
user_salt text, user_salt text,
user_algorithm text, user_algorithm text,
user_hash_count text, user_hash_count text,
@ -83,7 +81,6 @@ BEGIN
(user_uuid, (user_uuid,
user_name, user_name,
user_password_hash, user_password_hash,
user_session_salt,
user_salt, user_salt,
user_algorithm, user_algorithm,
user_hash_count, user_hash_count,
@ -96,7 +93,6 @@ BEGIN
(history_users.user_uuid, (history_users.user_uuid,
history_users.user_name, history_users.user_name,
history_users.user_password_hash, history_users.user_password_hash,
history_users.user_session_salt,
history_users.user_salt, history_users.user_salt,
history_users.user_algorithm, history_users.user_algorithm,
history_users.user_hash_count, history_users.user_hash_count,
@ -116,6 +112,62 @@ CREATE TRIGGER trigger_users
FOR EACH ROW EXECUTE PROCEDURE history_users(); FOR EACH ROW EXECUTE PROCEDURE history_users();
-- This stores user session information on a per-dashboard basis.
CREATE TABLE sessions (
session_uuid uuid not null primary key, -- This is the single most important record in Anvil!. Everything links back to here.
session_host_uuid uuid not null, -- This is the host uuid for this session.
session_user_uuid uuid not null, -- This is the user uuid for the user logging in.
session_session_salt text not null, -- This is used when generating a session hash for a session when they log in.
session_user_agent text,
modified_date timestamp with time zone not null
FOREIGN KEY(session_host_uuid) REFERENCES hosts(host_uuid),
FOREIGN KEY(session_user_uuid) REFERENCES users(user_uuid)
);
ALTER TABLE sessions OWNER TO #!variable!session!#;
CREATE TABLE history.sessions (
history_id bigserial,
session_uuid uuid,
session_host_uuid uuid,
session_user_uuid uuid,
session_session_salt text,
session_user_agent text,
modified_date timestamp with time zone not null
);
ALTER TABLE history.sessions OWNER TO #!variable!session!#;
CREATE FUNCTION history_sessions() RETURNS trigger
AS $$
DECLARE
history_sessions RECORD;
BEGIN
SELECT INTO history_sessions * FROM sessions WHERE session_uuid = new.session_uuid;
INSERT INTO history.sessions
(session_uuid,
session_host_uuid,
session_user_uuid,
session_session_salt,
session_user_agent,
modified_date)
VALUES
(history_sessions.session_uuid,
history_sessions.session_host_uuid,
history_sessions.session_user_uuid,
history_sessions.session_session_salt,
history_sessions.session_user_agent,
history_sessions.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_sessions() OWNER TO #!variable!session!#;
CREATE TRIGGER trigger_sessions
AFTER INSERT OR UPDATE ON sessions
FOR EACH ROW EXECUTE PROCEDURE history_sessions();
-- This stores information about the host machine. This is the master table that everything will be linked -- This stores information about the host machine. This is the master table that everything will be linked
-- to. -- to.

Loading…
Cancel
Save