diff --git a/debian/control b/debian/control index af9c7cfa8..43915d7d2 100644 --- a/debian/control +++ b/debian/control @@ -270,6 +270,7 @@ Depends: ${misc:Depends}, Recommends: libcrypt-openssl-bignum-perl, libconvert-base32-perl, libemail-sender-perl (>=1.300027) | libemail-sender-transport-smtps-perl, + libio-string-perl, libipc-run-perl, libgd-securityimage-perl, libmime-tools-perl, diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/Constants.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/Constants.pm index 8491340bd..9362915df 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/Constants.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/Constants.pm @@ -24,7 +24,7 @@ use constant MANAGERSECTION => "manager"; use constant SESSIONSEXPLORERSECTION => "sessionsExplorer"; use constant APPLYSECTION => "apply"; our $hashParameters = qr/^(?:(?:l(?:o(?:ca(?:lSessionStorageOption|tionRule)|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|(?:(?:d(?:emo|bi)|facebook|webID)ExportedVa|exported(?:Heade|Va)|issuerDBGetParamete)r|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|macro)s|o(?:idc(?:RPMetaData(?:(?:Option(?:sExtraClaim)?|ExportedVar)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node)|S(?:erviceMetaDataAuthnContext|torageOptions))|penIdExportedVars)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars)|c(?:as(?:S(?:rvMetaData(?:(?:ExportedVar|Option)s|Node)|torageOptions)|A(?:ppMetaData(?:(?:ExportedVar|Option)s|Node)|ttributes))|(?:ustomAddParam|ombModule)s)|p(?:ersistentStorageOptions|o(?:rtalSkinRules|st))|a(?:ut(?:hChoiceMod|oSigninR)ules|pplicationList)|v(?:hostOptions|irtualHost)|S(?:MTPTLSOpts|SLVarIf))$/; -our $boolKeys = qr/^(?:s(?:aml(?:IDP(?:MetaDataOptions(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|IsPassiv)e|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Force(?:Authn|UTF8)|StoreSAMLToken|RelayStateURL)|SSODescriptorWantAuthnRequestsSigned)|S(?:P(?:MetaDataOptions(?:(?:CheckS[LS]OMessageSignatur|OneTimeUs)e|EnableIDPInitiatedURL|ForceUTF8)|SSODescriptor(?:WantAssertion|AuthnRequest)sSigned)|erviceUseCertificateInResponse)|DiscoveryProtocol(?:Activation|IsPassive)|CommonDomainCookieActivation|UseQueryStringSpecific|MetadataForceUTF8)|ingle(?:Session(?:UserByIP)?|(?:UserBy)?IP)|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|kipRenewConfirmation|howLanguages|slByAjax)|o(?:idc(?:ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken)|RPMetaDataOptions(?:LogoutSessionRequired|BypassConsent))|ldNotifFormat)|p(?:ortal(?:ErrorOn(?:ExpiredSession|MailNotFound)|DisplayRe(?:setPassword|gister)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|RequireOldPassword|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl)|oginHistoryEnabled)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:User(?:Display(?:PersistentInfo|EmptyValues))?|State|XSS)|da)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonation(?:SkipEmptyValue|MergeSSOgroup)s)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|no(?:tif(?:ication(?:Server)?|y(?:Deleted|Other))|AjaxHook)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|(?:(?:rest(?:Session|Config)|wsdl)Serv|activeTim)er|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|krb(?:RemoveDomain|ByJs)|dbiDynamicHashEnabled|bruteForceProtection)$/; +our $boolKeys = qr/^(?:s(?:aml(?:IDP(?:MetaDataOptions(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|IsPassiv)e|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Force(?:Authn|UTF8)|StoreSAMLToken|RelayStateURL)|SSODescriptorWantAuthnRequestsSigned)|S(?:P(?:MetaDataOptions(?:(?:CheckS[LS]OMessageSignatur|OneTimeUs)e|EnableIDPInitiatedURL|ForceUTF8)|SSODescriptor(?:WantAssertion|AuthnRequest)sSigned)|erviceUseCertificateInResponse)|DiscoveryProtocol(?:Activation|IsPassive)|CommonDomainCookieActivation|UseQueryStringSpecific|MetadataForceUTF8)|ingle(?:Session(?:UserByIP)?|(?:UserBy)?IP)|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|kipRenewConfirmation|howLanguages|slByAjax)|o(?:idc(?:ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|RPMetaDataOptions(?:LogoutSessionRequired|BypassConsent|RequirePKCE|Public)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:ErrorOn(?:ExpiredSession|MailNotFound)|DisplayRe(?:setPassword|gister)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|RequireOldPassword|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl)|oginHistoryEnabled)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:User(?:Display(?:PersistentInfo|EmptyValues))?|State|XSS)|da)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonation(?:SkipEmptyValue|MergeSSOgroup)s)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|no(?:tif(?:ication(?:Server)?|y(?:Deleted|Other))|AjaxHook)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|(?:(?:rest(?:Session|Config)|wsdl)Serv|activeTim)er|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|krb(?:RemoveDomain|ByJs)|dbiDynamicHashEnabled|bruteForceProtection)$/; our @sessionTypes = ( 'remoteGlobal', 'global', 'localSession', 'persistent', 'saml', 'oidc', 'cas' ); 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 6de45d452..2a681321a 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/ReConstants.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/ReConstants.pm @@ -24,10 +24,10 @@ our $specialNodeHash = { our $doubleHashKeys = 'issuerDBGetParameters'; our $simpleHashKeys = '(?:(?:l(?:o(?:calSessionStorageOption|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|c(?:as(?:StorageOption|Attribute)|ustomAddParam|ombModule)|(?:(?:d(?:emo|bi)|facebook|webID)E|e)xportedVar|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|p(?:ersistentStorageOption|ortalSkinRule)|macro)s|o(?:idcS(?:erviceMetaDataAuthnContext|torageOptions)|penIdExportedVars)|s(?:(?:amlStorageOption|laveExportedVar)s|essionDataToRemember)|a(?:ut(?:hChoiceMod|oSigninR)ules|pplicationList)|S(?:MTPTLSOpts|SLVarIf))'; our $specialNodeKeys = '(?:(?:(?:saml(?:ID|S)|oidc[OR])P|cas(?:App|Srv))MetaDataNode|virtualHost)s'; -our $casAppMetaDataNodeKeys = 'casAppMetaData(?:Options(?:Servic|Rul)e|ExportedVars)'; +our $casAppMetaDataNodeKeys = 'casAppMetaData(?:Options(?:UserAttribut|Servic|Rul)e|ExportedVars)'; our $casSrvMetaDataNodeKeys = 'casSrvMetaData(?:Options(?:ProxiedServices|DisplayName|SortNumber|Gateway|Renew|Icon|Url)|ExportedVars)'; our $oidcOPMetaDataNodeKeys = 'oidcOPMetaData(?:Options(?:C(?:lient(?:Secret|ID)|heckJWTSignature|onfigurationURI)|S(?:toreIDToken|ortNumber|cope)|TokenEndpointAuthMethod|(?:JWKSTimeou|Promp)t|I(?:DTokenMaxAge|con)|U(?:iLocales|seNonce)|Display(?:Name)?|AcrValues|MaxAge)|ExportedVars|J(?:SON|WKS))'; -our $oidcRPMetaDataNodeKeys = 'oidcRPMetaData(?:Options(?:(?:PostLogoutRedirectUri|ExtraClaim)s|I(?:DToken(?:Expiration|SignAlg)|con)|Logout(?:SessionRequired|Type|Url)|AccessTokenExpiration|R(?:edirectUris|ule)|Client(?:Secret|ID)|BypassConsent|DisplayName|UserIDAttr)|ExportedVars)'; +our $oidcRPMetaDataNodeKeys = 'oidcRPMetaData(?:Options(?:I(?:DToken(?:Expiration|SignAlg)|con)|Logout(?:SessionRequired|Type|Url)|R(?:e(?:directUris|quirePKCE)|ule)|P(?:ostLogoutRedirectUris|ublic)|AccessTokenExpiration|Client(?:Secret|ID)|BypassConsent|DisplayName|ExtraClaims|UserIDAttr)|ExportedVars)'; our $samlIDPMetaDataNodeKeys = 'samlIDPMetaData(?:Options(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|EncryptionMod|UserAttribut|DisplayNam)e|S(?:ignS[LS]OMessage|toreSAMLToken|[LS]OBinding|ortNumber)|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Re(?:questedAuthnContext|solutionRule|layStateURL)|Force(?:Authn|UTF8)|I(?:sPassive|con)|NameIDFormat)|ExportedAttributes|XML)'; our $samlSPMetaDataNodeKeys = 'samlSPMetaData(?:Options(?:N(?:ameID(?:SessionKey|Format)|otOnOrAfterTimeout)|S(?:essionNotOnOrAfterTimeout|ignS[LS]OMessage)|(?:CheckS[LS]OMessageSignatur|OneTimeUs|Rul)e|En(?:ableIDPInitiatedURL|cryptionMode)|ForceUTF8)|ExportedAttributes|XML)'; our $virtualHostKeys = '(?:vhost(?:A(?:uthnLevel|liases)|(?:Maintenanc|Typ)e|Https|Port)|(?:exportedHeader|locationRule)s|post)'; diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm index 6295b3097..3c8fa7781 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm @@ -678,6 +678,9 @@ sub attributes { 'casAppMetaDataOptionsService' => { 'type' => 'url' }, + 'casAppMetaDataOptionsUserAttribute' => { + 'type' => 'text' + }, 'casAttr' => { 'type' => 'text' }, @@ -1998,9 +2001,17 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][ 'oidcRPMetaDataOptionsPostLogoutRedirectUris' => { 'type' => 'text' }, + 'oidcRPMetaDataOptionsPublic' => { + 'default' => 0, + 'type' => 'bool' + }, 'oidcRPMetaDataOptionsRedirectUris' => { 'type' => 'text' }, + 'oidcRPMetaDataOptionsRequirePKCE' => { + 'default' => 0, + 'type' => 'bool' + }, 'oidcRPMetaDataOptionsRule' => { 'test' => sub { my ( $val, $conf ) = @_; 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 2eb8a260f..f46602b47 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm @@ -1824,6 +1824,10 @@ sub attributes { type => 'url', documentation => 'CAS App service', }, + casAppMetaDataOptionsUserAttribute => { + type => 'text', + documentation => 'CAS User attribute', + }, casAppMetaDataOptionsRule => { type => 'text', test => $perlExpr, @@ -3349,11 +3353,6 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?: oidcOPMetaDataOptionsIcon => { type => 'text', }, oidcOPMetaDataOptionsStoreIDToken => { type => 'bool', default => 0 }, oidcOPMetaDataOptionsSortNumber => { type => 'int', }, - oidcRPMetaDataOptionsRule => { - type => 'text', - test => $perlExpr, - documentation => 'Rule to grant access to this SP', - }, # OpenID Connect relying parties oidcRPMetaDataExportedVars => { @@ -3413,6 +3412,21 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?: default => 0, documentation => 'Session required for logout', }, + oidcRPMetaDataOptionsPublic => { + type => 'bool', + default => 0, + documentation => 'Declare this RP as public client', + }, + oidcRPMetaDataOptionsRequirePKCE => { + type => 'bool', + default => 0, + documentation => 'Require PKCE', + }, + oidcRPMetaDataOptionsRule => { + type => 'text', + test => $perlExpr, + documentation => 'Rule to grant access to this RP', + }, }; } diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/CTrees.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/CTrees.pm index bf3e30d50..dca65be4d 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/CTrees.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/CTrees.pm @@ -194,7 +194,9 @@ sub cTrees { form => 'simpleInputContainer', nodes => [ 'oidcRPMetaDataOptionsClientID', - 'oidcRPMetaDataOptionsClientSecret' + 'oidcRPMetaDataOptionsClientSecret', + 'oidcRPMetaDataOptionsPublic', + 'oidcRPMetaDataOptionsRequirePKCE', ] }, 'oidcRPMetaDataOptionsUserIDAttr', @@ -252,6 +254,7 @@ sub cTrees { form => 'simpleInputContainer', nodes => [ 'casAppMetaDataOptionsService', + 'casAppMetaDataOptionsUserAttribute', 'casAppMetaDataOptionsRule' ] }, diff --git a/lemonldap-ng-manager/site/htdocs/static/js/conftree.js b/lemonldap-ng-manager/site/htdocs/static/js/conftree.js index 4d73753c4..1133785c4 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/conftree.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/conftree.js @@ -17,6 +17,11 @@ function templates(tpl,key) { "id" : tpl+"s/"+key+"/"+"casAppMetaDataOptionsService", "title" : "casAppMetaDataOptionsService" }, + { + "get" : tpl+"s/"+key+"/"+"casAppMetaDataOptionsUserAttribute", + "id" : tpl+"s/"+key+"/"+"casAppMetaDataOptionsUserAttribute", + "title" : "casAppMetaDataOptionsUserAttribute" + }, { "get" : tpl+"s/"+key+"/"+"casAppMetaDataOptionsRule", "id" : tpl+"s/"+key+"/"+"casAppMetaDataOptionsRule", @@ -405,6 +410,20 @@ function templates(tpl,key) { "id" : tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsClientSecret", "title" : "oidcRPMetaDataOptionsClientSecret", "type" : "password" + }, + { + "default" : 0, + "get" : tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsPublic", + "id" : tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsPublic", + "title" : "oidcRPMetaDataOptionsPublic", + "type" : "bool" + }, + { + "default" : 0, + "get" : tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRequirePKCE", + "id" : tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRequirePKCE", + "title" : "oidcRPMetaDataOptionsRequirePKCE", + "type" : "bool" } ], "id" : "oidcRPMetaDataOptionsAuthentication", diff --git a/lemonldap-ng-manager/site/htdocs/static/js/conftree.min.js b/lemonldap-ng-manager/site/htdocs/static/js/conftree.min.js index ab14da7d9..e2ff88479 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/conftree.min.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/conftree.min.js @@ -1 +1 @@ -function templates(tpl,key){var ind;var scalarTemplate=function(r){return{id:tpl+"s/"+ind++,title:r,get:tpl+"s/"+key+"/"+r}};switch(tpl){case"casAppMetaDataNode":return[{_nodes:[{get:tpl+"s/"+key+"/"+"casAppMetaDataOptionsService",id:tpl+"s/"+key+"/"+"casAppMetaDataOptionsService",title:"casAppMetaDataOptionsService"},{get:tpl+"s/"+key+"/"+"casAppMetaDataOptionsRule",id:tpl+"s/"+key+"/"+"casAppMetaDataOptionsRule",title:"casAppMetaDataOptionsRule"}],id:"casAppMetaDataOptions",title:"casAppMetaDataOptions",type:"simpleInputContainer"},{cnodes:tpl+"s/"+key+"/"+"casAppMetaDataExportedVars",default:[{data:"cn",id:tpl+"s/"+key+"/"+"casAppMetaDataExportedVars/cn",title:"cn",type:"keyText"},{data:"mail",id:tpl+"s/"+key+"/"+"casAppMetaDataExportedVars/mail",title:"mail",type:"keyText"},{data:"uid",id:tpl+"s/"+key+"/"+"casAppMetaDataExportedVars/uid",title:"uid",type:"keyText"}],id:tpl+"s/"+key+"/"+"casAppMetaDataExportedVars",title:"casAppMetaDataExportedVars",type:"keyTextContainer"}];case"casSrvMetaDataNode":return[{cnodes:tpl+"s/"+key+"/"+"casSrvMetaDataExportedVars",default:[{data:"cn",id:tpl+"s/"+key+"/"+"casSrvMetaDataExportedVars/cn",title:"cn",type:"keyText"},{data:"mail",id:tpl+"s/"+key+"/"+"casSrvMetaDataExportedVars/mail",title:"mail",type:"keyText"},{data:"uid",id:tpl+"s/"+key+"/"+"casSrvMetaDataExportedVars/uid",title:"uid",type:"keyText"}],id:tpl+"s/"+key+"/"+"casSrvMetaDataExportedVars",title:"casSrvMetaDataExportedVars",type:"keyTextContainer"},{cnodes:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsProxiedServices",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsProxiedServices",title:"casSrvMetaDataOptionsProxiedServices",type:"keyTextContainer"},{_nodes:[{get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsUrl",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsUrl",title:"casSrvMetaDataOptionsUrl"},{default:0,get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsRenew",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsRenew",title:"casSrvMetaDataOptionsRenew",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsGateway",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsGateway",title:"casSrvMetaDataOptionsGateway",type:"bool"}],id:"casSrvMetaDataOptions",title:"casSrvMetaDataOptions",type:"simpleInputContainer"},{_nodes:[{get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsDisplayName",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsDisplayName",title:"casSrvMetaDataOptionsDisplayName"},{get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsIcon",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsIcon",title:"casSrvMetaDataOptionsIcon"},{get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsSortNumber",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsSortNumber",title:"casSrvMetaDataOptionsSortNumber",type:"int"}],id:"casSrvMetaDataOptionsDisplay",title:"casSrvMetaDataOptionsDisplay",type:"simpleInputContainer"}];case"oidcOPMetaDataNode":return[{get:tpl+"s/"+key+"/"+"oidcOPMetaDataJSON",id:tpl+"s/"+key+"/"+"oidcOPMetaDataJSON",title:"oidcOPMetaDataJSON",type:"file"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataJWKS",id:tpl+"s/"+key+"/"+"oidcOPMetaDataJWKS",title:"oidcOPMetaDataJWKS",type:"file"},{cnodes:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars",default:[{data:"name",id:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars/cn",title:"cn",type:"keyText"},{data:"email",id:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars/mail",title:"mail",type:"keyText"},{data:"family_name",id:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars/sn",title:"sn",type:"keyText"},{data:"sub",id:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars/uid",title:"uid",type:"keyText"}],id:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars",title:"oidcOPMetaDataExportedVars",type:"keyTextContainer"},{_nodes:[{_nodes:[{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsConfigurationURI",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsConfigurationURI",title:"oidcOPMetaDataOptionsConfigurationURI"},{default:0,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsJWKSTimeout",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsJWKSTimeout",title:"oidcOPMetaDataOptionsJWKSTimeout",type:"int"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsClientID",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsClientID",title:"oidcOPMetaDataOptionsClientID"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsClientSecret",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsClientSecret",title:"oidcOPMetaDataOptionsClientSecret",type:"password"},{default:0,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsStoreIDToken",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsStoreIDToken",title:"oidcOPMetaDataOptionsStoreIDToken",type:"bool"}],id:"oidcOPMetaDataOptionsConfiguration",title:"oidcOPMetaDataOptionsConfiguration",type:"simpleInputContainer"},{_nodes:[{default:"openid profile",get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsScope",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsScope",title:"oidcOPMetaDataOptionsScope"},{default:"",get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsDisplay",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsDisplay",select:[{k:"",v:""},{k:"page",v:"page"},{k:"popup",v:"popup"},{k:"touch",v:"touch"},{k:"wap",v:"wap"}],title:"oidcOPMetaDataOptionsDisplay",type:"select"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsPrompt",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsPrompt",title:"oidcOPMetaDataOptionsPrompt"},{default:0,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsMaxAge",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsMaxAge",title:"oidcOPMetaDataOptionsMaxAge",type:"int"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsUiLocales",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsUiLocales",title:"oidcOPMetaDataOptionsUiLocales"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsAcrValues",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsAcrValues",title:"oidcOPMetaDataOptionsAcrValues"},{default:"client_secret_post",get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsTokenEndpointAuthMethod",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsTokenEndpointAuthMethod",select:[{k:"client_secret_post",v:"client_secret_post"},{k:"client_secret_basic",v:"client_secret_basic"}],title:"oidcOPMetaDataOptionsTokenEndpointAuthMethod",type:"select"},{default:1,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsCheckJWTSignature",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsCheckJWTSignature",title:"oidcOPMetaDataOptionsCheckJWTSignature",type:"bool"},{default:30,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsIDTokenMaxAge",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsIDTokenMaxAge",title:"oidcOPMetaDataOptionsIDTokenMaxAge",type:"int"},{default:1,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsUseNonce",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsUseNonce",title:"oidcOPMetaDataOptionsUseNonce",type:"bool"}],id:"oidcOPMetaDataOptionsProtocol",title:"oidcOPMetaDataOptionsProtocol",type:"simpleInputContainer"}],id:"oidcOPMetaDataOptions",title:"oidcOPMetaDataOptions"},{_nodes:[{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsDisplayName",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsDisplayName",title:"oidcOPMetaDataOptionsDisplayName"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsIcon",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsIcon",title:"oidcOPMetaDataOptionsIcon"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsSortNumber",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsSortNumber",title:"oidcOPMetaDataOptionsSortNumber",type:"int"}],id:"oidcOPMetaDataOptionsDisplayParams",title:"oidcOPMetaDataOptionsDisplayParams",type:"simpleInputContainer"}];case"oidcRPMetaDataNode":return[{cnodes:tpl+"s/"+key+"/"+"oidcRPMetaDataExportedVars",default:[{data:"mail",id:tpl+"s/"+key+"/"+"oidcRPMetaDataExportedVars/email",title:"email",type:"keyText"},{data:"sn",id:tpl+"s/"+key+"/"+"oidcRPMetaDataExportedVars/family_name",title:"family_name",type:"keyText"},{data:"cn",id:tpl+"s/"+key+"/"+"oidcRPMetaDataExportedVars/name",title:"name",type:"keyText"}],id:tpl+"s/"+key+"/"+"oidcRPMetaDataExportedVars",title:"oidcRPMetaDataExportedVars",type:"keyTextContainer"},{cnodes:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsExtraClaims",default:[],id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsExtraClaims",title:"oidcRPMetaDataOptionsExtraClaims",type:"keyTextContainer"},{_nodes:[{_nodes:[{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsClientID",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsClientID",title:"oidcRPMetaDataOptionsClientID"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsClientSecret",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsClientSecret",title:"oidcRPMetaDataOptionsClientSecret",type:"password"}],id:"oidcRPMetaDataOptionsAuthentication",title:"oidcRPMetaDataOptionsAuthentication",type:"simpleInputContainer"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsUserIDAttr",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsUserIDAttr",title:"oidcRPMetaDataOptionsUserIDAttr"},{default:"HS512",get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIDTokenSignAlg",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIDTokenSignAlg",select:[{k:"none",v:"None"},{k:"HS256",v:"HS256"},{k:"HS384",v:"HS384"},{k:"HS512",v:"HS512"},{k:"RS256",v:"RS256"},{k:"RS384",v:"RS384"},{k:"RS512",v:"RS512"}],title:"oidcRPMetaDataOptionsIDTokenSignAlg",type:"select"},{default:3600,get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIDTokenExpiration",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIDTokenExpiration",title:"oidcRPMetaDataOptionsIDTokenExpiration",type:"int"},{default:3600,get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsAccessTokenExpiration",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsAccessTokenExpiration",title:"oidcRPMetaDataOptionsAccessTokenExpiration",type:"int"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRedirectUris",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRedirectUris",title:"oidcRPMetaDataOptionsRedirectUris"},{default:0,get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsBypassConsent",help:"openidconnectclaims.html",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsBypassConsent",title:"oidcRPMetaDataOptionsBypassConsent",type:"bool"},{_nodes:[{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsPostLogoutRedirectUris",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsPostLogoutRedirectUris",title:"oidcRPMetaDataOptionsPostLogoutRedirectUris"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutUrl",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutUrl",title:"oidcRPMetaDataOptionsLogoutUrl"},{default:"front",get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutType",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutType",select:[{k:"front",v:"Front Channel"},{k:"back",v:"Back Channel"}],title:"oidcRPMetaDataOptionsLogoutType",type:"select"},{default:0,get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutSessionRequired",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutSessionRequired",title:"oidcRPMetaDataOptionsLogoutSessionRequired",type:"bool"}],id:"logout",title:"logout",type:"simpleInputContainer"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRule",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRule",title:"oidcRPMetaDataOptionsRule"}],id:"oidcRPMetaDataOptions",title:"oidcRPMetaDataOptions"},{_nodes:[{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsDisplayName",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsDisplayName",title:"oidcRPMetaDataOptionsDisplayName"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIcon",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIcon",title:"oidcRPMetaDataOptionsIcon"}],id:"oidcRPMetaDataOptionsDisplay",title:"oidcRPMetaDataOptionsDisplay",type:"simpleInputContainer"}];case"samlIDPMetaDataNode":return[{get:tpl+"s/"+key+"/"+"samlIDPMetaDataXML",id:tpl+"s/"+key+"/"+"samlIDPMetaDataXML",title:"samlIDPMetaDataXML",type:"file"},{cnodes:tpl+"s/"+key+"/"+"samlIDPMetaDataExportedAttributes",default:[],help:"authsaml.html#exported_attributes",id:tpl+"s/"+key+"/"+"samlIDPMetaDataExportedAttributes",title:"samlIDPMetaDataExportedAttributes",type:"samlAttributeContainer"},{_nodes:[{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAdaptSessionUtime",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAdaptSessionUtime",title:"samlIDPMetaDataOptionsAdaptSessionUtime",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsForceUTF8",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsForceUTF8",title:"samlIDPMetaDataOptionsForceUTF8",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsStoreSAMLToken",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsStoreSAMLToken",title:"samlIDPMetaDataOptionsStoreSAMLToken",type:"bool"},{get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsUserAttribute",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsUserAttribute",title:"samlIDPMetaDataOptionsUserAttribute"}],id:"samlIDPMetaDataOptionsSession",title:"samlIDPMetaDataOptionsSession",type:"simpleInputContainer"},{_nodes:[{default:-1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSignSSOMessage",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSignSSOMessage",title:"samlIDPMetaDataOptionsSignSSOMessage",type:"trool"},{default:1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckSSOMessageSignature",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckSSOMessageSignature",title:"samlIDPMetaDataOptionsCheckSSOMessageSignature",type:"bool"},{default:-1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSignSLOMessage",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSignSLOMessage",title:"samlIDPMetaDataOptionsSignSLOMessage",type:"trool"},{default:1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckSLOMessageSignature",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckSLOMessageSignature",title:"samlIDPMetaDataOptionsCheckSLOMessageSignature",type:"bool"}],id:"samlIDPMetaDataOptionsSignature",title:"samlIDPMetaDataOptionsSignature",type:"simpleInputContainer"},{_nodes:[{default:"",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSSOBinding",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSSOBinding",select:[{k:"",v:""},{k:"http-post",v:"POST"},{k:"http-redirect",v:"Redirect"},{k:"artifact-get",v:"Artifact GET"}],title:"samlIDPMetaDataOptionsSSOBinding",type:"select"},{default:"",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSLOBinding",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSLOBinding",select:[{k:"",v:""},{k:"http-post",v:"POST"},{k:"http-redirect",v:"Redirect"},{k:"http-soap",v:"SOAP"}],title:"samlIDPMetaDataOptionsSLOBinding",type:"select"}],id:"samlIDPMetaDataOptionsBinding",title:"samlIDPMetaDataOptionsBinding",type:"simpleInputContainer"},{_nodes:[{default:"none",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsEncryptionMode",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsEncryptionMode",select:[{k:"none",v:"None"},{k:"nameid",v:"Name ID"},{k:"assertion",v:"Assertion"}],title:"samlIDPMetaDataOptionsEncryptionMode",type:"select"},{default:1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckTime",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckTime",title:"samlIDPMetaDataOptionsCheckTime",type:"bool"},{default:1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckAudience",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckAudience",title:"samlIDPMetaDataOptionsCheckAudience",type:"bool"}],id:"samlIDPMetaDataOptionsSecurity",title:"samlIDPMetaDataOptionsSecurity",type:"simpleInputContainer"},{_nodes:[{default:"",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsResolutionRule",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsResolutionRule",title:"samlIDPMetaDataOptionsResolutionRule",type:"longtext"},{default:"",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsNameIDFormat",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsNameIDFormat",select:[{k:"",v:""},{k:"unspecified",v:"Unspecified"},{k:"email",v:"Email"},{k:"x509",v:"X509 certificate"},{k:"windows",v:"Windows"},{k:"kerberos",v:"Kerberos"},{k:"entity",v:"Entity"},{k:"persistent",v:"Persistent"},{k:"transient",v:"Transient"},{k:"encrypted",v:"Encrypted"}],title:"samlIDPMetaDataOptionsNameIDFormat",type:"select"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsForceAuthn",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsForceAuthn",title:"samlIDPMetaDataOptionsForceAuthn",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsIsPassive",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsIsPassive",title:"samlIDPMetaDataOptionsIsPassive",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAllowProxiedAuthn",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAllowProxiedAuthn",title:"samlIDPMetaDataOptionsAllowProxiedAuthn",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAllowLoginFromIDP",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAllowLoginFromIDP",title:"samlIDPMetaDataOptionsAllowLoginFromIDP",type:"bool"},{default:"",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsRequestedAuthnContext",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsRequestedAuthnContext",select:[{k:"",v:""},{k:"kerberos",v:"Kerberos"},{k:"password-protected-transport",v:"Password protected transport"},{k:"password",v:"Password"},{k:"tls-client",v:"TLS client certificate"}],title:"samlIDPMetaDataOptionsRequestedAuthnContext",type:"select"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsRelayStateURL",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsRelayStateURL",title:"samlIDPMetaDataOptionsRelayStateURL",type:"bool"}],help:"authsaml.html#options",id:"samlIDPMetaDataOptions",title:"samlIDPMetaDataOptions",type:"simpleInputContainer"},{_nodes:[{get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsDisplayName",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsDisplayName",title:"samlIDPMetaDataOptionsDisplayName"},{get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsIcon",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsIcon",title:"samlIDPMetaDataOptionsIcon"},{get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSortNumber",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSortNumber",title:"samlIDPMetaDataOptionsSortNumber",type:"int"}],id:"samlIDPMetaDataOptionsDisplay",title:"samlIDPMetaDataOptionsDisplay",type:"simpleInputContainer"}];case"samlSPMetaDataNode":return[{get:tpl+"s/"+key+"/"+"samlSPMetaDataXML",id:tpl+"s/"+key+"/"+"samlSPMetaDataXML",title:"samlSPMetaDataXML",type:"file"},{cnodes:tpl+"s/"+key+"/"+"samlSPMetaDataExportedAttributes",default:[],help:"idpsaml.html#exported_attributes",id:tpl+"s/"+key+"/"+"samlSPMetaDataExportedAttributes",title:"samlSPMetaDataExportedAttributes",type:"samlAttributeContainer"},{_nodes:[{_nodes:[{default:"",get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNameIDFormat",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNameIDFormat",select:[{k:"",v:""},{k:"unspecified",v:"Unspecified"},{k:"email",v:"Email"},{k:"x509",v:"X509 certificate"},{k:"windows",v:"Windows"},{k:"kerberos",v:"Kerberos"},{k:"entity",v:"Entity"},{k:"persistent",v:"Persistent"},{k:"transient",v:"Transient"},{k:"encrypted",v:"Encrypted"}],title:"samlSPMetaDataOptionsNameIDFormat",type:"select"},{get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNameIDSessionKey",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNameIDSessionKey",title:"samlSPMetaDataOptionsNameIDSessionKey"},{default:0,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsOneTimeUse",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsOneTimeUse",title:"samlSPMetaDataOptionsOneTimeUse",type:"bool"},{default:72e3,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSessionNotOnOrAfterTimeout",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSessionNotOnOrAfterTimeout",title:"samlSPMetaDataOptionsSessionNotOnOrAfterTimeout",type:"int"},{default:72e3,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNotOnOrAfterTimeout",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNotOnOrAfterTimeout",title:"samlSPMetaDataOptionsNotOnOrAfterTimeout",type:"int"},{default:1,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsForceUTF8",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsForceUTF8",title:"samlSPMetaDataOptionsForceUTF8",type:"bool"}],id:"samlSPMetaDataOptionsAuthnResponse",title:"samlSPMetaDataOptionsAuthnResponse",type:"simpleInputContainer"},{_nodes:[{default:-1,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSignSSOMessage",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSignSSOMessage",title:"samlSPMetaDataOptionsSignSSOMessage",type:"trool"},{default:1,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsCheckSSOMessageSignature",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsCheckSSOMessageSignature",title:"samlSPMetaDataOptionsCheckSSOMessageSignature",type:"bool"},{default:-1,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSignSLOMessage",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSignSLOMessage",title:"samlSPMetaDataOptionsSignSLOMessage",type:"trool"},{default:1,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsCheckSLOMessageSignature",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsCheckSLOMessageSignature",title:"samlSPMetaDataOptionsCheckSLOMessageSignature",type:"bool"}],id:"samlSPMetaDataOptionsSignature",title:"samlSPMetaDataOptionsSignature",type:"simpleInputContainer"},{_nodes:[{default:"none",get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsEncryptionMode",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsEncryptionMode",select:[{k:"none",v:"None"},{k:"nameid",v:"Name ID"},{k:"assertion",v:"Assertion"}],title:"samlSPMetaDataOptionsEncryptionMode",type:"select"},{default:0,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsEnableIDPInitiatedURL",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsEnableIDPInitiatedURL",title:"samlSPMetaDataOptionsEnableIDPInitiatedURL",type:"bool"},{get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsRule",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsRule",title:"samlSPMetaDataOptionsRule"}],id:"samlSPMetaDataOptionsSecurity",title:"samlSPMetaDataOptionsSecurity",type:"simpleInputContainer"}],help:"idpsaml.html#options",id:"samlSPMetaDataOptions",title:"samlSPMetaDataOptions"}];case"virtualHost":return[{cnodes:tpl+"s/"+key+"/"+"locationRules",default:[{data:"deny",id:tpl+"s/"+key+"/"+"locationRules/default",re:"default",title:"default",type:"rule"}],help:"writingrulesand_headers.html#rules",id:tpl+"s/"+key+"/"+"locationRules",title:"locationRules",type:"ruleContainer"},{cnodes:tpl+"s/"+key+"/"+"exportedHeaders",help:"writingrulesand_headers.html#headers",id:tpl+"s/"+key+"/"+"exportedHeaders",title:"exportedHeaders",type:"keyTextContainer"},{cnodes:tpl+"s/"+key+"/"+"post",help:"formreplay.html",id:tpl+"s/"+key+"/"+"post",title:"post",type:"postContainer"},{_nodes:[{default:-1,get:tpl+"s/"+key+"/"+"vhostPort",id:tpl+"s/"+key+"/"+"vhostPort",title:"vhostPort",type:"int"},{default:-1,get:tpl+"s/"+key+"/"+"vhostHttps",id:tpl+"s/"+key+"/"+"vhostHttps",title:"vhostHttps",type:"trool"},{default:0,get:tpl+"s/"+key+"/"+"vhostMaintenance",id:tpl+"s/"+key+"/"+"vhostMaintenance",title:"vhostMaintenance",type:"bool"},{get:tpl+"s/"+key+"/"+"vhostAliases",id:tpl+"s/"+key+"/"+"vhostAliases",title:"vhostAliases"},{default:"Main",get:tpl+"s/"+key+"/"+"vhostType",id:tpl+"s/"+key+"/"+"vhostType",select:[{k:"AuthBasic",v:"AuthBasic"},{k:"CDA",v:"CDA"},{k:"DevOps",v:"DevOps"},{k:"DevOpsST",v:"DevOpsST"},{k:"Main",v:"Main"},{k:"OAuth2",v:"OAuth2"},{k:"SecureToken",v:"SecureToken"},{k:"ServiceToken",v:"ServiceToken"},{k:"Zimbra",v:"ZimbraPreAuth"}],title:"vhostType",type:"select"},{get:tpl+"s/"+key+"/"+"vhostAuthnLevel",id:tpl+"s/"+key+"/"+"vhostAuthnLevel",title:"vhostAuthnLevel",type:"int"}],help:"configvhost.html#options",id:"vhostOptions",title:"vhostOptions",type:"simpleInputContainer"}];default:return[]}}function setScopeVars(scope){scope.portal=scope.data[0]._nodes[0]._nodes[0];scope.getKey(scope.portal);scope.domain=scope.data[0]._nodes[4]._nodes[1];scope.getKey(scope.domain)} +function templates(tpl,key){var ind;var scalarTemplate=function(r){return{id:tpl+"s/"+ind++,title:r,get:tpl+"s/"+key+"/"+r}};switch(tpl){case"casAppMetaDataNode":return[{_nodes:[{get:tpl+"s/"+key+"/"+"casAppMetaDataOptionsService",id:tpl+"s/"+key+"/"+"casAppMetaDataOptionsService",title:"casAppMetaDataOptionsService"},{get:tpl+"s/"+key+"/"+"casAppMetaDataOptionsUserAttribute",id:tpl+"s/"+key+"/"+"casAppMetaDataOptionsUserAttribute",title:"casAppMetaDataOptionsUserAttribute"},{get:tpl+"s/"+key+"/"+"casAppMetaDataOptionsRule",id:tpl+"s/"+key+"/"+"casAppMetaDataOptionsRule",title:"casAppMetaDataOptionsRule"}],id:"casAppMetaDataOptions",title:"casAppMetaDataOptions",type:"simpleInputContainer"},{cnodes:tpl+"s/"+key+"/"+"casAppMetaDataExportedVars",default:[{data:"cn",id:tpl+"s/"+key+"/"+"casAppMetaDataExportedVars/cn",title:"cn",type:"keyText"},{data:"mail",id:tpl+"s/"+key+"/"+"casAppMetaDataExportedVars/mail",title:"mail",type:"keyText"},{data:"uid",id:tpl+"s/"+key+"/"+"casAppMetaDataExportedVars/uid",title:"uid",type:"keyText"}],id:tpl+"s/"+key+"/"+"casAppMetaDataExportedVars",title:"casAppMetaDataExportedVars",type:"keyTextContainer"}];case"casSrvMetaDataNode":return[{cnodes:tpl+"s/"+key+"/"+"casSrvMetaDataExportedVars",default:[{data:"cn",id:tpl+"s/"+key+"/"+"casSrvMetaDataExportedVars/cn",title:"cn",type:"keyText"},{data:"mail",id:tpl+"s/"+key+"/"+"casSrvMetaDataExportedVars/mail",title:"mail",type:"keyText"},{data:"uid",id:tpl+"s/"+key+"/"+"casSrvMetaDataExportedVars/uid",title:"uid",type:"keyText"}],id:tpl+"s/"+key+"/"+"casSrvMetaDataExportedVars",title:"casSrvMetaDataExportedVars",type:"keyTextContainer"},{cnodes:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsProxiedServices",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsProxiedServices",title:"casSrvMetaDataOptionsProxiedServices",type:"keyTextContainer"},{_nodes:[{get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsUrl",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsUrl",title:"casSrvMetaDataOptionsUrl"},{default:0,get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsRenew",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsRenew",title:"casSrvMetaDataOptionsRenew",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsGateway",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsGateway",title:"casSrvMetaDataOptionsGateway",type:"bool"}],id:"casSrvMetaDataOptions",title:"casSrvMetaDataOptions",type:"simpleInputContainer"},{_nodes:[{get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsDisplayName",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsDisplayName",title:"casSrvMetaDataOptionsDisplayName"},{get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsIcon",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsIcon",title:"casSrvMetaDataOptionsIcon"},{get:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsSortNumber",id:tpl+"s/"+key+"/"+"casSrvMetaDataOptionsSortNumber",title:"casSrvMetaDataOptionsSortNumber",type:"int"}],id:"casSrvMetaDataOptionsDisplay",title:"casSrvMetaDataOptionsDisplay",type:"simpleInputContainer"}];case"oidcOPMetaDataNode":return[{get:tpl+"s/"+key+"/"+"oidcOPMetaDataJSON",id:tpl+"s/"+key+"/"+"oidcOPMetaDataJSON",title:"oidcOPMetaDataJSON",type:"file"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataJWKS",id:tpl+"s/"+key+"/"+"oidcOPMetaDataJWKS",title:"oidcOPMetaDataJWKS",type:"file"},{cnodes:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars",default:[{data:"name",id:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars/cn",title:"cn",type:"keyText"},{data:"email",id:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars/mail",title:"mail",type:"keyText"},{data:"family_name",id:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars/sn",title:"sn",type:"keyText"},{data:"sub",id:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars/uid",title:"uid",type:"keyText"}],id:tpl+"s/"+key+"/"+"oidcOPMetaDataExportedVars",title:"oidcOPMetaDataExportedVars",type:"keyTextContainer"},{_nodes:[{_nodes:[{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsConfigurationURI",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsConfigurationURI",title:"oidcOPMetaDataOptionsConfigurationURI"},{default:0,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsJWKSTimeout",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsJWKSTimeout",title:"oidcOPMetaDataOptionsJWKSTimeout",type:"int"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsClientID",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsClientID",title:"oidcOPMetaDataOptionsClientID"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsClientSecret",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsClientSecret",title:"oidcOPMetaDataOptionsClientSecret",type:"password"},{default:0,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsStoreIDToken",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsStoreIDToken",title:"oidcOPMetaDataOptionsStoreIDToken",type:"bool"}],id:"oidcOPMetaDataOptionsConfiguration",title:"oidcOPMetaDataOptionsConfiguration",type:"simpleInputContainer"},{_nodes:[{default:"openid profile",get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsScope",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsScope",title:"oidcOPMetaDataOptionsScope"},{default:"",get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsDisplay",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsDisplay",select:[{k:"",v:""},{k:"page",v:"page"},{k:"popup",v:"popup"},{k:"touch",v:"touch"},{k:"wap",v:"wap"}],title:"oidcOPMetaDataOptionsDisplay",type:"select"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsPrompt",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsPrompt",title:"oidcOPMetaDataOptionsPrompt"},{default:0,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsMaxAge",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsMaxAge",title:"oidcOPMetaDataOptionsMaxAge",type:"int"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsUiLocales",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsUiLocales",title:"oidcOPMetaDataOptionsUiLocales"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsAcrValues",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsAcrValues",title:"oidcOPMetaDataOptionsAcrValues"},{default:"client_secret_post",get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsTokenEndpointAuthMethod",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsTokenEndpointAuthMethod",select:[{k:"client_secret_post",v:"client_secret_post"},{k:"client_secret_basic",v:"client_secret_basic"}],title:"oidcOPMetaDataOptionsTokenEndpointAuthMethod",type:"select"},{default:1,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsCheckJWTSignature",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsCheckJWTSignature",title:"oidcOPMetaDataOptionsCheckJWTSignature",type:"bool"},{default:30,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsIDTokenMaxAge",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsIDTokenMaxAge",title:"oidcOPMetaDataOptionsIDTokenMaxAge",type:"int"},{default:1,get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsUseNonce",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsUseNonce",title:"oidcOPMetaDataOptionsUseNonce",type:"bool"}],id:"oidcOPMetaDataOptionsProtocol",title:"oidcOPMetaDataOptionsProtocol",type:"simpleInputContainer"}],id:"oidcOPMetaDataOptions",title:"oidcOPMetaDataOptions"},{_nodes:[{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsDisplayName",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsDisplayName",title:"oidcOPMetaDataOptionsDisplayName"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsIcon",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsIcon",title:"oidcOPMetaDataOptionsIcon"},{get:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsSortNumber",id:tpl+"s/"+key+"/"+"oidcOPMetaDataOptionsSortNumber",title:"oidcOPMetaDataOptionsSortNumber",type:"int"}],id:"oidcOPMetaDataOptionsDisplayParams",title:"oidcOPMetaDataOptionsDisplayParams",type:"simpleInputContainer"}];case"oidcRPMetaDataNode":return[{cnodes:tpl+"s/"+key+"/"+"oidcRPMetaDataExportedVars",default:[{data:"mail",id:tpl+"s/"+key+"/"+"oidcRPMetaDataExportedVars/email",title:"email",type:"keyText"},{data:"sn",id:tpl+"s/"+key+"/"+"oidcRPMetaDataExportedVars/family_name",title:"family_name",type:"keyText"},{data:"cn",id:tpl+"s/"+key+"/"+"oidcRPMetaDataExportedVars/name",title:"name",type:"keyText"}],id:tpl+"s/"+key+"/"+"oidcRPMetaDataExportedVars",title:"oidcRPMetaDataExportedVars",type:"keyTextContainer"},{cnodes:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsExtraClaims",default:[],id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsExtraClaims",title:"oidcRPMetaDataOptionsExtraClaims",type:"keyTextContainer"},{_nodes:[{_nodes:[{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsClientID",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsClientID",title:"oidcRPMetaDataOptionsClientID"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsClientSecret",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsClientSecret",title:"oidcRPMetaDataOptionsClientSecret",type:"password"},{default:0,get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsPublic",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsPublic",title:"oidcRPMetaDataOptionsPublic",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRequirePKCE",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRequirePKCE",title:"oidcRPMetaDataOptionsRequirePKCE",type:"bool"}],id:"oidcRPMetaDataOptionsAuthentication",title:"oidcRPMetaDataOptionsAuthentication",type:"simpleInputContainer"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsUserIDAttr",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsUserIDAttr",title:"oidcRPMetaDataOptionsUserIDAttr"},{default:"HS512",get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIDTokenSignAlg",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIDTokenSignAlg",select:[{k:"none",v:"None"},{k:"HS256",v:"HS256"},{k:"HS384",v:"HS384"},{k:"HS512",v:"HS512"},{k:"RS256",v:"RS256"},{k:"RS384",v:"RS384"},{k:"RS512",v:"RS512"}],title:"oidcRPMetaDataOptionsIDTokenSignAlg",type:"select"},{default:3600,get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIDTokenExpiration",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIDTokenExpiration",title:"oidcRPMetaDataOptionsIDTokenExpiration",type:"int"},{default:3600,get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsAccessTokenExpiration",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsAccessTokenExpiration",title:"oidcRPMetaDataOptionsAccessTokenExpiration",type:"int"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRedirectUris",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRedirectUris",title:"oidcRPMetaDataOptionsRedirectUris"},{default:0,get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsBypassConsent",help:"openidconnectclaims.html",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsBypassConsent",title:"oidcRPMetaDataOptionsBypassConsent",type:"bool"},{_nodes:[{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsPostLogoutRedirectUris",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsPostLogoutRedirectUris",title:"oidcRPMetaDataOptionsPostLogoutRedirectUris"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutUrl",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutUrl",title:"oidcRPMetaDataOptionsLogoutUrl"},{default:"front",get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutType",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutType",select:[{k:"front",v:"Front Channel"},{k:"back",v:"Back Channel"}],title:"oidcRPMetaDataOptionsLogoutType",type:"select"},{default:0,get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutSessionRequired",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsLogoutSessionRequired",title:"oidcRPMetaDataOptionsLogoutSessionRequired",type:"bool"}],id:"logout",title:"logout",type:"simpleInputContainer"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRule",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsRule",title:"oidcRPMetaDataOptionsRule"}],id:"oidcRPMetaDataOptions",title:"oidcRPMetaDataOptions"},{_nodes:[{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsDisplayName",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsDisplayName",title:"oidcRPMetaDataOptionsDisplayName"},{get:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIcon",id:tpl+"s/"+key+"/"+"oidcRPMetaDataOptionsIcon",title:"oidcRPMetaDataOptionsIcon"}],id:"oidcRPMetaDataOptionsDisplay",title:"oidcRPMetaDataOptionsDisplay",type:"simpleInputContainer"}];case"samlIDPMetaDataNode":return[{get:tpl+"s/"+key+"/"+"samlIDPMetaDataXML",id:tpl+"s/"+key+"/"+"samlIDPMetaDataXML",title:"samlIDPMetaDataXML",type:"file"},{cnodes:tpl+"s/"+key+"/"+"samlIDPMetaDataExportedAttributes",default:[],help:"authsaml.html#exported_attributes",id:tpl+"s/"+key+"/"+"samlIDPMetaDataExportedAttributes",title:"samlIDPMetaDataExportedAttributes",type:"samlAttributeContainer"},{_nodes:[{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAdaptSessionUtime",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAdaptSessionUtime",title:"samlIDPMetaDataOptionsAdaptSessionUtime",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsForceUTF8",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsForceUTF8",title:"samlIDPMetaDataOptionsForceUTF8",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsStoreSAMLToken",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsStoreSAMLToken",title:"samlIDPMetaDataOptionsStoreSAMLToken",type:"bool"},{get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsUserAttribute",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsUserAttribute",title:"samlIDPMetaDataOptionsUserAttribute"}],id:"samlIDPMetaDataOptionsSession",title:"samlIDPMetaDataOptionsSession",type:"simpleInputContainer"},{_nodes:[{default:-1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSignSSOMessage",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSignSSOMessage",title:"samlIDPMetaDataOptionsSignSSOMessage",type:"trool"},{default:1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckSSOMessageSignature",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckSSOMessageSignature",title:"samlIDPMetaDataOptionsCheckSSOMessageSignature",type:"bool"},{default:-1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSignSLOMessage",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSignSLOMessage",title:"samlIDPMetaDataOptionsSignSLOMessage",type:"trool"},{default:1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckSLOMessageSignature",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckSLOMessageSignature",title:"samlIDPMetaDataOptionsCheckSLOMessageSignature",type:"bool"}],id:"samlIDPMetaDataOptionsSignature",title:"samlIDPMetaDataOptionsSignature",type:"simpleInputContainer"},{_nodes:[{default:"",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSSOBinding",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSSOBinding",select:[{k:"",v:""},{k:"http-post",v:"POST"},{k:"http-redirect",v:"Redirect"},{k:"artifact-get",v:"Artifact GET"}],title:"samlIDPMetaDataOptionsSSOBinding",type:"select"},{default:"",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSLOBinding",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSLOBinding",select:[{k:"",v:""},{k:"http-post",v:"POST"},{k:"http-redirect",v:"Redirect"},{k:"http-soap",v:"SOAP"}],title:"samlIDPMetaDataOptionsSLOBinding",type:"select"}],id:"samlIDPMetaDataOptionsBinding",title:"samlIDPMetaDataOptionsBinding",type:"simpleInputContainer"},{_nodes:[{default:"none",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsEncryptionMode",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsEncryptionMode",select:[{k:"none",v:"None"},{k:"nameid",v:"Name ID"},{k:"assertion",v:"Assertion"}],title:"samlIDPMetaDataOptionsEncryptionMode",type:"select"},{default:1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckTime",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckTime",title:"samlIDPMetaDataOptionsCheckTime",type:"bool"},{default:1,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckAudience",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsCheckAudience",title:"samlIDPMetaDataOptionsCheckAudience",type:"bool"}],id:"samlIDPMetaDataOptionsSecurity",title:"samlIDPMetaDataOptionsSecurity",type:"simpleInputContainer"},{_nodes:[{default:"",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsResolutionRule",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsResolutionRule",title:"samlIDPMetaDataOptionsResolutionRule",type:"longtext"},{default:"",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsNameIDFormat",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsNameIDFormat",select:[{k:"",v:""},{k:"unspecified",v:"Unspecified"},{k:"email",v:"Email"},{k:"x509",v:"X509 certificate"},{k:"windows",v:"Windows"},{k:"kerberos",v:"Kerberos"},{k:"entity",v:"Entity"},{k:"persistent",v:"Persistent"},{k:"transient",v:"Transient"},{k:"encrypted",v:"Encrypted"}],title:"samlIDPMetaDataOptionsNameIDFormat",type:"select"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsForceAuthn",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsForceAuthn",title:"samlIDPMetaDataOptionsForceAuthn",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsIsPassive",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsIsPassive",title:"samlIDPMetaDataOptionsIsPassive",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAllowProxiedAuthn",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAllowProxiedAuthn",title:"samlIDPMetaDataOptionsAllowProxiedAuthn",type:"bool"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAllowLoginFromIDP",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsAllowLoginFromIDP",title:"samlIDPMetaDataOptionsAllowLoginFromIDP",type:"bool"},{default:"",get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsRequestedAuthnContext",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsRequestedAuthnContext",select:[{k:"",v:""},{k:"kerberos",v:"Kerberos"},{k:"password-protected-transport",v:"Password protected transport"},{k:"password",v:"Password"},{k:"tls-client",v:"TLS client certificate"}],title:"samlIDPMetaDataOptionsRequestedAuthnContext",type:"select"},{default:0,get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsRelayStateURL",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsRelayStateURL",title:"samlIDPMetaDataOptionsRelayStateURL",type:"bool"}],help:"authsaml.html#options",id:"samlIDPMetaDataOptions",title:"samlIDPMetaDataOptions",type:"simpleInputContainer"},{_nodes:[{get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsDisplayName",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsDisplayName",title:"samlIDPMetaDataOptionsDisplayName"},{get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsIcon",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsIcon",title:"samlIDPMetaDataOptionsIcon"},{get:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSortNumber",id:tpl+"s/"+key+"/"+"samlIDPMetaDataOptionsSortNumber",title:"samlIDPMetaDataOptionsSortNumber",type:"int"}],id:"samlIDPMetaDataOptionsDisplay",title:"samlIDPMetaDataOptionsDisplay",type:"simpleInputContainer"}];case"samlSPMetaDataNode":return[{get:tpl+"s/"+key+"/"+"samlSPMetaDataXML",id:tpl+"s/"+key+"/"+"samlSPMetaDataXML",title:"samlSPMetaDataXML",type:"file"},{cnodes:tpl+"s/"+key+"/"+"samlSPMetaDataExportedAttributes",default:[],help:"idpsaml.html#exported_attributes",id:tpl+"s/"+key+"/"+"samlSPMetaDataExportedAttributes",title:"samlSPMetaDataExportedAttributes",type:"samlAttributeContainer"},{_nodes:[{_nodes:[{default:"",get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNameIDFormat",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNameIDFormat",select:[{k:"",v:""},{k:"unspecified",v:"Unspecified"},{k:"email",v:"Email"},{k:"x509",v:"X509 certificate"},{k:"windows",v:"Windows"},{k:"kerberos",v:"Kerberos"},{k:"entity",v:"Entity"},{k:"persistent",v:"Persistent"},{k:"transient",v:"Transient"},{k:"encrypted",v:"Encrypted"}],title:"samlSPMetaDataOptionsNameIDFormat",type:"select"},{get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNameIDSessionKey",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNameIDSessionKey",title:"samlSPMetaDataOptionsNameIDSessionKey"},{default:0,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsOneTimeUse",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsOneTimeUse",title:"samlSPMetaDataOptionsOneTimeUse",type:"bool"},{default:72e3,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSessionNotOnOrAfterTimeout",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSessionNotOnOrAfterTimeout",title:"samlSPMetaDataOptionsSessionNotOnOrAfterTimeout",type:"int"},{default:72e3,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNotOnOrAfterTimeout",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsNotOnOrAfterTimeout",title:"samlSPMetaDataOptionsNotOnOrAfterTimeout",type:"int"},{default:1,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsForceUTF8",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsForceUTF8",title:"samlSPMetaDataOptionsForceUTF8",type:"bool"}],id:"samlSPMetaDataOptionsAuthnResponse",title:"samlSPMetaDataOptionsAuthnResponse",type:"simpleInputContainer"},{_nodes:[{default:-1,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSignSSOMessage",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSignSSOMessage",title:"samlSPMetaDataOptionsSignSSOMessage",type:"trool"},{default:1,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsCheckSSOMessageSignature",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsCheckSSOMessageSignature",title:"samlSPMetaDataOptionsCheckSSOMessageSignature",type:"bool"},{default:-1,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSignSLOMessage",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsSignSLOMessage",title:"samlSPMetaDataOptionsSignSLOMessage",type:"trool"},{default:1,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsCheckSLOMessageSignature",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsCheckSLOMessageSignature",title:"samlSPMetaDataOptionsCheckSLOMessageSignature",type:"bool"}],id:"samlSPMetaDataOptionsSignature",title:"samlSPMetaDataOptionsSignature",type:"simpleInputContainer"},{_nodes:[{default:"none",get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsEncryptionMode",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsEncryptionMode",select:[{k:"none",v:"None"},{k:"nameid",v:"Name ID"},{k:"assertion",v:"Assertion"}],title:"samlSPMetaDataOptionsEncryptionMode",type:"select"},{default:0,get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsEnableIDPInitiatedURL",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsEnableIDPInitiatedURL",title:"samlSPMetaDataOptionsEnableIDPInitiatedURL",type:"bool"},{get:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsRule",id:tpl+"s/"+key+"/"+"samlSPMetaDataOptionsRule",title:"samlSPMetaDataOptionsRule"}],id:"samlSPMetaDataOptionsSecurity",title:"samlSPMetaDataOptionsSecurity",type:"simpleInputContainer"}],help:"idpsaml.html#options",id:"samlSPMetaDataOptions",title:"samlSPMetaDataOptions"}];case"virtualHost":return[{cnodes:tpl+"s/"+key+"/"+"locationRules",default:[{data:"deny",id:tpl+"s/"+key+"/"+"locationRules/default",re:"default",title:"default",type:"rule"}],help:"writingrulesand_headers.html#rules",id:tpl+"s/"+key+"/"+"locationRules",title:"locationRules",type:"ruleContainer"},{cnodes:tpl+"s/"+key+"/"+"exportedHeaders",help:"writingrulesand_headers.html#headers",id:tpl+"s/"+key+"/"+"exportedHeaders",title:"exportedHeaders",type:"keyTextContainer"},{cnodes:tpl+"s/"+key+"/"+"post",help:"formreplay.html",id:tpl+"s/"+key+"/"+"post",title:"post",type:"postContainer"},{_nodes:[{default:-1,get:tpl+"s/"+key+"/"+"vhostPort",id:tpl+"s/"+key+"/"+"vhostPort",title:"vhostPort",type:"int"},{default:-1,get:tpl+"s/"+key+"/"+"vhostHttps",id:tpl+"s/"+key+"/"+"vhostHttps",title:"vhostHttps",type:"trool"},{default:0,get:tpl+"s/"+key+"/"+"vhostMaintenance",id:tpl+"s/"+key+"/"+"vhostMaintenance",title:"vhostMaintenance",type:"bool"},{get:tpl+"s/"+key+"/"+"vhostAliases",id:tpl+"s/"+key+"/"+"vhostAliases",title:"vhostAliases"},{default:"Main",get:tpl+"s/"+key+"/"+"vhostType",id:tpl+"s/"+key+"/"+"vhostType",select:[{k:"AuthBasic",v:"AuthBasic"},{k:"CDA",v:"CDA"},{k:"DevOps",v:"DevOps"},{k:"DevOpsST",v:"DevOpsST"},{k:"Main",v:"Main"},{k:"OAuth2",v:"OAuth2"},{k:"SecureToken",v:"SecureToken"},{k:"ServiceToken",v:"ServiceToken"},{k:"Zimbra",v:"ZimbraPreAuth"}],title:"vhostType",type:"select"},{get:tpl+"s/"+key+"/"+"vhostAuthnLevel",id:tpl+"s/"+key+"/"+"vhostAuthnLevel",title:"vhostAuthnLevel",type:"int"}],help:"configvhost.html#options",id:"vhostOptions",title:"vhostOptions",type:"simpleInputContainer"}];default:return[]}}function setScopeVars(scope){scope.portal=scope.data[0]._nodes[0]._nodes[0];scope.getKey(scope.portal);scope.domain=scope.data[0]._nodes[4]._nodes[1];scope.getKey(scope.domain)} diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/ar.json b/lemonldap-ng-manager/site/htdocs/static/languages/ar.json index 54259e8bf..daa66b986 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/ar.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/ar.json @@ -116,6 +116,7 @@ "casAppMetaDataOptions":"خيارات", "casAppMetaDataOptionsService":"خدمة أل يو أر ل", "casAppMetaDataOptionsRule":"القاعدة", +"casAppMetaDataOptionsUserAttribute":"خاصّيّة المستخدم", "casAppName":"اسم التطبيق كاس", "casAttr":"تسجيل الدخول كاس", "casAttributes":"السمات المصدرة لي كاس", @@ -506,6 +507,8 @@ "oidcRPMetaDataOptionsLogoutType":"نوع", "oidcRPMetaDataOptionsLogoutUrl":"يو آر إل", "oidcOPMetaDataOptionsProtocol":"بروتوكول", +"oidcRPMetaDataOptionsPublic":"Public client", +"oidcRPMetaDataOptionsRequirePKCE":"Require PKCE", "oidcRPMetaDataOptionsRule":"قاعدة الدخول", "oidcOPMetaDataOptionsScope":"نطاق", "oidcOPMetaDataOptionsStoreIDToken":"مخزن تعريف التوكن", diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/de.json b/lemonldap-ng-manager/site/htdocs/static/languages/de.json index 35aba11e3..36aca1909 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/de.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/de.json @@ -116,6 +116,7 @@ "casAppMetaDataOptions":"Optionen", "casAppMetaDataOptionsService":"Service URL", "casAppMetaDataOptionsRule":"Regel", +"casAppMetaDataOptionsUserAttribute":"User attribute", "casAppName":"CAS App Name", "casAttr":"CAS login", "casAttributes":"CAS exported attributes", @@ -506,6 +507,8 @@ "oidcRPMetaDataOptionsLogoutType":"Type", "oidcRPMetaDataOptionsLogoutUrl":"URL", "oidcOPMetaDataOptionsProtocol":"Protocol", +"oidcRPMetaDataOptionsPublic":"Public client", +"oidcRPMetaDataOptionsRequirePKCE":"Require PKCE", "oidcRPMetaDataOptionsRule":"Access rule", "oidcOPMetaDataOptionsScope":"Scope", "oidcOPMetaDataOptionsStoreIDToken":"Store ID Token", diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/en.json b/lemonldap-ng-manager/site/htdocs/static/languages/en.json index d60cca61d..bb7297225 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/en.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/en.json @@ -116,6 +116,7 @@ "casAppMetaDataOptions":"Options", "casAppMetaDataOptionsService":"Service URL", "casAppMetaDataOptionsRule":"Rule", +"casAppMetaDataOptionsUserAttribute":"User attribute", "casAppName":"CAS App Name", "casAttr":"CAS login", "casAttributes":"CAS exported attributes", @@ -506,6 +507,8 @@ "oidcRPMetaDataOptionsLogoutType":"Type", "oidcRPMetaDataOptionsLogoutUrl":"URL", "oidcOPMetaDataOptionsProtocol":"Protocol", +"oidcRPMetaDataOptionsPublic":"Public client", +"oidcRPMetaDataOptionsRequirePKCE":"Require PKCE", "oidcRPMetaDataOptionsRule":"Access rule", "oidcOPMetaDataOptionsScope":"Scope", "oidcOPMetaDataOptionsStoreIDToken":"Store ID Token", diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/fr.json b/lemonldap-ng-manager/site/htdocs/static/languages/fr.json index 328a0fbd2..21c8d470f 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/fr.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/fr.json @@ -116,6 +116,7 @@ "casAppMetaDataOptions":"Options", "casAppMetaDataOptionsService":"URL du service", "casAppMetaDataOptionsRule":"Règle", +"casAppMetaDataOptionsUserAttribute":"Attribut de l'identifiant", "casAppName":"Nom de l'application CAS", "casAttr":"Identifiant CAS", "casAttributes":"Attributs CAS", @@ -506,6 +507,8 @@ "oidcRPMetaDataOptionsLogoutType":"Type", "oidcRPMetaDataOptionsLogoutUrl":"URL", "oidcOPMetaDataOptionsProtocol":"Protocole", +"oidcRPMetaDataOptionsPublic":"Client publique", +"oidcRPMetaDataOptionsRequirePKCE":"PKCE requis", "oidcRPMetaDataOptionsRule":"Règle d'accès", "oidcOPMetaDataOptionsScope":"Étendue", "oidcOPMetaDataOptionsStoreIDToken":"Conserver le jeton d'identité", diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/it.json b/lemonldap-ng-manager/site/htdocs/static/languages/it.json index d16384017..0913d306c 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/it.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/it.json @@ -116,6 +116,7 @@ "casAppMetaDataOptions":"Opzioni", "casAppMetaDataOptionsService":"URL del servizio", "casAppMetaDataOptionsRule":"Regola", +"casAppMetaDataOptionsUserAttribute":"Attributo utente", "casAppName":"Nome App CAS", "casAttr":"Login CAS", "casAttributes":"Attributi CAS esportati", @@ -506,6 +507,8 @@ "oidcRPMetaDataOptionsLogoutType":"Tipo", "oidcRPMetaDataOptionsLogoutUrl":"URL", "oidcOPMetaDataOptionsProtocol":"Protocollo", +"oidcRPMetaDataOptionsPublic":"Public client", +"oidcRPMetaDataOptionsRequirePKCE":"Require PKCE", "oidcRPMetaDataOptionsRule":"Regola di accesso", "oidcOPMetaDataOptionsScope":"Scopo", "oidcOPMetaDataOptionsStoreIDToken":"Immagazzina ID Token", diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/vi.json b/lemonldap-ng-manager/site/htdocs/static/languages/vi.json index 1a6474c84..2c35a0539 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/vi.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/vi.json @@ -116,6 +116,7 @@ "casAppMetaDataOptions":"Tùy chọn", "casAppMetaDataOptionsService":"Dịch vụ URL", "casAppMetaDataOptionsRule":"Quy tắc", +"casAppMetaDataOptionsUserAttribute":"thuộc tính người dùng", "casAppName":"Tên ứng dụng CAS", "casAttr":"Đăng nhập CAS ", "casAttributes":"Thuộc tính CAS đã được xuất", @@ -506,6 +507,8 @@ "oidcRPMetaDataOptionsLogoutType":"Loại", "oidcRPMetaDataOptionsLogoutUrl":"URL", "oidcOPMetaDataOptionsProtocol":"Giao thức", +"oidcRPMetaDataOptionsPublic":"Public client", +"oidcRPMetaDataOptionsRequirePKCE":"Require PKCE", "oidcRPMetaDataOptionsRule":"Quy tắc truy cập", "oidcOPMetaDataOptionsScope":"Phạm vi", "oidcOPMetaDataOptionsStoreIDToken":"Mã thông báo Cửa hàng", diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/zh.json b/lemonldap-ng-manager/site/htdocs/static/languages/zh.json index 2db4ff928..bba08bd49 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/zh.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/zh.json @@ -116,6 +116,7 @@ "casAppMetaDataOptions":"选项", "casAppMetaDataOptionsService":"服务 URL", "casAppMetaDataOptionsRule":"规则", +"casAppMetaDataOptionsUserAttribute":"User attribute", "casAppName":"CAS App 名称", "casAttr":"CAS 登录", "casAttributes":"CAS 声明的attributes", @@ -506,6 +507,8 @@ "oidcRPMetaDataOptionsLogoutType":"Type", "oidcRPMetaDataOptionsLogoutUrl":"URL", "oidcOPMetaDataOptionsProtocol":"Protocol", +"oidcRPMetaDataOptionsPublic":"Public client", +"oidcRPMetaDataOptionsRequirePKCE":"Require PKCE", "oidcRPMetaDataOptionsRule":"Access rule", "oidcOPMetaDataOptionsScope":"Scope", "oidcOPMetaDataOptionsStoreIDToken":"Store ID Token", diff --git a/lemonldap-ng-portal/MANIFEST b/lemonldap-ng-portal/MANIFEST index 903bf4d71..120489e53 100644 --- a/lemonldap-ng-portal/MANIFEST +++ b/lemonldap-ng-portal/MANIFEST @@ -440,6 +440,7 @@ t/30-SAML-Head-to-Tail-POST.t t/30-SAML-ReAuth-with-choice.t t/30-SAML-ReAuth.t t/30-SAML-SP-rule.t +t/31-Auth-and-issuer-CAS-declared-app-userattr.t t/31-Auth-and-issuer-CAS-declared-app.t t/31-Auth-and-issuer-CAS-declared-apps.t t/31-Auth-and-issuer-CAS-default.t @@ -448,11 +449,13 @@ t/31-Auth-and-issuer-CAS-proxied.t t/31-Auth-and-issuer-CAS-with-choice-and-cancel.t t/31-Auth-and-issuer-CAS-with-choice.t t/32-Auth-and-issuer-OIDC-authorization_code-OP-logout.t +t/32-Auth-and-issuer-OIDC-authorization_code-public_client.t t/32-Auth-and-issuer-OIDC-authorization_code-with-authchoice.t t/32-Auth-and-issuer-OIDC-authorization_code.t t/32-Auth-and-issuer-OIDC-hybrid.t t/32-Auth-and-issuer-OIDC-implicit.t t/32-Auth-and-issuer-OIDC-sorted.t +t/32-CAS-10.t t/32-OIDC-RP-rule.t t/33-Auth-and-issuer-OpenID2.t t/34-Auth-Proxy-and-REST-Server.t diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/TOTP.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/TOTP.pm index 9b18d13a3..eb082d085 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/TOTP.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/TOTP.pm @@ -295,24 +295,17 @@ sub run { return $self->p->sendError( $req, "Corrupted session", 500 ); } } - else { $self->logger->debug("No 2F Device found"); $_2fDevices = []; } # Delete TOTP 2F device - my @keep = (); - while (@$_2fDevices) { - my $element = shift @$_2fDevices; - $self->logger->debug("Looking for 2F device to delete ..."); - push @keep, $element unless ( $element->{epoch} eq $epoch ); - } - + @$_2fDevices = grep { $_->{epoch} ne $epoch } @$_2fDevices; $self->logger->debug( "Delete 2F Device : { type => 'TOTP', epoch => $epoch }"); $self->p->updatePersistentSession( $req, - { _2fDevices => to_json( \@keep ) } ); + { _2fDevices => to_json( $_2fDevices ) } ); $self->userLogger->notice('TOTP deletion succeed'); return [ 200, diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/U2F.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/U2F.pm index c4926182a..1eabded61 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/U2F.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/U2F.pm @@ -287,17 +287,12 @@ sub run { $_2fDevices = []; } - my @keep = (); - while (@$_2fDevices) { - my $element = shift @$_2fDevices; - $self->logger->debug("Looking for 2F device to delete ..."); - push @keep, $element unless ( $element->{epoch} eq $epoch ); - } - + # Delete U2F device + @$_2fDevices = grep { $_->{epoch} ne $epoch } @$_2fDevices; $self->logger->debug( "Delete 2F Device : { type => 'U2F', epoch => $epoch }"); $self->p->updatePersistentSession( $req, - { _2fDevices => to_json( \@keep ) } ); + { _2fDevices => to_json( $_2fDevices ) } ); $self->userLogger->notice('U2F key unregistration succeed'); return [ 200, diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm index 2c437917a..34aa8968b 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm @@ -176,31 +176,23 @@ sub run { return $self->p->sendError( $req, "Corrupted session", 500 ); } } - else { $self->logger->debug("No 2F Device found"); $_2fDevices = []; } - my @keep = (); - while (@$_2fDevices) { - my $element = shift @$_2fDevices; - $self->logger->debug("Looking for 2F device to delete ..."); - push @keep, $element unless ( $element->{epoch} eq $epoch ); - } - + # Delete Yubikey device + @$_2fDevices = grep { $_->{epoch} ne $epoch } @$_2fDevices; $self->logger->debug( "Delete 2F Device : { type => 'UBK', epoch => $epoch }"); $self->p->updatePersistentSession( $req, - { _2fDevices => to_json( \@keep ) } ); - + { _2fDevices => to_json( $_2fDevices ) } ); $self->userLogger->notice('Yubikey deletion succeed'); return [ 200, [ 'Content-Type' => 'application/json', 'Content-Length' => 12, ], ['{"result":1}'] ]; - } else { $self->logger->error("Unknown Yubikey action -> $action"); diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Kerberos.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Kerberos.pm index ca2cf907a..2642feb4b 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Kerberos.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Kerberos.pm @@ -107,9 +107,16 @@ sub extractFormInfo { # Call kerberos.js if Kerberos is the only Auth module # kerberosChoice.js is used by Choice $self->{AjaxInitScript} =~ s/kerberosChoice/kerberos/; - $req->data->{customScript} .= $self->{AjaxInitScript}; - $self->logger->debug( - "Send init/script -> " . $req->data->{customScript} ); + + # In some Combination scenarios, Kerberos may be called multiple + # times but we only want to add the JS once + unless ( $req->data->{_krbJsAlreadySent} ) { + + $req->data->{customScript} .= $self->{AjaxInitScript}; + $self->logger->debug( + "Send init/script -> " . $req->data->{customScript} ); + $req->data->{_krbJsAlreadySent} = 1; + } #$self->p->setHiddenFormValue( $req, kerberos => 0, '', 0 ); eval( $self->InitCmd ); diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/CAS.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/CAS.pm index aaf67bcff..90a14aefa 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/CAS.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/CAS.pm @@ -458,14 +458,23 @@ sub validate { } # Get username - my $username = $localSession->data->{ $self->conf->{casAttr} - || $self->conf->{whatToTrace} }; + my $app = $casServiceSession->data->{_casApp}; + my $username_attribute = + ( $app + and $self->conf->{casAppMetaDataOptions}->{$app} + ->{casAppMetaDataOptionsUserAttribute} ) + ? $self->conf->{casAppMetaDataOptions}->{$app} + ->{casAppMetaDataOptionsUserAttribute} + : ( $self->conf->{casAttr} + || $self->conf->{whatToTrace} ); + + my $username = $localSession->data->{$username_attribute}; $self->logger->debug("Get username $username"); # Return success message $self->deleteCasSession($casServiceSession); - return $self->returnCasValidateSuccess($username); + return $self->returnCasValidateSuccess( $req, $username ); } sub proxy { @@ -728,8 +737,16 @@ sub _validate2 { } # Get username - my $username = $localSession->data->{ $self->conf->{casAttr} - || $self->conf->{whatToTrace} }; + my $username_attribute = + ( $app + and $self->conf->{casAppMetaDataOptions}->{$app} + ->{casAppMetaDataOptionsUserAttribute} ) + ? $self->conf->{casAppMetaDataOptions}->{$app} + ->{casAppMetaDataOptionsUserAttribute} + : ( $self->conf->{casAttr} + || $self->conf->{whatToTrace} ); + + my $username = $localSession->data->{$username_attribute}; $self->logger->debug("Get username $username"); 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 988255b56..85b3fbd9f 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/OpenIDConnect.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/OpenIDConnect.pm @@ -150,7 +150,7 @@ sub run { foreach my $param ( qw/response_type scope client_id state redirect_uri nonce response_mode display prompt max_age ui_locales id_token_hint - login_hint acr_values request request_uri/ + login_hint acr_values request request_uri code_challenge code_challenge_method/ ) { if ( $req->param($param) ) { @@ -574,6 +574,24 @@ sub run { my $session_state = $self->createSessionState( $req->id, $client_id ); + # Check if PKCE is required + if ( $self->conf->{oidcRPMetaDataOptions}->{$rp} + ->{oidcRPMetaDataOptionsRequirePKCE} + and !$oidc_request->{'code_challenge'} ) + { + $self->userLogger->error( + "Relying Party must use PKCE protection"); + return $self->returnRedirectError( + $req, + $oidc_request->{'redirect_uri'}, + 'invalid_request', + "Code challenge is required", + undef, + $oidc_request->{'state'}, + ( $flow ne "authorizationcode" ) + ); + } + # Authorization Code Flow if ( $flow eq "authorizationcode" ) { @@ -586,6 +604,9 @@ sub run { user_session_id => $req->id, _utime => time, nonce => $oidc_request->{'nonce'}, + code_challenge => $oidc_request->{'code_challenge'}, + code_challenge_method => + $oidc_request->{'code_challenge_method'}, } ); @@ -944,7 +965,7 @@ sub token { my ( $client_id, $client_secret ) = $self->getEndPointAuthenticationCredentials($req); - unless ( $client_id && $client_secret ) { + unless ($client_id) { $self->logger->error( "No authentication provided to get token, or authentication type not supported" ); @@ -964,11 +985,25 @@ sub token { } # Check client_secret - unless ( $client_secret eq $self->conf->{oidcRPMetaDataOptions}->{$rp} - ->{oidcRPMetaDataOptionsClientSecret} ) + if ( $self->conf->{oidcRPMetaDataOptions}->{$rp} + ->{oidcRPMetaDataOptionsPublic} ) { - $self->logger->error("Wrong credentials for $rp"); - return $self->p->sendError( 'invalid_request', 400 ); + $self->logger->debug( + "Relying Party $rp is public, do not check client secret"); + } + else { + unless ($client_secret) { + $self->logger->error( +"Relying Party $rp is confidential but no client secret was provided to authenticate on token endpoint" + ); + return $self->p->sendError( 'invalid_request', 400 ); + } + unless ( $client_secret eq $self->conf->{oidcRPMetaDataOptions}->{$rp} + ->{oidcRPMetaDataOptionsClientSecret} ) + { + $self->logger->error("Wrong credentials for $rp"); + return $self->p->sendError( 'invalid_request', 400 ); + } } # Get code session @@ -983,11 +1018,27 @@ sub token { return $self->p->sendError( $req, 'invalid_request', 400 ); } + # Check PKCE + if ( $self->conf->{oidcRPMetaDataOptions}->{$rp} + ->{oidcRPMetaDataOptionsRequirePKCE} ) + { + unless ( + $self->validatePKCEChallenge( + $req->param('code_verifier'), + $codeSession->data->{'code_challenge'}, + $codeSession->data->{'code_challenge_method'} + ) + ) + { + return $self->p->sendError( $req, 'invalid_grant', 400 ); + } + } + # Check we have the same redirect_uri value unless ( $req->param("redirect_uri") eq $codeSession->data->{redirect_uri} ) { $self->userLogger->error( "Provided redirect_uri does not match " - . $codeSession->{redirect_uri} ); + . $codeSession->data->{redirect_uri} ); return $self->p->sendError( $req, 'invalid_request', 400 ); } @@ -1454,10 +1505,13 @@ sub metadata { [qw/none HS256 HS384 HS512 RS256 RS384 RS512/], userinfo_signing_alg_values_supported => [qw/none HS256 HS384 HS512 RS256 RS384 RS512/], + + # PKCE + code_challenge_methods_supported => [qw/plain S256/], } ); - # response_modes_supported} + # response_modes_supported # id_token_encryption_alg_values_supported # id_token_encryption_enc_values_supported 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 12150daa4..a3cefa0c7 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OpenIDConnect.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OpenIDConnect.pm @@ -1047,6 +1047,10 @@ sub getEndPointAuthenticationCredentials { $client_id = $req->param('client_id'); $client_secret = $req->param('client_secret'); } + elsif ( $req->param('client_id') and !$req->param('client_secret') ) { + $self->logger->debug("Method none used"); + $client_id = $req->param('client_id'); + } return ( $client_id, $client_secret ); } @@ -1385,6 +1389,52 @@ sub addRouteFromConf { } } +# Validate PKCE code challenge with given code challenge method +# @param code_verifier +# @param code_challenge +# @param code_challenge_method +# @return boolean 1 if challenge succeed, 0 else +sub validatePKCEChallenge { + my ( $self, $code_verifier, $code_challenge, $code_challenge_method ) = @_; + + unless ($code_verifier) { + $self->logger->error("PKCE required but no code verifier provided"); + return 0; + } + + $self->logger->debug("PKCE code verifier received: $code_verifier"); + + if ( !$code_challenge_method or $code_challenge_method eq "plain" ) { + if ( $code_verifier eq $code_challenge ) { + $self->logger->debug("PKCE challenge validated (plain method)"); + return 1; + } + else { + $self->logger->error("PKCE challenge failed (plain method)"); + return 0; + } + } + + elsif ( $code_challenge_method eq "S256" ) { + my $code_verifier_hashed = encode_base64url( sha256($code_verifier) ); + if ( $code_verifier_hashed eq $code_challenge ) { + $self->logger->debug("PKCE challenge validated (S256 method)"); + return 1; + } + else { + $self->logger->error("PKCE challenge failed (S256 method)"); + return 0; + } + } + + else { + $self->logger->error("PKCE challenge method not valid"); + return 0; + } + + return 0; +} + 1; __END__ @@ -1543,6 +1593,10 @@ Build Logout Response URI Build a Lemonldap::NG::Common::PSGI::Router route from OIDC configuration attribute +=head2 validatePKCEChallenge + +Validate PKCE code challenge with given code challenge method + =head1 SEE ALSO L, L diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CheckUser.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CheckUser.pm index 64e78f979..7ce1579cf 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CheckUser.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CheckUser.pm @@ -288,8 +288,9 @@ sub _urlFormat { $port ||= ''; $vhost =~ s/:\d+$//; $vhost .= $self->conf->{domain} unless ( $vhost =~ /\./ ); + #$appuri ||= '/'; - return lc ("$proto$vhost$port") . "$appuri"; + return lc("$proto$vhost$port") . "$appuri"; } sub _userDatas { @@ -387,6 +388,27 @@ sub _splitAttributes { } push @$others, $element unless $ok; } + + # Sort real and spoofed attributes if required + if ( $self->conf->{impersonationRule} ) { + $self->logger->debug('Dispatching real and spoofed attributes...'); + my ( $realAttrs, $spoofedAttrs ) = ( [], [] ); + my $prefix = "$self->{conf}->{impersonationPrefix}"; + while (@$others) { + my $element = shift @$others; + $self->logger->debug( + 'Processing attribute: ' . Data::Dumper::Dumper($element) ); + if ( $element->{key} =~ /^$prefix.+$/ ) { + push @$realAttrs, $element; + $self->logger->debug(' -> Real attribute'); + } + else { + push @$spoofedAttrs, $element; + $self->logger->debug(' -> Spoofed attribute'); + } + } + @$others = ( @$spoofedAttrs, @$realAttrs ); + } return [ $grps, $mcrs, $others ]; } diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm index f4e774033..d3b3ad153 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm @@ -11,7 +11,7 @@ extends 'Lemonldap::NG::Portal::Main::Plugin'; # INITIALIZATION -use constant endAuth => 'run'; +use constant afterData => 'run'; has rule => ( is => 'rw', default => sub { 1 } ); has idRule => ( is => 'rw', default => sub { 1 } ); @@ -137,6 +137,8 @@ sub run { # Main session $self->p->updateSession( $req, $spoofSession ); + $req->steps( [ $self->p->validSession, @{ $self->p->endAuth } ] ); + return $statut; } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/ar.json b/lemonldap-ng-portal/site/htdocs/static/languages/ar.json index 84c8bab50..8f4ed8882 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/ar.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/ar.json @@ -189,7 +189,7 @@ "pwdWillExpire":"٪ s من الأيام و٪ s من الساعات و٪ s من الدقائق و٪ s من الثواني قبل انتهاء صلاحية كلمة المرور، قم بتغييرها!", "redirectedFrom":"تمت إعادة توجيهك من", "redirectedIn":"ستتم إعادة توجيهك خلال 30 ثانية", -"redirectionInProgres":"جار إعادة التوجيه قيد التقدم ...", +"redirectionInProgress":"جار إعادة التوجيه قيد التقدم ...", "redirectionToIdp":"إعادة توجيهك إلى موفر الهوية الخاص بك", "refreshrights":"قم بتحديث حقوقي", "refuse":"رفض", diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/de.json b/lemonldap-ng-portal/site/htdocs/static/languages/de.json index 31b10520a..9fc670c6e 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/de.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/de.json @@ -189,7 +189,7 @@ "pwdWillExpire":"%s Tage, %s Stunden, %s Minuten und %s Sekunden bevor dein Passwort abläuft, bitte ändere es!", "redirectedFrom":"Du wurdest umgeleitet von", "redirectedIn":"Du wirst in 30 Sekunden umgeleitet", -"redirectionInProgres":"Umleitung läuft ...", +"redirectionInProgress":"Umleitung läuft ...", "redirectionToIdp":"Weiterleitung an deinen Identitätsanbieter", "refreshrights":"Aktualisiere meine Rechte", "refuse":"Verweigern", diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/en.json b/lemonldap-ng-portal/site/htdocs/static/languages/en.json index 609650f47..0ad2cb805 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/en.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/en.json @@ -189,7 +189,7 @@ "pwdWillExpire":"%s days, %s hours, %s minutes and %s seconds before password expiration, change it!", "redirectedFrom":"You were redirect from ", "redirectedIn":"You'll be redirected in 30 seconds", -"redirectionInProgres":"Redirection in progress...", +"redirectionInProgress":"Redirection in progress...", "redirectionToIdp":"Redirection to your Identity Provider", "refreshrights": "Refresh my rights", "refuse":"Refuse", diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/es.json b/lemonldap-ng-portal/site/htdocs/static/languages/es.json index ac1d91d76..90a4571d7 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/es.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/es.json @@ -189,7 +189,7 @@ "pwdWillExpire":"%s days, %s hours, %s minutes and %s seconds before password expiration, change it!", "redirectedFrom":"You were redirect from ", "redirectedIn":"You'll be redirected in 30 seconds", -"redirectionInProgres":"Redirection in progress...", +"redirectionInProgress":"Redirection in progress...", "redirectionToIdp":"Redirection to your Identity Provider", "refreshrights":"Refresh my rights", "refuse":"Refuse", diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/fi.json b/lemonldap-ng-portal/site/htdocs/static/languages/fi.json index f744fa7c4..77186f6a0 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/fi.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/fi.json @@ -189,7 +189,7 @@ "pwdWillExpire":"%d päivää, %d tuntia, %d minuuttia ja %sekunttia jäljellä salasanan vanhentumiseen, vaihda salasana!", "redirectedFrom":"Olet uudelleenohjattu", "redirectedIn":"You'll be redirected in 30 seconds", -"redirectionInProgres":"Redirection in progress...", +"redirectionInProgress":"Redirection in progress...", "redirectionToIdp":"Redirection to your Identity Provider", "refreshrights":"Refresh my rights", "refuse":"Refuse", diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/fr.json b/lemonldap-ng-portal/site/htdocs/static/languages/fr.json index 1e26414cc..9f6acc698 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/fr.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/fr.json @@ -189,7 +189,7 @@ "pwdWillExpire":"%s jours, %s heures, %s minutes et %s secondes avant expiration de votre mot de passe, pensez à le changer !", "redirectedFrom":"Vous avez été redirigé depuis ", "redirectedIn":"Vous allez être redirigé(e) automatiquement dans 30 secondes", -"redirectionInProgres":"Redirection en cours ...", +"redirectionInProgress":"Redirection en cours ...", "redirectionToIdp":"Redirection vers votre fournisseur d'identité", "refreshrights": "Rafraîchir mes droits", "refuse":"Refuser", diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/it.json b/lemonldap-ng-portal/site/htdocs/static/languages/it.json index 8f614e95c..8229437bf 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/it.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/it.json @@ -189,7 +189,7 @@ "pwdWillExpire":"%s giorni, %s ore, %s minuti e %s secondi prima della scadenza della password, cambiala!", "redirectedFrom":"Sei stato reindirizzato da", "redirectedIn":"Sarai reindirizzato in 30 secondi", -"redirectionInProgres":"Reindirizzamento in corso ...", +"redirectionInProgress":"Reindirizzamento in corso ...", "redirectionToIdp":"Reindirizzamento al tuo provider di identità", "refreshrights":"Aggiorna i miei diritti", "refuse":"Rifiuta", diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/nl.json b/lemonldap-ng-portal/site/htdocs/static/languages/nl.json index 537f75e11..f5577e4d3 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/nl.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/nl.json @@ -189,7 +189,7 @@ "pwdWillExpire":"%s days, %s hours, %s minutes and %s seconds before password expiration, change it!", "redirectedFrom":"You were redirect from ", "redirectedIn":"You'll be redirected in 30 seconds", -"redirectionInProgres":"Redirection in progress...", +"redirectionInProgress":"Redirection in progress...", "redirectionToIdp":"Redirection to your Identity Provider", "refreshrights":"Refresh my rights", "refuse":"Refuse", diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/pt.json b/lemonldap-ng-portal/site/htdocs/static/languages/pt.json index 6d37203c9..ee348445d 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/pt.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/pt.json @@ -189,7 +189,7 @@ "pwdWillExpire":"%s days, %s hours, %s minutes and %s seconds before password expiration, change it!", "redirectedFrom":"You were redirect from ", "redirectedIn":"You'll be redirected in 30 seconds", -"redirectionInProgres":"Redirection in progress...", +"redirectionInProgress":"Redirection in progress...", "redirectionToIdp":"Redirection to your Identity Provider", "refreshrights":"Refresh my rights", "refuse":"Refuse", diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/ro.json b/lemonldap-ng-portal/site/htdocs/static/languages/ro.json index 3e78c6890..2fea25d23 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/ro.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/ro.json @@ -189,7 +189,7 @@ "pwdWillExpire":"%s days, %s hours, %s minutes and %s seconds before password expiration, change it!", "redirectedFrom":"You were redirect from ", "redirectedIn":"You'll be redirected in 30 seconds", -"redirectionInProgres":"Redirection in progress...", +"redirectionInProgress":"Redirection in progress...", "redirectionToIdp":"Redirection to your Identity Provider", "refreshrights":"Refresh my rights", "refuse":"Refuse", diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/vi.json b/lemonldap-ng-portal/site/htdocs/static/languages/vi.json index d16305e11..17ab9d772 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/vi.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/vi.json @@ -189,7 +189,7 @@ "pwdWillExpire":"%s ngày, %s giờ, %s phút và %s giây trước khi hết hạn mật khẩu, hãy thay đổi nó!", "redirectedFrom":"Bạn đã được chuyển hướng từ", "redirectedIn":"Bạn sẽ được chuyển hướng trong 30 giây", -"redirectionInProgres":"Đang tiến hành chuyển hướng...", +"redirectionInProgress":"Đang tiến hành chuyển hướng...", "redirectionToIdp":"Chuyển hướng tới Bộ cung cấp Nhận dạng của bạn", "refreshrights":"Làm mới lại quyền của tôi", "refuse":"Từ chối", diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/zh.json b/lemonldap-ng-portal/site/htdocs/static/languages/zh.json index e473aa33f..0b909b0bd 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/zh.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/zh.json @@ -189,7 +189,7 @@ "pwdWillExpire":"距离密码失效还有 %d 天, %d 小时, %d 分钟, %d 秒, 请修改!", "redirectedFrom":"您重定向自", "redirectedIn":"您将30秒后重定向", -"redirectionInProgres":"重定向进行中", +"redirectionInProgress":"重定向进行中", "redirectionToIdp":"重定向至你的Identity Provider", "refreshrights":"刷新我的权限", "refuse":"拒绝", diff --git a/lemonldap-ng-portal/site/templates/bootstrap/redirect.tpl b/lemonldap-ng-portal/site/templates/bootstrap/redirect.tpl deleted file mode 120000 index 7e1a83bac..000000000 --- a/lemonldap-ng-portal/site/templates/bootstrap/redirect.tpl +++ /dev/null @@ -1 +0,0 @@ -../common/redirect.tpl \ No newline at end of file diff --git a/lemonldap-ng-portal/site/templates/bootstrap/redirect.tpl b/lemonldap-ng-portal/site/templates/bootstrap/redirect.tpl new file mode 100644 index 000000000..afc40f695 --- /dev/null +++ b/lemonldap-ng-portal/site/templates/bootstrap/redirect.tpl @@ -0,0 +1,40 @@ + + + + + +
+
+
+

Redirection in progress...

+
+
+
+
+
+ + +
" method="" class="login"> + + + + + +
+
+
+
+ + diff --git a/lemonldap-ng-portal/site/templates/common/redirect.tpl b/lemonldap-ng-portal/site/templates/common/redirect.tpl deleted file mode 100644 index e5a32d009..000000000 --- a/lemonldap-ng-portal/site/templates/common/redirect.tpl +++ /dev/null @@ -1,45 +0,0 @@ - - - - - Authentication portal - - - - common/favicon.ico" rel="icon" type="image/x-icon" /> - common/favicon.ico" rel="shortcut icon" /> - - - - - - - - -

Redirection in progress...

- - -
" method="" class="login"> - - - - - -
- - - diff --git a/lemonldap-ng-portal/t/31-Auth-and-issuer-CAS-declared-app-userattr.t b/lemonldap-ng-portal/t/31-Auth-and-issuer-CAS-declared-app-userattr.t new file mode 100644 index 000000000..62e10bc8b --- /dev/null +++ b/lemonldap-ng-portal/t/31-Auth-and-issuer-CAS-declared-app-userattr.t @@ -0,0 +1,322 @@ +use lib 'inc'; +use Test::More; # skip_all => 'CAS is in rebuild'; +use strict; +use IO::String; +use LWP::UserAgent; +use LWP::Protocol::PSGI; +use MIME::Base64; + +BEGIN { + require 't/test-lib.pm'; +} + +my $debug = 'error'; +my ( $issuer, $sp, $res ); +my %handlerOR = ( issuer => [], sp => [] ); + +# Redefine LWP methods for tests +LWP::Protocol::PSGI->register( + sub { + my $req = Plack::Request->new(@_); + ok( $req->uri =~ m#http://auth.((?:id|s)p).com([^\?]*)(?:\?(.*))?$#, + 'SOAP request' ); + my $host = $1; + my $url = $2; + my $query = $3; + my $res; + my $client = ( $host eq 'idp' ? $issuer : $sp ); + if ( $req->method eq 'POST' ) { + my $s = $req->content; + ok( + $res = $client->_post( + $url, IO::String->new($s), + length => length($s), + query => $query, + type => 'application/xml', + ), + "Execute POST request to $url" + ); + } + else { + ok( + $res = $client->_get( + $url, + type => 'application/xml', + query => $query, + ), + "Execute request to $url" + ); + } + expectOK($res); + ok( getHeader( $res, 'Content-Type' ) =~ m#xml#, 'Content is XML' ) + or explain( $res->[1], 'Content-Type => application/xml' ); + count(3); + return $res; + } +); + +ok( $issuer = issuer(), 'Issuer portal' ); +$handlerOR{issuer} = \@Lemonldap::NG::Handler::Main::_onReload; +count(1); +switch ('sp'); +&Lemonldap::NG::Handler::Main::cfgNum( 0, 0 ); + +ok( $sp = sp(), 'SP portal' ); +count(1); +$handlerOR{sp} = \@Lemonldap::NG::Handler::Main::_onReload; + +# Simple SP access +ok( + $res = $sp->_get( + '/', accept => 'text/html', + ), + 'Unauth SP request' +); +count(1); +expectRedirection( $res, + 'http://auth.idp.com/cas/login?service=http%3A%2F%2Fauth.sp.com%2F' ); + +# Query IdP +switch ('issuer'); +ok( + $res = $issuer->_get( + '/cas/login', + query => 'service=http://auth.sp.com/', + accept => 'text/html' + ), + 'Query CAS server' +); +count(1); +expectOK($res); +my $pdata = 'lemonldappdata=' . expectCookie( $res, 'lemonldappdata' ); + +# Try to authenticate with an unauthorized user to IdP +my $body = $res->[2]->[0]; +$body =~ s/^.*?//s; +$body =~ s#.*$##s; +my %fields = + ( $body =~ /[2]->[0] ); +count(1); + +# Simple SP access +ok( + $res = $sp->_get( + '/', accept => 'text/html', + ), + 'Unauth SP request' +); +count(1); +expectRedirection( $res, + 'http://auth.idp.com/cas/login?service=http%3A%2F%2Fauth.sp.com%2F' ); + +# Query IdP +switch ('issuer'); +ok( + $res = $issuer->_get( + '/cas/login', + query => 'service=http://auth.sp.com/', + accept => 'text/html' + ), + 'Query CAS server' +); +count(1); +expectOK($res); +$pdata = 'lemonldappdata=' . expectCookie( $res, 'lemonldappdata' ); + +# Try to authenticate with an authorized to IdP +$body = $res->[2]->[0]; +$body =~ s/^.*?//s; +$body =~ s#.*$##s; +%fields = ( $body =~ /_get("/sessions/global/$spId"), 'Get UTF-8' ); +expectOK($res); +ok( $res = eval { JSON::from_json( $res->[2]->[0] ) }, ' GET JSON' ) + or print STDERR $@; +ok( $res->{cn} eq 'Frédéric Accents', 'UTF-8 values' ) + or explain( $res, 'cn => Frédéric Accents' ); +count(3); + +# Logout initiated by SP +ok( + $res = $sp->_get( + '/', + query => 'logout', + cookie => "lemonldap=$spId", + accept => 'text/html' + ), + 'Query SP for logout' +); +count(1); +expectOK($res); +ok( + $res->[2]->[0] =~ m#iframe src="http://auth.idp.com(/cas/logout)\?(.+?)"#s, + 'Found iframe' +); +count(1); + +# Query IdP with iframe src +my $url = $1; +$query = $2; +ok( getHeader( $res, 'Content-Security-Policy' ) =~ /child-src auth.idp.com/, + 'Frame is authorizated' ) + or + explain( $res->[1], 'Content-Security-Policy => ...child-src auth.idp.com' ); +count(1); + +switch ('issuer'); +ok( + $res = $issuer->_get( + $url, + query => $query, + accept => 'text/html', + cookie => "lemonldap=$idpId" + ), + 'Get iframe from IdP' +); +count(1); +expectRedirection( $res, 'http://auth.sp.com/?logout' ); +my $h = getHeader( $res, 'Content-Security-Policy' ); +ok( ( not $h or $h !~ /frame-ancestors/ ), ' Frame can be embedded' ) + or explain( $res->[1], + 'Content-Security-Policy does not contain a frame-ancestors' ); +count(1); + +# Verify that user has been disconnected +ok( $res = $issuer->_get( '/', cookie => "lemonldap=$idpId" ), 'Query IdP' ); +count(1); +expectReject($res); + +switch ('sp'); +ok( + $res = + $sp->_get( '/', accept => 'text/html', cookie => "lemonldap=$idpId" ), + 'Query IdP' +); +count(1); +expectRedirection( $res, + 'http://auth.idp.com/cas/login?service=http%3A%2F%2Fauth.sp.com%2F' ); + +clean_sessions(); +done_testing( count() ); + +sub switch { + my $type = shift; + @Lemonldap::NG::Handler::Main::_onReload = @{ + $handlerOR{$type}; + }; +} + +sub issuer { + return LLNG::Manager::Test->new( { + ini => { + logLevel => $debug, + templatesDir => 'site/htdocs/static', + domain => 'idp.com', + portal => 'http://auth.idp.com', + authentication => 'Demo', + userDB => 'Same', + issuerDBCASActivation => 1, + issuerDBCASRule => '$uid eq "french"', + casAttr => 'uid', + casAccessControlPolicy => 'error', + multiValuesSeparator => ';', + casAppMetaDataExportedVars => { + sp => { + cn => 'cn', + mail => 'mail', + uid => 'uid', + } + }, + casAppMetaDataOptions => { + sp => { + casAppMetaDataOptionsService => 'http://auth.sp.com', + casAppMetaDataOptionsUserAttribute => 'mail', + }, + sp2 => { + casAppMetaDataOptionsService => 'http://auth.sp2.com', + }, + }, + } + } + ); +} + +sub sp { + return LLNG::Manager::Test->new( { + ini => { + logLevel => $debug, + domain => 'sp.com', + portal => 'http://auth.sp.com', + authentication => 'CAS', + userDB => 'CAS', + restSessionServer => 1, + issuerDBCASActivation => 0, + multiValuesSeparator => ';', + exportedVars => { + cn => 'cn', + }, + casSrvMetaDataExportedVars => { + idp => { + cn => 'cn', + mail => 'mail', + uid => 'uid', + } + }, + casSrvMetaDataOptions => { + idp => { + casSrvMetaDataOptionsUrl => 'http://auth.idp.com/cas', + casSrvMetaDataOptionsGateway => 0, + } + }, + }, + } + ); +} diff --git a/lemonldap-ng-portal/t/32-Auth-and-issuer-OIDC-authorization_code-public_client.t b/lemonldap-ng-portal/t/32-Auth-and-issuer-OIDC-authorization_code-public_client.t new file mode 100644 index 000000000..f32ca1be3 --- /dev/null +++ b/lemonldap-ng-portal/t/32-Auth-and-issuer-OIDC-authorization_code-public_client.t @@ -0,0 +1,448 @@ +use lib 'inc'; +use Test::More; +use strict; +use IO::String; +use LWP::UserAgent; +use LWP::Protocol::PSGI; +use MIME::Base64; + +BEGIN { + require 't/test-lib.pm'; +} + +my $debug = 'error'; +my ( $op, $rp, $res ); +my %handlerOR = ( op => [], rp => [] ); + +my $access_token; + +LWP::Protocol::PSGI->register( + sub { + my $req = Plack::Request->new(@_); + ok( $req->uri =~ m#http://auth.((?:o|r)p).com(.*)#, ' REST request' ); + my $host = $1; + my $url = $2; + my ( $res, $client ); + count(1); + if ( $host eq 'op' ) { + pass(" Request from RP to OP, endpoint $url"); + $client = $op; + } + elsif ( $host eq 'rp' ) { + pass(' Request from OP to RP'); + $client = $rp; + } + else { + fail(' Aborting REST request (external)'); + return [ 500, [], [] ]; + } + if ( $req->method =~ /^post$/i ) { + my $s = $req->content; + ok( + $res = $client->_post( + $url, IO::String->new($s), + length => length($s), + type => $req->header('Content-Type'), + ), + ' Execute request' + ); + } + else { + ok( + $res = $client->_get( + $url, + custom => { + HTTP_AUTHORIZATION => $req->header('Authorization'), + } + ), + ' Execute request' + ); + } + ok( $res->[0] == 200, ' Response is 200' ); + ok( getHeader( $res, 'Content-Type' ) =~ m#^application/json#, + ' Content is JSON' ) + or explain( $res->[1], 'Content-Type => application/json' ); + count(4); + if ( $res->[2]->[0] =~ /"access_token":"(.*?)"/ ) { + $access_token = $1; + pass "Found access_token $access_token"; + count(1); + } + return $res; + } +); + +# Initialization +ok( $op = op(), 'OP portal' ); + +ok( $res = $op->_get('/oauth2/jwks'), 'Get JWKS, endpoint /oauth2/jwks' ); +expectOK($res); +my $jwks = $res->[2]->[0]; + +ok( + $res = $op->_get('/.well-known/openid-configuration'), + 'Get metadata, endpoint /.well-known/openid-configuration' +); +expectOK($res); +my $metadata = $res->[2]->[0]; +count(3); + +switch ('rp'); +&Lemonldap::NG::Handler::Main::cfgNum( 0, 0 ); +ok( $rp = rp( $jwks, $metadata ), 'RP portal' ); +count(1); + +# Query RP for auth +ok( $res = $rp->_get( '/', accept => 'text/html' ), 'Unauth SP request' ); +count(1); +my ( $url, $query ) = + expectRedirection( $res, qr#http://auth.op.com(/oauth2/authorize)\?(.*)$# ); + +# Push request to OP +switch ('op'); +ok( $res = $op->_get( $url, query => $query, accept => 'text/html' ), + "Push request to OP, endpoint $url" ); +count(1); +expectOK($res); + +# Try to authenticate to OP +$query = "user=french&password=french&$query"; +ok( + $res = $op->_post( + $url, + IO::String->new($query), + accept => 'text/html', + length => length($query), + ), + "Post authentication, endpoint $url" +); +count(1); +my $idpId = expectCookie($res); +my ( $host, $tmp ); +( $host, $tmp, $query ) = expectForm( $res, '#', undef, 'confirm' ); + +ok( + $res = $op->_post( + $url, + IO::String->new($query), + accept => 'text/html', + cookie => "lemonldap=$idpId", + length => length($query), + ), + "Post confirmation, endpoint $url" +); +count(1); + +($query) = expectRedirection( $res, qr#^http://auth.rp.com/?\?(.*)$# ); + +# Push OP response to RP +switch ('rp'); + +ok( $res = $rp->_get( '/', query => $query, accept => 'text/html' ), + 'Call openidconnectcallback on RP' ); +count(1); +my $spId = expectCookie($res); + +switch ('op'); +ok( + $res = $op->_get( '/oauth2/checksession.html', accept => 'text.html' ), + 'Check session, endpoint /oauth2/checksession.html' +); +count(1); +expectOK($res); +ok( getHeader( $res, 'Content-Security-Policy' ) !~ /frame-ancestors/, + ' Frame can be embedded' ) + or explain( $res->[1], + 'Content-Security-Policy does not contain a frame-ancestors' ); +count(1); + +# Verify UTF-8 +ok( + $res = $op->_get( + '/oauth2/userinfo', query => 'access_token=' . $access_token, + ), + 'Get userinfo' +); +ok( $res = eval { JSON::from_json( $res->[2]->[0] ) }, ' GET JSON' ) + or print STDERR $@; +ok( $res->{name} eq 'Frédéric Accents', 'UTF-8 values' ) + or explain( $res, 'name => Frédéric Accents' ); +count(3); + +ok( $res = $op->_get("/sessions/global/$spId"), 'Get UTF-8' ); +expectOK($res); +ok( $res = eval { JSON::from_json( $res->[2]->[0] ) }, ' GET JSON' ) + or print STDERR $@; +ok( $res->{cn} eq 'Frédéric Accents', 'UTF-8 values' ) + or explain( $res, 'cn => Frédéric Accents' ); +count(3); + +switch ('rp'); +ok( $res = $rp->_get("/sessions/global/$spId"), 'Get UTF-8' ); +expectOK($res); +ok( $res = eval { JSON::from_json( $res->[2]->[0] ) }, ' GET JSON' ) + or print STDERR $@; +ok( $res->{cn} eq 'Frédéric Accents', 'UTF-8 values' ) + or explain( $res, 'cn => Frédéric Accents' ); +count(3); + +# Logout initiated by RP +ok( + $res = $rp->_get( + '/', + query => 'logout', + cookie => "lemonldap=$spId", + accept => 'text/html' + ), + 'Query RP for logout' +); +count(1); +( $url, $query ) = expectRedirection( $res, + qr#http://auth.op.com(/oauth2/logout)\?(post_logout_redirect_uri=.+)$# ); + +# Push logout to OP +switch ('op'); + +ok( + $res = $op->_get( + $url, + query => $query, + cookie => "lemonldap=$idpId", + accept => 'text/html' + ), + "Push logout request to OP, endpoint $url" +); +count(1); + +( $host, $tmp, $query ) = expectForm( $res, '#', undef, 'confirm' ); + +ok( + $res = $op->_post( + $url, IO::String->new($query), + length => length($query), + cookie => "lemonldap=$idpId", + accept => 'text/html', + ), + "Confirm logout, endpoint $url" +); +count(1); + +( $url, $query ) = expectRedirection( $res, qr#.# ); + +# Test logout endpoint without session +ok( + $res = $op->_get( + '/oauth2/logout', + accept => 'text/html', + query => 'post_logout_redirect_uri=http://auth.rp.com/?logout=1' + ), + 'logout endpoint with redirect, endpoint /oauth2/logout' +); +count(1); +expectRedirection( $res, 'http://auth.rp.com/?logout=1' ); + +ok( $res = $op->_get('/oauth2/logout'), + 'logout endpoint, endpoint /oauth2/logout' ); +count(1); +expectReject($res); + +# Test if logout is done +ok( + $res = $op->_get( + '/', cookie => "lemonldap=$idpId", + ), + 'Test if user is reject on IdP' +); +count(1); +expectReject($res); + +switch ('rp'); +ok( + $res = $rp->_get( + '/', + accept => 'text/html', + cookie => + "lemonldapidp=http://auth.idp.com/saml/metadata; lemonldap=$spId" + ), + 'Test if user is reject on SP' +); +count(1); +( $url, $query ) = + expectRedirection( $res, qr#^http://auth.op.com(/oauth2/authorize)\?(.*)$# ); + +# Test if consent was saved +# ------------------------- + +# Push request to OP +switch ('op'); +ok( $res = $op->_get( $url, query => $query, accept => 'text/html' ), + "Push request to OP, endpoint $url" ); +count(1); +expectOK($res); + +# Try to authenticate to OP +$query = "user=french&password=french&$query"; +ok( + $res = $op->_post( + $url, + IO::String->new($query), + accept => 'text/html', + length => length($query), + ), + "Post authentication, endpoint $url" +); +count(1); +$idpId = expectCookie($res); + +#expectRedirection( $res, qr#^http://auth.rp.com/# ); + +#print STDERR Dumper($res); + +clean_sessions(); +done_testing( count() ); + +sub switch { + my $type = shift; + pass( '==> Switching to ' . uc($type) . ' <==' ); + count(1); + @Lemonldap::NG::Handler::Main::_onReload = @{ + $handlerOR{$type}; + }; +} + +sub op { + return LLNG::Manager::Test->new( { + ini => { + logLevel => $debug, + domain => 'idp.com', + portal => 'http://auth.op.com/', + authentication => 'Demo', + userDB => 'Same', + issuerDBOpenIDConnectActivation => "1", + restSessionServer => 1, + oidcRPMetaDataExportedVars => { + rp => { + 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", + oidcRPMetaDataOptionsBypassConsent => 0, + oidcRPMetaDataOptionsPublic => 1, + oidcRPMetaDataOptionsUserIDAttr => "", + oidcRPMetaDataOptionsAccessTokenExpiration => 3600, + oidcRPMetaDataOptionsPostLogoutRedirectUris => + "http://auth.rp.com/?logout=1" + } + }, + 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----- +", + } + } + ); +} + +sub rp { + my ( $jwks, $metadata ) = @_; + return LLNG::Manager::Test->new( { + ini => { + logLevel => $debug, + domain => 'rp.com', + portal => 'http://auth.rp.com/', + authentication => 'OpenIDConnect', + userDB => 'Same', + restSessionServer => 1, + oidcOPMetaDataExportedVars => { + op => { + cn => "name", + uid => "sub", + sn => "family_name", + mail => "email" + } + }, + oidcOPMetaDataOptions => { + op => { + oidcOPMetaDataOptionsJWKSTimeout => 0, + oidcOPMetaDataOptionsScope => "openid profile", + oidcOPMetaDataOptionsStoreIDToken => 0, + oidcOPMetaDataOptionsMaxAge => 30, + oidcOPMetaDataOptionsDisplay => "", + oidcOPMetaDataOptionsClientID => "rpid", + oidcOPMetaDataOptionsConfigurationURI => + "https://auth.op.com/.well-known/openid-configuration" + } + }, + oidcOPMetaDataJWKS => { + op => $jwks, + }, + oidcOPMetaDataJSON => { + op => $metadata, + } + } + } + ); +} diff --git a/lemonldap-ng-portal/t/32-CAS-10.t b/lemonldap-ng-portal/t/32-CAS-10.t new file mode 100644 index 000000000..18bf6751c --- /dev/null +++ b/lemonldap-ng-portal/t/32-CAS-10.t @@ -0,0 +1,109 @@ +use lib 'inc'; +use Test::More; # skip_all => 'CAS is in rebuild'; +use strict; +use IO::String; +use LWP::UserAgent; +use LWP::Protocol::PSGI; +use MIME::Base64; + +BEGIN { + require 't/test-lib.pm'; +} + +my $debug = 'error'; +my ( $issuer, $res ); +my %handlerOR = ( issuer => [] ); + +ok( $issuer = issuer(), 'Issuer portal' ); +count(1); +switch ('issuer'); + +ok( + $res = $issuer->_get( + '/cas/login', + query => 'service=http://auth.sp.com/', + accept => 'text/html' + ), + 'Query CAS server' +); +count(1); +expectOK($res); +my $pdata = 'lemonldappdata=' . expectCookie( $res, 'lemonldappdata' ); + +# Try to authenticate to IdP +my $body = $res->[2]->[0]; +$body =~ s/^.*?//s; +$body =~ s#.*$##s; +my %fields = + ( $body =~ /%, ' PE40 found' ) or explain( $res->[2]->[0], "PE40 - Bad formed user" ); count(2); -my $id = expectCookie($res); -$client->logout($id); +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); ## Try to impersonate with a forbidden identity ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); @@ -82,8 +83,9 @@ m%
%, ) or explain( $res->[2]->[0], "PE5 - Forbidden identity" ); count(2); -$id = expectCookie($res); -$client->logout($id); +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); ## An unauthorized user try to impersonate ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); @@ -110,8 +112,9 @@ m%
%, ) or explain( $res->[2]->[0], "PE93 - Impersonation service not allowed" ); count(2); -$id = expectCookie($res); -$client->logout($id); +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); ## An unauthorized user to impersonate tries to authenticate ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); @@ -132,7 +135,7 @@ ok( ); count(1); -$id = expectCookie($res); +my $id = expectCookie($res); expectRedirection( $res, 'http://auth.example.com/' ); # CheckUser form diff --git a/lemonldap-ng-portal/t/75-2F-Registers.t b/lemonldap-ng-portal/t/75-2F-Registers.t index 8745b27b3..8980ce044 100644 --- a/lemonldap-ng-portal/t/75-2F-Registers.t +++ b/lemonldap-ng-portal/t/75-2F-Registers.t @@ -4,7 +4,7 @@ use IO::String; use Data::Dumper; require 't/test-lib.pm'; -my $maintests = 29; +my $maintests = 51; SKIP: { eval { require Convert::Base32 }; @@ -54,7 +54,6 @@ SKIP: { 'Form registration' ); - #expectRedirection( $res, qr#/2fregisters/totp$# ); ok( $res = $client->_get( '/2fregisters/totp', @@ -70,6 +69,7 @@ SKIP: { ) or print STDERR Dumper( $res->[2]->[0] ); count(1); + # Register TOTP # JS query ok( $res = $client->_post( @@ -105,7 +105,7 @@ SKIP: { eval { $res = JSON::from_json( $res->[2]->[0] ) }; ok( not($@), 'Content is JSON' ) or explain( $res->[2]->[0], 'JSON content' ); - ok( $res->{result} == 1, 'Key is registered' ); + ok( $res->{result} == 1, 'TOTP is registered' ); # Try to sign-in $client->logout($id); @@ -132,6 +132,7 @@ SKIP: { ); $id = expectCookie($res); + # Get 2F register form ok( $res = $client->_get( '/2fregisters', @@ -142,7 +143,6 @@ SKIP: { ); ok( $res->[2]->[0] =~ /2fregistration\.(?:min\.)?js/, 'Found 2f registration js' ); - ok( $res->[2]->[0] =~ qr%%, 'Found totp.png' ) or print STDERR Dumper( $res->[2]->[0] ); @@ -155,9 +155,129 @@ SKIP: { ok( $res->[2]->[0] =~ qr%%, 'Found 2fregisters/totp link' ) or print STDERR Dumper( $res->[2]->[0] ); + + # Get U2F register form + ok( + $res = $client->_get( + '/2fregisters/u', + cookie => "lemonldap=$id", + accept => 'text/html', + ), + 'Form registration' + ); + ok( $res->[2]->[0] =~ /u2fregistration\.(?:min\.)?js/, 'Found U2F js' ); + ok( + $res->[2]->[0] =~ qr%[2]->[0] ); + + # Wait to have two different epoch values + sleep 1; + + # Ajax registration request + ok( + $res = $client->_post( + '/2fregisters/u/register', IO::String->new(''), + accept => 'application/json', + cookie => "lemonldap=$id", + length => 0, + ), + 'Get registration challenge' + ); + expectOK($res); + my $data; + eval { $data = JSON::from_json( $res->[2]->[0] ) }; + ok( not($@), ' Content is JSON' ) + or explain( [ $@, $res->[2] ], 'JSON content' ); + ok( ( $data->{challenge} and $data->{appId} ), ' Get challenge and appId' ) + or explain( $data, 'challenge and appId' ); + + # Build U2F tester + my $tester = Authen::U2F::Tester->new( + certificate => Crypt::OpenSSL::X509->new_from_string( + '-----BEGIN CERTIFICATE----- +MIIB6DCCAY6gAwIBAgIJAJKuutkN2sAfMAoGCCqGSM49BAMCME8xCzAJBgNVBAYT +AlVTMQ4wDAYDVQQIDAVUZXhhczEaMBgGA1UECgwRVW50cnVzdGVkIFUyRiBPcmcx +FDASBgNVBAMMC3ZpcnR1YWwtdTJmMB4XDTE4MDMyODIwMTc1OVoXDTI3MTIyNjIw +MTc1OVowTzELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRowGAYDVQQKDBFV +bnRydXN0ZWQgVTJGIE9yZzEUMBIGA1UEAwwLdmlydHVhbC11MmYwWTATBgcqhkjO +PQIBBggqhkjOPQMBBwNCAAQTij+9mI1FJdvKNHLeSQcOW4ob3prvIXuEGJMrQeJF +6OYcgwxrVqsmNMl5w45L7zx8ryovVOti/mtqkh2pQjtpo1MwUTAdBgNVHQ4EFgQU +QXKKf+rrZwA4WXDCU/Vebe4gYXEwHwYDVR0jBBgwFoAUQXKKf+rrZwA4WXDCU/Ve +be4gYXEwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAiCdOEmw5 +hknzHR1FoyFZKRrcJu17a1PGcqTFMJHTC70CIHeCZ8KVuuMIPjoofQd1l1E221rv +RJY1Oz1fUNbrIPsL +-----END CERTIFICATE-----', Crypt::OpenSSL::X509::FORMAT_PEM() + ), + key => Crypt::PK::ECC->new( + \'-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIOdbZw1swQIL+RZoDQ9zwjWY5UjA1NO81WWjwbmznUbgoAoGCCqGSM49 +AwEHoUQDQgAEE4o/vZiNRSXbyjRy3kkHDluKG96a7yF7hBiTK0HiRejmHIMMa1ar +JjTJecOOS+88fK8qL1TrYv5rapIdqUI7aQ== +-----END EC PRIVATE KEY-----' + ), + ); + my $r = $tester->register( $data->{appId}, $data->{challenge} ); + ok( $r->is_success, ' Good challenge value' ) + or diag( $r->error_message ); + + my $registrationData = JSON::to_json( { + clientData => $r->client_data, + errorCode => 0, + registrationData => $r->registration_data, + version => "U2F_V2" + } + ); + my ( $host, $url, $query ); + $query = Lemonldap::NG::Common::FormEncode::build_urlencoded( + registration => $registrationData, + challenge => $res->[2]->[0], + ); + + ok( + $res = $client->_post( + '/2fregisters/u/registration', IO::String->new($query), + length => length($query), + accept => 'application/json', + cookie => "lemonldap=$id", + ), + 'Push registration data' + ); + expectOK($res); + eval { $data = JSON::from_json( $res->[2]->[0] ) }; + ok( not($@), ' Content is JSON' ) + or explain( [ $@, $res->[2] ], 'JSON content' ); + ok( $data->{result} == 1, 'Key is registered' ) + or explain( $data, '"result":1' ); + + # Get 2F register form + ok( + $res = $client->_get( + '/2fregisters', + cookie => "lemonldap=$id", + accept => 'text/html', + ), + 'Form 2fregisters' + ); + ok( $res->[2]->[0] =~ /2fregistration\.(?:min\.)?js/, + 'Found 2f registration js' ); + ok( $res->[2]->[0] =~ qr%%, + 'Found 2fregisters/u link' ) + or print STDERR Dumper($res); + ok( $res->[2]->[0] =~ qr%%, + 'Found 2fregisters/totp link' ) + or print STDERR Dumper($res); + + # Two 2F devices must be registered + my @sf = map m%[2]->[0]; + ok( scalar @sf == 2, 'Two 2F devices found' ) + or print STDERR Dumper($res); + ok( $sf[0] eq 'TOTP', 'TOTP device found' ) or print STDERR Dumper( \@sf ); + ok( $sf[1] eq 'U2F', 'U2F device found' ) or print STDERR Dumper( \@sf ); + + # Unregister TOTP ok( $res->[2]->[0] =~ qr%TOTP.*epoch.*(\d{10})%m, "TOTP epoch $1 found" ) or print STDERR Dumper( $res->[2]->[0] ); - ok( $res = $client->_post( '/2fregisters/totp/delete', @@ -167,7 +287,10 @@ SKIP: { ), 'Delete TOTP query' ); + ok( $data->{result} == 1, 'TOTP is unregistered' ) + or explain( $data, '"result":1' ); + # Get 2F register form ok( $res = $client->_get( '/2fregisters', @@ -176,20 +299,38 @@ SKIP: { ), 'Form 2fregisters' ); - - ok( $res->[2]->[0] =~ /2fregistration\.(?:min\.)?js/, - 'Found 2f registration js' ); ok( $res->[2]->[0] =~ qr%%, 'Found 2fregisters/u link' ) or print STDERR Dumper($res); ok( $res->[2]->[0] =~ qr%%, 'Found 2fregisters/totp link' ) or print STDERR Dumper($res); + + # One 2F device must be registered + @sf = map m%[2]->[0]; + ok( scalar @sf == 1, 'One 2F device found' ) + or print STDERR Dumper($res); + ok( $sf[0] eq 'U2F', 'U2F device found' ) or print STDERR Dumper( \@sf ); + + # Unregister U2F key + ok( $res->[2]->[0] =~ qr%U2F.*epoch.*(\d{10})%m, "U2F key epoch $1 found" ) + or print STDERR Dumper( $res->[2]->[0] ); ok( - $res->[2]->[0] !~ -qr%TOTP(\d{10})\d{10}%, - "TOTP deleted" - ) or print STDERR Dumper( $res->[2]->[0] ); + $res = $client->_post( + '/2fregisters/u/delete', + IO::String->new("epoch=$1"), + length => 16, + cookie => "lemonldap=$id", + ), + 'Delete U2F key query' + ); + ok( $data->{result} == 1, 'U2F key is unregistered' ) + or explain( $data, '"result":1' ); + + # No more 2F device must be registered + @sf = map m%[2]->[0]; + ok( scalar @sf == 0, 'No 2F device found' ) + or print STDERR Dumper($res); $client->logout($id); }