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 => scalar($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 %user = $self->read_user($login);
441 my $u_dbh = DBI->connect($user{dbconnect}, $user{dbuser}, $user{dbpasswd});
443 my $dbh = $self->dbconnect();
447 my $query = qq|SELECT id FROM auth."user" WHERE login = ?|;
449 my ($id) = selectrow_query($form, $dbh, $query, $login);
451 $dbh->rollback and return $main::lxdebug->leave_sub() if (!$id);
453 do_query($form, $dbh, qq|DELETE FROM auth.user_group WHERE user_id = ?|, $id);
454 do_query($form, $dbh, qq|DELETE FROM auth.user_config WHERE user_id = ?|, $id);
455 do_query($form, $u_dbh, qq|UPDATE employee SET deleted = 't' WHERE login = ?|, $login);
460 $main::lxdebug->leave_sub();
463 # --------------------------------------
467 sub restore_session {
468 $main::lxdebug->enter_sub();
472 my $cgi = $main::cgi;
473 $cgi ||= CGI->new('');
475 $session_id = $cgi->cookie($self->get_session_cookie_name());
476 $session_id =~ s|[^0-9a-f]||g;
478 $self->{SESSION} = { };
481 $main::lxdebug->leave_sub();
485 my ($dbh, $query, $sth, $cookie, $ref, $form);
489 $dbh = $self->dbconnect();
490 $query = qq|SELECT *, (mtime < (now() - '$self->{session_timeout}m'::interval)) AS is_expired FROM auth.session WHERE id = ?|;
492 $cookie = selectfirst_hashref_query($form, $dbh, $query, $session_id);
494 if (!$cookie || $cookie->{is_expired} || ($cookie->{ip_address} ne $ENV{REMOTE_ADDR})) {
495 $self->destroy_session();
496 $main::lxdebug->leave_sub();
497 return $cookie ? SESSION_EXPIRED : SESSION_NONE;
500 $query = qq|SELECT sess_key, sess_value FROM auth.session_content WHERE session_id = ?|;
501 $sth = prepare_execute_query($form, $dbh, $query, $session_id);
503 while (my $ref = $sth->fetchrow_hashref()) {
504 $self->{SESSION}->{$ref->{sess_key}} = $ref->{sess_value};
505 next if defined $form->{$ref->{sess_key}};
507 my $params = $self->_load_value($ref->{sess_value});
508 $form->{$ref->{sess_key}} = $params->{data} if $params->{auto_restore} || $params->{simple};
513 $main::lxdebug->leave_sub();
519 my ($self, $value) = @_;
521 return { simple => 1, data => $value } if $value !~ m/^---/;
523 my %params = ( simple => 1 );
525 my $data = YAML::Load($value);
527 if (ref $data eq 'HASH') {
528 map { $params{$_} = $data->{$_} } keys %{ $data };
532 $params{data} = $data;
536 } or $params{data} = $value;
541 sub destroy_session {
542 $main::lxdebug->enter_sub();
547 my $dbh = $self->dbconnect();
551 do_query($main::form, $dbh, qq|DELETE FROM auth.session_content WHERE session_id = ?|, $session_id);
552 do_query($main::form, $dbh, qq|DELETE FROM auth.session WHERE id = ?|, $session_id);
557 $self->{SESSION} = { };
560 $main::lxdebug->leave_sub();
563 sub expire_sessions {
564 $main::lxdebug->enter_sub();
568 my $dbh = $self->dbconnect();
573 qq|DELETE FROM auth.session_content
577 WHERE (mtime < (now() - '$self->{session_timeout}m'::interval)))|;
579 do_query($main::form, $dbh, $query);
582 qq|DELETE FROM auth.session
583 WHERE (mtime < (now() - '$self->{session_timeout}m'::interval))|;
585 do_query($main::form, $dbh, $query);
589 $main::lxdebug->leave_sub();
592 sub _create_session_id {
593 $main::lxdebug->enter_sub();
596 map { push @data, int(rand() * 255); } (1..32);
598 my $id = md5_hex(pack 'C*', @data);
600 $main::lxdebug->leave_sub();
605 sub create_or_refresh_session {
606 $session_id ||= shift->_create_session_id;
610 $::lxdebug->enter_sub;
612 my $provided_dbh = shift;
614 my $dbh = $provided_dbh || $self->dbconnect(1);
616 $::lxdebug->leave_sub && return unless $dbh;
618 $dbh->begin_work unless $provided_dbh;
620 do_query($::form, $dbh, qq|LOCK auth.session_content|);
621 do_query($::form, $dbh, qq|DELETE FROM auth.session_content WHERE session_id = ?|, $session_id);
623 my $query = qq|SELECT id FROM auth.session WHERE id = ?|;
625 my ($id) = selectrow_query($::form, $dbh, $query, $session_id);
628 do_query($::form, $dbh, qq|UPDATE auth.session SET mtime = now() WHERE id = ?|, $session_id);
630 do_query($::form, $dbh, qq|INSERT INTO auth.session (id, ip_address, mtime) VALUES (?, ?, now())|, $session_id, $ENV{REMOTE_ADDR});
633 if (%{ $self->{SESSION} }) {
634 my $query = qq|INSERT INTO auth.session_content (session_id, sess_key, sess_value) VALUES (?, ?, ?)|;
635 my $sth = prepare_query($::form, $dbh, $query);
637 foreach my $key (sort keys %{ $self->{SESSION} }) {
638 do_statement($::form, $sth, $query, $session_id, $key, $self->{SESSION}->{$key});
644 $dbh->commit() unless $provided_dbh;
645 $::lxdebug->leave_sub;
648 sub set_session_value {
649 $main::lxdebug->enter_sub();
654 $self->{SESSION} ||= { };
656 while (my ($key, $value) = each %params) {
657 $self->{SESSION}->{ $key } = YAML::Dump(ref($value) eq 'HASH' ? { data => $value } : $value);
660 $main::lxdebug->leave_sub();
665 sub delete_session_value {
666 $main::lxdebug->enter_sub();
670 $self->{SESSION} ||= { };
671 delete @{ $self->{SESSION} }{ @_ };
673 $main::lxdebug->leave_sub();
678 sub get_session_value {
679 $main::lxdebug->enter_sub();
682 my $params = $self->{SESSION} ? $self->_load_value($self->{SESSION}->{ $_[0] }) : {};
684 $main::lxdebug->leave_sub();
686 return $params->{data};
689 sub create_unique_sesion_value {
690 my ($self, $value, %params) = @_;
692 $self->{SESSION} ||= { };
694 my @now = gettimeofday();
695 my $key = "$$-" . ($now[0] * 1000000 + $now[1]) . "-";
696 $self->{unique_counter} ||= 0;
698 $self->{unique_counter}++ while exists $self->{SESSION}->{$key . $self->{unique_counter}};
699 $self->{unique_counter}++;
701 $value = { expiration => $params{expiration} ? ($now[0] + $params{expiration}) * 1000000 + $now[1] : undef,
702 no_auto => !$params{auto_restore},
706 $self->{SESSION}->{$key . $self->{unique_counter}} = YAML::Dump($value);
708 return $key . $self->{unique_counter};
711 sub save_form_in_session {
712 my ($self, %params) = @_;
714 my $form = delete($params{form}) || $::form;
715 my $non_scalars = delete $params{non_scalars};
718 my %skip_keys = map { ( $_ => 1 ) } (qw(login password stylesheet version titlebar), @{ $params{skip_keys} || [] });
720 foreach my $key (grep { !$skip_keys{$_} } keys %{ $form }) {
721 $data->{$key} = $form->{$key} if !ref($form->{$key}) || $non_scalars;
724 return $self->create_unique_sesion_value($data, %params);
727 sub restore_form_from_session {
728 my ($self, $key, %params) = @_;
730 my $data = $self->get_session_value($key);
731 return $self unless $data;
733 my $form = delete($params{form}) || $::form;
734 my $clobber = exists $params{clobber} ? $params{clobber} : 1;
736 map { $form->{$_} = $data->{$_} if $clobber || !exists $form->{$_} } keys %{ $data };
741 sub expire_session_keys {
744 $self->{SESSION} ||= { };
746 my @now = gettimeofday();
747 my $now = $now[0] * 1000000 + $now[1];
749 $self->delete_session_value(map { $_->[0] }
750 grep { $_->[1]->{expiration} && ($now > $_->[1]->{expiration}) }
751 map { [ $_, $self->_load_value($self->{SESSION}->{$_}) ] }
752 keys %{ $self->{SESSION} });
757 sub _has_expiration {
759 return (ref $value eq 'HASH') && exists($value->{expiration}) && $value->{data};
762 sub set_cookie_environment_variable {
764 $ENV{HTTP_COOKIE} = $self->get_session_cookie_name() . "=${session_id}";
767 sub get_session_cookie_name {
770 return $self->{cookie_name} || 'lx_office_erp_session_id';
777 sub session_tables_present {
778 $main::lxdebug->enter_sub();
781 my $dbh = $self->dbconnect(1);
784 $main::lxdebug->leave_sub();
791 WHERE (schemaname = 'auth')
792 AND (tablename IN ('session', 'session_content'))|;
794 my ($count) = selectrow_query($main::form, $dbh, $query);
796 $main::lxdebug->leave_sub();
801 # --------------------------------------
803 sub all_rights_full {
804 my $locale = $main::locale;
807 ["--crm", $locale->text("CRM optional software")],
808 ["crm_search", $locale->text("CRM search")],
809 ["crm_new", $locale->text("CRM create customers, vendors and contacts")],
810 ["crm_service", $locale->text("CRM services")],
811 ["crm_admin", $locale->text("CRM admin")],
812 ["crm_adminuser", $locale->text("CRM user")],
813 ["crm_adminstatus", $locale->text("CRM status")],
814 ["crm_email", $locale->text("CRM send email")],
815 ["crm_termin", $locale->text("CRM termin")],
816 ["crm_opportunity", $locale->text("CRM opportunity")],
817 ["crm_knowhow", $locale->text("CRM know how")],
818 ["crm_follow", $locale->text("CRM follow up")],
819 ["crm_notices", $locale->text("CRM notices")],
820 ["crm_other", $locale->text("CRM other")],
821 ["--master_data", $locale->text("Master Data")],
822 ["customer_vendor_edit", $locale->text("Create and edit customers and vendors")],
823 ["part_service_assembly_edit", $locale->text("Create and edit parts, services, assemblies")],
824 ["project_edit", $locale->text("Create and edit projects")],
825 ["license_edit", $locale->text("Manage license keys")],
826 ["--ar", $locale->text("AR")],
827 ["sales_quotation_edit", $locale->text("Create and edit sales quotations")],
828 ["sales_order_edit", $locale->text("Create and edit sales orders")],
829 ["sales_delivery_order_edit", $locale->text("Create and edit sales delivery orders")],
830 ["invoice_edit", $locale->text("Create and edit invoices and credit notes")],
831 ["dunning_edit", $locale->text("Create and edit dunnings")],
832 ["sales_all_edit", $locale->text("View/edit all employees sales documents")],
833 ["--ap", $locale->text("AP")],
834 ["request_quotation_edit", $locale->text("Create and edit RFQs")],
835 ["purchase_order_edit", $locale->text("Create and edit purchase orders")],
836 ["purchase_delivery_order_edit", $locale->text("Create and edit purchase delivery orders")],
837 ["vendor_invoice_edit", $locale->text("Create and edit vendor invoices")],
838 ["--warehouse_management", $locale->text("Warehouse management")],
839 ["warehouse_contents", $locale->text("View warehouse content")],
840 ["warehouse_management", $locale->text("Warehouse management")],
841 ["--general_ledger_cash", $locale->text("General ledger and cash")],
842 ["general_ledger", $locale->text("Transactions, AR transactions, AP transactions")],
843 ["datev_export", $locale->text("DATEV Export")],
844 ["cash", $locale->text("Receipt, payment, reconciliation")],
845 ["--reports", $locale->text('Reports')],
846 ["report", $locale->text('All reports')],
847 ["advance_turnover_tax_return", $locale->text('Advance turnover tax return')],
848 ["--batch_printing", $locale->text("Batch Printing")],
849 ["batch_printing", $locale->text("Batch Printing")],
850 ["--others", $locale->text("Others")],
851 ["email_bcc", $locale->text("May set the BCC field when sending emails")],
852 ["config", $locale->text("Change Lx-Office installation settings (all menu entries beneath 'System')")],
859 return grep !/^--/, map { $_->[0] } all_rights_full();
863 $main::lxdebug->enter_sub();
867 my $form = $main::form;
869 my $dbh = $self->dbconnect();
871 my $query = 'SELECT * FROM auth."group"';
872 my $sth = prepare_execute_query($form, $dbh, $query);
876 while ($row = $sth->fetchrow_hashref()) {
877 $groups->{$row->{id}} = $row;
881 $query = 'SELECT * FROM auth.user_group WHERE group_id = ?';
882 $sth = prepare_query($form, $dbh, $query);
884 foreach $group (values %{$groups}) {
887 do_statement($form, $sth, $query, $group->{id});
889 while ($row = $sth->fetchrow_hashref()) {
890 push @members, $row->{user_id};
892 $group->{members} = [ uniq @members ];
896 $query = 'SELECT * FROM auth.group_rights WHERE group_id = ?';
897 $sth = prepare_query($form, $dbh, $query);
899 foreach $group (values %{$groups}) {
900 $group->{rights} = {};
902 do_statement($form, $sth, $query, $group->{id});
904 while ($row = $sth->fetchrow_hashref()) {
905 $group->{rights}->{$row->{right}} |= $row->{granted};
908 map { $group->{rights}->{$_} = 0 if (!defined $group->{rights}->{$_}); } all_rights();
912 $main::lxdebug->leave_sub();
918 $main::lxdebug->enter_sub();
923 my $form = $main::form;
924 my $dbh = $self->dbconnect();
928 my ($query, $sth, $row, $rights);
931 ($group->{id}) = selectrow_query($form, $dbh, qq|SELECT nextval('auth.group_id_seq')|);
933 $query = qq|INSERT INTO auth."group" (id, name, description) VALUES (?, '', '')|;
934 do_query($form, $dbh, $query, $group->{id});
937 do_query($form, $dbh, qq|UPDATE auth."group" SET name = ?, description = ? WHERE id = ?|, map { $group->{$_} } qw(name description id));
939 do_query($form, $dbh, qq|DELETE FROM auth.user_group WHERE group_id = ?|, $group->{id});
941 $query = qq|INSERT INTO auth.user_group (user_id, group_id) VALUES (?, ?)|;
942 $sth = prepare_query($form, $dbh, $query);
944 foreach my $user_id (uniq @{ $group->{members} }) {
945 do_statement($form, $sth, $query, $user_id, $group->{id});
949 do_query($form, $dbh, qq|DELETE FROM auth.group_rights WHERE group_id = ?|, $group->{id});
951 $query = qq|INSERT INTO auth.group_rights (group_id, "right", granted) VALUES (?, ?, ?)|;
952 $sth = prepare_query($form, $dbh, $query);
954 foreach my $right (keys %{ $group->{rights} }) {
955 do_statement($form, $sth, $query, $group->{id}, $right, $group->{rights}->{$right} ? 't' : 'f');
961 $main::lxdebug->leave_sub();
965 $main::lxdebug->enter_sub();
970 my $form = $main::form;
972 my $dbh = $self->dbconnect();
975 do_query($form, $dbh, qq|DELETE FROM auth.user_group WHERE group_id = ?|, $id);
976 do_query($form, $dbh, qq|DELETE FROM auth.group_rights WHERE group_id = ?|, $id);
977 do_query($form, $dbh, qq|DELETE FROM auth."group" WHERE id = ?|, $id);
981 $main::lxdebug->leave_sub();
984 sub evaluate_rights_ary {
985 $main::lxdebug->enter_sub(2);
992 foreach my $el (@{$ary}) {
993 if (ref $el eq "ARRAY") {
994 if ($action eq '|') {
995 $value |= evaluate_rights_ary($el);
997 $value &= evaluate_rights_ary($el);
1000 } elsif (($el eq '&') || ($el eq '|')) {
1003 } elsif ($action eq '|') {
1012 $main::lxdebug->leave_sub(2);
1017 sub _parse_rights_string {
1018 $main::lxdebug->enter_sub(2);
1028 push @stack, $cur_ary;
1030 while ($access =~ m/^([a-z_0-9]+|\||\&|\(|\)|\s+)/) {
1032 substr($access, 0, length $1) = "";
1034 next if ($token =~ /\s/);
1036 if ($token eq "(") {
1037 my $new_cur_ary = [];
1038 push @stack, $new_cur_ary;
1039 push @{$cur_ary}, $new_cur_ary;
1040 $cur_ary = $new_cur_ary;
1042 } elsif ($token eq ")") {
1046 $main::lxdebug->leave_sub(2);
1050 $cur_ary = $stack[-1];
1052 } elsif (($token eq "|") || ($token eq "&")) {
1053 push @{$cur_ary}, $token;
1056 push @{$cur_ary}, $self->{RIGHTS}->{$login}->{$token} * 1;
1060 my $result = ($access || (1 < scalar @stack)) ? 0 : evaluate_rights_ary($stack[0]);
1062 $main::lxdebug->leave_sub(2);
1068 $main::lxdebug->enter_sub(2);
1073 my $default = shift;
1075 $self->{FULL_RIGHTS} ||= { };
1076 $self->{FULL_RIGHTS}->{$login} ||= { };
1078 if (!defined $self->{FULL_RIGHTS}->{$login}->{$right}) {
1079 $self->{RIGHTS} ||= { };
1080 $self->{RIGHTS}->{$login} ||= $self->load_rights_for_user($login);
1082 $self->{FULL_RIGHTS}->{$login}->{$right} = $self->_parse_rights_string($login, $right);
1085 my $granted = $self->{FULL_RIGHTS}->{$login}->{$right};
1086 $granted = $default if (!defined $granted);
1088 $main::lxdebug->leave_sub(2);
1094 $main::lxdebug->enter_sub(2);
1098 my $dont_abort = shift;
1100 my $form = $main::form;
1102 if ($self->check_right($form->{login}, $right)) {
1103 $main::lxdebug->leave_sub(2);
1108 delete $form->{title};
1109 $form->show_generic_error($main::locale->text("You do not have the permissions to access this function."));
1112 $main::lxdebug->leave_sub(2);
1117 sub load_rights_for_user {
1118 $::lxdebug->enter_sub;
1120 my ($self, $login) = @_;
1121 my $dbh = $self->dbconnect;
1122 my ($query, $sth, $row, $rights);
1124 $rights = { map { $rights->{$_} = 0 } all_rights() };
1127 qq|SELECT gr."right", gr.granted
1128 FROM auth.group_rights gr
1131 FROM auth.user_group ug
1132 LEFT JOIN auth."user" u ON (ug.user_id = u.id)
1133 WHERE u.login = ?)|;
1135 $sth = prepare_execute_query($::form, $dbh, $query, $login);
1137 while ($row = $sth->fetchrow_hashref()) {
1138 $rights->{$row->{right}} |= $row->{granted};
1142 $::lxdebug->leave_sub;
1156 SL::Auth - Authentication and session handling
1162 =item C<set_session_value %values>
1164 Store all key/value pairs in C<%values> in the session. All of these
1165 values are copied back into C<$::form> in the next request
1168 The values can be any Perl structure. They are stored as YAML dumps.
1170 =item C<get_session_value $key>
1172 Retrieve a value from the session. Returns C<undef> if the value
1175 =item C<create_unique_sesion_value $value, %params>
1177 Create a unique key in the session and store C<$value>
1180 If C<$params{expiration}> is set then it is interpreted as a number of
1181 seconds after which the value is removed from the session. It will
1182 never expire if that parameter is falsish.
1184 If C<$params{auto_restore}> is trueish then the value will be copied
1185 into C<$::form> upon the next request automatically. It defaults to
1186 C<false> and has therefore different behaviour than
1187 L</set_session_value>.
1189 Returns the key created in the session.
1191 =item C<expire_session_keys>
1193 Removes all keys from the session that have an expiration time set and
1194 whose expiration time is in the past.
1196 =item C<save_session>
1198 Stores the session values in the database. This is the only function
1199 that actually stores stuff in the database. Neither the various
1200 setters nor the deleter access the database.
1202 =item <save_form_in_session %params>
1204 Stores the content of C<$params{form}> (default: C<$::form>) in the
1205 session using L</create_unique_sesion_value>.
1207 If C<$params{non_scalars}> is trueish then non-scalar values will be
1208 stored as well. Default is to only store scalar values.
1210 The following keys will never be saved: C<login>, C<password>,
1211 C<stylesheet>, C<titlebar>, C<version>. Additional keys not to save
1212 can be given as an array ref in C<$params{skip_keys}>.
1214 Returns the unique key under which the form is stored.
1216 =item <restore_form_from_session $key, %params>
1218 Restores the form from the session into C<$params{form}> (default:
1221 If C<$params{clobber}> is falsish then existing values with the same
1222 key in C<$params{form}> will not be overwritten. C<$params{clobber}>
1235 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>