diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBOpenIDConnect.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBOpenIDConnect.pm index 755e6cf46..938851982 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBOpenIDConnect.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBOpenIDConnect.pm @@ -436,7 +436,7 @@ sub issuerForAuthUser { my $max_age = $oidc_request->{'max_age'}; my $_lastAuthnUTime = $self->{sessionInfo}->{_lastAuthnUTime}; - if ( defined $max_age && time > $_lastAuthnUTime + $max_age ) { + if ( $max_age && time > $_lastAuthnUTime + $max_age ) { $self->lmLog( "Reauthentication forced cause authentication time ($_lastAuthnUTime) is too old (>$max_age s)", 'debug' @@ -495,6 +495,36 @@ sub issuerForAuthUser { $self->lmLog( "Client id $client_id match RP $rp", 'debug' ); } + # Check id_token_hint + my $id_token_hint = $oidc_request->{'id_token_hint'}; + if ($id_token_hint) { + + $self->lmLog( "Check sub of ID Token $id_token_hint", 'debug' ); + + # Check that id_token_hint sub match current user + my $sub = $self->getIDTokenSub($id_token_hint); + my $user_id_attribute = $self->{oidcRPMetaDataOptions}->{$rp} + ->{oidcRPMetaDataOptionsUserIDAttr} || $self->{whatToTrace}; + my $user_id = $self->{sessionInfo}->{$user_id_attribute}; + unless ( $sub eq $user_id ) { + $self->lmLog( + "ID Token hint sub $sub do not match user $user_id", + 'error' ); + $self->returnRedirectError( + $oidc_request->{'redirect_uri'}, + "invalid_request", + "current user do not match id_token_hint sub", + undef, + $oidc_request->{'state'}, + ( $flow ne "authorizationcode" ) + ); + } + else { + $self->lmLog( "ID Token hint sub $sub match current user", + 'debug' ); + } + } + # Obtain consent my $ask_for_consent = 1; if ( $self->{sessionInfo}->{"_oidc_consent_time_$rp"} diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_OpenIDConnect.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_OpenIDConnect.pm index bcf5b9c66..5b471d0d5 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_OpenIDConnect.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_OpenIDConnect.pm @@ -1159,6 +1159,19 @@ sub getFlowType { return $response_types->{$response_type}; } +## @method String getIDTokenSub(String id_token) +# Return sub field of an ID Token +# @param id_token ID Token +# @return String sub +sub getIDTokenSub { + my ( $self, $id_token ) = splice @_; + + my $jwt = $self->extractJWT($id_token); + my $payload = decode_json( decode_base64( $jwt->[1] ) ); + + return $payload->{sub}; +} + 1; __END__ @@ -1300,6 +1313,10 @@ Return ID Token Return flow type +=head2 getIDTokenSub + +Return sub field of an ID Token + =head1 SEE ALSO L, L