b2620c2679
datas => des données data => les données
243 lines
6.0 KiB
Perl
243 lines
6.0 KiB
Perl
package Lemonldap::NG::Portal::Auth::LinkedIn;
|
|
|
|
use strict;
|
|
use JSON;
|
|
use Mouse;
|
|
use MIME::Base64 qw/encode_base64 decode_base64/;
|
|
use Lemonldap::NG::Common::FormEncode;
|
|
use Lemonldap::NG::Common::UserAgent;
|
|
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_ERROR PE_REDIRECT);
|
|
|
|
our $VERSION = '2.0.0';
|
|
|
|
extends 'Lemonldap::NG::Portal::Main::Auth';
|
|
|
|
# INITIALIZATION
|
|
|
|
# return LWP::UserAgent object
|
|
has ua => (
|
|
is => 'rw',
|
|
lazy => 1,
|
|
builder => sub {
|
|
|
|
# TODO : LWP options to use a proxy for example
|
|
my $ua = Lemonldap::NG::Common::UserAgent->new( $_[0]->{conf} );
|
|
$ua->env_proxy();
|
|
return $ua;
|
|
}
|
|
);
|
|
|
|
has linkedInAuthorizationEndpoint => (
|
|
is => 'ro',
|
|
lazy => 1,
|
|
default => sub {
|
|
$_[0]->conf->{linkedInAuthorizationEndpoint}
|
|
|| 'https://www.linkedin.com/oauth/v2/authorization';
|
|
}
|
|
);
|
|
|
|
has linkedInTokenEndpoint => (
|
|
is => 'ro',
|
|
lazy => 1,
|
|
default => sub {
|
|
$_[0]->conf->{linkedInTokenEndpoint}
|
|
|| 'https://www.linkedin.com/oauth/v2/accessToken';
|
|
}
|
|
);
|
|
|
|
has linkedInPeopleEndpoint => (
|
|
is => 'ro',
|
|
lazy => 1,
|
|
default => sub {
|
|
$_[0]->conf->{linkedInPeopleEndpoint}
|
|
|| 'https://api.linkedin.com/v1/people/';
|
|
}
|
|
);
|
|
|
|
sub init {
|
|
my ($self) = @_;
|
|
|
|
my $ret = 1;
|
|
foreach my $arg (qw(linkedInClientID linkedInClientSecret)) {
|
|
unless ( $self->conf->{$arg} ) {
|
|
$ret = 0;
|
|
$self->error("Parameter $arg is required");
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
# RUNNING METHODS
|
|
|
|
sub extractFormInfo {
|
|
my ( $self, $req ) = @_;
|
|
my $nonce = time;
|
|
|
|
# Build redirect_uri
|
|
my $callback_url = $self->conf->{portal};
|
|
|
|
# Check return values
|
|
my $error = $req->param("error");
|
|
my $code = $req->param("code");
|
|
my $state = $req->param("state");
|
|
|
|
# Error
|
|
if ($error) {
|
|
$self->logger->error(
|
|
"Error $error with LinkedIn: " . $req->param("error_description") );
|
|
return PE_ERROR;
|
|
}
|
|
|
|
# Code
|
|
if ($code) {
|
|
my %form;
|
|
$form{"code"} = $code;
|
|
$form{"client_id"} = $self->conf->{linkedInClientID};
|
|
$form{"client_secret"} = $self->conf->{linkedInClientSecret};
|
|
$form{"redirect_uri"} = $callback_url;
|
|
$form{"grant_type"} = "authorization_code";
|
|
|
|
my $response = $self->ua->post( $self->linkedInTokenEndpoint,
|
|
\%form, "Content-Type" => 'application/x-www-form-urlencoded' );
|
|
|
|
if ( $response->is_error ) {
|
|
$self->logger->error(
|
|
"Bad authorization response: " . $response->message );
|
|
$self->logger->debug( $response->content );
|
|
return PE_ERROR;
|
|
}
|
|
|
|
my $content = $response->decoded_content;
|
|
|
|
my $json_hash;
|
|
|
|
eval { $json_hash = from_json( $content, { allow_nonref => 1 } ); };
|
|
|
|
if ($@) {
|
|
$self->logger->error("Unable to decode JSON $content");
|
|
return PE_ERROR;
|
|
}
|
|
|
|
my $access_token = $json_hash->{access_token};
|
|
|
|
$self->logger->debug("Get access token $access_token from LinkedIn");
|
|
|
|
# Build People EndPoint URI
|
|
my $linkedInPeopleEndpoint =
|
|
$self->linkedInPeopleEndpoint . "~:("
|
|
. $self->conf->{linkedInFields}
|
|
. ")?format=json";
|
|
|
|
my $people_response = $self->ua->get( $linkedInPeopleEndpoint,
|
|
"Authorization" => "Bearer $access_token" );
|
|
|
|
if ( $people_response->is_error ) {
|
|
$self->logger->error(
|
|
"Bad authorization response: " . $people_response->message );
|
|
$self->logger->debug( $people_response->content );
|
|
return PE_ERROR;
|
|
}
|
|
|
|
my $people_content = $people_response->decoded_content;
|
|
|
|
eval {
|
|
$json_hash = from_json( $people_content, { allow_nonref => 1 } );
|
|
};
|
|
if ($@) {
|
|
$self->logger->error("Unable to decode JSON $people_content");
|
|
return PE_ERROR;
|
|
}
|
|
|
|
foreach ( keys %$json_hash ) {
|
|
$req->data->{linkedInData}->{$_} = $json_hash->{$_};
|
|
}
|
|
|
|
$req->user(
|
|
$req->data->{linkedInData}->{ $self->conf->{linkedInUserField} } );
|
|
|
|
$self->logger->debug(
|
|
"Good LinkedIn authentication for " . $req->user );
|
|
|
|
# Extract state
|
|
if ($state) {
|
|
my $stateSession = $self->p->getApacheSession( $state, 1 );
|
|
|
|
$req->urldc( $stateSession->data->{urldc} );
|
|
$req->{checkLogins} = $stateSession->data->{checkLogins};
|
|
|
|
$stateSession->remove;
|
|
}
|
|
|
|
return PE_OK;
|
|
}
|
|
|
|
# No code, redirect to LinkedIn
|
|
else {
|
|
$self->logger->debug('Redirection to LinkedIn');
|
|
|
|
# Store state
|
|
my $stateSession =
|
|
$self->p->getApacheSession( undef, 1, 0, 'LinkedInState' );
|
|
|
|
my $stateInfos = {};
|
|
$stateInfos->{_utime} = time() + $self->conf->{timeout};
|
|
$stateInfos->{urldc} = $req->urldc;
|
|
$stateInfos->{checkLogins} = $req->{checkLogins};
|
|
|
|
$stateSession->update($stateInfos);
|
|
|
|
my $authn_uri = $self->linkedInAuthorizationEndpoint;
|
|
$authn_uri .= '?'
|
|
. build_urlencoded(
|
|
response_type => 'code',
|
|
client_id => $self->conf->{linkedInClientID},
|
|
redirect_uri => $callback_url,
|
|
scope => $self->conf->{linkedInScope},
|
|
state => $stateSession->id,
|
|
);
|
|
|
|
$req->urldc($authn_uri);
|
|
|
|
$self->logger->debug( "Redirect user to " . $req->urldc );
|
|
|
|
return PE_REDIRECT;
|
|
}
|
|
}
|
|
|
|
sub setAuthSessionInfo {
|
|
my ( $self, $req ) = @_;
|
|
|
|
$req->{sessionInfo}->{authenticationLevel} =
|
|
$self->conf->{linkedInAuthnLevel};
|
|
|
|
foreach ( keys %{ $req->data->{linkedInData} } ) {
|
|
$req->{sessionInfo}->{ 'linkedIn_' . $_ } =
|
|
$req->data->{linkedInData}->{$_};
|
|
}
|
|
|
|
PE_OK;
|
|
}
|
|
|
|
sub authenticate {
|
|
PE_OK;
|
|
}
|
|
|
|
sub authFinish {
|
|
PE_OK;
|
|
}
|
|
|
|
sub authLogout {
|
|
PE_OK;
|
|
}
|
|
|
|
sub authForce {
|
|
return 0;
|
|
}
|
|
|
|
sub getDisplayType {
|
|
return "logo";
|
|
}
|
|
|
|
1;
|