diff --git a/TODO-2.0.md b/TODO-2.0.md
index 6c1b3a87d3cfa977db0e550abad61ab1057b40ca..d6d883287343de4de594fdccd2f9f8a620edfbde 100644
--- a/TODO-2.0.md
+++ b/TODO-2.0.md
@@ -1,9 +1,6 @@
-# Missing methods
-
-* info()
-
-# Other
-
+* checkLogins in SAML
+* 2nd arg for trspan
+* verify activeTimer on/off on screen
* Verify `useSafeJail=0`
* Finish IssuerGet logout (-> info())
* Import r5420 (ssl\_opts) to trunk
diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/OpenIDConnect.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/OpenIDConnect.pm
index 83d8a147a7bf0f685e774440967964e9c80719c0..362a28b56574ac96d7daf4fd7d4e9ae0b36568a6 100644
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/OpenIDConnect.pm
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/OpenIDConnect.pm
@@ -2,6 +2,7 @@ package Lemonldap::NG::Portal::Auth::OpenIDConnect;
use strict;
use Mouse;
+use MIME::Base64 qw/encode_base64 decode_base64/;
use Lemonldap::NG::Portal::Main::Constants qw(
PE_CONFIRM
PE_ERROR
@@ -15,7 +16,7 @@ extends 'Lemonldap::NG::Portal::Auth::Base',
# INTERFACE
-has oplist => ( is => 'rw', default => sub { [] } );
+has opList => ( is => 'rw', default => sub { [] } );
has opNumber => ( is => 'rw', default => 0 );
# INITIALIZATION
@@ -56,7 +57,7 @@ sub init {
class => "openidconnect",
};
}
- $self->oplist( [@list] );
+ $self->opList( [@list] );
return 1;
}
@@ -68,15 +69,15 @@ sub extractFormInfo {
# Check callback
if ( $req->param( $self->conf->{oidcRPCallbackGetParam} ) ) {
- $self->lmLog(
- 'OpenIDConnect callback URI detected: ' . $req->uri, 'debug' );
+ $self->lmLog( 'OpenIDConnect callback URI detected: ' . $req->uri,
+ 'debug' );
# AuthN Response
my $state = $req->param('state');
# Restore state
if ($state) {
- if ( $self->extractState($req, $state) ) {
+ if ( $self->extractState( $req, $state ) ) {
$self->lmLog( "State $state extracted", 'debug' );
}
else {
@@ -86,8 +87,6 @@ sub extractFormInfo {
}
# Get OpenID Provider
- $self->lmLog( "################### TODO: verify this (Auth:52)",
- 'debug' );
my $op = $req->datas->{_oidcOPCurrent};
unless ($op) {
@@ -115,7 +114,8 @@ sub extractFormInfo {
my $code = $req->param("code");
my $auth_method =
$self->conf->{oidcOPMetaDataOptions}->{$op}
- ->{oidcOPMetaDataOptionsTokenEndpointAuthMethod};
+ ->{oidcOPMetaDataOptionsTokenEndpointAuthMethod}
+ || 'client_secret_post';
my $content =
$self->getAuthorizationCodeAccessToken( $req, $op, $code,
@@ -197,7 +197,7 @@ sub extractFormInfo {
$req->datas->{id_token} = $id_token;
$self->lmLog( "Found user_id: " . $user_id, 'debug' );
- $self->{user} = $user_id;
+ $req->user($user_id);
return PE_OK;
}
@@ -210,7 +210,7 @@ sub extractFormInfo {
# Auto select provider if there is only one
if ( $self->opNumber == 1 ) {
- $op = $self->opList->[0];
+ $op = $self->opList->[0]->{val};
$self->lmLog( "Selecting the only defined OP: $op", 'debug' );
}
@@ -222,29 +222,7 @@ sub extractFormInfo {
my $portalPath = $self->{portal};
$portalPath =~ s#^https?://[^/]+/?#/#;
- foreach ( @{ $self->oplist } ) {
- my $name = $self->conf->{oidcOPMetaDataOptions}->{$_}
- ->{oidcOPMetaDataOptionsDisplayName};
- my $icon = $self->conf->{oidcOPMetaDataOptions}->{$_}
- ->{oidcOPMetaDataOptionsIcon};
- my $img_src;
-
- if ($icon) {
- $img_src =
- ( $icon =~ m#^https?://# )
- ? $icon
- : $portalPath . "skins/common/" . $icon;
- }
-
- push @list,
- {
- val => $_,
- name => $name,
- icon => $img_src,
- class => "openidconnect",
- };
- }
- $req->datas->{list} = $self->opList;
+ $req->datas->{list} = $self->opList;
$req->datas->{confirmRemember} = 0;
$req->datas->{login} = 1;
@@ -261,14 +239,15 @@ sub extractFormInfo {
$self->lmLog( "Build OpenIDConnect AuthN Request", 'debug' );
# Save state
- my $state = $self->storeState(qw/urldc checkLogins _oidcOPCurrent/);
+ my $state = $self->storeState( $req, qw/urldc checkLogins _oidcOPCurrent/ );
# Authorization Code Flow
- $req->urldc( $self->buildAuthorizationCodeAuthnRequest( $req, $op, $state ) );
-
- $self->lmLog( "Redirect user to " . $self->{urldc}, 'debug' );
+ $req->urldc(
+ $self->buildAuthorizationCodeAuthnRequest( $req, $op, $state ) );
- $req->steps([]);
+ $self->lmLog( "Redirect user to " . $req->{urldc}, 'debug' );
+ $req->continue(1);
+ $req->steps( [] );
return PE_OK;
}
@@ -279,15 +258,17 @@ sub authenticate {
sub setAuthSessionInfo {
my ( $self, $req ) = @_;
- my $op = $req->datas->{_oidcOPCurrent};
+ my $op = $req->datas->{_oidcOPCurrent};
$req->{sessionInfo}->{authenticationLevel} = $self->conf->{oidcAuthnLevel};
$req->{sessionInfo}->{OpenIDConnect_OP} = $op;
- $req->{sessionInfo}->{OpenIDConnect_access_token} = $req->datas->{access_token};
+ $req->{sessionInfo}->{OpenIDConnect_access_token} =
+ $req->datas->{access_token};
# Keep ID Token in session
- my $store_IDToken = $self->conf->{oidcOPMetaDataOptions}->{$op}->{oidcOPMetaDataOptionsStoreIDToken};
+ my $store_IDToken = $self->conf->{oidcOPMetaDataOptions}->{$op}
+ ->{oidcOPMetaDataOptionsStoreIDToken};
if ($store_IDToken) {
$self->lmLog( "Store ID Token in session", 'debug' );
$req->{sessionInfo}->{OpenIDConnect_IDToken} = $req->datas->{id_token};
@@ -311,11 +292,14 @@ sub authLogout {
if ($endsession_endpoint) {
my $logout_url = $self->conf->{portal} . '?logout=1';
$req->urldc(
- $self->buildLogoutRequest( $endsession_endpoint,
- $self->{sessionInfo}->{OpenIDConnect_IDToken}, $logout_url ));
+ $self->buildLogoutRequest(
+ $endsession_endpoint,
+ $self->{sessionInfo}->{OpenIDConnect_IDToken}, $logout_url
+ )
+ );
$self->lmLog(
- "OpenID Connect logout to $op will be done on ".$req->urldc,
+ "OpenID Connect logout to $op will be done on " . $req->urldc,
'debug' );
}
else {
diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/OpenIDConnect.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/OpenIDConnect.pm
index 3a2dd2db2cf94dd81360f589fbf0d0e6b9c599e7..aa5a0d79a8f8d39c3ac3ed0f28793c508632a3b6 100644
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/OpenIDConnect.pm
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/OpenIDConnect.pm
@@ -116,11 +116,14 @@ sub run {
login_hint acr_valuesi request request_uri/
)
{
- $oidc_request->{$param} = $req->param($param);
- $self->lmLog(
- "OIDC request parameter $param: " . $oidc_request->{$param},
- 'debug'
- );
+ if ( $req->param($param) ) {
+ $oidc_request->{$param} = $req->param($param);
+ $self->lmLog(
+ "OIDC request parameter $param: "
+ . $oidc_request->{$param},
+ 'debug'
+ );
+ }
}
# Detect requested flow
@@ -244,7 +247,7 @@ sub run {
# Check if user needs to be reauthenticated
my $reauthentication = 0;
my $prompt = $oidc_request->{'prompt'};
- if ( $prompt =~ /\blogin\b/ ) {
+ if ( $prompt and $prompt =~ /\blogin\b/ ) {
$self->lmLog(
"Reauthentication requested by Relying Party in prompt parameter",
'debug'
@@ -439,10 +442,12 @@ sub run {
$ask_for_consent = 1 if ( $prompt =~ /\bconsent\b/ );
}
if ($ask_for_consent) {
- if ( $self->param('confirm') == 1 ) {
- $self->updatePersistentSession(
+ if ( $req->param('confirm')
+ and $req->param('confirm') == 1 )
+ {
+ $self->p->updatePersistentSession(
{ "_oidc_consent_time_$rp" => time } );
- $self->updatePersistentSession(
+ $self->p->updatePersistentSession(
{
"_oidc_consent_scope_$rp" =>
$oidc_request->{'scope'}
@@ -451,7 +456,9 @@ sub run {
$self->lmLog( "Consent given for Relying Party $rp",
'debug' );
}
- elsif ( $req->param('confirm') == -1 ) {
+ elsif ( $req->param('confirm')
+ and $req->param('confirm') == -1 )
+ {
$self->lmLog(
"User refused consent for Relying party $rp",
'debug' );
@@ -471,7 +478,7 @@ sub run {
'debug' );
# Return error if prompt is none
- if ( $prompt =~ /\bnone\b/ ) {
+ if ( $prompt and $prompt =~ /\bnone\b/ ) {
$self->lmLog(
"Consent is needed but prompt is none",
'debug' );
@@ -501,10 +508,10 @@ sub run {
}
# HERE
- $self->info('
');
- $self->info( '

' )
+ $req->info('
');
+ $req->info( '

' )
if $img_src;
- $self->info(
+ $req->info(
qq'
The application $display_name would like to know:
'
);
@@ -520,10 +527,10 @@ qq'The application $display_name would li
{
my $message = $scope_messages->{$requested_scope}
|| 'anotherInformation';
- $self->info(
+ $req->info(
qq'
- $message
');
}
- $self->info('
');
+ $req->info('
');
$req->datas->{activeTimer} = 0;
return PE_CONFIRM;
}
@@ -833,7 +840,7 @@ qq'The application $display_name would li
# Ask consent for logout
if ( $req->param('confirm') ) {
- if ( $self->param('confirm') == 1 ) {
+ if ( $req->param('confirm') == 1 ) {
my $apacheSession = $self->p->getApacheSession( $req->id );
$self->p->_deleteSession($apacheSession);
}
@@ -853,7 +860,7 @@ qq'The application $display_name would li
return $req->param('confirm') == 1 ? PE_LOGOUT_OK : PE_OK;
}
- $self->info(
+ $req->info(
'
Do you want to logout?
'
);
$req->datas->{activeTimer} = 0;
@@ -867,6 +874,7 @@ qq'The application $display_name would li
# Handle token endpoint
sub token {
my ( $self, $req ) = @_;
+ $req->parseBody if($req->method =~ /^post$/i);
$self->lmLog( "URL detected as an OpenID Connect TOKEN URL", 'debug' );
# Check authentication
@@ -903,7 +911,7 @@ sub token {
}
# Get code session
- my $code = $self->param('code');
+ my $code = $req->param('code');
$self->lmLog( "OpenID Connect Code: $code", 'debug' );
@@ -1025,6 +1033,7 @@ sub token {
sub userInfo {
my ( $self, $req ) = @_;
$self->lmLog( "URL detected as an OpenID Connect USERINFO URL", 'debug' );
+ $req->parseBody if($req->method =~ /^post$/i);
my $access_token = $self->getEndPointAccessToken($req);
@@ -1081,6 +1090,7 @@ sub userInfo {
sub jwks {
my ( $self, $req ) = @_;
$self->lmLog( "URL detected as an OpenID Connect JWKS URL", 'debug' );
+ $req->parseBody if($req->method =~ /^post$/i);
my $jwks = { keys => [] };
@@ -1210,10 +1220,11 @@ sub endSessionDone {
my ( $self, $req ) = @_;
$self->lmLog( "URL detected as an OpenID Connect END SESSION URL",
'debug' );
+ $req->parseBody if($req->method =~ /^post$/i);
$self->lmLog( "User is already logged out", 'debug' );
- my $post_logout_redirect_uri = $self->param('post_logout_redirect_uri');
- my $state = $self->param('state');
+ my $post_logout_redirect_uri = $req->param('post_logout_redirect_uri');
+ my $state = $req->param('state');
if ($post_logout_redirect_uri) {
@@ -1234,6 +1245,7 @@ sub checkSession {
my ( $self, $req ) = @_;
$self->lmLog( "URL detected as an OpenID Connect CHECK SESSION URL",
'debug' );
+ $req->parseBody if($req->method =~ /^post$/i);
my $portalPath = $self->{portal};
$portalPath =~ s#^https?://[^/]+/?#/#;
diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OpenIDConnect.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OpenIDConnect.pm
index 02455c336c3f2d8c69568b4ee87404a473104f62..cd19b51413e22e220243fd37e815b493164430c3 100644
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OpenIDConnect.pm
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OpenIDConnect.pm
@@ -69,7 +69,7 @@ sub loadOPs {
}
# Extract JSON data
- foreach ( keys %{ $self->{oidcOPMetaDataJSON} } ) {
+ foreach ( keys %{ $self->conf->{oidcOPMetaDataJSON} } ) {
$self->oidcOPList->{$_}->{conf} =
$self->decodeJSON( $self->conf->{oidcOPMetaDataJSON}->{$_} );
$self->oidcOPList->{$_}->{jwks} =
@@ -209,7 +209,7 @@ sub getCallbackUri {
my $callback_uri = $self->conf->{portal};
$callback_uri .=
- ( $self->{portal} =~ /\?/ )
+ ( $self->conf->{portal} =~ /\?/ )
? '&' . $callback_get_param . '=1'
: '?' . $callback_get_param . '=1';
@@ -693,12 +693,13 @@ sub getOpenIDConnectSession {
# corresponding session_id
# @return State Session ID
sub storeState {
- my ( $self, @data ) = @_;
+ my ( $self, $req, @data ) = @_;
# check if there are data to store
my $infos;
foreach (@data) {
- $infos->{$_} = $self->{$_} if $self->{$_};
+ $infos->{$_} = $req->{$_} if $req->{$_};
+ $infos->{"datas_$_"} = $req->datas->{$_} if $req->datas->{$_};
}
return unless ($infos);
@@ -738,12 +739,16 @@ sub extractState {
# Push values in $self
foreach ( keys %{ $stateSession->data } ) {
- next if $_ =~ /(type|_session_id|_utime)/;
- if ( $req->can($_) ) {
- $req->$_( $stateSession->data->{$_} );
+ next if $_ =~ /(type|_session_id|_session_kind|_utime)/;
+ my $tmp = $stateSession->data->{$_};
+ if (s/^datas_//) {
+ $req->datas->{$_} = $tmp;
+ }
+ elsif ( $req->can($_) ) {
+ $req->$_($tmp);
}
else {
- $req->datas->{$_} = $stateSession->data->{$_};
+ $self->lmLog( "Unknown request property $_, skipping", 'warn' );
}
}
@@ -1071,7 +1076,7 @@ sub getEndPointAuthenticationCredentials {
my ( $client_id, $client_secret );
my $authorization = $req->authorization;
- if ( $authorization =~ /^Basic (\w+)/i ) {
+ if ( $authorization and $authorization =~ /^Basic (\w+)/i ) {
$self->lmLog( "Method client_secret_basic used", 'debug' );
eval {
( $client_id, $client_secret ) = split( /:/, decode_base64($1) );
diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Display.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Display.pm
index 26a25ffd85d3a44e49f669e6a7253a5f6d66efc5..7e263fd07777a5422e3d5a2f01e034faf699f3c0 100644
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Display.pm
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Display.pm
@@ -59,53 +59,11 @@ sub display {
}
- # 1. Good authentication
+ # 1. Authentication not complete
- # 1.1 Case : there is a message to display
- if ( my $info = $req->info() ) {
- $skinfile = 'info';
- %templateParams = (
- AUTH_ERROR_TYPE => $req->error_type,
- MSG => $info,
- URL => $req->{urldc},
- HIDDEN_INPUTS => $self->buildHiddenForm(),
- ACTIVE_TIMER => $req->datas->{activeTimer},
- FORM_METHOD => $self->conf->{infoFormMethod},
- );
- }
-
- # 1.2 Redirection
- elsif ( $req->{error} == PE_REDIRECT ) {
- $skinfile = "redirect";
- %templateParams = (
- URL => $req->{urldc},
- HIDDEN_INPUTS => $self->buildHiddenForm($req),
- FORM_METHOD => $req->datas->{redirectFormMethod} || 'get',
- );
- }
-
- # 1.3 Case : display menu
- elsif ( $req->error == PE_OK ) {
-
- $skinfile = 'menu';
-
- #utf8::decode($auth_user);
-
- %templateParams = (
- AUTH_USER => $req->{sessionInfo}->{ $self->conf->{portalUserAttr} },
- NEWWINDOW => $self->conf->{portalOpenLinkInNewWindow},
- LOGOUT_URL => $self->conf->{portal} . "?logout=1",
- APPSLIST_ORDER => $req->{sessionInfo}->{'appsListOrder'},
- PING => $self->conf->{portalPingInterval},
- $self->menu->params($req),
- );
- }
-
- # 2. Authentication not complete
-
- # 2.1 A notification has to be done (session is created but hidden and
+ # 1.1 A notification has to be done (session is created but hidden and
# unusable until the user has accept the message)
- elsif ( my $notif = $req->datas->{notification} ) {
+ if ( my $notif = $req->datas->{notification} ) {
$skinfile = 'notification';
%templateParams = (
AUTH_ERROR_TYPE => $req->error_type,
@@ -117,7 +75,7 @@ sub display {
);
}
- # 2.2 An authentication (or userDB) module needs to ask a question
+ # 1.2 An authentication (or userDB) module needs to ask a question
# before processing to the request
elsif ( $req->{error} == PE_CONFIRM ) {
$skinfile = 'confirm';
@@ -140,8 +98,8 @@ sub display {
);
}
- # 2.3 There is a message to disp->conf->conflay
- elsif ( $info = $req->info ) {
+ # 1.3 There is a message to display
+ elsif ( my $info = $req->info ) {
$skinfile = 'info';
%templateParams = (
AUTH_ERROR => $self->error,
@@ -156,7 +114,7 @@ sub display {
);
}
- # 2.4 OpenID menu page
+ # 1.4 OpenID menu page
elsif ($req->{error} == PE_OPENID_EMPTY
or $req->{error} == PE_OPENID_BADID )
{
@@ -175,7 +133,36 @@ sub display {
);
}
- # 2.5 Authentication has been refused OR this is the first access
+ # 2. Good authentication
+
+ # 2.1 Redirection
+ elsif ( $req->{error} == PE_REDIRECT ) {
+ $skinfile = "redirect";
+ %templateParams = (
+ URL => $req->{urldc},
+ HIDDEN_INPUTS => $self->buildHiddenForm($req),
+ FORM_METHOD => $req->datas->{redirectFormMethod} || 'get',
+ );
+ }
+
+ # 2.2 Case : display menu
+ elsif ( $req->error == PE_OK ) {
+
+ $skinfile = 'menu';
+
+ #utf8::decode($auth_user);
+
+ %templateParams = (
+ AUTH_USER => $req->{sessionInfo}->{ $self->conf->{portalUserAttr} },
+ NEWWINDOW => $self->conf->{portalOpenLinkInNewWindow},
+ LOGOUT_URL => $self->conf->{portal} . "?logout=1",
+ APPSLIST_ORDER => $req->{sessionInfo}->{'appsListOrder'},
+ PING => $self->conf->{portalPingInterval},
+ $self->menu->params($req),
+ );
+ }
+
+ # 3 Authentication has been refused OR this is the first access
else {
$skinfile = 'login';
my $login = $self->userId($req);
diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Issuer.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Issuer.pm
index 0206c9e09ad73e568f9590a56241b1d1d1acea20..4ec462670f41985a5b8c963529df3cbbd12ec717 100644
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Issuer.pm
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Issuer.pm
@@ -107,10 +107,10 @@ sub _forAuthUser {
}
sub _pForAuthUser {
- my ( $self, $req ) = @_;
+ my ( $self, $req, @path ) = @_;
$self->lmLog( 'Parsing posted datas', 'debug' );
$req->parseBody;
- return $self->_forAuthUser($req);
+ return $self->_forAuthUser( $req, @path );
}
1;
diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Process.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Process.pm
index e1a892f02eb20dc333f87b5818490c5355f9df2f..9fe8a92dede6ca5e394b91b7cf4204ee912f8bc7 100644
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Process.pm
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Process.pm
@@ -52,9 +52,28 @@ sub importHandlerDatas {
PE_OK;
}
-# Verify url parameter
+# Verify url and confirm parameter
sub controlUrl {
my ( $self, $req ) = @_;
+ if ( my $c = $req->param('confirm') ) {
+
+ # Replace confirm stamp by 1 or -1
+ $c =~ s/^(-?)(.*)$/${1}1/;
+
+ # Decrypt confirm stamp if cipher available
+ # and confirm not already decrypted
+ if ( $self->conf->{cipher} and $2 ne "1" ) {
+ my $time = time() - $self->conf->{cipher}->decrypt($2);
+ if ( $time < 600 ) {
+ $self->lmLog( "Confirm parameter accepted $c", 'debug' );
+ $req->param( 'confirm', $c );
+ }
+ else {
+ $self->lmLog( 'Confirmation to old, refused', 'notice' );
+ $req->param( 'confirm', 0 );
+ }
+ }
+ }
$req->{datas}->{_url} ||= '';
if ( my $url = $req->param('url') ) {
diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Request.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Request.pm
index d2449bb281de5cc3bb3d9c09bc9b83ca47157651..c15a3ffdefcc2e4a877292d32a105d1d8657b961 100644
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Request.pm
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Request.pm
@@ -50,9 +50,6 @@ has checkLogins => ( is => 'rw' );
# Boolean to indicate that url isn't Base64 encoded
has urlNotBase64 => ( is => 'rw' );
-# Info to display at login
-has info => ( is => 'rw' );
-
# Menu error
has menuError => ( is => 'rw' );
diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDB/OpenIDConnect.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDB/OpenIDConnect.pm
index 32830a5653526b1b0bb7546546fa7b004f84f20f..5277134936ab7a0f7f6db3ff342dccc2775651e2 100644
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDB/OpenIDConnect.pm
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDB/OpenIDConnect.pm
@@ -15,6 +15,7 @@ extends 'Lemonldap::NG::Common::Module', 'Lemonldap::NG::Portal::Lib::OpenIDConn
sub init {
my ($self) = @_;
+ return $self->loadOPs;
}
# RUNNING METHODS
diff --git a/lemonldap-ng-portal/t/32-Auth-and-issuer-OIDC.t b/lemonldap-ng-portal/t/32-Auth-and-issuer-OIDC.t
index ffdd106ae9b99bb2f782ba49b96c96348eb845a1..2ba4b9ad95d10ee78b1bd7bde4a6c3373e604dfc 100644
--- a/lemonldap-ng-portal/t/32-Auth-and-issuer-OIDC.t
+++ b/lemonldap-ng-portal/t/32-Auth-and-issuer-OIDC.t
@@ -7,7 +7,7 @@ BEGIN {
require 't/test-lib.pm';
}
-my $debug = 'error';
+my $debug = 'debug';
my ( $issuer, $sp, $res );
my %handlerOR = ( issuer => [], sp => [] );
@@ -25,11 +25,105 @@ switch ('sp');
ok( $sp = sp( $jwks, $metadata ), 'RP portal' );
count(1);
-#print STDERR Dumper( $jwks, $metadata );
+# Query RP for auth
+ok( $res = $sp->_get( '/', accept => 'text/html' ), 'Unauth SP request' );
+count(1);
+my ( $url, $query ) =
+ expectRedirection( $res, qr#http://auth.op.com(/oauth2/authorize)\?(.*)$# );
+
+# Push request to OP
+switch ('issuer');
+ok( $res = $issuer->_get( $url, query => $query, accept => 'text/html' ),
+ 'Push request to OP' );
+count(1);
+expectOK($res);
+
+# Try to authenticate to IdP
+$query = "user=dwho&password=dwho&$query";
+ok(
+ $res = $issuer->_post(
+ $url,
+ IO::String->new($query),
+ accept => 'text/html',
+ length => length($query),
+ ),
+ 'Post authentication'
+);
+count(1);
+my $idpId = expectCookie($res);
+my ( $host, $tmp );
+( $host, $tmp, $query ) = expectForm( $res, '#' );
+
+ok(
+ $res = $issuer->_post(
+ $url,
+ IO::String->new($query),
+ accept => 'text/html',
+ cookie => "lemonldap=$idpId",
+ length => length($query),
+ ),
+ 'Post authentication'
+);
+count(1);
+
+($query) = expectRedirection( $res, qr#^http://auth.rp.com/?\?(.*)$# );
+
+# Push OP response to RP
+switch ('sp');
+
+ok( $res = $sp->_get( '/', query => $query, accept => 'text/html' ),
+ 'Call openidconnectcallback on RP' );
+count(1);
+my $rpId = expectCookie($res);
clean_sessions();
done_testing( count() );
+no warnings 'redefine';
+
+sub LWP::UserAgent::request {
+ my ( $self, $req ) = @_;
+ ok( $req->uri =~ m#http://auth.((?:o|r)p).com(.*)#, 'REST request' );
+ my $host = $1;
+ my $url = $2;
+ my $res;
+ my $client = ( $host eq 'op' ? $issuer : $sp );
+ if ( $req->method =~ /^post$/i ) {
+ my $s = $req->content;
+ ok(
+ $res = $client->_post(
+ $url, IO::String->new($s),
+ length => length($s),
+ type => $req->header('Content-Type'),
+ ),
+ 'Execute request'
+ );
+ }
+ else {
+ ok(
+ $res = $client->_get(
+ $url,
+ custom => {
+ HTTP_AUTHORIZATION => $req->header('Authorization'),
+ }
+ ),
+ 'Execute request'
+ );
+ }
+ expectOK($res);
+ ok( getHeader( $res, 'Content-Type' ) =~ m#^application/json#,
+ 'Content is JSON' )
+ or explain( $res->[1], 'Content-Type => application/json' );
+ my $httpResp = HTTP::Response->new( $res->[0], 'OK' );
+
+ while ( my $name = shift @{ $res->[1] } ) {
+ $httpResp->header( $name, shift( @{ $res->[1] } ) );
+ }
+ $httpResp->content( join( '', @{ $res->[2] } ) );
+ count(3);
+ return $httpResp;
+}
+
sub switch {
my $type = shift;
@Lemonldap::NG::Handler::Main::Reload::_onReload = @{
diff --git a/lemonldap-ng-portal/t/lmConf-1.js b/lemonldap-ng-portal/t/lmConf-1.js
index 85ae008b06384fc8f4c9204bd64e26680da066ce..c5525963442c4066fdc0e019e8e09b8279b416c8 100644
--- a/lemonldap-ng-portal/t/lmConf-1.js
+++ b/lemonldap-ng-portal/t/lmConf-1.js
@@ -66,6 +66,12 @@
"LockDirectory": "t/sessions/saml/lock",
"generateModule": "Lemonldap::NG::Common::Apache::Session::Generate::SHA256"
},
+ "oidcStorage": "Apache::Session::File",
+ "oidcStorageOptions": {
+ "Directory": "t/sessions/saml",
+ "LockDirectory": "t/sessions/saml/lock",
+ "generateModule": "Lemonldap::NG::Common::Apache::Session::Generate::SHA256"
+ },
"reloadUrls": {},
"userDB": "Demo",
"whatToTrace": "_whatToTrace"
diff --git a/lemonldap-ng-portal/t/test-lib.pm b/lemonldap-ng-portal/t/test-lib.pm
index cdba6d8e821abd38e19266e5396dd3c8049e1da8..aeef03c310c02f8133bd72a3dc4ae3f474703701 100644
--- a/lemonldap-ng-portal/t/test-lib.pm
+++ b/lemonldap-ng-portal/t/test-lib.pm
@@ -48,33 +48,46 @@ sub expectRedirection {
my ( $res, $location ) = @_;
ok( $res->[0] == 302, 'Get redirection' )
or explain( $res->[0], 302 );
- count(2);
+ count(1);
if ( ref $location ) {
my @match;
@match = ( getRedirection($res) =~ $location );
ok( @match, 'Location header found' )
or explain( $res->[1], "Location match: " . Dumper($location) );
+ count(1);
return @match;
}
else {
ok( getRedirection($res) eq $location, "Location is $location" )
or explain( $res->[1], "Location => $location" );
+count(1);
}
}
sub expectAutoPost {
+ my @r = expectForm(@_);
+ my $method = pop @r;
+ ok ( $method =~ /^post$/i );
+ count(1);
+}
+
+sub expectForm {
my ( $res, $hostRe, $uriRe, @requiredFields ) = @_;
expectOK($res);
- count(2);
+ count(1);
if (
ok(
$res->[2]->[0] =~
- m@
[2]->[0] =~
- m#app->(
{
'HTTP_ACCEPT' => $args{accept}