NG auth: autocreate records for external users, RT#21563
authorIvan Kohler <ivan@freeside.biz>
Fri, 10 May 2013 04:42:37 +0000 (21:42 -0700)
committerIvan Kohler <ivan@freeside.biz>
Fri, 10 May 2013 04:42:37 +0000 (21:42 -0700)
FS/FS/Auth/external.pm
FS/FS/Auth/internal.pm
FS/FS/Auth/legacy.pm
FS/FS/AuthCookieHandler.pm
FS/FS/CurrentUser.pm
FS/FS/Schema.pm
FS/FS/access_user.pm
eg/Auth-my_external_auth.pm

index d2bc746..51f1f04 100644 (file)
@@ -1,18 +1,9 @@
-packages FS::Auth::external;
+package FS::Auth::external;
 #use base qw( FS::Auth );
 
 use strict;
 
-sub autocreate {
-  my $username = shift;
-  my $access_user = new FS::access_user {
-    'username' => $username,
-    #'_password' => #XXX something random so a switch to internal auth doesn't
-                    #let people on?
-  };
-  my $error = $access_user->insert;
-  #die $error if $error;
-}
+sub autocreate { 1; }
 
 1;
 
index bb116ce..f6d1a00 100644 (file)
@@ -42,6 +42,8 @@ sub authenticate {
 
 }
 
+sub autocreate { 0; }
+
 sub change_password {
   my($self, $access_user, $new_password) = @_;
 
index 7212202..1133197 100644 (file)
@@ -16,6 +16,8 @@ sub authenticate {
     )->htCheckPassword($username, $check_password);
 }
 
+sub autocreate { 0; }
+
 #don't support this in legacy?  change in both htpasswd and database like 3.x
 # for easier transitioning?  hoping its really only me+employees that have a
 # mismatch in htpasswd vs access_user, so maybe that's not necessary
index cd89f55..b571e47 100644 (file)
@@ -11,24 +11,23 @@ sub authen_cred {
 
   preuser_setup();
 
-  unless ( _is_valid_user($username, $password) ) {
+  my $info = {};
+
+  unless ( FS::Auth->authenticate($username, $password, $info) ) {
     warn "failed auth $username from ". $r->connection->remote_ip. "\n";
     return undef;
   }
 
   warn "authenticated $username from ". $r->connection->remote_ip. "\n";
 
-  FS::CurrentUser->load_user($username);
+  FS::CurrentUser->load_user( $username,
+                              'autocreate' => FS::Auth->auth_class->autocreate,
+                              %$info,
+                            );
 
   FS::CurrentUser->new_session;
 }
 
-sub _is_valid_user {
-  my( $username, $password ) = @_;
-
-  FS::Auth->authenticate($username, $password);
-}
-
 sub authen_ses_key {
   my( $self, $r, $sessionkey ) = @_;
 
index 7b0fe28..d272066 100644 (file)
@@ -27,13 +27,13 @@ Sets the current user to the provided username
 =cut
 
 sub load_user {
-  my( $class, $user ) = @_; #, $pass
+  my( $class, $username, %opt ) = @_;
 
   if ( $upgrade_hack ) {
     return $CurrentUser = new FS::CurrentUser::BootstrapUser;
   }
 
-  #return "" if $user =~ /^fs_(queue|selfservice)$/;
+  #return "" if $username =~ /^fs_(queue|selfservice)$/;
 
   #not the best thing in the world...
   eval "use FS::Record qw(qsearchs);";
@@ -41,13 +41,52 @@ sub load_user {
   eval "use FS::access_user;";
   die $@ if $@;
 
-  $CurrentUser = qsearchs('access_user', {
-    'username' => $user,
-    #'_password' =>
-    'disabled' => '',
-  } );
+  my %hash = ( 'username' => $username,
+               'disabled' => '',
+             );
 
-  die "unknown user: $user" unless $CurrentUser; # or bad password
+  $CurrentUser = qsearchs('access_user', \%hash) and return $CurrentUser;
+
+  die "unknown user: $username" unless $opt{'autocreate'};
+
+  $CurrentUser = new FS::access_user \%hash;
+  $CurrentUser->set($_, $opt{$_}) foreach qw( first last );
+  my $error = $CurrentUser->insert;
+  die $error if $error; #better way to handle this error?
+
+  my $template_user =
+    $opt{'template_user'}
+      || FS::Conf->new->config('external_auth-access_group-template_user');
+
+  if ( $template_user ) {
+
+    my $tmpl_access_user =
+       qsearchs('access_user', { 'username' => $template_user } );
+
+    if ( $tmpl_access_user ) {
+      eval "use FS::access_usergroup;";
+      die $@ if $@;
+
+      foreach my $tmpl_access_usergroup
+                ($tmpl_access_user->access_usergroup) {
+        my $access_usergroup = new FS::access_usergroup {
+          'usernum'  => $CurrentUser->usernum,
+          'groupnum' => $tmpl_access_usergroup->groupnum,
+        };
+        my $error = $access_usergroup->insert;
+        if ( $error ) {
+          #shouldn't happen, but seems better to proceed than to die
+          warn "error inserting access_usergroup: $error";
+        };
+      }
+
+    } else {
+      warn "template username $template_user not found\n";
+    }
+
+  } else {
+    warn "no access template user for autocreated user $username\n";
+  }
 
   $CurrentUser;
 }
index 899b67b..633e59c 100644 (file)
@@ -3586,10 +3586,10 @@ sub tables_hashref {
       'columns' => [
         'usernum',             'serial',     '',      '', '', '',
         'username',           'varchar',     '', $char_d, '', '',
-        '_password',          'varchar',     '', $char_d, '', '',
+        '_password',          'varchar', 'NULL', $char_d, '', '',
         '_password_encoding', 'varchar', 'NULL', $char_d, '', '',
-        'last',               'varchar',     '', $char_d, '', '', 
-        'first',              'varchar',     '', $char_d, '', '', 
+        'last',               'varchar', 'NULL', $char_d, '', '', 
+        'first',              'varchar', 'NULL', $char_d, '', '', 
         'user_custnum',           'int', 'NULL',      '', '', '',
         'disabled',              'char', 'NULL',       1, '', '', 
       ],
index 79e863b..7c25acb 100644 (file)
@@ -209,9 +209,9 @@ sub check {
   my $error = 
     $self->ut_numbern('usernum')
     || $self->ut_alpha_lower('username')
-    || $self->ut_text('_password')
-    || $self->ut_text('last')
-    || $self->ut_text('first')
+    || $self->ut_textn('_password')
+    || $self->ut_textn('last')
+    || $self->ut_textn('first')
     || $self->ut_foreign_keyn('user_custnum', 'cust_main', 'custnum')
     || $self->ut_enum('disabled', [ '', 'Y' ] )
   ;
@@ -229,7 +229,8 @@ Returns a name string for this user: "Last, First".
 sub name {
   my $self = shift;
   return $self->username
-    if $self->get('last') eq 'Lastname' && $self->first eq 'Firstname';
+    if $self->get('last') eq 'Lastname' && $self->first eq 'Firstname'
+    or $self->get('last') eq ''         && $self->first eq '';
   return $self->get('last'). ', '. $self->first;
 }
 
index 38f9d5b..8eda462 100644 (file)
@@ -4,24 +4,25 @@ use base qw( FS::Auth::external ); #need to inherit from ::external
 use strict;
 
 sub authenticate {
-  my($self, $username, $check_password ) = @_;
+  my($self, $username, $check_password, $info ) = @_;
 
-  #magic happens here
+  #your magic happens here
+
+  if ( $auth_good ) {
+
+    #optionally return a real name
+    #$info->{'first'} = "Jean";
+    #$info->{'last'}  = "D'eau";
+
+    #optionally return a template username to copy access groups from that user
+    #$info->{'template_user'} = 'username';
 
-  if ( $auth_good ) { #verbose for clarity
     return 1;
+
   } else {
     return 0;
   }
 
 }
 
-#omitting these subroutines will eliminate those options from the UI
-
-#sub create_user {
-#
-
-#sub change_password {
-#}
-
 1;