This commit is contained in:
Christophe Maudoux 2020-05-23 23:52:09 +02:00
parent 279538613f
commit 79246c8da9
102 changed files with 464 additions and 1427 deletions

View File

@ -23,16 +23,20 @@ use constant HANDLERSECTION => "handler";
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(?:S(?:ervice(?:DynamicRegistrationEx(?:portedVar|traClaim)s|MetaDataAuthnContext)|torageOptions)|RPMetaData(?:(?:Option(?:sExtraClaim)?|ExportedVar|Macro)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node))|penIdExportedVars)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option|Macro)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars|fExtra)|c(?:as(?:A(?:ppMetaData(?:(?:ExportedVar|Option|Macro)s|Node)|ttributes)|S(?:rvMetaData(?:(?:ExportedVar|Option)s|Node)|torageOptions))|(?:ustom(?:Plugins|Add)Param|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)|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|kipRenewConfirmation|fRemovedUseNotif|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:Allow(?:PasswordGrant|Offline)|Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|GeneratePassword|PasswordPolicy)|ErrorOn(?:ExpiredSession|MailNotFound)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|o(?:ntextSwitchingStopWithLogout|mpactConf|rsEnabled)|heck(?:State|User|XSS)|da)|no(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|re(?:st(?:(?:Password|Session|Config|Auth)Server|ExportSecretKeys)|freshSessions)|br(?:uteForceProtection(?:IncrementalTempo)?|owsersDontStorePassword)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|d(?:isablePersistentStorage|biDynamicHashEnabled)|g(?:roupsBeforeMacros|lobalLogoutTimer)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|(?:activeTim|wsdlServ)er|krb(?:RemoveDomain|ByJs))$/;
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(?:S(?:ervice(?:DynamicRegistrationEx(?:portedVar|traClaim)s|MetaDataAuthnContext)|torageOptions)|RPMetaData(?:(?:Option(?:sExtraClaim)?|ExportedVar|Macro)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node))|penIdExportedVars)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option|Macro)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars|fExtra)|c(?:as(?:A(?:ppMetaData(?:(?:ExportedVar|Option|Macro)s|Node)|ttributes)|S(?:rvMetaData(?:(?:ExportedVar|Option)s|Node)|torageOptions))|(?:ustom(?:Plugins|Add)Param|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)|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|kipRenewConfirmation|fRemovedUseNotif|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:Allow(?:PasswordGrant|Offline)|Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|GeneratePassword|PasswordPolicy)|ErrorOn(?:ExpiredSession|MailNotFound)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|o(?:ntextSwitchingStopWithLogout|mpactConf|rsEnabled)|heck(?:State|User|XSS)|da)|no(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|re(?:st(?:(?:Password|Session|Config|Auth)Server|ExportSecretKeys)|freshSessions)|br(?:uteForceProtection(?:IncrementalTempo)?|owsersDontStorePassword)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|d(?:isablePersistentStorage|biDynamicHashEnabled)|g(?:roupsBeforeMacros|lobalLogoutTimer)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|(?:activeTim|wsdlServ)er|krb(?:RemoveDomain|ByJs))$/;
our @sessionTypes = ( 'remoteGlobal', 'global', 'localSession', 'persistent', 'saml', 'oidc', 'cas' );
our @sessionTypes = (
'remoteGlobal', 'global', 'localSession', 'persistent',
'saml', 'oidc', 'cas'
);
sub NO { qr/^(?:off|no|0)?$/i }
our %EXPORT_TAGS = (
'all' => [
qw(
'all' => [ qw(
CONFIG_WAS_CHANGED
UNKNOWN_ERROR
DATABASE_LOCKED

View File

@ -7,30 +7,54 @@ use base qw(Exporter);
our $VERSION = '2.1.0';
our %EXPORT_TAGS = ( 'all' => [qw($simpleHashKeys $doubleHashKeys $specialNodeKeys $casAppMetaDataNodeKeys $casSrvMetaDataNodeKeys $oidcOPMetaDataNodeKeys $oidcRPMetaDataNodeKeys $samlIDPMetaDataNodeKeys $samlSPMetaDataNodeKeys $virtualHostKeys $specialNodeHash $authParameters $issuerParameters $samlServiceParameters $oidcServiceParameters $casServiceParameters)] );
our %EXPORT_TAGS = (
'all' => [
qw($simpleHashKeys $doubleHashKeys $specialNodeKeys $casAppMetaDataNodeKeys $casSrvMetaDataNodeKeys $oidcOPMetaDataNodeKeys $oidcRPMetaDataNodeKeys $samlIDPMetaDataNodeKeys $samlSPMetaDataNodeKeys $virtualHostKeys $specialNodeHash $authParameters $issuerParameters $samlServiceParameters $oidcServiceParameters $casServiceParameters)
]
);
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = ( @{ $EXPORT_TAGS{'all'} } );
our $specialNodeHash = {
virtualHosts => [qw(exportedHeaders locationRules post vhostOptions)],
samlIDPMetaDataNodes => [qw(samlIDPMetaDataXML samlIDPMetaDataExportedAttributes samlIDPMetaDataOptions)],
samlSPMetaDataNodes => [qw(samlSPMetaDataXML samlSPMetaDataExportedAttributes samlSPMetaDataOptions samlSPMetaDataMacros)],
oidcOPMetaDataNodes => [qw(oidcOPMetaDataJSON oidcOPMetaDataJWKS oidcOPMetaDataOptions oidcOPMetaDataExportedVars)],
oidcRPMetaDataNodes => [qw(oidcRPMetaDataOptions oidcRPMetaDataExportedVars oidcRPMetaDataOptionsExtraClaims oidcRPMetaDataMacros)],
casSrvMetaDataNodes => [qw(casSrvMetaDataOptions casSrvMetaDataExportedVars)],
casAppMetaDataNodes => [qw(casAppMetaDataOptions casAppMetaDataExportedVars casAppMetaDataMacros)],
samlIDPMetaDataNodes => [
qw(samlIDPMetaDataXML samlIDPMetaDataExportedAttributes samlIDPMetaDataOptions)
],
samlSPMetaDataNodes => [
qw(samlSPMetaDataXML samlSPMetaDataExportedAttributes samlSPMetaDataOptions samlSPMetaDataMacros)
],
oidcOPMetaDataNodes => [
qw(oidcOPMetaDataJSON oidcOPMetaDataJWKS oidcOPMetaDataOptions oidcOPMetaDataExportedVars)
],
oidcRPMetaDataNodes => [
qw(oidcRPMetaDataOptions oidcRPMetaDataExportedVars oidcRPMetaDataOptionsExtraClaims oidcRPMetaDataMacros)
],
casSrvMetaDataNodes =>
[qw(casSrvMetaDataOptions casSrvMetaDataExportedVars)],
casAppMetaDataNodes => [
qw(casAppMetaDataOptions casAppMetaDataExportedVars casAppMetaDataMacros)
],
};
our $doubleHashKeys = 'issuerDBGetParameters';
our $simpleHashKeys = '(?:(?:l(?:o(?:calSessionStorageOption|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|c(?:as(?:StorageOption|Attribute)|ustom(?:Plugins|Add)Param|ombModule)|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|(?:(?:d(?:emo|bi)|facebook|webID)E|e)xportedVar|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|p(?:ersistentStorageOption|ortalSkinRule)|macro)s|o(?:idcS(?:ervice(?:DynamicRegistrationEx(?:portedVar|traClaim)s|MetaDataAuthnContext)|torageOptions)|penIdExportedVars)|s(?:(?:amlStorageOption|laveExportedVar)s|essionDataToRemember|fExtra)|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(?:UserAttribut|Servic|Rul)e|(?:ExportedVar|Macro)s)';
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(?:A(?:(?:uthorizationCode|ccessToken)Expiration|llow(?:PasswordGrant|Offline)|dditionalAudiences)|I(?:DToken(?:ForceClaims|Expiration|SignAlg)|con)|R(?:e(?:directUris|freshToken|quirePKCE)|ule)|Logout(?:SessionRequired|Type|Url)|P(?:ostLogoutRedirectUris|ublic)|OfflineSessionExpiration|Client(?:Secret|ID)|BypassConsent|DisplayName|ExtraClaims|UserIDAttr)|(?:ExportedVar|Macro)s)';
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)|(?:ExportedAttribute|Macro)s|XML)';
our $virtualHostKeys = '(?:vhost(?:A(?:uthnLevel|liases)|(?:Maintenanc|Typ)e|ServiceTokenTTL|Https|Port)|(?:exportedHeader|locationRule)s|post)';
our $simpleHashKeys =
'(?:(?:l(?:o(?:calSessionStorageOption|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|c(?:as(?:StorageOption|Attribute)|ustom(?:Plugins|Add)Param|ombModule)|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|(?:(?:d(?:emo|bi)|facebook|webID)E|e)xportedVar|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|p(?:ersistentStorageOption|ortalSkinRule)|macro)s|o(?:idcS(?:ervice(?:DynamicRegistrationEx(?:portedVar|traClaim)s|MetaDataAuthnContext)|torageOptions)|penIdExportedVars)|s(?:(?:amlStorageOption|laveExportedVar)s|essionDataToRemember|fExtra)|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(?:UserAttribut|Servic|Rul)e|(?:ExportedVar|Macro)s)';
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(?:A(?:(?:uthorizationCode|ccessToken)Expiration|llow(?:PasswordGrant|Offline)|dditionalAudiences)|I(?:DToken(?:ForceClaims|Expiration|SignAlg)|con)|R(?:e(?:directUris|freshToken|quirePKCE)|ule)|Logout(?:SessionRequired|Type|Url)|P(?:ostLogoutRedirectUris|ublic)|OfflineSessionExpiration|Client(?:Secret|ID)|BypassConsent|DisplayName|ExtraClaims|UserIDAttr)|(?:ExportedVar|Macro)s)';
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)|(?:ExportedAttribute|Macro)s|XML)';
our $virtualHostKeys =
'(?:vhost(?:A(?:uthnLevel|liases)|(?:Maintenanc|Typ)e|ServiceTokenTTL|Https|Port)|(?:exportedHeader|locationRule)s|post)';
our $authParameters = {
adParams => [qw(ADPwdMaxAge ADPwdExpireWarning)],
@ -38,37 +62,72 @@ our $authParameters = {
casParams => [qw(casAuthnLevel)],
choiceParams => [qw(authChoiceParam authChoiceModules authChoiceAuthBasic)],
combinationParams => [qw(combination combModules combinationForms)],
customParams => [qw(customAuth customUserDB customPassword customRegister customResetCertByMail customAddParams)],
dbiParams => [qw(dbiAuthnLevel dbiExportedVars dbiAuthChain dbiAuthUser dbiAuthPassword dbiUserChain dbiUserUser dbiUserPassword dbiAuthTable dbiUserTable dbiAuthLoginCol dbiAuthPasswordCol dbiPasswordMailCol userPivot dbiAuthPasswordHash dbiDynamicHashEnabled dbiDynamicHashValidSchemes dbiDynamicHashValidSaltedSchemes dbiDynamicHashNewPasswordScheme)],
customParams => [
qw(customAuth customUserDB customPassword customRegister customResetCertByMail customAddParams)
],
dbiParams => [
qw(dbiAuthnLevel dbiExportedVars dbiAuthChain dbiAuthUser dbiAuthPassword dbiUserChain dbiUserUser dbiUserPassword dbiAuthTable dbiUserTable dbiAuthLoginCol dbiAuthPasswordCol dbiPasswordMailCol userPivot dbiAuthPasswordHash dbiDynamicHashEnabled dbiDynamicHashValidSchemes dbiDynamicHashValidSaltedSchemes dbiDynamicHashNewPasswordScheme)
],
demoParams => [qw(demoExportedVars)],
facebookParams => [qw(facebookAuthnLevel facebookExportedVars facebookAppId facebookAppSecret facebookUserField)],
githubParams => [qw(githubAuthnLevel githubClientID githubClientSecret githubUserField githubScope)],
facebookParams => [
qw(facebookAuthnLevel facebookExportedVars facebookAppId facebookAppSecret facebookUserField)
],
githubParams => [
qw(githubAuthnLevel githubClientID githubClientSecret githubUserField githubScope)
],
gpgParams => [qw(gpgAuthnLevel gpgDb)],
kerberosParams => [qw(krbAuthnLevel krbKeytab krbByJs krbRemoveDomain)],
ldapParams => [qw(ldapAuthnLevel ldapExportedVars ldapServer ldapPort ldapBase managerDn managerPassword ldapTimeout ldapVersion ldapRaw LDAPFilter AuthLDAPFilter mailLDAPFilter ldapSearchDeref ldapGroupBase ldapGroupObjectClass ldapGroupAttributeName ldapGroupAttributeNameUser ldapGroupAttributeNameSearch ldapGroupDecodeSearchedValue ldapGroupRecursive ldapGroupAttributeNameGroup ldapPpolicyControl ldapSetPassword ldapChangePasswordAsUser ldapPwdEnc ldapUsePasswordResetAttribute ldapPasswordResetAttribute ldapPasswordResetAttributeValue ldapAllowResetExpiredPassword ldapITDS)],
linkedinParams => [qw(linkedInAuthnLevel linkedInClientID linkedInClientSecret linkedInUserField linkedInScope)],
ldapParams => [
qw(ldapAuthnLevel ldapExportedVars ldapServer ldapPort ldapBase managerDn managerPassword ldapTimeout ldapVersion ldapRaw LDAPFilter AuthLDAPFilter mailLDAPFilter ldapSearchDeref ldapGroupBase ldapGroupObjectClass ldapGroupAttributeName ldapGroupAttributeNameUser ldapGroupAttributeNameSearch ldapGroupDecodeSearchedValue ldapGroupRecursive ldapGroupAttributeNameGroup ldapPpolicyControl ldapSetPassword ldapChangePasswordAsUser ldapPwdEnc ldapUsePasswordResetAttribute ldapPasswordResetAttribute ldapPasswordResetAttributeValue ldapAllowResetExpiredPassword ldapITDS)
],
linkedinParams => [
qw(linkedInAuthnLevel linkedInClientID linkedInClientSecret linkedInUserField linkedInScope)
],
nullParams => [qw(nullAuthnLevel)],
oidcParams => [qw(oidcAuthnLevel oidcRPCallbackGetParam oidcRPStateTimeout)],
openidParams => [qw(openIdAuthnLevel openIdExportedVars openIdSecret openIdIDPList)],
oidcParams =>
[qw(oidcAuthnLevel oidcRPCallbackGetParam oidcRPStateTimeout)],
openidParams =>
[qw(openIdAuthnLevel openIdExportedVars openIdSecret openIdIDPList)],
pamParams => [qw(pamAuthnLevel pamService)],
proxyParams => [qw(proxyAuthnLevel proxyAuthService proxySessionService remoteCookieName proxyUseSoap)],
proxyParams => [
qw(proxyAuthnLevel proxyAuthService proxySessionService remoteCookieName proxyUseSoap)
],
radiusParams => [qw(radiusAuthnLevel radiusSecret radiusServer)],
remoteParams => [qw(remotePortal remoteCookieName remoteGlobalStorage remoteGlobalStorageOptions)],
restParams => [qw(restAuthnLevel restAuthUrl restUserDBUrl restPwdConfirmUrl restPwdModifyUrl)],
slaveParams => [qw(slaveAuthnLevel slaveUserHeader slaveMasterIP slaveHeaderName slaveHeaderContent slaveDisplayLogo slaveExportedVars)],
remoteParams => [
qw(remotePortal remoteCookieName remoteGlobalStorage remoteGlobalStorageOptions)
],
restParams => [
qw(restAuthnLevel restAuthUrl restUserDBUrl restPwdConfirmUrl restPwdModifyUrl)
],
slaveParams => [
qw(slaveAuthnLevel slaveUserHeader slaveMasterIP slaveHeaderName slaveHeaderContent slaveDisplayLogo slaveExportedVars)
],
sslParams => [qw(SSLAuthnLevel SSLVar SSLVarIf sslByAjax sslHost)],
twitterParams => [qw(twitterAuthnLevel twitterKey twitterSecret twitterAppName twitterUserField)],
twitterParams => [
qw(twitterAuthnLevel twitterKey twitterSecret twitterAppName twitterUserField)
],
webidParams => [qw(webIDAuthnLevel webIDExportedVars webIDWhitelist)],
};
our $issuerParameters = {
issuerDBCAS => [qw(issuerDBCASActivation issuerDBCASPath issuerDBCASRule)],
issuerDBGet => [qw(issuerDBGetActivation issuerDBGetPath issuerDBGetRule issuerDBGetParameters)],
issuerDBOpenID => [qw(issuerDBOpenIDActivation issuerDBOpenIDPath issuerDBOpenIDRule openIdIssuerSecret openIdAttr openIdSPList openIdSreg_fullname openIdSreg_nickname openIdSreg_language openIdSreg_postcode openIdSreg_timezone openIdSreg_country openIdSreg_gender openIdSreg_email openIdSreg_dob)],
issuerDBOpenIDConnect => [qw(issuerDBOpenIDConnectActivation issuerDBOpenIDConnectPath issuerDBOpenIDConnectRule)],
issuerDBSAML => [qw(issuerDBSAMLActivation issuerDBSAMLPath issuerDBSAMLRule)],
issuerDBGet => [
qw(issuerDBGetActivation issuerDBGetPath issuerDBGetRule issuerDBGetParameters)
],
issuerDBOpenID => [
qw(issuerDBOpenIDActivation issuerDBOpenIDPath issuerDBOpenIDRule openIdIssuerSecret openIdAttr openIdSPList openIdSreg_fullname openIdSreg_nickname openIdSreg_language openIdSreg_postcode openIdSreg_timezone openIdSreg_country openIdSreg_gender openIdSreg_email openIdSreg_dob)
],
issuerDBOpenIDConnect => [
qw(issuerDBOpenIDConnectActivation issuerDBOpenIDConnectPath issuerDBOpenIDConnectRule)
],
issuerDBSAML =>
[qw(issuerDBSAMLActivation issuerDBSAMLPath issuerDBSAMLRule)],
issuerOptions => [qw(issuersTimeout)],
};
our $samlServiceParameters = [qw(samlEntityID samlServicePrivateKeySig samlServicePrivateKeySigPwd samlServicePublicKeySig samlServicePrivateKeyEnc samlServicePrivateKeyEncPwd samlServicePublicKeyEnc samlServiceUseCertificateInResponse samlServiceSignatureMethod samlNameIDFormatMapEmail samlNameIDFormatMapX509 samlNameIDFormatMapWindows samlNameIDFormatMapKerberos samlAuthnContextMapPassword samlAuthnContextMapPasswordProtectedTransport samlAuthnContextMapTLSClient samlAuthnContextMapKerberos samlOrganizationDisplayName samlOrganizationName samlOrganizationURL samlSPSSODescriptorAuthnRequestsSigned samlSPSSODescriptorWantAssertionsSigned samlSPSSODescriptorSingleLogoutServiceHTTPRedirect samlSPSSODescriptorSingleLogoutServiceHTTPPost samlSPSSODescriptorSingleLogoutServiceSOAP samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact samlSPSSODescriptorAssertionConsumerServiceHTTPPost samlSPSSODescriptorArtifactResolutionServiceArtifact samlIDPSSODescriptorWantAuthnRequestsSigned samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect samlIDPSSODescriptorSingleSignOnServiceHTTPPost samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect samlIDPSSODescriptorSingleLogoutServiceHTTPPost samlIDPSSODescriptorSingleLogoutServiceSOAP samlIDPSSODescriptorArtifactResolutionServiceArtifact samlAttributeAuthorityDescriptorAttributeServiceSOAP samlMetadataForceUTF8 samlRelayStateTimeout samlUseQueryStringSpecific samlOverrideIDPEntityID samlStorage samlStorageOptions samlCommonDomainCookieActivation samlCommonDomainCookieDomain samlCommonDomainCookieReader samlCommonDomainCookieWriter samlDiscoveryProtocolActivation samlDiscoveryProtocolURL samlDiscoveryProtocolPolicy samlDiscoveryProtocolIsPassive)];
our $oidcServiceParameters = [qw(oidcServiceMetaDataAuthorizeURI oidcServiceMetaDataTokenURI oidcServiceMetaDataUserInfoURI oidcServiceMetaDataJWKSURI oidcServiceMetaDataRegistrationURI oidcServiceMetaDataIntrospectionURI oidcServiceMetaDataEndSessionURI oidcServiceMetaDataCheckSessionURI oidcServiceMetaDataFrontChannelURI oidcServiceMetaDataBackChannelURI oidcServiceMetaDataAuthnContext oidcServicePrivateKeySig oidcServicePublicKeySig oidcServiceKeyIdSig oidcServiceAllowDynamicRegistration oidcServiceAllowAuthorizationCodeFlow oidcServiceAllowImplicitFlow oidcServiceAllowHybridFlow oidcServiceAuthorizationCodeExpiration oidcServiceAccessTokenExpiration oidcServiceIDTokenExpiration oidcServiceOfflineSessionExpiration oidcStorage oidcStorageOptions oidcServiceDynamicRegistrationExportedVars oidcServiceDynamicRegistrationExtraClaims)];
our $samlServiceParameters = [
qw(samlEntityID samlServicePrivateKeySig samlServicePrivateKeySigPwd samlServicePublicKeySig samlServicePrivateKeyEnc samlServicePrivateKeyEncPwd samlServicePublicKeyEnc samlServiceUseCertificateInResponse samlServiceSignatureMethod samlNameIDFormatMapEmail samlNameIDFormatMapX509 samlNameIDFormatMapWindows samlNameIDFormatMapKerberos samlAuthnContextMapPassword samlAuthnContextMapPasswordProtectedTransport samlAuthnContextMapTLSClient samlAuthnContextMapKerberos samlOrganizationDisplayName samlOrganizationName samlOrganizationURL samlSPSSODescriptorAuthnRequestsSigned samlSPSSODescriptorWantAssertionsSigned samlSPSSODescriptorSingleLogoutServiceHTTPRedirect samlSPSSODescriptorSingleLogoutServiceHTTPPost samlSPSSODescriptorSingleLogoutServiceSOAP samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact samlSPSSODescriptorAssertionConsumerServiceHTTPPost samlSPSSODescriptorArtifactResolutionServiceArtifact samlIDPSSODescriptorWantAuthnRequestsSigned samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect samlIDPSSODescriptorSingleSignOnServiceHTTPPost samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect samlIDPSSODescriptorSingleLogoutServiceHTTPPost samlIDPSSODescriptorSingleLogoutServiceSOAP samlIDPSSODescriptorArtifactResolutionServiceArtifact samlAttributeAuthorityDescriptorAttributeServiceSOAP samlMetadataForceUTF8 samlRelayStateTimeout samlUseQueryStringSpecific samlOverrideIDPEntityID samlStorage samlStorageOptions samlCommonDomainCookieActivation samlCommonDomainCookieDomain samlCommonDomainCookieReader samlCommonDomainCookieWriter samlDiscoveryProtocolActivation samlDiscoveryProtocolURL samlDiscoveryProtocolPolicy samlDiscoveryProtocolIsPassive)
];
our $oidcServiceParameters = [
qw(oidcServiceMetaDataAuthorizeURI oidcServiceMetaDataTokenURI oidcServiceMetaDataUserInfoURI oidcServiceMetaDataJWKSURI oidcServiceMetaDataRegistrationURI oidcServiceMetaDataIntrospectionURI oidcServiceMetaDataEndSessionURI oidcServiceMetaDataCheckSessionURI oidcServiceMetaDataFrontChannelURI oidcServiceMetaDataBackChannelURI oidcServiceMetaDataAuthnContext oidcServicePrivateKeySig oidcServicePublicKeySig oidcServiceKeyIdSig oidcServiceAllowDynamicRegistration oidcServiceAllowAuthorizationCodeFlow oidcServiceAllowImplicitFlow oidcServiceAllowHybridFlow oidcServiceAuthorizationCodeExpiration oidcServiceAccessTokenExpiration oidcServiceIDTokenExpiration oidcServiceOfflineSessionExpiration oidcStorage oidcStorageOptions oidcServiceDynamicRegistrationExportedVars oidcServiceDynamicRegistrationExtraClaims)
];
1;

View File

@ -37,14 +37,17 @@ ok( $res = $client->_get( '/', undef, undef, "lemonldap=$sessionId" ),
ok( $res->[0] == 200, ' Code is 200' ) or explain( $res, 200 );
count(2);
SKIP: {
skip "Regexp match in rules only supported in recent Perl", 0 unless $^V ge v5.25.7;
ok( $res = $client->_get( '/user_dwho/', undef, undef, "lemonldap=$sessionId" ),
'Regexp query' );
skip "Regexp match in rules only supported in recent Perl", 0
unless $^V ge v5.25.7;
ok(
$res =
$client->_get( '/user_dwho/', undef, undef, "lemonldap=$sessionId" ),
'Regexp query'
);
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res, 200 );
count(2);
};
}
# Request an URI protected by custom function -> allowed
ok(
@ -115,14 +118,18 @@ ok( $res->[0] == 200, ' Code is 200' ) or explain( $res, 200 );
count(2);
SKIP: {
skip "Regexp match in rules only supported in recent Perl", 0 unless $^V ge v5.25.7;
ok( $res = $client->_get( '/user_rtyler/', undef, undef, "lemonldap=$sessionId" ),
'Regexp deny query' );
skip "Regexp match in rules only supported in recent Perl", 0
unless $^V ge v5.25.7;
ok(
$res = $client->_get(
'/user_rtyler/', undef, undef, "lemonldap=$sessionId"
),
'Regexp deny query'
);
ok( $res->[0] == 403, 'Code is 403' ) or explain( $res, 403 );
count(2);
}
# Required AuthnLevel = 5
ok(
$res = $client->_get( '/AuthStrong', undef, undef, "lemonldap=$sessionId" ),

View File

@ -1456,7 +1456,8 @@ sub attributes {
portalRequireOldPassword => {
default => 1,
type => 'boolOrExpr',
documentation => 'Rule to require old password to change the password',
documentation =>
'Rule to require old password to change the password',
},
hideOldPassword => {
default => 0,
@ -3018,8 +3019,7 @@ sub attributes {
type => 'boolOrExpr',
default => 1,
help => 'secondfactor.html',
documentation =>
'Rule to display second factor Manager link',
documentation => 'Rule to display second factor Manager link',
},
sfRemovedMsgRule => {
type => 'boolOrExpr',
@ -4029,6 +4029,7 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
type => 'select',
select => [
{ k => 'front', v => 'Front Channel' },
#TODO #1194
# { k => 'back', v => 'Back Channel' },
],

View File

@ -580,8 +580,8 @@ sub tree {
form => 'simpleInputContainer',
nodes => [
'singleSession', 'singleIP',
'singleUserByIP',
'notifyDeleted', 'notifyOther'
'singleUserByIP', 'notifyDeleted',
'notifyOther'
]
},
{

View File

@ -23,11 +23,7 @@ my $res;
# Test 'set' command
@cmd = qw(-yes 1 set notification 1);
combined_like(
sub { llclient->run(@cmd) },
qr/Saved under/,
'"addKey" OK'
);
combined_like( sub { llclient->run(@cmd) }, qr/Saved under/, '"addKey" OK' );
# Test 'get' command
@cmd = qw(get notification);
@ -37,11 +33,7 @@ ok( $res =~ /^notification\s+=\s+1$/, '"get notification" OK' )
# Test 'addKey' command
@cmd = qw(-yes 1 addKey locationRules/test1.example.com ^/reject deny);
combined_like(
sub { llclient->run(@cmd) },
qr/Saved under/,
'"addKey" OK'
);
combined_like( sub { llclient->run(@cmd) }, qr/Saved under/, '"addKey" OK' );
# Test 'delKey' command
@cmd = qw(-yes 1 delKey locationRules/test1.example.com ^/reject);
@ -59,11 +51,7 @@ ok( $res =~ m#accept#, '"get key/subkey" OK' )
# Test 'set' command with key/subkey
@cmd = qw(-yes 1 set locationRules/test1.example.com/default deny);
combined_like(
sub { llclient->run(@cmd) },
qr/Saved under/,
'"addKey" OK'
);
combined_like( sub { llclient->run(@cmd) }, qr/Saved under/, '"addKey" OK' );
# Test 'save' command
@cmd = qw(-cfgNum 1 save);
@ -96,8 +84,7 @@ combined_like(
qr#\bAuthor IP\b#s,
'"Author IP" OK'
);
combined_like( sub { llcommonClient->run(@cmd) },
qr#\bLog\b#s, '"Log" OK' );
combined_like( sub { llcommonClient->run(@cmd) }, qr#\bLog\b#s, '"Log" OK' );
combined_like( sub { llcommonClient->run(@cmd) },
qr#\bVersion\b#s, '"Version" OK' );

View File

@ -111,8 +111,8 @@ sub verify {
return PE_OK;
}
else {
$self->userLogger->notice( 'Invalid TOTP for '
. $session->{ $self->conf->{whatToTrace} } );
$self->userLogger->notice(
'Invalid TOTP for ' . $session->{ $self->conf->{whatToTrace} } );
return PE_BADOTP;
}
}

View File

@ -1,307 +0,0 @@
package Lemonldap::NG::Portal::Lib::Choice;
use strict;
use Mouse;
use Safe;
use IO::String;
extends 'Lemonldap::NG::Portal::Lib::Wrapper';
with 'Lemonldap::NG::Portal::Lib::OverConf';
our $VERSION = '2.1.0';
has modules => ( is => 'rw', default => sub { {} } );
has rules => ( is => 'rw', default => sub { {} } );
has type => ( is => 'rw' );
has catch => ( is => 'rw', default => sub { {} } );
has sessionKey => ( is => 'ro', default => '_choice' );
my $_choiceRules;
# INITIALIZATION
# init() must be called by module::init() with a number:
# - 0 for auth
# - 1 for userDB
# - 2 for passwordDB ?
sub init {
my ( $self, $type ) = @_;
$self->type($type);
unless ( $self->conf->{authChoiceModules}
and %{ $self->conf->{authChoiceModules} } )
{
$self->error("'authChoiceModules' is empty");
return 0;
}
foreach my $name ( keys %{ $self->conf->{authChoiceModules} } ) {
my @mods =
split( /[;\|]/, $self->conf->{authChoiceModules}->{$name} );
my $module = '::'
. [ 'Auth', 'UserDB', 'Password' ]->[$type] . '::'
. $mods[$type];
my $over;
if ( $mods[5] ) {
eval { $over = JSON::from_json( $mods[5] ) };
if ($@) {
$self->logger->error("Bad over value ($@), skipped");
}
}
if ( $module = $self->loadModule( $module, $over ) ) {
$self->modules->{$name} = $module;
$self->logger->debug(
[qw(Authentication User Password)]->[$type]
. " module $name selected" );
}
else {
$self->logger->error(
"Choice: unable to load $name, disabling it: " . $self->error );
$self->error('');
}
# Test if auth module wants to catch some path
unless ($type) {
if ( $module->can('catch') ) {
$self->catch->{$name} = $module->catch;
}
}
# Display conditions
my $safe = Safe->new;
my $cond = $mods[4];
if ( defined $cond and $cond !~ /^$/ ) {
$self->logger->debug("Found rule $cond for $name");
$_choiceRules->{$name} =
$safe->reval("sub{my(\$env)=\@_;return ($cond)}");
if ($@) {
$self->logger->error("Bad condition $cond: $@");
return 0;
}
}
else {
$self->logger->debug("No rule for $name");
$_choiceRules->{$name} = sub { 1 };
}
}
unless ( keys %{ $self->modules } ) {
$self->error('Choice: no available modules found, aborting');
return 0;
}
return 1;
}
# RUNNING METHODS
sub checkChoice {
my ( $self, $req ) = @_;
my $name;
# Check Choice from pdata
if ( defined $req->pdata->{_choice} ) {
$name = $req->pdata->{_choice};
$self->logger->debug("Choice $name selected from pdata");
}
unless ($name) {
# Check with catch method
foreach ( keys %{ $self->catch } ) {
if ( $req->path_info =~ $self->catch->{$_} ) {
$name = $_;
$self->logger->debug(
"Choice $name selected from " . $req->path_info );
last;
}
}
}
unless ($name) {
# Check with other methods
$name ||=
$req->param( $self->conf->{authChoiceParam} )
|| $req->userData->{_choice}
|| $req->sessionInfo->{_choice}
or return 0;
$self->logger->debug("Choice $name selected");
}
unless ( defined $self->modules->{$name} ) {
$self->logger->error("Unknown choice '$name'");
return 0;
}
# Store choice if module loops
$req->pdata->{_choice} = $name;
$req->data->{_authChoice} = $name;
return $name if ( $req->data->{ "enabledMods" . $self->type } );
$req->sessionInfo->{_choice} = $name;
$req->data->{ "enabledMods" . $self->type } = [ $self->modules->{$name} ];
$self->p->_authentication->authnLevel("${name}AuthnLevel");
return $name;
}
sub name {
my ( $self, $req, $type ) = @_;
unless ($req) {
return 'Choice';
}
my $n = ref( $req->data->{ "enabledMods" . $self->type }->[0] );
$n =~ s/^Lemonldap::NG::Portal::(?:(?:UserDB|Auth)::)?//;
return $n;
}
sub getForm {
my ( $self, $req ) = @_;
my @authLoop;
# Test authentication choices
unless ( ref $self->conf->{authChoiceModules} eq 'HASH' ) {
$self->logger->warn("No authentication choices defined");
return [];
}
foreach ( sort keys %{ $self->conf->{authChoiceModules} } ) {
my $name = $_;
# Name can have a digit as first character
# for sorting purpose
# Remove it in displayed name
$name =~ s/^(\d*)?(\s*)?//;
# Replace also _ by space for a nice display
$name =~ s/\_/ /g;
# Find modules associated to authChoice
my ( $auth, $userDB, $passwordDB, $url, $condition ) =
split( /[;\|]/, $self->conf->{authChoiceModules}->{$_} );
unless ( $_choiceRules->{$_} ) {
$self->logger->error("$_ has no rule");
$_choiceRules->{$_} = sub { 1 };
}
unless ( $_choiceRules->{$_}->( $req->env ) ) {
$self->logger->debug(
"Condition returns false, authentication choice $_ will not be displayed"
);
}
else {
$self->logger->debug("Displaying authentication choice $_");
if ( $auth and $userDB and $passwordDB ) {
# Default URL
$req->{cspFormAction} ||= '';
if (
defined $url
and not $self->checkXSSAttack( 'URI',
$req->env->{'REQUEST_URI'} )
and $url =~
q%^(https?://)?[^\s/.?#$].[^\s]+$% # URL must be well formatted
)
{
#$url .= $req->env->{'REQUEST_URI'};
# Avoid append same URL
$req->{cspFormAction} .= " $url"
unless $req->{cspFormAction} =~ qr%\b$url\b%;
}
else {
$url .= '#';
}
$self->logger->debug("Use URL $url");
# Options to store in the loop
my $optionsLoop = {
name => $name,
key => $_,
module => $auth,
url => $url,
CHOICE_VALUE => $req->data->{_authChoice},
CHOICE_PARAM => $self->conf->{authChoiceParam},
};
# Get displayType for this module
no strict 'refs';
my $displayType = eval {
"Lemonldap::NG::Portal::Auth::${auth}"
->can('getForm')->( $self, $req );
} || 'logo';
$self->logger->debug( 'Display type '
. ( ref $displayType ? '[ref]' : $displayType )
. ' for module $auth' );
#$optionsLoop->{$displayType} = 1 unless(ref $displayType);
$optionsLoop->{form} = $displayType;
my $logo = $_;
if ( $auth eq 'Custom' ) {
$logo =
( $self->{conf}->{customAuth} =~ /::(\w+)$/ )[0];
}
# If displayType is logo, check if key.png is available
if ( -e $self->conf->{templateDir}
. "/../htdocs/static/common/modules/"
. $logo
. ".png" )
{
$optionsLoop->{logoFile} = $logo . ".png";
}
else {
$optionsLoop->{logoFile} = $auth . ".png";
}
# Register item in loop
push @authLoop, $optionsLoop;
$self->logger->debug(
"Authentication choice $name will be displayed");
}
else {
$req->error("Authentication choice $_ value is invalid");
return 0;
}
}
}
open my $fh,
$self->conf->{templateDir} . '/'
. $self->p->getSkin($req)
. "/choice.tpl"
or die $!;
my $res;
{
local $/ = undef;
$res = readline $fh;
}
close $fh;
while ( $res =~ m#<TMPL_LOOP NAME="AUTH_LOOP">(.*?)</TMPL_LOOP>#s ) {
my $content = $1;
my $new = '';
foreach (@authLoop) {
my $tmp = $content;
if ( my @match = ( $tmp =~ m#<TMPL_VAR NAME="(\w+)">#gs ) ) {
foreach my $key (@match) {
$tmp =~ s#<TMPL_VAR NAME="$key">#$_->{$key}#gs
if defined $_->{$key};
}
}
$tmp =~ s#__LLNG_FORM__#<TMPL_INCLUDE NAME="$_->{form}.tpl">#gs;
$new .= $tmp;
}
$res =~ s#<TMPL_LOOP NAME="AUTH_LOOP">.*?</TMPL_LOOP>#$new#s;
}
$req->tplParams->{CHOICE_PARAM} = $self->conf->{authChoiceParam};
return IO::String->new($res);
}
1;

View File

@ -1,181 +0,0 @@
package Lemonldap::NG::Portal::Lib::LDAP;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Lib::Net::LDAP;
use Lemonldap::NG::Portal::Main::Constants
qw(PE_OK PE_LDAPCONNECTFAILED PE_LDAPERROR PE_BADCREDENTIALS);
extends 'Lemonldap::NG::Common::Module';
our $VERSION = '2.1.0';
# PROPERTIES
has ldap => (
is => 'rw',
lazy => 1,
builder => 'newLdap',
);
has attrs => (
is => 'rw',
lazy => 1,
builder => sub {
return [
values %{ $_[0]->{conf}->{exportedVars} },
values %{ $_[0]->{conf}->{ldapExportedVars} }
];
}
);
sub newLdap {
my $self = $_[0];
my $ldap;
# Build object and test LDAP connexion
unless (
$ldap = Lemonldap::NG::Portal::Lib::Net::LDAP->new(
{ p => $self->{p}, conf => $self->{conf} }
)
)
{
$self->logger->error("LDAP initialization error: $@");
return undef;
}
# Test connection
my $msg = $ldap->bind;
if ( $msg->code ) {
$self->logger->error( 'LDAP test has failed: ' . $msg->error );
}
elsif ( $self->{conf}->{ldapPpolicyControl} and not $ldap->loadPP() ) {
$self->logger->error("LDAP password policy error");
}
return $ldap;
}
has filter => (
is => 'rw',
lazy => 1,
builder => 'buildFilter',
);
has mailFilter => (
is => 'rw',
lazy => 1,
builder => 'buildMailFilter',
);
sub buildFilter {
return $_[0]->_buildFilter( $_[0]->conf->{AuthLDAPFilter}
|| $_[0]->conf->{LDAPFilter}
|| '(&(uid=$user)(objectClass=inetOrgPerson))' );
}
sub buildMailFilter {
my $f = $_[0]->conf->{mailLDAPFilter}
|| '(&(mail=$user)(objectClass=inetOrgPerson))';
$f =~ s/\$mail\b/\$user/g;
return $_[0]->_buildFilter($f);
}
sub _buildFilter {
my ( $self, $filter ) = @_;
my $conf = $self->{conf};
$self->{p}->logger->debug("LDAP Search base: $_[0]->{conf}->{ldapBase}");
$filter =~ s/"/\\"/g;
$filter =~ s/\$(\w+)/".\$req->{sessionInfo}->{$1}."/g;
$filter =~ s/\$req->\{sessionInfo\}->\{user\}/\$req->{user}/g;
$filter =~
s/\$req->\{sessionInfo\}->\{(_?password|mail)\}/\$req->{data}->{$1}/g;
$self->{p}->logger->debug("LDAP transformed filter: $filter");
$filter = "sub{my(\$req)=\$_[0];return \"$filter\";}";
my $res = eval $filter;
if ($@) {
$self->error("Unable to build fiter: $@");
}
return $res;
}
# INITIALIZATION
sub init {
my ($self) = @_;
$self->ldap
or $self->logger->error(
"LDAP initialization has failed, but let's continue");
$self->filter;
}
# RUNNING METHODS
sub getUser {
my ( $self, $req, %args ) = @_;
$self->validateLdap;
unless ( $self->ldap ) {
return PE_LDAPCONNECTFAILED;
}
$self->bind();
my $mesg = $self->ldap->search(
base => $self->conf->{ldapBase},
scope => 'sub',
filter => (
$args{useMail}
? $self->mailFilter->($req)
: $self->filter->($req)
),
defer => $self->conf->{ldapSearchDeref} || 'find',
attrs => $self->attrs,
);
if ( $mesg->code() != 0 ) {
$self->logger->error(
'LDAP Search error ' . $mesg->code . ": " . $mesg->error );
return PE_LDAPERROR;
}
if ( $mesg->count() > 1 ) {
$self->logger->error('More than one entry returned by LDAP directory');
eval { $self->p->_authentication->setSecurity($req) };
return PE_BADCREDENTIALS;
}
unless ( $req->data->{ldapentry} = $mesg->entry(0) ) {
$self->userLogger->warn("$req->{user} was not found in LDAP directory");
eval { $self->p->_authentication->setSecurity($req) };
return PE_BADCREDENTIALS;
}
$req->data->{dn} = $req->data->{ldapentry}->dn();
PE_OK;
}
# Validate LDAP connection before use
sub validateLdap {
my ($self) = @_;
unless ($self->ldap
and $self->ldap->root_dse( attrs => ['supportedLDAPVersion'] ) )
{
$self->ldap->DESTROY if ( $self->ldap );
$self->ldap( $self->newLdap );
}
}
# Bind
sub bind {
my $self = shift;
$self->validateLdap;
return undef unless ( $self->ldap );
my $msg = $self->ldap->bind(@_);
if ( $msg->code ) {
$self->logger->error( $msg->error );
return undef;
}
return 1;
}
1;

View File

@ -35,7 +35,7 @@ sub checkForNotifications {
unless ($notifs) {
$self->logger->info("No notification found");
return 0;
};
}
# Transform notifications
my $i = 0; # Files count
@ -125,7 +125,7 @@ sub viewNotification {
unless ($notifs) {
$self->logger->info("No accepted notification found");
return 0;
};
}
# Transform notifications
my $i = 0; # Files count

View File

@ -66,7 +66,7 @@ sub checkForNotifications {
unless ($notifs) {
$self->logger->info("No notification found");
return 0;
};
}
# Transform notifications
my $i = 0; # Files count
@ -173,7 +173,7 @@ sub viewNotification {
unless ($notifs) {
$self->logger->info("No accepted notification found");
return 0;
};
}
# Transform notifications
my $i = 0; # Files count

View File

@ -1,248 +0,0 @@
## @file
# OpenID SREG extension for Lemonldap::NG::Portal::Issuer::OpenID class
## @class
# OpenID SREG extension for Lemonldap::NG::Portal::Issuer::OpenID class
package Lemonldap::NG::Portal::Lib::OpenID::SREG;
use strict;
use Lemonldap::NG::Common::Regexp;
our $VERSION = '2.1.0';
## @method protected hash sregHook(hash prm)
# Hook called to add SREG parameters to the OpenID response
# @return Hash containing wanted parameters
sub sregHook {
my ( $self, $req, $u, $trust_root, $is_id, $is_trusted, $prm ) = @_;
my ( @req, @opt );
# Refuse federation if rejected by user
if ( $req->param('confirm') and $req->param('confirm') == -1 ) {
my %h;
$h{$_} = undef foreach (
qw(fullname nickname language postcode timezone country gender email dob)
);
$self->p->updatePersistentSession( $req, \%h );
return 0;
}
# If identity is not trusted, does nothing
return ( 0, $prm ) unless ( $is_id and $is_trusted );
$self->logger->debug("SREG start");
my $accepted = 1;
# Check all parameters
my @pol;
while ( my ( $k, $v ) = each %$prm ) {
# Store policy if provided
if ( $k eq 'policy_url' ) {
if ( $v =~ Lemonldap::NG::Common::Regexp::HTTP_URI ) {
push @pol, { url => $v };
# Question: is it important to notify policy changes ?
# if yes, uncomment this
#my $p =
# $req->{sessionInfo}->{"_openidTrust$trust_root\_Policy"};
#$accepted = 0 unless ( $p and $p eq $v );
}
else {
$self->logger->error("Bad policy url");
}
}
# Parse required attributes
elsif ( $k eq 'required' ) {
$self->logger->debug("Required attr $v");
push @req, split( /,/, $v );
}
# Parse optional attributes
elsif ( $k eq 'optional' ) {
$self->logger->debug("Optional attr $v");
push @opt,
grep { defined $self->conf->{"openIdSreg_$trust_root$_"} }
split( /,/, $v );
}
else {
$self->logger->error("Unknown OpenID SREG request $k");
}
}
$req->data->{_openIdTrustExtMsg} .= $self->loadTemplate(
$req,
'openIdPol',
params => {
policies => \@pol,
}
) if (@pol);
# Check if required keys are valid SREG requests
# Question: reject bad SREG request ? Not done yet
@req = sregfilter( $self, @req );
@opt = sregfilter( $self, @opt );
# Return if nothing is asked
return ( 1, {} ) unless ( @req or @opt );
# If a required data is not available, returns nothing
foreach my $k (@req) {
unless ( $self->conf->{"openIdSreg_$k"} ) {
$self->logger->notice(
"Parameter $k is required by $trust_root but not defined in configuration"
);
$req->info(
$self->loadTemplate(
$req, 'simpleInfo',
params => { trspan => "openidRpns,$k" }
)
);
return ( 0, {} );
}
}
# Now set data
my ( %r, %msg, %ag, %toStore );
# Requested parameters: check if already agreed or confirm is set
foreach my $k (@req) {
my $agree = $req->{sessionInfo}->{"_openidTrust$trust_root\_$k"};
if ($accepted) {
unless ( $req->param('confirm') or $agree ) {
$accepted = 0;
}
elsif ( !$agree ) {
$toStore{"_openidTrust$trust_root\_$k"} = 1;
}
}
my $tmp = $self->conf->{"openIdSreg_$k"};
$tmp =~ s/^\$//;
$msg{req}->{$k} = $r{$k} =
$req->{sessionInfo}->{ $self->{"openIdSreg_$k"} } || '';
}
# Optional parameters:
foreach my $k (@opt) {
my $tmp = $self->conf->{"openIdSreg_$k"};
$tmp =~ s/^\$//;
my $agree = $req->{sessionInfo}->{"_openidTrust$trust_root\_$k"};
if ($accepted) {
# First, check if already accepted
unless ( $req->param('confirm') or defined($agree) ) {
$accepted = 0;
$r{$k} = $req->{sessionInfo}->{$tmp}
|| '';
}
# If confirmation is returned, check the value for this field
elsif ( $req->param('confirm') == 1 ) {
my $ck = 0;
if ( defined( $req->param("sreg_$k") ) ) {
$ck = ( $req->param("sreg_$k") eq 'OK' ) || 0;
}
# Store the value returned
if ( !defined($agree) or $agree != $ck ) {
$toStore{"_openidTrust$trust_root\_$k"} = $ck;
$agree = $ck;
}
}
}
$msg{opt}->{$k} = $req->{sessionInfo}->{$tmp} || '';
# Store the value only if user agree it
if ($agree) {
$r{$k} = $msg{opt}->{$k};
$ag{$k} = 1;
}
elsif ( !defined($agree) ) {
$ag{$k} = 1;
}
else {
$ag{$k} = 0;
}
}
$self->p->updatePersistentSession( $req, \%toStore ) if (%toStore);
# Check if user has agreed request
if ($accepted) {
$self->userLogger->info(
$req->{sessionInfo}->{ $self->conf->{whatToTrace} }
. " has accepted OpenID SREG exchange with $trust_root" );
return ( 1, \%r );
}
# else build message and return 0
else {
my ( @mopt, @mreq );
# No choice for requested parameters: just an information
foreach my $k (@req) {
utf8::decode( $msg{req}->{$k} );
push @mreq, { k => $k, m => $msg{req}->{$k} };
}
# For optional parameters: checkboxes are displayed
foreach my $k (@opt) {
utf8::decode( $msg{opt}->{$k} );
push @mopt,
{
k => $k,
m => $msg{opt}->{$k},
c => ( $ag{$k} ? 'checked' : '' )
};
}
$req->data->{_openIdTrustExtMsg} .= $self->loadTemplate(
$req,
'openIdTrust',
params => {
required => \@mreq,
optional => \@mopt,
}
);
$self->logger->debug('Building validation form');
return ( 0, $prm );
}
}
## @method private array sregfilter(array attr)
# Filter the arguments passed as parameters by checking their compliance with
# SREG.
# @return fitered data
sub sregfilter {
my ( $self, @attr ) = @_;
my ( @ret, @rej );
# Browse attributes
foreach my $s (@attr) {
if ( $s =~
/^(?:(?:(?:full|nick)nam|languag|postcod|timezon)e|country|gender|email|dob)$/
)
{
push @ret, $s;
}
else {
$s =~ s/\W/\./sg;
push @rej, $s;
}
}
# Warn if some parameters are rejected
if (@rej) {
$self->logger->warn( "Requested parameter(s) "
. join( ',', @rej )
. "is(are) not valid OpenID SREG parameter(s)" );
}
# Return valid SREG parameters
return @ret;
}
1;

View File

@ -1,232 +0,0 @@
## @file
# Subclass of Net::OpenID::Server that manage OpenID extensions
## @class
# Subclass of Net::OpenID::Server that manage OpenID extensions
package Lemonldap::NG::Portal::Lib::OpenID::Server;
use strict;
use base qw(Net::OpenID::Server);
use fields qw(_extensions);
use Net::OpenID::Server;
use Lemonldap::NG::Common::Regexp;
use constant DEBUG => 0;
our $VERSION = '2.1.0';
use constant OPENID2_NS => 'http://specs.openid.net/auth/2.0';
use constant OPENID2_ID_SELECT =>
'http://specs.openid.net/auth/2.0/identifier_select';
*_push_url_arg =
( $Net::OpenID::Server::VERSION >= 1.09 )
? *OpenID::util::push_url_arg
: *Net::OpenID::Server::_push_url_arg;
## @cmethod Lemonldap::NG::Portal::Lib::OpenID::Server new(hash opts)
# Call Net::OpenID::Server::new() and store extensions
# @param %opts Net::OpenID::Server options
# @return Lemonldap::NG::Portal::Lib::OpenID::Server new object
sub new {
my $class = shift;
my $self = fields::new($class);
my %opts = @_;
$self->$_( delete $opts{$_} ) foreach (qw(extensions));
$self->SUPER::new(%opts);
#$self->{get_args} = sub { $self->param(@_) };
}
## @method protected void extensions()
# Manage "extensions" constructor parameter
sub extensions {
my $self = shift;
$self->{_extensions} = shift;
}
## @method protected list _mode_checkid(string mode, boolean redirect_for_setup)
# Overload Net::OpenID::Server::_mode_checkid to call extensions hook
# @param $mode OpenID mode
# @param $redirect_for_setup indicates that user must be redirected or not for
# setup
# @return (string $type, hashref parameters)
sub _mode_checkid {
my Lemonldap::NG::Portal::Lib::OpenID::Server $self = shift;
my ( $mode, $redirect_for_setup ) = @_;
my $return_to = $self->args("openid.return_to");
return $self->_fail("no_return_to")
unless ( $return_to
and $return_to =~ m!^https?://! );
my $trust_root = $self->args("openid.trust_root") || $return_to;
$trust_root = $self->args("openid.realm")
if $self->args('openid.ns') eq OPENID2_NS;
return $self->_fail("invalid_trust_root")
unless ( $trust_root =~ Lemonldap::NG::Common::Regexp::HTTP_URI
and Net::OpenID::Server::_url_is_under( $trust_root, $return_to ) );
my $identity = $self->args("openid.identity");
# chop off the query string, in case our trust_root came from the return_to URL
$trust_root =~ s/\?.*//;
my $u = $self->_proxy("get_user");
if ( $self->args('openid.ns') eq OPENID2_NS
&& $identity eq OPENID2_ID_SELECT )
{
$identity = $self->_proxy( "get_identity", $u, $identity );
}
my $is_identity = $self->_proxy( "is_identity", $u, $identity );
my $is_trusted =
$self->_proxy( "is_trusted", $u, $trust_root, $is_identity );
my ( %extVars, %is_ext_trusted );
my $is_exts_trusted = 1;
if ( ref( $self->{_extensions} ) ) {
my @list = $self->args->();
my %extArgs;
foreach my $arg (@list) {
next unless ( $arg =~ /^openid\.(\w+)\.([\w\.]+)?/ );
my $tmp = $1;
my $val = $2;
$extArgs{$tmp}->{$val} = scalar $self->args->($arg);
}
foreach my $ns ( keys %{ $self->{_extensions} } ) {
print STDERR "Launching OpenIP $ns hook\n" if (DEBUG);
my $h;
( $is_ext_trusted{$ns}, $h ) = $self->{_extensions}->{$ns}->(
$u, $trust_root, $is_identity, $is_trusted,
delete( $extArgs{$ns} ) || {}
);
if ($h) {
while ( my ( $k, $v ) = each %$h ) {
print STDERR "$ns returned data: $k => $v\n" if (DEBUG);
$extVars{"$ns.$k"} = $v;
}
}
$is_exts_trusted &&= $is_ext_trusted{$ns};
}
# TODO: warn if keys(%extArgs)
}
# assertion path:
if ( $is_identity && $is_trusted && $is_exts_trusted ) {
my %sArgs = (
identity => $identity,
claimed_id => $self->args('openid.claimed_id'),
return_to => $return_to,
assoc_handle => $self->args("openid.assoc_handle"),
ns => $self->args('openid.ns'),
);
$sArgs{additional_fields} = \%extVars if (%extVars);
my $ret_url = $self->signed_return_url(%sArgs);
return ( "redirect", $ret_url );
}
# Assertion could not be made, so user requires setup (login/trust...
# something). Two ways that can happen: caller might have asked us for an
# immediate return with a setup URL (the default), or explictly said that
# we're in control of the user-agent's full window, and we can do whatever
# we want with them now.
# TODO: call extension sub for setup
my %setup_args = (
$self->_setup_map("trust_root"), $trust_root,
$self->_setup_map("realm"), $trust_root,
$self->_setup_map("return_to"), $return_to,
$self->_setup_map("identity"), $identity,
$self->_setup_map("assoc_handle"), $self->args("openid.assoc_handle"),
%extVars,
);
$setup_args{ $self->_setup_map('ns') } = $self->args('openid.ns')
if $self->args('openid.ns');
my $setup_url = $self->{setup_url}
or Carp::croak("No setup_url defined.");
_push_url_arg( \$setup_url, %setup_args );
if ( $mode eq "checkid_immediate" ) {
my $ret_url = $return_to;
if ( $self->args('openid.ns') eq OPENID2_NS ) {
_push_url_arg( \$ret_url, "openid.ns", $self->args('openid.ns') );
_push_url_arg( \$ret_url, "openid.mode", "setup_needed" );
}
else {
_push_url_arg( \$ret_url, "openid.mode", "id_res" );
_push_url_arg( \$ret_url, "openid.user_setup_url", $setup_url );
}
return ( "redirect", $ret_url );
}
else {
# the "checkid_setup" mode, where we take control of the user-agent
# and return to their return_to URL later.
if ($redirect_for_setup) {
return ( "redirect", $setup_url );
}
else {
return ( "setup", \%setup_args );
}
}
}
1;
__END__
=encoding utf8
=head1 NAME
Lemonldap::NG::Portal::Lib::OpenID::Server - Add capability to manage extensions to
Net::OpenID::Server
=head1 DESCRIPTION
Lemonldap::NG::Portal::Lib::OpenID::Server adds capability to manage extensions to
Net::OpenID::Server.
=head1 SEE ALSO
L<http://lemonldap-ng.org>, L<Net::OpenID::Server>
=head1 AUTHORS
=over
=item LemonLDAP::NG team L<http://lemonldap-ng.org/team>
=back
=head1 BUG REPORT
Use OW2 system to report bug or ask for features:
L<https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues>
=head1 DOWNLOAD
Lemonldap::NG is available at
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
=head1 COPYRIGHT AND LICENSE
See COPYING file for details.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see L<http://www.gnu.org/licenses/>.
=cut

View File

@ -1743,8 +1743,10 @@ sub replayProtection {
return 0;
}
}
} else {
$self->logger->warn( "No assertion session found for request ID ".$samlID);
}
else {
$self->logger->warn(
"No assertion session found for request ID " . $samlID );
}
return 0;

View File

@ -1,52 +0,0 @@
##@file
# Slave common functions
##@class
# Slave common functions
package Lemonldap::NG::Portal::Lib::Slave;
use Exporter;
use base qw(Exporter);
use strict;
our @EXPORT = qw(checkIP checkHeader);
our $VERSION = '2.1.0';
# RUNNING METHODS
## @method Lemonldap::NG::Portal::_Slave checkIP()
# @return true if remote IP is accredited in LL::NG conf
sub checkIP {
my ( $self, $req ) = @_;
my $remoteIP = $req->address;
return 1
if (!$self->conf->{slaveMasterIP}
|| $self->conf->{slaveMasterIP} =~ /\b$remoteIP\b/ );
$self->userLogger->warn('Client IP not accredited for Slave module');
return 0;
}
## @method Lemonldap::NG::Portal::_Slave checkHeader()
# @return true if header content matches LL::NG conf
sub checkHeader {
my ( $self, $req ) = @_;
return 1
unless ( $self->conf->{slaveHeaderName}
and $self->conf->{slaveHeaderContent} );
my $slave_header = 'HTTP_' . uc( $self->{conf}->{slaveHeaderName} );
$slave_header =~ s/\-/_/g;
my $headerContent = $req->env->{$slave_header};
$self->logger->debug(
"Required Slave header => $self->{conf}->{slaveHeaderName}");
$self->logger->debug("Received Slave header content => $headerContent");
return 1
if ( $headerContent
and $self->conf->{slaveHeaderContent} =~ /\b$headerContent\b/ );
$self->userLogger->warn('Matching header not found for Slave module ');
return 0;
}
1;

View File

@ -1,26 +0,0 @@
package Lemonldap::NG::Portal::Lib::_tokenRule;
use strict;
use Mouse;
our $VERSION = '2.1.0';
has ottRule => (
is => 'rw',
lazy => 1,
default => sub {
my $rule = $_[0]->conf->{requireToken};
my $hd = $_[0]->p->HANDLER;
$rule = $hd->buildSub( $hd->substitute($rule) );
unless ($rule) {
$_[0]->logger->error(
'Unable to compile "requireToken" rule => Forcing token');
$rule = sub { 1 };
}
return $rule;
}
);
sub init { 1 }
1;

View File

@ -45,8 +45,7 @@ sub displayInit {
HANDLER->substitute( $self->conf->{portalDisplayFavApps} ) );
unless ($rule) {
my $error = HANDLER->tsv->{jail}->error || '???';
$self->error(
"Bad FavApps activation rule -> " . $error );
$self->error( "Bad FavApps activation rule -> " . $error );
return 0;
}
$self->favAppsRule($rule);
@ -239,7 +238,8 @@ sub display {
LOGOUT_URL => $self->conf->{portal} . "?logout=1",
APPSLIST_ORDER => $req->{sessionInfo}->{'_appsListOrder'},
PING => $self->conf->{portalPingInterval},
REQUIRE_OLDPASSWORD => $self->requireOldPwd->($req, $req->userData),
REQUIRE_OLDPASSWORD =>
$self->requireOldPwd->( $req, $req->userData ),
HIDE_OLDPASSWORD => 0,
STARS => $self->favAppsRule->( $req, $req->userData ),
DISPLAY_PPOLICY => $self->conf->{portalDisplayPasswordPolicy},

View File

@ -42,8 +42,11 @@ sub _modifyPassword {
return PE_PASSWORD_MISMATCH
unless ( $req->data->{newpassword} eq $req->param('confirmpassword') );
my $rule =
$self->p->HANDLER->buildSub( $self->p->HANDLER->substitute( $self->conf->{portalRequireOldPassword} ) );
my $rule = $self->p->HANDLER->buildSub(
$self->p->HANDLER->substitute(
$self->conf->{portalRequireOldPassword}
)
);
unless ($rule) {
my $error = $self->p->HANDLER->tsv->{jail}->error || '???';
}
@ -157,9 +160,13 @@ sub checkPasswordQuality {
# Fobidden special characters
$password =~ s/[\Q$speChars\E\w]//g;
if ($password) {
$self->logger->error(
'Password contains ' . length($password) . " forbidden character(s): $password");
return length($password) > 1 ? PE_PP_NOT_ALLOWED_CHARACTERS : PE_PP_NOT_ALLOWED_CHARACTER;
$self->logger->error( 'Password contains '
. length($password)
. " forbidden character(s): $password" );
return
length($password) > 1
? PE_PP_NOT_ALLOWED_CHARACTERS
: PE_PP_NOT_ALLOWED_CHARACTER;
}
return PE_OK;

View File

@ -59,7 +59,8 @@ sub modifyPassword {
# Call the modify password method
my $code =
$self->ldap->userModifyPassword( $dn, $pwd, $req->data->{oldpassword}, 0 , $requireOldPassword );
$self->ldap->userModifyPassword( $dn, $pwd, $req->data->{oldpassword},
0, $requireOldPassword );
unless ( $code == PE_PASSWORD_OK ) {
return $code;

View File

@ -66,7 +66,8 @@ sub init {
$lockTimes = $self->conf->{failedLoginNumber};
}
my $sum = $self->conf->{bruteForceProtectionMaxAge} * ( 1 + $self->conf->{failedLoginNumber} - $lockTimes );
my $sum = $self->conf->{bruteForceProtectionMaxAge} *
( 1 + $self->conf->{failedLoginNumber} - $lockTimes );
$sum += $_ foreach @{ $self->lockTimes };
$self->maxAge($sum);
}

View File

@ -276,7 +276,8 @@ sub check {
"checkUser requested for an unvalid user ($user)");
$req->{sessionInfo} = {};
$self->logger->debug('Identity not authorized');
$req->error(PE_BADCREDENTIALS); # Catch error to preserve protected Id
$req->error(PE_BADCREDENTIALS)
; # Catch error to preserve protected Id
}
}

View File

@ -191,7 +191,8 @@ sub run {
# Main session
$self->p->updateSession( $req, $req->sessionInfo );
$self->userLogger->notice(
"ContextSwitching: Update \"$realId\" session with \"$spoofId\" session data");
"ContextSwitching: Update \"$realId\" session with \"$spoofId\" session data"
);
return $self->p->do( $req, [ sub { $statut } ] );
}

View File

@ -167,7 +167,8 @@ sub myNotifs {
my ( $self, $req, $ref ) = @_;
if ($ref) {
return $self->sendJSONresponse( $req, { error => 'Missing epoch parameter' } )
return $self->sendJSONresponse( $req,
{ error => 'Missing epoch parameter' } )
unless $req->param('epoch');
# Retrieve notification reference=$ref with epoch
@ -228,7 +229,8 @@ sub retrieveNotifs {
sub _viewNotif {
my ( $self, $req, $ref, $epoch ) = @_;
$self->logger->debug( "Retrieve notification with reference: \"$ref\" and epoch: \"$epoch\"" );
$self->logger->debug(
"Retrieve notification with reference: \"$ref\" and epoch: \"$epoch\"");
my $notif = eval { $self->module->viewNotification( $req, $ref, $epoch ); };
if ($@) {
$self->logger->debug("Notification not found");

View File

@ -25,8 +25,7 @@ ok(
),
'Get Menu'
);
ok( $res->[2]->[0] =~ m%<span trmsg="37">%,
'Rejected with PE_BADURL' )
ok( $res->[2]->[0] =~ m%<span trmsg="37">%, 'Rejected with PE_BADURL' )
or print STDERR Dumper( $res->[2]->[0] );
ok( $res->[2]->[0] =~ m%<span id="languages"></span>%, ' Language icons found' )
or print STDERR Dumper( $res->[2]->[0] );
@ -41,8 +40,7 @@ ok(
),
'Get Menu'
);
ok( $res->[2]->[0] =~ /<span trmsg="9">/,
'Rejected with PE_FIRSTACCESS' )
ok( $res->[2]->[0] =~ /<span trmsg="9">/, 'Rejected with PE_FIRSTACCESS' )
or print STDERR Dumper( $res->[2]->[0] );
ok( $res->[2]->[0] =~ m%<span id="languages"></span>%, ' Language icons found' )
or print STDERR Dumper( $res->[2]->[0] );
@ -73,9 +71,10 @@ ok(
),
'Auth query'
);
ok( $res->[2]->[0] =~ /<span trmsg="5">/,
'jdoe rejected with PE_BADCREDENTIALS' )
or print STDERR Dumper( $res->[2]->[0] );
ok(
$res->[2]->[0] =~ /<span trmsg="5">/,
'jdoe rejected with PE_BADCREDENTIALS'
) or print STDERR Dumper( $res->[2]->[0] );
ok( $res->[2]->[0] =~ m%<span trspan="connect">Connect</span>%,
'Found connect button' )
or print STDERR Dumper( $res->[2]->[0] );
@ -93,9 +92,10 @@ ok(
'Auth query'
);
count(1);
ok( $res->[2]->[0] =~ /<span trmsg="5">/,
'dwho rejected with PE_BADCREDENTIALS' )
or print STDERR Dumper( $res->[2]->[0] );
ok(
$res->[2]->[0] =~ /<span trmsg="5">/,
'dwho rejected with PE_BADCREDENTIALS'
) or print STDERR Dumper( $res->[2]->[0] );
count(1);
ok( $res->[2]->[0] =~ m%<span trspan="connect">Connect</span>%,
'Found connect button' )

View File

@ -10,8 +10,7 @@ require 't/test-lib.pm';
my $res;
my $client = LLNG::Manager::Test->new(
{
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
useSafeJail => 1,
@ -31,8 +30,7 @@ ok( $app = Lemonldap::NG::Handler::Server->run( $client->ini ), 'App' );
count(1);
ok(
$res = $app->(
{
$res = $app->( {
'HTTP_ACCEPT' => 'text/html',
'SCRIPT_NAME' => '/',
'SERVER_NAME' => '127.0.0.1',
@ -69,8 +67,7 @@ expectForm( $res, undef, undef, 'url' );
count(1);
ok(
$res = $app->(
{
$res = $app->( {
'HTTP_ACCEPT' => 'text/html',
'SCRIPT_NAME' => '/',
'SERVER_NAME' => '127.0.0.1',

View File

@ -72,9 +72,10 @@ m#<img class="renewcaptchaclick" src="/static/common/icons/arrow_refresh.png" al
( $host, $url, $query ) =
expectForm( $res, '#', undef, 'user', 'password', 'token' );
ok( $res->[2]->[0] =~ /<span trmsg="5">/,
'dalek rejected with PE_BADCREDENTIALS' )
or print STDERR Dumper( $res->[2]->[0] );
ok(
$res->[2]->[0] =~ /<span trmsg="5">/,
'dalek rejected with PE_BADCREDENTIALS'
) or print STDERR Dumper( $res->[2]->[0] );
# Try to authenticate
# -------------------

View File

@ -52,9 +52,10 @@ ok(
( $host, $url, $query ) =
expectForm( $res, '#', undef, 'user', 'password', 'token' );
ok( $res->[2]->[0] =~ /<span trmsg="5">/,
'dalek rejected with PE_BADCREDENTIALS' )
or print STDERR Dumper( $res->[2]->[0] );
ok(
$res->[2]->[0] =~ /<span trmsg="5">/,
'dalek rejected with PE_BADCREDENTIALS'
) or print STDERR Dumper( $res->[2]->[0] );
# Try to authenticate
# -------------------

View File

@ -235,7 +235,8 @@ m%<span notif=\'testref\' epoch=\'(\d{10})\' class="btn btn-success" role="butto
);
ok( $json = eval { from_json( $res->[2]->[0] ) }, 'Response is JSON' )
or print STDERR "$@\n" . Dumper($res);
ok( $json->{error} eq 'Missing epoch parameter', ' Missing epoch parameter' )
ok( $json->{error} eq 'Missing epoch parameter',
' Missing epoch parameter' )
or explain( $json, "Missing epoch parameter" );
# Bad request

View File

@ -50,8 +50,11 @@ ok(
);
count(1);
ok( $res->[2]->[0] =~ m%<h3 trspan="logoutFromOtherApp">logoutFromOtherApp</h3>%, 'Found Logout Forward page' )
or explain( $res->[2]->[0], "PE_LOGOUT_OK" );
ok(
$res->[2]->[0] =~
m%<h3 trspan="logoutFromOtherApp">logoutFromOtherApp</h3>%,
'Found Logout Forward page'
) or explain( $res->[2]->[0], "PE_LOGOUT_OK" );
count(1);
$client->logout( $idd[0] );

View File

@ -114,8 +114,7 @@ SKIP: {
),
'Auth query'
);
ok( $res->[2]->[0] =~ /<span trspan="enterTotpCode">/,
'Enter TOTP code' )
ok( $res->[2]->[0] =~ /<span trspan="enterTotpCode">/, 'Enter TOTP code' )
or print STDERR Dumper( $res->[2]->[0] );
count(2);
@ -170,8 +169,7 @@ SKIP: {
),
'Auth query'
);
ok( $res->[2]->[0] =~ /<span trspan="enterTotpCode">/,
'Enter TOTP code' )
ok( $res->[2]->[0] =~ /<span trspan="enterTotpCode">/, 'Enter TOTP code' )
or print STDERR Dumper( $res->[2]->[0] );
count(2);

View File

@ -51,9 +51,10 @@ ok(
'Auth query'
);
count(1);
ok( $res->[2]->[0] =~ /<span trmsg="5">/,
'dwho rejected with PE_BADCREDENTIALS' )
or print STDERR Dumper( $res->[2]->[0] );
ok(
$res->[2]->[0] =~ /<span trmsg="5">/,
'dwho rejected with PE_BADCREDENTIALS'
) or print STDERR Dumper( $res->[2]->[0] );
count(1);
ok( $res->[2]->[0] =~ m%<span trspan="connect">Connect</span>%,
'Found connect button' )

View File

@ -204,10 +204,8 @@ ok(
m%<a href="http://auth.example.com/removeOther\?token=\d{10}_\d+" onclick="_go=0" trspan="removeOtherSessions"></a>%,
'Link found'
) or explain( $res->[2]->[0], 'Link found' );
ok(
$res->[2]->[0] =~ m%action="http://test1.example.com/"%,
'action found'
) or explain( $res->[2]->[0], 'action found' );
ok( $res->[2]->[0] =~ m%action="http://test1.example.com/"%, 'action found' )
or explain( $res->[2]->[0], 'action found' );
count(4);
clean_sessions();

View File

@ -177,9 +177,11 @@ ok( $res->[2]->[0] =~ m%<td scope="row">Macro_1</td>%, 'Found uid' )
ok( $nbr = ( $res->[2]->[0] =~ s%<td scope="row">Macro_1</td>%%g ),
'Found two well computed macros' )
or explain( $res->[2]->[0], 'Macros not well computed' );
ok( $res->[2]->[0] =~ m%<div class="col">authGroup</div>%, 'Found group "authGroup"' )
ok( $res->[2]->[0] =~ m%<div class="col">authGroup</div>%,
'Found group "authGroup"' )
or explain( $res->[2]->[0], 'Group "authgroup"' );
ok( $res->[2]->[0] =~ m%<div class="col">realAuthGroup</div>%, 'Found group "realAuthGroup"' )
ok( $res->[2]->[0] =~ m%<div class="col">realAuthGroup</div>%,
'Found group "realAuthGroup"' )
or explain( $res->[2]->[0], 'Found group "realAuthGroup"' );
count(7);

View File

@ -253,7 +253,8 @@ ok( $res->[2]->[0] =~ m%<td scope="row">dwho</td>%, 'Found dwho' )
or explain( $res->[2]->[0], 'Macro Value dwho' );
ok( $res->[2]->[0] =~ m%<td scope="row">array</td>%, 'Found empty macro' )
or explain( $res->[2]->[0], 'Macro: empty' );
ok( $res->[2]->[0] =~ m%<td scope="row">real_array</td>%, 'Found empty real_macro' )
ok( $res->[2]->[0] =~ m%<td scope="row">real_array</td>%,
'Found empty real_macro' )
or explain( $res->[2]->[0], 'Macro: empty real' );
count(9);

View File

@ -61,10 +61,16 @@ ok( $res->[2]->[0] =~ qr%<span id="languages"></span>%, 'Found language flags' )
expectAuthenticatedAs( $res, 'rtyler' );
ok( $res->[2]->[0] !~ m%contextSwitching_ON%, 'Connected as dwho' )
or print STDERR Dumper( $res->[2]->[0] );
ok( $res->[2]->[0] =~ qr%href="http://test1\.example\.com/" title="Application Test 1"%, 'Found test1 & title' )
or print STDERR Dumper( $res->[2]->[0] );
ok( $res->[2]->[0] =~ qr%href="http://test2\.example\.com/" title="A nice application!"%, 'Found test2 & title' )
or print STDERR Dumper( $res->[2]->[0] );
ok(
$res->[2]->[0] =~
qr%href="http://test1\.example\.com/" title="Application Test 1"%,
'Found test1 & title'
) or print STDERR Dumper( $res->[2]->[0] );
ok(
$res->[2]->[0] =~
qr%href="http://test2\.example\.com/" title="A nice application!"%,
'Found test2 & title'
) or print STDERR Dumper( $res->[2]->[0] );
my @appdesc = ( $res->[2]->[0] =~ qr%class="appdesc% );
ok( @appdesc == 1, 'Found only one description' )

View File

@ -32,6 +32,7 @@ TODO: {
local $TODO = "Not yet fully cleaned";
fail "Unable to really destroy a portal object for now";
# Test with initialization
#my $p = Lemonldap::NG::Portal::Main->new();
#$p->init($ini);