5 use Digest::MD5 qw(md5_hex);
7 use Time::HiRes qw(gettimeofday);
8 use List::MoreUtils qw(uniq);
11 use SL::Auth::Constants qw(:all);
23 $main::lxdebug->enter_sub();
30 $self->{SESSION} = { };
32 $self->_read_auth_config();
34 $main::lxdebug->leave_sub();
40 my ($self, %params) = @_;
42 $self->{SESSION} = { };
43 $self->{FULL_RIGHTS} = { };
44 $self->{RIGHTS} = { };
45 $self->{unique_counter} = 0;
49 my ($self, $login) = @_;
50 my %user = $self->read_user($login);
51 my $dbh = SL::DBConnect->connect(
56 pg_enable_utf8 => $::locale->is_utf8,
59 ) or $::form->dberror;
61 if ($user{dboptions}) {
62 $dbh->do($user{dboptions}) or $::form->dberror($user{dboptions});
71 $self->{dbh}->disconnect() if ($self->{dbh});
74 # form isn't loaded yet, so auth needs it's own error.
76 $::lxdebug->show_backtrace();
78 my ($self, @msg) = @_;
79 if ($ENV{HTTP_USER_AGENT}) {
80 print Form->create_http_response(content_type => 'text/html');
81 print "<pre>", join ('<br>', @msg), "</pre>";
83 print STDERR "Error: @msg\n";
88 sub _read_auth_config {
89 $main::lxdebug->enter_sub();
93 map { $self->{$_} = $::lx_office_conf{authentication}->{$_} } keys %{ $::lx_office_conf{authentication} };
94 $self->{DB_config} = $::lx_office_conf{'authentication/database'};
95 $self->{LDAP_config} = $::lx_office_conf{'authentication/ldap'};
97 if ($self->{module} eq 'DB') {
98 $self->{authenticator} = SL::Auth::DB->new($self);
100 } elsif ($self->{module} eq 'LDAP') {
101 $self->{authenticator} = SL::Auth::LDAP->new($self);
104 if (!$self->{authenticator}) {
105 my $locale = Locale->new('en');
106 $self->mini_error($locale->text('No or an unknown authenticantion module specified in "config/lx_office.conf".'));
109 my $cfg = $self->{DB_config};
112 my $locale = Locale->new('en');
113 $self->mini_error($locale->text('config/lx_office.conf: Key "DB_config" is missing.'));
116 if (!$cfg->{host} || !$cfg->{db} || !$cfg->{user}) {
117 my $locale = Locale->new('en');
118 $self->mini_error($locale->text('config/lx_office.conf: Missing parameters in "authentication/database". Required parameters are "host", "db" and "user".'));
121 $self->{authenticator}->verify_config();
123 $self->{session_timeout} *= 1;
124 $self->{session_timeout} = 8 * 60 if (!$self->{session_timeout});
126 $main::lxdebug->leave_sub();
129 sub authenticate_root {
130 $main::lxdebug->enter_sub();
133 my $password = shift;
134 my $is_crypted = shift;
136 $password = crypt $password, 'ro' if (!$password || !$is_crypted);
137 my $admin_password = crypt "$self->{admin_password}", 'ro';
139 $main::lxdebug->leave_sub();
141 return OK if $password eq $admin_password;
147 $main::lxdebug->enter_sub();
149 my ($self, $login, $password) = @_;
151 $main::lxdebug->leave_sub();
153 my $result = $login ? $self->{authenticator}->authenticate($login, $password) : ERR_USER;
154 return OK if $result eq OK;
160 $main::lxdebug->enter_sub(2);
163 my $may_fail = shift;
166 $main::lxdebug->leave_sub(2);
170 my $cfg = $self->{DB_config};
171 my $dsn = 'dbi:Pg:dbname=' . $cfg->{db} . ';host=' . $cfg->{host};
174 $dsn .= ';port=' . $cfg->{port};
177 $main::lxdebug->message(LXDebug->DEBUG1, "Auth::dbconnect DSN: $dsn");
179 $self->{dbh} = SL::DBConnect->connect($dsn, $cfg->{user}, $cfg->{password}, { pg_enable_utf8 => $::locale->is_utf8, AutoCommit => 1 });
181 if (!$may_fail && !$self->{dbh}) {
182 $main::form->error($main::locale->text('The connection to the authentication database failed:') . "\n" . $DBI::errstr);
185 $main::lxdebug->leave_sub(2);
191 $main::lxdebug->enter_sub();
196 $self->{dbh}->disconnect();
200 $main::lxdebug->leave_sub();
204 $main::lxdebug->enter_sub();
208 my $dbh = $self->dbconnect();
209 my $query = qq|SELECT COUNT(*) FROM pg_tables WHERE (schemaname = 'auth') AND (tablename = 'user')|;
211 my ($count) = $dbh->selectrow_array($query);
213 $main::lxdebug->leave_sub();
219 $main::lxdebug->enter_sub();
223 my $dbh = $self->dbconnect(1);
225 $main::lxdebug->leave_sub();
230 sub create_database {
231 $main::lxdebug->enter_sub();
236 my $cfg = $self->{DB_config};
238 if (!$params{superuser}) {
239 $params{superuser} = $cfg->{user};
240 $params{superuser_password} = $cfg->{password};
243 $params{template} ||= 'template0';
244 $params{template} =~ s|[^a-zA-Z0-9_\-]||g;
246 my $dsn = 'dbi:Pg:dbname=template1;host=' . $cfg->{host};
249 $dsn .= ';port=' . $cfg->{port};
252 $main::lxdebug->message(LXDebug->DEBUG1(), "Auth::create_database DSN: $dsn");
254 my $charset = $::lx_office_conf{system}->{dbcharset};
255 $charset ||= Common::DEFAULT_CHARSET;
256 my $encoding = $Common::charset_to_db_encoding{$charset};
257 $encoding ||= 'UNICODE';
259 my $dbh = SL::DBConnect->connect($dsn, $params{superuser}, $params{superuser_password}, { pg_enable_utf8 => $charset =~ m/^utf-?8$/i });
262 $main::form->error($main::locale->text('The connection to the template database failed:') . "\n" . $DBI::errstr);
265 my $query = qq|CREATE DATABASE "$cfg->{db}" OWNER "$cfg->{user}" TEMPLATE "$params{template}" ENCODING '$encoding'|;
267 $main::lxdebug->message(LXDebug->DEBUG1(), "Auth::create_database query: $query");
272 my $error = $dbh->errstr();
274 $query = qq|SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = 'template0'|;
275 my ($cluster_encoding) = $dbh->selectrow_array($query);
277 if ($cluster_encoding && ($cluster_encoding =~ m/^(?:UTF-?8|UNICODE)$/i) && ($encoding !~ m/^(?:UTF-?8|UNICODE)$/i)) {
278 $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.');
283 $main::form->error($main::locale->text('The creation of the authentication database failed:') . "\n" . $error);
288 $main::lxdebug->leave_sub();
292 $main::lxdebug->enter_sub();
295 my $dbh = $self->dbconnect();
297 my $charset = $::lx_office_conf{system}->{dbcharset};
298 $charset ||= Common::DEFAULT_CHARSET;
301 SL::DBUpgrade2->new(form => $::form)->process_query($dbh, 'sql/auth_db.sql', undef, $charset);
303 $main::lxdebug->leave_sub();
307 $main::lxdebug->enter_sub();
313 my $form = $main::form;
315 my $dbh = $self->dbconnect();
317 my ($sth, $query, $user_id);
321 $query = qq|SELECT id FROM auth."user" WHERE login = ?|;
322 ($user_id) = selectrow_query($form, $dbh, $query, $login);
325 $query = qq|SELECT nextval('auth.user_id_seq')|;
326 ($user_id) = selectrow_query($form, $dbh, $query);
328 $query = qq|INSERT INTO auth."user" (id, login) VALUES (?, ?)|;
329 do_query($form, $dbh, $query, $user_id, $login);
332 $query = qq|DELETE FROM auth.user_config WHERE (user_id = ?)|;
333 do_query($form, $dbh, $query, $user_id);
335 $query = qq|INSERT INTO auth.user_config (user_id, cfg_key, cfg_value) VALUES (?, ?, ?)|;
336 $sth = prepare_query($form, $dbh, $query);
338 while (my ($cfg_key, $cfg_value) = each %params) {
339 next if ($cfg_key eq 'password');
341 do_statement($form, $sth, $query, $user_id, $cfg_key, $cfg_value);
346 $main::lxdebug->leave_sub();
349 sub can_change_password {
352 return $self->{authenticator}->can_change_password();
355 sub change_password {
356 $main::lxdebug->enter_sub();
359 my $result = $self->{authenticator}->change_password(@_);
361 $main::lxdebug->leave_sub();
367 $main::lxdebug->enter_sub();
371 my $dbh = $self->dbconnect();
372 my $query = qq|SELECT u.id, u.login, cfg.cfg_key, cfg.cfg_value
373 FROM auth.user_config cfg
374 LEFT JOIN auth."user" u ON (cfg.user_id = u.id)|;
375 my $sth = prepare_execute_query($main::form, $dbh, $query);
379 while (my $ref = $sth->fetchrow_hashref()) {
380 $users{$ref->{login}} ||= { 'login' => $ref->{login}, 'id' => $ref->{id} };
381 $users{$ref->{login}}->{$ref->{cfg_key}} = $ref->{cfg_value} if (($ref->{cfg_key} ne 'login') && ($ref->{cfg_key} ne 'id'));
386 $main::lxdebug->leave_sub();
392 $main::lxdebug->enter_sub();
397 my $dbh = $self->dbconnect();
398 my $query = qq|SELECT u.id, u.login, cfg.cfg_key, cfg.cfg_value
399 FROM auth.user_config cfg
400 LEFT JOIN auth."user" u ON (cfg.user_id = u.id)
401 WHERE (u.login = ?)|;
402 my $sth = prepare_execute_query($main::form, $dbh, $query, $login);
406 while (my $ref = $sth->fetchrow_hashref()) {
407 $user_data{$ref->{cfg_key}} = $ref->{cfg_value};
408 @user_data{qw(id login)} = @{$ref}{qw(id login)};
413 $main::lxdebug->leave_sub();
419 $main::lxdebug->enter_sub();
424 my $dbh = $self->dbconnect();
425 my ($id) = selectrow_query($main::form, $dbh, qq|SELECT id FROM auth."user" WHERE login = ?|, $login);
427 $main::lxdebug->leave_sub();
433 $main::lxdebug->enter_sub();
438 my $form = $main::form;
440 my $dbh = $self->dbconnect();
444 my $query = qq|SELECT id FROM auth."user" WHERE login = ?|;
446 my ($id) = selectrow_query($form, $dbh, $query, $login);
448 $dbh->rollback and return $main::lxdebug->leave_sub() if (!$id);
450 do_query($form, $dbh, qq|DELETE FROM auth.user_group WHERE user_id = ?|, $id);
451 do_query($form, $dbh, qq|DELETE FROM auth.user_config WHERE user_id = ?|, $id);
455 $main::lxdebug->leave_sub();
458 # --------------------------------------
462 sub restore_session {
463 $main::lxdebug->enter_sub();
467 my $cgi = $main::cgi;
468 $cgi ||= CGI->new('');
470 $session_id = $cgi->cookie($self->get_session_cookie_name());
471 $session_id =~ s|[^0-9a-f]||g;
473 $self->{SESSION} = { };
476 $main::lxdebug->leave_sub();
480 my ($dbh, $query, $sth, $cookie, $ref, $form);
484 $dbh = $self->dbconnect();
485 $query = qq|SELECT *, (mtime < (now() - '$self->{session_timeout}m'::interval)) AS is_expired FROM auth.session WHERE id = ?|;
487 $cookie = selectfirst_hashref_query($form, $dbh, $query, $session_id);
489 if (!$cookie || $cookie->{is_expired} || ($cookie->{ip_address} ne $ENV{REMOTE_ADDR})) {
490 $self->destroy_session();
491 $main::lxdebug->leave_sub();
492 return $cookie ? SESSION_EXPIRED : SESSION_NONE;
495 $query = qq|SELECT sess_key, sess_value FROM auth.session_content WHERE session_id = ?|;
496 $sth = prepare_execute_query($form, $dbh, $query, $session_id);
498 while (my $ref = $sth->fetchrow_hashref()) {
499 $self->{SESSION}->{$ref->{sess_key}} = $ref->{sess_value};
500 next if defined $form->{$ref->{sess_key}};
502 my $params = $self->_load_value($ref->{sess_value});
503 $form->{$ref->{sess_key}} = $params->{data} if $params->{auto_restore} || $params->{simple};
508 $main::lxdebug->leave_sub();
514 my ($self, $value) = @_;
516 return { simple => 1, data => $value } if $value !~ m/^---/;
518 my %params = ( simple => 1 );
520 my $data = YAML::Load($value);
522 if (ref $data eq 'HASH') {
523 map { $params{$_} = $data->{$_} } keys %{ $data };
527 $params{data} = $data;
531 } or $params{data} = $value;
536 sub destroy_session {
537 $main::lxdebug->enter_sub();
542 my $dbh = $self->dbconnect();
546 do_query($main::form, $dbh, qq|DELETE FROM auth.session_content WHERE session_id = ?|, $session_id);
547 do_query($main::form, $dbh, qq|DELETE FROM auth.session WHERE id = ?|, $session_id);
552 $self->{SESSION} = { };
555 $main::lxdebug->leave_sub();
558 sub expire_sessions {
559 $main::lxdebug->enter_sub();
563 my $dbh = $self->dbconnect();
568 qq|DELETE FROM auth.session_content
572 WHERE (mtime < (now() - '$self->{session_timeout}m'::interval)))|;
574 do_query($main::form, $dbh, $query);
577 qq|DELETE FROM auth.session
578 WHERE (mtime < (now() - '$self->{session_timeout}m'::interval))|;
580 do_query($main::form, $dbh, $query);
584 $main::lxdebug->leave_sub();
587 sub _create_session_id {
588 $main::lxdebug->enter_sub();
591 map { push @data, int(rand() * 255); } (1..32);
593 my $id = md5_hex(pack 'C*', @data);
595 $main::lxdebug->leave_sub();
600 sub create_or_refresh_session {
601 $main::lxdebug->enter_sub();
605 $session_id ||= $self->_create_session_id();
607 my ($form, $dbh, $query, $sth, $id);
610 $dbh = $self->dbconnect();
613 do_query($::form, $dbh, qq|LOCK auth.session_content|);
615 $query = qq|SELECT id FROM auth.session WHERE id = ?|;
617 ($id) = selectrow_query($form, $dbh, $query, $session_id);
620 do_query($form, $dbh, qq|UPDATE auth.session SET mtime = now() WHERE id = ?|, $session_id);
623 do_query($form, $dbh, qq|INSERT INTO auth.session (id, ip_address, mtime) VALUES (?, ?, now())|, $session_id, $ENV{REMOTE_ADDR});
627 $self->save_session($dbh);
631 $main::lxdebug->leave_sub();
635 $::lxdebug->enter_sub;
637 my $provided_dbh = shift;
639 my $dbh = $provided_dbh || $self->dbconnect(1);
641 $::lxdebug->leave_sub && return unless $dbh;
643 $dbh->begin_work unless $provided_dbh;
645 do_query($::form, $dbh, qq|LOCK auth.session_content|);
646 do_query($::form, $dbh, qq|DELETE FROM auth.session_content WHERE session_id = ?|, $session_id);
648 if (%{ $self->{SESSION} }) {
649 my $query = qq|INSERT INTO auth.session_content (session_id, sess_key, sess_value) VALUES (?, ?, ?)|;
650 my $sth = prepare_query($::form, $dbh, $query);
652 foreach my $key (sort keys %{ $self->{SESSION} }) {
653 do_statement($::form, $sth, $query, $session_id, $key, $self->{SESSION}->{$key});
659 $dbh->commit() unless $provided_dbh;
660 $::lxdebug->leave_sub;
663 sub set_session_value {
664 $main::lxdebug->enter_sub();
669 $self->{SESSION} ||= { };
671 while (my ($key, $value) = each %params) {
672 $self->{SESSION}->{ $key } = YAML::Dump(ref($value) eq 'HASH' ? { data => $value } : $value);
675 $main::lxdebug->leave_sub();
680 sub delete_session_value {
681 $main::lxdebug->enter_sub();
685 $self->{SESSION} ||= { };
686 delete @{ $self->{SESSION} }{ @_ };
688 $main::lxdebug->leave_sub();
693 sub get_session_value {
694 $main::lxdebug->enter_sub();
697 my $params = $self->{SESSION} ? $self->_load_value($self->{SESSION}->{ $_[0] }) : {};
699 $main::lxdebug->leave_sub();
701 return $params->{data};
704 sub create_unique_sesion_value {
705 my ($self, $value, %params) = @_;
707 $self->{SESSION} ||= { };
709 my @now = gettimeofday();
710 my $key = "$$-" . ($now[0] * 1000000 + $now[1]) . "-";
711 $self->{unique_counter} ||= 0;
713 $self->{unique_counter}++ while exists $self->{SESSION}->{$key . $self->{unique_counter}};
714 $self->{unique_counter}++;
716 $value = { expiration => $params{expiration} ? ($now[0] + $params{expiration}) * 1000000 + $now[1] : undef,
717 no_auto => !$params{auto_restore},
721 $self->{SESSION}->{$key . $self->{unique_counter}} = YAML::Dump($value);
723 return $key . $self->{unique_counter};
726 sub save_form_in_session {
727 my ($self, %params) = @_;
729 my $form = delete($params{form}) || $::form;
730 my $non_scalars = delete $params{non_scalars};
733 my %skip_keys = map { ( $_ => 1 ) } (qw(login password stylesheet version titlebar), @{ $params{skip_keys} || [] });
735 foreach my $key (grep { !$skip_keys{$_} } keys %{ $form }) {
736 $data->{$key} = $form->{$key} if !ref($form->{$key}) || $non_scalars;
739 return $self->create_unique_sesion_value($data, %params);
742 sub restore_form_from_session {
743 my ($self, $key, %params) = @_;
745 my $data = $self->get_session_value($key);
746 return $self unless $data;
748 my $form = delete($params{form}) || $::form;
749 my $clobber = exists $params{clobber} ? $params{clobber} : 1;
751 map { $form->{$_} = $data->{$_} if $clobber || !exists $form->{$_} } keys %{ $data };
756 sub expire_session_keys {
759 $self->{SESSION} ||= { };
761 my @now = gettimeofday();
762 my $now = $now[0] * 1000000 + $now[1];
764 $self->delete_session_value(map { $_->[0] }
765 grep { $_->[1]->{expiration} && ($now > $_->[1]->{expiration}) }
766 map { [ $_, $self->_load_value($self->{SESSION}->{$_}) ] }
767 keys %{ $self->{SESSION} });
772 sub _has_expiration {
774 return (ref $value eq 'HASH') && exists($value->{expiration}) && $value->{data};
777 sub set_cookie_environment_variable {
779 $ENV{HTTP_COOKIE} = $self->get_session_cookie_name() . "=${session_id}";
782 sub get_session_cookie_name {
785 return $self->{cookie_name} || 'lx_office_erp_session_id';
792 sub session_tables_present {
793 $main::lxdebug->enter_sub();
796 my $dbh = $self->dbconnect(1);
799 $main::lxdebug->leave_sub();
806 WHERE (schemaname = 'auth')
807 AND (tablename IN ('session', 'session_content'))|;
809 my ($count) = selectrow_query($main::form, $dbh, $query);
811 $main::lxdebug->leave_sub();
816 # --------------------------------------
818 sub all_rights_full {
819 my $locale = $main::locale;
822 ["--crm", $locale->text("CRM optional software")],
823 ["crm_search", $locale->text("CRM search")],
824 ["crm_new", $locale->text("CRM create customers, vendors and contacts")],
825 ["crm_service", $locale->text("CRM services")],
826 ["crm_admin", $locale->text("CRM admin")],
827 ["crm_adminuser", $locale->text("CRM user")],
828 ["crm_adminstatus", $locale->text("CRM status")],
829 ["crm_email", $locale->text("CRM send email")],
830 ["crm_termin", $locale->text("CRM termin")],
831 ["crm_opportunity", $locale->text("CRM opportunity")],
832 ["crm_knowhow", $locale->text("CRM know how")],
833 ["crm_follow", $locale->text("CRM follow up")],
834 ["crm_notices", $locale->text("CRM notices")],
835 ["crm_other", $locale->text("CRM other")],
836 ["--master_data", $locale->text("Master Data")],
837 ["customer_vendor_edit", $locale->text("Create and edit customers and vendors")],
838 ["part_service_assembly_edit", $locale->text("Create and edit parts, services, assemblies")],
839 ["project_edit", $locale->text("Create and edit projects")],
840 ["license_edit", $locale->text("Manage license keys")],
841 ["--ar", $locale->text("AR")],
842 ["sales_quotation_edit", $locale->text("Create and edit sales quotations")],
843 ["sales_order_edit", $locale->text("Create and edit sales orders")],
844 ["sales_delivery_order_edit", $locale->text("Create and edit sales delivery orders")],
845 ["invoice_edit", $locale->text("Create and edit invoices and credit notes")],
846 ["dunning_edit", $locale->text("Create and edit dunnings")],
847 ["sales_all_edit", $locale->text("View/edit all employees sales documents")],
848 ["--ap", $locale->text("AP")],
849 ["request_quotation_edit", $locale->text("Create and edit RFQs")],
850 ["purchase_order_edit", $locale->text("Create and edit purchase orders")],
851 ["purchase_delivery_order_edit", $locale->text("Create and edit purchase delivery orders")],
852 ["vendor_invoice_edit", $locale->text("Create and edit vendor invoices")],
853 ["--warehouse_management", $locale->text("Warehouse management")],
854 ["warehouse_contents", $locale->text("View warehouse content")],
855 ["warehouse_management", $locale->text("Warehouse management")],
856 ["--general_ledger_cash", $locale->text("General ledger and cash")],
857 ["general_ledger", $locale->text("Transactions, AR transactions, AP transactions")],
858 ["datev_export", $locale->text("DATEV Export")],
859 ["cash", $locale->text("Receipt, payment, reconciliation")],
860 ["--reports", $locale->text('Reports')],
861 ["report", $locale->text('All reports')],
862 ["advance_turnover_tax_return", $locale->text('Advance turnover tax return')],
863 ["--batch_printing", $locale->text("Batch Printing")],
864 ["batch_printing", $locale->text("Batch Printing")],
865 ["--others", $locale->text("Others")],
866 ["email_bcc", $locale->text("May set the BCC field when sending emails")],
867 ["config", $locale->text("Change Lx-Office installation settings (all menu entries beneath 'System')")],
874 return grep !/^--/, map { $_->[0] } all_rights_full();
878 $main::lxdebug->enter_sub();
882 my $form = $main::form;
884 my $dbh = $self->dbconnect();
886 my $query = 'SELECT * FROM auth."group"';
887 my $sth = prepare_execute_query($form, $dbh, $query);
891 while ($row = $sth->fetchrow_hashref()) {
892 $groups->{$row->{id}} = $row;
896 $query = 'SELECT * FROM auth.user_group WHERE group_id = ?';
897 $sth = prepare_query($form, $dbh, $query);
899 foreach $group (values %{$groups}) {
902 do_statement($form, $sth, $query, $group->{id});
904 while ($row = $sth->fetchrow_hashref()) {
905 push @members, $row->{user_id};
907 $group->{members} = [ uniq @members ];
911 $query = 'SELECT * FROM auth.group_rights WHERE group_id = ?';
912 $sth = prepare_query($form, $dbh, $query);
914 foreach $group (values %{$groups}) {
915 $group->{rights} = {};
917 do_statement($form, $sth, $query, $group->{id});
919 while ($row = $sth->fetchrow_hashref()) {
920 $group->{rights}->{$row->{right}} |= $row->{granted};
923 map { $group->{rights}->{$_} = 0 if (!defined $group->{rights}->{$_}); } all_rights();
927 $main::lxdebug->leave_sub();
933 $main::lxdebug->enter_sub();
938 my $form = $main::form;
939 my $dbh = $self->dbconnect();
943 my ($query, $sth, $row, $rights);
946 ($group->{id}) = selectrow_query($form, $dbh, qq|SELECT nextval('auth.group_id_seq')|);
948 $query = qq|INSERT INTO auth."group" (id, name, description) VALUES (?, '', '')|;
949 do_query($form, $dbh, $query, $group->{id});
952 do_query($form, $dbh, qq|UPDATE auth."group" SET name = ?, description = ? WHERE id = ?|, map { $group->{$_} } qw(name description id));
954 do_query($form, $dbh, qq|DELETE FROM auth.user_group WHERE group_id = ?|, $group->{id});
956 $query = qq|INSERT INTO auth.user_group (user_id, group_id) VALUES (?, ?)|;
957 $sth = prepare_query($form, $dbh, $query);
959 foreach my $user_id (uniq @{ $group->{members} }) {
960 do_statement($form, $sth, $query, $user_id, $group->{id});
964 do_query($form, $dbh, qq|DELETE FROM auth.group_rights WHERE group_id = ?|, $group->{id});
966 $query = qq|INSERT INTO auth.group_rights (group_id, "right", granted) VALUES (?, ?, ?)|;
967 $sth = prepare_query($form, $dbh, $query);
969 foreach my $right (keys %{ $group->{rights} }) {
970 do_statement($form, $sth, $query, $group->{id}, $right, $group->{rights}->{$right} ? 't' : 'f');
976 $main::lxdebug->leave_sub();
980 $main::lxdebug->enter_sub();
985 my $form = $main::form;
987 my $dbh = $self->dbconnect();
990 do_query($form, $dbh, qq|DELETE FROM auth.user_group WHERE group_id = ?|, $id);
991 do_query($form, $dbh, qq|DELETE FROM auth.group_rights WHERE group_id = ?|, $id);
992 do_query($form, $dbh, qq|DELETE FROM auth."group" WHERE id = ?|, $id);
996 $main::lxdebug->leave_sub();
999 sub evaluate_rights_ary {
1000 $main::lxdebug->enter_sub(2);
1007 foreach my $el (@{$ary}) {
1008 if (ref $el eq "ARRAY") {
1009 if ($action eq '|') {
1010 $value |= evaluate_rights_ary($el);
1012 $value &= evaluate_rights_ary($el);
1015 } elsif (($el eq '&') || ($el eq '|')) {
1018 } elsif ($action eq '|') {
1027 $main::lxdebug->leave_sub(2);
1032 sub _parse_rights_string {
1033 $main::lxdebug->enter_sub(2);
1043 push @stack, $cur_ary;
1045 while ($access =~ m/^([a-z_0-9]+|\||\&|\(|\)|\s+)/) {
1047 substr($access, 0, length $1) = "";
1049 next if ($token =~ /\s/);
1051 if ($token eq "(") {
1052 my $new_cur_ary = [];
1053 push @stack, $new_cur_ary;
1054 push @{$cur_ary}, $new_cur_ary;
1055 $cur_ary = $new_cur_ary;
1057 } elsif ($token eq ")") {
1061 $main::lxdebug->leave_sub(2);
1065 $cur_ary = $stack[-1];
1067 } elsif (($token eq "|") || ($token eq "&")) {
1068 push @{$cur_ary}, $token;
1071 push @{$cur_ary}, $self->{RIGHTS}->{$login}->{$token} * 1;
1075 my $result = ($access || (1 < scalar @stack)) ? 0 : evaluate_rights_ary($stack[0]);
1077 $main::lxdebug->leave_sub(2);
1083 $main::lxdebug->enter_sub(2);
1088 my $default = shift;
1090 $self->{FULL_RIGHTS} ||= { };
1091 $self->{FULL_RIGHTS}->{$login} ||= { };
1093 if (!defined $self->{FULL_RIGHTS}->{$login}->{$right}) {
1094 $self->{RIGHTS} ||= { };
1095 $self->{RIGHTS}->{$login} ||= $self->load_rights_for_user($login);
1097 $self->{FULL_RIGHTS}->{$login}->{$right} = $self->_parse_rights_string($login, $right);
1100 my $granted = $self->{FULL_RIGHTS}->{$login}->{$right};
1101 $granted = $default if (!defined $granted);
1103 $main::lxdebug->leave_sub(2);
1109 $main::lxdebug->enter_sub(2);
1113 my $dont_abort = shift;
1115 my $form = $main::form;
1117 if ($self->check_right($form->{login}, $right)) {
1118 $main::lxdebug->leave_sub(2);
1123 delete $form->{title};
1124 $form->show_generic_error($main::locale->text("You do not have the permissions to access this function."));
1127 $main::lxdebug->leave_sub(2);
1132 sub load_rights_for_user {
1133 $::lxdebug->enter_sub;
1135 my ($self, $login) = @_;
1136 my $dbh = $self->dbconnect;
1137 my ($query, $sth, $row, $rights);
1139 $rights = { map { $rights->{$_} = 0 } all_rights() };
1142 qq|SELECT gr."right", gr.granted
1143 FROM auth.group_rights gr
1146 FROM auth.user_group ug
1147 LEFT JOIN auth."user" u ON (ug.user_id = u.id)
1148 WHERE u.login = ?)|;
1150 $sth = prepare_execute_query($::form, $dbh, $query, $login);
1152 while ($row = $sth->fetchrow_hashref()) {
1153 $rights->{$row->{right}} |= $row->{granted};
1157 $::lxdebug->leave_sub;
1171 SL::Auth - Authentication and session handling
1177 =item C<set_session_value %values>
1179 Store all key/value pairs in C<%values> in the session. All of these
1180 values are copied back into C<$::form> in the next request
1183 The values can be any Perl structure. They are stored as YAML dumps.
1185 =item C<get_session_value $key>
1187 Retrieve a value from the session. Returns C<undef> if the value
1190 =item C<create_unique_sesion_value $value, %params>
1192 Create a unique key in the session and store C<$value>
1195 If C<$params{expiration}> is set then it is interpreted as a number of
1196 seconds after which the value is removed from the session. It will
1197 never expire if that parameter is falsish.
1199 If C<$params{auto_restore}> is trueish then the value will be copied
1200 into C<$::form> upon the next request automatically. It defaults to
1201 C<false> and has therefore different behaviour than
1202 L</set_session_value>.
1204 Returns the key created in the session.
1206 =item C<expire_session_keys>
1208 Removes all keys from the session that have an expiration time set and
1209 whose expiration time is in the past.
1211 =item C<save_session>
1213 Stores the session values in the database. This is the only function
1214 that actually stores stuff in the database. Neither the various
1215 setters nor the deleter access the database.
1217 =item <save_form_in_session %params>
1219 Stores the content of C<$params{form}> (default: C<$::form>) in the
1220 session using L</create_unique_sesion_value>.
1222 If C<$params{non_scalars}> is trueish then non-scalar values will be
1223 stored as well. Default is to only store scalar values.
1225 The following keys will never be saved: C<login>, C<password>,
1226 C<stylesheet>, C<titlebar>, C<version>. Additional keys not to save
1227 can be given as an array ref in C<$params{skip_keys}>.
1229 Returns the unique key under which the form is stored.
1231 =item <restore_form_from_session $key, %params>
1233 Restores the form from the session into C<$params{form}> (default:
1236 If C<$params{clobber}> is falsish then existing values with the same
1237 key in C<$params{form}> will not be overwritten. C<$params{clobber}>
1250 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>