Merge branch 'feature-new-location-2325' into v2.0
This commit is contained in:
commit
a6bcf1b51b
1
debian/control
vendored
1
debian/control
vendored
|
@ -282,6 +282,7 @@ Depends: ${misc:Depends},
|
|||
liblemonldap-ng-handler-perl (= ${binary:Version}),
|
||||
libtext-unidecode-perl,
|
||||
libregexp-assemble-perl,
|
||||
liblist-moreutils-perl,
|
||||
libemail-date-format-perl
|
||||
Recommends: gsfonts,
|
||||
libcrypt-openssl-bignum-perl,
|
||||
|
|
|
@ -5,4 +5,5 @@ Attacks and Protection
|
|||
:maxdepth: 1
|
||||
|
||||
bruteforceprotection
|
||||
newlocationwarning
|
||||
safejail
|
||||
|
|
55
doc/sources/admin/newlocationwarning.rst
Normal file
55
doc/sources/admin/newlocationwarning.rst
Normal file
|
@ -0,0 +1,55 @@
|
|||
|image0|
|
||||
|
||||
New Location Warning Plugin
|
||||
===========================
|
||||
|
||||
Presentation
|
||||
------------
|
||||
|
||||
This plugin allows LL::NG to send a warning message to the user's email
|
||||
address when their account connects from a new location.
|
||||
|
||||
By default, the location is the IP address. Meaning that any connection from a
|
||||
different IP address will send a warning. If this is not what you want, you can
|
||||
change the way location is computed (see below).
|
||||
|
||||
Following steps are performed when the user logs in
|
||||
|
||||
#. Extract the location from session info (by default, the IP address is used)
|
||||
#. Compare the current location to the previous locations saved in history
|
||||
#. If it is a new location, send an email to warn the user
|
||||
#. On the next login, the location will no longer be considered as new
|
||||
|
||||
The very first time a user logs in (empty login history), no email is sent.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Just enable it in the Manager (section ``General Parameters`` > ``Advanced parameters`` > ``Security`` > ``New location warning``:
|
||||
|
||||
- **Activation**: Enable this plugin *(default: disabled)*
|
||||
- **Session attribute containing location**: Indicate the session attribute you are using to store the location. You can use `ipAddr`, or a custom macro.
|
||||
- **Session attribute to display**: By default, the raw value of the location session attribute is displayed in the warning email. If you want to use a different session attribute in the warning email, you can specify it here.
|
||||
- **Maximum number of locations to consider**: By default, all previous value of the location are checked
|
||||
- **Session mail attribute**: Session key containing mail address *(default: mail)*
|
||||
- **Warning mail subject**: Subject of the email containing the warning
|
||||
- **Warning mail content**: Content of the email containing the warning
|
||||
|
||||
.. warning::
|
||||
If you use a macro instead of ``ipAddr`` as the location value, be sure to add the name of this macro to
|
||||
|
||||
General Parameters » Plugins » Login History » Session data to store
|
||||
|
||||
Otherwise, the value of the macro will not be remembered across logins
|
||||
|
||||
Email body variables
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Following variables are available in the Warning email body:
|
||||
|
||||
* ``$location``: the location value, from **Session attribute to display**
|
||||
* ``$date``: the date of login
|
||||
* ``$ua``: the full user agent string
|
||||
|
||||
.. |image0| image:: /documentation/beta.png
|
||||
:width: 100px
|
|
@ -285,12 +285,13 @@ Name Description
|
|||
:doc:`Grant Sessions<grantsession>` Rules to apply before allowing a user to open a session
|
||||
:doc:`Impersonation<impersonation>` [11]_\ |new| Allow users to use another identity
|
||||
:doc:`Find user<finduser>` [12]_\ |new| Search for user account
|
||||
:doc:`Notifications system<notifications>` DIsplay a message during log in process
|
||||
:doc:`NewLocationWarning<newlocationwarning>` [13]_\ |beta| Send an email when user sign in from a new location
|
||||
:doc:`Notifications system<notifications>` Display a message during log in process
|
||||
:doc:`Portal Status<status>` Experimental portal status page
|
||||
:doc:`Public pages<public_pages>` Enable public pages system
|
||||
:doc:`Refresh session API<refreshsessionapi>` [13]_ Plugin that provides an API to refresh a user session
|
||||
:doc:`Refresh session API<refreshsessionapi>` [14]_ Plugin that provides an API to refresh a user session
|
||||
:doc:`Reset password by mail<resetpassword>` Send a mail to reset its password
|
||||
:doc:`Reset certificate by mail<resetcertificate>` [14]_\ |new| Allow users to reset their certificate
|
||||
:doc:`Reset certificate by mail<resetcertificate>` [15]_\ |new| Allow users to reset their certificate
|
||||
:doc:`REST services<restservices>` |new| REST server for :doc:`Proxy<authproxy>`
|
||||
:doc:`SOAP services<soapservices>` |deprecated| SOAP server for :doc:`Proxy<authproxy>`
|
||||
:doc:`Stay connected<stayconnected>` |new| Enable persistent connection on same browser
|
||||
|
@ -308,12 +309,12 @@ Handlers are software control agents to be installed on your web servers
|
|||
==================================================================== ========== ============================================================= =========================================== ================================================================================== =============================================== ======================================================================================================================
|
||||
Handler type Apache LLNG FastCGI/uWSGI server (Nginx, or :doc:`SSOaaS<ssoaas>`) `Plack servers <https://plackperl.org>`__ Node.js ( `express apps <http://expressjs.com/>`__\ or :doc:`SSOaaS<ssoaas>`) :doc:`Self protected apps<selfmadeapplication>` Comment
|
||||
==================================================================== ========== ============================================================= =========================================== ================================================================================== =============================================== ======================================================================================================================
|
||||
Main *(default handler)* ✔ ✔ ✔ :doc:`Partial<nodehandler>` ** [15]_ ** ✔
|
||||
Main *(default handler)* ✔ ✔ ✔ :doc:`Partial<nodehandler>` ** [16]_ ** ✔
|
||||
:doc:`AuthBasic<handlerauthbasic>` ✔ ✔ ✔ ✔ Designed for some server-to-server applications
|
||||
:doc:`CDA<cda>` ✔ ✔ ✔ ✔ For Cross Domain Authentication
|
||||
:doc:`DevOps<devopshandler>` (:doc:`SSOaaS<ssoaas>`) |new| ✔ ✔ ✔ ✔ Allows application developers to define their own rules and headers inside their applications
|
||||
:doc:`DevOpsST<devopssthandler>` (:doc:`SSOaaS<ssoaas>`) |new| ✔ ✔ ✔ ✔ Enables both :doc:`DevOps<devopshandler>` and :doc:`Service Token<servertoserver>`
|
||||
:doc:`OAuth2<oauth2handler>` [16]_\ |new| ✔ ✔ ✔ ✔ Uses OpenID Connect/OAuth2 access token to check authentication and authorization, can be used to protect Web Services
|
||||
:doc:`OAuth2<oauth2handler>` [17]_\ |new| ✔ ✔ ✔ ✔ Uses OpenID Connect/OAuth2 access token to check authentication and authorization, can be used to protect Web Services
|
||||
:doc:`Secure Token<securetoken>` ✔ ✔ ✔ Designed to secure exchanges between a LLNG reverse-proxy and a remote app
|
||||
:doc:`Service Token<servertoserver>` |new| *(Server-to-Server)* ✔ ✔ ✔ ✔ ✔ Designed to permit underlying requests *(API-Based Infrastructure)*
|
||||
:doc:`Zimbra PreAuth<applications/zimbra>` ✔ ✔ ✔
|
||||
|
@ -598,18 +599,22 @@ by your language code):
|
|||
2.0.11
|
||||
|
||||
.. [13]
|
||||
:doc:`NewLocationWarning<newlocationwarning>` is available
|
||||
with LLNG ≥ 2.0.14
|
||||
|
||||
.. [14]
|
||||
:doc:`Refresh session API plugin<refreshsessionapi>` is available
|
||||
with LLNG ≥ 2.0.7
|
||||
|
||||
.. [14]
|
||||
.. [15]
|
||||
:doc:`Reset certificate by mail plugin<resetcertificate>` is
|
||||
available with LLNG ≥ 2.0.7
|
||||
|
||||
.. [15]
|
||||
.. [16]
|
||||
:doc:`Node.js handler<nodehandler>` has not yet reached the same
|
||||
level of functionalities
|
||||
|
||||
.. [16]
|
||||
.. [17]
|
||||
:doc:`OAuth2 Handler<oauth2handler>` is available with LLNG ≥ 2.0.4
|
||||
|
||||
.. |image0| image:: /icons/kthememgr.png
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35)
|
||||
.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40)
|
||||
.\"
|
||||
.\" Standard preamble:
|
||||
.\" ========================================================================
|
||||
|
@ -133,7 +133,7 @@
|
|||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "llng-fastcgi-server 8"
|
||||
.TH llng-fastcgi-server 8 "2021-07-03" "perl v5.30.0" "User Contributed Perl Documentation"
|
||||
.TH llng-fastcgi-server 8 "2021-08-10" "perl v5.32.1" "User Contributed Perl Documentation"
|
||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||
.\" way too many mistakes in technical documents.
|
||||
.if n .ad l
|
||||
|
|
|
@ -31,7 +31,7 @@ use constant DEFAULTCONFBACKENDOPTIONS => (
|
|||
);
|
||||
our $hashParameters = qr/^(?:(?:l(?:o(?:ca(?:lSessionStorageOption|tionRule)|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|(?:(?:d(?:emo|bi)|webID)ExportedVa|exported(?:Heade|Va)|issuerDBGetParamete)r|f(?:indUser(?:Exclud|Search)ingAttribute|acebookExportedVar)|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|ScopeRule|Macro)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node))|penIdExportedVars)|c(?:as(?:A(?:ppMetaData(?:(?:ExportedVar|Option|Macro)s|Node)|ttributes)|S(?:rvMetaData(?:(?:ExportedVar|Option)s|Node)|torageOptions))|(?:ustom(?:Plugins|Add)Param|heckUserHiddenHeader|ombModule)s)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option|Macro)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars|fExtra)|a(?:(?:daptativeAuthenticationLevelR|ut(?:hChoiceMod|oSigninR))ules|pplicationList)|p(?:ersistentStorageOptions|o(?:rtalSkinRules|st))|v(?:hostOptions|irtualHost)|S(?:MTPTLSOpts|SLVarIf))$/;
|
||||
our $arrayParameters = qr/^mySessionAuthorizedRWKeys$/;
|
||||
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)|f(?:RemovedUseNotif|OnlyUpgrade)|kip(?:Upgrade|Renew)Confirmation|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:A(?:llow(?:(?:ClientCredentials|Password)Grant|Offline)|ccessToken(?:Claims|JWT))|Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration|OnlyDeclaredScopes)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|c(?:a(?:sS(?:rvMetaDataOptions(?:Gateway|Renew)|trictMatching)|ptcha_(?:register|login|mail)_enabled)|o(?:ntextSwitching(?:Allowed2fModifications|StopWithLogout)|mpactConf|rsEnabled)|heck(?:DevOps(?:D(?:isplayNormalizedHeaders|ownload))?|State|User|XSS)|rowdsec|da)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|CertificateResetByMail|GeneratePassword|PasswordPolicy)|E(?:rrorOn(?:ExpiredSession|MailNotFound)|nablePasswordDisplay)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:G(?:roup(?:DecodeSearchedValu|Recursiv)|etUserBeforePasswordChang)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|no(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|re(?:st(?:(?:Password|Session|Config|Auth)Server|ExportSecretKeys)|freshSessions)|br(?:uteForceProtection(?:IncrementalTempo)?|owsersDontStorePassword)|d(?:is(?:ablePersistentStorage|playSessionId)|biDynamicHashEnabled)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|to(?:tp2fUserCanRemoveKey|kenUseGlobalStorage)|g(?:roupsBeforeMacros|lobalLogoutTimer)|a(?:voidAssignment|ctiveTimer)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|krb(?:RemoveDomain|ByJs)|(?:wsdlServ|findUs)er)$/;
|
||||
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)|f(?:RemovedUseNotif|OnlyUpgrade)|kip(?:Upgrade|Renew)Confirmation|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:A(?:llow(?:(?:ClientCredentials|Password)Grant|Offline)|ccessToken(?:Claims|JWT))|Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration|OnlyDeclaredScopes)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|c(?:a(?:sS(?:rvMetaDataOptions(?:Gateway|Renew)|trictMatching)|ptcha_(?:register|login|mail)_enabled)|o(?:ntextSwitching(?:Allowed2fModifications|StopWithLogout)|mpactConf|rsEnabled)|heck(?:DevOps(?:D(?:isplayNormalizedHeaders|ownload))?|State|User|XSS)|rowdsec|da)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|CertificateResetByMail|GeneratePassword|PasswordPolicy)|E(?:rrorOn(?:ExpiredSession|MailNotFound)|nablePasswordDisplay)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:G(?:roup(?:DecodeSearchedValu|Recursiv)|etUserBeforePasswordChang)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|n(?:o(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|ewLocationWarning)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|re(?:st(?:(?:Password|Session|Config|Auth)Server|ExportSecretKeys)|freshSessions)|br(?:uteForceProtection(?:IncrementalTempo)?|owsersDontStorePassword)|d(?:is(?:ablePersistentStorage|playSessionId)|biDynamicHashEnabled)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|to(?:tp2fUserCanRemoveKey|kenUseGlobalStorage)|g(?:roupsBeforeMacros|lobalLogoutTimer)|a(?:voidAssignment|ctiveTimer)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|krb(?:RemoveDomain|ByJs)|(?:wsdlServ|findUs)er)$/;
|
||||
|
||||
our @sessionTypes = ( 'remoteGlobal', 'global', 'localSession', 'persistent', 'saml', 'oidc', 'cas' );
|
||||
|
||||
|
|
|
@ -186,8 +186,11 @@ sub defaultValues {
|
|||
'multiValuesSeparator' => '; ',
|
||||
'mySessionAuthorizedRWKeys' =>
|
||||
[ '_appsListOrder', '_oidcConnectedRP', '_oidcConsents' ],
|
||||
'notificationDefaultCond' => '',
|
||||
'notificationServerPOST' => 1,
|
||||
'newLocationWarningLocationAttribute' => 'ipAddr',
|
||||
'newLocationWarningLocationDisplayAttribute' => '',
|
||||
'newLocationWarningMaxValues' => '0',
|
||||
'notificationDefaultCond' => '',
|
||||
'notificationServerPOST' => 1,
|
||||
'notificationServerSentAttributes' =>
|
||||
'uid reference date title subtitle text check',
|
||||
'notificationsMaxRetrieve' => 3,
|
||||
|
|
|
@ -2067,6 +2067,31 @@ m[^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
|||
[ '_appsListOrder', '_oidcConnectedRP', '_oidcConsents' ],
|
||||
'type' => 'array'
|
||||
},
|
||||
'newLocationWarning' => {
|
||||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
},
|
||||
'newLocationWarningLocationAttribute' => {
|
||||
'default' => 'ipAddr',
|
||||
'type' => 'text'
|
||||
},
|
||||
'newLocationWarningLocationDisplayAttribute' => {
|
||||
'default' => '',
|
||||
'type' => 'text'
|
||||
},
|
||||
'newLocationWarningMailAttribute' => {
|
||||
'type' => 'text'
|
||||
},
|
||||
'newLocationWarningMailBody' => {
|
||||
'type' => 'longtext'
|
||||
},
|
||||
'newLocationWarningMailSubject' => {
|
||||
'type' => 'text'
|
||||
},
|
||||
'newLocationWarningMaxValues' => {
|
||||
'default' => '0',
|
||||
'type' => 'int'
|
||||
},
|
||||
'nginxCustomHandlers' => {
|
||||
'keyTest' => qr/^\w+$/,
|
||||
'msgFail' => '__badPerlPackageName__',
|
||||
|
|
|
@ -579,6 +579,38 @@ sub attributes {
|
|||
default => '^[*\w]+$',
|
||||
documentation => 'Regular expression to validate parameters',
|
||||
},
|
||||
newLocationWarning => {
|
||||
default => 0,
|
||||
type => 'bool',
|
||||
documentation => 'Enable New Location Warning',
|
||||
},
|
||||
newLocationWarningLocationAttribute => {
|
||||
type => 'text',
|
||||
default => 'ipAddr',
|
||||
documentation => 'New location session attribute',
|
||||
},
|
||||
newLocationWarningLocationDisplayAttribute => {
|
||||
type => 'text',
|
||||
default => '',
|
||||
documentation => 'New location session attribute for user display',
|
||||
},
|
||||
newLocationWarningMaxValues => {
|
||||
type => 'int',
|
||||
default => '0',
|
||||
documentation => 'How many previous locations should be compared',
|
||||
},
|
||||
newLocationWarningMailAttribute => {
|
||||
type => 'text',
|
||||
documentation => 'New location warning mail session attribute',
|
||||
},
|
||||
newLocationWarningMailBody => {
|
||||
type => 'longtext',
|
||||
documentation => 'Mail body for new location warning',
|
||||
},
|
||||
newLocationWarningMailSubject=> {
|
||||
type => 'text',
|
||||
documentation => 'Mail subject for new location warning',
|
||||
},
|
||||
globalLogoutRule => {
|
||||
type => 'boolOrExpr',
|
||||
default => 0,
|
||||
|
|
|
@ -1038,11 +1038,26 @@ sub tree {
|
|||
{
|
||||
title => 'CrowdSecPlugin',
|
||||
help => 'crowdsec.html',
|
||||
form => 'simpleInputContainer',
|
||||
nodes => [
|
||||
'crowdsec', 'crowdsecAction',
|
||||
'crowdsecUrl', 'crowdsecKey',
|
||||
],
|
||||
},
|
||||
{
|
||||
title => 'newLocationWarnings',
|
||||
help => 'newlocationwarning.html',
|
||||
form => 'simpleInputContainer',
|
||||
nodes => [
|
||||
'newLocationWarning',
|
||||
'newLocationWarningLocationAttribute',
|
||||
'newLocationWarningLocationDisplayAttribute',
|
||||
'newLocationWarningMaxValues',
|
||||
'newLocationWarningMailAttribute',
|
||||
'newLocationWarningMailSubject',
|
||||
'newLocationWarningMailBody'
|
||||
]
|
||||
},
|
||||
{
|
||||
title => 'bruteForceAttackProtection',
|
||||
help => 'bruteforceprotection.html',
|
||||
|
|
|
@ -180,8 +180,8 @@
|
|||
"cfgLog":"Summary",
|
||||
"cfgVersion":"عملية ضبط الإصدارات",
|
||||
"checkDevOps":"تفعيل",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkState":"تفعيل",
|
||||
"checkStateSecret":"سر مشترك",
|
||||
"checkUser":"تفعيل",
|
||||
|
@ -568,6 +568,14 @@
|
|||
"newEntry":"أنتري جديد",
|
||||
"newGrantRule":"قاعدة منح جديدة",
|
||||
"newHost":"خادم جديد",
|
||||
"newLocationWarning":"Activation",
|
||||
"newLocationWarningLocationAttribute":"Session attribute containing location",
|
||||
"newLocationWarningLocationDisplayAttribute":"Session attribute to display",
|
||||
"newLocationWarningMailAttribute":"Session mail attribute",
|
||||
"newLocationWarningMailBody":"Warning mail content",
|
||||
"newLocationWarningMailSubject":"Warning mail subject",
|
||||
"newLocationWarningMaxValues":"Maximum number of locations to consider",
|
||||
"newLocationWarnings":"New location warning",
|
||||
"newPost":"استمارة وظيفة replay جديدة",
|
||||
"newPostVar":"متغير جديد",
|
||||
"newRSAKey":"مفاتيح جديدة",
|
||||
|
@ -1210,4 +1218,4 @@
|
|||
"yubikey2fUrl":"خدمة أل يو أر ل",
|
||||
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
|
||||
"zeroConfExplanations":"لا يحتوي الخادم على إعدادات. استخدام قالب لحفظ الأول"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,8 +180,8 @@
|
|||
"cfgLog":"Summary",
|
||||
"cfgVersion":"Configuration version",
|
||||
"checkDevOps":"Activation",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkState":"Activation",
|
||||
"checkStateSecret":"Shared secret",
|
||||
"checkUser":"Activation",
|
||||
|
@ -568,6 +568,14 @@
|
|||
"newEntry":"New entry",
|
||||
"newGrantRule":"New grant rule",
|
||||
"newHost":"New host",
|
||||
"newLocationWarning":"Activation",
|
||||
"newLocationWarningLocationAttribute":"Session attribute containing location",
|
||||
"newLocationWarningLocationDisplayAttribute":"Session attribute to display",
|
||||
"newLocationWarningMailAttribute":"Session mail attribute",
|
||||
"newLocationWarningMailBody":"Warning mail content",
|
||||
"newLocationWarningMailSubject":"Warning mail subject",
|
||||
"newLocationWarningMaxValues":"Maximum number of locations to consider",
|
||||
"newLocationWarnings":"New location warning",
|
||||
"newPost":"New form replay",
|
||||
"newPostVar":"New variable",
|
||||
"newRSAKey":"New keys",
|
||||
|
@ -1210,4 +1218,4 @@
|
|||
"yubikey2fUrl":"Service URL",
|
||||
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
|
||||
"zeroConfExplanations":"Server has no configuration. Use template to save the first."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,8 +180,8 @@
|
|||
"cfgLog":"Summary",
|
||||
"cfgVersion":"Configuration version",
|
||||
"checkDevOps":"Activation",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkState":"Activation",
|
||||
"checkStateSecret":"Shared secret",
|
||||
"checkUser":"Activation",
|
||||
|
@ -568,6 +568,14 @@
|
|||
"newEntry":"New entry",
|
||||
"newGrantRule":"New grant rule",
|
||||
"newHost":"New host",
|
||||
"newLocationWarning":"Activation",
|
||||
"newLocationWarningLocationAttribute":"Session attribute containing location",
|
||||
"newLocationWarningLocationDisplayAttribute":"Session attribute to display",
|
||||
"newLocationWarningMailAttribute":"Session mail attribute",
|
||||
"newLocationWarningMailBody":"Warning mail content",
|
||||
"newLocationWarningMailSubject":"Warning mail subject",
|
||||
"newLocationWarningMaxValues":"Maximum number of locations to consider",
|
||||
"newLocationWarnings":"New location warning",
|
||||
"newPost":"New form replay",
|
||||
"newPostVar":"New variable",
|
||||
"newRSAKey":"New keys",
|
||||
|
|
|
@ -180,8 +180,8 @@
|
|||
"cfgLog":"Sumario",
|
||||
"cfgVersion":"Configuration version",
|
||||
"checkDevOps":"Activación",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkState":"Activación",
|
||||
"checkStateSecret":"Secreto compartido",
|
||||
"checkUser":"Activación",
|
||||
|
@ -568,6 +568,14 @@
|
|||
"newEntry":"Nueva entrada",
|
||||
"newGrantRule":"Nueva regla de admisión",
|
||||
"newHost":"Nuevo host",
|
||||
"newLocationWarning":"Activation",
|
||||
"newLocationWarningLocationAttribute":"Session attribute containing location",
|
||||
"newLocationWarningLocationDisplayAttribute":"Session attribute to display",
|
||||
"newLocationWarningMailAttribute":"Session mail attribute",
|
||||
"newLocationWarningMailBody":"Warning mail content",
|
||||
"newLocationWarningMailSubject":"Warning mail subject",
|
||||
"newLocationWarningMaxValues":"Maximum number of locations to consider",
|
||||
"newLocationWarnings":"New location warning",
|
||||
"newPost":"New form replay",
|
||||
"newPostVar":"Nueva variable",
|
||||
"newRSAKey":"Nuevas claves",
|
||||
|
@ -1210,4 +1218,4 @@
|
|||
"yubikey2fUrl":"Service URL",
|
||||
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
|
||||
"zeroConfExplanations":"Server has no configuration. Use template to save the first."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,8 +180,8 @@
|
|||
"cfgLog":"Résumé",
|
||||
"cfgVersion":"Version de la configuration",
|
||||
"checkDevOps":"Activation",
|
||||
"checkDevOpsDownload":"Télécharger un fichier",
|
||||
"checkDevOpsDisplayNormalizedHeaders":"Afficher les entêtes normalisés",
|
||||
"checkDevOpsDownload":"Télécharger un fichier",
|
||||
"checkState":"Activation",
|
||||
"checkStateSecret":"Secret partagé",
|
||||
"checkUser":"Activation",
|
||||
|
@ -568,6 +568,14 @@
|
|||
"newEntry":"Nouvelle entrée",
|
||||
"newGrantRule":"Nouvelle règle d'accès",
|
||||
"newHost":"Nouvel hôte",
|
||||
"newLocationWarning":"Activation",
|
||||
"newLocationWarningLocationAttribute":"Attribut de session contenant la localisation",
|
||||
"newLocationWarningLocationDisplayAttribute":"Attribut de session à afficher",
|
||||
"newLocationWarningMailAttribute":"Attribut utilisateur contenant le mail ",
|
||||
"newLocationWarningMailBody":"Contenu du mail d'avertissement",
|
||||
"newLocationWarningMailSubject":"Sujet du mail d'avertissement",
|
||||
"newLocationWarningMaxValues":"Nombre maximum de localisations à mémoriser",
|
||||
"newLocationWarnings":"Avertissement de nouvelle connexion",
|
||||
"newPost":"Nouveau rejeu de formulaire",
|
||||
"newPostVar":"Nouvelle variable",
|
||||
"newRSAKey":"Nouvelles clefs",
|
||||
|
|
|
@ -180,8 +180,8 @@
|
|||
"cfgLog":"Summary",
|
||||
"cfgVersion":"Versione configurazione",
|
||||
"checkDevOps":"Activation",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkState":"Attivazione",
|
||||
"checkStateSecret":"Segreto condiviso",
|
||||
"checkUser":"Attivazione",
|
||||
|
@ -568,6 +568,14 @@
|
|||
"newEntry":"Nuova entrata",
|
||||
"newGrantRule":"Nuova regola di autorizzazione",
|
||||
"newHost":"Nuovo host",
|
||||
"newLocationWarning":"Activation",
|
||||
"newLocationWarningLocationAttribute":"Session attribute containing location",
|
||||
"newLocationWarningLocationDisplayAttribute":"Session attribute to display",
|
||||
"newLocationWarningMailAttribute":"Session mail attribute",
|
||||
"newLocationWarningMailBody":"Warning mail content",
|
||||
"newLocationWarningMailSubject":"Warning mail subject",
|
||||
"newLocationWarningMaxValues":"Maximum number of locations to consider",
|
||||
"newLocationWarnings":"New location warning",
|
||||
"newPost":"Nuovo formulario di risposta",
|
||||
"newPostVar":"Nuova variabile",
|
||||
"newRSAKey":"Nuove chiavi",
|
||||
|
@ -1210,4 +1218,4 @@
|
|||
"yubikey2fUrl":"URL del servizio",
|
||||
"yubikey2fUserCanRemoveKey":"Autorizza l'utente a rimuovere la Yubikey",
|
||||
"zeroConfExplanations":"Il server non ha alcuna configurazione. Utilizza il modello per salvare il primo."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,8 +180,8 @@
|
|||
"cfgLog":"Podsumowanie",
|
||||
"cfgVersion":"Wersja konfiguracji",
|
||||
"checkDevOps":"Aktywacja",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkState":"Aktywacja",
|
||||
"checkStateSecret":"Współdzielony sekret",
|
||||
"checkUser":"Aktywacja",
|
||||
|
@ -568,6 +568,14 @@
|
|||
"newEntry":"Nowy wpis",
|
||||
"newGrantRule":"Nowa reguła przyznawania",
|
||||
"newHost":"Nowy host",
|
||||
"newLocationWarning":"Activation",
|
||||
"newLocationWarningLocationAttribute":"Session attribute containing location",
|
||||
"newLocationWarningLocationDisplayAttribute":"Session attribute to display",
|
||||
"newLocationWarningMailAttribute":"Session mail attribute",
|
||||
"newLocationWarningMailBody":"Warning mail content",
|
||||
"newLocationWarningMailSubject":"Warning mail subject",
|
||||
"newLocationWarningMaxValues":"Maximum number of locations to consider",
|
||||
"newLocationWarnings":"New location warning",
|
||||
"newPost":"Nowy formularz powtórzenia",
|
||||
"newPostVar":"Nowa zmienna",
|
||||
"newRSAKey":"Nowe klucze",
|
||||
|
@ -1210,4 +1218,4 @@
|
|||
"yubikey2fUrl":"URL usługi",
|
||||
"yubikey2fUserCanRemoveKey":"Pozwól użytkownikowi usunąć Yubikey",
|
||||
"zeroConfExplanations":"Serwer nie ma konfiguracji. Użyj szablonu, aby zapisać pierwszy."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,8 +180,8 @@
|
|||
"cfgLog":"Özet",
|
||||
"cfgVersion":"Yapılandırma sürümü",
|
||||
"checkDevOps":"Aktivasyon",
|
||||
"checkDevOpsDownload":"Dosyayı indir",
|
||||
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
|
||||
"checkDevOpsDownload":"Dosyayı indir",
|
||||
"checkState":"Aktivasyon",
|
||||
"checkStateSecret":"Paylaşılan sır",
|
||||
"checkUser":"Aktivasyon",
|
||||
|
@ -568,6 +568,14 @@
|
|||
"newEntry":"Yeni kayıt",
|
||||
"newGrantRule":"Yeni imtiyaz kuralı",
|
||||
"newHost":"Yeni konak",
|
||||
"newLocationWarning":"Activation",
|
||||
"newLocationWarningLocationAttribute":"Session attribute containing location",
|
||||
"newLocationWarningLocationDisplayAttribute":"Session attribute to display",
|
||||
"newLocationWarningMailAttribute":"Session mail attribute",
|
||||
"newLocationWarningMailBody":"Warning mail content",
|
||||
"newLocationWarningMailSubject":"Warning mail subject",
|
||||
"newLocationWarningMaxValues":"Maximum number of locations to consider",
|
||||
"newLocationWarnings":"New location warning",
|
||||
"newPost":"Yeni form tekrarı",
|
||||
"newPostVar":"Yeni değişken",
|
||||
"newRSAKey":"Yeni anahtarlar",
|
||||
|
@ -1210,4 +1218,4 @@
|
|||
"yubikey2fUrl":"Servis URL'si",
|
||||
"yubikey2fUserCanRemoveKey":"Yubikey'i kaldırmak için kullanıcıya izin ver",
|
||||
"zeroConfExplanations":"Sunucunun yapılandırması yok. Şimdi bir tane kaydetmek için şablonu kullanın."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,8 +180,8 @@
|
|||
"cfgLog":"Summary",
|
||||
"cfgVersion":"Phiên bản cấu hình",
|
||||
"checkDevOps":"Activation",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkState":"Kích hoạt",
|
||||
"checkStateSecret":"Chia sẻ bí mật",
|
||||
"checkUser":"Kích hoạt",
|
||||
|
@ -568,6 +568,14 @@
|
|||
"newEntry":"Mục nhập mới",
|
||||
"newGrantRule":"Quy tắc cấp mới",
|
||||
"newHost":"Máy chủ mới",
|
||||
"newLocationWarning":"Activation",
|
||||
"newLocationWarningLocationAttribute":"Session attribute containing location",
|
||||
"newLocationWarningLocationDisplayAttribute":"Session attribute to display",
|
||||
"newLocationWarningMailAttribute":"Session mail attribute",
|
||||
"newLocationWarningMailBody":"Warning mail content",
|
||||
"newLocationWarningMailSubject":"Warning mail subject",
|
||||
"newLocationWarningMaxValues":"Maximum number of locations to consider",
|
||||
"newLocationWarnings":"New location warning",
|
||||
"newPost":"Phát lại mẫu mới",
|
||||
"newPostVar":"Biến mới",
|
||||
"newRSAKey":"Khóa mới",
|
||||
|
@ -1210,4 +1218,4 @@
|
|||
"yubikey2fUrl":"Dịch vụ URL",
|
||||
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
|
||||
"zeroConfExplanations":"Máy chủ không có cấu hình. Sử dụng mẫu để lưu đầu tiên. "
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,8 +180,8 @@
|
|||
"cfgLog":"Summary",
|
||||
"cfgVersion":"配置信息",
|
||||
"checkDevOps":"Activation",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkState":"激活",
|
||||
"checkStateSecret":"Shared secret",
|
||||
"checkUser":"激活",
|
||||
|
@ -568,6 +568,14 @@
|
|||
"newEntry":"New entry",
|
||||
"newGrantRule":"New grant rule",
|
||||
"newHost":"New host",
|
||||
"newLocationWarning":"Activation",
|
||||
"newLocationWarningLocationAttribute":"Session attribute containing location",
|
||||
"newLocationWarningLocationDisplayAttribute":"Session attribute to display",
|
||||
"newLocationWarningMailAttribute":"Session mail attribute",
|
||||
"newLocationWarningMailBody":"Warning mail content",
|
||||
"newLocationWarningMailSubject":"Warning mail subject",
|
||||
"newLocationWarningMaxValues":"Maximum number of locations to consider",
|
||||
"newLocationWarnings":"New location warning",
|
||||
"newPost":"New form replay",
|
||||
"newPostVar":"New variable",
|
||||
"newRSAKey":"New keys",
|
||||
|
@ -1210,4 +1218,4 @@
|
|||
"yubikey2fUrl":"Service URL",
|
||||
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
|
||||
"zeroConfExplanations":"Server has no configuration. Use template to save the first."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,8 +180,8 @@
|
|||
"cfgLog":"概要",
|
||||
"cfgVersion":"設定版本",
|
||||
"checkDevOps":"啟用",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
|
||||
"checkDevOpsDownload":"Download file",
|
||||
"checkState":"啟用",
|
||||
"checkStateSecret":"已分享的祕密",
|
||||
"checkUser":"啟用",
|
||||
|
@ -568,6 +568,14 @@
|
|||
"newEntry":"新項目",
|
||||
"newGrantRule":"新授權規則",
|
||||
"newHost":"新主機",
|
||||
"newLocationWarning":"Activation",
|
||||
"newLocationWarningLocationAttribute":"Session attribute containing location",
|
||||
"newLocationWarningLocationDisplayAttribute":"Session attribute to display",
|
||||
"newLocationWarningMailAttribute":"Session mail attribute",
|
||||
"newLocationWarningMailBody":"Warning mail content",
|
||||
"newLocationWarningMailSubject":"Warning mail subject",
|
||||
"newLocationWarningMaxValues":"Maximum number of locations to consider",
|
||||
"newLocationWarnings":"New location warning",
|
||||
"newPost":"新表單重新進行",
|
||||
"newPostVar":"新變數",
|
||||
"newRSAKey":"新金鑰",
|
||||
|
@ -1210,4 +1218,4 @@
|
|||
"yubikey2fUrl":"服務 URL",
|
||||
"yubikey2fUserCanRemoveKey":"允許使用者移除 Yubikey",
|
||||
"zeroConfExplanations":"伺服器未設定。使用飯本來儲存第一個。"
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -120,6 +120,7 @@ lib/Lemonldap/NG/Portal/Plugins/GrantSession.pm
|
|||
lib/Lemonldap/NG/Portal/Plugins/History.pm
|
||||
lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm
|
||||
lib/Lemonldap/NG/Portal/Plugins/MailPasswordReset.pm
|
||||
lib/Lemonldap/NG/Portal/Plugins/NewLocationWarning.pm
|
||||
lib/Lemonldap/NG/Portal/Plugins/Notifications.pm
|
||||
lib/Lemonldap/NG/Portal/Plugins/PublicPages.pm
|
||||
lib/Lemonldap/NG/Portal/Plugins/Refresh.pm
|
||||
|
@ -470,6 +471,7 @@ site/templates/common/mail_certificateReset.tpl
|
|||
site/templates/common/mail_confirm.tpl
|
||||
site/templates/common/mail_footer.tpl
|
||||
site/templates/common/mail_header.tpl
|
||||
site/templates/common/mail_new_location_warning.tpl
|
||||
site/templates/common/mail_password.tpl
|
||||
site/templates/common/mail_register_confirm.tpl
|
||||
site/templates/common/mail_register_done.tpl
|
||||
|
@ -672,6 +674,8 @@ t/61-CrowdSec-warn.t
|
|||
t/61-CrowdSec.t
|
||||
t/61-ForceAuthn.t
|
||||
t/61-GrantSession.t
|
||||
t/61-NewLocationWarning-Custom.t
|
||||
t/61-NewLocationWarning.t
|
||||
t/61-Session-ActivityTimeout.t
|
||||
t/61-Session-Timeout.t
|
||||
t/62-Refresh-plugin.t
|
||||
|
|
|
@ -33,7 +33,8 @@ our @pList = (
|
|||
contextSwitchingRule => '::Plugins::ContextSwitching',
|
||||
decryptValueRule => '::Plugins::DecryptValue',
|
||||
findUser => '::Plugins::FindUser',
|
||||
adaptativeAuthenticationLevelRules =>
|
||||
newLocationWarning => '::Plugins::NewLocationWarning',
|
||||
adaptativeAuthenticationLevelRules =>
|
||||
'::Plugins::AdaptativeAuthenticationLevel',
|
||||
globalLogoutRule => '::Plugins::GlobalLogout',
|
||||
refreshSessions => '::Plugins::Refresh',
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
package Lemonldap::NG::Portal::Plugins::NewLocationWarning;
|
||||
|
||||
use strict;
|
||||
use Mouse;
|
||||
use POSIX qw(strftime);
|
||||
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK);
|
||||
use List::MoreUtils qw/uniq/;
|
||||
|
||||
our $VERSION = '2.0.14';
|
||||
|
||||
has locationAttribute => ( is => 'rw' );
|
||||
has locationDisplayAttribute => ( is => 'rw' );
|
||||
has locationMaxValues => ( is => 'rw' );
|
||||
|
||||
has mailSessionKey => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub {
|
||||
return
|
||||
$_[0]->{conf}->{newLocationWarningMailAttribute}
|
||||
|| $_[0]->{conf}->{mailSessionKey}
|
||||
|| 'mail';
|
||||
}
|
||||
);
|
||||
|
||||
extends qw(
|
||||
Lemonldap::NG::Portal::Lib::SMTP
|
||||
Lemonldap::NG::Portal::Main::Plugin
|
||||
);
|
||||
|
||||
# Entrypoint
|
||||
use constant afterSub => { setLocalGroups => 'checkNewLocation' };
|
||||
use constant endAuth => 'sendWarningEmail';
|
||||
|
||||
sub init {
|
||||
my ($self) = @_;
|
||||
|
||||
if ( $self->conf->{disablePersistentStorage} ) {
|
||||
$self->logger->error(
|
||||
'"NewLocationWarning" plugin enabled WITHOUT persistent session storage"'
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
unless ( $self->conf->{loginHistoryEnabled} ) {
|
||||
$self->logger->error(
|
||||
'"NewLocationWarning" plugin enabled WITHOUT "History" plugin');
|
||||
return 0;
|
||||
}
|
||||
|
||||
$self->locationAttribute( $self->conf->{newLocationWarningLocationAttribute}
|
||||
|| 'ipAddr' );
|
||||
$self->locationDisplayAttribute(
|
||||
$self->conf->{newLocationWarningLocationDisplayAttribute}
|
||||
|| $self->locationAttribute );
|
||||
$self->locationMaxValues( $self->conf->{newLocationWarningMaxValues} || 0 );
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub checkNewLocation {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my $successLogin = $req->sessionInfo->{_loginHistory}->{successLogin} || [];
|
||||
|
||||
my $location = $req->sessionInfo->{ $self->locationAttribute };
|
||||
|
||||
unless ($location) {
|
||||
$self->logger->debug( "Could not find location of user " . $req->user );
|
||||
}
|
||||
|
||||
# Get all non-empty, unique values of location attribute through list of
|
||||
# successful logins
|
||||
my @envHistory =
|
||||
grep { $_ // "" }
|
||||
uniq( map { $_->{ $self->locationAttribute } // "" } @{$successLogin} );
|
||||
|
||||
# Only consider some of the past unique locations
|
||||
my $maxLocations = $self->locationMaxValues;
|
||||
splice @envHistory, $maxLocations
|
||||
if ( $maxLocations and ( scalar @envHistory > $maxLocations ) );
|
||||
|
||||
if ( grep { $_ eq $location } @envHistory ) {
|
||||
$self->userLogger->debug(
|
||||
"User " . $req->user . " logged in from known location $location" );
|
||||
}
|
||||
else {
|
||||
# Not the first location in history, warn if new location
|
||||
if (@envHistory) {
|
||||
$self->userLogger->info( "User "
|
||||
. $req->user
|
||||
. " logged in from unknown location $location" );
|
||||
my $riskLevel = ( $req->sessionInfo->{_riskLevel} || 0 ) + 1;
|
||||
$req->sessionInfo->{_riskDetails}->{newLocation} =
|
||||
$req->sessionInfo->{ $self->locationDisplayAttribute };
|
||||
}
|
||||
else {
|
||||
$self->userLogger->info( "User "
|
||||
. $req->user
|
||||
. " logged with empty location history from location $location"
|
||||
);
|
||||
}
|
||||
}
|
||||
return PE_OK;
|
||||
}
|
||||
|
||||
sub sendWarningEmail {
|
||||
my ( $self, $req ) = @_;
|
||||
if ( $req->sessionInfo->{_riskDetails}->{newLocation} ) {
|
||||
return $self->_sendMail($req);
|
||||
}
|
||||
return PE_OK;
|
||||
}
|
||||
|
||||
sub _sendMail {
|
||||
my ( $self, $req ) = @_;
|
||||
my $date = strftime( '%F %X', localtime );
|
||||
my $location = $req->sessionInfo->{_riskDetails}->{newLocation};
|
||||
my $ua = $req->env->{HTTP_USER_AGENT};
|
||||
my $mail = $req->sessionInfo->{ $self->mailSessionKey };
|
||||
|
||||
# Build mail content
|
||||
my $tr = $self->translate($req);
|
||||
my $subject = $self->conf->{newLocationWarningMailSubject};
|
||||
unless ($subject) {
|
||||
$self->logger->debug('Use default warning subject');
|
||||
$subject = 'newLocationWarningMailSubject';
|
||||
$tr->( \$subject );
|
||||
}
|
||||
my ( $body, $html );
|
||||
if ( $self->conf->{newLocationWarningMailBody} ) {
|
||||
|
||||
# We use a specific text message, no html
|
||||
$self->logger->debug('Use specific warning body message');
|
||||
$body = $self->conf->{newLocationWarningMailBody};
|
||||
|
||||
# Replace variables in body
|
||||
$body =~ s/\$ua\b/$ua/ge;
|
||||
$body =~ s/\$location\b/$location/ge;
|
||||
$body =~ s/\$date\b/$date/ge;
|
||||
$body =~ s/\$(\w+)/$req->{sessionInfo}->{$1} || ''/ge;
|
||||
}
|
||||
else {
|
||||
|
||||
# Use HTML template
|
||||
$body = $self->loadMailTemplate(
|
||||
$req,
|
||||
'mail_new_location_warning',
|
||||
filter => $tr,
|
||||
params => {
|
||||
location => $location,
|
||||
date => $date,
|
||||
ua => $ua
|
||||
},
|
||||
);
|
||||
$html = 1;
|
||||
}
|
||||
if ( $mail && $subject && $body ) {
|
||||
$self->logger->warn("User $mail is signing in from a new location");
|
||||
|
||||
# Send mail
|
||||
$self->logger->debug('Unable to send new location warning mail')
|
||||
unless ( $self->send_mail( $mail, $subject, $body, $html ) );
|
||||
}
|
||||
else {
|
||||
$self->logger->error(
|
||||
'Unable to send new location warning mail: missing parameter(s)');
|
||||
}
|
||||
return PE_OK;
|
||||
}
|
||||
|
||||
1;
|
|
@ -1 +1 @@
|
|||
(function(){var r,e,s,o,t;s=function(e,r){return $("#msg").attr("trspan",e),$("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning message-danger alert-success alert-warning alert-danger"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},r=function(e,r,t){var o;if(console.log("Error",t),(o=JSON.parse(e.responseText))&&o.error)return o=o.error.replace(/.* /,""),console.log("Returned error",o),s(o,"warning")},o="",e=function(){return s("yourTotpKey","warning"),$.ajax({type:"POST",url:portal+"/2fregisters/totp/getkey",dataType:"json",error:r,success:function(e){var r,t;return e.error?(e.error.match(/totpExistingKey/)&&$("#divToHide").hide(),s(e.error,"warning")):e.portal&&e.user&&e.secret?($("#divToHide").show(),r="otpauth://totp/"+escape(e.portal)+":"+escape(e.user)+"?secret="+e.secret+"&issuer="+escape(e.portal),6!==e.digits&&(r+="&digits="+e.digits),30!==e.interval&&(r+="&period="+e.interval),new QRious({element:document.getElementById("qr"),value:r,size:150}),t=e.secret||"",$("#secret").text(t.toUpperCase().replace(/(.{4})/g,"$1 ").trim()),e.newkey?s("yourNewTotpKey","warning"):s("yourTotpKey","success"),o=e.token):s("PE24","danger")}})},t=function(){var e;return(e=$("#code").val())?$.ajax({type:"POST",url:portal+"/2fregisters/totp/verify",dataType:"json",data:{token:o,code:e,TOTPName:$("#TOTPName").val()},error:r,success:function(e){return e.error?e.error.match(/bad(Code|Name)/)?s(e.error,"warning"):s(e.error,"danger"):s("yourKeyIsRegistered","success")}}):(s("totpMissingCode","warning"),$("#code").focus())},$(document).ready(function(){return e(),$("#verify").on("click",function(){return t()})})}).call(this);
|
||||
!function(){var o=function(e,r){return $("#msg").attr("trspan",e),$("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning message-danger alert-success alert-warning alert-danger"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},r=function(e,r,t){if(console.log("Error",t),(e=JSON.parse(e.responseText))&&e.error)return e=e.error.replace(/.* /,""),console.log("Returned error",e),o(e,"warning")},t="",e=function(){return o("yourTotpKey","warning"),$.ajax({type:"POST",url:portal+"/2fregisters/totp/getkey",dataType:"json",error:r,success:function(e){var r;return e.error?(e.error.match(/totpExistingKey/)&&$("#divToHide").hide(),o(e.error,"warning")):e.portal&&e.user&&e.secret?($("#divToHide").show(),r="otpauth://totp/"+escape(e.portal)+":"+escape(e.user)+"?secret="+e.secret+"&issuer="+escape(e.portal),6!==e.digits&&(r+="&digits="+e.digits),30!==e.interval&&(r+="&period="+e.interval),new QRious({element:document.getElementById("qr"),value:r,size:150}),r=e.secret||"",$("#secret").text(r.toUpperCase().replace(/(.{4})/g,"$1 ").trim()),e.newkey?o("yourNewTotpKey","warning"):o("yourTotpKey","success"),t=e.token):o("PE24","danger")}})},s=function(){var e=$("#code").val();return e?$.ajax({type:"POST",url:portal+"/2fregisters/totp/verify",dataType:"json",data:{token:t,code:e,TOTPName:$("#TOTPName").val()},error:r,success:function(e){return e.error?e.error.match(/bad(Code|Name)/)?o(e.error,"warning"):o(e.error,"danger"):o("yourKeyIsRegistered","success")}}):(o("totpMissingCode","warning"),$("#code").focus())};$(document).ready(function(){return e(),$("#verify").on("click",s)})}.call(this);
|
|
@ -1 +1 @@
|
|||
{"version":3,"sources":["totpregistration.js"],"names":["displayError","getKey","setMsg","token","verify","msg","level","$","attr","html","window","translate","removeClass","addClass","j","status","err","res","console","log","JSON","parse","responseText","error","replace","ajax","type","url","portal","dataType","success","data","s","secret","match","hide","user","show","escape","digits","interval","QRious","element","document","getElementById","value","size","text","toUpperCase","trim","newkey","val","code","TOTPName","focus","ready","on","call","this"],"mappings":"CAMA,WACE,IAAIA,EAAcC,EAAQC,EAAQC,EAAOC,EAEzCF,EAAS,SAASG,EAAKC,GAQrB,OAPAC,EAAE,QAAQC,KAAK,SAAUH,GACzBE,EAAE,QAAQE,KAAKC,OAAOC,UAAUN,IAChCE,EAAE,UAAUK,YAAY,4FACxBL,EAAE,UAAUM,SAAS,WAAaP,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUM,SAAS,SAAWP,IAGzCN,EAAe,SAASc,EAAGC,EAAQC,GACjC,IAAIC,EAGJ,GAFAC,QAAQC,IAAI,QAASH,IACrBC,EAAMG,KAAKC,MAAMP,EAAEQ,gBACRL,EAAIM,MAGb,OAFAN,EAAMA,EAAIM,MAAMC,QAAQ,MAAO,IAC/BN,QAAQC,IAAI,iBAAkBF,GACvBf,EAAOe,EAAK,YAIvBd,EAAQ,GAERF,EAAS,WAEP,OADAC,EAAO,cAAe,WACfK,EAAEkB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVN,MAAOvB,EACP8B,QAAS,SAASC,GAChB,IAAQC,EAAGC,EACX,OAAIF,EAAKR,OACHQ,EAAKR,MAAMW,MAAM,oBACnB3B,EAAE,cAAc4B,OAEXjC,EAAO6B,EAAKR,MAAO,YAEtBQ,EAAKH,QAAUG,EAAKK,MAAQL,EAAKE,QAGvC1B,EAAE,cAAc8B,OAChBL,EAAI,kBAAqBM,OAAOP,EAAKH,QAAW,IAAOU,OAAOP,EAAKK,MAAS,WAAaL,EAAKE,OAAS,WAAcK,OAAOP,EAAKH,QAC7G,IAAhBG,EAAKQ,SACPP,GAAK,WAAaD,EAAKQ,QAEH,KAAlBR,EAAKS,WACPR,GAAK,WAAaD,EAAKS,UAEpB,IAAIC,OAAO,CACdC,QAASC,SAASC,eAAe,MACjCC,MAAOb,EACPc,KAAM,MAERb,EAASF,EAAKE,QAAU,GACxB1B,EAAE,WAAWwC,KAAKd,EAAOe,cAAcxB,QAAQ,UAAW,OAAOyB,QAC7DlB,EAAKmB,OACPhD,EAAO,iBAAkB,WAEzBA,EAAO,cAAe,WAEjBC,EAAQ4B,EAAK5B,OAtBXD,EAAO,OAAQ,cA2B9BE,EAAS,WACP,IAAI+C,EAEJ,OADAA,EAAM5C,EAAE,SAAS4C,OAKR5C,EAAEkB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVE,KAAM,CACJ5B,MAAOA,EACPiD,KAAMD,EACNE,SAAU9C,EAAE,aAAa4C,OAE3B5B,MAAOvB,EACP8B,QAAS,SAASC,GAChB,OAAIA,EAAKR,MACHQ,EAAKR,MAAMW,MAAM,kBACZhC,EAAO6B,EAAKR,MAAO,WAEnBrB,EAAO6B,EAAKR,MAAO,UAGrBrB,EAAO,sBAAuB,eArB3CA,EAAO,kBAAmB,WACnBK,EAAE,SAAS+C,UA2BtB/C,EAAEoC,UAAUY,MAAM,WAEhB,OADAtD,IACOM,EAAE,WAAWiD,GAAG,QAAS,WAC9B,OAAOpD,UAIVqD,KAAKC"}
|
||||
{"version":3,"sources":["totpregistration.js"],"names":["setMsg","msg","level","$","attr","html","window","translate","removeClass","addClass","displayError","j","status","err","console","log","res","JSON","parse","responseText","error","replace","token","getKey","ajax","type","url","portal","dataType","success","data","secret","match","hide","user","show","s","escape","digits","interval","QRious","element","document","getElementById","value","size","text","toUpperCase","trim","newkey","verify","val","code","TOTPName","focus","ready","on","call","this"],"mappings":"CAMA,WACE,IAEAA,EAAS,SAASC,EAAKC,GAQrB,OAPAC,EAAE,QAAQC,KAAK,SAAUH,GACzBE,EAAE,QAAQE,KAAKC,OAAOC,UAAUN,IAChCE,EAAE,UAAUK,YAAY,4FACxBL,EAAE,UAAUM,SAAS,WAAaP,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUM,SAAS,SAAWP,IAGzCQ,EAAe,SAASC,EAAGC,EAAQC,GAIjC,GAFAC,QAAQC,IAAI,QAASF,IACrBG,EAAMC,KAAKC,MAAMP,EAAEQ,gBACRH,EAAII,MAGb,OAFAJ,EAAMA,EAAII,MAAMC,QAAQ,MAAO,IAC/BP,QAAQC,IAAI,iBAAkBC,GACvBhB,EAAOgB,EAAK,YAIvBM,EAAQ,GAERC,EAAS,WAEP,OADAvB,EAAO,cAAe,WACfG,EAAEqB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVR,MAAOV,EACPmB,QAAS,SAASC,GAChB,IAAWC,EACX,OAAID,EAAKV,OACHU,EAAKV,MAAMY,MAAM,oBACnB7B,EAAE,cAAc8B,OAEXjC,EAAO8B,EAAKV,MAAO,YAEtBU,EAAKH,QAAUG,EAAKI,MAAQJ,EAAKC,QAGvC5B,EAAE,cAAcgC,OAChBC,EAAI,kBAAqBC,OAAOP,EAAKH,QAAW,IAAOU,OAAOP,EAAKI,MAAS,WAAaJ,EAAKC,OAAS,WAAcM,OAAOP,EAAKH,QAC7G,IAAhBG,EAAKQ,SACPF,GAAK,WAAaN,EAAKQ,QAEH,KAAlBR,EAAKS,WACPH,GAAK,WAAaN,EAAKS,UAEpB,IAAIC,OAAO,CACdC,QAASC,SAASC,eAAe,MACjCC,MAAOR,EACPS,KAAM,MAERd,EAASD,EAAKC,QAAU,GACxB5B,EAAE,WAAW2C,KAAKf,EAAOgB,cAAc1B,QAAQ,UAAW,OAAO2B,QAC7DlB,EAAKmB,OACPjD,EAAO,iBAAkB,WAEzBA,EAAO,cAAe,WAEjBsB,EAAQQ,EAAKR,OAtBXtB,EAAO,OAAQ,cA2B9BkD,EAAS,WACP,IACAC,EAAMhD,EAAE,SAASgD,MACjB,OAAKA,EAIIhD,EAAEqB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVE,KAAM,CACJR,MAAOA,EACP8B,KAAMD,EACNE,SAAUlD,EAAE,aAAagD,OAE3B/B,MAAOV,EACPmB,QAAS,SAASC,GAChB,OAAIA,EAAKV,MACHU,EAAKV,MAAMY,MAAM,kBACZhC,EAAO8B,EAAKV,MAAO,WAEnBpB,EAAO8B,EAAKV,MAAO,UAGrBpB,EAAO,sBAAuB,eArB3CA,EAAO,kBAAmB,WACnBG,EAAE,SAASmD,UA2BtBnD,EAAEuC,UAAUa,MAAM,WAEhB,OADAhC,IACOpB,EAAE,WAAWqD,GAAG,QACdN,MAIVO,KAAKC"}
|
|
@ -6,15 +6,20 @@
|
|||
"click2Reset":"انقر هنا لإعادة تعيين كلمة المرور",
|
||||
"goToPortal":"انتقل إلى البوابة",
|
||||
"hello":"مرحبا ",
|
||||
"host":"Host",
|
||||
"location": "Location",
|
||||
"mail2fSubject":"[LemonLDAP::NG] تسجيل الدخول الخاص بك هو ",
|
||||
"mailConfirmSubject":"تأكيد إعادة تعيين كلمة المرور[LemonLDAP::NG]",
|
||||
"mailSubject":"كلمة المرور الجديدة [LemonLDAP::NG]",
|
||||
"newLocationWarningMailBody":"Your account was signed in to from a new location.",
|
||||
"newLocationWarningMailSubject":"[LemonLDAP::NG] Sign-in from a new location",
|
||||
"newPwdIs":"كلمة المرور الجديدة هي",
|
||||
"pwdChanged":"تم تغيير كلمة المرور الخاصة بك",
|
||||
"pwdIs":"كلمة المرور الخاصة بك هي",
|
||||
"registerConfirmSubject":"تأكيد تسجيل الحساب[LemonLDAP::NG] ",
|
||||
"registerDoneSubject":"حسابك الجديد[LemonLDAP::NG]",
|
||||
"requestIssuedFromIP":"الطلب قد أرسل من عنوان الآي بي",
|
||||
"date":"Date",
|
||||
"yourLoginCodeIs":"Your login code is",
|
||||
"yourLoginIs":"تسجيل الدخول الخاص بك هو"
|
||||
}
|
|
@ -6,15 +6,20 @@
|
|||
"click2Reset":"Click here to reset your password",
|
||||
"goToPortal":"Go to portal",
|
||||
"hello":"Hello",
|
||||
"host":"Host",
|
||||
"location": "Location",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Your login code",
|
||||
"mailConfirmSubject": "[LemonLDAP::NG] Password reset confirmation",
|
||||
"mailSubject": "[LemonLDAP::NG] Your new password",
|
||||
"newLocationWarningMailBody":"Your account was signed in to from a new location.",
|
||||
"newLocationWarningMailSubject":"[LemonLDAP::NG] Sign-in from a new location",
|
||||
"newPwdIs":"Your new password is",
|
||||
"pwdChanged":"Your password was changed.",
|
||||
"pwdIs":"Your password is",
|
||||
"registerConfirmSubject": "[LemonLDAP::NG] Account register confirmation",
|
||||
"registerDoneSubject": "[LemonLDAP::NG] Your new account",
|
||||
"requestIssuedFromIP":"The request was issued from IP",
|
||||
"date":"Date",
|
||||
"yourLoginCodeIs":"Your login code is",
|
||||
"yourLoginIs":"Your login is"
|
||||
}
|
||||
|
|
|
@ -6,15 +6,20 @@
|
|||
"click2Reset":"Haga clic para reiniciar su contraseña",
|
||||
"goToPortal":"Ir al portal",
|
||||
"hello":"Hola",
|
||||
"host":"Host",
|
||||
"location": "Location",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Su código de acceso",
|
||||
"mailConfirmSubject":"[LemonLDAP::NG] Confirmación de reinicio de contraseña",
|
||||
"mailSubject":"[LemonLDAP::NG] Su nueva contraseña",
|
||||
"newLocationWarningMailBody":"Your account was signed in to from a new location.",
|
||||
"newLocationWarningMailSubject":"[LemonLDAP::NG] Sign-in from a new location",
|
||||
"newPwdIs":"Su nueva contraseña es",
|
||||
"pwdChanged":"Su contraseña ha sido cambiada.",
|
||||
"pwdIs":"Su contraseña es",
|
||||
"registerConfirmSubject":"[LemonLDAP::NG] Confirmación de creación de cuenta",
|
||||
"registerDoneSubject":"[LemonLDAP::NG] Su nueva cuenta",
|
||||
"requestIssuedFromIP":"El pedido fue emitido desde la IP",
|
||||
"date":"Date",
|
||||
"yourLoginCodeIs":"Su código de acceso es ",
|
||||
"yourLoginIs":"Su nombre de usuario es"
|
||||
}
|
|
@ -6,15 +6,20 @@
|
|||
"click2Reset":"Klikkaa tästä nollataksesi salasanasi",
|
||||
"goToPortal":"Siirry portaaliin",
|
||||
"hello":"Hei",
|
||||
"host":"Host",
|
||||
"location":"Location",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Your login code",
|
||||
"mailConfirmSubject":"[LemonLDAP::NG] Salasanan nollauksen vahvistus",
|
||||
"mailSubject":"[LemonLDAP::NG] Uusi salasanasi",
|
||||
"newLocationWarningMailBody":"Your account was signed in to from a new location.",
|
||||
"newLocationWarningMailSubject":"[LemonLDAP::NG] Sign-in from a new location",
|
||||
"newPwdIs":"Uusi salasanasi on",
|
||||
"pwdChanged":"Salasanasi on vaihdettu.",
|
||||
"pwdIs":"Sinun salasanasi on",
|
||||
"registerConfirmSubject":"[LemonLDAP::NG] Tunnuksen rekisteröinnin vahvistus",
|
||||
"registerDoneSubject":"[LemonLDAP::NG] Uusi käyttäjätunnuksesi",
|
||||
"requestIssuedFromIP":"The request was issued from IP",
|
||||
"date":"Date",
|
||||
"yourLoginCodeIs":"Your login code is",
|
||||
"yourLoginIs":"Your login is"
|
||||
}
|
|
@ -6,15 +6,20 @@
|
|||
"click2Reset":"Cliquez ici pour réinitialiser votre mot de passe",
|
||||
"goToPortal":"Aller au portail",
|
||||
"hello":"Bonjour",
|
||||
"host":"Hôte",
|
||||
"location":"Localisation",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Votre code de connexion",
|
||||
"mailConfirmSubject": "[LemonLDAP::NG] Confirmation de réinitialisation de mot de passe",
|
||||
"mailSubject": "[LemonLDAP::NG] Votre nouveau mot de passe",
|
||||
"newLocationWarningMailBody":"Une nouvelle connexion à votre compte a été détectée",
|
||||
"newLocationWarningMailSubject":"[LemonLDAP::NG] Nouvelle connexion à votre compte",
|
||||
"newPwdIs":"Votre nouveau mot de passe est",
|
||||
"pwdChanged":"Votre mot de passe a été changé.",
|
||||
"pwdIs":"Votre mot de passe est",
|
||||
"registerConfirmSubject": "[LemonLDAP::NG] Confirmation d'enregistrement de compte",
|
||||
"registerDoneSubject": "[LemonLDAP::NG] Votre nouveau compte",
|
||||
"requestIssuedFromIP":"La demande provient de l'IP",
|
||||
"date":"Date",
|
||||
"yourLoginCodeIs":"Votre code de connexion est",
|
||||
"yourLoginIs":"Votre identifiant est"
|
||||
}
|
||||
|
|
|
@ -6,15 +6,20 @@
|
|||
"click2Reset":"Clicca qui per reimpostare la password",
|
||||
"goToPortal":"Vai al portale",
|
||||
"hello":"Salve",
|
||||
"host":"Host",
|
||||
"location":"Location",
|
||||
"mail2fSubject":"[LemonLDAP :: NG] Il tuo codice di accesso",
|
||||
"mailConfirmSubject":"Conferma reimpostazione password [LemonLDAP::NG] ",
|
||||
"mailSubject":"[LemonLDAP::NG] La tua nuova password",
|
||||
"newLocationWarningMailBody":"Your account was signed in to from a new location.",
|
||||
"newLocationWarningMailSubject":"[LemonLDAP::NG] Sign-in from a new location",
|
||||
"newPwdIs":"La tua nuova password é",
|
||||
"pwdChanged":"La tua password é stata cambiata",
|
||||
"pwdIs":"La tua password é",
|
||||
"registerConfirmSubject":"[LemonLDAP :: NG] Conferma registro account",
|
||||
"registerDoneSubject":"[LemonLDAP::NG] Il tuo nuovo account",
|
||||
"requestIssuedFromIP":"La richiesta è stata emessa da IP",
|
||||
"date":"Date",
|
||||
"yourLoginCodeIs":"Il tuo codice di accesso è",
|
||||
"yourLoginIs":"Il tuo login é"
|
||||
}
|
|
@ -6,15 +6,20 @@
|
|||
"click2Reset":"Kilik disini untuk menetapkan semula kata laluan anda",
|
||||
"goToPortal":"Go to portal",
|
||||
"hello":"Hello",
|
||||
"host":"Host",
|
||||
"location":"Location",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Kod login anda",
|
||||
"mailConfirmSubject":"[LemonLDAP::NG] Pengesahan penetapan semula kata laluan",
|
||||
"mailSubject":"[LemonLDAP::NG] Kata laluan baru anda",
|
||||
"newLocationWarningMailBody":"Your account was signed in to from a new location.",
|
||||
"newLocationWarningMailSubject":"[LemonLDAP::NG] Sign-in from a new location",
|
||||
"newPwdIs":"Kata laluan baru anda ialah",
|
||||
"pwdChanged":"Kata laluan anda telah ditukar",
|
||||
"pwdIs":"Kata laluan anda ialah",
|
||||
"registerConfirmSubject":"[LemonLDAP::NG] Pengesahan pendaftaran akaun",
|
||||
"registerDoneSubject":"[LemonLDAP::NG] Akaun baru anda",
|
||||
"requestIssuedFromIP":"Permintaan itu dari alamat IP",
|
||||
"date":"Date",
|
||||
"yourLoginCodeIs":"Kod login anda ialah",
|
||||
"yourLoginIs":"Login anda ialah"
|
||||
}
|
|
@ -6,15 +6,20 @@
|
|||
"click2Reset":"Parolanızı sıfırlamak için buraya tıklayın",
|
||||
"goToPortal":"Portala git",
|
||||
"hello":"Merhaba",
|
||||
"host":"Host",
|
||||
"location":"Location",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Giriş kodunuz",
|
||||
"mailConfirmSubject":"[LemonLDAP::NG] Parola sıfırlama onayı",
|
||||
"mailSubject":"[LemonLDAP::NG] Yeni parolanız",
|
||||
"newLocationWarningMailBody":"Your account was signed in to from a new location.",
|
||||
"newLocationWarningMailSubject":"[LemonLDAP::NG] Sign-in from a new location",
|
||||
"newPwdIs":"Yeni parolanız",
|
||||
"pwdChanged":"Parolanız değiştirildi.",
|
||||
"pwdIs":"Parolanız",
|
||||
"registerConfirmSubject":"[LemonLDAP::NG] Hesap açma onayı",
|
||||
"registerDoneSubject":"[LemonLDAP::NG] Yeni hesabınız",
|
||||
"requestIssuedFromIP":"İstek IP'den gönderildi",
|
||||
"date":"Date",
|
||||
"yourLoginCodeIs":"Giriş kodunuz",
|
||||
"yourLoginIs":"Giriş bilgileriniz"
|
||||
}
|
|
@ -6,15 +6,20 @@
|
|||
"click2Reset":"Nhấn ở đây để thiết lập lại mật khẩu của bạn",
|
||||
"goToPortal":"Đi tới cổng thông tin",
|
||||
"hello":"Xin chào",
|
||||
"host":"Host",
|
||||
"location":"Location",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Your login code",
|
||||
"mailConfirmSubject":"[LemonLDAP::NG] Xác nhận thiết lập lại mật khẩu",
|
||||
"mailSubject":"[LemonLDAP::NG] Mật khẩu mới của bạn",
|
||||
"newLocationWarningMailBody":"Your account was signed in to from a new location.",
|
||||
"newLocationWarningMailSubject":"[LemonLDAP::NG] Sign-in from a new location",
|
||||
"newPwdIs":"Mật khẩu mới của bạn là",
|
||||
"pwdChanged":"Mật khẩu của bạn đã được thay đổi.",
|
||||
"pwdIs":"Mật khẩu của bạn là",
|
||||
"registerConfirmSubject":"[LemonLDAP::NG] Xác nhận đăng ký tài khoản",
|
||||
"registerDoneSubject":"[LemonLDAP::NG] Tài khoản mới của bạn",
|
||||
"requestIssuedFromIP":"Yêu cầu được gửi đi từ địa chỉ IP",
|
||||
"date":"Date",
|
||||
"yourLoginCodeIs":"Your login code is",
|
||||
"yourLoginIs":"Đăng nhập của bạn là"
|
||||
}
|
|
@ -6,15 +6,20 @@
|
|||
"click2Reset":"请点击此处充值您的密码",
|
||||
"goToPortal":"回到首页",
|
||||
"hello":"您好",
|
||||
"host":"Host",
|
||||
"location":"Location",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Your login code",
|
||||
"mailConfirmSubject":"[LemonLDAP::NG] 密码重置确认",
|
||||
"mailSubject":"[LemonLDAP::NG] 您的新密码",
|
||||
"newLocationWarningMailBody":"Your account was signed in to from a new location.",
|
||||
"newLocationWarningMailSubject":"[LemonLDAP::NG] Sign-in from a new location",
|
||||
"newPwdIs":"您的新密码是",
|
||||
"pwdChanged":"您的密码已经修改",
|
||||
"pwdIs":"您的密码是",
|
||||
"registerConfirmSubject":"[LemonLDAP::NG] 账号注册确认",
|
||||
"registerDoneSubject":"[LemonLDAP::NG] 您的新账号",
|
||||
"requestIssuedFromIP":"此请求来自IP地址",
|
||||
"date":"Date",
|
||||
"yourLoginCodeIs":"Your login code is",
|
||||
"yourLoginIs":"您登陆的账户是"
|
||||
}
|
|
@ -6,15 +6,20 @@
|
|||
"click2Reset":"點擊此處以重設您的密碼",
|
||||
"goToPortal":"回到首頁",
|
||||
"hello":"您好",
|
||||
"host":"Host",
|
||||
"location":"Location",
|
||||
"mail2fSubject":"[LemonLDAP::NG] 您的登入代碼",
|
||||
"mailConfirmSubject":"[LemonLDAP::NG] 確認重設密碼",
|
||||
"mailSubject":"[LemonLDAP::NG] 您的新密碼",
|
||||
"newLocationWarningMailBody":"Your account was signed in to from a new location.",
|
||||
"newLocationWarningMailSubject":"[LemonLDAP::NG] Sign-in from a new location",
|
||||
"newPwdIs":"您的新密碼為",
|
||||
"pwdChanged":"您的密碼已變更",
|
||||
"pwdIs":"您的密碼為",
|
||||
"registerConfirmSubject":"[LemonLDAP::NG] 確認帳號註冊",
|
||||
"registerDoneSubject":"[LemonLDAP::NG] 您的新帳號",
|
||||
"requestIssuedFromIP":"請求發出從 IP",
|
||||
"date":"Date",
|
||||
"yourLoginCodeIs":"您的登入代碼為",
|
||||
"yourLoginIs":"您的登入為"
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<TMPL_INCLUDE NAME="mail_header.tpl">
|
||||
|
||||
<p>
|
||||
<span trspan="hello">Hello</span> <TMPL_VAR NAME="session_cn" ESCAPE=HTML>,<br />
|
||||
<br />
|
||||
<h3><span trspan="newLocationWarningMailBody">Your account was signed in to from a new location</span></h3></br>
|
||||
<span trspan="location">Location</span> <b><TMPL_VAR NAME="location"></b></br>
|
||||
<span trspan="date">Date</span> <b><TMPL_VAR NAME="date"></b></br>
|
||||
<span trspan="UA">UA</span> <b><TMPL_VAR NAME="ua"></b></br>
|
||||
</p>
|
||||
|
||||
<TMPL_INCLUDE NAME="mail_footer.tpl">
|
79
lemonldap-ng-portal/t/61-NewLocationWarning-Custom.t
Normal file
79
lemonldap-ng-portal/t/61-NewLocationWarning-Custom.t
Normal file
|
@ -0,0 +1,79 @@
|
|||
use Test::More;
|
||||
use strict;
|
||||
use IO::String;
|
||||
|
||||
use POSIX qw(locale_h);
|
||||
use locale;
|
||||
setlocale( LC_TIME, "C" );
|
||||
|
||||
BEGIN {
|
||||
eval {
|
||||
require 't/test-lib.pm';
|
||||
require 't/smtp.pm';
|
||||
};
|
||||
}
|
||||
|
||||
my $res;
|
||||
my $maintests = 5;
|
||||
|
||||
SKIP: {
|
||||
eval 'require Email::Sender::Simple;';
|
||||
if ($@) {
|
||||
skip 'Missing dependencies', $maintests;
|
||||
}
|
||||
|
||||
my $client = LLNG::Manager::Test->new( {
|
||||
ini => {
|
||||
logLevel => 'error',
|
||||
useSafeJail => 1,
|
||||
authentication => 'Demo',
|
||||
userDB => 'Same',
|
||||
passwordDB => 'Demo',
|
||||
captcha_mail_enabled => 0,
|
||||
portalMainLogo => 'common/logos/logo_llng_old.png',
|
||||
newLocationWarning => 1,
|
||||
loginHistoryEnabled => 1,
|
||||
newLocationWarningMailSubject => 'Test new location mail',
|
||||
newLocationWarningMailBody => 'Test $location $date $ua',
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
## Simple access
|
||||
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Portal', );
|
||||
my ( $host, $url, $query ) =
|
||||
expectForm( $res, '#', undef, 'user', 'password' );
|
||||
|
||||
## Authentication #1 with IP #1 (Test 1)
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'First auth query'
|
||||
);
|
||||
|
||||
## Authentication #1 with IP #2 (Test 2)
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
ip => '127.0.0.2',
|
||||
),
|
||||
'Second auth query'
|
||||
);
|
||||
like( subject(), qr#Test new location mail#, ' Subject found' );
|
||||
like(
|
||||
mail(),
|
||||
qr#^Test 127\.0\.0\.2 \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} Mozilla/5\.0 \(VAX-4000; rv:36\.0\) Gecko/20350101 Firefox$#,
|
||||
' Mail sent (IP, Date and UA found)'
|
||||
);
|
||||
}
|
||||
|
||||
count($maintests);
|
||||
clean_sessions();
|
||||
done_testing( count() );
|
187
lemonldap-ng-portal/t/61-NewLocationWarning.t
Normal file
187
lemonldap-ng-portal/t/61-NewLocationWarning.t
Normal file
|
@ -0,0 +1,187 @@
|
|||
use Test::More;
|
||||
use strict;
|
||||
use IO::String;
|
||||
|
||||
use POSIX qw(locale_h);
|
||||
use locale;
|
||||
setlocale( LC_TIME, "C" );
|
||||
|
||||
BEGIN {
|
||||
eval {
|
||||
require 't/test-lib.pm';
|
||||
require 't/smtp.pm';
|
||||
};
|
||||
}
|
||||
|
||||
my $res;
|
||||
my $maintests = 20;
|
||||
|
||||
SKIP: {
|
||||
eval 'require Email::Sender::Simple;';
|
||||
if ($@) {
|
||||
skip 'Missing dependencies', $maintests;
|
||||
}
|
||||
|
||||
my $client = LLNG::Manager::Test->new( {
|
||||
ini => {
|
||||
logLevel => 'error',
|
||||
useSafeJail => 1,
|
||||
authentication => 'Demo',
|
||||
userDB => 'Same',
|
||||
passwordDB => 'Demo',
|
||||
captcha_mail_enabled => 0,
|
||||
portalMainLogo => 'common/logos/logo_llng_old.png',
|
||||
newLocationWarning => 1,
|
||||
loginHistoryEnabled => 1
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
## Simple access
|
||||
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Portal', );
|
||||
my ( $host, $url, $query ) =
|
||||
expectForm( $res, '#', undef, 'user', 'password' );
|
||||
|
||||
## Authentication #1 with IP #1
|
||||
clear_mail();
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'First auth query'
|
||||
);
|
||||
my $id = expectCookie($res);
|
||||
$client->logout($id);
|
||||
ok( !mail(), "First time seeing a new IP, no mail sent" );
|
||||
|
||||
## Authentication #2 with IP #1
|
||||
clear_mail();
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Second auth query'
|
||||
);
|
||||
$id = expectCookie($res);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
$client->logout($id);
|
||||
ok( !mail(), "Second time seeing a new IP, no mail sent" );
|
||||
|
||||
## Authentication #3 with IP #2
|
||||
clear_mail();
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
ip => '127.0.0.2',
|
||||
),
|
||||
'Third auth query'
|
||||
);
|
||||
$id = expectCookie($res);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
$client->logout($id);
|
||||
like(
|
||||
mail(),
|
||||
qr#<h3><span>Your account was signed in to from a new location\.</span></h3></br>
|
||||
#, 'First login on a new IP, email sent'
|
||||
);
|
||||
|
||||
## Authentication #1 with IP #3 wrong password
|
||||
clear_mail();
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=ohwd'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
ip => "127.0.0.3",
|
||||
),
|
||||
'Fourth auth query'
|
||||
);
|
||||
ok( $res->[2]->[0] =~ /<span trmsg="5"><\/span>/, ' Bad credential' )
|
||||
or print STDERR Dumper( $res->[2]->[0] );
|
||||
ok( !mail(), "Failed login with a new IP, no email sent" );
|
||||
|
||||
## Authentication #2 with IP #3
|
||||
clear_mail();
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
ip => '127.0.0.3',
|
||||
),
|
||||
'Fifth auth query'
|
||||
);
|
||||
$id = expectCookie($res);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
like(
|
||||
subject(),
|
||||
qr#\[LemonLDAP::NG\] Sign-in from a new location#,
|
||||
' Subject found'
|
||||
);
|
||||
like(
|
||||
mail(),
|
||||
qr#<h3><span>Your account was signed in to from a new location\.</span></h3></br>#,
|
||||
' Mail sent (Wrong password)'
|
||||
);
|
||||
like(
|
||||
mail(),
|
||||
qr#<span>Location</span> <b>127.0.0.3</b>#,
|
||||
' Location found in mail body'
|
||||
);
|
||||
like(
|
||||
mail(),
|
||||
qr#<span>Date</span> <b>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}</b>#,
|
||||
' Date found in mail body'
|
||||
);
|
||||
like(
|
||||
mail(),
|
||||
qr#<span>UA</span> <b>Mozilla/5\.0 \(VAX-4000; rv:36\.0\) Gecko/20350101 Firefox</b></br>#,
|
||||
' UserAgent found in mail body'
|
||||
);
|
||||
|
||||
## Authentication #3 with IP #3
|
||||
clear_mail();
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
ip => '127.0.0.3',
|
||||
),
|
||||
'Fifth auth query'
|
||||
);
|
||||
$id = expectCookie($res);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
ok( !mail(), "Login on newly learned address, no email" );
|
||||
|
||||
## Authentication #3 with IP #1
|
||||
clear_mail();
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Fifth auth query'
|
||||
);
|
||||
$id = expectCookie($res);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
ok( !mail(), "Login on previously learned address, no email" );
|
||||
}
|
||||
|
||||
count($maintests);
|
||||
clean_sessions();
|
||||
done_testing( count() );
|
|
@ -1,17 +1,23 @@
|
|||
package main;
|
||||
|
||||
my ($mail, $mail_envelope, $mail_subject);
|
||||
my ( $mail, $mail_envelope, $mail_subject );
|
||||
|
||||
sub mail {
|
||||
return $mail;
|
||||
}
|
||||
|
||||
sub clear_mail {
|
||||
$mail = undef;
|
||||
$mail_envelope = undef;
|
||||
$mail_subject = undef;
|
||||
}
|
||||
|
||||
sub envelope {
|
||||
return $mail_envelope;
|
||||
}
|
||||
|
||||
sub subject {
|
||||
my $subject = ($mail_subject =~ /=\?utf-8\?B\?(.+?)\?=/)[0];
|
||||
my $subject = ( $mail_subject =~ /=\?utf-8\?B\?(.+?)\?=/ )[0];
|
||||
return decode_base64($subject);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user