From 2d60af304f126fff787a39b620a75240c1950cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20OUDOT?= Date: Mon, 29 Mar 2021 20:54:49 +0200 Subject: [PATCH 1/9] Fix notifications documentation (#2497) --- doc/sources/admin/notifications.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/sources/admin/notifications.rst b/doc/sources/admin/notifications.rst index eb1361f86..87217ea77 100644 --- a/doc/sources/admin/notifications.rst +++ b/doc/sources/admin/notifications.rst @@ -20,7 +20,7 @@ Activation To activate notifications system: -Go to Manager ``General Parameters`` » ``Advanced Parameters`` » ``Notifications`` » ``Activation`` +Go to Manager ``General Parameters`` » ``Plugins`` » ``Notifications`` » ``Activation`` or in ``lemonldap-ng.ini`` [portal] section: @@ -34,7 +34,7 @@ Explorer Notifications explorer allows users to see and display theirs accepted notifications. Disable by default, you just have to activate it in the -Manager (``General Parameters`` » ``Advanced Parameters`` » ``Notifications`` » +Manager (``General Parameters`` » ``Plugins`` » ``Notifications`` » ``Explorer``) or in ``lemonldap-ng.ini`` [portal] section: @@ -91,7 +91,7 @@ configuration: You can change default parameters using the "notificationStorage" and "notificationStorageOptions" parameters with the same syntax as configuration storage parameters. To do this in Manager, go in General -Parameters > Advanced Parameters > Notifications. +Parameters > Plugins > Notifications. File ^^^^ @@ -200,7 +200,7 @@ The notifications module uses a wildcard to manage notifications for all users. The default value of this wildcard is ``allusers``, but you can change it if ``allusers`` is a known identifier in your system. -To change it, go in General Parameters > Advanced Parameters > +To change it, go in General Parameters > Plugins > Notifications > Wildcard for all users, and set for example ``alluserscustom``. From 2c8cbbefe6cb859dacea688522616492f1b94f31 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Tue, 23 Mar 2021 09:17:51 +0100 Subject: [PATCH 2/9] "xxx is allowed to update 2FA" should be a debug message --- lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Plugin.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Plugin.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Plugin.pm index fffddd769..3053ea1fc 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Plugin.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Plugin.pm @@ -107,7 +107,7 @@ sub createNotification { sub canUpdateSfa { my ( $self, $req, $action ) = @_; my $user = $req->userData->{ $self->conf->{whatToTrace} }; - my $msg = undef; + my $msg = undef; # Test action if ( $action && $action eq 'delete' ) { @@ -157,7 +157,7 @@ sub canUpdateSfa { $msg = 'notAuthorized'; } } - $self->userLogger->info("$user is allowed to update 2FA") unless $msg; + $self->logger->debug("$user is allowed to update 2FA") unless $msg; return $msg; } From 20e1f9ded0a4414b3e58f199bf7f3cba20ce4012 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Mon, 29 Mar 2021 15:12:10 +0200 Subject: [PATCH 3/9] Hash JWT to catch tampering (#2419) This mechanism's only purpose is to make the introsection endpoint fail to verify the token when the JWT itself has been tampered with. --- .../NG/Portal/Issuer/OpenIDConnect.pm | 2 +- .../Lemonldap/NG/Portal/Lib/OpenIDConnect.pm | 163 +++++++++++------- 2 files changed, 98 insertions(+), 67 deletions(-) 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 4c866fb3e..944a3e62d 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/OpenIDConnect.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/OpenIDConnect.pm @@ -1719,7 +1719,7 @@ sub userInfo { unless ($accessTokenSession) { $self->userLogger->error( - "Unable to get access token session for id $access_token"); + "Unable to validate access token $access_token"); return $self->returnBearerError( 'invalid_request', 'Invalid request', 401 ); } 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 d8fd72ea5..40c1823ab 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OpenIDConnect.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OpenIDConnect.pm @@ -722,93 +722,100 @@ sub getAuthorizationCode { sub newAccessToken { my ( $self, $req, $rp, $scope, $sessionInfo, $info ) = @_; + my $at_info = { + + scope => $scope, + rp => $rp, + %{$info}, + }; + my $session = $self->getOpenIDConnectSession( undef, "access_token", $self->conf->{oidcRPMetaDataOptions}->{$rp} ->{oidcRPMetaDataOptionsAccessTokenExpiration} || $self->conf->{oidcServiceAccessTokenExpiration}, - { - - scope => $scope, - rp => $rp, - %{$info}, - } + $at_info, ); if ($session) { - return $self->maybeJWT( $req, $rp, $scope, $session->id, $sessionInfo ); + if ( $self->_wantJWT($rp) ) { + my $at_jwt = + $self->makeJWT( $req, $rp, $scope, $session->id, $sessionInfo ); + $at_info->{sha256_hash} = $self->createHash( $at_jwt, 256 ); + $self->updateToken( $session->id, $at_info ); + return $at_jwt; + } + else { + return $session->id; + } } else { return undef; } } -sub maybeJWT { +sub _wantJWT { + my ( $self, $rp ) = @_; + return $self->conf->{oidcRPMetaDataOptions}->{$rp} + ->{oidcRPMetaDataOptionsAccessTokenJWT}; +} + +sub makeJWT { my ( $self, $req, $rp, $scope, $id, $sessionInfo ) = @_; - if ( $self->conf->{oidcRPMetaDataOptions}->{$rp} - ->{oidcRPMetaDataOptionsAccessTokenJWT} ) - { + my $exp = + $self->conf->{oidcRPMetaDataOptions}->{$rp} + ->{oidcRPMetaDataOptionsAccessTokenExpiration} + || $self->conf->{oidcServiceAccessTokenExpiration}; + $exp += time; + my $client_id = $self->oidcRPList->{$rp}->{oidcRPMetaDataOptionsClientID}; - my $exp = - $self->conf->{oidcRPMetaDataOptions}->{$rp} - ->{oidcRPMetaDataOptionsAccessTokenExpiration} - || $self->conf->{oidcServiceAccessTokenExpiration}; - $exp += time; - my $client_id = - $self->oidcRPList->{$rp}->{oidcRPMetaDataOptionsClientID}; + my $access_token_payload = { + iss => $self->iss, # Issuer Identifier + exp => $exp, # expiration + aud => $self->getAudiences($rp), # Audience + client_id => $client_id, # Client ID + iat => time, # Issued time + jti => $id, # Access Token session ID + scope => $scope, # Scope + }; - my $access_token_payload = { - iss => $self->iss, # Issuer Identifier - exp => $exp, # expiration - aud => $self->getAudiences($rp), # Audience - client_id => $client_id, # Client ID - iat => time, # Issued time - jti => $id, # Access Token session ID - scope => $scope, # Scope - }; - - my $claims; - if ( ref($sessionInfo) eq "HASH" ) { - $claims = $self->buildUserInfoResponseFromData( $req, $scope, - $rp, $sessionInfo ); - } - else { - $claims = $self->buildUserInfoResponseFromId( $req, $scope, - $rp, $sessionInfo ); - } - - # Release claims, or only sub - if ( $self->conf->{oidcRPMetaDataOptions}->{$rp} - ->{oidcRPMetaDataOptionsAccessTokenClaims} ) - { - foreach ( keys %$claims ) { - $access_token_payload->{$_} = $claims->{$_}; - } - } - else { - $access_token_payload->{sub} = $claims->{sub}; - } - - # Call hook to let the user modify payload - my $h = $self->p->processHook( $req, 'oidcGenerateAccessToken', - $access_token_payload, $rp ); - return undef if ( $h != PE_OK ); - - # Get signature algorithm - my $alg = $self->conf->{oidcRPMetaDataOptions}->{$rp} - ->{oidcRPMetaDataOptionsAccessTokenSignAlg} || "RS256"; - $self->logger->debug("Access Token signature algorithm: $alg"); - - my $jwt = - $self->createJWT( $access_token_payload, $alg, $rp, "at+JWT" ); - - return $jwt; + my $claims; + if ( ref($sessionInfo) eq "HASH" ) { + $claims = $self->buildUserInfoResponseFromData( $req, $scope, + $rp, $sessionInfo ); } else { - return $id; + $claims = + $self->buildUserInfoResponseFromId( $req, $scope, $rp, $sessionInfo ); } + + # Release claims, or only sub + if ( $self->conf->{oidcRPMetaDataOptions}->{$rp} + ->{oidcRPMetaDataOptionsAccessTokenClaims} ) + { + foreach ( keys %$claims ) { + $access_token_payload->{$_} = $claims->{$_}; + } + } + else { + $access_token_payload->{sub} = $claims->{sub}; + } + + # Call hook to let the user modify payload + my $h = $self->p->processHook( $req, 'oidcGenerateAccessToken', + $access_token_payload, $rp ); + return undef if ( $h != PE_OK ); + + # Get signature algorithm + my $alg = $self->conf->{oidcRPMetaDataOptions}->{$rp} + ->{oidcRPMetaDataOptionsAccessTokenSignAlg} || "RS256"; + $self->logger->debug("Access Token signature algorithm: $alg"); + + my $jwt = $self->createJWT( $access_token_payload, $alg, $rp, "at+JWT" ); + + return $jwt; } # Get an session from the supplied Access Token @@ -820,7 +827,26 @@ sub getAccessToken { my $id = getAccessTokenSessionId($access_token); return unless $id; - return $self->getOpenIDConnectSession( $id, "access_token" ); + my $session = $self->getOpenIDConnectSession( $id, "access_token" ); + return undef unless $session; + + my $stored_hash = $session->{data}->{sha256_hash}; + if ($stored_hash) { + my $incoming_hash = $self->createHash( $access_token, 256 ); + if ( $stored_hash eq $incoming_hash ) { + return $session; + } + else { + $self->logger->error( + "Incoming Access token hash $incoming_hash " + . "does not match stored hash $stored_hash. " + . "The access token might have been tampered with." ); + return undef; + } + } + else { + return $session; + } } # Create a new Refresh Token @@ -851,6 +877,11 @@ sub getRefreshToken { } sub updateRefreshToken { + my $self = shift; + return $self->updateToken($@); +} + +sub updateToken { my ( $self, $id, $infos ) = @_; my %storage = ( From dca8483ec592bc4ebe066bed54462632f3ebb790 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Mon, 29 Mar 2021 15:28:17 +0200 Subject: [PATCH 4/9] Relax scope name constraints in manager (#2424) --- lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm | 2 +- .../lib/Lemonldap/NG/Manager/Build/Attributes.pm | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm index 68f9ab780..259eeb3fe 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm @@ -2443,7 +2443,7 @@ m[^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?: 'default' => {}, 'test' => { 'keyMsgFail' => '__badMacroName__', - 'keyTest' => qr/^[_a-zA-Z][a-zA-Z0-9_]*$/, + 'keyTest' => qr/^[\x21\x23-\x5B\x5D-\x7E]+$/, 'test' => sub { return perlExpr(@_); } diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm index 732568b5a..f3212ff66 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm @@ -4338,7 +4338,8 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?: type => 'keyTextContainer', help => 'idpopenidconnect.html#scope-rules', test => { - keyTest => qr/^[_a-zA-Z][a-zA-Z0-9_]*$/, + # RFC6749 + keyTest => qr/^[\x21\x23-\x5B\x5D-\x7E]+$/, keyMsgFail => '__badMacroName__', test => sub { return perlExpr(@_) }, }, From b4f5ee58c36e5a2b9718c9aa09e329774f4cdefc Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Tue, 30 Mar 2021 12:07:09 +0200 Subject: [PATCH 5/9] Fix #2498 --- lemonldap-ng-common/scripts/convertSessions | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lemonldap-ng-common/scripts/convertSessions b/lemonldap-ng-common/scripts/convertSessions index 9aae913b1..e76af7a00 100755 --- a/lemonldap-ng-common/scripts/convertSessions +++ b/lemonldap-ng-common/scripts/convertSessions @@ -128,6 +128,17 @@ Lemonldap::NG::Common::Apache::Session->get_key_from_all_sessions( my $entry = shift; my $id = shift; + # If filtering sessionKind + if (@sessionKindOnly) { + + unless ( grep { $_ eq $entry->{_session_kind} } @sessionKindOnly ) { + print "Ignoring session $id with type " + . $entry->{_session_kind} . "\n" + if $debug; + return undef; + } + } + print "Processing session $id\n" if $debug; my $s = Lemonldap::NG::Common::Session->new( { storageModule => $backendTo->{backend}, @@ -138,14 +149,6 @@ Lemonldap::NG::Common::Apache::Session->get_key_from_all_sessions( } ); - # If filtering sessionKind - if (@sessionKindOnly) { - - unless ( grep { $_ eq $entry->{_session_kind} } @sessionKindOnly ) { - return undef; - } - } - if ( $s->error ) { die "Error encountered on session $id" unless $ignore_errors; $nb_error += 1; From 6f9734db92a5e01975f050567c8879ce385271b2 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Tue, 30 Mar 2021 12:07:32 +0200 Subject: [PATCH 6/9] convertSession: add option to rename fields (#2499) --- lemonldap-ng-common/scripts/convertSessions | 109 +++++++++++--------- 1 file changed, 63 insertions(+), 46 deletions(-) diff --git a/lemonldap-ng-common/scripts/convertSessions b/lemonldap-ng-common/scripts/convertSessions index e76af7a00..9ba895895 100755 --- a/lemonldap-ng-common/scripts/convertSessions +++ b/lemonldap-ng-common/scripts/convertSessions @@ -13,62 +13,45 @@ use Lemonldap::NG::Common::Apache::Session; use Lemonldap::NG::Common::Session; use Config::IniFiles; use strict; -use Getopt::Std; -$Getopt::Std::STANDARD_HELP_VERSION = 1; +use Getopt::Long; +use Pod::Usage; our $VERSION = "2.0.6"; # Options # -d: debug mode # -c: configuration file +# -r: configuration file # -i: ignore errors -my $opts = {}; -getopts( 'dic:', $opts ); -my $debug = $opts->{d}; -my $config_file = $opts->{c}; -my $ignore_errors = $opts->{i}; -my $nb_converted = 0; -my $nb_error = 0; +my $debug; +my $config_file; +my $ignore_errors; +my %rename; +my $help; +my $nb_converted = 0; +my $nb_error = 0; -sub HELP_MESSAGE { - my $OUT = shift; - print $OUT < '/var/lib/lemonldap-ng/sessions', \\ - 'LockDirectory' => '/var/lib/lemonldap-ng/sessions/lock', \\ -} -# Only convert some session types -# sessionKind = Persistent, SSO - -[sessions_to] -storageModule = Apache::Session::Browseable::Postgres -storageModuleOptions = { \\ - 'DataSource' => 'DBI:Pg:database=lemonldapdb;host=pg.example.com', \\ - 'UserName' => 'lemonldaplogin', \\ - 'Password' => 'lemonldappw', \\ - 'Commit' => 1, \\ - 'Index' => 'ipAddr _whatToTrace user', \\ - 'TableName' => 'sessions', \\ -} - -END_MESSAGE -} +GetOptions( + 'help|?' => \$help, + 'debug|d' => \$debug, + 'config|c=s' => \$config_file, + 'ignore-errors|i' => \$ignore_errors, + 'rename|r=s' => \%rename, +) or pod2usage(2); +pod2usage( + -exitval => 1, + -verbose => 99, + -sections => "SYNOPSIS|OPTIONS|CONFIGURATION FILE FORMAT" +) if $help; unless ($config_file) { - HELP_MESSAGE( \*STDERR ); - die "You must provide the -c option"; + pod2usage( + -exitval => 2, + -verbose => 99, + -message => "You must provide the -c option\n", + -sections => "SYNOPSIS|OPTIONS|CONFIGURATION FILE FORMAT" + ); } my $inicfg = @@ -139,6 +122,17 @@ Lemonldap::NG::Common::Apache::Session->get_key_from_all_sessions( } } + if (%rename) { + for my $oldkey ( keys %rename ) { + my $newkey = $rename{$oldkey}; + if ( $newkey and $entry->{$oldkey} ) { + print "Renaming $oldkey to $newkey in session $id\n" + if $debug; + $entry->{$newkey} = delete $entry->{$oldkey}; + } + } + } + print "Processing session $id\n" if $debug; my $s = Lemonldap::NG::Common::Session->new( { storageModule => $backendTo->{backend}, @@ -178,7 +172,7 @@ convertSessions - A tool to convert Lemonldap::NG sessions between storage backe =head1 SYNOPSIS - convertSession [-di] -c parameters.ini + convertSession [-di] [-r oldkey=newkey ] -c parameters.ini =head1 DESCRIPTION @@ -194,6 +188,29 @@ destination backend will be kept, unless they have the same session ID as a session in the source backend. In that case, the source will overwrite the destination. +=head1 OPTIONS + +=over + +=item B<--config>,B<-c> + +Specify configuration file + +=item B<--debug>,B<-d> + +Turns on debugging information + +=item B<--ignore-errors>,B<-i> + +Skip to the next session if converting a session fails + +=item B<--rename oldkey=newkey>,B<-r oldkey=newkey> + +Rename key names when migrating from one backend to the next. + +This option can be specified multiple times + +=back =head1 CONFIGURATION FILE FORMAT From 47a3a534a3856c2574ac65eaae37c78cc0110699 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Tue, 30 Mar 2021 12:11:08 +0200 Subject: [PATCH 7/9] Doc for #2499 --- doc/sources/admin/changesessionbackend.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/sources/admin/changesessionbackend.rst b/doc/sources/admin/changesessionbackend.rst index 9c6501145..d14c4e2f6 100644 --- a/doc/sources/admin/changesessionbackend.rst +++ b/doc/sources/admin/changesessionbackend.rst @@ -45,6 +45,7 @@ Invocation Options: - ``-c``: job configuration file (mandatory) +- ``-r oldkey=newkey``: rename session keys during conversion (optional, can be given multiple times) - ``-i``: ignore errors. By default errors will stop the script execution - ``-d``: print debugging output From 824cd5fb89e428f041f1d18adab999611d326aa5 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Tue, 30 Mar 2021 16:30:22 +0200 Subject: [PATCH 8/9] Fix CLI for oidcOPMetaDataJSON (#2439) and oidcOPMetaDataJWKS --- .../lib/Lemonldap/NG/Common/Conf/ReConstants.pm | 2 +- .../lib/Lemonldap/NG/Manager/Attributes.pm | 6 ++++++ lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build.pm | 9 +++++++++ .../lib/Lemonldap/NG/Manager/Build/Attributes.pm | 4 ++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/ReConstants.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/ReConstants.pm index f512756d8..125e94220 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/ReConstants.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/ReConstants.pm @@ -22,7 +22,7 @@ our $specialNodeHash = { }; our $doubleHashKeys = 'issuerDBGetParameters'; -our $simpleHashKeys = '(?:(?:c(?:as(?:StorageOption|Attribute)|ustom(?:Plugins|Add)Param|heckUserHiddenHeader|ombModule)|l(?:o(?:calSessionStorageOption|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|f(?:indUser(?:Exclud|Search)ingAttribute|acebookExportedVar)|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|p(?:ersistentStorageOption|ortalSkinRule)|(?:(?:d(?:emo|bi)|webID)E|e)xportedVar|macro)s|o(?:idcS(?:ervice(?:DynamicRegistrationEx(?:portedVar|traClaim)s|MetaDataAuthnContext)|torageOptions)|penIdExportedVars)|a(?:(?:daptativeAuthenticationLevelR|ut(?:hChoiceMod|oSigninR))ules|pplicationList)|s(?:(?:amlStorageOption|laveExportedVar)s|essionDataToRemember|fExtra)|S(?:MTPTLSOpts|SLVarIf))'; +our $simpleHashKeys = '(?:(?:c(?:as(?:StorageOption|Attribute)|ustom(?:Plugins|Add)Param|heckUserHiddenHeader|ombModule)|l(?:o(?:calSessionStorageOption|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|f(?:indUser(?:Exclud|Search)ingAttribute|acebookExportedVar)|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|p(?:ersistentStorageOption|ortalSkinRule)|(?:(?:d(?:emo|bi)|webID)E|e)xportedVar|macro)s|o(?:idc(?:S(?:ervice(?:DynamicRegistrationEx(?:portedVar|traClaim)s|MetaDataAuthnContext)|torageOptions)|OPMetaDataJ(?:SON|WKS))|penIdExportedVars)|a(?:(?:daptativeAuthenticationLevelR|ut(?:hChoiceMod|oSigninR))ules|pplicationList)|s(?:(?:amlStorageOption|laveExportedVar)s|essionDataToRemember|fExtra)|S(?:MTPTLSOpts|SLVarIf))'; our $specialNodeKeys = '(?:(?:(?:saml(?:ID|S)|oidc[OR])P|cas(?:App|Srv))MetaDataNode|virtualHost)s'; our $casAppMetaDataNodeKeys = 'casAppMetaData(?:Options(?:(?:UserAttribut|Servic|Rul)e|AuthnLevel)|(?:ExportedVar|Macro)s)'; our $casSrvMetaDataNodeKeys = 'casSrvMetaData(?:Options(?:ProxiedServices|DisplayName|SortNumber|Gateway|Renew|Icon|Url)|ExportedVars)'; diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm index 259eeb3fe..4605961b3 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm @@ -2148,9 +2148,15 @@ m[^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?: 'type' => 'keyTextContainer' }, 'oidcOPMetaDataJSON' => { + 'keyTest' => sub { + 1; + }, 'type' => 'file' }, 'oidcOPMetaDataJWKS' => { + 'keyTest' => sub { + 1; + }, 'type' => 'file' }, 'oidcOPMetaDataNodes' => { diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build.pm index 16a60b20c..1cb6cc6a9 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build.pm @@ -694,9 +694,18 @@ sub scanTree { } } } + if ($prefix) { push @cnodesKeys, $leaf; } + + # issue 2439 + # FIXME: in future versions, oidcOPMetaDataJSON and samlIDPMetaDataXML shoud + # behave the same + if ( $leaf =~ /^oidcOPMetaData(?:JSON|JWKS)$/ ) { + push @simpleHashKeys, $leaf; + } + if ( $attr->{type} =~ /^(?:catAndAppList|\w+Container)$/ ) { $jleaf->{cnodes} = $prefix . $leaf; unless ( $prefix or $leaf =~ $reIgnoreKeys ) { diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm index f3212ff66..7668339fc 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm @@ -4152,8 +4152,8 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?: oidcRPMetaDataOptions => { type => 'subContainer', }, # OpenID Connect providers - oidcOPMetaDataJSON => { type => 'file', }, - oidcOPMetaDataJWKS => { type => 'file', }, + oidcOPMetaDataJSON => { type => 'file', keyTest => sub { 1 } }, + oidcOPMetaDataJWKS => { type => 'file', keyTest => sub { 1 } }, oidcOPMetaDataExportedVars => { type => 'keyTextContainer', default => { From 5d649f67f5b05528512a894189626df9368e1091 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Tue, 30 Mar 2021 16:57:05 +0200 Subject: [PATCH 9/9] clarify auth::openidconnect doc (#2500) --- doc/sources/admin/authopenidconnect.rst | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/doc/sources/admin/authopenidconnect.rst b/doc/sources/admin/authopenidconnect.rst index ae8d03e82..baf2e0eb0 100644 --- a/doc/sources/admin/authopenidconnect.rst +++ b/doc/sources/admin/authopenidconnect.rst @@ -113,22 +113,19 @@ Register LL::NG to an OpenID Connect Provider ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To register LL::NG, you will need to give some information like -application name or logo. One of mandatory information is the redirect -URL (one or many). +application name or logo. -To know this information, just take the portal URL and the Callback GET -parameter, for example: +You will be asked to provide a *Redirect URI* for LemonLDAP::NG, which is constructed by appending the ``openidcallback=1`` parameter to the Portal URL. -- http://auth.example.com/?openidcallback=1 -- http://auth.example.com/index.pl?openidcallback=1 -- http://auth.example.com/?lmAuth=oidc&openidcallback=1 +For example: + +- https://auth.example.com/?openidcallback=1 .. attention:: - If you use the :doc:`choice backend`, you - need to add the choice parameter in redirect URL or - set SameSite cookie value to "Lax" or "None". + If you use the :doc:`choice backend`, + you need to set SameSite cookie value to "Lax" or "None". See :doc:`SSO cookie parameters` After registration, the OP must give you a client ID and a client