lemonldap-ng/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Facebook.pm

179 lines
4.8 KiB
Perl
Raw Normal View History

2016-05-24 18:53:41 +02:00
package Lemonldap::NG::Portal::Auth::Facebook;
use strict;
use Mouse;
use URI::Escape;
use Lemonldap::NG::Common::FormEncode;
2016-05-24 18:53:41 +02:00
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_ERROR PE_BADCREDENTIALS);
use utf8;
2016-05-24 18:53:41 +02:00
2021-02-01 22:30:37 +01:00
our $VERSION = '2.0.12';
2016-05-24 18:53:41 +02:00
2018-02-19 22:11:43 +01:00
extends 'Lemonldap::NG::Portal::Main::Auth';
2016-05-24 18:53:41 +02:00
2016-06-09 20:40:20 +02:00
# INITIALIZATION
2016-05-24 18:53:41 +02:00
sub init {
2019-04-05 22:58:48 +02:00
my $self = shift;
2016-05-24 18:53:41 +02:00
eval { require Net::Facebook::Oauth2; };
if ($@) {
2016-05-24 22:50:22 +02:00
$self->error("Unable to load Net::Facebook::Oauth2: $@");
2016-05-24 18:53:41 +02:00
return 0;
}
my $ret = 1;
foreach my $arg (qw(facebookAppId facebookAppSecret)) {
unless ( $self->conf->{$arg} ) {
$ret = 0;
2016-05-24 22:50:22 +02:00
$self->error("Parameter $arg is required");
2016-05-24 18:53:41 +02:00
}
}
return $ret;
}
2016-06-09 20:40:20 +02:00
# RUNNING METHODS
2016-05-24 18:53:41 +02:00
sub extractFormInfo {
my ( $self, $req ) = @_;
my $fb = $self->fb($req);
# 1. Check Facebook responses
# 1.1 Good responses
if ( my $code = $req->param('code') ) {
$self->logger->debug("Get code $code from Facebook");
my $access_token;
eval { $access_token = $fb->get_access_token( code => $code ); };
if ($@) {
$self->logger->error("Error while getting access token: $@");
return PE_ERROR;
}
if ($access_token) {
2016-05-24 18:53:41 +02:00
$req->{sessionInfo}->{_facebookToken} = $access_token;
# Get mandatory fields (see https://developers.facebook.com/tools/explorer)
2018-06-22 18:16:24 +02:00
my @fields = ( $self->conf->{facebookUserField} );
# Search all wanted fields
push @fields,
map { /^(\w+)$/ ? ($1) : () }
values %{ $self->conf->{facebookExportedVars} };
2016-05-24 18:53:41 +02:00
my $data;
2016-05-24 18:53:41 +02:00
# When a field is not granted, Facebook returns only an error
# without real explanation. So here we try to reduce query until
# having a valid response
while (@fields) {
$data = $fb->get(
2016-05-24 18:53:41 +02:00
'https://graph.facebook.com/me',
{ fields => join( ',', @fields ) }
)->as_hash;
unless ( ref $data ) {
2017-02-15 07:41:50 +01:00
$self->logger->error("Unable to get any Facebook field");
2016-05-24 18:53:41 +02:00
return PE_ERROR;
}
if ( $data->{error} ) {
2016-05-24 18:53:41 +02:00
my $tmp = pop @fields;
2017-02-15 07:41:50 +01:00
$self->logger->warn(
"Unable to get some Facebook fields ($data->{error}->{message}). Retrying without $tmp"
2016-05-24 18:53:41 +02:00
);
}
else {
last;
}
}
unless (@fields) {
2017-02-15 07:41:50 +01:00
$self->logger->error("Unable to get any Facebook field");
2016-05-24 18:53:41 +02:00
return PE_ERROR;
}
# Parse received data
foreach ( keys %$data ) {
utf8::encode $data->{$_};
$self->logger->debug( "Facebook data $_: " . $data->{$_} );
}
2018-06-22 18:16:24 +02:00
# Field to trace user
unless ( $data->{ $self->conf->{facebookUserField} } ) {
2017-02-15 07:41:50 +01:00
$self->logger->error('Unable to get Facebook id');
2016-05-24 18:53:41 +02:00
return PE_ERROR;
}
$req->user( $data->{ $self->conf->{facebookUserField} } );
$req->data->{_facebookData} = $data;
$req->{sessionInfo}->{_facebookData} = $data;
2016-05-24 18:53:41 +02:00
# Force redirection to avoid displaying Oauth data
2016-05-24 18:53:41 +02:00
$req->mustRedirect(1);
return PE_OK;
}
return PE_BADCREDENTIALS;
}
# 1.2 Bad responses
if ( my $error_code = $req->param('error_code') ) {
my $error_message = $req->param('error_message');
2017-02-19 12:51:58 +01:00
$self->userLogger->error(
"Facebook error code $error_code: $error_message");
2016-05-24 18:53:41 +02:00
return PE_ERROR;
}
# 2. Else redirect user to Facebook login page:
# Build Facebook redirection
# TODO: use a param to use "publish_stream" or not
my $check_url = $fb->get_authorization_url(
scope => [ 'public_profile', 'email' ],
display => 'page',
);
$req->urldc($check_url);
$self->logger->debug( "Redirect user to " . $req->{urldc} );
$req->continue(1);
2016-05-24 18:53:41 +02:00
$req->steps( [] );
2021-02-01 22:30:37 +01:00
return PE_OK;
2016-05-24 18:53:41 +02:00
}
sub authenticate {
2021-02-01 22:30:37 +01:00
return PE_OK;
2016-05-24 18:53:41 +02:00
}
2016-12-01 23:25:05 +01:00
sub setAuthSessionInfo {
my ( $self, $req ) = @_;
2016-12-26 10:23:35 +01:00
$req->{sessionInfo}->{authenticationLevel} =
$self->conf->{facebookAuthnLevel};
2021-02-01 22:30:37 +01:00
return PE_OK;
2016-12-01 23:25:05 +01:00
}
2016-05-24 18:53:41 +02:00
sub authFinish {
2021-02-01 22:30:37 +01:00
return PE_OK;
2016-05-24 18:53:41 +02:00
}
sub authLogout {
2021-02-01 22:30:37 +01:00
return PE_OK;
2016-05-24 18:53:41 +02:00
}
sub getDisplayType {
return "logo";
}
sub fb {
my ( $self, $req ) = @_;
my $conf = $self->{conf};
my $fb;
my $sep = '?';
my $ret = $conf->{portal};
eval {
$fb = Net::Facebook::Oauth2->new(
application_id => $conf->{facebookAppId},
application_secret => $conf->{facebookAppSecret},
callback => $ret,
);
};
2017-02-15 07:41:50 +01:00
$self->logger->error($@) if ($@);
2021-02-01 22:30:37 +01:00
2016-05-24 18:53:41 +02:00
return $fb;
}
1;