X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FAuth.pm;h=9b465ce65ed1639a1cf4ce267ea023caf7b8c403;hb=8fdebd9cf2e3aa8fc9643f34cec96f172812abfb;hp=cbd90bcdb5114c3e1d63a9473b68ce621a96fc64;hpb=de998cce754a73341988441034e2649f3ded6c54;p=kivitendo-erp.git diff --git a/SL/Auth.pm b/SL/Auth.pm index cbd90bcdb..9b465ce65 100644 --- a/SL/Auth.pm +++ b/SL/Auth.pm @@ -1,19 +1,22 @@ 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::DBUtils; +use strict; + sub new { $main::lxdebug->enter_sub(); @@ -31,25 +34,57 @@ sub new { return $self; } +sub get_user_dbh { + my ($self, $login) = @_; + my %user = $self->read_user($login); + my $dbh = DBI->connect( + $user{dbconnect}, + $user{dbuser}, + $user{dbpasswd}, + { + pg_enable_utf8 => $::locale->is_utf8, + AutoCommit => 0 + } + ) or $::form->dberror; + + if ($user{dboptions}) { + $dbh->do($user{dboptions}) or $::form->dberror($user{dboptions}); + } + + return $dbh; +} + sub DESTROY { my $self = shift; $self->{dbh}->disconnect() if ($self->{dbh}); } +# form isn't loaded yet, so auth needs it's own error. +sub mini_error { + $::lxdebug->show_backtrace(); + + 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; - my $form = $main::form; - my $locale = $main::locale; - my $code; my $in = IO::File->new('config/authentication.pl', 'r'); if (!$in) { - $form->error($locale->text('The config file "config/authentication.pl" was not found.')); + my $locale = Locale->new('en'); + $self->mini_error($locale->text('The config file "config/authentication.pl" was not found.')); } while (<$in>) { @@ -60,7 +95,8 @@ sub _read_auth_config { eval $code; if ($@) { - $form->error($locale->text('The config file "config/authentication.pl" contained invalid Perl code:') . "\n" . $@); + my $locale = Locale->new('en'); + $self->mini_error($locale->text('The config file "config/authentication.pl" contained invalid Perl code:'), $@); } if ($self->{module} eq 'DB') { @@ -71,21 +107,27 @@ 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/authentication.pl".')); } 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/authentication.pl: 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/authentication.pl: Missing parameters in "DB_config". 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(); } @@ -101,7 +143,9 @@ sub authenticate_root { $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 { @@ -111,17 +155,20 @@ sub authenticate { $main::lxdebug->leave_sub(); - return $self->{authenticator}->authenticate(@_); + my $result = $self->{authenticator}->authenticate(@_); + 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,9 +179,9 @@ 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} = DBI->connect($dsn, $cfg->{user}, $cfg->{password}, { pg_enable_utf8 => $::locale->is_utf8, AutoCommit => 0 }); if (!$may_fail && !$self->{dbh}) { $main::form->error($main::locale->text('The connection to the authentication database failed:') . "\n" . $DBI::errstr); @@ -207,29 +254,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 = $main::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 = DBI->connect($dsn, $params{superuser}, $params{superuser_password}, { pg_enable_utf8 => $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,7 +299,7 @@ sub create_tables { my $self = shift; my $dbh = $self->dbconnect(); - my $charset = $main::charset; + my $charset = $main::dbcharset; $charset ||= Common::DEFAULT_CHARSET; $dbh->rollback(); @@ -342,7 +398,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 +408,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(); @@ -416,34 +472,52 @@ 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() - '8h'::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 SESSION_EXPIRED; } $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}} = $ref->{sess_value} if (!defined $form->{$ref->{sess_key}}); + my $value = $self->_load_value($ref->{sess_value}); + $self->{SESSION}->{$ref->{sess_key}} = $value; + $form->{$ref->{sess_key}} = $value if (!defined $form->{$ref->{sess_key}}); } $sth->finish(); $main::lxdebug->leave_sub(); + + return SESSION_OK; +} + +sub _load_value { + return $_[1] if $_[1] !~ m/^---/; + + my $value; + eval { + $value = YAML::Load($_[1]); + 1; + } or return $_[1]; + + return $value; } sub destroy_session { @@ -477,13 +551,13 @@ sub expire_sessions { WHERE session_id IN (SELECT id FROM auth.session - WHERE (mtime < (now() - '8h'::interval)))|; + WHERE (mtime < (now() - '$self->{session_timeout}m'::interval)))|; do_query($main::form, $dbh, $query); $query = qq|DELETE FROM auth.session - WHERE (mtime < (now() - '8h'::interval))|; + WHERE (mtime < (now() - '$self->{session_timeout}m'::interval))|; do_query($main::form, $dbh, $query); @@ -495,9 +569,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); @@ -549,15 +620,13 @@ sub create_or_refresh_session { sub set_session_value { $main::lxdebug->enter_sub(); - my $self = shift; + my $self = shift; + my %params = @_; $self->{SESSION} ||= { }; - while (2 <= scalar @_) { - my $key = shift; - my $value = shift; - - $self->{SESSION}->{$key} = $value; + while (my ($key, $value) = each %params) { + $self->{SESSION}->{ $key } = YAML::Dump($value); } $main::lxdebug->leave_sub(); @@ -608,6 +677,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 +702,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 +718,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 +755,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(); @@ -722,7 +812,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(); @@ -789,7 +879,7 @@ sub evaluate_rights_ary { } } - $main::lxdebug->enter_sub(2); + $main::lxdebug->leave_sub(2); return $value; } @@ -823,7 +913,7 @@ sub _parse_rights_string { pop @stack; if (!@stack) { - $main::lxdebug->enter_sub(2); + $main::lxdebug->leave_sub(2); return 0; } @@ -839,7 +929,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; }