X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FAuth.pm;h=9ed86d66505160e332d5364b14658f77f2711b66;hb=07b14d1f5c08e87ac700564520bc70e1c1ea1923;hp=f2d15a8c71d4bd5cf59920fdcd2e4aeb31f424f2;hpb=1072cd08c6f5b1905a34dcb3eeab3ddec98d6905;p=kivitendo-erp.git diff --git a/SL/Auth.pm b/SL/Auth.pm index f2d15a8c7..9ed86d665 100644 --- a/SL/Auth.pm +++ b/SL/Auth.pm @@ -8,11 +8,16 @@ use Time::HiRes qw(gettimeofday); use List::MoreUtils qw(uniq); use YAML; +use SL::Auth::ColumnInformation; use SL::Auth::Constants qw(:all); use SL::Auth::DB; use SL::Auth::LDAP; +use SL::Auth::Password; +use SL::Auth::SessionValue; +use SL::SessionFile; use SL::User; +use SL::DBConnect; use SL::DBUpgrade2; use SL::DBUtils; @@ -26,19 +31,31 @@ sub new { bless $self, $type; - $self->{SESSION} = { }; - $self->_read_auth_config(); + $self->reset; $main::lxdebug->leave_sub(); return $self; } +sub reset { + my ($self, %params) = @_; + + $self->{SESSION} = { }; + $self->{FULL_RIGHTS} = { }; + $self->{RIGHTS} = { }; + $self->{unique_counter} = 0; + $self->{column_information} = SL::Auth::ColumnInformation->new(auth => $self); + $self->{authenticator}->reset; +} + sub get_user_dbh { - my ($self, $login) = @_; - my %user = $self->read_user($login); - my $dbh = DBI->connect( + my ($self, $login, %params) = @_; + my $may_fail = delete $params{may_fail}; + + my %user = $self->read_user(login => $login); + my $dbh = SL::DBConnect->connect( $user{dbconnect}, $user{dbuser}, $user{dbpasswd}, @@ -46,9 +63,13 @@ sub get_user_dbh { pg_enable_utf8 => $::locale->is_utf8, AutoCommit => 0 } - ) or $::form->dberror; + ); - if ($user{dboptions}) { + if (!$may_fail && !$dbh) { + $::form->error($::locale->text('The connection to the authentication database failed:') . "\n" . $DBI::errstr); + } + + if ($user{dboptions} && $dbh) { $dbh->do($user{dboptions}) or $::form->dberror($user{dboptions}); } @@ -78,27 +99,11 @@ sub mini_error { sub _read_auth_config { $main::lxdebug->enter_sub(); - my $self = shift; - - my $code; - my $in = IO::File->new('config/authentication.pl', 'r'); - - if (!$in) { - my $locale = Locale->new('en'); - $self->mini_error($locale->text('The config file "config/authentication.pl" was not found.')); - } - - while (<$in>) { - $code .= $_; - } - $in->close(); - - eval $code; + my $self = shift; - if ($@) { - my $locale = Locale->new('en'); - $self->mini_error($locale->text('The config file "config/authentication.pl" contained invalid Perl code:'), $@); - } + map { $self->{$_} = $::lx_office_conf{authentication}->{$_} } keys %{ $::lx_office_conf{authentication} }; + $self->{DB_config} = $::lx_office_conf{'authentication/database'}; + $self->{LDAP_config} = $::lx_office_conf{'authentication/ldap'}; if ($self->{module} eq 'DB') { $self->{authenticator} = SL::Auth::DB->new($self); @@ -109,19 +114,19 @@ sub _read_auth_config { if (!$self->{authenticator}) { my $locale = Locale->new('en'); - $self->mini_error($locale->text('No or an unknown authenticantion module specified in "config/authentication.pl".')); + $self->mini_error($locale->text('No or an unknown authenticantion module specified in "config/lx_office.conf".')); } my $cfg = $self->{DB_config}; if (!$cfg) { my $locale = Locale->new('en'); - $self->mini_error($locale->text('config/authentication.pl: Key "DB_config" is missing.')); + $self->mini_error($locale->text('config/lx_office.conf: Key "DB_config" is missing.')); } if (!$cfg->{host} || !$cfg->{db} || !$cfg->{user}) { my $locale = Locale->new('en'); - $self->mini_error($locale->text('config/authentication.pl: Missing parameters in "DB_config". Required parameters are "host", "db" and "user".')); + $self->mini_error($locale->text('config/lx_office.conf: Missing parameters in "authentication/database". Required parameters are "host", "db" and "user".')); } $self->{authenticator}->verify_config(); @@ -135,12 +140,10 @@ sub _read_auth_config { sub authenticate_root { $main::lxdebug->enter_sub(); - my $self = shift; - my $password = shift; - my $is_crypted = shift; + my ($self, $password) = @_; - $password = crypt $password, 'ro' if (!$password || !$is_crypted); - my $admin_password = crypt "$self->{admin_password}", 'ro'; + $password = SL::Auth::Password->hash_if_unhashed(login => 'root', password => $password); + my $admin_password = SL::Auth::Password->hash_if_unhashed(login => 'root', password => $self->{admin_password}); $main::lxdebug->leave_sub(); @@ -152,16 +155,48 @@ sub authenticate_root { sub authenticate { $main::lxdebug->enter_sub(); - my $self = shift; + my ($self, $login, $password) = @_; $main::lxdebug->leave_sub(); - my $result = $self->{authenticator}->authenticate(@_); + my $result = $login ? $self->{authenticator}->authenticate($login, $password) : ERR_USER; return OK if $result eq OK; sleep 5; return $result; } +sub store_credentials_in_session { + my ($self, %params) = @_; + + if (!$self->{authenticator}->requires_cleartext_password) { + $params{password} = SL::Auth::Password->hash_if_unhashed(login => $params{login}, + password => $params{password}, + look_up_algorithm => 1, + auth => $self); + } + + $self->set_session_value(login => $params{login}, password => $params{password}); +} + +sub store_root_credentials_in_session { + my ($self, $rpw) = @_; + + $self->set_session_value(rpw => SL::Auth::Password->hash_if_unhashed(login => 'root', password => $rpw)); +} + +sub get_stored_password { + my ($self, $login) = @_; + + my $dbh = $self->dbconnect; + + return undef unless $dbh; + + my $query = qq|SELECT password FROM auth."user" WHERE login = ?|; + my ($stored_password) = $dbh->selectrow_array($query, undef, $login); + + return $stored_password; +} + sub dbconnect { $main::lxdebug->enter_sub(2); @@ -182,7 +217,7 @@ sub dbconnect { $main::lxdebug->message(LXDebug->DEBUG1, "Auth::dbconnect DSN: $dsn"); - $self->{dbh} = DBI->connect($dsn, $cfg->{user}, $cfg->{password}, { pg_enable_utf8 => $::locale->is_utf8, AutoCommit => 0 }); + $self->{dbh} = SL::DBConnect->connect($dsn, $cfg->{user}, $cfg->{password}, { pg_enable_utf8 => $::locale->is_utf8, AutoCommit => 1 }); if (!$may_fail && !$self->{dbh}) { $main::form->error($main::locale->text('The connection to the authentication database failed:') . "\n" . $DBI::errstr); @@ -209,9 +244,9 @@ sub dbdisconnect { sub check_tables { $main::lxdebug->enter_sub(); - my $self = shift; + my ($self, $dbh) = @_; - my $dbh = $self->dbconnect(); + $dbh ||= $self->dbconnect(); my $query = qq|SELECT COUNT(*) FROM pg_tables WHERE (schemaname = 'auth') AND (tablename = 'user')|; my ($count) = $dbh->selectrow_array($query); @@ -262,7 +297,7 @@ sub create_database { my $encoding = $Common::charset_to_db_encoding{$charset}; $encoding ||= 'UNICODE'; - my $dbh = DBI->connect($dsn, $params{superuser}, $params{superuser_password}, { pg_enable_utf8 => $charset =~ m/^utf-?8$/i }); + my $dbh = SL::DBConnect->connect($dsn, $params{superuser}, $params{superuser_password}, { pg_enable_utf8 => scalar($charset =~ m/^utf-?8$/i) }); if (!$dbh) { $main::form->error($main::locale->text('The connection to the template database failed:') . "\n" . $DBI::errstr); @@ -322,6 +357,8 @@ sub save_user { my ($sth, $query, $user_id); + $dbh->begin_work; + $query = qq|SELECT id FROM auth."user" WHERE login = ?|; ($user_id) = selectrow_query($form, $dbh, $query, $login); @@ -359,8 +396,14 @@ sub can_change_password { sub change_password { $main::lxdebug->enter_sub(); - my $self = shift; - my $result = $self->{authenticator}->change_password(@_); + my ($self, $login, $new_password) = @_; + + my $result = $self->{authenticator}->change_password($login, $new_password); + + $self->store_credentials_in_session(login => $login, + password => $new_password, + look_up_algorithm => 1, + auth => $self); $main::lxdebug->leave_sub(); @@ -395,15 +438,25 @@ sub read_all_users { sub read_user { $main::lxdebug->enter_sub(); - my $self = shift; - my $login = shift; + my ($self, %params) = @_; my $dbh = $self->dbconnect(); + + my (@where, @values); + if ($params{login}) { + push @where, 'u.login = ?'; + push @values, $params{login}; + } + if ($params{id}) { + push @where, 'u.id = ?'; + push @values, $params{id}; + } + my $where = join ' AND ', '1 = 1', @where; my $query = qq|SELECT u.id, u.login, cfg.cfg_key, cfg.cfg_value FROM auth.user_config cfg LEFT JOIN auth."user" u ON (cfg.user_id = u.id) - WHERE (u.login = ?)|; - my $sth = prepare_execute_query($main::form, $dbh, $query, $login); + WHERE $where|; + my $sth = prepare_execute_query($main::form, $dbh, $query, @values); my %user_data; @@ -412,6 +465,9 @@ sub read_user { @user_data{qw(id login)} = @{$ref}{qw(id login)}; } + # The XUL/XML backed menu has been removed. + $user_data{menustyle} = 'v3' if lc($user_data{menustyle} || '') eq 'xml'; + $sth->finish(); $main::lxdebug->leave_sub(); @@ -434,26 +490,33 @@ sub get_user_id { } sub delete_user { - $main::lxdebug->enter_sub(); + $::lxdebug->enter_sub; my $self = shift; my $login = shift; - my $form = $main::form; + my $dbh = $self->dbconnect; + my $id = $self->get_user_id($login); + my $user_db_exists; - my $dbh = $self->dbconnect(); - my $query = qq|SELECT id FROM auth."user" WHERE login = ?|; + $dbh->rollback and return $::lxdebug->leave_sub if (!$id); - my ($id) = selectrow_query($form, $dbh, $query, $login); + my $u_dbh = $self->get_user_dbh($login, may_fail => 1); + $user_db_exists = $self->check_tables($u_dbh) if $u_dbh; - return $main::lxdebug->leave_sub() if (!$id); + $u_dbh->begin_work if $u_dbh && $user_db_exists; - do_query($form, $dbh, qq|DELETE FROM auth.user_group WHERE user_id = ?|, $id); - do_query($form, $dbh, qq|DELETE FROM auth.user_config WHERE user_id = ?|, $id); + $dbh->begin_work; - $dbh->commit(); + do_query($::form, $dbh, qq|DELETE FROM auth.user_group WHERE user_id = ?|, $id); + do_query($::form, $dbh, qq|DELETE FROM auth.user_config WHERE user_id = ?|, $id); + do_query($::form, $dbh, qq|DELETE FROM auth.user WHERE id = ?|, $id); + do_query($::form, $u_dbh, qq|UPDATE employee SET deleted = 't' WHERE login = ?|, $login) if $u_dbh && $user_db_exists; - $main::lxdebug->leave_sub(); + $dbh->commit; + $u_dbh->commit if $u_dbh && $user_db_exists; + + $::lxdebug->leave_sub; } # -------------------------------------- @@ -465,11 +528,8 @@ sub restore_session { my $self = shift; - my $cgi = $main::cgi; - $cgi ||= CGI->new(''); - - $session_id = $cgi->cookie($self->get_session_cookie_name()); - $session_id =~ s|[^0-9a-f]||g; + $session_id = $::request->{cgi}->cookie($self->get_session_cookie_name()); + $session_id =~ s|[^0-9a-f]||g if $session_id; $self->{SESSION} = { }; @@ -482,10 +542,24 @@ sub restore_session { $form = $main::form; - $dbh = $self->dbconnect(); + # Don't fail if the auth DB doesn't yet. + if (!( $dbh = $self->dbconnect(1) )) { + $::lxdebug->leave_sub; + return SESSION_NONE; + } + + # Don't fail if the "auth" schema doesn't exist yet, e.g. if the + # admin is creating the session tables at the moment. $query = qq|SELECT *, (mtime < (now() - '$self->{session_timeout}m'::interval)) AS is_expired FROM auth.session WHERE id = ?|; - $cookie = selectfirst_hashref_query($form, $dbh, $query, $session_id); + if (!($sth = $dbh->prepare($query)) || !$sth->execute($session_id)) { + $sth->finish if $sth; + $::lxdebug->leave_sub; + return SESSION_NONE; + } + + $cookie = $sth->fetchrow_hashref; + $sth->finish; if (!$cookie || $cookie->{is_expired} || ($cookie->{ip_address} ne $ENV{REMOTE_ADDR})) { $self->destroy_session(); @@ -493,31 +567,85 @@ sub restore_session { return $cookie ? SESSION_EXPIRED : SESSION_NONE; } - $query = qq|SELECT sess_key, sess_value FROM auth.session_content WHERE session_id = ?|; - $sth = prepare_execute_query($form, $dbh, $query, $session_id); - - while (my $ref = $sth->fetchrow_hashref()) { - $self->{SESSION}->{$ref->{sess_key}} = $ref->{sess_value}; - $form->{$ref->{sess_key}} = $self->_load_value($ref->{sess_value}) if (!defined $form->{$ref->{sess_key}}); + if ($self->{column_information}->has('auto_restore')) { + $self->_load_with_auto_restore_column($dbh, $session_id); + } else { + $self->_load_without_auto_restore_column($dbh, $session_id); } - $sth->finish(); - $main::lxdebug->leave_sub(); return SESSION_OK; } -sub _load_value { - return $_[1] if $_[1] !~ m/^---/; +sub _load_without_auto_restore_column { + my ($self, $dbh, $session_id) = @_; - my $value; - eval { - $value = YAML::Load($_[1]); - 1; - } or return $_[1]; + my $query = <fetchrow_hashref) { + my $value = SL::Auth::SessionValue->new(auth => $self, + key => $ref->{sess_key}, + value => $ref->{sess_value}, + raw => 1); + $self->{SESSION}->{ $ref->{sess_key} } = $value; + + next if defined $::form->{$ref->{sess_key}}; + + my $data = $value->get; + $::form->{$ref->{sess_key}} = $data if $value->{auto_restore} || !ref $data; + } +} + +sub _load_with_auto_restore_column { + my ($self, $dbh, $session_id) = @_; + + my $auto_restore_keys = join ', ', map { "'${_}'" } qw(login password rpw); + + my $query = <fetchrow_hashref) { + my $value = SL::Auth::SessionValue->new(auth => $self, + key => $ref->{sess_key}, + value => $ref->{sess_value}, + auto_restore => $ref->{auto_restore}, + raw => 1); + $self->{SESSION}->{ $ref->{sess_key} } = $value; + + next if defined $::form->{$ref->{sess_key}}; + + my $data = $value->get; + $::form->{$ref->{sess_key}} = $data if $value->{auto_restore} || !ref $data; + } + + $sth->finish; + + $query = <fetchrow_hashref) { + my $value = SL::Auth::SessionValue->new(auth => $self, + key => $ref->{sess_key}); + $self->{SESSION}->{ $ref->{sess_key} } = $value; + } } sub destroy_session { @@ -528,11 +656,15 @@ sub destroy_session { if ($session_id) { my $dbh = $self->dbconnect(); + $dbh->begin_work; + do_query($main::form, $dbh, qq|DELETE FROM auth.session_content WHERE session_id = ?|, $session_id); do_query($main::form, $dbh, qq|DELETE FROM auth.session WHERE id = ?|, $session_id); $dbh->commit(); + SL::SessionFile->destroy_session($session_id); + $session_id = undef; $self->{SESSION} = { }; } @@ -545,23 +677,31 @@ sub expire_sessions { my $self = shift; + $main::lxdebug->leave_sub and return if !$self->session_tables_present; + my $dbh = $self->dbconnect(); - my $query = - qq|DELETE FROM auth.session_content - WHERE session_id IN - (SELECT id - FROM auth.session - WHERE (mtime < (now() - '$self->{session_timeout}m'::interval)))|; - do_query($main::form, $dbh, $query); + my $query = qq|SELECT id + FROM auth.session + WHERE (mtime < (now() - '$self->{session_timeout}m'::interval))|; - $query = - qq|DELETE FROM auth.session - WHERE (mtime < (now() - '$self->{session_timeout}m'::interval))|; + my @ids = selectall_array_query($::form, $dbh, $query); - do_query($main::form, $dbh, $query); + if (@ids) { + $dbh->begin_work; - $dbh->commit(); + SL::SessionFile->destroy_session($_) for @ids; + + $query = qq|DELETE FROM auth.session_content + WHERE session_id IN (| . join(', ', ('?') x scalar(@ids)) . qq|)|; + do_query($main::form, $dbh, $query, @ids); + + $query = qq|DELETE FROM auth.session + WHERE id IN (| . join(', ', ('?') x scalar(@ids)) . qq|)|; + do_query($main::form, $dbh, $query, @ids); + + $dbh->commit(); + } $main::lxdebug->leave_sub(); } @@ -580,68 +720,95 @@ sub _create_session_id { } sub create_or_refresh_session { - $main::lxdebug->enter_sub(); + $session_id ||= shift->_create_session_id; +} - my $self = shift; +sub save_session { + $::lxdebug->enter_sub; + my $self = shift; + my $provided_dbh = shift; - $session_id ||= $self->_create_session_id(); + my $dbh = $provided_dbh || $self->dbconnect(1); - my ($form, $dbh, $query, $sth, $id); + $::lxdebug->leave_sub && return unless $dbh && $session_id; - $form = $main::form; - $dbh = $self->dbconnect(); + $dbh->begin_work unless $provided_dbh; - $query = qq|SELECT id FROM auth.session WHERE id = ?|; + # If this fails then the "auth" schema might not exist yet, e.g. if + # the admin is just trying to create the auth database. + if (!$dbh->do(qq|LOCK auth.session_content|)) { + $dbh->rollback unless $provided_dbh; + $::lxdebug->leave_sub; + return; + } - ($id) = selectrow_query($form, $dbh, $query, $session_id); + my @unfetched_keys = map { $_->{key} } + grep { ! $_->{fetched} } + values %{ $self->{SESSION} }; + # $::lxdebug->dump(0, "unfetched_keys", [ sort @unfetched_keys ]); + # $::lxdebug->dump(0, "all keys", [ sort map { $_->{key} } values %{ $self->{SESSION} } ]); + my $query = qq|DELETE FROM auth.session_content WHERE (session_id = ?)|; + $query .= qq| AND (sess_key NOT IN (| . join(', ', ('?') x scalar @unfetched_keys) . qq|))| if @unfetched_keys; - if ($id) { - do_query($form, $dbh, qq|UPDATE auth.session SET mtime = now() WHERE id = ?|, $session_id); + do_query($::form, $dbh, $query, $session_id, @unfetched_keys); - } else { - do_query($form, $dbh, qq|INSERT INTO auth.session (id, ip_address, mtime) VALUES (?, ?, now())|, $session_id, $ENV{REMOTE_ADDR}); + my ($id) = selectrow_query($::form, $dbh, qq|SELECT id FROM auth.session WHERE id = ?|, $session_id); + if ($id) { + do_query($::form, $dbh, qq|UPDATE auth.session SET mtime = now() WHERE id = ?|, $session_id); + } else { + do_query($::form, $dbh, qq|INSERT INTO auth.session (id, ip_address, mtime) VALUES (?, ?, now())|, $session_id, $ENV{REMOTE_ADDR}); } - $self->save_session($dbh); - - $dbh->commit(); + my @values_to_save = grep { $_->{fetched} } + values %{ $self->{SESSION} }; + if (@values_to_save) { + my ($columns, $placeholders) = ('', ''); + my $auto_restore = $self->{column_information}->has('auto_restore'); - $main::lxdebug->leave_sub(); -} - -sub save_session { - my $self = shift; - my $provided_dbh = shift; - - my $dbh = $provided_dbh || $self->dbconnect(); + if ($auto_restore) { + $columns .= ', auto_restore'; + $placeholders .= ', ?'; + } - do_query($::form, $dbh, qq|DELETE FROM auth.session_content WHERE session_id = ?|, $session_id); + $query = qq|INSERT INTO auth.session_content (session_id, sess_key, sess_value ${columns}) VALUES (?, ?, ? ${placeholders})|; + my $sth = prepare_query($::form, $dbh, $query); - if (%{ $self->{SESSION} }) { - my $query = qq|INSERT INTO auth.session_content (session_id, sess_key, sess_value) VALUES (?, ?, ?)|; - my $sth = prepare_query($::form, $dbh, $query); + foreach my $value (@values_to_save) { + my @values = ($value->{key}, $value->get_dumped); + push @values, $value->{auto_restore} if $auto_restore; - foreach my $key (sort keys %{ $self->{SESSION} }) { - do_statement($::form, $sth, $query, $session_id, $key, $self->{SESSION}->{$key}); + do_statement($::form, $sth, $query, $session_id, @values); } $sth->finish(); } $dbh->commit() unless $provided_dbh; + $::lxdebug->leave_sub; } sub set_session_value { $main::lxdebug->enter_sub(); my $self = shift; - my %params = @_; + my @params = @_; $self->{SESSION} ||= { }; - while (my ($key, $value) = each %params) { - $self->{SESSION}->{ $key } = YAML::Dump($value); + while (@params) { + my $key = shift @params; + + if (ref $key eq 'HASH') { + $self->{SESSION}->{ $key->{key} } = SL::Auth::SessionValue->new(key => $key->{key}, + value => $key->{value}, + auto_restore => $key->{auto_restore}); + + } else { + my $value = shift @params; + $self->{SESSION}->{ $key } = SL::Auth::SessionValue->new(key => $key, + value => $value); + } } $main::lxdebug->leave_sub(); @@ -665,12 +832,62 @@ sub delete_session_value { sub get_session_value { $main::lxdebug->enter_sub(); - my $self = shift; - my $value = $self->{SESSION} ? $self->_load_value($self->{SESSION}->{ $_[0] }) : undef; + my $self = shift; + my $data = $self->{SESSION} && $self->{SESSION}->{ $_[0] } ? $self->{SESSION}->{ $_[0] }->get : undef; $main::lxdebug->leave_sub(); - return $value; + return $data; +} + +sub create_unique_sesion_value { + my ($self, $value, %params) = @_; + + $self->{SESSION} ||= { }; + + my @now = gettimeofday(); + my $key = "$$-" . ($now[0] * 1000000 + $now[1]) . "-"; + $self->{unique_counter} ||= 0; + + my $hashed_key; + do { + $self->{unique_counter}++; + $hashed_key = md5_hex($key . $self->{unique_counter}); + } while (exists $self->{SESSION}->{$hashed_key}); + + $self->set_session_value($hashed_key => $value); + + return $hashed_key; +} + +sub save_form_in_session { + my ($self, %params) = @_; + + my $form = delete($params{form}) || $::form; + my $non_scalars = delete $params{non_scalars}; + my $data = {}; + + my %skip_keys = map { ( $_ => 1 ) } (qw(login password stylesheet version titlebar), @{ $params{skip_keys} || [] }); + + foreach my $key (grep { !$skip_keys{$_} } keys %{ $form }) { + $data->{$key} = $form->{$key} if !ref($form->{$key}) || $non_scalars; + } + + return $self->create_unique_sesion_value($data, %params); +} + +sub restore_form_from_session { + my ($self, $key, %params) = @_; + + my $data = $self->get_session_value($key); + return $self unless $data; + + my $form = delete($params{form}) || $::form; + my $clobber = exists $params{clobber} ? $params{clobber} : 1; + + map { $form->{$_} = $data->{$_} if $clobber || !exists $form->{$_} } keys %{ $data }; + + return $self; } sub set_cookie_environment_variable { @@ -692,6 +909,14 @@ sub session_tables_present { $main::lxdebug->enter_sub(); my $self = shift; + + # Only re-check for the presence of auth tables if either the check + # hasn't been done before of if they weren't present. + if ($self->{session_tables_present}) { + $main::lxdebug->leave_sub(); + return $self->{session_tables_present}; + } + my $dbh = $self->dbconnect(1); if (!$dbh) { @@ -707,9 +932,11 @@ sub session_tables_present { my ($count) = selectrow_query($main::form, $dbh, $query); + $self->{session_tables_present} = 2 == $count; + $main::lxdebug->leave_sub(); - return 2 == $count; + return $self->{session_tables_present}; } # -------------------------------------- @@ -733,10 +960,10 @@ sub all_rights_full { ["crm_notices", $locale->text("CRM notices")], ["crm_other", $locale->text("CRM other")], ["--master_data", $locale->text("Master Data")], - ["customer_vendor_edit", $locale->text("Create and edit customers and vendors")], + ["customer_vendor_edit", $locale->text("Create customers and vendors. Edit all vendors. Edit only customers where salesman equals employee (login)")], + ["customer_vendor_all_edit", $locale->text("Create customers and vendors. Edit all vendors. Edit all customers")], ["part_service_assembly_edit", $locale->text("Create and edit parts, services, assemblies")], ["project_edit", $locale->text("Create and edit projects")], - ["license_edit", $locale->text("Manage license keys")], ["--ar", $locale->text("AR")], ["sales_quotation_edit", $locale->text("Create and edit sales quotations")], ["sales_order_edit", $locale->text("Create and edit sales orders")], @@ -744,6 +971,7 @@ sub all_rights_full { ["invoice_edit", $locale->text("Create and edit invoices and credit notes")], ["dunning_edit", $locale->text("Create and edit dunnings")], ["sales_all_edit", $locale->text("View/edit all employees sales documents")], + ["edit_prices", $locale->text("Edit prices and discount (if not used, textfield is ONLY set readonly)")], ["--ap", $locale->text("AP")], ["request_quotation_edit", $locale->text("Create and edit RFQs")], ["purchase_order_edit", $locale->text("Create and edit purchase orders")], @@ -764,6 +992,7 @@ sub all_rights_full { ["--others", $locale->text("Others")], ["email_bcc", $locale->text("May set the BCC field when sending emails")], ["config", $locale->text("Change Lx-Office installation settings (all menu entries beneath 'System')")], + ["admin", $locale->text("Administration (Used to access instance administration from user logins)")], ); return @all_rights; @@ -837,6 +1066,8 @@ sub save_group { my $form = $main::form; my $dbh = $self->dbconnect(); + $dbh->begin_work; + my ($query, $sth, $row, $rights); if (!$group->{id}) { @@ -879,9 +1110,10 @@ sub delete_group { my $self = shift; my $id = shift; - my $form = $main::from; + my $form = $main::form; my $dbh = $self->dbconnect(); + $dbh->begin_work; do_query($form, $dbh, qq|DELETE FROM auth.user_group WHERE group_id = ?|, $id); do_query($form, $dbh, qq|DELETE FROM auth.group_rights WHERE group_id = ?|, $id); @@ -1002,41 +1234,32 @@ sub check_right { } sub assert { - $main::lxdebug->enter_sub(2); - - my $self = shift; - my $right = shift; - my $dont_abort = shift; + $::lxdebug->enter_sub(2); + my ($self, $right, $dont_abort) = @_; - my $form = $main::form; - - if ($self->check_right($form->{login}, $right)) { - $main::lxdebug->leave_sub(2); + if ($self->check_right($::myconfig{login}, $right)) { + $::lxdebug->leave_sub(2); return 1; } if (!$dont_abort) { - delete $form->{title}; - $form->show_generic_error($main::locale->text("You do not have the permissions to access this function.")); + delete $::form->{title}; + $::form->show_generic_error($::locale->text("You do not have the permissions to access this function.")); } - $main::lxdebug->leave_sub(2); + $::lxdebug->leave_sub(2); return 0; } sub load_rights_for_user { - $main::lxdebug->enter_sub(); - - my $self = shift; - my $login = shift; - - my $form = $main::form; - my $dbh = $self->dbconnect(); + $::lxdebug->enter_sub; + my ($self, $login) = @_; + my $dbh = $self->dbconnect; my ($query, $sth, $row, $rights); - $rights = {}; + $rights = { map { $_ => 0 } all_rights() }; $query = qq|SELECT gr."right", gr.granted @@ -1047,18 +1270,112 @@ sub load_rights_for_user { LEFT JOIN auth."user" u ON (ug.user_id = u.id) WHERE u.login = ?)|; - $sth = prepare_execute_query($form, $dbh, $query, $login); + $sth = prepare_execute_query($::form, $dbh, $query, $login); while ($row = $sth->fetchrow_hashref()) { $rights->{$row->{right}} |= $row->{granted}; } $sth->finish(); - map({ $rights->{$_} = 0 unless (defined $rights->{$_}); } SL::Auth::all_rights()); - - $main::lxdebug->leave_sub(); + $::lxdebug->leave_sub; return $rights; } 1; +__END__ + +=pod + +=encoding utf8 + +=head1 NAME + +SL::Auth - Authentication and session handling + +=head1 FUNCTIONS + +=over 4 + +=item C + +=item C + +Store all values of C<@values> or C<%values> in the session. Each +member of C<@values> is tested if it is a hash reference. If it is +then it must contain the keys C and C and can optionally +contain the key C. In this case C is associated +with C and restored to C<$::form> upon the next request +automatically if C is trueish or if C is a scalar +value. + +If the current member of C<@values> is not a hash reference then it +will be used as the C and the next entry of C<@values> is used as +the C to store. In this case setting C is not +possible. + +Therefore the following two invocations are identical: + + $::auth-Eset_session_value(name =E "Charlie"); + $::auth-Eset_session_value({ key =E "name", value =E "Charlie" }); + +All of these values are copied back into C<$::form> for the next +request automatically if they're scalar values or if they have +C set to trueish. + +The values can be any Perl structure. They are stored as YAML dumps. + +=item C + +Retrieve a value from the session. Returns C if the value +doesn't exist. + +=item C + +Create a unique key in the session and store C<$value> +there. + +Returns the key created in the session. + +=item C + +Stores the session values in the database. This is the only function +that actually stores stuff in the database. Neither the various +setters nor the deleter access the database. + +=item + +Stores the content of C<$params{form}> (default: C<$::form>) in the +session using L. + +If C<$params{non_scalars}> is trueish then non-scalar values will be +stored as well. Default is to only store scalar values. + +The following keys will never be saved: C, C, +C, C, C. Additional keys not to save +can be given as an array ref in C<$params{skip_keys}>. + +Returns the unique key under which the form is stored. + +=item + +Restores the form from the session into C<$params{form}> (default: +C<$::form>). + +If C<$params{clobber}> is falsish then existing values with the same +key in C<$params{form}> will not be overwritten. C<$params{clobber}> +is on by default. + +Returns C<$self>. + +=back + +=head1 BUGS + +Nothing here yet. + +=head1 AUTHOR + +Moritz Bunkus Em.bunkus@linet-services.deE + +=cut