Automatische Authentifizierung bestehender Sessions über Session-ID + API-Token
authorMoritz Bunkus <m.bunkus@linet-services.de>
Mon, 26 Nov 2012 17:41:50 +0000 (18:41 +0100)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Mon, 26 Nov 2012 17:41:50 +0000 (18:41 +0100)
Wird für CRM-Menü benötigt.

SL/Auth.pm
SL/Auth/ColumnInformation.pm
SL/Controller/LoginScreen.pm
SL/Dispatcher/AuthHandler/Admin.pm
SL/Dispatcher/AuthHandler/User.pm
sql/Pg-upgrade2-auth/add_api_token.sql [new file with mode: 0644]

index 0a87ca0..e4d487b 100644 (file)
@@ -592,7 +592,17 @@ sub restore_session {
   $cookie = $sth->fetchrow_hashref;
   $sth->finish;
 
-  if (!$cookie || $cookie->{is_expired} || ($cookie->{ip_address} ne $ENV{REMOTE_ADDR})) {
+  # The session ID provided is valid in the following cases:
+  #  1. session ID exists in the database
+  #  2. hasn't expired yet
+  #  3. if form field '{AUTH}api_token' is given: form field must equal database column 'auth.session.api_token' for the session ID
+  #  4. if form field '{AUTH}api_token' is NOT given then: the requestee's IP address must match the stored IP address
+  $self->{api_token}   = $cookie->{api_token} if $cookie;
+  my $api_token_cookie = $self->get_api_token_cookie;
+  my $cookie_is_bad    = !$cookie || $cookie->{is_expired};
+  $cookie_is_bad     ||= $api_token_cookie && ($api_token_cookie ne $cookie->{api_token}) if  $api_token_cookie;
+  $cookie_is_bad     ||= $cookie->{ip_address} ne $ENV{REMOTE_ADDR}                       if !$api_token_cookie;
+  if ($cookie_is_bad) {
     $self->destroy_session();
     $main::lxdebug->leave_sub();
     return $cookie ? SESSION_EXPIRED : SESSION_NONE;
@@ -791,6 +801,11 @@ sub save_session {
     do_query($::form, $dbh, qq|INSERT INTO auth.session (id, ip_address, mtime) VALUES (?, ?, now())|, $session_id, $ENV{REMOTE_ADDR});
   }
 
+  if ($self->{column_information}->has('api_token', 'session')) {
+    my ($stored_api_token) = $dbh->selectrow_array(qq|SELECT api_token FROM auth.session WHERE id = ?|, undef, $session_id);
+    do_query($::form, $dbh, qq|UPDATE auth.session SET api_token = ? WHERE id = ?|, $self->_create_session_id, $session_id) unless $stored_api_token;
+  }
+
   my @values_to_save = grep    { $_->{fetched} }
                        values %{ $self->{SESSION} };
   if (@values_to_save) {
@@ -927,15 +942,25 @@ sub set_cookie_environment_variable {
 }
 
 sub get_session_cookie_name {
-  my $self = shift;
+  my ($self, %params) = @_;
 
-  return $self->{cookie_name} || 'lx_office_erp_session_id';
+  $params{type}     ||= 'id';
+  my $name            = $self->{cookie_name} || 'lx_office_erp_session_id';
+  $name              .= '_api_token' if $params{type} eq 'api_token';
+
+  return $name;
 }
 
 sub get_session_id {
   return $session_id;
 }
 
+sub get_api_token_cookie {
+  my ($self) = @_;
+
+  $::request->{cgi}->cookie($self->get_session_cookie_name(type => 'api_token'));
+}
+
 sub session_tables_present {
   $main::lxdebug->enter_sub();
 
index e053561..64b600d 100644 (file)
@@ -23,17 +23,21 @@ sub _fetch {
 
   return $self if $self->{info};
 
-  my $query = <<SQL;
-    SELECT a.attname, format_type(a.atttypid, a.atttypmod) AS format_type, d.adsrc, a.attnotnull
-    FROM pg_attribute a
-    LEFT JOIN pg_attrdef d ON (a.attrelid = d.adrelid) AND (a.attnum = d.adnum)
-    WHERE (a.attrelid = 'auth.session_content'::regclass)
-      AND (a.attnum > 0)
-      AND NOT a.attisdropped
-    ORDER BY a.attnum
+  $self->{info} = {};
+
+  foreach my $table (qw(session session_content)) {
+    my $query = <<SQL;
+      SELECT a.attname, format_type(a.atttypid, a.atttypmod) AS format_type, d.adsrc, a.attnotnull
+      FROM pg_attribute a
+      LEFT JOIN pg_attrdef d ON (a.attrelid = d.adrelid) AND (a.attnum = d.adnum)
+      WHERE (a.attrelid = 'auth.${table}'::regclass)
+        AND (a.attnum > 0)
+        AND NOT a.attisdropped
+      ORDER BY a.attnum
 SQL
 
-  $self->{info} = { selectall_as_map($::form, $self->{auth}->dbconnect, $query, 'attname', [ qw(format_type adsrc attnotnull) ]) };
+    $self->{info}->{$table} = { selectall_as_map($::form, $self->{auth}->dbconnect, $query, 'attname', [ qw(format_type adsrc attnotnull) ]) };
+  }
 
   return $self;
 }
@@ -44,8 +48,8 @@ sub info {
 }
 
 sub has {
-  my ($self, $column) = @_;
-  return $self->info->{$column};
+  my ($self, $column, $table) = @_;
+  return $self->info->{$table || 'session_content'}->{$column};
 }
 
 1;
index 89f21cc..81ad8dd 100644 (file)
@@ -34,8 +34,9 @@ sub action_logout {
 sub action_login {
   my ($self) = @_;
 
-  %::myconfig      = $::form->{'{AUTH}login'} ? $::auth->read_user(login => $::form->{'{AUTH}login'}) : ();
-  %::myconfig      = SL::Dispatcher::AuthHandler::User->new->handle(countrycode => $::myconfig{countrycode});
+  my $login        = $::form->{'{AUTH}login'} || $::auth->get_session_value('login');
+  %::myconfig      = $login ? $::auth->read_user(login => $login) : ();
+  SL::Dispatcher::AuthHandler::User->new->handle(countrycode => $::myconfig{countrycode});
   $::form->{login} = $::myconfig{login};
   $::locale        = Locale->new($::myconfig{countrycode}) if $::myconfig{countrycode};
   my $user         = User->new(login => $::myconfig{login});
index cc13b5d..a7b649c 100644 (file)
@@ -8,6 +8,7 @@ use SL::Layout::Dispatcher;
 sub handle {
   %::myconfig = ();
 
+  return 1 if  $::auth->get_api_token_cookie;
   return 1 if  $::form->{'{AUTH}admin_password'} && ($::auth->authenticate_root($::form->{'{AUTH}admin_password'})            == $::auth->OK());
   return 1 if !$::form->{'{AUTH}admin_password'} && ($::auth->authenticate_root($::auth->get_session_value('admin_password')) == $::auth->OK());
 
index e1c080e..e126d87 100644 (file)
@@ -18,7 +18,8 @@ sub handle {
   $::locale = Locale->new($::myconfig{countrycode});
   $::request->{layout} = SL::Layout::Dispatcher->new(style => $::myconfig{menustyle});
 
-  my $ok   =  $::form->{'{AUTH}login'} && (SL::Auth::OK() == $::auth->authenticate($::myconfig{login}, $::form->{'{AUTH}password'}));
+  my $ok   =  $::auth->get_api_token_cookie ? 1 : 0;
+  $ok    ||=  $::form->{'{AUTH}login'} && (SL::Auth::OK() == $::auth->authenticate($::myconfig{login}, $::form->{'{AUTH}password'}));
   $ok    ||= !$::form->{'{AUTH}login'} && (SL::Auth::OK() == $::auth->authenticate($::myconfig{login}, undef));
 
   return $self->_error(%param) if !$ok;
diff --git a/sql/Pg-upgrade2-auth/add_api_token.sql b/sql/Pg-upgrade2-auth/add_api_token.sql
new file mode 100644 (file)
index 0000000..82375f6
--- /dev/null
@@ -0,0 +1,5 @@
+-- @tag: add_api_token
+-- @description: Feld 'api_token' in 'session' ergänzen
+-- @depends:
+-- @charset: utf-8
+ALTER TABLE auth.session ADD COLUMN api_token text;