Implement introspection endpoint for access tokens (#1843)
This commit is contained in:
parent
fd7453b7a5
commit
d61935ab6e
|
@ -178,54 +178,55 @@ sub defaultValues {
|
|||
'loa-4' => 4,
|
||||
'loa-5' => 5
|
||||
},
|
||||
'oidcServiceMetaDataAuthorizeURI' => 'authorize',
|
||||
'oidcServiceMetaDataBackChannelURI' => 'blogout',
|
||||
'oidcServiceMetaDataCheckSessionURI' => 'checksession.html',
|
||||
'oidcServiceMetaDataEndSessionURI' => 'logout',
|
||||
'oidcServiceMetaDataFrontChannelURI' => 'flogout',
|
||||
'oidcServiceMetaDataJWKSURI' => 'jwks',
|
||||
'oidcServiceMetaDataRegistrationURI' => 'register',
|
||||
'oidcServiceMetaDataTokenURI' => 'token',
|
||||
'oidcServiceMetaDataUserInfoURI' => 'userinfo',
|
||||
'openIdAuthnLevel' => 1,
|
||||
'openIdExportedVars' => {},
|
||||
'openIdIDPList' => '0;',
|
||||
'openIdSPList' => '0;',
|
||||
'openIdSreg_email' => 'mail',
|
||||
'openIdSreg_fullname' => 'cn',
|
||||
'openIdSreg_nickname' => 'uid',
|
||||
'openIdSreg_timezone' => '_timezone',
|
||||
'pamAuthnLevel' => 2,
|
||||
'pamService' => 'login',
|
||||
'passwordDB' => 'Demo',
|
||||
'passwordResetAllowedRetries' => 3,
|
||||
'port' => -1,
|
||||
'portal' => 'http://auth.example.com/',
|
||||
'portalAntiFrame' => 1,
|
||||
'portalCheckLogins' => 1,
|
||||
'portalDisplayAppslist' => 1,
|
||||
'portalDisplayChangePassword' => '$_auth =~ /^(LDAP|DBI|Demo)$/',
|
||||
'portalDisplayLoginHistory' => 1,
|
||||
'portalDisplayLogout' => 1,
|
||||
'portalDisplayOidcConsents' => '$_oidcConnectedRP',
|
||||
'portalDisplayRegister' => 1,
|
||||
'portalErrorOnExpiredSession' => 1,
|
||||
'portalForceAuthnInterval' => 5,
|
||||
'portalMainLogo' => 'common/logos/logo_llng_400px.png',
|
||||
'portalPingInterval' => 60000,
|
||||
'portalRequireOldPassword' => 1,
|
||||
'portalSkin' => 'bootstrap',
|
||||
'portalUserAttr' => '_user',
|
||||
'proxyAuthnLevel' => 2,
|
||||
'radius2fActivation' => 0,
|
||||
'radius2fTimeout' => 20,
|
||||
'radiusAuthnLevel' => 3,
|
||||
'randomPasswordRegexp' => '[A-Z]{3}[a-z]{5}.\\d{2}',
|
||||
'redirectFormMethod' => 'get',
|
||||
'registerDB' => 'Null',
|
||||
'registerTimeout' => 0,
|
||||
'registerUrl' => 'http://auth.example.com/register',
|
||||
'reloadTimeout' => 5,
|
||||
'oidcServiceMetaDataAuthorizeURI' => 'authorize',
|
||||
'oidcServiceMetaDataBackChannelURI' => 'blogout',
|
||||
'oidcServiceMetaDataCheckSessionURI' => 'checksession.html',
|
||||
'oidcServiceMetaDataEndSessionURI' => 'logout',
|
||||
'oidcServiceMetaDataFrontChannelURI' => 'flogout',
|
||||
'oidcServiceMetaDataIntrospectionURI' => 'introspect',
|
||||
'oidcServiceMetaDataJWKSURI' => 'jwks',
|
||||
'oidcServiceMetaDataRegistrationURI' => 'register',
|
||||
'oidcServiceMetaDataTokenURI' => 'token',
|
||||
'oidcServiceMetaDataUserInfoURI' => 'userinfo',
|
||||
'openIdAuthnLevel' => 1,
|
||||
'openIdExportedVars' => {},
|
||||
'openIdIDPList' => '0;',
|
||||
'openIdSPList' => '0;',
|
||||
'openIdSreg_email' => 'mail',
|
||||
'openIdSreg_fullname' => 'cn',
|
||||
'openIdSreg_nickname' => 'uid',
|
||||
'openIdSreg_timezone' => '_timezone',
|
||||
'pamAuthnLevel' => 2,
|
||||
'pamService' => 'login',
|
||||
'passwordDB' => 'Demo',
|
||||
'passwordResetAllowedRetries' => 3,
|
||||
'port' => -1,
|
||||
'portal' => 'http://auth.example.com/',
|
||||
'portalAntiFrame' => 1,
|
||||
'portalCheckLogins' => 1,
|
||||
'portalDisplayAppslist' => 1,
|
||||
'portalDisplayChangePassword' => '$_auth =~ /^(LDAP|DBI|Demo)$/',
|
||||
'portalDisplayLoginHistory' => 1,
|
||||
'portalDisplayLogout' => 1,
|
||||
'portalDisplayOidcConsents' => '$_oidcConnectedRP',
|
||||
'portalDisplayRegister' => 1,
|
||||
'portalErrorOnExpiredSession' => 1,
|
||||
'portalForceAuthnInterval' => 5,
|
||||
'portalMainLogo' => 'common/logos/logo_llng_400px.png',
|
||||
'portalPingInterval' => 60000,
|
||||
'portalRequireOldPassword' => 1,
|
||||
'portalSkin' => 'bootstrap',
|
||||
'portalUserAttr' => '_user',
|
||||
'proxyAuthnLevel' => 2,
|
||||
'radius2fActivation' => 0,
|
||||
'radius2fTimeout' => 20,
|
||||
'radiusAuthnLevel' => 3,
|
||||
'randomPasswordRegexp' => '[A-Z]{3}[a-z]{5}.\\d{2}',
|
||||
'redirectFormMethod' => 'get',
|
||||
'registerDB' => 'Null',
|
||||
'registerTimeout' => 0,
|
||||
'registerUrl' => 'http://auth.example.com/register',
|
||||
'reloadTimeout' => 5,
|
||||
'remoteGlobalStorage' => 'Lemonldap::NG::Common::Apache::Session::SOAP',
|
||||
'remoteGlobalStorageOptions' => {
|
||||
'ns' =>
|
||||
|
|
|
@ -67,6 +67,6 @@ our $issuerParameters = {
|
|||
issuerDBSAML => [qw(issuerDBSAMLActivation issuerDBSAMLPath issuerDBSAMLRule)],
|
||||
};
|
||||
our $samlServiceParameters = [qw(samlEntityID samlServicePrivateKeySig samlServicePrivateKeySigPwd samlServicePublicKeySig samlServicePrivateKeyEnc samlServicePrivateKeyEncPwd samlServicePublicKeyEnc samlServiceUseCertificateInResponse samlServiceSignatureMethod samlNameIDFormatMapEmail samlNameIDFormatMapX509 samlNameIDFormatMapWindows samlNameIDFormatMapKerberos samlAuthnContextMapPassword samlAuthnContextMapPasswordProtectedTransport samlAuthnContextMapTLSClient samlAuthnContextMapKerberos samlOrganizationDisplayName samlOrganizationName samlOrganizationURL samlSPSSODescriptorAuthnRequestsSigned samlSPSSODescriptorWantAssertionsSigned samlSPSSODescriptorSingleLogoutServiceHTTPRedirect samlSPSSODescriptorSingleLogoutServiceHTTPPost samlSPSSODescriptorSingleLogoutServiceSOAP samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact samlSPSSODescriptorAssertionConsumerServiceHTTPPost samlSPSSODescriptorArtifactResolutionServiceArtifact samlIDPSSODescriptorWantAuthnRequestsSigned samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect samlIDPSSODescriptorSingleSignOnServiceHTTPPost samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect samlIDPSSODescriptorSingleLogoutServiceHTTPPost samlIDPSSODescriptorSingleLogoutServiceSOAP samlIDPSSODescriptorArtifactResolutionServiceArtifact samlAttributeAuthorityDescriptorAttributeServiceSOAP samlIdPResolveCookie samlMetadataForceUTF8 samlStorage samlStorageOptions samlRelayStateTimeout samlUseQueryStringSpecific samlCommonDomainCookieActivation samlCommonDomainCookieDomain samlCommonDomainCookieReader samlCommonDomainCookieWriter samlDiscoveryProtocolActivation samlDiscoveryProtocolURL samlDiscoveryProtocolPolicy samlDiscoveryProtocolIsPassive samlOverrideIDPEntityID)];
|
||||
our $oidcServiceParameters = [qw(oidcServiceMetaDataIssuer oidcServiceMetaDataAuthorizeURI oidcServiceMetaDataTokenURI oidcServiceMetaDataUserInfoURI oidcServiceMetaDataJWKSURI oidcServiceMetaDataRegistrationURI oidcServiceMetaDataEndSessionURI oidcServiceMetaDataCheckSessionURI oidcServiceMetaDataFrontChannelURI oidcServiceMetaDataBackChannelURI oidcServiceMetaDataAuthnContext oidcServicePrivateKeySig oidcServicePublicKeySig oidcServiceKeyIdSig oidcServiceAllowDynamicRegistration oidcServiceAllowAuthorizationCodeFlow oidcServiceAllowImplicitFlow oidcServiceAllowHybridFlow oidcStorage oidcStorageOptions)];
|
||||
our $oidcServiceParameters = [qw(oidcServiceMetaDataIssuer oidcServiceMetaDataAuthorizeURI oidcServiceMetaDataTokenURI oidcServiceMetaDataUserInfoURI oidcServiceMetaDataJWKSURI oidcServiceMetaDataRegistrationURI oidcServiceMetaDataIntrospectionURI oidcServiceMetaDataEndSessionURI oidcServiceMetaDataCheckSessionURI oidcServiceMetaDataFrontChannelURI oidcServiceMetaDataBackChannelURI oidcServiceMetaDataAuthnContext oidcServicePrivateKeySig oidcServicePublicKeySig oidcServiceKeyIdSig oidcServiceAllowDynamicRegistration oidcServiceAllowAuthorizationCodeFlow oidcServiceAllowImplicitFlow oidcServiceAllowHybridFlow oidcStorage oidcStorageOptions)];
|
||||
|
||||
1;
|
||||
|
|
|
@ -2100,6 +2100,10 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
|
|||
'default' => 'flogout',
|
||||
'type' => 'text'
|
||||
},
|
||||
'oidcServiceMetaDataIntrospectionURI' => {
|
||||
'default' => 'introspect',
|
||||
'type' => 'text'
|
||||
},
|
||||
'oidcServiceMetaDataIssuer' => {
|
||||
'type' => 'text'
|
||||
},
|
||||
|
|
|
@ -3467,6 +3467,11 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
|||
default => 'register',
|
||||
documentation => 'OpenID Connect registration endpoint',
|
||||
},
|
||||
oidcServiceMetaDataIntrospectionURI => {
|
||||
type => 'text',
|
||||
default => 'introspect',
|
||||
documentation => 'OpenID Connect introspection endpoint',
|
||||
},
|
||||
oidcServiceMetaDataEndSessionURI => {
|
||||
type => 'text',
|
||||
default => 'logout',
|
||||
|
|
|
@ -499,7 +499,8 @@ sub tree {
|
|||
title => 'logParams',
|
||||
help => 'logs.html',
|
||||
form => 'simpleInputContainer',
|
||||
nodes => [ 'whatToTrace', 'customToTrace', 'hiddenAttributes' ]
|
||||
nodes =>
|
||||
[ 'whatToTrace', 'customToTrace', 'hiddenAttributes' ]
|
||||
},
|
||||
{
|
||||
title => 'cookieParams',
|
||||
|
@ -1113,6 +1114,7 @@ sub tree {
|
|||
'oidcServiceMetaDataUserInfoURI',
|
||||
'oidcServiceMetaDataJWKSURI',
|
||||
'oidcServiceMetaDataRegistrationURI',
|
||||
'oidcServiceMetaDataIntrospectionURI',
|
||||
'oidcServiceMetaDataEndSessionURI',
|
||||
'oidcServiceMetaDataCheckSessionURI',
|
||||
'oidcServiceMetaDataFrontChannelURI',
|
||||
|
|
|
@ -566,6 +566,7 @@
|
|||
"oidcServiceMetaDataJWKSURI":"JWKS",
|
||||
"oidcServiceMetaDataKeys":"المفاتيح",
|
||||
"oidcServiceMetaDataRegistrationURI":"التسجيل",
|
||||
"oidcServiceMetaDataIntrospectionURI":"Introspection",
|
||||
"oidcServiceMetaDataSecurity":"الحماية",
|
||||
"oidcServiceMetaDataEndSessionURI":"نهاية الجلسة",
|
||||
"oidcServiceMetaDataAuthnContext":"سياق إثبات الهوية",
|
||||
|
@ -1046,4 +1047,4 @@
|
|||
"samlRelayStateTimeout":"تناوب حالة مهلة الجلسة ",
|
||||
"samlUseQueryStringSpecific":"استخدام أسلوب query_string المعين",
|
||||
"samlOverrideIDPEntityID":"Override Entity ID when acting as IDP"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -566,6 +566,7 @@
|
|||
"oidcServiceMetaDataJWKSURI":"JWKS",
|
||||
"oidcServiceMetaDataKeys":"Keys",
|
||||
"oidcServiceMetaDataRegistrationURI":"Registration",
|
||||
"oidcServiceMetaDataIntrospectionURI":"Introspection",
|
||||
"oidcServiceMetaDataSecurity":"Security",
|
||||
"oidcServiceMetaDataEndSessionURI":"End of session",
|
||||
"oidcServiceMetaDataAuthnContext":"Authentication context",
|
||||
|
@ -1046,4 +1047,4 @@
|
|||
"samlRelayStateTimeout":"RelayState session timeout",
|
||||
"samlUseQueryStringSpecific":"Use specific query_string method",
|
||||
"samlOverrideIDPEntityID":"Override Entity ID when acting as IDP"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -566,6 +566,7 @@
|
|||
"oidcServiceMetaDataJWKSURI":"JWKS",
|
||||
"oidcServiceMetaDataKeys":"Keys",
|
||||
"oidcServiceMetaDataRegistrationURI":"Registration",
|
||||
"oidcServiceMetaDataIntrospectionURI":"Introspection",
|
||||
"oidcServiceMetaDataSecurity":"Security",
|
||||
"oidcServiceMetaDataEndSessionURI":"End of session",
|
||||
"oidcServiceMetaDataAuthnContext":"Authentication context",
|
||||
|
|
|
@ -566,6 +566,7 @@
|
|||
"oidcServiceMetaDataJWKSURI":"JWKS",
|
||||
"oidcServiceMetaDataKeys":"Clefs",
|
||||
"oidcServiceMetaDataRegistrationURI":"Enregistrement",
|
||||
"oidcServiceMetaDataIntrospectionURI":"Introspection",
|
||||
"oidcServiceMetaDataSecurity":"Sécurité",
|
||||
"oidcServiceMetaDataEndSessionURI":"Fin de session",
|
||||
"oidcServiceMetaDataAuthnContext":"Contexte d'authentification",
|
||||
|
|
|
@ -566,6 +566,7 @@
|
|||
"oidcServiceMetaDataJWKSURI":"JWKS",
|
||||
"oidcServiceMetaDataKeys":"Chiavi",
|
||||
"oidcServiceMetaDataRegistrationURI":"Registrazione",
|
||||
"oidcServiceMetaDataIntrospectionURI":"Introspection",
|
||||
"oidcServiceMetaDataSecurity":"Sicurezza",
|
||||
"oidcServiceMetaDataEndSessionURI":"Fine sessione",
|
||||
"oidcServiceMetaDataAuthnContext":"Contesto di autenticazione",
|
||||
|
@ -1046,4 +1047,4 @@
|
|||
"samlRelayStateTimeout":"Timeout di sessione di RelayState",
|
||||
"samlUseQueryStringSpecific":"Utilizza il metodo specifico query_string",
|
||||
"samlOverrideIDPEntityID":"Sostituisci l'ID entità quando agisce come IDP"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -566,6 +566,7 @@
|
|||
"oidcServiceMetaDataJWKSURI":"JWKS",
|
||||
"oidcServiceMetaDataKeys":"Khóa",
|
||||
"oidcServiceMetaDataRegistrationURI":"Đăng ký",
|
||||
"oidcServiceMetaDataIntrospectionURI":"Introspection",
|
||||
"oidcServiceMetaDataSecurity":"Bảo mật",
|
||||
"oidcServiceMetaDataEndSessionURI":"Kết thúc phiên",
|
||||
"oidcServiceMetaDataAuthnContext":"Ngữ cảnh xác thực",
|
||||
|
@ -1046,4 +1047,4 @@
|
|||
"samlRelayStateTimeout":"Thời gian hết hạn phiên RelayState ",
|
||||
"samlUseQueryStringSpecific":"Sử dụng phương pháp query_string cụ thể",
|
||||
"samlOverrideIDPEntityID":"Override Entity ID when acting as IDP"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -566,6 +566,7 @@
|
|||
"oidcServiceMetaDataJWKSURI":"JWKS",
|
||||
"oidcServiceMetaDataKeys":"键值",
|
||||
"oidcServiceMetaDataRegistrationURI":"Registration",
|
||||
"oidcServiceMetaDataIntrospectionURI":"Introspection",
|
||||
"oidcServiceMetaDataSecurity":"Security",
|
||||
"oidcServiceMetaDataEndSessionURI":"End of session",
|
||||
"oidcServiceMetaDataAuthnContext":"Authentication context",
|
||||
|
@ -1046,4 +1047,4 @@
|
|||
"samlRelayStateTimeout":"RelayState session timeout",
|
||||
"samlUseQueryStringSpecific":"Use specific query_string method",
|
||||
"samlOverrideIDPEntityID":"Override Entity ID when acting as IDP"
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -57,6 +57,7 @@ has iss => (
|
|||
# - userinfo : => userInfo() for unauth users (RP)
|
||||
# - jwks : => jwks() for unauth users (RP)
|
||||
# - register : => registration() for unauth users (RP)
|
||||
# - introspect : => introspection() for unauth users (RP)
|
||||
#
|
||||
# Other paths will be handle by run() and return PE_ERROR
|
||||
#
|
||||
|
@ -86,22 +87,24 @@ sub init {
|
|||
# Manage RP requests
|
||||
$self->addRouteFromConf(
|
||||
'Unauth',
|
||||
oidcServiceMetaDataEndSessionURI => 'endSessionDone',
|
||||
oidcServiceMetaDataCheckSessionURI => 'checkSession',
|
||||
oidcServiceMetaDataTokenURI => 'token',
|
||||
oidcServiceMetaDataUserInfoURI => 'userInfo',
|
||||
oidcServiceMetaDataJWKSURI => 'jwks',
|
||||
oidcServiceMetaDataRegistrationURI => 'registration',
|
||||
oidcServiceMetaDataEndSessionURI => 'endSessionDone',
|
||||
oidcServiceMetaDataCheckSessionURI => 'checkSession',
|
||||
oidcServiceMetaDataTokenURI => 'token',
|
||||
oidcServiceMetaDataUserInfoURI => 'userInfo',
|
||||
oidcServiceMetaDataJWKSURI => 'jwks',
|
||||
oidcServiceMetaDataRegistrationURI => 'registration',
|
||||
oidcServiceMetaDataIntrospectionURI => 'introspection',
|
||||
);
|
||||
|
||||
# Manage user requests
|
||||
$self->addRouteFromConf(
|
||||
'Auth',
|
||||
oidcServiceMetaDataCheckSessionURI => 'checkSession',
|
||||
oidcServiceMetaDataTokenURI => 'badAuthRequest',
|
||||
oidcServiceMetaDataUserInfoURI => 'badAuthRequest',
|
||||
oidcServiceMetaDataJWKSURI => 'badAuthRequest',
|
||||
oidcServiceMetaDataRegistrationURI => 'badAuthRequest',
|
||||
oidcServiceMetaDataCheckSessionURI => 'checkSession',
|
||||
oidcServiceMetaDataTokenURI => 'badAuthRequest',
|
||||
oidcServiceMetaDataUserInfoURI => 'badAuthRequest',
|
||||
oidcServiceMetaDataJWKSURI => 'badAuthRequest',
|
||||
oidcServiceMetaDataRegistrationURI => 'badAuthRequest',
|
||||
oidcServiceMetaDataIntrospectionURI => 'badAuthRequest',
|
||||
);
|
||||
|
||||
# Metadata (.well-known/openid-configuration)
|
||||
|
@ -999,7 +1002,7 @@ sub token {
|
|||
|
||||
my $rp = $self->checkEndPointAuthenticationCredentials($req);
|
||||
|
||||
unless($rp) {
|
||||
unless ($rp) {
|
||||
return $self->p->sendError( $req, 'invalid_request', 400 );
|
||||
}
|
||||
|
||||
|
@ -1153,7 +1156,7 @@ sub token {
|
|||
return $self->p->sendJSONresponse( $req, $token_response );
|
||||
}
|
||||
|
||||
# Handle uerinfo endpoint
|
||||
# Handle userinfo endpoint
|
||||
sub userInfo {
|
||||
my ( $self, $req ) = @_;
|
||||
$self->logger->debug("URL detected as an OpenID Connect USERINFO URL");
|
||||
|
@ -1210,6 +1213,66 @@ sub userInfo {
|
|||
}
|
||||
}
|
||||
|
||||
sub introspection {
|
||||
my ( $self, $req ) = @_;
|
||||
$self->logger->debug("URL detected as an OpenID Connect INTROSPECTION URL");
|
||||
|
||||
my $rp = $self->checkEndPointAuthenticationCredentials($req);
|
||||
|
||||
unless ($rp) {
|
||||
return $self->p->sendError( $req, 'invalid_request', 400 );
|
||||
}
|
||||
|
||||
if ( $self->conf->{oidcRPMetaDataOptions}->{$rp}
|
||||
->{oidcRPMetaDataOptionsPublic} )
|
||||
{
|
||||
$self->logger->error(
|
||||
"Public clients are not allowed to acces the introspection endpoint"
|
||||
);
|
||||
return $self->p->sendError( $req, 'unauthorized_client', 401 );
|
||||
}
|
||||
|
||||
my $token = $req->param('token');
|
||||
unless ($token) {
|
||||
return $self->p->sendError( $req, 'invalid_request', 400 );
|
||||
}
|
||||
|
||||
my $response = { active => JSON::false };
|
||||
my $oidcSession = $self->getOpenIDConnectSession($token);
|
||||
if ($oidcSession) {
|
||||
if ( my $user_session_id = $oidcSession->{data}->{user_session_id} ) {
|
||||
|
||||
# Get user identifier
|
||||
my $apacheSession = $self->p->getApacheSession($user_session_id);
|
||||
if ($apacheSession) {
|
||||
|
||||
$response->{active} = JSON::true;
|
||||
|
||||
# The ID attribute we choose is the one of the calling webservice,
|
||||
# which might be different from the OIDC client the token was issued to.
|
||||
my $user_id_attribute =
|
||||
$self->conf->{oidcRPMetaDataOptions}->{$rp}
|
||||
->{oidcRPMetaDataOptionsUserIDAttr}
|
||||
|| $self->conf->{whatToTrace};
|
||||
$response->{sub} = $apacheSession->data->{$user_id_attribute};
|
||||
$response->{scope} = $oidcSession->{data}->{scope}
|
||||
if $oidcSession->{data}->{scope};
|
||||
$response->{client_id} =
|
||||
$self->oidcRPList->{ $oidcSession->{data}->{rp} }
|
||||
->{oidcRPMetaDataOptionsClientID}
|
||||
if $oidcSession->{data}->{rp};
|
||||
$response->{exp} =
|
||||
$oidcSession->{data}->{_utime} + $self->conf->{timeout};
|
||||
}
|
||||
}
|
||||
else {
|
||||
$self->logger->error(
|
||||
"Could not find user session ID in access token object");
|
||||
}
|
||||
}
|
||||
return $self->p->sendJSONresponse( $req, $response );
|
||||
}
|
||||
|
||||
# Handle jwks endpoint
|
||||
sub jwks {
|
||||
my ( $self, $req ) = @_;
|
||||
|
@ -1448,13 +1511,14 @@ sub logout {
|
|||
sub metadata {
|
||||
my ( $self, $req ) = @_;
|
||||
my $issuerDBOpenIDConnectPath = $self->conf->{issuerDBOpenIDConnectPath};
|
||||
my $authorize_uri = $self->conf->{oidcServiceMetaDataAuthorizeURI};
|
||||
my $token_uri = $self->conf->{oidcServiceMetaDataTokenURI};
|
||||
my $userinfo_uri = $self->conf->{oidcServiceMetaDataUserInfoURI};
|
||||
my $jwks_uri = $self->conf->{oidcServiceMetaDataJWKSURI};
|
||||
my $registration_uri = $self->conf->{oidcServiceMetaDataRegistrationURI};
|
||||
my $endsession_uri = $self->conf->{oidcServiceMetaDataEndSessionURI};
|
||||
my $checksession_uri = $self->conf->{oidcServiceMetaDataCheckSessionURI};
|
||||
my $authorize_uri = $self->conf->{oidcServiceMetaDataAuthorizeURI};
|
||||
my $token_uri = $self->conf->{oidcServiceMetaDataTokenURI};
|
||||
my $userinfo_uri = $self->conf->{oidcServiceMetaDataUserInfoURI};
|
||||
my $jwks_uri = $self->conf->{oidcServiceMetaDataJWKSURI};
|
||||
my $registration_uri = $self->conf->{oidcServiceMetaDataRegistrationURI};
|
||||
my $endsession_uri = $self->conf->{oidcServiceMetaDataEndSessionURI};
|
||||
my $checksession_uri = $self->conf->{oidcServiceMetaDataCheckSessionURI};
|
||||
my $introspection_uri = $self->conf->{oidcServiceMetaDataIntrospectionURI};
|
||||
|
||||
my $path = $self->path . '/';
|
||||
my $issuer = $self->iss;
|
||||
|
@ -1494,6 +1558,7 @@ sub metadata {
|
|||
authorization_endpoint => $baseUrl . $authorize_uri,
|
||||
end_session_endpoint => $baseUrl . $endsession_uri,
|
||||
check_session_iframe => $baseUrl . $checksession_uri,
|
||||
introspection_endpoint => $baseUrl . $introspection_uri,
|
||||
|
||||
# Logout capabilities
|
||||
backchannel_logout_supported => JSON::true,
|
||||
|
@ -1514,6 +1579,8 @@ sub metadata {
|
|||
subject_types_supported => ["public"],
|
||||
token_endpoint_auth_methods_supported =>
|
||||
[qw/client_secret_post client_secret_basic/],
|
||||
introspection_endpoint_auth_methods_supported =>
|
||||
[qw/client_secret_post client_secret_basic/],
|
||||
claims_supported => [qw/sub iss auth_time acr/],
|
||||
request_parameter_supported => JSON::true,
|
||||
request_uri_parameter_supported => JSON::true,
|
||||
|
|
|
@ -728,7 +728,7 @@ sub getOpenIDConnectSession {
|
|||
return undef;
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
if ( $id and $type ) {
|
||||
my $storedType = $oidcSession->{data}->{_type};
|
||||
|
||||
# Only check if a type is set in DB, for backward compatibility
|
||||
|
@ -1112,7 +1112,7 @@ sub returnBearerError {
|
|||
}
|
||||
|
||||
sub checkEndPointAuthenticationCredentials {
|
||||
my ($self, $req, $allow_public) = @_;
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
# Check authentication
|
||||
my ( $client_id, $client_secret ) =
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
html,body{height:100%;background:radial-gradient(circle at 50% 0,#fff 0,#ddd 100%) no-repeat scroll 0 0 #ddd}#wrap{min-height:100%;height:auto;margin:0 auto -80px;padding:20px 0 80px}#footer{height:80px;background-color:#fff;background-color:rgba(255,255,255,0.9);text-align:center;padding-top:10px;overflow:hidden}#header img{background-color:#fff;background-color:rgba(255,255,255,0.8);margin-bottom:20px}.card,.navbar-light{background-color:#fff;background-color:rgba(255,255,255,0.9);background-image:none}.login,.password{text-align:center;padding:20px}div.form{margin:0 auto;max-width:330px}div.actions{margin:10px 0 0 0}div.actions a{margin-top:10px}.buttons{text-align:center;margin:10px 0 0 0;cursor:pointer}.btn{white-space:normal}.btn span.fa{padding-right:8px}li.ui-state-active{background-color:#fafafa;background-color:rgba(250,250,250,0.9)}#appslist,#password,#loginHistory,#logout,#oidcConsents{margin-top:20px}div.category{margin:10px 0;cursor:grab}div.application{margin:5px 0;overflow:hidden}div.application a,div.application a:hover{text-decoration:none}p.notifCheck label{margin-left:5px;margin-top:3px;display:inline-block}img.langicon{cursor:pointer}button.idploop{max-width:300px}button.idploop img{max-height:30px}div.oidc_consent_message>ul{text-align:left;list-style:circle}@media(min-width:768px){div.application{height:80px}div.application h4.appname{margin:0}#wrap{margin:0 auto -60px}#footer{height:60px}}.hiddenFrame{border:0;display:hidden;margin:0}.noborder{border:0}.max{width:100%}.link{cursor:pointer}.nodecor:hover,.nodecor:active.nodecor:focus{text-decoration:none}.fa.icon-blue{color:blue}.progress-bar-animated{width:100%}
|
212
lemonldap-ng-portal/t/32-OIDC-Token-Introspection.t
Normal file
212
lemonldap-ng-portal/t/32-OIDC-Token-Introspection.t
Normal file
|
@ -0,0 +1,212 @@
|
|||
use lib 'inc';
|
||||
use Test::More;
|
||||
use strict;
|
||||
use IO::String;
|
||||
use LWP::UserAgent;
|
||||
use LWP::Protocol::PSGI;
|
||||
use MIME::Base64;
|
||||
use JSON;
|
||||
|
||||
BEGIN {
|
||||
require 't/test-lib.pm';
|
||||
}
|
||||
|
||||
my $debug = 'error';
|
||||
|
||||
# Initialization
|
||||
my $op = LLNG::Manager::Test->new( {
|
||||
ini => {
|
||||
logLevel => $debug,
|
||||
domain => 'idp.com',
|
||||
portal => 'http://auth.op.com',
|
||||
authentication => 'Demo',
|
||||
userDB => 'Same',
|
||||
issuerDBOpenIDConnectActivation => 1,
|
||||
issuerDBOpenIDConnectRule => '$uid eq "french"',
|
||||
oidcRPMetaDataExportedVars => {
|
||||
rp => {
|
||||
email => "mail",
|
||||
family_name => "cn",
|
||||
name => "cn"
|
||||
},
|
||||
rp2 => {
|
||||
email => "mail",
|
||||
family_name => "cn",
|
||||
name => "cn"
|
||||
}
|
||||
},
|
||||
oidcServiceMetaDataIssuer => "http://auth.op.com",
|
||||
oidcServiceMetaDataAuthorizeURI => "authorize",
|
||||
oidcServiceMetaDataCheckSessionURI => "checksession.html",
|
||||
oidcServiceMetaDataJWKSURI => "jwks",
|
||||
oidcServiceMetaDataEndSessionURI => "logout",
|
||||
oidcServiceMetaDataRegistrationURI => "register",
|
||||
oidcServiceMetaDataTokenURI => "token",
|
||||
oidcServiceMetaDataUserInfoURI => "userinfo",
|
||||
oidcServiceAllowHybridFlow => 1,
|
||||
oidcServiceAllowImplicitFlow => 1,
|
||||
oidcServiceAllowDynamicRegistration => 1,
|
||||
oidcServiceAllowAuthorizationCodeFlow => 1,
|
||||
oidcRPMetaDataOptions => {
|
||||
rp => {
|
||||
oidcRPMetaDataOptionsDisplayName => "RP",
|
||||
oidcRPMetaDataOptionsIDTokenExpiration => 3600,
|
||||
oidcRPMetaDataOptionsClientID => "rpid",
|
||||
oidcRPMetaDataOptionsIDTokenSignAlg => "HS512",
|
||||
oidcRPMetaDataOptionsClientSecret => "rpsecret",
|
||||
oidcRPMetaDataOptionsUserIDAttr => "",
|
||||
oidcRPMetaDataOptionsAccessTokenExpiration => 1,
|
||||
oidcRPMetaDataOptionsBypassConsent => 1,
|
||||
},
|
||||
oauth => {
|
||||
oidcRPMetaDataOptionsDisplayName => "oauth",
|
||||
oidcRPMetaDataOptionsClientID => "oauth",
|
||||
oidcRPMetaDataOptionsClientSecret => "service",
|
||||
oidcRPMetaDataOptionsUserIDAttr => "",
|
||||
}
|
||||
},
|
||||
oidcOPMetaDataOptions => {},
|
||||
oidcOPMetaDataJSON => {},
|
||||
oidcOPMetaDataJWKS => {},
|
||||
oidcServiceMetaDataAuthnContext => {
|
||||
'loa-4' => 4,
|
||||
'loa-1' => 1,
|
||||
'loa-5' => 5,
|
||||
'loa-2' => 2,
|
||||
'loa-3' => 3
|
||||
},
|
||||
oidcServicePrivateKeySig => "-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAs2jsmIoFuWzMkilJaA8//5/T30cnuzX9GImXUrFR2k9EKTMt
|
||||
GMHCdKlWOl3BV+BTAU9TLz7Jzd/iJ5GJ6B8TrH1PHFmHpy8/qE/S5OhinIpIi7eb
|
||||
ABqnoVcwDdCa8ugzq8k8SWxhRNXfVIlwz4NH1caJ8lmiERFj7IvNKqEhzAk0pyDr
|
||||
8hubveTC39xREujKlsqutpPAFPJ3f2ybVsdykX5rx0h5SslG3jVWYhZ/SOb2aIzO
|
||||
r0RMjhQmsYRwbpt3anjlBZ98aOzg7GAkbO8093X5VVk9vaPRg0zxJQ0Do0YLyzkR
|
||||
isSAIFb0tdKuDnjRGK6y/N2j6At2HjkxntbtGQIDAQABAoIBADYq6LxJd977LWy3
|
||||
0HT9nboFPIf+SM2qSEc/S5Po+6ipJBA4ZlZCMf7dHa6znet1TDpqA9iQ4YcqIHMH
|
||||
6xZNQ7hhgSAzG9TrXBHqP+djDlrrGWotvjuy0IfS9ixFnnLWjrtAH9afRWLuG+a/
|
||||
NHNC1M6DiiTE0TzL/lpt/zzut3CNmWzH+t19X6UsxUg95AzooEeewEYkv25eumWD
|
||||
mfQZfCtSlIw1sp/QwxeJa/6LJw7KcPZ1wXUm1BN0b9eiKt9Cmni1MS7elgpZlgGt
|
||||
xtfGTZtNLQ7bgDiM8MHzUfPBhbceNSIx2BeCuOCs/7eaqgpyYHBbAbuBQex2H61l
|
||||
Lcc3Tz0CgYEA4Kx/avpCPxnvsJ+nHVQm5d/WERuDxk4vH1DNuCYBvXTdVCGADf6a
|
||||
F5No1JcTH3nPTyPWazOyGdT9LcsEJicLyD8vCM6hBFstG4XjqcAuqG/9DRsElpHQ
|
||||
yi1zc5DNP7Vxmiz9wII0Mjy0abYKtxnXh9YK4a9g6wrcTpvShhIcIb8CgYEAzGzG
|
||||
lorVCfX9jXULIznnR/uuP5aSnTEsn0xJeqTlbW0RFWLdj8aIL1peirh1X89HroB9
|
||||
GeTNqEJXD+3CVL2cx+BRggMDUmEz4hR59meZCDGUyT5fex4LIsceb/ESUl2jo6Sw
|
||||
HXwWbN67rQ55N4oiOcOppsGxzOHkl5HdExKidycCgYEAr5Qev2tz+fw65LzfzHvH
|
||||
Kj4S/KuT/5V6He731cFd+sEpdmX3vPgLVAFPG1Q1DZQT/rTzDDQKK0XX1cGiLG63
|
||||
NnaqOye/jbfzOF8Z277kt51NFMDYhRLPKDD82IOA4xjY/rPKWndmcxwdob8yAIWh
|
||||
efY76sMz6ntCT+xWSZA9i+ECgYBWMZM2TIlxLsBfEbfFfZewOUWKWEGvd9l5vV/K
|
||||
D5cRIYivfMUw5yPq2267jPUolayCvniBH4E7beVpuPVUZ7KgcEvNxtlytbt7muil
|
||||
5Z6X3tf+VodJ0Swe2NhTmNEB26uwxzLe68BE3VFCsbSYn2y48HAq+MawPZr18bHG
|
||||
ZfgMxwKBgHHRg6HYqF5Pegzk1746uH2G+OoCovk5ylGGYzcH2ghWTK4agCHfBcDt
|
||||
EYqYAev/l82wi+OZ5O8U+qjFUpT1CVeUJdDs0o5u19v0UJjunU1cwh9jsxBZAWLy
|
||||
PAGd6SWf4S3uQCTw6dLeMna25YIlPh5qPA6I/pAahe8e3nSu2ckl
|
||||
-----END RSA PRIVATE KEY-----
|
||||
",
|
||||
oidcServicePublicKeySig => "-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2jsmIoFuWzMkilJaA8/
|
||||
/5/T30cnuzX9GImXUrFR2k9EKTMtGMHCdKlWOl3BV+BTAU9TLz7Jzd/iJ5GJ6B8T
|
||||
rH1PHFmHpy8/qE/S5OhinIpIi7ebABqnoVcwDdCa8ugzq8k8SWxhRNXfVIlwz4NH
|
||||
1caJ8lmiERFj7IvNKqEhzAk0pyDr8hubveTC39xREujKlsqutpPAFPJ3f2ybVsdy
|
||||
kX5rx0h5SslG3jVWYhZ/SOb2aIzOr0RMjhQmsYRwbpt3anjlBZ98aOzg7GAkbO80
|
||||
93X5VVk9vaPRg0zxJQ0Do0YLyzkRisSAIFb0tdKuDnjRGK6y/N2j6At2Hjkxntbt
|
||||
GQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
",
|
||||
}
|
||||
}
|
||||
);
|
||||
my $res;
|
||||
|
||||
# Authenticate to LLNG
|
||||
my $url = "/";
|
||||
my $query = "user=french&password=french";
|
||||
ok(
|
||||
$res = $op->_post(
|
||||
"/",
|
||||
IO::String->new($query),
|
||||
accept => 'text/html',
|
||||
length => length($query),
|
||||
),
|
||||
"Post authentication"
|
||||
);
|
||||
my $idpId = expectCookie($res);
|
||||
|
||||
# Get code for RP1
|
||||
my $query =
|
||||
"response_type=code&scope=openid%20profile%20email&client_id=rpid&state=af0ifjsldkj&redirect_uri=http%3A%2F%2Frp2.com%2F";
|
||||
ok(
|
||||
$res = $op->_get(
|
||||
"/oauth2/authorize",
|
||||
query => "$query",
|
||||
accept => 'text/html',
|
||||
cookie => "lemonldap=$idpId",
|
||||
),
|
||||
"Get authorization code"
|
||||
);
|
||||
|
||||
my ($code) = expectRedirection( $res, qr#http://rp2\.com/.*code=([^\&]*)# );
|
||||
|
||||
# Exchange code for AT
|
||||
$query =
|
||||
"grant_type=authorization_code&code=$code&redirect_uri=http%3A%2F%2Frp2.com%2F";
|
||||
|
||||
ok(
|
||||
$res = $op->_post(
|
||||
"/oauth2/token",
|
||||
IO::String->new($query),
|
||||
accept => 'text/html',
|
||||
length => length($query),
|
||||
custom => {
|
||||
HTTP_AUTHORIZATION => "Basic " . encode_base64("rpid:rpsecret"),
|
||||
},
|
||||
),
|
||||
"Post token"
|
||||
);
|
||||
my $json = from_json( $res->[2]->[0] );
|
||||
my $token = $json->{access_token};
|
||||
ok( $token, 'Access token present' );
|
||||
|
||||
my $query = "token=$token";
|
||||
ok(
|
||||
$res = $op->_post(
|
||||
"/oauth2/introspect",
|
||||
IO::String->new($query),
|
||||
accept => 'text/html',
|
||||
length => length $query,
|
||||
custom => {
|
||||
HTTP_AUTHORIZATION => "Basic " . encode_base64("oauth:service"),
|
||||
},
|
||||
),
|
||||
"Post introspection"
|
||||
);
|
||||
|
||||
expectOK($res);
|
||||
my $json = from_json( $res->[2]->[0] );
|
||||
ok( $json->{active}, "Token is valid" );
|
||||
is( $json->{sub}, "french", "Response contains the correct sub" );
|
||||
|
||||
# Check status after expiration
|
||||
sleep(2);
|
||||
|
||||
$query = "token=$token";
|
||||
ok(
|
||||
$res = $op->_post(
|
||||
"/oauth2/introspect",
|
||||
IO::String->new($query),
|
||||
accept => 'text/html',
|
||||
length => length $query,
|
||||
custom => {
|
||||
HTTP_AUTHORIZATION => "Basic " . encode_base64("oauth:service"),
|
||||
},
|
||||
),
|
||||
"Post introspection"
|
||||
);
|
||||
|
||||
expectOK($res);
|
||||
$json = from_json( $res->[2]->[0] );
|
||||
ok( !$json->{active}, "Token is no longer valid" );
|
||||
|
||||
clean_sessions();
|
||||
done_testing();
|
||||
|
Loading…
Reference in New Issue
Block a user