X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FAuth.pm;h=ff77bfcc795b20b9dfd7e85f0303a3439367399d;hb=c781fb44ddffd751ae494781cbd239c44c844e15;hp=062a4baeb66448287f309c7d080ebbd206a5e552;hpb=8c7e44938a661e035f62840e1e177353240ace5d;p=kivitendo-erp.git diff --git a/SL/Auth.pm b/SL/Auth.pm index 062a4baeb..ff77bfcc7 100644 --- a/SL/Auth.pm +++ b/SL/Auth.pm @@ -1,19 +1,24 @@ package SL::Auth; -use constant OK => 0; -use constant ERR_PASSWORD => 1; -use constant ERR_BACKEND => 100; +use DBI; use Digest::MD5 qw(md5_hex); use IO::File; use Time::HiRes qw(gettimeofday); +use List::MoreUtils qw(uniq); +use YAML; +use SL::Auth::Constants qw(:all); use SL::Auth::DB; use SL::Auth::LDAP; use SL::User; +use SL::DBConnect; +use SL::DBUpgrade2; use SL::DBUtils; +use strict; + sub new { $main::lxdebug->enter_sub(); @@ -31,37 +36,69 @@ sub new { return $self; } -sub DESTROY { - my $self = shift; +sub reset { + my ($self, %params) = @_; - $self->{dbh}->disconnect() if ($self->{dbh}); + $self->{SESSION} = { }; + $self->{FULL_RIGHTS} = { }; + $self->{RIGHTS} = { }; + $self->{unique_counter} = 0; } -sub _read_auth_config { - $main::lxdebug->enter_sub(); +sub get_user_dbh { + my ($self, $login, %params) = @_; + my $may_fail = delete $params{may_fail}; + + my %user = $self->read_user($login); + my $dbh = SL::DBConnect->connect( + $user{dbconnect}, + $user{dbuser}, + $user{dbpasswd}, + { + pg_enable_utf8 => $::locale->is_utf8, + AutoCommit => 0 + } + ); - my $self = shift; + if (!$may_fail && !$dbh) { + $::form->error($::locale->text('The connection to the authentication database failed:') . "\n" . $DBI::errstr); + } - my $form = $main::form; - my $locale = $main::locale; + if ($user{dboptions} && $dbh) { + $dbh->do($user{dboptions}) or $::form->dberror($user{dboptions}); + } - my $code; - my $in = IO::File->new('config/authentication.pl', 'r'); + return $dbh; +} - if (!$in) { - $form->error($locale->text('The config file "config/authentication.pl" was not found.')); - } +sub DESTROY { + my $self = shift; - while (<$in>) { - $code .= $_; - } - $in->close(); + $self->{dbh}->disconnect() if ($self->{dbh}); +} - eval $code; +# form isn't loaded yet, so auth needs it's own error. +sub mini_error { + $::lxdebug->show_backtrace(); - if ($@) { - $form->error($locale->text('The config file "config/authentication.pl" contained invalid Perl code:') . "\n" . $@); + my ($self, @msg) = @_; + if ($ENV{HTTP_USER_AGENT}) { + print Form->create_http_response(content_type => 'text/html'); + print "
", join ('
', @msg), "
"; + } else { + print STDERR "Error: @msg\n"; } + ::end_of_request(); +} + +sub _read_auth_config { + $main::lxdebug->enter_sub(); + + my $self = shift; + + 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); @@ -71,57 +108,68 @@ sub _read_auth_config { } if (!$self->{authenticator}) { - $form->error($locale->text('No or an unknown authenticantion module specified in "config/authentication.pl".')); + my $locale = Locale->new('en'); + $self->mini_error($locale->text('No or an unknown authenticantion module specified in "config/lx_office.conf".')); } my $cfg = $self->{DB_config}; if (!$cfg) { - $form->error($locale->text('config/authentication.pl: Key "DB_config" is missing.')); + my $locale = Locale->new('en'); + $self->mini_error($locale->text('config/lx_office.conf: Key "DB_config" is missing.')); } if (!$cfg->{host} || !$cfg->{db} || !$cfg->{user}) { - $form->error($locale->text('config/authentication.pl: Missing parameters in "DB_config". Required parameters are "host", "db" and "user".')); + my $locale = Locale->new('en'); + $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(); + $self->{session_timeout} *= 1; + $self->{session_timeout} = 8 * 60 if (!$self->{session_timeout}); + $main::lxdebug->leave_sub(); } sub authenticate_root { $main::lxdebug->enter_sub(); - my $self = shift; - my $password = shift; - my $is_crypted = shift; + my $self = shift; + my $password = shift; + my $is_crypted = shift; - $password = crypt $password, 'ro' if (!$password || !$is_crypted); - $admin_password = crypt "$self->{admin_password}", 'ro'; + $password = crypt $password, 'ro' if (!$password || !$is_crypted); + my $admin_password = crypt "$self->{admin_password}", 'ro'; $main::lxdebug->leave_sub(); - return $password eq $admin_password ? OK : ERR_PASSWORD; + return OK if $password eq $admin_password; + sleep 5; + return ERR_PASSWORD; } sub authenticate { $main::lxdebug->enter_sub(); - my $self = shift; + my ($self, $login, $password) = @_; $main::lxdebug->leave_sub(); - return $self->{authenticator}->authenticate(@_); + my $result = $login ? $self->{authenticator}->authenticate($login, $password) : ERR_USER; + return OK if $result eq OK; + sleep 5; + return $result; } sub dbconnect { - $main::lxdebug->enter_sub(); + $main::lxdebug->enter_sub(2); my $self = shift; my $may_fail = shift; if ($self->{dbh}) { - $main::lxdebug->leave_sub(); + $main::lxdebug->leave_sub(2); return $self->{dbh}; } @@ -132,15 +180,15 @@ sub dbconnect { $dsn .= ';port=' . $cfg->{port}; } - $main::lxdebug->message(LXDebug::DEBUG1, "Auth::dbconnect DSN: $dsn"); + $main::lxdebug->message(LXDebug->DEBUG1, "Auth::dbconnect DSN: $dsn"); - $self->{dbh} = DBI->connect($dsn, $cfg->{user}, $cfg->{password}, { '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); } - $main::lxdebug->leave_sub(); + $main::lxdebug->leave_sub(2); return $self->{dbh}; } @@ -207,29 +255,38 @@ sub create_database { $dsn .= ';port=' . $cfg->{port}; } - $main::lxdebug->message(LXDebug::DEBUG1, "Auth::create_database DSN: $dsn"); + $main::lxdebug->message(LXDebug->DEBUG1(), "Auth::create_database DSN: $dsn"); + + my $charset = $::lx_office_conf{system}->{dbcharset}; + $charset ||= Common::DEFAULT_CHARSET; + my $encoding = $Common::charset_to_db_encoding{$charset}; + $encoding ||= 'UNICODE'; - my $dbh = DBI->connect($dsn, $params{superuser}, $params{superuser_password}); + 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); } - my $charset = $main::charset; - $charset ||= Common::DEFAULT_CHARSET; - my $encoding = $Common::charset_to_db_encoding{$charset}; - $encoding ||= 'UNICODE'; - my $query = qq|CREATE DATABASE "$cfg->{db}" OWNER "$cfg->{user}" TEMPLATE "$params{template}" ENCODING '$encoding'|; - $main::lxdebug->message(LXDebug::DEBUG1, "Auth::create_database query: $query"); + $main::lxdebug->message(LXDebug->DEBUG1(), "Auth::create_database query: $query"); $dbh->do($query); if ($dbh->err) { + my $error = $dbh->errstr(); + + $query = qq|SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = 'template0'|; + my ($cluster_encoding) = $dbh->selectrow_array($query); + + if ($cluster_encoding && ($cluster_encoding =~ m/^(?:UTF-?8|UNICODE)$/i) && ($encoding !~ m/^(?:UTF-?8|UNICODE)$/i)) { + $error = $main::locale->text('Your PostgreSQL installationen uses UTF-8 as its encoding. Therefore you have to configure Lx-Office to use UTF-8 as well.'); + } + $dbh->disconnect(); - $main::form->error($main::locale->text('The creation of the authentication database failed:') . "\n" . $DBI::errstr); + $main::form->error($main::locale->text('The creation of the authentication database failed:') . "\n" . $error); } $dbh->disconnect(); @@ -243,11 +300,11 @@ sub create_tables { my $self = shift; my $dbh = $self->dbconnect(); - my $charset = $main::charset; + my $charset = $::lx_office_conf{system}->{dbcharset}; $charset ||= Common::DEFAULT_CHARSET; $dbh->rollback(); - User->process_query($main::form, $dbh, 'sql/auth_db.sql', undef, $charset); + SL::DBUpgrade2->new(form => $::form)->process_query($dbh, 'sql/auth_db.sql', undef, $charset); $main::lxdebug->leave_sub(); } @@ -265,6 +322,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); @@ -325,7 +384,7 @@ sub read_all_users { while (my $ref = $sth->fetchrow_hashref()) { $users{$ref->{login}} ||= { 'login' => $ref->{login}, 'id' => $ref->{id} }; - $users{$ref->{login}}->{$ref->{cfg_key}} = $ref->{cfg_value} if (($cfg_key ne 'login') && ($cfg_key ne 'id')); + $users{$ref->{login}}->{$ref->{cfg_key}} = $ref->{cfg_value} if (($ref->{cfg_key} ne 'login') && ($ref->{cfg_key} ne 'id')); } $sth->finish(); @@ -342,7 +401,7 @@ sub read_user { my $login = shift; my $dbh = $self->dbconnect(); - my $query = qq|SELECT cfg.cfg_key, cfg.cfg_value + 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 = ?)|; @@ -352,7 +411,7 @@ sub read_user { while (my $ref = $sth->fetchrow_hashref()) { $user_data{$ref->{cfg_key}} = $ref->{cfg_value}; - $user_data{login} = $login; + @user_data{qw(id login)} = @{$ref}{qw(id login)}; } $sth->finish(); @@ -377,26 +436,30 @@ 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 $u_dbh = $self->get_user_dbh($login, may_fail => 1); + my $dbh = $self->dbconnect; + + $dbh->begin_work; - my $dbh = $self->dbconnect(); my $query = qq|SELECT id FROM auth."user" WHERE login = ?|; - my ($id) = selectrow_query($form, $dbh, $query, $login); + my ($id) = selectrow_query($::form, $dbh, $query, $login); - return $main::lxdebug->leave_sub() if (!$id); + $dbh->rollback and return $::lxdebug->leave_sub if (!$id); - 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_group WHERE user_id = ?|, $id); + do_query($::form, $dbh, qq|DELETE FROM auth.user_config WHERE user_id = ?|, $id); + do_query($::form, $u_dbh, qq|UPDATE employee SET deleted = 't' WHERE login = ?|, $login) if $u_dbh; - $dbh->commit(); + $dbh->commit; + $u_dbh->commit if $u_dbh; - $main::lxdebug->leave_sub(); + $::lxdebug->leave_sub; } # -------------------------------------- @@ -416,21 +479,24 @@ sub restore_session { $self->{SESSION} = { }; - return $main::lxdebug->leave_sub() if (!$session_id); + if (!$session_id) { + $main::lxdebug->leave_sub(); + return SESSION_NONE; + } my ($dbh, $query, $sth, $cookie, $ref, $form); $form = $main::form; $dbh = $self->dbconnect(); - $query = qq|SELECT *, (mtime < (now() - '24h'::interval)) AS is_expired FROM auth.session WHERE id = ?|; + $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 (!$cookie || $cookie->{is_expired} || ($cookie->{ip_address} ne $ENV{REMOTE_ADDR})) { $self->destroy_session(); $main::lxdebug->leave_sub(); - return; + return $cookie ? SESSION_EXPIRED : SESSION_NONE; } $query = qq|SELECT sess_key, sess_value FROM auth.session_content WHERE session_id = ?|; @@ -438,12 +504,40 @@ sub restore_session { while (my $ref = $sth->fetchrow_hashref()) { $self->{SESSION}->{$ref->{sess_key}} = $ref->{sess_value}; - $form->{$ref->{sess_key}} = $ref->{sess_value} if (!defined $form->{$ref->{sess_key}}); + next if defined $form->{$ref->{sess_key}}; + + my $params = $self->_load_value($ref->{sess_value}); + $form->{$ref->{sess_key}} = $params->{data} if $params->{auto_restore} || $params->{simple}; } $sth->finish(); $main::lxdebug->leave_sub(); + + return SESSION_OK; +} + +sub _load_value { + my ($self, $value) = @_; + + return { simple => 1, data => $value } if $value !~ m/^---/; + + my %params = ( simple => 1 ); + eval { + my $data = YAML::Load($value); + + if (ref $data eq 'HASH') { + map { $params{$_} = $data->{$_} } keys %{ $data }; + $params{simple} = 0; + + } else { + $params{data} = $data; + } + + 1; + } or $params{data} = $value; + + return \%params; } sub destroy_session { @@ -454,6 +548,8 @@ 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); @@ -472,18 +568,21 @@ sub expire_sessions { my $self = shift; my $dbh = $self->dbconnect(); + + $dbh->begin_work; + my $query = qq|DELETE FROM auth.session_content WHERE session_id IN (SELECT id FROM auth.session - WHERE (mtime < (now() - '24h'::interval)))|; + WHERE (mtime < (now() - '$self->{session_timeout}m'::interval)))|; do_query($main::form, $dbh, $query); $query = qq|DELETE FROM auth.session - WHERE (mtime < (now() - '24h'::interval))|; + WHERE (mtime < (now() - '$self->{session_timeout}m'::interval))|; do_query($main::form, $dbh, $query); @@ -495,9 +594,6 @@ sub expire_sessions { sub _create_session_id { $main::lxdebug->enter_sub(); - my @secs = gettimeofday(); - srand $secs[1] + $$; - my @data; map { push @data, int(rand() * 255); } (1..32); @@ -509,58 +605,159 @@ 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 = ?|; + do_query($::form, $dbh, qq|LOCK auth.session_content|); + do_query($::form, $dbh, qq|DELETE FROM auth.session_content WHERE session_id = ?|, $session_id); - ($id) = selectrow_query($form, $dbh, $query, $session_id); + my $query = qq|SELECT id FROM auth.session WHERE id = ?|; - if ($id) { - do_query($form, $dbh, qq|UPDATE auth.session SET mtime = now() WHERE id = ?|, $session_id); - do_query($form, $dbh, qq|DELETE FROM auth.session_content WHERE session_id = ?|, $session_id); + my ($id) = selectrow_query($::form, $dbh, $query, $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}); + do_query($::form, $dbh, qq|INSERT INTO auth.session (id, ip_address, mtime) VALUES (?, ?, now())|, $session_id, $ENV{REMOTE_ADDR}); + } + + 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 $key (sort keys %{ $self->{SESSION} }) { + do_statement($::form, $sth, $query, $session_id, $key, $self->{SESSION}->{$key}); + } + $sth->finish(); } - $query = qq|INSERT INTO auth.session_content (session_id, sess_key, sess_value) VALUES (?, ?, ?)|; - $sth = prepare_query($form, $dbh, $query); + $dbh->commit() unless $provided_dbh; + $::lxdebug->leave_sub; +} - foreach my $key (sort keys %{ $self->{SESSION} }) { - do_statement($form, $sth, $query, $session_id, $key, $self->{SESSION}->{$key}); +sub set_session_value { + $main::lxdebug->enter_sub(); + + my $self = shift; + my %params = @_; + + $self->{SESSION} ||= { }; + + while (my ($key, $value) = each %params) { + $self->{SESSION}->{ $key } = YAML::Dump(ref($value) eq 'HASH' ? { data => $value } : $value); } - $sth->finish(); - $dbh->commit(); + $main::lxdebug->leave_sub(); + + return $self; +} + +sub delete_session_value { + $main::lxdebug->enter_sub(); + + my $self = shift; + + $self->{SESSION} ||= { }; + delete @{ $self->{SESSION} }{ @_ }; $main::lxdebug->leave_sub(); + + return $self; } -sub set_session_value { +sub get_session_value { $main::lxdebug->enter_sub(); - my $self = shift; + my $self = shift; + my $params = $self->{SESSION} ? $self->_load_value($self->{SESSION}->{ $_[0] }) : {}; + + $main::lxdebug->leave_sub(); + + return $params->{data}; +} + +sub create_unique_sesion_value { + my ($self, $value, %params) = @_; $self->{SESSION} ||= { }; - while (2 <= scalar @_) { - my $key = shift; - my $value = shift; + my @now = gettimeofday(); + my $key = "$$-" . ($now[0] * 1000000 + $now[1]) . "-"; + $self->{unique_counter} ||= 0; + + $self->{unique_counter}++ while exists $self->{SESSION}->{$key . $self->{unique_counter}}; + $self->{unique_counter}++; + + $value = { expiration => $params{expiration} ? ($now[0] + $params{expiration}) * 1000000 + $now[1] : undef, + data => $value, + }; + + $self->{SESSION}->{$key . $self->{unique_counter}} = YAML::Dump($value); + + return $key . $self->{unique_counter}; +} + +sub save_form_in_session { + my ($self, %params) = @_; + + my $form = delete($params{form}) || $::form; + my $non_scalars = delete $params{non_scalars}; + my $data = {}; - $self->{SESSION}->{$key} = $value; + 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; } - $main::lxdebug->leave_sub(); + 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 expire_session_keys { + my ($self) = @_; + + $self->{SESSION} ||= { }; + + my @now = gettimeofday(); + my $now = $now[0] * 1000000 + $now[1]; + + $self->delete_session_value(map { $_->[0] } + grep { $_->[1]->{expiration} && ($now > $_->[1]->{expiration}) } + map { [ $_, $self->_load_value($self->{SESSION}->{$_}) ] } + keys %{ $self->{SESSION} }); + + return $self; +} + +sub _has_expiration { + my ($value) = @_; + return (ref $value eq 'HASH') && exists($value->{expiration}) && $value->{data}; } sub set_cookie_environment_variable { @@ -608,6 +805,20 @@ sub all_rights_full { my $locale = $main::locale; my @all_rights = ( + ["--crm", $locale->text("CRM optional software")], + ["crm_search", $locale->text("CRM search")], + ["crm_new", $locale->text("CRM create customers, vendors and contacts")], + ["crm_service", $locale->text("CRM services")], + ["crm_admin", $locale->text("CRM admin")], + ["crm_adminuser", $locale->text("CRM user")], + ["crm_adminstatus", $locale->text("CRM status")], + ["crm_email", $locale->text("CRM send email")], + ["crm_termin", $locale->text("CRM termin")], + ["crm_opportunity", $locale->text("CRM opportunity")], + ["crm_knowhow", $locale->text("CRM know how")], + ["crm_follow", $locale->text("CRM follow up")], + ["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")], ["part_service_assembly_edit", $locale->text("Create and edit parts, services, assemblies")], @@ -619,11 +830,15 @@ sub all_rights_full { ["sales_delivery_order_edit", $locale->text("Create and edit sales delivery orders")], ["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")], ["--ap", $locale->text("AP")], ["request_quotation_edit", $locale->text("Create and edit RFQs")], ["purchase_order_edit", $locale->text("Create and edit purchase orders")], ["purchase_delivery_order_edit", $locale->text("Create and edit purchase delivery orders")], ["vendor_invoice_edit", $locale->text("Create and edit vendor invoices")], + ["--warehouse_management", $locale->text("Warehouse management")], + ["warehouse_contents", $locale->text("View warehouse content")], + ["warehouse_management", $locale->text("Warehouse management")], ["--general_ledger_cash", $locale->text("General ledger and cash")], ["general_ledger", $locale->text("Transactions, AR transactions, AP transactions")], ["datev_export", $locale->text("DATEV Export")], @@ -631,6 +846,8 @@ sub all_rights_full { ["--reports", $locale->text('Reports')], ["report", $locale->text('All reports')], ["advance_turnover_tax_return", $locale->text('Advance turnover tax return')], + ["--batch_printing", $locale->text("Batch Printing")], + ["batch_printing", $locale->text("Batch Printing")], ["--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')")], @@ -666,13 +883,14 @@ sub read_groups { $sth = prepare_query($form, $dbh, $query); foreach $group (values %{$groups}) { - $group->{members} = []; + my @members; do_statement($form, $sth, $query, $group->{id}); while ($row = $sth->fetchrow_hashref()) { - push @{$group->{members}}, $row->{user_id}; + push @members, $row->{user_id}; } + $group->{members} = [ uniq @members ]; } $sth->finish(); @@ -706,6 +924,8 @@ sub save_group { my $form = $main::form; my $dbh = $self->dbconnect(); + $dbh->begin_work; + my ($query, $sth, $row, $rights); if (!$group->{id}) { @@ -722,7 +942,7 @@ sub save_group { $query = qq|INSERT INTO auth.user_group (user_id, group_id) VALUES (?, ?)|; $sth = prepare_query($form, $dbh, $query); - foreach my $user_id (@{ $group->{members} }) { + foreach my $user_id (uniq @{ $group->{members} }) { do_statement($form, $sth, $query, $user_id, $group->{id}); } $sth->finish(); @@ -748,9 +968,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); @@ -789,7 +1010,7 @@ sub evaluate_rights_ary { } } - $main::lxdebug->enter_sub(2); + $main::lxdebug->leave_sub(2); return $value; } @@ -823,7 +1044,7 @@ sub _parse_rights_string { pop @stack; if (!@stack) { - $main::lxdebug->enter_sub(2); + $main::lxdebug->leave_sub(2); return 0; } @@ -839,7 +1060,7 @@ sub _parse_rights_string { my $result = ($access || (1 < scalar @stack)) ? 0 : evaluate_rights_ary($stack[0]); - $main::lxdebug->enter_sub(2); + $main::lxdebug->leave_sub(2); return $result; } @@ -871,41 +1092,32 @@ sub check_right { } sub assert { - $main::lxdebug->enter_sub(2); - - my $self = shift; - my $right = shift; - my $dont_abort = shift; - - my $form = $main::form; + $::lxdebug->enter_sub(2); + my ($self, $right, $dont_abort) = @_; - 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 { $rights->{$_} = 0 } all_rights() }; $query = qq|SELECT gr."right", gr.granted @@ -916,18 +1128,101 @@ 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 + +Store all key/value pairs in C<%values> in the session. All of these +values are copied back into C<$::form> in the next request +automatically. + +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. + +If C<$params{expiration}> is set then it is interpreted as a number of +seconds after which the value is removed from the session. It will +never expire if that parameter is falsish. + +Returns the key created in the session. + +=item C + +Removes all keys from the session that have an expiration time set and +whose expiration time is in the past. + +=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