Start of registration endpoint implementation (#184)

This commit is contained in:
Clément Oudot 2015-03-30 15:57:23 +00:00
parent b14ec43a88
commit 2e0f1b7088
5 changed files with 150 additions and 55 deletions

View File

@ -774,6 +774,13 @@ has 'oidcServiceMetaDataJWKSURI' => (
documentation => 'OpenID Connect JWKS endpoint', documentation => 'OpenID Connect JWKS endpoint',
); );
has 'oidcServiceMetaDataRegistrationURI' => (
is => 'rw',
isa => 'Str',
default => 'register',
documentation => 'OpenID Connect registration endpoint',
);
has 'oidcServiceMetaDataTokenURI' => ( has 'oidcServiceMetaDataTokenURI' => (
is => 'rw', is => 'rw',
isa => 'Str', isa => 'Str',

View File

@ -316,9 +316,8 @@ sub cstruct {
%$h, %$h,
oidcRPMetaDataNode => { oidcRPMetaDataNode => {
$k2 => { $k2 => {
_nodes => [ _nodes =>
qw(oidcRPMetaDataExportedVars oidcRPMetaDataOptions) [ qw(oidcRPMetaDataExportedVars oidcRPMetaDataOptions) ],
],
oidcRPMetaDataExportedVars => { oidcRPMetaDataExportedVars => {
_nodes => _nodes =>
["hash:/oidcRPMetaDataExportedVars/$k2:vars:btext"], ["hash:/oidcRPMetaDataExportedVars/$k2:vars:btext"],
@ -328,24 +327,24 @@ sub cstruct {
_nodes => [ _nodes => [
qw(oidcRPMetaDataOptionsAuthentication oidcRPMetaDataOptionsDisplay oidcRPMetaDataOptionsUserIDAttr oidcRPMetaDataOptionsIDTokenSignAlg oidcRPMetaDataOptionsIDTokenExpiration oidcRPMetaDataOptionsAccessTokenExpiration oidcRPMetaDataOptionsRedirectUris) qw(oidcRPMetaDataOptionsAuthentication oidcRPMetaDataOptionsDisplay oidcRPMetaDataOptionsUserIDAttr oidcRPMetaDataOptionsIDTokenSignAlg oidcRPMetaDataOptionsIDTokenExpiration oidcRPMetaDataOptionsAccessTokenExpiration oidcRPMetaDataOptionsRedirectUris)
], ],
oidcRPMetaDataOptionsAuthentication => { oidcRPMetaDataOptionsAuthentication => {
_nodes => [ _nodes => [
qw(oidcRPMetaDataOptionsClientID oidcRPMetaDataOptionsClientSecret) qw(oidcRPMetaDataOptionsClientID oidcRPMetaDataOptionsClientSecret)
], ],
oidcRPMetaDataOptionsClientID => oidcRPMetaDataOptionsClientID =>
"text:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsClientID", "text:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsClientID",
oidcRPMetaDataOptionsClientSecret => oidcRPMetaDataOptionsClientSecret =>
"password:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsClientSecret", "password:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsClientSecret",
}, },
oidcRPMetaDataOptionsDisplay => { oidcRPMetaDataOptionsDisplay => {
_nodes => [ _nodes => [
qw(oidcRPMetaDataOptionsDisplayName oidcRPMetaDataOptionsIcon) qw(oidcRPMetaDataOptionsDisplayName oidcRPMetaDataOptionsIcon)
], ],
oidcRPMetaDataOptionsDisplayName => oidcRPMetaDataOptionsDisplayName =>
"text:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsDisplayName", "text:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsDisplayName",
oidcRPMetaDataOptionsIcon => oidcRPMetaDataOptionsIcon =>
"text:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsIcon", "text:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsIcon",
}, },
oidcRPMetaDataOptionsUserIDAttr => oidcRPMetaDataOptionsUserIDAttr =>
"text:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsUserIDAttr", "text:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsUserIDAttr",
oidcRPMetaDataOptionsIDTokenSignAlg => oidcRPMetaDataOptionsIDTokenSignAlg =>
@ -1601,7 +1600,7 @@ sub struct {
oidcServiceMetaDataEndPoints => { oidcServiceMetaDataEndPoints => {
_nodes => [ _nodes => [
qw(oidcServiceMetaDataAuthorizeURI oidcServiceMetaDataTokenURI oidcServiceMetaDataUserInfoURI oidcServiceMetaDataJWKSURI) qw(oidcServiceMetaDataAuthorizeURI oidcServiceMetaDataTokenURI oidcServiceMetaDataUserInfoURI oidcServiceMetaDataJWKSURI oidcServiceMetaDataRegistrationURI)
], ],
oidcServiceMetaDataAuthorizeURI => oidcServiceMetaDataAuthorizeURI =>
@ -1612,6 +1611,8 @@ sub struct {
'text:/oidcServiceMetaDataUserInfoURI', 'text:/oidcServiceMetaDataUserInfoURI',
oidcServiceMetaDataJWKSURI => oidcServiceMetaDataJWKSURI =>
'text:/oidcServiceMetaDataJWKSURI', 'text:/oidcServiceMetaDataJWKSURI',
oidcServiceMetaDataRegistrationURI =>
'text:/oidcServiceMetaDataRegistrationURI',
}, },
oidcServiceMetaDataSecurity => { oidcServiceMetaDataSecurity => {

View File

@ -306,6 +306,7 @@ sub en {
oidcServiceMetaDataEndPoints => 'End points', oidcServiceMetaDataEndPoints => 'End points',
oidcServiceMetaDataIssuer => 'Issuer identifier', oidcServiceMetaDataIssuer => 'Issuer identifier',
oidcServiceMetaDataJWKSURI => 'JWKS', oidcServiceMetaDataJWKSURI => 'JWKS',
oidcServiceMetaDataRegistrationURI => 'Registration',
oidcServiceMetaDataSecurity => 'Security', oidcServiceMetaDataSecurity => 'Security',
oidcServiceMetaDataTokenURI => 'Token', oidcServiceMetaDataTokenURI => 'Token',
oidcServiceMetaDataUserInfoURI => 'User Info', oidcServiceMetaDataUserInfoURI => 'User Info',
@ -864,41 +865,42 @@ sub fr {
"Expiration des jetons d'identité", "Expiration des jetons d'identité",
oidcRPMetaDataOptionsIDTokenSignAlg => oidcRPMetaDataOptionsIDTokenSignAlg =>
"Algorithme de signature des jetons d'identité", "Algorithme de signature des jetons d'identité",
oidcRPMetaDataOptionsRedirectUris => 'Adresses de redirection', oidcRPMetaDataOptionsRedirectUris => 'Adresses de redirection',
oidcRPMetaDataOptionsUserIDAttr => "Attribut de l'identifiant", oidcRPMetaDataOptionsUserIDAttr => "Attribut de l'identifiant",
oidcRPStateTimeout => 'Durée d\'une session state', oidcRPStateTimeout => 'Durée d\'une session state',
oidcServiceMetaData => "Service OpenID Connect", oidcServiceMetaData => "Service OpenID Connect",
oidcServiceMetaDataAuthorizeURI => "Autorisation", oidcServiceMetaDataAuthorizeURI => "Autorisation",
oidcServiceMetaDataEndPoints => "Points d'accès", oidcServiceMetaDataEndPoints => "Points d'accès",
oidcServiceMetaDataIssuer => "Identifiant du fournisseur", oidcServiceMetaDataIssuer => "Identifiant du fournisseur",
oidcServiceMetaDataJWKSURI => 'JWKS', oidcServiceMetaDataJWKSURI => 'JWKS',
oidcServiceMetaDataSecurity => 'Sécurité', oidcServiceMetaDataRegistrationURI => 'Enregistrement',
oidcServiceMetaDataTokenURI => "Jeton", oidcServiceMetaDataSecurity => 'Sécurité',
oidcServiceMetaDataUserInfoURI => 'Informations Utilisateur', oidcServiceMetaDataTokenURI => "Jeton",
oidcServicePrivateKeySig => 'Clé privée de signature', oidcServiceMetaDataUserInfoURI => 'Informations Utilisateur',
oidcServicePublicKeySig => 'Clé publique de signature', oidcServicePrivateKeySig => 'Clé privée de signature',
openIdAttr => 'Identifiant OpenID', oidcServicePublicKeySig => 'Clé publique de signature',
openIdAuthnLevel => 'Niveau d\'authentification', openIdAttr => 'Identifiant OpenID',
openIdExportedVars => 'Variables exportées', openIdAuthnLevel => 'Niveau d\'authentification',
openIdIDPList => 'Domaines autorisés', openIdExportedVars => 'Variables exportées',
openIdIssuerSecret => 'Jeton secret', openIdIDPList => 'Domaines autorisés',
openIdParams => 'Paramètres OpenID', openIdIssuerSecret => 'Jeton secret',
openIdSecret => 'Jeton secret', openIdParams => 'Paramètres OpenID',
openIdSreg => 'Associations SREG', openIdSecret => 'Jeton secret',
openIdSreg_fullname => 'Nom complet', openIdSreg => 'Associations SREG',
openIdSreg_nickname => 'Surnom', openIdSreg_fullname => 'Nom complet',
openIdSreg_language => 'Langage', openIdSreg_nickname => 'Surnom',
openIdSreg_postcode => 'Code postal', openIdSreg_language => 'Langage',
openIdSreg_timezone => 'Zone horaire', openIdSreg_postcode => 'Code postal',
openIdSreg_country => 'Pays', openIdSreg_timezone => 'Zone horaire',
openIdSreg_gender => 'Genre', openIdSreg_country => 'Pays',
openIdSreg_email => 'Email', openIdSreg_gender => 'Genre',
openIdSreg_dob => 'Date de naissance', openIdSreg_email => 'Email',
openIdSPList => 'Domaines autorisés', openIdSreg_dob => 'Date de naissance',
passwordDB => 'Module de mot de passe', openIdSPList => 'Domaines autorisés',
passwordManagement => 'Gestion des mots de passe', passwordDB => 'Module de mot de passe',
persistentSessions => 'Sessions persistantes', passwordManagement => 'Gestion des mots de passe',
persistentStorage => 'Module Apache::Session', persistentSessions => 'Sessions persistantes',
persistentStorage => 'Module Apache::Session',
persistentStorageOptions => 'Paramètres du module Apache::Session', persistentStorageOptions => 'Paramètres du module Apache::Session',
port => 'Port', port => 'Port',
portal => 'URL', portal => 'URL',

View File

@ -11,6 +11,7 @@ my $authorize_uri = $portal->{oidcServiceMetaDataAuthorizeURI};
my $token_uri = $portal->{oidcServiceMetaDataTokenURI}; my $token_uri = $portal->{oidcServiceMetaDataTokenURI};
my $userinfo_uri = $portal->{oidcServiceMetaDataUserInfoURI}; my $userinfo_uri = $portal->{oidcServiceMetaDataUserInfoURI};
my $jwks_uri = $portal->{oidcServiceMetaDataJWKSURI}; my $jwks_uri = $portal->{oidcServiceMetaDataJWKSURI};
my $registration_uri = $portal->{oidcServiceMetaDataRegistrationURI};
my ($path) = ( $issuerDBOpenIDConnectPath =~ /(\w+)/ ); my ($path) = ( $issuerDBOpenIDConnectPath =~ /(\w+)/ );
my $issuer = $portal->{oidcServiceMetaDataIssuer}; my $issuer = $portal->{oidcServiceMetaDataIssuer};
@ -23,8 +24,8 @@ $configuration->{authorization_endpoint} =
$configuration->{token_endpoint} = $issuer . $path . "/" . $token_uri; $configuration->{token_endpoint} = $issuer . $path . "/" . $token_uri;
$configuration->{userinfo_endpoint} = $issuer . $path . "/" . $userinfo_uri; $configuration->{userinfo_endpoint} = $issuer . $path . "/" . $userinfo_uri;
$configuration->{jwks_uri} = $issuer . $path . "/" . $jwks_uri; $configuration->{jwks_uri} = $issuer . $path . "/" . $jwks_uri;
$configuration->{registration_endpoint} =
# RECOMMENDED # $configuration->{registration_endpoint} $issuer . $path . "/" . $registration_uri;
$configuration->{scopes_supported} = [qw/openid profile email address phone/]; $configuration->{scopes_supported} = [qw/openid profile email address phone/];
$configuration->{response_types_supported} = [ $configuration->{response_types_supported} = [
"code", "code",

View File

@ -7,6 +7,7 @@ package Lemonldap::NG::Portal::IssuerDBOpenIDConnect;
use strict; use strict;
use Lemonldap::NG::Portal::Simple; use Lemonldap::NG::Portal::Simple;
use String::Random qw(random_string);
use base qw(Lemonldap::NG::Portal::_OpenIDConnect); use base qw(Lemonldap::NG::Portal::_OpenIDConnect);
our $VERSION = '2.00'; our $VERSION = '2.00';
@ -34,6 +35,7 @@ sub issuerForUnAuthUser {
my $token_uri = $self->{oidcServiceMetaDataTokenURI}; my $token_uri = $self->{oidcServiceMetaDataTokenURI};
my $userinfo_uri = $self->{oidcServiceMetaDataUserInfoURI}; my $userinfo_uri = $self->{oidcServiceMetaDataUserInfoURI};
my $jwks_uri = $self->{oidcServiceMetaDataJWKSURI}; my $jwks_uri = $self->{oidcServiceMetaDataJWKSURI};
my $registration_uri = $self->{oidcServiceMetaDataRegistrationURI};
my $issuer = $self->{oidcServiceMetaDataIssuer}; my $issuer = $self->{oidcServiceMetaDataIssuer};
# Called URL # Called URL
@ -356,6 +358,71 @@ sub issuerForUnAuthUser {
} }
# REGISTRATION
if ( $url_path =~ m#${issuerDBOpenIDConnectPath}${registration_uri}# ) {
$self->lmLog( "URL $url detected as an OpenID Connect REGISTRATION URL",
'debug' );
# TODO: check Initial Access Token
# Specific message to allow DOS detection
my $source_ip = $self->ipAddr;
$self->lmLog( "OpenID Connect Registration request from $source_ip",
'warn' );
# Get client metadata
my $client_metadata_json = $self->param('POSTDATA');
$self->lmLog( "Client metadata received: $client_metadata_json",
'debug' );
my $client_metadata = $self->decodeJSON($client_metadata_json);
my $registration_response = {};
# Check redirect_uris
unless ( $client_metadata->{redirect_uris} ) {
$self->lmLog( "Field redirect_uris is mandatory", 'error' );
$self->returnJSONError( 'invalid_client_metadata',
'Field redirect_uris is mandatory' );
$self->quit;
}
# RP identifier
my $registration_time = time;
my $rp = "register-$registration_time";
# Generate Client ID and Client Password
my $client_id = random_string("...............");
my $client_secret = random_string("...............");
# Register known parameters
my $client_name =
$client_metadata->{client_name} || "Self registered client";
my $logo_uri = $client_metadata->{logo_uri};
my $id_token_signed_response_alg =
$client_metadata->{id_token_signed_response_alg} || "RS256";
# TODO: register RP in global configuration
# Send registration response
$registration_response->{'client_id'} = $client_id;
$registration_response->{'client_secret'} = $client_secret;
$registration_response->{'client_id_issued_at'} = $registration_time;
$registration_response->{'client_id_expires_at'} = 0;
$registration_response->{'client_name'} = $client_name;
$registration_response->{'logo_uri'} = $logo_uri;
$registration_response->{'id_token_signed_response_alg'} =
$id_token_signed_response_alg;
# TODO: return 201 HTTP code
$self->returnJSON($registration_response);
$self->lmLog( "Registration response sent", 'debug' );
$self->quit;
}
PE_OK; PE_OK;
} }
@ -371,6 +438,7 @@ sub issuerForAuthUser {
my $token_uri = $self->{issuerDBOpenIDConnectTokenURI}; my $token_uri = $self->{issuerDBOpenIDConnectTokenURI};
my $userinfo_uri = $self->{issuerDBOpenIDConnectUserInfoURI}; my $userinfo_uri = $self->{issuerDBOpenIDConnectUserInfoURI};
my $jwks_uri = $self->{oidcServiceMetaDataJWKSURI}; my $jwks_uri = $self->{oidcServiceMetaDataJWKSURI};
my $registration_uri = $self->{oidcServiceMetaDataRegistrationURI};
my $issuer = $self->{oidcServiceMetaDataIssuer}; my $issuer = $self->{oidcServiceMetaDataIssuer};
# Session ID # Session ID
@ -989,6 +1057,22 @@ sub issuerForAuthUser {
$self->quit; $self->quit;
} }
# REGISTRATION
if ( $url_path =~ m#${issuerDBOpenIDConnectPath}${registration_uri}# ) {
$self->lmLog( "URL $url detected as an OpenID Connect REGISTRATION URL",
'debug' );
# This should not happen
$self->lmLog(
"Registration request found on an active SSO session, ignoring it",
'error'
);
$self->returnJSONError("invalid_request");
$self->quit;
}
PE_OK; PE_OK;
} }