Ado
view release on metacpan or search on metacpan
lib/Ado/Plugin/Auth.pm view on Meta::CPAN
$c->debug(
"in _login_facebook error from provider: " . ($c->param('error') || 'no error'));
} if $Ado::Control::DEV_MODE;
if ($response->{access_token}) { #Athenticate, create and login the user.
return _create_or_authenticate_facebook_user(
$c,
$response->{access_token},
$providers->{$provider}
);
}
else {
#Redirect to front-page and say sorry
# We are very sorry but we need to know you are a reasonable human being.
$c->flash(error_login => $c->l('oauth2_sorry[_1]', ucfirst($provider))
. ($c->param('error') || ''));
$c->app->log->error('error_response:' . $c->dumper($response));
$c->res->code(307); #307 Temporary Redirect
$c->redirect_to('/');
}
return;
}
sub _authenticate_oauth2_user {
my ($c, $user, $time) = @_;
if ( $user->disabled
|| ($user->stop_date != 0 && $user->stop_date < $time)
|| $user->start_date > $time)
{
$c->flash(login_message => $c->l('oauth2_disabled'));
$c->redirect_to('/');
return;
}
$c->session(login_name => $user->login_name);
$c->user($user);
$c->app->log->info('$user ' . $user->login_name . ' logged in!');
return 1;
}
#Creates a user using given info from provider
sub _create_oauth2_user {
my ($c, $user_info, $provider) = @_;
state $app = $c->app;
if (my $user = Ado::Model::Users->add(_user_info_to_args($user_info, $provider))) {
$app->plugins->emit_hook(after_user_add => $c, $user, $user_info);
$c->user($user);
$c->session(login_name => $user->login_name);
$app->log->info($user->description . ' New $user ' . $user->login_name . ' logged in!');
$c->flash(login_message => $c->l('oauth2_wellcome[_1]', $user->name));
$c->redirect_to('/');
return 1;
}
$app->log->error($@);
return;
}
#next two methods
#(_create_or_authenticate_facebook_user and _create_or_authenticate_google_user)
# exist only because we pass different parameters in the form
# which are specific to the provider.
# TODO: think of a way to map the generation of the form arguments to the
# specific provider so we can dramatically reduce the number of provider
# specific subroutines
sub _create_or_authenticate_facebook_user {
my ($c, $access_token, $provider) = @_;
my $ua = Mojo::UserAgent->new;
my $appsecret_proof = Digest::SHA::hmac_sha256_hex($access_token, $provider->{secret});
$c->debug('$appsecret_proof:' . $appsecret_proof);
my $user_info =
$ua->get($provider->{info_url},
form => {access_token => $access_token, appsecret_proof => $appsecret_proof})->res->json;
$c->debug('Response from info_url:' . $c->dumper($user_info)) if $Ado::Control::DEV_MODE;
my $user = Ado::Model::Users->by_email($user_info->{email});
my $time = time;
if ($user->id) {
return _authenticate_oauth2_user($c, $user, $time);
}
#else create the user
return _create_oauth2_user($c, $user_info, $provider);
}
sub _create_or_authenticate_google_user {
my ($c, $access_token, $provider) = @_;
#make request for the user info
my $token_type = 'Bearer';
my $ua = Mojo::UserAgent->new;
my $user_info =
$ua->get($provider->{info_url} => {Authorization => "$token_type $access_token"})
->res->json;
my $user = Ado::Model::Users->by_email($user_info->{email});
my $time = time;
if ($user->id) {
return _authenticate_oauth2_user($c, $user, $time);
}
#else create the user
return _create_oauth2_user($c, $user_info, $provider);
}
# Redirects to Consent screen
sub authorize {
my ($c) = @_;
my $m = $c->param('auth_method');
my $params = $c->app->config('Ado::Plugin::Auth')->{providers}{$m};
$params->{redirect_uri} = '' . $c->url_for("/login/$m")->to_abs;
#This call will redirect the user to the provider Consent screen.
$c->redirect_to($c->oauth2->auth_url($m, %$params));
return;
}
# Maps user info given from provider to arguments for
# Ado::Model::Users->new
sub _user_info_to_args {
my ($ui, $provider) = @_;
my %args;
if (index($provider->{info_url}, 'google') > -1) {
$args{first_name} = $ui->{given_name};
$args{last_name} = $ui->{family_name};
}
elsif (index($provider->{info_url}, 'facebook') > -1) {
$args{first_name} = $ui->{first_name};
$args{last_name} = $ui->{last_name};
}
#Add another elsif to map different %args to $ui from a new provider
else {
Carp::croak('Unknown provider info_url:' . $provider->{info_url});
}
$args{email} = $ui->{email};
$args{login_name} = $ui->{email};
$args{login_name} =~ s/[\@\.]+//g;
$args{login_password} =
Mojo::Util::sha1_hex($args{login_name} . Ado::Sessions->generate_id());
$args{description} = "Registered via $provider->{info_url}!";
$args{created_by} = $args{changed_by} = 1;
$args{start_date} = $args{disabled} = $args{stop_date} = 0;
return %args;
}
1;
=pod
=encoding utf8
=head1 NAME
Ado::Plugin::Auth - Passwordless user authentication for Ado
=head1 SYNOPSIS
#in etc/ado.$mode.conf
plugins =>[
#...
'auth',
#...
],
#in etc/plugins/auth.$mode.conf
{
#methods which will be displayed in the "Sign in" menu
auth_methods => ['ado', 'facebook', 'google'],
providers => {
google => {
key =>'123456789....apps.googleusercontent.com',
secret =>'YourSECR3T',
scope=>'profile email',
info_url => 'https://www.googleapis.com/userinfo/v2/me',
},
facebook => {
key =>'123456789',
secret =>'123456789abcdef',
scope =>'public_profile,email',
info_url => 'https://graph.facebook.com/v2.2/me',
},
}
}
=head1 DESCRIPTION
L<Ado::Plugin::Auth> is a plugin that authenticates users to an L<Ado> system.
Users can be authenticated via Google, Facebook, locally and in the future
other authentication service-providers.
( run in 0.626 second using v1.01-cache-2.11-cpan-39bf76dae61 )