From 56f9dffcd409d2a10e7a2cbe4c15b397f6f3abe1 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Thu, 9 May 2013 21:42:37 -0700 Subject: [PATCH] NG auth: autocreate records for external users, RT#21563 --- FS/FS/Auth/external.pm | 13 ++--------- FS/FS/Auth/internal.pm | 2 ++ FS/FS/Auth/legacy.pm | 2 ++ FS/FS/AuthCookieHandler.pm | 15 ++++++------- FS/FS/CurrentUser.pm | 55 ++++++++++++++++++++++++++++++++++++++------- FS/FS/Schema.pm | 6 ++--- FS/FS/access_user.pm | 9 ++++---- eg/Auth-my_external_auth.pm | 23 ++++++++++--------- 8 files changed, 80 insertions(+), 45 deletions(-) diff --git a/FS/FS/Auth/external.pm b/FS/FS/Auth/external.pm index d2bc74600..51f1f0496 100644 --- a/FS/FS/Auth/external.pm +++ b/FS/FS/Auth/external.pm @@ -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; diff --git a/FS/FS/Auth/internal.pm b/FS/FS/Auth/internal.pm index bb116ce75..f6d1a0086 100644 --- a/FS/FS/Auth/internal.pm +++ b/FS/FS/Auth/internal.pm @@ -42,6 +42,8 @@ sub authenticate { } +sub autocreate { 0; } + sub change_password { my($self, $access_user, $new_password) = @_; diff --git a/FS/FS/Auth/legacy.pm b/FS/FS/Auth/legacy.pm index 72122029e..1133197bc 100644 --- a/FS/FS/Auth/legacy.pm +++ b/FS/FS/Auth/legacy.pm @@ -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 diff --git a/FS/FS/AuthCookieHandler.pm b/FS/FS/AuthCookieHandler.pm index cd89f55af..b571e4705 100644 --- a/FS/FS/AuthCookieHandler.pm +++ b/FS/FS/AuthCookieHandler.pm @@ -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 ) = @_; diff --git a/FS/FS/CurrentUser.pm b/FS/FS/CurrentUser.pm index 7b0fe28a6..d272066e0 100644 --- a/FS/FS/CurrentUser.pm +++ b/FS/FS/CurrentUser.pm @@ -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; } diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 899b67b35..633e59cb6 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -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, '', '', ], diff --git a/FS/FS/access_user.pm b/FS/FS/access_user.pm index 79e863bde..7c25acbe3 100644 --- a/FS/FS/access_user.pm +++ b/FS/FS/access_user.pm @@ -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; } diff --git a/eg/Auth-my_external_auth.pm b/eg/Auth-my_external_auth.pm index 38f9d5bfb..8eda462f8 100644 --- a/eg/Auth-my_external_auth.pm +++ b/eg/Auth-my_external_auth.pm @@ -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; -- 2.11.0