diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/Serializer.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/Serializer.pm index 7a653150b..b498682f1 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/Serializer.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/Serializer.pm @@ -126,6 +126,8 @@ sub unserialize { |oidcOPMetaDataJSON |oidcOPMetaDataJWKS |oidcOPMetaDataOptions + |oidcRPMetaDataExportedVars + |oidcRPMetaDataOptions |openIdExportedVars |persistentStorageOptions |portalSkinRules diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/SubAttributes.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/SubAttributes.pm index 91ed5817c..14f6759a7 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/SubAttributes.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/SubAttributes.pm @@ -100,6 +100,27 @@ has 'oidcOPMetaDataOptionsTokenEndpointAuthMethod' => ( documentation => "OIDC OP scope", ); +has 'oidcRPMetaDataExportedVars' => ( + is => 'rw', + isa => 'HashRef', + default => sub { return { 'sub' => 'uid' }; }, + documentation => "Exported vars for a RP", +); + +has 'oidcRPMetaDataOptionsClientID' => ( + is => 'rw', + isa => 'Str|Undef', + default => undef, + documentation => "OIDC RP client ID", +); + +has 'oidcRPMetaDataOptionsClientSecret' => ( + is => 'rw', + isa => 'Str|Undef', + default => undef, + documentation => "OIDC RP client Secret", +); + ## P has 'post' => ( diff --git a/lemonldap-ng-manager/example/skins/default/js/manager.js b/lemonldap-ng-manager/example/skins/default/js/manager.js index 4c531b8a2..bbc26f138 100644 --- a/lemonldap-ng-manager/example/skins/default/js/manager.js +++ b/lemonldap-ng-manager/example/skins/default/js/manager.js @@ -465,6 +465,7 @@ function display(div, title) { $('#newpostr,#delpost').hide(); $('#newpostdatar,#delpostdata').hide(); $('#newoidcopb,#deloidcopb').hide(); + $('#newoidcrpb,#deloidcrpb').hide(); // Resize (or hide) Help window resizeHelp(); } @@ -497,6 +498,11 @@ function oidcOPRoot(id) { display('default', ''); $('#newoidcopb').show(); } +function oidcRPRoot(id) { + currentId = id; + display('default', ''); + $('#newoidcrpb').show(); +} /* @function splitModuleAndOptions(string data) * Split module and options from authentication or userDB string * @return module, options @@ -847,6 +853,17 @@ function oidcOPMetaData(id) { } $('#newoidcopb').show(); } +function oidcRPMetaData(id) { + currentId = id; + $('#oidcRPMetaData').val(lmtext(id)); + display('oidcRPMetaData', lmtext(id)); + if ($('#li_' + myB64('/oidcRPMetaDataNode')).find('span').size() == 1) { + $('#deloidcrpb').hide(); + } else { + $('#deloidcrpb').show(); + } + $('#newoidcrpb').show(); +} function samlService(id) { currentId = id; var t = lmdata(id).split(';'); @@ -1123,6 +1140,24 @@ function delOidcOp(id) { oidcOPMetaData(id); } } +function newOidcRp() { + var name = prompt(text4newOidcRp, 'rp-example'); + if (!name) { + return false; + } + var rpId = 'li_' + myB64('/oidcRPMetaDataExportedVars/' + name); + simpleTreeCollection[0].newAjaxNodeIn($('#li_L29pZGNSUE1ldGFEYXRhTm9kZQ2'), rpId, name, scriptname + '?type=new&node=/oidcRPMetaDataNode/' + name, function(d, s) { + $('>span', s).attr('name', name).attr('help', 'default').attr('id', 'text_' + rpId).attr('onclick', 'oidcRPMetaData(\'' + rpId + '\')'); + oidcRPMetaData(rpId); + }); +} +function delOidcRp(id) { + var rpname = lmtext(id); + if (confirm('Delete ' + rpname + ' ?')) { + delKey(id); + oidcRPMetaData(id); + } +} var cfgAttrDone = 0; function uploadConf(f) { if (! (f == 1)) f = 0; diff --git a/lemonldap-ng-manager/example/skins/default/manager.tpl b/lemonldap-ng-manager/example/skins/default/manager.tpl index 1cf9dd1ef..708992913 100644 --- a/lemonldap-ng-manager/example/skins/default/manager.tpl +++ b/lemonldap-ng-manager/example/skins/default/manager.tpl @@ -53,6 +53,7 @@ var text4newCondition=''; var lang=''; var text4newOidcOp=''; + var text4newOidcRp=''; //]]> @@ -266,6 +267,16 @@ + + + + diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Uploader.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Uploader.pm index 5daf1e67f..8c7d458a9 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Uploader.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Uploader.pm @@ -43,6 +43,7 @@ sub confUpload { my $catid; my $postname; my $opname; + my $rpname; # 1. ANALYSE DATAS @@ -117,6 +118,12 @@ s/^text_(NewID_)?li_([\w\/\+\=]+)(\d)(?:_\d+)?$/decode_base64($2.'='x $3)/e; $opname = $name; } + # Get OIDC RP name + if ( $id =~ /oidcRPMetaDataExportedVars\/([^\/]*)?$/ ) { + $self->lmLog( "Entering RP $name", 'debug' ); + $rpname = $name; + } + # Set menu category and application flags if ( $id =~ /applicationList/ ) { if ( $value =~ /^(.*)?\|(.*)?\|(.*)?\|(.*)?\|(.*?)$/ ) { @@ -139,7 +146,7 @@ s/^text_(NewID_)?li_([\w\/\+\=]+)(\d)(?:_\d+)?$/decode_base64($2.'='x $3)/e; # Special case: avoid bug with node created from parent node if ( $id =~ -/^(virtualHosts|samlIDPMetaDataNode|samlSPMetaDataNode|oidcOPMetaDataNode|generalParameters\/authParams\/choiceParams)/ +/^(virtualHosts|samlIDPMetaDataNode|samlSPMetaDataNode|oidcOPMetaDataNode|oidcRPMetaDataNode|generalParameters\/authParams\/choiceParams)/ ) { $self->lmLog( "Special trigger for $id (attribute $name)", @@ -168,6 +175,10 @@ s/^samlSPMetaDataNode\/([^\/]*)?.*/samlSPMetaDataExportedAttributes\/$1\/$name/; $id =~ s/^oidcOPMetaDataNode\/([^\/]*)?.*/oidcOPMetaDataExportedVars\/$1\/$name/; + # OIDC RP attribute + $id =~ +s/^oidcRPMetaDataNode\/([^\/]*)?.*/oidcRPMetaDataExportedVars\/$1\/$name/; + # Authentication choice $id =~ s/^generalParameters\/authParams\/choiceParams\/([^\/]*)?.*/authChoiceModules\/$name/; @@ -213,13 +224,17 @@ s/^(samlSPMetaDataXML|samlSPMetaDataExportedAttributes|samlSPMetaDataOptions)\/( $id =~ s/^(oidcOPMetaDataJSON|oidcOPMetaDataJWKS|oidcOPMetaDataExportedVars|oidcOPMetaDataOptions)\/([^\/]*)?\/(.*)$/$1\/$opname\/$3/; + # Set current OIDC RP name + $id =~ +s/^(oidcRPMetaDataExportedVars|oidcRPMetaDataOptions)\/([^\/]*)?\/(.*)$/$1\/$rpname\/$3/; + # Set current POST URL name $id =~ s/^(post)\/([^\/]*)?\/(.*)$/$1\/$vhostname\/$postname/; $self->lmLog( "id transformed into $id", 'debug' ); if ( $id =~ -/^(generalParameters|variables|virtualHosts|samlIDPMetaDataNode|samlSPMetaDataNode|oidcOPMetaDataNode)/ +/^(generalParameters|variables|virtualHosts|samlIDPMetaDataNode|samlSPMetaDataNode|oidcOPMetaDataNode|oidcRPMetaDataNode)/ ) { $self->lmLog( "Ignoring attribute $name (id $id)", 'debug' ); diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_Struct.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_Struct.pm index ee249460b..3a1dc0a17 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_Struct.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_Struct.pm @@ -311,6 +311,31 @@ sub cstruct { }, ); } + elsif ( $k1 =~ /^oidcRPMetaDataNode/i ) { + %$h = ( + %$h, + oidcRPMetaDataNode => { + $k2 => { + _nodes => + [qw(oidcRPMetaDataExportedVars oidcRPMetaDataOptions)], + oidcRPMetaDataExportedVars => { + _nodes => + ["hash:/oidcRPMetaDataExportedVars/$k2:vars:btext"], + _js => 'hashRoot', + }, + oidcRPMetaDataOptions => { + _nodes => [ + qw(oidcRPMetaDataOptionsClientID oidcRPMetaDataOptionsClientSecret) + ], + oidcRPMetaDataOptionsClientID => +"text:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsClientID", + oidcRPMetaDataOptionsClientSecret => +"password:/oidcRPMetaDataOptions/$k2/oidcRPMetaDataOptionsClientSecret", + }, + }, + }, + ); + } return $h; } @@ -322,7 +347,7 @@ sub struct { my $self = shift; return { _nodes => [ - qw(n:generalParameters n:variables n:virtualHosts n:samlServiceMetaData n:samlIDPMetaDataNode n:samlSPMetaDataNode n:oidcServiceMetaData n:oidcOPMetaDataNode) + qw(n:generalParameters n:variables n:virtualHosts n:samlServiceMetaData n:samlIDPMetaDataNode n:samlSPMetaDataNode n:oidcServiceMetaData n:oidcOPMetaDataNode n:oidcRPMetaDataNode) ], _help => 'default', @@ -1573,6 +1598,15 @@ sub struct { _js => 'oidcOPRoot', }, + oidcRPMetaDataNode => { + _nodes => [ +'nhash:/oidcRPMetaDataExportedVars:oidcRPMetaDataNode:oidcRPMetaData' + ], + _upload => ['/oidcRPMetaDataOptions'], + _help => 'oidcRP', + _js => 'oidcRPRoot', + }, + }; } @@ -2327,6 +2361,25 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?: }, }, + # OIDC RP + oidcRPMetaDataExportedVars => { + keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/, + keyMsgFail => 'Bad metadata name', + '*' => { + keyTest => qr/^\w([\w\-]*\w)?$/, + keyMsgFail => 'Bad attribute name', + test => sub { return 1; }, + }, + }, + oidcRPMetaDataOptions => { + keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/, + keyMsgFail => 'Bad metadata name', + '*' => { + test => sub { return 1; }, + keyTest => sub { return 1; }, + }, + }, + }; } ## @method hashref subDefaultConf() diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_i18n.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_i18n.pm index fcebc4bdf..84f1faf32 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_i18n.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_i18n.pm @@ -284,77 +284,82 @@ sub en { oidcOPMetaDataOptionsScope => 'Scope', oidcOPMetaDataOptionsTokenEndpointAuthMethod => 'Token endpoint authentication method', - oidcParams => 'OpenID Connect parameters', - oidcRPCallbackGetParam => 'Callback GET parameter', - oidcRPStateTimeout => 'State session timeout', - oidcServiceMetaData => 'OpenID Connect Service', - oidcServiceMetaDataAuthorizeURI => 'Autorization', - oidcServiceMetaDataEndPoints => 'End points', - oidcServiceMetaDataIssuer => 'Issuer identifier', - oidcServiceMetaDataTokenURI => 'Token', - openIdAttr => 'OpenID login', - openIdAuthnLevel => 'Authentication level', - openIdExportedVars => 'Exported variables', - openIdIDPList => 'Authorizated domains', - openIdIssuerSecret => 'Secret token', - openIdParams => 'OpenID parameters', - openIdSecret => 'Secret token', - openIdSreg => 'SREG mapping', - openIdSreg_fullname => 'Full name', - openIdSreg_nickname => 'Nick name', - openIdSreg_language => 'Language', - openIdSreg_postcode => 'Postal code', - openIdSreg_timezone => 'Timezone', - openIdSreg_country => 'Country', - openIdSreg_gender => 'Gender', - openIdSreg_email => 'Email', - openIdSreg_dob => 'Date of birth', - openIdSPList => 'Authorizated domains', - passwordDB => 'Password module', - passwordManagement => 'Password management', - persistentSessions => 'Persistent sessions', - persistentStorage => 'Apache::Session module', - persistentStorageOptions => 'Apache::Session module parameters', - port => 'Port', - portal => 'URL', - portalAntiFrame => 'Anti frame protection', - portalAutocomplete => 'Auto complete', - portalButtons => 'Buttons on login page', - portalCaptcha => 'Captcha', - portalCheckLogins => 'Check last logins', - portalCustomization => 'Customization', - portalDisplayAppslist => 'Applications list', - portalDisplayChangePassword => 'Password change', - portalDisplayLoginHistory => 'Login History', - portalDisplayLogout => 'Logout', - portalDisplayRegister => 'Register new account', - portalDisplayResetPassword => 'Reset password', - portalForceAuthn => 'Force authentication', - portalMenu => 'Menu', - portalModules => 'Modules activation', - portalOpenLinkInNewWindow => 'New window', - portalOther => 'Other', - portalParams => 'Portal', - portalPingInterval => 'Ping Interval', - portalRedirection => 'Portal redirections', - portalRequireOldPassword => 'Require old password', - portalSkin => 'Default Skin', - portalSkinBackground => 'Background image', - portalSkinRules => 'Skin display rules', - portalUserAttr => 'User attribute', - post => 'Form replay', - proxyParams => 'Proxy parameters', - purgeNotification => 'Delete notification definitely', - radiusAuthnLevel => 'Authentication level', - radiusParams => 'Radius parameters', - radiusSecret => 'Shared secret', - radiusServer => 'Server hostname', - randomPasswordRegexp => 'Regexp for password generation', - redirection => 'Handler redirections', - register => 'Register new account', - registerConfirmSubject => 'Subject for confirmation mail', - registerDB => 'Module', - registerDoneSubject => 'Subject for done mail', + oidcParams => 'OpenID Connect parameters', + oidcRPCallbackGetParam => 'Callback GET parameter', + oidcRPMetaDataExportedVars => 'Exported attributes', + oidcRPMetaDataNode => 'OpenID Connect Relaying Parties', + oidcRPMetaDataOptions => 'Options', + oidcRPMetaDataOptionsClientID => 'Client ID', + oidcRPMetaDataOptionsClientSecret => 'Client secret', + oidcRPStateTimeout => 'State session timeout', + oidcServiceMetaData => 'OpenID Connect Service', + oidcServiceMetaDataAuthorizeURI => 'Autorization', + oidcServiceMetaDataEndPoints => 'End points', + oidcServiceMetaDataIssuer => 'Issuer identifier', + oidcServiceMetaDataTokenURI => 'Token', + openIdAttr => 'OpenID login', + openIdAuthnLevel => 'Authentication level', + openIdExportedVars => 'Exported variables', + openIdIDPList => 'Authorizated domains', + openIdIssuerSecret => 'Secret token', + openIdParams => 'OpenID parameters', + openIdSecret => 'Secret token', + openIdSreg => 'SREG mapping', + openIdSreg_fullname => 'Full name', + openIdSreg_nickname => 'Nick name', + openIdSreg_language => 'Language', + openIdSreg_postcode => 'Postal code', + openIdSreg_timezone => 'Timezone', + openIdSreg_country => 'Country', + openIdSreg_gender => 'Gender', + openIdSreg_email => 'Email', + openIdSreg_dob => 'Date of birth', + openIdSPList => 'Authorizated domains', + passwordDB => 'Password module', + passwordManagement => 'Password management', + persistentSessions => 'Persistent sessions', + persistentStorage => 'Apache::Session module', + persistentStorageOptions => 'Apache::Session module parameters', + port => 'Port', + portal => 'URL', + portalAntiFrame => 'Anti frame protection', + portalAutocomplete => 'Auto complete', + portalButtons => 'Buttons on login page', + portalCaptcha => 'Captcha', + portalCheckLogins => 'Check last logins', + portalCustomization => 'Customization', + portalDisplayAppslist => 'Applications list', + portalDisplayChangePassword => 'Password change', + portalDisplayLoginHistory => 'Login History', + portalDisplayLogout => 'Logout', + portalDisplayRegister => 'Register new account', + portalDisplayResetPassword => 'Reset password', + portalForceAuthn => 'Force authentication', + portalMenu => 'Menu', + portalModules => 'Modules activation', + portalOpenLinkInNewWindow => 'New window', + portalOther => 'Other', + portalParams => 'Portal', + portalPingInterval => 'Ping Interval', + portalRedirection => 'Portal redirections', + portalRequireOldPassword => 'Require old password', + portalSkin => 'Default Skin', + portalSkinBackground => 'Background image', + portalSkinRules => 'Skin display rules', + portalUserAttr => 'User attribute', + post => 'Form replay', + proxyParams => 'Proxy parameters', + purgeNotification => 'Delete notification definitely', + radiusAuthnLevel => 'Authentication level', + radiusParams => 'Radius parameters', + radiusSecret => 'Shared secret', + radiusServer => 'Server hostname', + randomPasswordRegexp => 'Regexp for password generation', + redirection => 'Handler redirections', + register => 'Register new account', + registerConfirmSubject => 'Subject for confirmation mail', + registerDB => 'Module', + registerDoneSubject => 'Subject for done mail', registerTimeout => 'Validity time of a register request', registerUrl => 'Page URL', reloadUrls => 'Configuration reload', @@ -828,36 +833,41 @@ sub fr { oidcOPMetaDataOptionsScope => 'Étendue', oidcOPMetaDataOptionsTokenEndpointAuthMethod => 'Méthode d\'authentification pour l\'accès aux jetons', - oidcParams => 'Paramètres OpenID Connect', - oidcRPCallbackGetParam => 'Paramètre GET callback', - oidcRPStateTimeout => 'Durée d\'une session state', - oidcServiceMetaData => "Service OpenID Connect", - oidcServiceMetaDataAuthorizeURI => "Autorisation", - oidcServiceMetaDataEndPoints => "Points d'accès", - oidcServiceMetaDataIssuer => "Identifiant du fournisseur", - oidcServiceMetaDataTokenURI => "Jeton", - openIdAttr => 'Identifiant OpenID', - openIdAuthnLevel => 'Niveau d\'authentification', - openIdExportedVars => 'Variables exportées', - openIdIDPList => 'Domaines autorisés', - openIdIssuerSecret => 'Jeton secret', - openIdParams => 'Paramètres OpenID', - openIdSecret => 'Jeton secret', - openIdSreg => 'Associations SREG', - openIdSreg_fullname => 'Nom complet', - openIdSreg_nickname => 'Surnom', - openIdSreg_language => 'Langage', - openIdSreg_postcode => 'Code postal', - openIdSreg_timezone => 'Zone horaire', - openIdSreg_country => 'Pays', - openIdSreg_gender => 'Genre', - openIdSreg_email => 'Email', - openIdSreg_dob => 'Date de naissance', - openIdSPList => 'Domaines autorisés', - passwordDB => 'Module de mot de passe', - passwordManagement => 'Gestion des mots de passe', - persistentSessions => 'Sessions persistantes', - persistentStorage => 'Module Apache::Session', + oidcParams => 'Paramètres OpenID Connect', + oidcRPCallbackGetParam => 'Paramètre GET callback', + oidcRPMetaDataExportedVars => 'Attributs exportés', + oidcRPMetaDataNode => 'Relais OpenID Connect', + oidcRPMetaDataOptions => 'Options', + oidcRPMetaDataOptionsClientID => 'Identifiant', + oidcRPMetaDataOptionsClientSecret => 'Mot de passe', + oidcRPStateTimeout => 'Durée d\'une session state', + oidcServiceMetaData => "Service OpenID Connect", + oidcServiceMetaDataAuthorizeURI => "Autorisation", + oidcServiceMetaDataEndPoints => "Points d'accès", + oidcServiceMetaDataIssuer => "Identifiant du fournisseur", + oidcServiceMetaDataTokenURI => "Jeton", + openIdAttr => 'Identifiant OpenID', + openIdAuthnLevel => 'Niveau d\'authentification', + openIdExportedVars => 'Variables exportées', + openIdIDPList => 'Domaines autorisés', + openIdIssuerSecret => 'Jeton secret', + openIdParams => 'Paramètres OpenID', + openIdSecret => 'Jeton secret', + openIdSreg => 'Associations SREG', + openIdSreg_fullname => 'Nom complet', + openIdSreg_nickname => 'Surnom', + openIdSreg_language => 'Langage', + openIdSreg_postcode => 'Code postal', + openIdSreg_timezone => 'Zone horaire', + openIdSreg_country => 'Pays', + openIdSreg_gender => 'Genre', + openIdSreg_email => 'Email', + openIdSreg_dob => 'Date de naissance', + openIdSPList => 'Domaines autorisés', + passwordDB => 'Module de mot de passe', + passwordManagement => 'Gestion des mots de passe', + persistentSessions => 'Sessions persistantes', + persistentStorage => 'Module Apache::Session', persistentStorageOptions => 'Paramètres du module Apache::Session', port => 'Port', portal => 'URL',