In progress... (#595)
This commit is contained in:
parent
c535422a98
commit
25365061de
|
@ -38,4 +38,8 @@ sub authLogout {
|
||||||
PE_OK;
|
PE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub getDisplayType {
|
||||||
|
return 'logo';
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
144
lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/BrowserID.pm
Normal file
144
lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/BrowserID.pm
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
package Lemonldap::NG::Portal::Auth::BrowserID;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Mouse;
|
||||||
|
use JSON;
|
||||||
|
use LWP::UserAgent;
|
||||||
|
use HTTP::Request;
|
||||||
|
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_ERROR PE_BADCREDENTIALS PE_FIRSTACCESS);
|
||||||
|
|
||||||
|
our $VERSION = '2.0.0';
|
||||||
|
|
||||||
|
extends 'Lemonldap::NG::Portal::Auth::Base';
|
||||||
|
|
||||||
|
## @method LWP::UserAgent ua()
|
||||||
|
# @return LWP::UserAgent object
|
||||||
|
has ua => (
|
||||||
|
is => 'rw',
|
||||||
|
lasy => 1,
|
||||||
|
builder => sub {
|
||||||
|
|
||||||
|
# TODO : LWP options to use a proxy for example
|
||||||
|
my $ua = LWP::UserAgent->new();
|
||||||
|
push @{ $ua->requests_redirectable }, 'POST';
|
||||||
|
$ua->env_proxy();
|
||||||
|
return $ua;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
# Initialization: enables Browser ID (required for templates) and
|
||||||
|
# LWP::UserAgent object
|
||||||
|
sub init {
|
||||||
|
my ($self) = @_;
|
||||||
|
$self->p->{customParameters}->{browserIdEnabled} = 1;
|
||||||
|
foreach (
|
||||||
|
qw(browserIdSiteName browserIdSiteLogo browserIdBackgroundColor browserIdAutoLogin)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$self->p->{customParameters}->{$_} = $self->conf->{$_}
|
||||||
|
if ( $self->conf->{$_} );
|
||||||
|
}
|
||||||
|
return $self->ua;
|
||||||
|
}
|
||||||
|
|
||||||
|
## @apmethod int extractFormInfo()
|
||||||
|
# Get BrowserID assertion
|
||||||
|
# @return Lemonldap::NG::Portal constant
|
||||||
|
sub extractFormInfo {
|
||||||
|
my ( $self, $req ) = @_;
|
||||||
|
|
||||||
|
# Assertion should be browserIdAssertion parameter
|
||||||
|
if ( my $browserIdAssertion = $req->param('browserIdAssertion') ) {
|
||||||
|
$self->lmLog( "BrowserID Assertion found: $browserIdAssertion",
|
||||||
|
'debug' );
|
||||||
|
|
||||||
|
# Resolve assertion
|
||||||
|
my $postdata =
|
||||||
|
"assertion=$browserIdAssertion&audience=" . $self->conf->{portal};
|
||||||
|
|
||||||
|
$self->lmLog(
|
||||||
|
"Send $postdata to " . $self->conf->{browserIdVerificationURL},
|
||||||
|
'debug' );
|
||||||
|
|
||||||
|
# Prepare and launch request to BrowserID IdP
|
||||||
|
my $request = HTTP::Request->new(
|
||||||
|
'POST' => $self->conf->{browserIdVerificationURL} );
|
||||||
|
$request->content_type('application/x-www-form-urlencoded');
|
||||||
|
$request->content($postdata);
|
||||||
|
|
||||||
|
my $answer = $self->ua()->request($request);
|
||||||
|
|
||||||
|
$self->lmLog( "Verification response: " . $answer->as_string, 'debug' );
|
||||||
|
|
||||||
|
# Check if HTTP response is OK
|
||||||
|
if ( $answer->code() == "200" ) {
|
||||||
|
|
||||||
|
# Get JSON answser and decode it
|
||||||
|
my $browserIdAnswer = $answer->content;
|
||||||
|
$self->lmLog( "Received BrowserID answer: $browserIdAnswer",
|
||||||
|
'debug' );
|
||||||
|
eval { $browserIdAnswer = JSON::from_json($browserIdAnswer); };
|
||||||
|
if ($@) {
|
||||||
|
$self->lmLog( "JSON decode error: $@", 'error' );
|
||||||
|
return PE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Then check for IdP response
|
||||||
|
if ( $browserIdAnswer->{status} eq "okay" ) {
|
||||||
|
$req->user( $browserIdAnswer->{email} );
|
||||||
|
$self->lmLog(
|
||||||
|
"Found user $req->user in BrowserID verification answer",
|
||||||
|
'debug' );
|
||||||
|
return PE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Look for IdP rejection reason
|
||||||
|
else {
|
||||||
|
if ( $browserIdAnswer->{reason} ) {
|
||||||
|
$self->lmLog(
|
||||||
|
"Assertion $browserIdAssertion verification error: $browserIdAnswer->{reason}",
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$self->lmLog(
|
||||||
|
"Assertion $browserIdAssertion not verified by BrowserID provider",
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return PE_BADCREDENTIALS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$self->lmLog(
|
||||||
|
"Fail to validate BrowserId assertion $browserIdAssertion: BrowserID server has returned a $answer->code code",
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
return PE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# No assertion, return to login page with BrowserID login script
|
||||||
|
$req->{customParameters}->{browserIdLoadLoginScript} = 1;
|
||||||
|
return PE_FIRSTACCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub authenticate {
|
||||||
|
PE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub authLogout {
|
||||||
|
$_[1]->{customParameters}->{browserIdLoadLoginScript} = 1;
|
||||||
|
PE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub authForce {
|
||||||
|
return PE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getDisplayType {
|
||||||
|
return 'logo';
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
|
@ -30,4 +30,12 @@ sub authLogout {
|
||||||
PE_OK;
|
PE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub getDisplayType {
|
||||||
|
return 'logo';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getDisplayType {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -15,7 +15,7 @@ sub display {
|
||||||
my $skin_dir = $self->conf->{templatesDir};
|
my $skin_dir = $self->conf->{templatesDir};
|
||||||
my $skinfile;
|
my $skinfile;
|
||||||
my %templateParams =
|
my %templateParams =
|
||||||
( %{ $self->customParameters }, %{ $req->customParameters } );
|
( %{ $self->customParameters }, %{ $req->{customParameters} // {} } );
|
||||||
|
|
||||||
# 0. Display error page
|
# 0. Display error page
|
||||||
if ( my $http_error = $req->param('lmError') ) {
|
if ( my $http_error = $req->param('lmError') ) {
|
||||||
|
@ -97,7 +97,7 @@ sub display {
|
||||||
|
|
||||||
# 2.1 A notification has to be done (session is created but hidden and unusable
|
# 2.1 A notification has to be done (session is created but hidden and unusable
|
||||||
# until the user has accept the message)
|
# until the user has accept the message)
|
||||||
elsif ( my $notif = $req->notification ) {
|
elsif ( my $notif = $req->{notification} ) {
|
||||||
$skinfile = 'notification';
|
$skinfile = 'notification';
|
||||||
%templateParams = (
|
%templateParams = (
|
||||||
AUTH_ERROR_TYPE => $req->error_type,
|
AUTH_ERROR_TYPE => $req->error_type,
|
||||||
|
@ -281,7 +281,8 @@ sub display {
|
||||||
DISPLAY_YUBIKEY_FORM => $displayType eq "yubikeyform" ? 1
|
DISPLAY_YUBIKEY_FORM => $displayType eq "yubikeyform" ? 1
|
||||||
: 0,
|
: 0,
|
||||||
DISPLAY_LOGO_FORM => $displayType eq "logo" ? 1 : 0,
|
DISPLAY_LOGO_FORM => $displayType eq "logo" ? 1 : 0,
|
||||||
module => $displayType eq "logo" ? $self->get_module('auth')
|
module => $displayType eq "logo"
|
||||||
|
? $self->getModule( $req, 'auth' )
|
||||||
: "",
|
: "",
|
||||||
AUTH_LOOP => [],
|
AUTH_LOOP => [],
|
||||||
PORTAL_URL =>
|
PORTAL_URL =>
|
||||||
|
|
|
@ -119,7 +119,7 @@ sub checkLogout {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub authLogout {
|
sub authLogout {
|
||||||
my $self = shift;
|
my ( $self, $req ) = @_;
|
||||||
return $self->_authentication->authLogout(@_);
|
return $self->_authentication->authLogout(@_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,18 +215,18 @@ sub checkXSSAttack {
|
||||||
# -------------------------------------------------------
|
# -------------------------------------------------------
|
||||||
|
|
||||||
sub extractFormInfo {
|
sub extractFormInfo {
|
||||||
my $self = shift;
|
my ( $self, $req ) = @_;
|
||||||
return $self->_authentication->extractFormInfo(@_);
|
return $self->_authentication->extractFormInfo($req);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getUser {
|
sub getUser {
|
||||||
my $self = shift;
|
my ( $self, $req ) = @_;
|
||||||
return $self->_userDB->getUser(@_);
|
return $self->_userDB->getUser($req);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub authenticate {
|
sub authenticate {
|
||||||
my $self = shift;
|
my ( $self, $req ) = @_;
|
||||||
return $self->_authentication->authenticate(@_);
|
return $self->_authentication->authenticate($req);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Third block: Session data providing
|
# Third block: Session data providing
|
||||||
|
@ -288,7 +288,7 @@ sub setMacros {
|
||||||
|
|
||||||
sub setGroups {
|
sub setGroups {
|
||||||
my ( $self, $req ) = @_;
|
my ( $self, $req ) = @_;
|
||||||
return $self->_userDB->setGroups(@_);
|
return $self->_userDB->setGroups($req);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub setPersistentSessionInfo {
|
sub setPersistentSessionInfo {
|
||||||
|
@ -396,8 +396,6 @@ sub buildCookie {
|
||||||
expires => $self->conf->{cookieExpiration},
|
expires => $self->conf->{cookieExpiration},
|
||||||
);
|
);
|
||||||
if ( $self->conf->{securedCookie} >= 2 ) {
|
if ( $self->conf->{securedCookie} >= 2 ) {
|
||||||
shift;
|
|
||||||
shift;
|
|
||||||
push @{ $req->respHeaders },
|
push @{ $req->respHeaders },
|
||||||
'Set-Cookie' => $self->cookie(
|
'Set-Cookie' => $self->cookie(
|
||||||
name => $self->conf->{cookieName} . "http",
|
name => $self->conf->{cookieName} . "http",
|
||||||
|
@ -407,7 +405,6 @@ sub buildCookie {
|
||||||
secure => 0,
|
secure => 0,
|
||||||
HttpOnly => $self->conf->{httpOnly},
|
HttpOnly => $self->conf->{httpOnly},
|
||||||
expires => $self->conf->{cookieExpiration},
|
expires => $self->conf->{cookieExpiration},
|
||||||
@_,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
PE_OK;
|
PE_OK;
|
||||||
|
|
|
@ -31,7 +31,7 @@ extends 'Lemonldap::NG::Common::PSGI::Request';
|
||||||
has steps => ( is => 'rw' );
|
has steps => ( is => 'rw' );
|
||||||
|
|
||||||
# Datas shared between methods
|
# Datas shared between methods
|
||||||
has datas => ( is => 'rw', default => sub { {} } );
|
has datas => ( is => 'rw' );
|
||||||
|
|
||||||
# Session datas when created
|
# Session datas when created
|
||||||
has id => ( is => 'rw' );
|
has id => ( is => 'rw' );
|
||||||
|
@ -45,7 +45,7 @@ has respCookies => ( is => 'rw' );
|
||||||
has template => ( is => 'rw' );
|
has template => ( is => 'rw' );
|
||||||
|
|
||||||
# Custom template parameters
|
# Custom template parameters
|
||||||
has customParameters => ( is => 'rw', default => sub { {} } );
|
has customParameters => ( is => 'rw' );
|
||||||
|
|
||||||
# Boolean to indicate that response must be a redirection
|
# Boolean to indicate that response must be a redirection
|
||||||
has mustRedirect => ( is => 'rw' );
|
has mustRedirect => ( is => 'rw' );
|
||||||
|
@ -62,12 +62,6 @@ has info => ( is => 'rw' );
|
||||||
# Menu error
|
# Menu error
|
||||||
has menuError => ( is => 'rw' );
|
has menuError => ( is => 'rw' );
|
||||||
|
|
||||||
# Notification
|
|
||||||
has notification => ( is => 'rw' );
|
|
||||||
|
|
||||||
has _authChoice => ( is => 'rw' );
|
|
||||||
has _openidPortal => ( is => 'rw' );
|
|
||||||
|
|
||||||
# Error type
|
# Error type
|
||||||
sub error_type {
|
sub error_type {
|
||||||
my $req = shift;
|
my $req = shift;
|
||||||
|
|
|
@ -112,7 +112,7 @@ my $id;
|
||||||
ok( $id = getCookies($res)->{lemonldap}, 'Get LLNG cookie' )
|
ok( $id = getCookies($res)->{lemonldap}, 'Get LLNG cookie' )
|
||||||
or explain( $res, 'Set-Cookie: something' );
|
or explain( $res, 'Set-Cookie: something' );
|
||||||
|
|
||||||
count(4);
|
count(3);
|
||||||
|
|
||||||
while ( defined( my $url = shift(@tests) ) ) {
|
while ( defined( my $url = shift(@tests) ) ) {
|
||||||
last if ( $url eq 'LOGOUT' );
|
last if ( $url eq 'LOGOUT' );
|
||||||
|
|
Loading…
Reference in New Issue
Block a user