Merge branch 'v2.0' into 2600

This commit is contained in:
Alexandre KARIM 2021-09-08 17:25:46 +02:00
commit aa0db663c6
55 changed files with 1148 additions and 61 deletions

1
debian/control vendored
View File

@ -282,6 +282,7 @@ Depends: ${misc:Depends},
liblemonldap-ng-handler-perl (= ${binary:Version}), liblemonldap-ng-handler-perl (= ${binary:Version}),
libtext-unidecode-perl, libtext-unidecode-perl,
libregexp-assemble-perl, libregexp-assemble-perl,
liblist-moreutils-perl,
libemail-date-format-perl libemail-date-format-perl
Recommends: gsfonts, Recommends: gsfonts,
libcrypt-openssl-bignum-perl, libcrypt-openssl-bignum-perl,

View File

@ -17,6 +17,7 @@ Applications
applications/drupal applications/drupal
applications/fusiondirectory applications/fusiondirectory
applications/gerrit applications/gerrit
applications/gitea
applications/gitlab applications/gitlab
applications/glpi applications/glpi
applications/googleapps applications/googleapps
@ -99,6 +100,7 @@ Application Configuration
.. image:: applications/fusiondirectory-logo.jpg :doc:`FusionDirectory<applications/fusiondirectory>` .. image:: applications/fusiondirectory-logo.jpg :doc:`FusionDirectory<applications/fusiondirectory>`
.. image:: applications/gerrit_logo.png :doc:`Gerrit<applications/gerrit>` .. image:: applications/gerrit_logo.png :doc:`Gerrit<applications/gerrit>`
.. image:: applications/gitlab_logo.png :doc:`Gitlab<applications/gitlab>` ✔ ✔ .. image:: applications/gitlab_logo.png :doc:`Gitlab<applications/gitlab>` ✔ ✔
.. image:: applications/gitea_logo.png :doc:`Gitea<applications/gitea>`
.. image:: applications/glpi_logo.png :doc:`GLPI<applications/glpi>` .. image:: applications/glpi_logo.png :doc:`GLPI<applications/glpi>`
.. image:: applications/googleapps_logo.png :doc:`Google Apps<applications/googleapps>` .. image:: applications/googleapps_logo.png :doc:`Google Apps<applications/googleapps>`
.. image:: applications/grafana_logo.png :doc:`Grafana<applications/grafana>` .. image:: applications/grafana_logo.png :doc:`Grafana<applications/grafana>`

View File

@ -0,0 +1,67 @@
Gitea
=====
|logo|
Presentation
------------
`Gitea <https://gitea.io/>`__ is a community managed lightweight
code hosting solution written in Go. It is published under the MIT license.
It can be configured to authenticate users with :doc:`OpenID Connect <../idpopenidconnect>`.
Configuration
--------------
LL:NG
~~~~~
Make sure you have already
:doc:`enabled OpenID Connect<../idpopenidconnect>` on your LemonLDAP::NG
server
Make sure you have generated a set of signing keys in
``OpenID Connect Service`` » ``Security`` » ``Keys``
You also need to set a Signing key ID to a non-empty value of your choice.
Then, add a Relaying Party with the following configuration:
- Options » Basic » Client ID : choose a client ID, such as ``gitea``
- Options » Basic » Client Secret : choose a client secret, such as ``xxxx``
- Options » Basic » Allowed redirection address : ``https://git.example.com/user/oauth2/NAME/callback``
- Options » ID Token Signature Algorithm : ``RS256``
- No Exported Attributes needed
.. note::
The redirection address is built like this: ``<Gitea service URL>`` ``/user/oauth2/`` ``<Name of the OIDC authentication source in Gitea>`` ``/callback``
Gitea
~~~~~
Go in administration panel and create a new authentication source:
|screenshot_admin|
Configure settings:
- Authentication name: set here the value used for the redirection address
- OAuth2 Provider: set OpenID Connect
- Client ID: the Client ID configured on LL::NG side
- Client Secret: the Client Secret configured on LL::NG side
- OpenID Connect Auto Discovery URL: use the default OIDC configuration URL of your LL::NG server
- Enable the authentication source
Usage
-----
In Gitea login screen, a new OpenID logo appears at the bottom. Click on it to authenticate.
At first connection, the user must associate his account to an existing one (local or LDAP). The assocation is then remembered for further connections.
.. |logo| image:: /applications/gitea_logo.png
:class: align-center
.. |screenshot_admin| image:: /applications/gitea_oidc_config.png
:class: align-center

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -31,7 +31,7 @@ As an RP, LL::NG supports a lot of OpenID Connect features:
- Logout on EndSession end point - Logout on EndSession end point
You can use this authentication module to link your LL::NG server to any You can use this authentication module to link your LL::NG server to any
OpenID Connect Provider. Here are some examples, witch their specific OpenID Connect Provider. Here are some examples, with their specific
documentation: documentation:
@ -40,13 +40,14 @@ documentation:
authopenidconnect_google authopenidconnect_google
authopenidconnect_franceconnect authopenidconnect_franceconnect
authopenidconnect_prosanteconnect
=============== ================== =============== ================== ==================
Google France Connect Google France Connect Pro Santé Connect
=============== ================== =============== ================== ==================
|google| |franceconnect| |google| |franceconnect| |prosanteconnect|
=============== ================== =============== ================== ==================
.. |google| image:: applications/google_logo.png .. |google| image:: applications/google_logo.png
:target: authopenidconnect_google.html :target: authopenidconnect_google.html
@ -54,11 +55,14 @@ Google France Connect
.. |franceconnect| image:: applications/franceconnect_logo.png .. |franceconnect| image:: applications/franceconnect_logo.png
:target: authopenidconnect_franceconnect.html :target: authopenidconnect_franceconnect.html
.. |prosanteconnect| image:: applications/prosanteconnect_logo.png
:target: authopenidconnect_prosanteconnect.html
.. attention:: .. attention::
OpenID-Connect specification is not finished for logout OpenID Connect specification is not finished for logout
propagation. So logout initiated by relaying-party will be forward to propagation. So logout initiated by relaying-party will be forward to
OpenID-Connect provider but logout initiated by the provider (or another OpenID Connect provider but logout initiated by the provider (or another
RP) will not be propagated. LLNG will implement this when spec will be RP) will not be propagated. LLNG will implement this when spec will be
published. published.
@ -68,7 +72,7 @@ Configuration
OpenID Connect Service OpenID Connect Service
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
See :doc:`OpenIDConnect service<openidconnectservice>` configuration See :doc:`OpenID Connect service<openidconnectservice>` configuration
chapter. chapter.
Authentication and UserDB Authentication and UserDB

View File

@ -0,0 +1,209 @@
Pro Santé Connect
=================
|logo|
Presentation
------------
`Pro Santé Connect <https://tech.esante.gouv.fr/outils-services/pro-sante-connect-e-cps/presentation-generale>`__ is
a French identity provider for healthcare professionals. It relies on OpenID Connect protocol.
Register on Pro Santé Connect
-----------------------------
Once :doc:`OpenID Connect service<openidconnectservice>` is configured,
you need to register to Pro Santé Connect.
Go on https://integrateurs-cps.asipsante.fr.
You need to provide the callback URLs, for example
https://auth.domain.com/?openidcallback=1.
And also a logout URL, for example
https://auth.domain.com/?logout=1.
You will then get a ``client_id`` and a ``client_secret``.
Declare Pro Santé Connect in your LL::NG server
-----------------------------------------------
Go in Manager and create a new OpenID Connect provider. You can call it
``psc-connect`` for example.
Click on ``Metadata`` and set manually the metadata of the service.
For the sandbox server:
.. code-block:: javascript
{
"issuer": "https://auth.bas.esw.esante.gouv.fr/auth/realms/esante-wallet",
"authorization_endpoint": "https://wallet.bas.esw.esante.gouv.fr/auth",
"token_endpoint": "https://auth.bas.esw.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/token",
"introspection_endpoint": "https://auth.bas.esw.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/token/introspect",
"userinfo_endpoint": "https://auth.bas.esw.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/userinfo",
"end_session_endpoint": "https://auth.bas.esw.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/logout",
"jwks_uri": "https://auth.bas.esw.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/certs",
"check_session_iframe": "https://auth.bas.esw.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/login-status-iframe.html",
"grant_types_supported": [
"authorization_code",
"implicit",
"refresh_token",
"password",
"client_credentials"
],
"response_types_supported": [
"code",
"none",
"id_token",
"token",
"id_token token",
"code id_token",
"code token",
"code id_token token"
],
"subject_types_supported": [
"public",
"pairwise"
],
"id_token_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512"
],
"id_token_encryption_alg_values_supported": [
"RSA-OAEP",
"RSA1_5"
],
"id_token_encryption_enc_values_supported": [
"A256GCM",
"A192GCM",
"A128GCM",
"A128CBC-HS256",
"A192CBC-HS384",
"A256CBC-HS512"
],
"userinfo_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512",
"none"
],
"request_object_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512",
"none"
],
"response_modes_supported": [
"query",
"fragment",
"form_post"
],
"registration_endpoint": "https://auth.bas.esw.esante.gouv.fr/auth/realms/esante-wallet/clients-registrations/openid-connect",
"token_endpoint_auth_methods_supported": [
"private_key_jwt",
"client_secret_basic",
"client_secret_post",
"tls_client_auth",
"client_secret_jwt"
],
"token_endpoint_auth_signing_alg_values_supported": [
"PS384",
"ES384",
"RS384",
"HS256",
"HS512",
"ES256",
"RS256",
"HS384",
"ES512",
"PS256",
"PS512",
"RS512"
],
"claims_supported": [
"aud",
"sub",
"iss",
"auth_time",
"name",
"given_name",
"family_name",
"preferred_username",
"email",
"acr"
],
"claim_types_supported": [
"normal"
],
"claims_parameter_supported": false,
"scopes_supported": [
"openid",
"address",
"email",
"identity",
"microprofile-jwt",
"offline_access",
"phone",
"profile",
"roles",
"scope_1",
"scope_2",
"scope_all",
"web-origins",
"eidas2"
],
"request_parameter_supported": true,
"request_uri_parameter_supported": true,
"code_challenge_methods_supported": [
"plain",
"S256"
],
"tls_client_certificate_bound_access_tokens": true
}
You should alos import JWKS data from https://auth.bas.esw.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/certs
directly in configuration to avoid requests to reload them.
Go in ``Exported attributes`` to choose which attributes you want to collect.
Read the technical documentation to know available attributes:
https://tech.esante.gouv.fr/outils-services/pro-sante-connect-e-cps/documentation-technique
Now go in ``Options``:
- Register the ``client_id`` and ``client_secret`` given by Pro Santé Connect
- In ``Scopes`` set ``openid scope_all``
- In ``ACR values`` set ``eidas2``
- You can also set the name and the logo
.. |logo| image:: /applications/prosanteconnect_logo.png
:class: align-center

View File

@ -5,4 +5,5 @@ Attacks and Protection
:maxdepth: 1 :maxdepth: 1
bruteforceprotection bruteforceprotection
newlocationwarning
safejail safejail

View 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

View File

@ -285,12 +285,13 @@ Name Description
:doc:`Grant Sessions<grantsession>` Rules to apply before allowing a user to open a session :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:`Impersonation<impersonation>` [11]_\ |new| Allow users to use another identity
:doc:`Find user<finduser>` [12]_\ |new| Search for user account :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:`Portal Status<status>` Experimental portal status page
:doc:`Public pages<public_pages>` Enable public pages system :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 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:`REST services<restservices>` |new| REST server for :doc:`Proxy<authproxy>`
:doc:`SOAP services<soapservices>` |deprecated| SOAP 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 :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 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:`AuthBasic<handlerauthbasic>` ✔ ✔ ✔ ✔ Designed for some server-to-server applications
:doc:`CDA<cda>` ✔ ✔ ✔ ✔ For Cross Domain Authentication :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:`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:`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:`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:`Service Token<servertoserver>` |new| *(Server-to-Server)* ✔ ✔ ✔ ✔ ✔ Designed to permit underlying requests *(API-Based Infrastructure)*
:doc:`Zimbra PreAuth<applications/zimbra>` ✔ ✔ ✔ :doc:`Zimbra PreAuth<applications/zimbra>` ✔ ✔ ✔
@ -598,18 +599,22 @@ by your language code):
2.0.11 2.0.11
.. [13] .. [13]
:doc:`NewLocationWarning<newlocationwarning>` is available
with LLNG ≥ 2.0.14
.. [14]
:doc:`Refresh session API plugin<refreshsessionapi>` is available :doc:`Refresh session API plugin<refreshsessionapi>` is available
with LLNG ≥ 2.0.7 with LLNG ≥ 2.0.7
.. [14] .. [15]
:doc:`Reset certificate by mail plugin<resetcertificate>` is :doc:`Reset certificate by mail plugin<resetcertificate>` is
available with LLNG ≥ 2.0.7 available with LLNG ≥ 2.0.7
.. [15] .. [16]
:doc:`Node.js handler<nodehandler>` has not yet reached the same :doc:`Node.js handler<nodehandler>` has not yet reached the same
level of functionalities level of functionalities
.. [16] .. [17]
:doc:`OAuth2 Handler<oauth2handler>` is available with LLNG ≥ 2.0.4 :doc:`OAuth2 Handler<oauth2handler>` is available with LLNG ≥ 2.0.4
.. |image0| image:: /icons/kthememgr.png .. |image0| image:: /icons/kthememgr.png

View File

@ -8,9 +8,9 @@ We use in this example a public OIDC provider based on LL::NG: `<https://oidctes
Authentication Authentication
-------------- --------------
The first step is to obtain a valid SSO session on the portal. Several solutions: The first step is to obtain a valid SSO session on the portal. The standard solution is to use a web browser and log into the portal, then get the value of the SSO cookie.
* Use a web browser and log into the portal, then get the value of the SSO cookie
* Use portal REST API, and adapt the `requireToken` configuration to get cookie value in JSON response (see :doc:`REST services<restservices>`) In our case, to be able to use only command lines, we will use portal REST API (which requires to adapt the `requireToken` configuration to get cookie value in JSON response (see :doc:`REST services<restservices>`). This should not be what you will on a production service.
Example of REST service usage, with credentials `dwho`/`dwho`: Example of REST service usage, with credentials `dwho`/`dwho`:
@ -130,3 +130,68 @@ JSON response:
"preferred_username" : "dwho", "preferred_username" : "dwho",
"sub" : "dwho" "sub" : "dwho"
} }
Introspection
-------------
You can the validity of the access token with the introspection endpoint.
Parameters needed:
* Client ID and Client Secret, used as basic authorization
* Access token, sent as POST data
.. code-block:: shell
curl -u private:tardis -X POST -d 'token=a88b8dde538719e55c3cb8fbd14d06ed77853c685a62abf6ecb88d86228a9c64' 'https://oidctest.wsweet.org/oauth2/introspect' | json_pp
JSON response:
.. code-block:: javascript
{
"active" : true,
"client_id" : "private",
"exp" : 1630684115,
"iss" : "https://oidctest.wsweet.org/",
"scope" : "openid profile email",
"sub" : "dwho"
}
Refresh an access token
-----------------------
If the access token has expired, you can get a new one with the refresh token.
Parameters needed:
* Grant type: we use here `refresh_token`, sent as POST data
* Refresh token, sent as POST data
* Client ID and Client Secret, used as basic authorization
.. code-block:: shell
curl -X POST -d grant_type=refresh_token -d refresh_token=19434440ed4da2803e8ba9d91cb2eabd5b8bd12af2609429bda03ed487e6ef57 -u 'private:tardis' 'https://oidctest.wsweet.org/oauth2/token' | json_pp
JSON response:
.. code-block:: javascript
{
"access_token" : "78929118546b1a11a2e3b607f607d0ccb73d72bbd95c59d0b03ae69ffa17f41a",
"expires_in" : 3600,
"id_token" : "eyJhbGciOiJSUzI1NiIsImtpZCI6Im9pZGN0ZXN0IiwidHlwIjoiSldUIn0.eyJhdXRoX3RpbWUiOjE2MTQxNjAwMDYsImlhdCI6MTYxNDE2MzIxOCwiaXNzIjoiaHR0cHM6Ly9vaWRjdGVzdC53c3dlZXQub3JnLyIsImF0X2hhc2giOiJIVGswOVNjSjRObEFua3k5SGFFX2VRIiwiYWNyIjoibG9hLTIiLCJleHAiOjE2MTQxNjY4MTgsInN1YiI6ImR3aG8iLCJhenAiOiJwcml2YXRlIiwiYXVkIjpbInByaXZhdGUiXX0.N3TNufjKLzKM3qiIitA7JHUei4L572XjF6AcVl7UAFB6efdGUCiAL7amlUl0FgjZfzW9bzvulBVDidoYSicIaysIdI4KkjmjpVN0Z3gOSu0ecuk5p8fD1KbX6-tmA3txeR18nzfhdckq-S-6Lx7wrWpPNyrzGx-FImbOaUPN2yeVhKPXhdyHJbzI0RqJETxnBkyW-CLEzAJyq3rCUVX-D8kHADvg6a42QQyPdxvBuGrdBfyDDDb_Py13H1qhn40NnuFknR1wSahsY6U97uUooyk-0_U4J3XJAHySjCtivtSeP0fM_5eblMuh6WdVjrfnUF0xnCTbCa2gYRlTS38BkqcsWY26PXoRAOo31a1cmB5sMSZyPtRF9UZcmGiNBIymMMdFgVAJONb6uliiTS5j9-nkmHOqVC-XJ6tuiU3ZSBQ8nCRyNW2LaCzpJ5c3ytP9yYQtyT8HmhN0VnXob3K1uJEA_Xcu4sADjtrm-LbrGiwaVMkfu-C6YIrbuC9riOW6TneV2gAzAjXPOW_UZeXrCrx66GHIJPsJIq29UfbTN5Pxo9SH2yKw6PSfxevkZhBIhEXCOMaIUHrlWz2jDBBzPIWeiSRbK_MRtejQmdRUs8nqdq-McVwnFiUMDt1KZXxqScTtMDF_Lo9oK2RaCijEJ7MSPEscr_YOyp3KIq2FLVg",
"token_type" : "Bearer"
}
Logout
------
To kill SSO session, call the OIDC logout endpoint. By default a confirmation is requested, but you can bypass it by adding `confirm=1` to URL.
Parameters needed:
* SSO session id (will be passed in `lemonldap` cookie)
.. code-block:: shell
curl -s -D - -o /dev/null -b lemonldap=0640f95827111f00ba7ad5863ba819fe46cfbcecdb18ce525836369fb4c8350b 'https://oidctest.wsweet.org/oauth2/logout?confirm=1'
The session is deleted on server side and the cookie is destroyed in the browser. You can use the introspection endpoint to verify that the access token is no longer valid.

View File

@ -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: .\" Standard preamble:
.\" ======================================================================== .\" ========================================================================
@ -133,7 +133,7 @@
.\" ======================================================================== .\" ========================================================================
.\" .\"
.IX Title "llng-fastcgi-server 8" .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 .\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents. .\" way too many mistakes in technical documents.
.if n .ad l .if n .ad l

View File

@ -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 $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 $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)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|CertificateResetByMail|GeneratePassword|PasswordPolicy)|E(?:rrorOn(?:ExpiredSession|MailNotFound)|nablePasswordDisplay)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxy(?:AuthServiceImpersonation|UseSoap))|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)|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)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|CertificateResetByMail|GeneratePassword|PasswordPolicy)|E(?:rrorOn(?:ExpiredSession|MailNotFound)|nablePasswordDisplay)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxy(?:AuthServiceImpersonation|UseSoap))|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)|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' ); our @sessionTypes = ( 'remoteGlobal', 'global', 'localSession', 'persistent', 'saml', 'oidc', 'cas' );

View File

@ -186,8 +186,11 @@ sub defaultValues {
'multiValuesSeparator' => '; ', 'multiValuesSeparator' => '; ',
'mySessionAuthorizedRWKeys' => 'mySessionAuthorizedRWKeys' =>
[ '_appsListOrder', '_oidcConnectedRP', '_oidcConsents' ], [ '_appsListOrder', '_oidcConnectedRP', '_oidcConsents' ],
'notificationDefaultCond' => '', 'newLocationWarningLocationAttribute' => 'ipAddr',
'notificationServerPOST' => 1, 'newLocationWarningLocationDisplayAttribute' => '',
'newLocationWarningMaxValues' => '0',
'notificationDefaultCond' => '',
'notificationServerPOST' => 1,
'notificationServerSentAttributes' => 'notificationServerSentAttributes' =>
'uid reference date title subtitle text check', 'uid reference date title subtitle text check',
'notificationsMaxRetrieve' => 3, 'notificationsMaxRetrieve' => 3,

View File

@ -2067,6 +2067,31 @@ m[^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
[ '_appsListOrder', '_oidcConnectedRP', '_oidcConsents' ], [ '_appsListOrder', '_oidcConnectedRP', '_oidcConsents' ],
'type' => 'array' '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' => { 'nginxCustomHandlers' => {
'keyTest' => qr/^\w+$/, 'keyTest' => qr/^\w+$/,
'msgFail' => '__badPerlPackageName__', 'msgFail' => '__badPerlPackageName__',

View File

@ -579,6 +579,38 @@ sub attributes {
default => '^[*\w]+$', default => '^[*\w]+$',
documentation => 'Regular expression to validate parameters', 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 => { globalLogoutRule => {
type => 'boolOrExpr', type => 'boolOrExpr',
default => 0, default => 0,

View File

@ -1048,11 +1048,26 @@ sub tree {
{ {
title => 'CrowdSecPlugin', title => 'CrowdSecPlugin',
help => 'crowdsec.html', help => 'crowdsec.html',
form => 'simpleInputContainer',
nodes => [ nodes => [
'crowdsec', 'crowdsecAction', 'crowdsec', 'crowdsecAction',
'crowdsecUrl', 'crowdsecKey', 'crowdsecUrl', 'crowdsecKey',
], ],
}, },
{
title => 'newLocationWarnings',
help => 'newlocationwarning.html',
form => 'simpleInputContainer',
nodes => [
'newLocationWarning',
'newLocationWarningLocationAttribute',
'newLocationWarningLocationDisplayAttribute',
'newLocationWarningMaxValues',
'newLocationWarningMailAttribute',
'newLocationWarningMailSubject',
'newLocationWarningMailBody'
]
},
{ {
title => 'bruteForceAttackProtection', title => 'bruteForceAttackProtection',
help => 'bruteforceprotection.html', help => 'bruteforceprotection.html',

View File

@ -180,8 +180,8 @@
"cfgLog":"Summary", "cfgLog":"Summary",
"cfgVersion":"عملية ضبط الإصدارات", "cfgVersion":"عملية ضبط الإصدارات",
"checkDevOps":"تفعيل", "checkDevOps":"تفعيل",
"checkDevOpsDownload":"Download file",
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers", "checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
"checkDevOpsDownload":"Download file",
"checkState":"تفعيل", "checkState":"تفعيل",
"checkStateSecret":"سر مشترك", "checkStateSecret":"سر مشترك",
"checkUser":"تفعيل", "checkUser":"تفعيل",
@ -568,6 +568,14 @@
"newEntry":"أنتري جديد", "newEntry":"أنتري جديد",
"newGrantRule":"قاعدة منح جديدة", "newGrantRule":"قاعدة منح جديدة",
"newHost":"خادم جديد", "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 جديدة", "newPost":"استمارة وظيفة replay جديدة",
"newPostVar":"متغير جديد", "newPostVar":"متغير جديد",
"newRSAKey":"مفاتيح جديدة", "newRSAKey":"مفاتيح جديدة",
@ -1214,4 +1222,4 @@
"yubikey2fUrl":"خدمة أل يو أر ل", "yubikey2fUrl":"خدمة أل يو أر ل",
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey", "yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
"zeroConfExplanations":"لا يحتوي الخادم على إعدادات. استخدام قالب لحفظ الأول" "zeroConfExplanations":"لا يحتوي الخادم على إعدادات. استخدام قالب لحفظ الأول"
} }

View File

@ -180,8 +180,8 @@
"cfgLog":"Summary", "cfgLog":"Summary",
"cfgVersion":"Configuration version", "cfgVersion":"Configuration version",
"checkDevOps":"Activation", "checkDevOps":"Activation",
"checkDevOpsDownload":"Download file",
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers", "checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
"checkDevOpsDownload":"Download file",
"checkState":"Activation", "checkState":"Activation",
"checkStateSecret":"Shared secret", "checkStateSecret":"Shared secret",
"checkUser":"Activation", "checkUser":"Activation",
@ -568,6 +568,14 @@
"newEntry":"New entry", "newEntry":"New entry",
"newGrantRule":"New grant rule", "newGrantRule":"New grant rule",
"newHost":"New host", "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", "newPost":"New form replay",
"newPostVar":"New variable", "newPostVar":"New variable",
"newRSAKey":"New keys", "newRSAKey":"New keys",
@ -1214,4 +1222,4 @@
"yubikey2fUrl":"Service URL", "yubikey2fUrl":"Service URL",
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey", "yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
"zeroConfExplanations":"Server has no configuration. Use template to save the first." "zeroConfExplanations":"Server has no configuration. Use template to save the first."
} }

View File

@ -180,8 +180,8 @@
"cfgLog":"Summary", "cfgLog":"Summary",
"cfgVersion":"Configuration version", "cfgVersion":"Configuration version",
"checkDevOps":"Activation", "checkDevOps":"Activation",
"checkDevOpsDownload":"Download file",
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers", "checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
"checkDevOpsDownload":"Download file",
"checkState":"Activation", "checkState":"Activation",
"checkStateSecret":"Shared secret", "checkStateSecret":"Shared secret",
"checkUser":"Activation", "checkUser":"Activation",
@ -568,6 +568,14 @@
"newEntry":"New entry", "newEntry":"New entry",
"newGrantRule":"New grant rule", "newGrantRule":"New grant rule",
"newHost":"New host", "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", "newPost":"New form replay",
"newPostVar":"New variable", "newPostVar":"New variable",
"newRSAKey":"New keys", "newRSAKey":"New keys",

View File

@ -180,8 +180,8 @@
"cfgLog":"Sumario", "cfgLog":"Sumario",
"cfgVersion":"Configuration version", "cfgVersion":"Configuration version",
"checkDevOps":"Activación", "checkDevOps":"Activación",
"checkDevOpsDownload":"Download file",
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers", "checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
"checkDevOpsDownload":"Download file",
"checkState":"Activación", "checkState":"Activación",
"checkStateSecret":"Secreto compartido", "checkStateSecret":"Secreto compartido",
"checkUser":"Activación", "checkUser":"Activación",
@ -568,6 +568,14 @@
"newEntry":"Nueva entrada", "newEntry":"Nueva entrada",
"newGrantRule":"Nueva regla de admisión", "newGrantRule":"Nueva regla de admisión",
"newHost":"Nuevo host", "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", "newPost":"New form replay",
"newPostVar":"Nueva variable", "newPostVar":"Nueva variable",
"newRSAKey":"Nuevas claves", "newRSAKey":"Nuevas claves",
@ -1214,4 +1222,4 @@
"yubikey2fUrl":"Service URL", "yubikey2fUrl":"Service URL",
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey", "yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
"zeroConfExplanations":"Server has no configuration. Use template to save the first." "zeroConfExplanations":"Server has no configuration. Use template to save the first."
} }

View File

@ -180,8 +180,8 @@
"cfgLog":"Résumé", "cfgLog":"Résumé",
"cfgVersion":"Version de la configuration", "cfgVersion":"Version de la configuration",
"checkDevOps":"Activation", "checkDevOps":"Activation",
"checkDevOpsDownload":"Télécharger un fichier",
"checkDevOpsDisplayNormalizedHeaders":"Afficher les entêtes normalisés", "checkDevOpsDisplayNormalizedHeaders":"Afficher les entêtes normalisés",
"checkDevOpsDownload":"Télécharger un fichier",
"checkState":"Activation", "checkState":"Activation",
"checkStateSecret":"Secret partagé", "checkStateSecret":"Secret partagé",
"checkUser":"Activation", "checkUser":"Activation",
@ -568,6 +568,14 @@
"newEntry":"Nouvelle entrée", "newEntry":"Nouvelle entrée",
"newGrantRule":"Nouvelle règle d'accès", "newGrantRule":"Nouvelle règle d'accès",
"newHost":"Nouvel hôte", "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", "newPost":"Nouveau rejeu de formulaire",
"newPostVar":"Nouvelle variable", "newPostVar":"Nouvelle variable",
"newRSAKey":"Nouvelles clefs", "newRSAKey":"Nouvelles clefs",

View File

@ -180,8 +180,8 @@
"cfgLog":"Summary", "cfgLog":"Summary",
"cfgVersion":"Versione configurazione", "cfgVersion":"Versione configurazione",
"checkDevOps":"Activation", "checkDevOps":"Activation",
"checkDevOpsDownload":"Download file",
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers", "checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
"checkDevOpsDownload":"Download file",
"checkState":"Attivazione", "checkState":"Attivazione",
"checkStateSecret":"Segreto condiviso", "checkStateSecret":"Segreto condiviso",
"checkUser":"Attivazione", "checkUser":"Attivazione",
@ -568,6 +568,14 @@
"newEntry":"Nuova entrata", "newEntry":"Nuova entrata",
"newGrantRule":"Nuova regola di autorizzazione", "newGrantRule":"Nuova regola di autorizzazione",
"newHost":"Nuovo host", "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", "newPost":"Nuovo formulario di risposta",
"newPostVar":"Nuova variabile", "newPostVar":"Nuova variabile",
"newRSAKey":"Nuove chiavi", "newRSAKey":"Nuove chiavi",
@ -1214,4 +1222,4 @@
"yubikey2fUrl":"URL del servizio", "yubikey2fUrl":"URL del servizio",
"yubikey2fUserCanRemoveKey":"Autorizza l'utente a rimuovere la Yubikey", "yubikey2fUserCanRemoveKey":"Autorizza l'utente a rimuovere la Yubikey",
"zeroConfExplanations":"Il server non ha alcuna configurazione. Utilizza il modello per salvare il primo." "zeroConfExplanations":"Il server non ha alcuna configurazione. Utilizza il modello per salvare il primo."
} }

View File

@ -180,8 +180,8 @@
"cfgLog":"Podsumowanie", "cfgLog":"Podsumowanie",
"cfgVersion":"Wersja konfiguracji", "cfgVersion":"Wersja konfiguracji",
"checkDevOps":"Aktywacja", "checkDevOps":"Aktywacja",
"checkDevOpsDownload":"Download file",
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers", "checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
"checkDevOpsDownload":"Download file",
"checkState":"Aktywacja", "checkState":"Aktywacja",
"checkStateSecret":"Współdzielony sekret", "checkStateSecret":"Współdzielony sekret",
"checkUser":"Aktywacja", "checkUser":"Aktywacja",
@ -568,6 +568,14 @@
"newEntry":"Nowy wpis", "newEntry":"Nowy wpis",
"newGrantRule":"Nowa reguła przyznawania", "newGrantRule":"Nowa reguła przyznawania",
"newHost":"Nowy host", "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", "newPost":"Nowy formularz powtórzenia",
"newPostVar":"Nowa zmienna", "newPostVar":"Nowa zmienna",
"newRSAKey":"Nowe klucze", "newRSAKey":"Nowe klucze",
@ -1214,4 +1222,4 @@
"yubikey2fUrl":"URL usługi", "yubikey2fUrl":"URL usługi",
"yubikey2fUserCanRemoveKey":"Pozwól użytkownikowi usunąć Yubikey", "yubikey2fUserCanRemoveKey":"Pozwól użytkownikowi usunąć Yubikey",
"zeroConfExplanations":"Serwer nie ma konfiguracji. Użyj szablonu, aby zapisać pierwszy." "zeroConfExplanations":"Serwer nie ma konfiguracji. Użyj szablonu, aby zapisać pierwszy."
} }

View File

@ -180,8 +180,8 @@
"cfgLog":"Özet", "cfgLog":"Özet",
"cfgVersion":"Yapılandırma sürümü", "cfgVersion":"Yapılandırma sürümü",
"checkDevOps":"Aktivasyon", "checkDevOps":"Aktivasyon",
"checkDevOpsDownload":"Dosyayı indir",
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers", "checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
"checkDevOpsDownload":"Dosyayı indir",
"checkState":"Aktivasyon", "checkState":"Aktivasyon",
"checkStateSecret":"Paylaşılan sır", "checkStateSecret":"Paylaşılan sır",
"checkUser":"Aktivasyon", "checkUser":"Aktivasyon",
@ -568,6 +568,14 @@
"newEntry":"Yeni kayıt", "newEntry":"Yeni kayıt",
"newGrantRule":"Yeni imtiyaz kuralı", "newGrantRule":"Yeni imtiyaz kuralı",
"newHost":"Yeni konak", "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ı", "newPost":"Yeni form tekrarı",
"newPostVar":"Yeni değişken", "newPostVar":"Yeni değişken",
"newRSAKey":"Yeni anahtarlar", "newRSAKey":"Yeni anahtarlar",
@ -1214,4 +1222,4 @@
"yubikey2fUrl":"Servis URL'si", "yubikey2fUrl":"Servis URL'si",
"yubikey2fUserCanRemoveKey":"Yubikey'i kaldırmak için kullanıcıya izin ver", "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." "zeroConfExplanations":"Sunucunun yapılandırması yok. Şimdi bir tane kaydetmek için şablonu kullanın."
} }

View File

@ -180,8 +180,8 @@
"cfgLog":"Summary", "cfgLog":"Summary",
"cfgVersion":"Phiên bản cấu hình", "cfgVersion":"Phiên bản cấu hình",
"checkDevOps":"Activation", "checkDevOps":"Activation",
"checkDevOpsDownload":"Download file",
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers", "checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
"checkDevOpsDownload":"Download file",
"checkState":"Kích hoạt", "checkState":"Kích hoạt",
"checkStateSecret":"Chia sẻ bí mật", "checkStateSecret":"Chia sẻ bí mật",
"checkUser":"Kích hoạt", "checkUser":"Kích hoạt",
@ -568,6 +568,14 @@
"newEntry":"Mục nhập mới", "newEntry":"Mục nhập mới",
"newGrantRule":"Quy tắc cấp mới", "newGrantRule":"Quy tắc cấp mới",
"newHost":"Máy chủ 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", "newPost":"Phát lại mẫu mới",
"newPostVar":"Biến mới", "newPostVar":"Biến mới",
"newRSAKey":"Khóa mới", "newRSAKey":"Khóa mới",
@ -1214,4 +1222,4 @@
"yubikey2fUrl":"Dịch vụ URL", "yubikey2fUrl":"Dịch vụ URL",
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey", "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. " "zeroConfExplanations":"Máy chủ không có cấu hình. Sử dụng mẫu để lưu đầu tiên. "
} }

View File

@ -180,8 +180,8 @@
"cfgLog":"Summary", "cfgLog":"Summary",
"cfgVersion":"配置信息", "cfgVersion":"配置信息",
"checkDevOps":"Activation", "checkDevOps":"Activation",
"checkDevOpsDownload":"Download file",
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers", "checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
"checkDevOpsDownload":"Download file",
"checkState":"激活", "checkState":"激活",
"checkStateSecret":"Shared secret", "checkStateSecret":"Shared secret",
"checkUser":"激活", "checkUser":"激活",
@ -568,6 +568,14 @@
"newEntry":"New entry", "newEntry":"New entry",
"newGrantRule":"New grant rule", "newGrantRule":"New grant rule",
"newHost":"New host", "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", "newPost":"New form replay",
"newPostVar":"New variable", "newPostVar":"New variable",
"newRSAKey":"New keys", "newRSAKey":"New keys",
@ -1214,4 +1222,4 @@
"yubikey2fUrl":"Service URL", "yubikey2fUrl":"Service URL",
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey", "yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
"zeroConfExplanations":"Server has no configuration. Use template to save the first." "zeroConfExplanations":"Server has no configuration. Use template to save the first."
} }

View File

@ -180,8 +180,8 @@
"cfgLog":"概要", "cfgLog":"概要",
"cfgVersion":"設定版本", "cfgVersion":"設定版本",
"checkDevOps":"啟用", "checkDevOps":"啟用",
"checkDevOpsDownload":"Download file",
"checkDevOpsDisplayNormalizedHeaders":"Display normalized headers", "checkDevOpsDisplayNormalizedHeaders":"Display normalized headers",
"checkDevOpsDownload":"Download file",
"checkState":"啟用", "checkState":"啟用",
"checkStateSecret":"已分享的祕密", "checkStateSecret":"已分享的祕密",
"checkUser":"啟用", "checkUser":"啟用",
@ -568,6 +568,14 @@
"newEntry":"新項目", "newEntry":"新項目",
"newGrantRule":"新授權規則", "newGrantRule":"新授權規則",
"newHost":"新主機", "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":"新表單重新進行", "newPost":"新表單重新進行",
"newPostVar":"新變數", "newPostVar":"新變數",
"newRSAKey":"新金鑰", "newRSAKey":"新金鑰",
@ -1214,4 +1222,4 @@
"yubikey2fUrl":"服務 URL", "yubikey2fUrl":"服務 URL",
"yubikey2fUserCanRemoveKey":"允許使用者移除 Yubikey", "yubikey2fUserCanRemoveKey":"允許使用者移除 Yubikey",
"zeroConfExplanations":"伺服器未設定。使用飯本來儲存第一個。" "zeroConfExplanations":"伺服器未設定。使用飯本來儲存第一個。"
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -120,6 +120,7 @@ lib/Lemonldap/NG/Portal/Plugins/GrantSession.pm
lib/Lemonldap/NG/Portal/Plugins/History.pm lib/Lemonldap/NG/Portal/Plugins/History.pm
lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm
lib/Lemonldap/NG/Portal/Plugins/MailPasswordReset.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/Notifications.pm
lib/Lemonldap/NG/Portal/Plugins/PublicPages.pm lib/Lemonldap/NG/Portal/Plugins/PublicPages.pm
lib/Lemonldap/NG/Portal/Plugins/Refresh.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_confirm.tpl
site/templates/common/mail_footer.tpl site/templates/common/mail_footer.tpl
site/templates/common/mail_header.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_password.tpl
site/templates/common/mail_register_confirm.tpl site/templates/common/mail_register_confirm.tpl
site/templates/common/mail_register_done.tpl site/templates/common/mail_register_done.tpl
@ -510,7 +512,7 @@ t/24-AuthKerberos.t
t/25-AuthSlave-with-Choice.t t/25-AuthSlave-with-Choice.t
t/25-AuthSlave-with-Credentials.t t/25-AuthSlave-with-Credentials.t
t/26-AuthRemote.t t/26-AuthRemote.t
t/27-AuthProxy-choice.t t/27-AuthProxy-with-choice.t
t/27-AuthProxy.t t/27-AuthProxy.t
t/28-AuthChoice-and-password.t t/28-AuthChoice-and-password.t
t/28-AuthChoice-with-captcha.t t/28-AuthChoice-with-captcha.t
@ -675,6 +677,8 @@ t/61-CrowdSec-warn.t
t/61-CrowdSec.t t/61-CrowdSec.t
t/61-ForceAuthn.t t/61-ForceAuthn.t
t/61-GrantSession.t t/61-GrantSession.t
t/61-NewLocationWarning-Custom.t
t/61-NewLocationWarning.t
t/61-Session-ActivityTimeout.t t/61-Session-ActivityTimeout.t
t/61-Session-Timeout.t t/61-Session-Timeout.t
t/62-Refresh-plugin.t t/62-Refresh-plugin.t

View File

@ -33,7 +33,8 @@ our @pList = (
contextSwitchingRule => '::Plugins::ContextSwitching', contextSwitchingRule => '::Plugins::ContextSwitching',
decryptValueRule => '::Plugins::DecryptValue', decryptValueRule => '::Plugins::DecryptValue',
findUser => '::Plugins::FindUser', findUser => '::Plugins::FindUser',
adaptativeAuthenticationLevelRules => newLocationWarning => '::Plugins::NewLocationWarning',
adaptativeAuthenticationLevelRules =>
'::Plugins::AdaptativeAuthenticationLevel', '::Plugins::AdaptativeAuthenticationLevel',
globalLogoutRule => '::Plugins::GlobalLogout', globalLogoutRule => '::Plugins::GlobalLogout',
refreshSessions => '::Plugins::Refresh', refreshSessions => '::Plugins::Refresh',

View File

@ -0,0 +1,171 @@
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->{_riskLevel} = $riskLevel;
$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;

View File

@ -618,11 +618,11 @@ $(window).on 'load', () ->
user = data.user user = data.user
console.log 'Suggested spoofId=', user console.log 'Suggested spoofId=', user
$("input[name=spoofId]").each -> $("input[name=spoofId]").each ->
$(this).attr 'value', user $(this).val user
$('#captcha').attr 'src', data.captcha if data.captcha $('#captcha').attr 'src', data.captcha if data.captcha
if data.token if data.token
$('#finduserToken').attr 'value', data.token $('#finduserToken').val data.token
$('#token').attr 'value', data.token $('#token').val data.token
error: (j, status, err) -> error: (j, status, err) ->
document.body.style.cursor = 'default' document.body.style.cursor = 'default'
console.log 'Error', err if err console.log 'Error', err if err

View File

@ -687,14 +687,14 @@ LemonLDAP::NG Portal jQuery scripts
user = data.user; user = data.user;
console.log('Suggested spoofId=', user); console.log('Suggested spoofId=', user);
$("input[name=spoofId]").each(function() { $("input[name=spoofId]").each(function() {
return $(this).attr('value', user); return $(this).val(user);
}); });
if (data.captcha) { if (data.captcha) {
$('#captcha').attr('src', data.captcha); $('#captcha').attr('src', data.captcha);
} }
if (data.token) { if (data.token) {
$('#finduserToken').attr('value', data.token); $('#finduserToken').val(data.token);
return $('#token').attr('value', data.token); return $('#token').val(data.token);
} }
}, },
error: function(j, status, err) { error: function(j, status, err) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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);

View File

@ -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"}

View File

@ -6,15 +6,20 @@
"click2Reset":"انقر هنا لإعادة تعيين كلمة المرور", "click2Reset":"انقر هنا لإعادة تعيين كلمة المرور",
"goToPortal":"انتقل إلى البوابة", "goToPortal":"انتقل إلى البوابة",
"hello":"مرحبا ", "hello":"مرحبا ",
"host":"Host",
"location": "Location",
"mail2fSubject":"[LemonLDAP::NG] تسجيل الدخول الخاص بك هو ", "mail2fSubject":"[LemonLDAP::NG] تسجيل الدخول الخاص بك هو ",
"mailConfirmSubject":"تأكيد إعادة تعيين كلمة المرور[LemonLDAP::NG]", "mailConfirmSubject":"تأكيد إعادة تعيين كلمة المرور[LemonLDAP::NG]",
"mailSubject":"كلمة المرور الجديدة [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":"كلمة المرور الجديدة هي", "newPwdIs":"كلمة المرور الجديدة هي",
"pwdChanged":"تم تغيير كلمة المرور الخاصة بك", "pwdChanged":"تم تغيير كلمة المرور الخاصة بك",
"pwdIs":"كلمة المرور الخاصة بك هي", "pwdIs":"كلمة المرور الخاصة بك هي",
"registerConfirmSubject":"تأكيد تسجيل الحساب[LemonLDAP::NG] ", "registerConfirmSubject":"تأكيد تسجيل الحساب[LemonLDAP::NG] ",
"registerDoneSubject":"حسابك الجديد[LemonLDAP::NG]", "registerDoneSubject":"حسابك الجديد[LemonLDAP::NG]",
"requestIssuedFromIP":"الطلب قد أرسل من عنوان الآي بي", "requestIssuedFromIP":"الطلب قد أرسل من عنوان الآي بي",
"date":"Date",
"yourLoginCodeIs":"Your login code is", "yourLoginCodeIs":"Your login code is",
"yourLoginIs":"تسجيل الدخول الخاص بك هو" "yourLoginIs":"تسجيل الدخول الخاص بك هو"
} }

View File

@ -6,15 +6,20 @@
"click2Reset":"Click here to reset your password", "click2Reset":"Click here to reset your password",
"goToPortal":"Go to portal", "goToPortal":"Go to portal",
"hello":"Hello", "hello":"Hello",
"host":"Host",
"location": "Location",
"mail2fSubject":"[LemonLDAP::NG] Your login code", "mail2fSubject":"[LemonLDAP::NG] Your login code",
"mailConfirmSubject": "[LemonLDAP::NG] Password reset confirmation", "mailConfirmSubject": "[LemonLDAP::NG] Password reset confirmation",
"mailSubject": "[LemonLDAP::NG] Your new password", "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", "newPwdIs":"Your new password is",
"pwdChanged":"Your password was changed.", "pwdChanged":"Your password was changed.",
"pwdIs":"Your password is", "pwdIs":"Your password is",
"registerConfirmSubject": "[LemonLDAP::NG] Account register confirmation", "registerConfirmSubject": "[LemonLDAP::NG] Account register confirmation",
"registerDoneSubject": "[LemonLDAP::NG] Your new account", "registerDoneSubject": "[LemonLDAP::NG] Your new account",
"requestIssuedFromIP":"The request was issued from IP", "requestIssuedFromIP":"The request was issued from IP",
"date":"Date",
"yourLoginCodeIs":"Your login code is", "yourLoginCodeIs":"Your login code is",
"yourLoginIs":"Your login is" "yourLoginIs":"Your login is"
} }

View File

@ -6,15 +6,20 @@
"click2Reset":"Haga clic para reiniciar su contraseña", "click2Reset":"Haga clic para reiniciar su contraseña",
"goToPortal":"Ir al portal", "goToPortal":"Ir al portal",
"hello":"Hola", "hello":"Hola",
"host":"Host",
"location": "Location",
"mail2fSubject":"[LemonLDAP::NG] Su código de acceso", "mail2fSubject":"[LemonLDAP::NG] Su código de acceso",
"mailConfirmSubject":"[LemonLDAP::NG] Confirmación de reinicio de contraseña", "mailConfirmSubject":"[LemonLDAP::NG] Confirmación de reinicio de contraseña",
"mailSubject":"[LemonLDAP::NG] Su nueva 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", "newPwdIs":"Su nueva contraseña es",
"pwdChanged":"Su contraseña ha sido cambiada.", "pwdChanged":"Su contraseña ha sido cambiada.",
"pwdIs":"Su contraseña es", "pwdIs":"Su contraseña es",
"registerConfirmSubject":"[LemonLDAP::NG] Confirmación de creación de cuenta", "registerConfirmSubject":"[LemonLDAP::NG] Confirmación de creación de cuenta",
"registerDoneSubject":"[LemonLDAP::NG] Su nueva cuenta", "registerDoneSubject":"[LemonLDAP::NG] Su nueva cuenta",
"requestIssuedFromIP":"El pedido fue emitido desde la IP", "requestIssuedFromIP":"El pedido fue emitido desde la IP",
"date":"Date",
"yourLoginCodeIs":"Su código de acceso es ", "yourLoginCodeIs":"Su código de acceso es ",
"yourLoginIs":"Su nombre de usuario es" "yourLoginIs":"Su nombre de usuario es"
} }

View File

@ -6,15 +6,20 @@
"click2Reset":"Klikkaa tästä nollataksesi salasanasi", "click2Reset":"Klikkaa tästä nollataksesi salasanasi",
"goToPortal":"Siirry portaaliin", "goToPortal":"Siirry portaaliin",
"hello":"Hei", "hello":"Hei",
"host":"Host",
"location":"Location",
"mail2fSubject":"[LemonLDAP::NG] Your login code", "mail2fSubject":"[LemonLDAP::NG] Your login code",
"mailConfirmSubject":"[LemonLDAP::NG] Salasanan nollauksen vahvistus", "mailConfirmSubject":"[LemonLDAP::NG] Salasanan nollauksen vahvistus",
"mailSubject":"[LemonLDAP::NG] Uusi salasanasi", "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", "newPwdIs":"Uusi salasanasi on",
"pwdChanged":"Salasanasi on vaihdettu.", "pwdChanged":"Salasanasi on vaihdettu.",
"pwdIs":"Sinun salasanasi on", "pwdIs":"Sinun salasanasi on",
"registerConfirmSubject":"[LemonLDAP::NG] Tunnuksen rekisteröinnin vahvistus", "registerConfirmSubject":"[LemonLDAP::NG] Tunnuksen rekisteröinnin vahvistus",
"registerDoneSubject":"[LemonLDAP::NG] Uusi käyttäjätunnuksesi", "registerDoneSubject":"[LemonLDAP::NG] Uusi käyttäjätunnuksesi",
"requestIssuedFromIP":"The request was issued from IP", "requestIssuedFromIP":"The request was issued from IP",
"date":"Date",
"yourLoginCodeIs":"Your login code is", "yourLoginCodeIs":"Your login code is",
"yourLoginIs":"Your login is" "yourLoginIs":"Your login is"
} }

View File

@ -6,15 +6,20 @@
"click2Reset":"Cliquez ici pour réinitialiser votre mot de passe", "click2Reset":"Cliquez ici pour réinitialiser votre mot de passe",
"goToPortal":"Aller au portail", "goToPortal":"Aller au portail",
"hello":"Bonjour", "hello":"Bonjour",
"host":"Hôte",
"location":"Localisation",
"mail2fSubject":"[LemonLDAP::NG] Votre code de connexion", "mail2fSubject":"[LemonLDAP::NG] Votre code de connexion",
"mailConfirmSubject": "[LemonLDAP::NG] Confirmation de réinitialisation de mot de passe", "mailConfirmSubject": "[LemonLDAP::NG] Confirmation de réinitialisation de mot de passe",
"mailSubject": "[LemonLDAP::NG] Votre nouveau 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", "newPwdIs":"Votre nouveau mot de passe est",
"pwdChanged":"Votre mot de passe a été changé.", "pwdChanged":"Votre mot de passe a été changé.",
"pwdIs":"Votre mot de passe est", "pwdIs":"Votre mot de passe est",
"registerConfirmSubject": "[LemonLDAP::NG] Confirmation d'enregistrement de compte", "registerConfirmSubject": "[LemonLDAP::NG] Confirmation d'enregistrement de compte",
"registerDoneSubject": "[LemonLDAP::NG] Votre nouveau compte", "registerDoneSubject": "[LemonLDAP::NG] Votre nouveau compte",
"requestIssuedFromIP":"La demande provient de l'IP", "requestIssuedFromIP":"La demande provient de l'IP",
"date":"Date",
"yourLoginCodeIs":"Votre code de connexion est", "yourLoginCodeIs":"Votre code de connexion est",
"yourLoginIs":"Votre identifiant est" "yourLoginIs":"Votre identifiant est"
} }

View File

@ -6,15 +6,20 @@
"click2Reset":"Clicca qui per reimpostare la password", "click2Reset":"Clicca qui per reimpostare la password",
"goToPortal":"Vai al portale", "goToPortal":"Vai al portale",
"hello":"Salve", "hello":"Salve",
"host":"Host",
"location":"Location",
"mail2fSubject":"[LemonLDAP :: NG] Il tuo codice di accesso", "mail2fSubject":"[LemonLDAP :: NG] Il tuo codice di accesso",
"mailConfirmSubject":"Conferma reimpostazione password [LemonLDAP::NG] ", "mailConfirmSubject":"Conferma reimpostazione password [LemonLDAP::NG] ",
"mailSubject":"[LemonLDAP::NG] La tua nuova password", "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 é", "newPwdIs":"La tua nuova password é",
"pwdChanged":"La tua password é stata cambiata", "pwdChanged":"La tua password é stata cambiata",
"pwdIs":"La tua password é", "pwdIs":"La tua password é",
"registerConfirmSubject":"[LemonLDAP :: NG] Conferma registro account", "registerConfirmSubject":"[LemonLDAP :: NG] Conferma registro account",
"registerDoneSubject":"[LemonLDAP::NG] Il tuo nuovo account", "registerDoneSubject":"[LemonLDAP::NG] Il tuo nuovo account",
"requestIssuedFromIP":"La richiesta è stata emessa da IP", "requestIssuedFromIP":"La richiesta è stata emessa da IP",
"date":"Date",
"yourLoginCodeIs":"Il tuo codice di accesso è", "yourLoginCodeIs":"Il tuo codice di accesso è",
"yourLoginIs":"Il tuo login é" "yourLoginIs":"Il tuo login é"
} }

View File

@ -6,15 +6,20 @@
"click2Reset":"Kilik disini untuk menetapkan semula kata laluan anda", "click2Reset":"Kilik disini untuk menetapkan semula kata laluan anda",
"goToPortal":"Go to portal", "goToPortal":"Go to portal",
"hello":"Hello", "hello":"Hello",
"host":"Host",
"location":"Location",
"mail2fSubject":"[LemonLDAP::NG] Kod login anda", "mail2fSubject":"[LemonLDAP::NG] Kod login anda",
"mailConfirmSubject":"[LemonLDAP::NG] Pengesahan penetapan semula kata laluan", "mailConfirmSubject":"[LemonLDAP::NG] Pengesahan penetapan semula kata laluan",
"mailSubject":"[LemonLDAP::NG] Kata laluan baru anda", "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", "newPwdIs":"Kata laluan baru anda ialah",
"pwdChanged":"Kata laluan anda telah ditukar", "pwdChanged":"Kata laluan anda telah ditukar",
"pwdIs":"Kata laluan anda ialah", "pwdIs":"Kata laluan anda ialah",
"registerConfirmSubject":"[LemonLDAP::NG] Pengesahan pendaftaran akaun", "registerConfirmSubject":"[LemonLDAP::NG] Pengesahan pendaftaran akaun",
"registerDoneSubject":"[LemonLDAP::NG] Akaun baru anda", "registerDoneSubject":"[LemonLDAP::NG] Akaun baru anda",
"requestIssuedFromIP":"Permintaan itu dari alamat IP", "requestIssuedFromIP":"Permintaan itu dari alamat IP",
"date":"Date",
"yourLoginCodeIs":"Kod login anda ialah", "yourLoginCodeIs":"Kod login anda ialah",
"yourLoginIs":"Login anda ialah" "yourLoginIs":"Login anda ialah"
} }

View File

@ -6,15 +6,20 @@
"click2Reset":"Parolanızı sıfırlamak için buraya tıklayın", "click2Reset":"Parolanızı sıfırlamak için buraya tıklayın",
"goToPortal":"Portala git", "goToPortal":"Portala git",
"hello":"Merhaba", "hello":"Merhaba",
"host":"Host",
"location":"Location",
"mail2fSubject":"[LemonLDAP::NG] Giriş kodunuz", "mail2fSubject":"[LemonLDAP::NG] Giriş kodunuz",
"mailConfirmSubject":"[LemonLDAP::NG] Parola sıfırlama onayı", "mailConfirmSubject":"[LemonLDAP::NG] Parola sıfırlama onayı",
"mailSubject":"[LemonLDAP::NG] Yeni parolanız", "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", "newPwdIs":"Yeni parolanız",
"pwdChanged":"Parolanız değiştirildi.", "pwdChanged":"Parolanız değiştirildi.",
"pwdIs":"Parolanız", "pwdIs":"Parolanız",
"registerConfirmSubject":"[LemonLDAP::NG] Hesap açma onayı", "registerConfirmSubject":"[LemonLDAP::NG] Hesap açma onayı",
"registerDoneSubject":"[LemonLDAP::NG] Yeni hesabınız", "registerDoneSubject":"[LemonLDAP::NG] Yeni hesabınız",
"requestIssuedFromIP":"İstek IP'den gönderildi", "requestIssuedFromIP":"İstek IP'den gönderildi",
"date":"Date",
"yourLoginCodeIs":"Giriş kodunuz", "yourLoginCodeIs":"Giriş kodunuz",
"yourLoginIs":"Giriş bilgileriniz" "yourLoginIs":"Giriş bilgileriniz"
} }

View File

@ -6,15 +6,20 @@
"click2Reset":"Nhấn ở đây để thiết lập lại mật khẩu của bạn", "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", "goToPortal":"Đi tới cổng thông tin",
"hello":"Xin chào", "hello":"Xin chào",
"host":"Host",
"location":"Location",
"mail2fSubject":"[LemonLDAP::NG] Your login code", "mail2fSubject":"[LemonLDAP::NG] Your login code",
"mailConfirmSubject":"[LemonLDAP::NG] Xác nhận thiết lập lại mật khẩu", "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", "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à", "newPwdIs":"Mật khẩu mới của bạn là",
"pwdChanged":"Mật khẩu của bạn đã được thay đổi.", "pwdChanged":"Mật khẩu của bạn đã được thay đổi.",
"pwdIs":"Mật khẩu của bạn là", "pwdIs":"Mật khẩu của bạn là",
"registerConfirmSubject":"[LemonLDAP::NG] Xác nhận đăng ký tài khoản", "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", "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", "requestIssuedFromIP":"Yêu cầu được gửi đi từ địa chỉ IP",
"date":"Date",
"yourLoginCodeIs":"Your login code is", "yourLoginCodeIs":"Your login code is",
"yourLoginIs":"Đăng nhập của bạn là" "yourLoginIs":"Đăng nhập của bạn là"
} }

View File

@ -6,15 +6,20 @@
"click2Reset":"请点击此处充值您的密码", "click2Reset":"请点击此处充值您的密码",
"goToPortal":"回到首页", "goToPortal":"回到首页",
"hello":"您好", "hello":"您好",
"host":"Host",
"location":"Location",
"mail2fSubject":"[LemonLDAP::NG] Your login code", "mail2fSubject":"[LemonLDAP::NG] Your login code",
"mailConfirmSubject":"[LemonLDAP::NG] 密码重置确认", "mailConfirmSubject":"[LemonLDAP::NG] 密码重置确认",
"mailSubject":"[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":"您的新密码是", "newPwdIs":"您的新密码是",
"pwdChanged":"您的密码已经修改", "pwdChanged":"您的密码已经修改",
"pwdIs":"您的密码是", "pwdIs":"您的密码是",
"registerConfirmSubject":"[LemonLDAP::NG] 账号注册确认", "registerConfirmSubject":"[LemonLDAP::NG] 账号注册确认",
"registerDoneSubject":"[LemonLDAP::NG] 您的新账号", "registerDoneSubject":"[LemonLDAP::NG] 您的新账号",
"requestIssuedFromIP":"此请求来自IP地址", "requestIssuedFromIP":"此请求来自IP地址",
"date":"Date",
"yourLoginCodeIs":"Your login code is", "yourLoginCodeIs":"Your login code is",
"yourLoginIs":"您登陆的账户是" "yourLoginIs":"您登陆的账户是"
} }

View File

@ -6,15 +6,20 @@
"click2Reset":"點擊此處以重設您的密碼", "click2Reset":"點擊此處以重設您的密碼",
"goToPortal":"回到首頁", "goToPortal":"回到首頁",
"hello":"您好", "hello":"您好",
"host":"Host",
"location":"Location",
"mail2fSubject":"[LemonLDAP::NG] 您的登入代碼", "mail2fSubject":"[LemonLDAP::NG] 您的登入代碼",
"mailConfirmSubject":"[LemonLDAP::NG] 確認重設密碼", "mailConfirmSubject":"[LemonLDAP::NG] 確認重設密碼",
"mailSubject":"[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":"您的新密碼為", "newPwdIs":"您的新密碼為",
"pwdChanged":"您的密碼已變更", "pwdChanged":"您的密碼已變更",
"pwdIs":"您的密碼為", "pwdIs":"您的密碼為",
"registerConfirmSubject":"[LemonLDAP::NG] 確認帳號註冊", "registerConfirmSubject":"[LemonLDAP::NG] 確認帳號註冊",
"registerDoneSubject":"[LemonLDAP::NG] 您的新帳號", "registerDoneSubject":"[LemonLDAP::NG] 您的新帳號",
"requestIssuedFromIP":"請求發出從 IP", "requestIssuedFromIP":"請求發出從 IP",
"date":"Date",
"yourLoginCodeIs":"您的登入代碼為", "yourLoginCodeIs":"您的登入代碼為",
"yourLoginIs":"您的登入為" "yourLoginIs":"您的登入為"
} }

View File

@ -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">

View 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() );

View 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() );

View File

@ -1,17 +1,23 @@
package main; package main;
my ($mail, $mail_envelope, $mail_subject); my ( $mail, $mail_envelope, $mail_subject );
sub mail { sub mail {
return $mail; return $mail;
} }
sub clear_mail {
$mail = undef;
$mail_envelope = undef;
$mail_subject = undef;
}
sub envelope { sub envelope {
return $mail_envelope; return $mail_envelope;
} }
sub subject { sub subject {
my $subject = ($mail_subject =~ /=\?utf-8\?B\?(.+?)\?=/)[0]; my $subject = ( $mail_subject =~ /=\?utf-8\?B\?(.+?)\?=/ )[0];
return decode_base64($subject); return decode_base64($subject);
} }