165 lines
4.3 KiB
Perl
165 lines
4.3 KiB
Perl
package Lemonldap::NG::Portal::Auth::Facebook;
|
|
|
|
use strict;
|
|
use Mouse;
|
|
use URI::Escape;
|
|
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_ERROR PE_BADCREDENTIALS);
|
|
|
|
our $VERSION = '2.0.0';
|
|
|
|
extends 'Lemonldap::NG::Portal::Auth::Base';
|
|
|
|
# INITIALIZATION
|
|
|
|
sub init {
|
|
my ($self) = @_;
|
|
eval { require Net::Facebook::Oauth2; };
|
|
if ($@) {
|
|
$self->error("Unable to load Net::Facebook::Oauth2: $@");
|
|
return 0;
|
|
}
|
|
my $ret = 1;
|
|
foreach my $arg (qw(facebookAppId facebookAppSecret)) {
|
|
unless ( $self->conf->{$arg} ) {
|
|
$ret = 0;
|
|
$self->error("Parameter $arg is required");
|
|
}
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
# RUNNING METHODS
|
|
|
|
sub extractFormInfo {
|
|
my ( $self, $req ) = @_;
|
|
my $fb = $self->fb($req);
|
|
|
|
# 1. Check Facebook responses
|
|
|
|
# 1.1 Good responses
|
|
if ( my $code = $req->param('code') ) {
|
|
if ( my $access_token = $fb->get_access_token( code => $code ) ) {
|
|
$req->{sessionInfo}->{_facebookToken} = $access_token;
|
|
|
|
# Get mandatory fields (see https://developers.facebook.com/tools/explorer)
|
|
my @fields = ('id');
|
|
|
|
# Look at wanted fields
|
|
if ( $self->getModule( $req, 'user' ) =~ /^Facebook/ ) {
|
|
push @fields,
|
|
map { /^(\w+)$/ ? ($1) : () }
|
|
values %{ $self->conf->{facebookExportedVars} };
|
|
}
|
|
my $datas;
|
|
|
|
# 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) {
|
|
$datas = $fb->get(
|
|
'https://graph.facebook.com/me',
|
|
{ fields => join( ',', @fields ) }
|
|
)->as_hash;
|
|
unless ( ref $datas ) {
|
|
$self->lmLog( "Unable to get any Facebook field", 'error' );
|
|
return PE_ERROR;
|
|
}
|
|
if ( $datas->{error} ) {
|
|
my $tmp = pop @fields;
|
|
$self->lmLog(
|
|
"Unable to get some Facebook fields ($datas->{error}->{message}). Retrying without $tmp",
|
|
'warn'
|
|
);
|
|
}
|
|
else {
|
|
last;
|
|
}
|
|
}
|
|
unless (@fields) {
|
|
$self->lmLog( "Unable to get any Facebook field", 'error' );
|
|
return PE_ERROR;
|
|
}
|
|
|
|
# Use id fieldto trace user
|
|
unless ( $req->{user} = $datas->{id} ) {
|
|
$self->lmLog( 'Unable to get Facebook id', 'error' );
|
|
return PE_ERROR;
|
|
}
|
|
$req->datas->{_facebookDatas} = $datas;
|
|
|
|
# Force redirection to avoid displaying Oauth datas
|
|
$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');
|
|
$self->lmLog( "Facebook error code $error_code: $error_message",
|
|
'error' );
|
|
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);
|
|
$req->steps( [] );
|
|
PE_OK;
|
|
}
|
|
|
|
sub authenticate {
|
|
PE_OK;
|
|
}
|
|
|
|
sub authFinish {
|
|
PE_OK;
|
|
}
|
|
|
|
sub authLogout {
|
|
PE_OK;
|
|
}
|
|
|
|
sub authForce {
|
|
0;
|
|
}
|
|
|
|
sub getDisplayType {
|
|
return "logo";
|
|
}
|
|
|
|
sub fb {
|
|
my ( $self, $req ) = @_;
|
|
my $conf = $self->{conf};
|
|
my $fb;
|
|
my $sep = '?';
|
|
my $ret = $conf->{portal};
|
|
foreach my $v ( [ $req->datas->{_url}, "url" ],
|
|
[ $req->param( $conf->{authChoiceParam} ), $conf->{authChoiceParam} ] )
|
|
{
|
|
if ( $v->[0] ) {
|
|
$ret .= "$sep$v->[1]=$v->[0]";
|
|
$sep = '&';
|
|
}
|
|
}
|
|
|
|
eval {
|
|
$fb = Net::Facebook::Oauth2->new(
|
|
application_id => $conf->{facebookAppId},
|
|
application_secret => $conf->{facebookAppSecret},
|
|
callback => $ret,
|
|
);
|
|
};
|
|
$self->lmLog( $@, 'error' ) if ($@);
|
|
return $fb;
|
|
}
|
|
|
|
1;
|