Lieferadresse bei Auftrag->Lieferschein Umwandlung nicht vergessen.
[kivitendo-erp.git] / SL / Auth.pm
index 1d2f36f..eb5a780 100644 (file)
@@ -1,19 +1,21 @@
 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 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,6 +33,26 @@ 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;
 
@@ -86,18 +108,21 @@ sub _read_auth_config {
 
   $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);
-  my $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();
 
@@ -115,13 +140,13 @@ sub authenticate {
 }
 
 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 +157,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 +232,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 +277,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 +376,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 +386,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,21 +450,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 SESSION_EXPIRED;
   }
 
   $query = qq|SELECT sess_key, sess_value FROM auth.session_content WHERE session_id = ?|;
@@ -444,6 +481,8 @@ sub restore_session {
   $sth->finish();
 
   $main::lxdebug->leave_sub();
+
+  return SESSION_OK;
 }
 
 sub destroy_session {
@@ -477,13 +516,13 @@ sub expire_sessions {
        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 +534,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);
 
@@ -608,6 +644,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 +669,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")],
@@ -666,13 +720,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 +777,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 +844,7 @@ sub evaluate_rights_ary {
     }
   }
 
-  $main::lxdebug->enter_sub(2);
+  $main::lxdebug->leave_sub(2);
 
   return $value;
 }
@@ -823,7 +878,7 @@ sub _parse_rights_string {
       pop @stack;
 
       if (!@stack) {
-        $main::lxdebug->enter_sub(2);
+        $main::lxdebug->leave_sub(2);
         return 0;
       }
 
@@ -839,7 +894,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;
 }