rememberAuthChoice: reconciliation with v2.0 branch (#2737)
This commit is contained in:
commit
8f4eb83a2e
20
Makefile
20
Makefile
|
@ -887,23 +887,9 @@ install_examples_site:
|
|||
install_doc_site:
|
||||
# Offline documentation install
|
||||
@rm -rf $(RDEFDOCDIR)
|
||||
# Install doc directories
|
||||
@install -v -d -m 755 $(RDEFDOCDIR)
|
||||
@cd doc && find * -type d |(cd $(RDEFDOCDIR); xargs install -v -d -m 755) && cd -
|
||||
# Install HTML files
|
||||
@cd doc && for f in `find * -type f -name '*.html'`; do \
|
||||
echo "Installing $$f"; \
|
||||
../scripts/transform-templates \
|
||||
usedebianlibs $(USEDEBIANLIBS) \
|
||||
useexternallibs $(USEEXTERNALLIBS) \
|
||||
jsminified $(JSCOMPRESS) \
|
||||
cssminified $(CSSCOMPRESS) <$$f \
|
||||
> $(RDEFDOCDIR)/$$f; \
|
||||
done && cd -
|
||||
# Install other files
|
||||
@cd doc && for f in `find * -type f ! -name '*.html'`; do \
|
||||
install -v -m 644 $$f $(RDEFDOCDIR)/$$f; \
|
||||
done && cd -
|
||||
@cd doc && find index.html pages/* -type f ! -path '*/.*' -exec install -v -m 644 -D '{}' $(RDEFDOCDIR)/'{}' \; && cd -
|
||||
|
||||
# Remove js
|
||||
@cd $(RDEFDOCDIR) && if test "$(USEEXTERNALLIBS)" = "yes"; then \
|
||||
rm -rvf $(DOCEXTERNALLIBS); \
|
||||
|
@ -1105,7 +1091,7 @@ debian-dist: clean
|
|||
@cp lemonldap-ng-$(VERSION)/_example/etc/api-apache2.X.conf lemonldap-ng-$(VERSION)/_example/etc/api-apache2.conf
|
||||
@cp lemonldap-ng-$(VERSION)/_example/etc/test-apache2.X.conf lemonldap-ng-$(VERSION)/_example/etc/test-apache2.conf
|
||||
@rm -rf lemonldap-ng-$(VERSION)/lemonldap-ng-$(VERSION)
|
||||
@find lemonldap-ng-$(VERSION)/ -name node_modules -exec rm -rf '{}' \;
|
||||
-@find lemonldap-ng-$(VERSION)/ -name node_modules -exec rm -rf '{}' \;
|
||||
@$(COMPRESS) lemonldap-ng_$(VERSION).orig.$(COMPRESSSUFFIX) lemonldap-ng-$(VERSION)
|
||||
@rm -rf lemonldap-ng-$(VERSION)
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ Application Configuration
|
|||
.. image:: applications/simplesamlphp_logo.png :doc:`simpleSAMLphp<applications/simplesamlphp>` ✔
|
||||
.. image:: applications/spring_logo.png :doc:`Spring<applications/spring>` ✔
|
||||
.. image:: applications/symfony_logo.png :doc:`Symfony<applications/symfony>` ✔
|
||||
.. image:: applications/sympa_logo.png :doc:`Sympa<applications/sympa>` ✔
|
||||
.. image:: applications/sympa_logo.png :doc:`Sympa<applications/sympa>` ✔ ✔
|
||||
.. image:: applications/tomcat_logo.png :doc:`Tomcat<applications/tomcat>` ✔
|
||||
.. image:: applications/wekan-logo.png :doc:`Wekan<applications/wekan>` ✔
|
||||
.. image:: applications/wiki.js.svg :doc:`Wiki.js<applications/wikijs>` ✔
|
||||
|
|
|
@ -8,9 +8,59 @@ Presentation
|
|||
|
||||
`Sympa <http://www.sympa.org>`__ is a mailing list manager.
|
||||
|
||||
To configure SSO with Sympa, use **Magic authentication**: a special SSO
|
||||
URL is protected by LL::NG, Sympa will display a button for users who
|
||||
wants to use this feature.
|
||||
To configure SSO with Sympa, you have the choice between:
|
||||
* CAS
|
||||
* **Magic authentication**: a special SSO URL is protected by LL::NG, Sympa will display a button for users who wants to use this feature.
|
||||
|
||||
We recommend to use CAS.
|
||||
|
||||
CAS
|
||||
---
|
||||
|
||||
|
||||
Sympa configuration
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Edit the file "auth.conf", for example:
|
||||
|
||||
::
|
||||
|
||||
vi /etc/sympa/auth.conf
|
||||
|
||||
And fill it:
|
||||
|
||||
::
|
||||
|
||||
cas
|
||||
base_url https://auth.example.com/cas
|
||||
non_blocking_redirection on
|
||||
auth_service_name SSO
|
||||
ldap_host ldap.example.com:389
|
||||
ldap_get_email_by_uid_filter (uid=[uid])
|
||||
ldap_timeout 7
|
||||
ldap_suffix dc=example,dc=com
|
||||
ldap_scope sub
|
||||
ldap_email_attribute mail
|
||||
|
||||
Restart services:
|
||||
|
||||
::
|
||||
|
||||
service sympa restart
|
||||
service apache2 restart
|
||||
|
||||
See also `official documentation <https://sympa-community.github.io/manual/customize/cas.html>`__
|
||||
|
||||
LemonLDAP::NG configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Declare CAS application in the configuration, register the service URL.
|
||||
|
||||
No attributes are needed.
|
||||
|
||||
|
||||
Magic authentication
|
||||
--------------------
|
||||
|
||||
|
||||
.. tip::
|
||||
|
@ -19,9 +69,6 @@ wants to use this feature.
|
|||
removed since it works only with Sympa-5 which has been deprecated
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Sympa configuration
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ must set:
|
|||
- overloaded parameters: you can redefine any LLNG string parameters.
|
||||
For example, if you use 2 different LDAP, the first can use normal
|
||||
configuration and for the second, overwritten parameter can redefine
|
||||
ldapServer,...
|
||||
ldapServer or any existing parameter.
|
||||
|
||||
|
||||
.. note::
|
||||
|
@ -63,12 +63,13 @@ parameters.
|
|||
For example, if DBI is configured to use PostgreSQL but DB2 is a MySQL
|
||||
DB, you can override the "dbiChain" parameter.
|
||||
|
||||
You can also override a complex key like ldapExportedVars, by setting a
|
||||
JSON value:
|
||||
The over parameter is a HASH ref where keys are attributes names and values are the overriden value.
|
||||
To override a complex key like ldapExportedVars, you must use a JSON value, as the over parameter
|
||||
expect string values:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{"cn" => "cn", "uid" => "sAMAccounName", "mail" => "mail"}
|
||||
{"cn": "cn", "uid": "sAMAccounName", "mail": "mail"}
|
||||
|
||||
|
||||
.. attention::
|
||||
|
|
|
@ -301,7 +301,7 @@ In this example we have:
|
|||
/usr/share/lemonldap-ng/bin/lemonldap-ng-cli -yes 1 \
|
||||
addKey \
|
||||
casAppMetaDataExportedVars/testapp mail mail \
|
||||
casAppMetaDataExportedVars/testapp cn cn
|
||||
casAppMetaDataExportedVars/testapp cn cn \
|
||||
casAppMetaDataOptions/testapp casAppMetaDataOptionsService 'https://testapp.example.com/'
|
||||
|
||||
Configure SAML Identity Provider
|
||||
|
|
|
@ -138,6 +138,8 @@ if 'LLNGSPHINXWEBSITE' in os.environ:
|
|||
import sphinx_rtd_theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_options = {}
|
||||
else:
|
||||
html_copy_source = False
|
||||
|
||||
|
||||
# html_theme_options = {}
|
||||
|
|
|
@ -58,7 +58,7 @@ As *root:*
|
|||
|
||||
apt install aptitude
|
||||
aptitude install vim make devscripts yui-compressor git git-gui libjs-uglify coffeescript cpanminus autopkgtest pkg-perl-autopkgtest
|
||||
aptitude install libauth-yubikey-webclient-perl libnet-smtp-server-perl libtime-fake-perl libtest-output-perl libtest-pod-perl libtest-leaktrace-perl libtest-mockobject-perl uglifyjs
|
||||
aptitude install libauth-yubikey-webclient-perl libnet-smtp-server-perl libtime-fake-perl libtest-output-perl libtest-pod-perl libtest-leaktrace-perl libtest-mockobject-perl uglifyjs libdbd-sqlite3-perl libauthen-webauthn-perl libauthen-oath-perl
|
||||
|
||||
cpanm Authen::U2F Authen::U2F::Tester Crypt::U2F::Server::Simple
|
||||
|
||||
|
|
|
@ -51,13 +51,20 @@ portal:
|
|||
- macros are used to extend (or rewrite)
|
||||
:doc:`exported variables<exportedvars>`. A macro is stored as
|
||||
attributes: it can contain boolean results or any string
|
||||
- macros can also be used to import environment variables *(these
|
||||
- macros can also be used for importing environment variables *(these
|
||||
variables are in CGI format)*. Example: ``$ENV{HTTP_COOKIE}``
|
||||
- groups are stored as a string with values separated by ''; ''
|
||||
(default values separator) in the special attribute ``groups``: it
|
||||
contains the names of groups whose rules were returned true for the
|
||||
(default multivalues separator) in the special attribute ``groups``: it
|
||||
contains names of groups whose rules were returned true for the
|
||||
current user. For example:
|
||||
|
||||
.. danger::
|
||||
|
||||
Macros can be used for rewriting or overloading exported variables
|
||||
but it can lead to some side effects. Be aware of alphabetical order
|
||||
and keep in mind that exported variables are set. Then macros and
|
||||
groups are computed.
|
||||
|
||||
.. code-block:: perl
|
||||
|
||||
$groups = group3; admin
|
||||
|
|
|
@ -28,6 +28,7 @@ Plugins
|
|||
resetpassword
|
||||
resetcertificate
|
||||
restservices
|
||||
restauthuserpwdbackend
|
||||
soapservices
|
||||
stayconnected
|
||||
rememberauthchoice
|
||||
|
|
|
@ -361,7 +361,7 @@ Password Policy
|
|||
- **Minimal upper characters**: leave 0 to bypass the check
|
||||
- **Minimal digit characters**: leave 0 to bypass the check
|
||||
- **Minimal special characters**: leave 0 to bypass the check
|
||||
- **Allowed special characters**: set '__ALL__' value to allow ALL special characters. A blanck value forbids ALL special characters (Note that ``_`` is not a special character)
|
||||
- **Allowed special characters**: set '__ALL__' value to allow ALL special characters. A blank value forbids ALL special characters (Note that ``_`` is not a special character)
|
||||
|
||||
.. _portalcustom-other-parameters:
|
||||
|
||||
|
|
|
@ -95,6 +95,8 @@ Second factor
|
|||
|
||||
- Crypt::U2F::Server::Simple (U2F keys)
|
||||
- Convert::Base32 (TOTP)
|
||||
- Authen::WebAuthn (FIDO2 WebAuthen)
|
||||
- Authen::OATH (OTP)
|
||||
|
||||
Specific authentication backends
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -138,6 +140,7 @@ Unit tests
|
|||
- Authen::U2F::Tester
|
||||
- Crypt::U2F::Server
|
||||
- Test::MockObject
|
||||
- DBD::SQLite
|
||||
- Test::Output
|
||||
- Test::POD
|
||||
- Time::Fake
|
||||
|
|
|
@ -84,8 +84,6 @@ Then go in Manager, ``General Parameters`` » ``Plugins`` »
|
|||
- **Display generate password box**: display a checkbox to allow
|
||||
user to generate a new password instead of choosing one (default:
|
||||
disabled)
|
||||
|
||||
::
|
||||
|
||||
* **Regexp for password generation**: Regular expression used to generate the password (default: [A-Z]{3}[a-z]{5}.\d{2})
|
||||
- **Regexp for password generation**: Regular expression used to generate the password. Set a blank value to use
|
||||
password policy if enabled or default regexp will be employed: [A-Z]{3}[a-z]{5}.\d{2}
|
||||
|
||||
|
|
90
doc/sources/admin/restauthuserpwdbackend.rst
Normal file
90
doc/sources/admin/restauthuserpwdbackend.rst
Normal file
|
@ -0,0 +1,90 @@
|
|||
REST auth/user/password backend
|
||||
===============================
|
||||
|
||||
LL::NG Portal provides REST end points for auth/user/password:
|
||||
|
||||
- POST /proxy/pwdConfirm: check password
|
||||
- POST /proxy/getUser: get user data
|
||||
- POST /proxy/pwdReset: update password
|
||||
|
||||
These end points can be used to connect another LemonLDAP::NG server using :doc:`REST authentication backend<authrest>`.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
Password confirm
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
POST a JSON structure with ``user`` and ``password``.
|
||||
It will return a JSON structure with ``result`` parameter (``true`` or ``false``).
|
||||
|
||||
Request:
|
||||
|
||||
.. code::
|
||||
|
||||
curl -H "Accept: application/json" -d '{"user":"dwho","password":"dwho"}' https://auth.example.com/proxy/pwdConfirm
|
||||
|
||||
Response:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{"result":true}
|
||||
|
||||
Get user data
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
POST a JSON structure with ``user``.
|
||||
It will return a JSON structure with ``result`` and ``info`` parameters.
|
||||
|
||||
Request:
|
||||
|
||||
.. code::
|
||||
|
||||
curl -H "Accept: application/json" -d '{"user":"rtyler"}' https://auth.example.com/proxy/getUser
|
||||
|
||||
Response:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{"info":{"_utime":1651055131,"hGroups":{"users":{"name":"users"},"earthlings":{"name":"earthlings"}},"ipAddr":"127.0.0.1","_auth":"Demo","_url":null,"uid":"rtyler","mail":"rtyler@badwolf.org","_userDB":"Demo","_startTime":"20220427122531","UA":"curl/7.68.0","cn":"Rose Tyler","_user":"rtyler","_language":"en","groups":"users; earthlings","_whatToTrace":"rtyler"},"result":true}
|
||||
|
||||
Update password
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
POST a JSON structure with ``user`` or ``mail`` and ``password``.
|
||||
It will return a JSON structure with ``result`` parameter.
|
||||
|
||||
Request:
|
||||
|
||||
.. code::
|
||||
|
||||
curl -H "Accept: application/json" -d '{"user":"rtyler","password":"secret"}' https://auth.example.com/proxy/pwdReset
|
||||
|
||||
Response:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{"result":true}
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
Manager
|
||||
~~~~~~~
|
||||
|
||||
First, activate REST in ``General parameters`` » ``Plugins`` »
|
||||
``Portal servers`` » ``REST authentication server`` and ``REST password reset server``.
|
||||
|
||||
Apache
|
||||
~~~~~~
|
||||
|
||||
REST end points access must be allowed in Apache portal
|
||||
configuration (for example, access by IP range):
|
||||
|
||||
.. code-block:: apache
|
||||
|
||||
# REST/SOAP functions for proxy auth and password reset (disabled by default)
|
||||
<Location /index.fcgi/proxy>
|
||||
Require ip 192.168.2.0/24
|
||||
</Location>
|
||||
|
|
@ -21,6 +21,9 @@ example:
|
|||
|
||||
$env->{HTTP_ACCEPT} !~ m:application/json:
|
||||
|
||||
|
||||
Another solution is using the :doc:`REST auth/user/password backend<restauthuserpwdbackend>`.
|
||||
|
||||
API
|
||||
^^^
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ ways to do this:
|
|||
- the Ugly: provide to all applications SSO cookie. Not secured
|
||||
because SSO cookie can be caught and used everywhere, every time by
|
||||
everyone!!! **NOT RECOMMENDED**.
|
||||
- the Bad (:doc:`Secure Token Handler<securetoken>`)
|
||||
: **Deprecated**. Can be used in specific cases
|
||||
- the Bad (:doc:`Secure Token Handler<securetoken>`): **Deprecated**.
|
||||
Should be used for specific cases
|
||||
- the Good (Service Token Handler): See below! (Thanks Sergio...)
|
||||
|
||||
The "Bad" method consists to give the token (cookie value) to WebApp1
|
||||
|
@ -24,22 +24,22 @@ Tokens are time limited (30 seconds by default) and URL restricted.
|
|||
Webapp1 handler configuration
|
||||
-----------------------------
|
||||
|
||||
Select **Main** handler type to protect WebApp1 and insert a header
|
||||
named **X-Llng-Token** filled with this value:
|
||||
Select **Main** handler type to protect WebApp1 and append a header containing:
|
||||
|
||||
.. code-block:: perl
|
||||
|
||||
token( $_session_id, 'webapp2.example.com', 'webapp3.example.com', 'serviceHeader1=webapp1.example.com', "testHeader=$uid" )
|
||||
|
||||
WebApp1 can read this header and use it in its requests by setting the
|
||||
``X-Llng-Token`` header. The token is built by using the session ID and
|
||||
authorized virtualhosts list. By default, the Service Token is only
|
||||
available during 30 seconds and for specified virtualhosts. The token
|
||||
can be use to send service headers to webapp2 like origin host by
|
||||
example.
|
||||
``X-LLNG-TOKEN`` header. The token is built by using the ``token`` extended
|
||||
with session ID and authorized virtualhosts list parameters. A Service Token is valide
|
||||
for the specified virtual hosts only and during 30 seconds by default. It can also be
|
||||
used for sending service headers (headerName1=headerValue1) to requested
|
||||
apps. Can be useful to send the origin host by example. Service headers are
|
||||
sent to ALL requested applications.
|
||||
|
||||
You can set ServiceToken TTL in the virtualHost options in Manager for
|
||||
each required virtualHost.
|
||||
You can set Service Token TTL by editing virtualHost options in Manager
|
||||
for each requested virtualHost.
|
||||
|
||||
You can also set ServiceToken default timeout (30 seconds) by editing
|
||||
``lemonldap-ng.ini`` in section [handler]:
|
||||
|
|
|
@ -22,22 +22,22 @@ user attributes to an application
|
|||
``*aaS`` means that application can drive underlying layer (IaaS for
|
||||
infrastructure, PaaS for platform,…). So for us, ``SSOaaS`` must provide
|
||||
the ability for an application to manage authorizations and choose user
|
||||
attributes to set. Authentication can not be really ``*aaS``: application
|
||||
must just use it but not manage it.
|
||||
attributes to receive. Authentication can not be really ``*aaS``: application
|
||||
can just use it but not manage it.
|
||||
|
||||
LL::NG affords some features that can be used for providing SSO as a
|
||||
service. So a web application can manage its rules and headers.
|
||||
Docker or VM images (Nginx only) includes LL::NG Nginx configuration that
|
||||
aims to a
|
||||
:ref:`central LL::NG authorization server<platformsoverview-external-servers-for-nginx>`.
|
||||
:ref:`Central LL::NG authorization server<platformsoverview-external-servers-for-nginx>`.
|
||||
By default, all authenticated users can access and just one header is set:
|
||||
``Auth-User``. If application defines a ``RULES_URL`` parameter that refers to
|
||||
a JSON file, authorization server will read it, apply specified rules
|
||||
and set required headers (see :doc:`DevOps Handler<devopshandler>`).
|
||||
|
||||
Two different kind of architecture are existing to do this:
|
||||
Two different kinds of architecture are existing to do this:
|
||||
|
||||
- Using a :doc:`central FastCGI (or uWSGI) server<psgi>`
|
||||
- Using a :doc:`Central FastCGI (or uWSGI) server<psgi>`
|
||||
- Using front Reverse-Proxies *(some cloud or HA installations use
|
||||
reverse-proxies in front-end)*
|
||||
|
||||
|
@ -52,7 +52,7 @@ Two different kind of architecture are existing to do this:
|
|||
```route-remote-addr = ^127\.0\.0\.25[34]$ break: 403 Forbidden for IP ${REMOTE_ADDR}```
|
||||
|
||||
|
||||
Example of a central FastCGI architecture:
|
||||
Example of a Central FastCGI architecture:
|
||||
|
||||
|image0|
|
||||
|
||||
|
@ -69,7 +69,8 @@ Nginx
|
|||
|
||||
Examples below are customized web server templates for
|
||||
requesting authorization from a Central FastCGI server.
|
||||
You can use 'uwsgi_param' directive for requesting a Central uWSGI server (Nginx only):
|
||||
You can replace 'fastcgi_*' directives by 'uwsgi_*' for
|
||||
requesting a Central uWSGI server (Nginx only):
|
||||
|
||||
|
||||
.. code-block:: nginx
|
||||
|
@ -93,12 +94,12 @@ You can use 'uwsgi_param' directive for requesting a Central uWSGI server (Nginx
|
|||
fastcgi_pass_request_body off;
|
||||
fastcgi_param CONTENT_LENGTH "";
|
||||
|
||||
# Keep original hostname
|
||||
fastcgi_param HOST $http_host;
|
||||
|
||||
# Keep original request (LL::NG server will receive /lmauth)
|
||||
fastcgi_param X_ORIGINAL_URI $original_uri;
|
||||
|
||||
# Keep original hostname
|
||||
fastcgi_param HOST $http_host;
|
||||
|
||||
# Set redirection parameters
|
||||
fastcgi_param HTTPS_REDIRECT "$https";
|
||||
fastcgi_param PORT_REDIRECT $server_port;
|
||||
|
@ -130,7 +131,7 @@ You can use 'uwsgi_param' directive for requesting a Central uWSGI server (Nginx
|
|||
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
|
||||
}
|
||||
|
||||
# Example as ReverseProxy:
|
||||
# Example as Reverse-Proxy:
|
||||
location /api/ {
|
||||
auth_request /lmauth;
|
||||
set $original_uri $uri$is_args$args;
|
||||
|
@ -147,14 +148,15 @@ You can use 'uwsgi_param' directive for requesting a Central uWSGI server (Nginx
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
Apache
|
||||
^^^^^^
|
||||
|
||||
LL::NG provides an experimental FastCGI client. You have to
|
||||
LL::NG provides a dedicated FastCGI client. You have to
|
||||
install LemonLDAP::NG handler (LL::NG FastCGI client),
|
||||
FCGI::Client (Perl FastCGI dependency) and Mod_Perl2 (Apache module)
|
||||
used for parsing HTTP headers.
|
||||
Then, add this in your apache2.conf web applications or reverse-proxies.
|
||||
FCGI::Client (Perl FastCGI dependency) and Mod_Perl2 (Apache module
|
||||
used for parsing HTTP headers).
|
||||
Then, add this in your apache2.conf web applications or Reverse-Proxies.
|
||||
|
||||
|
||||
.. code-block:: apache
|
||||
|
@ -182,25 +184,25 @@ Then, add this in your apache2.conf web applications or reverse-proxies.
|
|||
# Keep original hostname
|
||||
PerlSetVar HOST HTTP_HOST
|
||||
|
||||
# This URL will be fetched by the Central FastCGI server then
|
||||
# used for compliling access rules and headers about this VirtualHost
|
||||
# CHECK THAT IT CAN BE REACHED BY THE CENTRAL FASTCGI SERVER
|
||||
# PerlSetVar RULES_URL http://rulesserver/my.json
|
||||
PerlSetVar RULES_URL http://myapp.domain.com/rules.json
|
||||
|
||||
# Set redirection parameters
|
||||
PerlSetVar PORT_REDIRECT SERVER_PORT
|
||||
PerlSetVar HTTPS_REDIRECT HTTPS
|
||||
</LocationMatch>
|
||||
|
||||
# This URL will be fetched by the Central FastCGI server every 10 mn and
|
||||
# then used for compliling access rules and headers relative to this VirtualHost
|
||||
# CHECK THAT IT CAN BE REACHED BY THE CENTRAL FASTCGI SERVER
|
||||
# PerlSetVar RULES_URL http://rulesserver/my.json
|
||||
PerlSetVar RULES_URL http://myapp.domain.com/rules.json
|
||||
</LocationMatch>
|
||||
</VirtualHost>
|
||||
|
||||
|
||||
Node.js
|
||||
^^^^^^^
|
||||
|
||||
Using `express <https://github.com/expressjs/express#readme>`__ and
|
||||
`fastcgi-authz-client <https://github.com/LemonLDAPNG/node-fastcgi-authz-client>`__,
|
||||
you can protect also an Express server. Example:
|
||||
you can also protect an Express server. Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
|
@ -229,6 +231,7 @@ you can protect also an Express server. Example:
|
|||
return console.log('Example app listening on port 3000!');
|
||||
});
|
||||
|
||||
|
||||
Plack application
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -259,7 +262,7 @@ Simple example:
|
|||
host => '127.0.0.1',
|
||||
port => '9090',
|
||||
fcgi_auth_params => {
|
||||
RULES_URL => 'https://my-server/my.json',
|
||||
RULES_URL => 'https://my-server/rules.json',
|
||||
HTTPS_REDIRECT => 'ON',
|
||||
PORT_REDIRECT => 443
|
||||
},
|
||||
|
@ -293,31 +296,40 @@ directory.
|
|||
internal;
|
||||
include /etc/nginx/fastcgi_params;
|
||||
fastcgi_pass unix:/var/run/llng-fastcgi-server/llng-fastcgi.sock;
|
||||
|
||||
# Force handler type:
|
||||
fastcgi_param VHOSTTYPE DevOps;
|
||||
|
||||
# Drop post datas
|
||||
fastcgi_pass_request_body off;
|
||||
fastcgi_param CONTENT_LENGTH "";
|
||||
|
||||
# Keep original hostname
|
||||
fastcgi_param HOST $http_host;
|
||||
|
||||
# Keep original request (LL::NG server will received /lmauth)
|
||||
fastcgi_param X_ORIGINAL_URI $original_uri;
|
||||
|
||||
# Set redirection params
|
||||
fastcgi_param HTTPS_REDIRECT "$https";
|
||||
fastcgi_param PORT_REDIRECT $server_port;
|
||||
}
|
||||
|
||||
location /rules.json {
|
||||
auth_request off;
|
||||
allow 127.0.0.0/8;
|
||||
deny all;
|
||||
}
|
||||
|
||||
location / {
|
||||
auth_request /lmauth;
|
||||
set $original_uri $uri$is_args$args;
|
||||
auth_request_set $lmremote_user $upstream_http_lm_remote_user;
|
||||
auth_request_set $lmlocation $upstream_http_location;
|
||||
error_page 401 $lmlocation;
|
||||
|
||||
include /etc/nginx/nginx-lua-headers.conf;
|
||||
|
||||
proxy_pass https://$vhost.internal.domain;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ Key Description
|
|||
\_auth Authentication module
|
||||
\_userDB User module
|
||||
\_passwordDB Password module
|
||||
\_2f Second factor (if 2FA was used)
|
||||
\_issuerDB Issuer module (can be multivalued)
|
||||
\_authChoice User choice done if :doc:`authentication choice<authchoice>` was used
|
||||
\_authMulti Full name of authentication module (with ``#label``) used in Multi
|
||||
|
|
|
@ -115,7 +115,7 @@ sub new {
|
|||
# Serialize $conf and call store().
|
||||
# @param $conf Lemonldap::NG configuration hashRef
|
||||
# @param %args Parameters
|
||||
# @return Number of the saved configuration, 0 in case of error.
|
||||
# @return Number of the saved configuration, <=0 in case of error.
|
||||
sub saveConf {
|
||||
my ( $self, $conf, %args ) = @_;
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ foreach (@available) {
|
|||
next if ( $opts{force} );
|
||||
exit 6;
|
||||
}
|
||||
if ( my $r = $new->saveConf( $conf, %newargs ) ) {
|
||||
if ( $new->saveConf( $conf, %newargs ) > 0 ) {
|
||||
print "Conf $conf->{cfgNum} stored\n";
|
||||
next;
|
||||
}
|
||||
|
|
|
@ -466,7 +466,7 @@ if ( !$opts{'dry-run'} ) {
|
|||
print "[OK] Configuration $numConf saved\n";
|
||||
$exitCode = 0;
|
||||
}
|
||||
unless ($numConf) {
|
||||
unless ( $numConf > 0 ) {
|
||||
print "[ERROR] Unable to save configuration\n";
|
||||
$exitCode = 1;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ $conf->{oidcServicePrivateKeySig} = $keys->{private};
|
|||
$conf->{oidcServicePublicKeySig} = $keys->{public};
|
||||
$conf->{oidcServiceKeyIdSig} = $keys->{id};
|
||||
|
||||
$lmconf->saveConf($conf) or die $Lemonldap::NG::Common::Conf::msg;
|
||||
( $lmconf->saveConf($conf) > 0 ) or die $Lemonldap::NG::Common::Conf::msg;
|
||||
|
||||
print "Configuration saved\n" if $debug;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Apache2 FastCGI client to query remote LLNG FastCGI server
|
||||
# Apache2 FastCGI client to query remote LL::NG FastCGI server
|
||||
#
|
||||
package Lemonldap::NG::Handler::ApacheMP2::FCGIClient;
|
||||
|
||||
|
@ -21,7 +21,7 @@ use constant REDIRECT => Apache2::Const::REDIRECT;
|
|||
use constant DECLINED => Apache2::Const::DECLINED;
|
||||
use constant SERVER_ERROR => Apache2::Const::SERVER_ERROR;
|
||||
|
||||
our $VERSION = '2.0.14';
|
||||
our $VERSION = '2.0.15';
|
||||
|
||||
sub handler {
|
||||
my ( $class, $r ) = @_;
|
||||
|
@ -43,11 +43,13 @@ sub handler {
|
|||
SERVER_PORT => $r->get_server_port,
|
||||
REQUEST_METHOD => $r->method,
|
||||
};
|
||||
|
||||
foreach (qw(VHOSTTYPE RULES_URL HTTPS_REDIRECT PORT_REDIRECT)) {
|
||||
if ( my $t = $r->dir_config($_) ) {
|
||||
$env->{$_} = $t;
|
||||
}
|
||||
}
|
||||
|
||||
$r->headers_in->do(
|
||||
sub {
|
||||
my $h = shift;
|
||||
|
@ -89,17 +91,14 @@ sub handler {
|
|||
return REDIRECT;
|
||||
}
|
||||
|
||||
if ( $hdrs{'Lm-Remote-User'} ) {
|
||||
$r->user( $hdrs{'Lm-Remote-User'} );
|
||||
}
|
||||
if ( $hdrs{'Lm-Remote-Custom'} ) {
|
||||
$r->subprocess_env( REMOTE_CUSTOM => $hdrs{'Lm-Remote-Custom'} );
|
||||
}
|
||||
$r->user( $hdrs{'Lm-Remote-User'} ) if $hdrs{'Lm-Remote-User'};
|
||||
$r->subprocess_env( REMOTE_CUSTOM => $hdrs{'Lm-Remote-Custom'} )
|
||||
if $hdrs{'Lm-Remote-Custom'};
|
||||
|
||||
my $i = 1;
|
||||
while ( $hdrs{"Headername$i"} ) {
|
||||
$r->headers_in->set( $hdrs{"Headername$i"} => $hdrs{"Headervalue$i"} )
|
||||
if ( $hdrs{"Headervalue$i"} );
|
||||
if $hdrs{"Headervalue$i"};
|
||||
$i++;
|
||||
}
|
||||
$status = DECLINED if ( $status < 300 );
|
||||
|
@ -129,6 +128,9 @@ In apache2.conf:
|
|||
PerlSetVar VHOSTTYPE DevOps
|
||||
# or PerlSetVar VHOSTTYPE DevOpsST
|
||||
PerlSetVar RULES_URL http://app.tld/rules.json
|
||||
PerlSetVar HOST HTTP_HOST
|
||||
PerlSetVar PORT_REDIRECT SERVER_PORT
|
||||
PerlSetVar HTTPS_REDIRECT HTTPS
|
||||
...
|
||||
</VirtualHost>
|
||||
|
||||
|
@ -148,7 +150,7 @@ L<https://lemonldap-ng.org/documentation/latest/ssoaas>
|
|||
|
||||
=over
|
||||
|
||||
=item LemonLDAP::NG team L<http://lemonldap-ng.org/team>
|
||||
=item LemonLDAP::NG team L<https://lemonldap-ng.org/team.html>
|
||||
|
||||
=back
|
||||
|
||||
|
@ -160,7 +162,7 @@ L<https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues>
|
|||
=head1 DOWNLOAD
|
||||
|
||||
Lemonldap::NG is available at
|
||||
L<https://lemonldap-ng.org/download>
|
||||
L<https://lemonldap-ng.org/download.html>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
|
|
|
@ -11,12 +11,23 @@ use Lemonldap::NG::Common::UserAgent;
|
|||
use Lemonldap::NG::Common::FormEncode;
|
||||
use Lemonldap::NG::Common::Session;
|
||||
|
||||
our $VERSION = '2.0.7';
|
||||
our $VERSION = '2.0.15';
|
||||
our @ISA = ('Exporter');
|
||||
our @EXPORT = qw(fetchId retrieveSession createSession hideCookie goToPortal);
|
||||
our @EXPORT_OK = @EXPORT;
|
||||
our $_ua;
|
||||
|
||||
sub ua {
|
||||
my ($class) = @_;
|
||||
return $_ua if $_ua;
|
||||
$_ua = Lemonldap::NG::Common::UserAgent->new( {
|
||||
lwpOpts => $class->tsv->{lwpOpts},
|
||||
lwpSslOpts => $class->tsv->{lwpSslOpts}
|
||||
}
|
||||
);
|
||||
return $_ua;
|
||||
}
|
||||
|
||||
## @rmethod protected fetchId
|
||||
# Get user session id from Authorization header
|
||||
# Unlike usual processing, session id is computed from user creds,
|
||||
|
@ -163,15 +174,4 @@ sub goToPortal {
|
|||
}
|
||||
}
|
||||
|
||||
sub ua {
|
||||
my ($class) = @_;
|
||||
return $_ua if ($_ua);
|
||||
$_ua = Lemonldap::NG::Common::UserAgent->new( {
|
||||
lwpOpts => $class->tsv->{lwpOpts},
|
||||
lwpSslOpts => $class->tsv->{lwpSslOpts}
|
||||
}
|
||||
);
|
||||
return $_ua;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -8,9 +8,14 @@ our $VERSION = '2.0.15';
|
|||
our $_ua;
|
||||
|
||||
sub ua {
|
||||
return $_ua
|
||||
? $_ua
|
||||
: Lemonldap::NG::Common::UserAgent->new( $_[0]->localConfig );
|
||||
my ($class) = @_;
|
||||
return $_ua if $_ua;
|
||||
$_ua = Lemonldap::NG::Common::UserAgent->new( {
|
||||
lwpOpts => $class->tsv->{lwpOpts},
|
||||
lwpSslOpts => $class->tsv->{lwpSslOpts}
|
||||
}
|
||||
);
|
||||
return $_ua;
|
||||
}
|
||||
|
||||
sub checkMaintenanceMode {
|
||||
|
|
|
@ -110,7 +110,7 @@ categories =
|
|||
dateTitle: ['_utime', '_startTime', '_updateTime', '_lastAuthnUTime', '_lastSeen']
|
||||
connectionTitle: ['ipAddr', '_timezone', '_url']
|
||||
authenticationTitle:['_session_id', '_user', '_password', 'authenticationLevel']
|
||||
modulesTitle: ['_auth', '_userDB', '_passwordDB', '_issuerDB', '_authChoice', '_authMulti', '_userDBMulti']
|
||||
modulesTitle: ['_auth', '_userDB', '_passwordDB', '_issuerDB', '_authChoice', '_authMulti', '_userDBMulti', '_2f']
|
||||
saml: ['_idp', '_idpConfKey', '_samlToken', '_lassoSessionDump', '_lassoIdentityDump']
|
||||
groups: ['groups', 'hGroups']
|
||||
ldap: ['dn']
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
dateTitle: ['_utime', '_startTime', '_updateTime', '_lastAuthnUTime', '_lastSeen'],
|
||||
connectionTitle: ['ipAddr', '_timezone', '_url'],
|
||||
authenticationTitle: ['_session_id', '_user', '_password', 'authenticationLevel'],
|
||||
modulesTitle: ['_auth', '_userDB', '_passwordDB', '_issuerDB', '_authChoice', '_authMulti', '_userDBMulti'],
|
||||
modulesTitle: ['_auth', '_userDB', '_passwordDB', '_issuerDB', '_authChoice', '_authMulti', '_userDBMulti', '_2f'],
|
||||
saml: ['_idp', '_idpConfKey', '_samlToken', '_lassoSessionDump', '_lassoIdentityDump'],
|
||||
groups: ['groups', 'hGroups'],
|
||||
ldap: ['dn'],
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -555,7 +555,6 @@ t/30-Auth-and-issuer-SAML-Artifact-with-SOAP-SLO-IdP-initiated.t
|
|||
t/30-Auth-and-issuer-SAML-Artifact-with-SOAP-SLO.t
|
||||
t/30-Auth-and-issuer-SAML-Metadata.t
|
||||
t/30-Auth-and-issuer-SAML-NameID.t
|
||||
t/30-Auth-and-issuer-SAML-POST-Hook.t
|
||||
t/30-Auth-and-issuer-SAML-POST-IdP-initiated.t
|
||||
t/30-Auth-and-issuer-SAML-POST-Missing-SLO.t
|
||||
t/30-Auth-and-issuer-SAML-POST.t
|
||||
|
|
|
@ -367,6 +367,10 @@ sub run {
|
|||
|
||||
# If only one 2F is authorized, display it
|
||||
unless ($#am) {
|
||||
$self->userLogger->info( 'Second factor '
|
||||
. $am[0]->prefix
|
||||
. '2F selected for '
|
||||
. $req->sessionInfo->{ $self->conf->{whatToTrace} } );
|
||||
my $res = $am[0]->run( $req, $token );
|
||||
$req->authResult($res);
|
||||
return $res;
|
||||
|
@ -437,6 +441,10 @@ sub _choice {
|
|||
my $ch = $req->param('sf');
|
||||
foreach my $m ( @{ $self->sfModules } ) {
|
||||
if ( $m->{m}->prefix eq $ch ) {
|
||||
$self->userLogger->info( 'Second factor '
|
||||
. $m->{m}->prefix
|
||||
. '2F selected for '
|
||||
. $req->sessionInfo->{ $self->conf->{whatToTrace} } );
|
||||
my $res = $m->{m}->run( $req, $token );
|
||||
$req->authResult($res);
|
||||
return $self->p->do(
|
||||
|
|
|
@ -1962,7 +1962,7 @@ sub registration {
|
|||
$self->conf->{oidcServiceDynamicRegistrationExtraClaims};
|
||||
}
|
||||
|
||||
if ( $self->confAcc->saveConf($conf) ) {
|
||||
if ( $self->confAcc->saveConf($conf) > 0 ) {
|
||||
|
||||
# Reload RP list
|
||||
$self->loadRPs();
|
||||
|
|
|
@ -58,7 +58,6 @@ sub displayInit {
|
|||
$self->logger->error("Bad passwordPolicyActivation rule: $error");
|
||||
}
|
||||
$self->passwordPolicyActivation($rule);
|
||||
|
||||
$rule =
|
||||
HANDLER->buildSub( HANDLER->substitute( $self->conf->{rememberAuthChoiceRule} ) );
|
||||
unless ($rule) {
|
||||
|
|
|
@ -134,9 +134,9 @@ sub _verify {
|
|||
"Update sessionInfo with new authenticationLevel: $l");
|
||||
$req->sessionInfo->{authenticationLevel} = $l;
|
||||
|
||||
# Compute macros & local groups again with new authenticationLevel
|
||||
$self->logger->debug("Compute macros and local groups...");
|
||||
$req->steps( [ 'setMacros', 'setLocalGroups' ] );
|
||||
# Compute macros & groups with new authenticationLevel
|
||||
$self->logger->debug("Compute macros and groups...");
|
||||
$req->steps( [ $self->p->groupsAndMacros, 'setLocalGroups' ] );
|
||||
if ( my $error = $self->p->process($req) ) {
|
||||
$self->logger->debug("SFA: Process returned error: $error");
|
||||
$req->error($error);
|
||||
|
@ -165,9 +165,16 @@ sub _verify {
|
|||
authenticationLevel => $l,
|
||||
groups => $req->sessionInfo->{groups},
|
||||
hGroups => $req->sessionInfo->{hGroups},
|
||||
_2f => $self->prefix,
|
||||
%macros
|
||||
}
|
||||
);
|
||||
} else {
|
||||
# Only update _2f session key
|
||||
$self->p->updateSession($req,
|
||||
{
|
||||
_2f => $self->prefix,
|
||||
});
|
||||
}
|
||||
|
||||
$req->authResult(PE_SENDRESPONSE);
|
||||
|
|
|
@ -17,7 +17,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(
|
|||
|
||||
extends 'Lemonldap::NG::Portal::Main::Plugin';
|
||||
|
||||
our $VERSION = '2.0.12';
|
||||
our $VERSION = '2.0.14';
|
||||
|
||||
# INITIALIZATION
|
||||
|
||||
|
@ -59,7 +59,8 @@ sub _modifyPassword {
|
|||
)
|
||||
);
|
||||
unless ($oldPwdRule) {
|
||||
my $error = $self->p->HANDLER->tsv->{jail}->error || '???';
|
||||
my $error =
|
||||
$self->p->HANDLER->tsv->{jail}->error || 'Unable to compile rule';
|
||||
}
|
||||
|
||||
my $pwdPolicyRule = $self->p->HANDLER->buildSub(
|
||||
|
@ -68,7 +69,8 @@ sub _modifyPassword {
|
|||
)
|
||||
);
|
||||
unless ($pwdPolicyRule) {
|
||||
my $error = $self->p->HANDLER->tsv->{jail}->error || '???';
|
||||
my $error =
|
||||
$self->p->HANDLER->tsv->{jail}->error || 'Unable to compile rule';
|
||||
}
|
||||
|
||||
# Check if portal require old password
|
||||
|
|
|
@ -32,7 +32,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(
|
|||
PE_PP_INSUFFICIENT_PASSWORD_QUALITY
|
||||
);
|
||||
|
||||
our $VERSION = '2.0.12';
|
||||
our $VERSION = '2.0.14';
|
||||
|
||||
extends qw(
|
||||
Lemonldap::NG::Portal::Lib::SMTP
|
||||
|
@ -58,6 +58,9 @@ has ott => (
|
|||
# Captcha generator
|
||||
has captcha => ( is => 'rw' );
|
||||
|
||||
# Password policy activation rule
|
||||
has passwordPolicyActivationRule => ( is => 'rw', default => sub { 0 } );
|
||||
|
||||
# INITIALIZATION
|
||||
|
||||
sub init {
|
||||
|
@ -70,6 +73,15 @@ sub init {
|
|||
if ( $self->conf->{captcha_mail_enabled} ) {
|
||||
$self->captcha( $self->p->loadModule('::Lib::Captcha') ) or return 0;
|
||||
}
|
||||
|
||||
# Parse password policy activation rule
|
||||
$self->passwordPolicyActivationRule(
|
||||
$self->p->buildRule(
|
||||
$self->conf->{passwordPolicyActivation},
|
||||
'passwordPolicyActivation'
|
||||
)
|
||||
);
|
||||
return 0 unless $self->passwordPolicyActivationRule;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -442,8 +454,32 @@ sub changePwd {
|
|||
"Reset password request for $req->{sessionInfo}->{_user}");
|
||||
|
||||
# Generate a complex password
|
||||
my $password =
|
||||
$self->gen_password( $self->conf->{randomPasswordRegexp} );
|
||||
my $pwdRegEx;
|
||||
if ( $self->passwordPolicyActivationRule->( $req, $req->sessionInfo )
|
||||
&& !$self->conf->{randomPasswordRegexp} )
|
||||
{
|
||||
my $uppers = $self->conf->{passwordPolicyMinUpper} || 3;
|
||||
my $lowers = $self->conf->{passwordPolicyMinLower} || 5;
|
||||
my $digits = $self->conf->{passwordPolicyMinDigit} || 2;
|
||||
my $chars =
|
||||
$self->conf->{passwordPolicyMinSize} -
|
||||
$self->conf->{passwordPolicyMinUpper} -
|
||||
$self->conf->{passwordPolicyMinLower} -
|
||||
$self->conf->{passwordPolicyMinDigit};
|
||||
$chars = 1 if $chars < 1;
|
||||
$pwdRegEx = "[A-Z]{$uppers}[a-z]{$lowers}\\d{$digits}";
|
||||
$pwdRegEx .=
|
||||
$self->conf->{passwordPolicySpecialChar} eq '__ALL__'
|
||||
? "\\W{$chars}"
|
||||
: "[$self->{conf}->{passwordPolicySpecialChar}]{$chars}";
|
||||
$self->logger->debug("Generated password RegEx: $pwdRegEx");
|
||||
}
|
||||
else {
|
||||
$pwdRegEx =
|
||||
$self->conf->{randomPasswordRegexp} || '[A-Z]{3}[a-z]{5}.\d{2}';
|
||||
$self->logger->debug("Used password RegEx: $pwdRegEx");
|
||||
}
|
||||
my $password = $self->gen_password($pwdRegEx);
|
||||
$self->logger->debug("Generated password: $password");
|
||||
$req->data->{newpassword} = $password;
|
||||
$req->data->{confirmpassword} = $password;
|
||||
|
@ -467,11 +503,13 @@ sub changePwd {
|
|||
}
|
||||
}
|
||||
|
||||
# Check password quality
|
||||
# Check password quality if enabled
|
||||
require Lemonldap::NG::Portal::Password::Base;
|
||||
my $cpq =
|
||||
$self->Lemonldap::NG::Portal::Password::Base::checkPasswordQuality(
|
||||
$req->data->{newpassword} );
|
||||
$self->passwordPolicyActivationRule->( $req, $req->sessionInfo )
|
||||
? $self->Lemonldap::NG::Portal::Password::Base::checkPasswordQuality(
|
||||
$req->data->{newpassword} )
|
||||
: PE_OK;
|
||||
unless ( $cpq == PE_OK ) {
|
||||
$self->ott->setToken( $req, $req->sessionInfo );
|
||||
return $cpq;
|
||||
|
@ -555,9 +593,19 @@ sub setSecurity {
|
|||
|
||||
sub display {
|
||||
my ( $self, $req ) = @_;
|
||||
my $speChars = $self->conf->{passwordPolicySpecialChar};
|
||||
my $speChars =
|
||||
$self->conf->{passwordPolicySpecialChar} eq '__ALL__'
|
||||
? ''
|
||||
: $self->conf->{passwordPolicySpecialChar};
|
||||
$speChars =~ s/\s+/ /g;
|
||||
$speChars =~ s/(?:^\s|\s$)//g;
|
||||
my $isPP =
|
||||
$self->conf->{passwordPolicyMinSize}
|
||||
|| $self->conf->{passwordPolicyMinLower}
|
||||
|| $self->conf->{passwordPolicyMinUpper}
|
||||
|| $self->conf->{passwordPolicyMinDigit}
|
||||
|| $self->conf->{passwordPolicyMinSpeChar}
|
||||
|| $speChars;
|
||||
$self->logger->debug( 'Display called with code: ' . $req->error );
|
||||
|
||||
my %tplPrm = (
|
||||
|
@ -576,7 +624,8 @@ sub display {
|
|||
STARTMAILTIME => $req->data->{startMailTime},
|
||||
MAILALREADYSENT => $req->data->{mailAlreadySent},
|
||||
MAIL => (
|
||||
$self->p->checkXSSAttack( 'mail', $req->{user} ) ? ''
|
||||
$self->p->checkXSSAttack( 'mail', $req->{user} )
|
||||
? ''
|
||||
: $req->{user}
|
||||
),
|
||||
DISPLAY_FORM => 0,
|
||||
|
@ -584,17 +633,13 @@ sub display {
|
|||
DISPLAY_CONFIRMMAILSENT => 0,
|
||||
DISPLAY_MAILSENT => 0,
|
||||
DISPLAY_PASSWORD_FORM => 0,
|
||||
DISPLAY_PPOLICY => $self->conf->{portalDisplayPasswordPolicy},
|
||||
DISPLAY_PPOLICY => $self->conf->{portalDisplayPasswordPolicy} && $isPP,
|
||||
PPOLICY_MINSIZE => $self->conf->{passwordPolicyMinSize},
|
||||
PPOLICY_MINLOWER => $self->conf->{passwordPolicyMinLower},
|
||||
PPOLICY_MINUPPER => $self->conf->{passwordPolicyMinUpper},
|
||||
PPOLICY_MINDIGIT => $self->conf->{passwordPolicyMinDigit},
|
||||
PPOLICY_MINSPECHAR => $self->conf->{passwordPolicyMinSpeChar},
|
||||
PPOLICY_ALLOWEDSPECHAR => $speChars,
|
||||
(
|
||||
$speChars
|
||||
? ( PPOLICY_MINSPECHAR => $self->conf->{passwordPolicyMinSpeChar} )
|
||||
: ()
|
||||
),
|
||||
DISPLAY_GENERATE_PASSWORD =>
|
||||
$self->conf->{portalDisplayGeneratePassword},
|
||||
);
|
||||
|
|
|
@ -156,7 +156,7 @@ sub setGroups {
|
|||
my $groups = $req->sessionInfo->{groups} || '';
|
||||
my $hGroups = $req->sessionInfo->{hGroups} || {};
|
||||
for my $grp ( keys %demoGroups ) {
|
||||
if ( grep { $_ eq $user } @{ $demoGroups{$grp} } ) {
|
||||
if ( grep { $user && $user eq $_ } @{ $demoGroups{$grp} } ) {
|
||||
$hGroups->{$grp} = { 'name' => $grp };
|
||||
$groups =
|
||||
($groups)
|
||||
|
|
|
@ -32,24 +32,65 @@
|
|||
|
||||
<TMPL_IF NAME="HEADERS">
|
||||
<div class="row">
|
||||
<div class="card col border-secondary">
|
||||
<div class="text-center bg-light text-dark"><b><span trspan="headers">HEADERS</span></b></div>
|
||||
<div class="font-weight-bold">
|
||||
<div class ="col-12 col-sm-12 col-md-12 pb-3">
|
||||
<div class="card h-100 border-secondary">
|
||||
<div class="card-title text-center bg-light text-dark"><b><span trspan="headers">HEADERS</span></b></div>
|
||||
<div class="card-text font-weight-bold m-2">
|
||||
<TMPL_LOOP NAME="HEADERS">
|
||||
<TMPL_VAR NAME="key">: <TMPL_VAR NAME="value"><br/>
|
||||
</TMPL_LOOP>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TMPL_IF>
|
||||
|
||||
<div class= "row ">
|
||||
|
||||
<!-- Groups Card 1 -->
|
||||
<div class ="col-6 col-sm-12 col-md-6 p-0">
|
||||
<div class="card h-100">
|
||||
<div class="card-title text-center bg-light text-dark"><b><span trspan="groups_sso">SSO GROUPS</span></b></div>
|
||||
<TMPL_LOOP NAME="GROUPS">
|
||||
<div class="card-text text-left ml-2"><TMPL_VAR NAME="value"></div>
|
||||
</TMPL_LOOP>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Macros Card 2 -->
|
||||
<div class ="col-6 col-sm-12 col-md-6 p-0">
|
||||
<div class="card h-100">
|
||||
<TMPL_IF NAME="MACROS">
|
||||
<div class="card-title text-center bg-light text-dark"><b><span trspan="macros">MACROS</span></b></div>
|
||||
<table class="table table-sm table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"><span trspan="key">Key</span></th>
|
||||
<th scope="col"><span trspan="value">Value</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<TMPL_LOOP NAME="MACROS">
|
||||
<tr>
|
||||
<td scope="row"><TMPL_VAR NAME="key"></td>
|
||||
<td scope="row"><TMPL_VAR NAME="value"></td>
|
||||
</tr>
|
||||
</TMPL_LOOP>
|
||||
</tbody>
|
||||
</table>
|
||||
</TMPL_IF>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- History Card 3 -->
|
||||
<div class ="col-6 col-sm-12 col-md-6 p-0">
|
||||
<div class="card h-100">
|
||||
<TMPL_IF NAME="HISTORY">
|
||||
<div class="card col border-secondary">
|
||||
<div class="text-center bg-light text-dark"><b><span trspan="loginHistory">HISTORY</span></b></div>
|
||||
<div class="card-title text-center bg-light text-dark"><b><span trspan="loginHistory">HISTORY</span></b></div>
|
||||
<TMPL_IF NAME="SUCCESS">
|
||||
<table class="table table-sm table-hover">
|
||||
<thead>
|
||||
<div class="text-center bg-light text-dark"><span trspan="lastLogins">Success</span></div>
|
||||
<div class="card-text text-center bg-light text-dark"><span trspan="lastLogins">Success</span></div>
|
||||
<tr>
|
||||
<th scope="col"><span trspan="date">Date</span></th>
|
||||
<th scope="col"><span trspan="value">Value</span></th>
|
||||
|
@ -68,7 +109,7 @@
|
|||
<TMPL_IF NAME="FAILED">
|
||||
<table class="table table-sm table-hover">
|
||||
<thead>
|
||||
<div class="text-center bg-light text-dark"><span trspan="lastFailedLogins">Failed</span></div>
|
||||
<div class="card-text text-center bg-light text-dark"><span trspan="lastFailedLogins">Failed</span></div>
|
||||
<tr>
|
||||
<th scope="col"><span trspan="date">Date</span></th>
|
||||
<th scope="col"><span trspan="value">Value</span></th>
|
||||
|
@ -84,24 +125,15 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</TMPL_IF>
|
||||
</div>
|
||||
</TMPL_IF>
|
||||
<TMPL_IF NAME="GROUPS">
|
||||
<div class="card col border-secondary">
|
||||
<div class="text-center bg-light text-dark"><b><span trspan="groups_sso">SSO GROUPS</span></b></div>
|
||||
<div class="row">
|
||||
<TMPL_LOOP NAME="GROUPS">
|
||||
<div class="w-100"></div>
|
||||
<div class="col"><TMPL_VAR NAME="value"></div>
|
||||
</TMPL_LOOP>
|
||||
</div>
|
||||
</div>
|
||||
</TMPL_IF>
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
|
||||
<!-- Attribute Card 4 -->
|
||||
<div class ="col-6 col-sm-12 col-md-6 p-0">
|
||||
<div class="card h-100">
|
||||
<TMPL_IF NAME="ATTRIBUTES">
|
||||
<div class="card col border-secondary">
|
||||
<div class="text-center bg-light text-dark"><b><span trspan="attributes">ATTRIBUTES</span></b></div>
|
||||
<div class="card-title text-center bg-light text-dark"><b><span trspan="attributes">ATTRIBUTES</span></b></div>
|
||||
<table class="table table-sm table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -118,32 +150,10 @@
|
|||
</TMPL_LOOP>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</TMPL_IF>
|
||||
<TMPL_IF NAME="GROUPS"><div class="w-100"></div></TMPL_IF>
|
||||
<TMPL_IF NAME="MACROS">
|
||||
<div class="card col border-secondary">
|
||||
<div class="text-center bg-light text-dark"><b><span trspan="macros">MACROS</span></b></div>
|
||||
<table class="table table-sm table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"><span trspan="key">Key</span></th>
|
||||
<th scope="col"><span trspan="value">Value</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<TMPL_LOOP NAME="MACROS">
|
||||
<tr>
|
||||
<td scope="row"><TMPL_VAR NAME="key"></td>
|
||||
<td scope="row"><TMPL_VAR NAME="value"></td>
|
||||
</tr>
|
||||
</TMPL_LOOP>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</TMPL_IF>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<br />
|
||||
<br />
|
||||
<span trspan="yourLoginIs">Your login is</span>
|
||||
<span><img src="cid:key:../common/bullet_go.png" alt="go"/></span>
|
||||
<span><img src="cid:arrow:../common/bullet_go.png" alt="go"/></span>
|
||||
<b><TMPL_VAR NAME="login" ESCAPE=HTML></b>
|
||||
<br />
|
||||
<span trspan="pwdIs">Your password is</span>
|
||||
|
|
|
@ -13,7 +13,7 @@ BEGIN {
|
|||
}
|
||||
|
||||
my ( $res, $user, $pwd );
|
||||
my $maintests = 17;
|
||||
my $maintests = 19;
|
||||
my $mailSend = 0;
|
||||
|
||||
my $mail2 = 0;
|
||||
|
@ -54,7 +54,12 @@ SKIP: {
|
|||
dbiAuthPasswordHash => '',
|
||||
dbiDynamicHashEnabled => 0,
|
||||
dbiMailCol => 'mail',
|
||||
portalDisplayPasswordPolicy => 1,
|
||||
passwordPolicyActivation => 0,
|
||||
passwordResetAllowedRetries => 4,
|
||||
passwordPolicyMinDigit => 2,
|
||||
passwordPolicyMinSpeChar => 1,
|
||||
passwordPolicySpecialChar => '__ALL__'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -141,8 +146,16 @@ SKIP: {
|
|||
# Post new password
|
||||
( $host, $url, $query ) = expectForm( $res, '#', undef, 'token' );
|
||||
ok( $res->[2]->[0] =~ /newpassword/s, ' Ask for a new password #4' );
|
||||
|
||||
$query .= '&newpassword=zz&confirmpassword=zz';
|
||||
ok(
|
||||
$res->[2]->[0] !~ /passwordPolicySpecialChar/,
|
||||
' Password special char list not found'
|
||||
);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicyMinDigit">Minimal digit characters:<\/span> 2/,
|
||||
' Found password policy min digit == 2'
|
||||
);
|
||||
$query .= '&newpassword=zz11#&confirmpassword=zz11#';
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/resetpwd', IO::String->new($query),
|
||||
|
@ -157,8 +170,8 @@ SKIP: {
|
|||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=zz'),
|
||||
length => 21
|
||||
IO::String->new('user=dwho&password=zz11#'),
|
||||
length => 24
|
||||
),
|
||||
'Auth query'
|
||||
);
|
||||
|
|
|
@ -10,7 +10,7 @@ BEGIN {
|
|||
}
|
||||
|
||||
my ( $res, $host, $url, $query );
|
||||
my $maintests = 16;
|
||||
my $maintests = 18;
|
||||
my $mailSend = 0;
|
||||
my $mail2 = 0;
|
||||
|
||||
|
@ -33,6 +33,13 @@ SKIP: {
|
|||
requireToken => 1,
|
||||
portalDisplayResetPassword => 1,
|
||||
portalMainLogo => 'common/logos/logo_llng_old.png',
|
||||
passwordPolicyActivation => 1,
|
||||
passwordPolicyMinUpper => 1,
|
||||
passwordPolicyMinLower => 1,
|
||||
passwordPolicyMinDigit => 2,
|
||||
passwordPolicyMinSpeChar => 1,
|
||||
randomPasswordRegexp => '',
|
||||
passwordPolicySpecialChar => '*#@'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -104,7 +111,7 @@ m#<img class="renewcaptchaclick" src="/static/common/icons/arrow_refresh.png"#,
|
|||
( $host, $url, $query ) = expectForm( $res, '#', undef, 'token' );
|
||||
ok( $res->[2]->[0] =~ /newpassword/s, ' Ask for a new password' );
|
||||
|
||||
$query .= '&newpassword=zz&confirmpassword=zz';
|
||||
$query .= '&reset=1';
|
||||
|
||||
# Post new password
|
||||
ok(
|
||||
|
@ -115,7 +122,9 @@ m#<img class="renewcaptchaclick" src="/static/common/icons/arrow_refresh.png"#,
|
|||
),
|
||||
'Post new password'
|
||||
);
|
||||
ok( mail() =~ /Your password was changed/, 'Password was changed' );
|
||||
ok( mail() =~ /<span>Your new password is<\/span>/, 'New password sent' );
|
||||
ok( mail() =~ /<b>(.+?)<\/b>/s, 'New generated password found' );
|
||||
ok( $1 =~ /[A-Z]{1}[a-z]{1}\d{2}[*#@]{1}/, 'New generated password matches' );
|
||||
|
||||
#print STDERR Dumper($query);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ BEGIN {
|
|||
}
|
||||
|
||||
my ( $res, $user, $pwd );
|
||||
my $maintests = 12;
|
||||
my $maintests = 18;
|
||||
|
||||
SKIP: {
|
||||
eval
|
||||
|
@ -30,6 +30,13 @@ SKIP: {
|
|||
captcha_mail_enabled => 0,
|
||||
portalDisplayResetPassword => 1,
|
||||
portalMainLogo => 'common/logos/logo_llng_old.png',
|
||||
portalDisplayPasswordPolicy => 1,
|
||||
passwordPolicyActivation => 1,
|
||||
passwordPolicyMinUpper => 1,
|
||||
passwordPolicyMinLower => 1,
|
||||
passwordPolicyMinDigit => 2,
|
||||
passwordPolicyMinSpeChar => 1,
|
||||
passwordPolicySpecialChar => '&%#'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -87,8 +94,34 @@ SKIP: {
|
|||
);
|
||||
( $host, $url, $query ) = expectForm( $res, '#', undef, 'token' );
|
||||
ok( $res->[2]->[0] =~ /newpassword/s, ' Ask for a new password' );
|
||||
|
||||
$query .= '&newpassword=zz&confirmpassword=zz';
|
||||
ok( $res->[2]->[0] =~ /<span trspan="passwordPolicy">/,
|
||||
' Found password policy' );
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicyMinLower">Minimal lower characters:<\/span> 1/,
|
||||
' Found password policy min lower == 1'
|
||||
);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicyMinUpper">Minimal upper characters:<\/span> 1/,
|
||||
' Found password policy min upper == 1'
|
||||
);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicyMinDigit">Minimal digit characters:<\/span> 2/,
|
||||
' Found password policy min digit == 2'
|
||||
);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicyMinSpeChar">Minimal special characters:<\/span> 1/,
|
||||
' Found password policy min speChar == 1'
|
||||
);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicySpecialChar">Allowed special characters:<\/span> &%#/,
|
||||
' Found password special char list'
|
||||
);
|
||||
$query .= '&newpassword=zZ11#&confirmpassword=zZ11#';
|
||||
|
||||
# Post new password
|
||||
ok(
|
||||
|
|
|
@ -166,7 +166,8 @@ ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
|
|||
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
|
||||
ok( $res->[2]->[0] =~ m%: rtyler<br/>%, 'Found rtyler' )
|
||||
or explain( $res->[2]->[0], 'Header Value: rtyler' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">su</div>%,
|
||||
'Found su' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: su' );
|
||||
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
|
||||
or explain( $res->[2]->[0], 'Attribute Value uid' );
|
||||
|
|
|
@ -186,10 +186,10 @@ ok( $res->[2]->[0] =~ m%<td scope="row">Macro_1</td>%, 'Found uid' )
|
|||
ok( $nbr = ( $res->[2]->[0] =~ s%<td scope="row">Macro_1</td>%%g ),
|
||||
'Found two well computed macros' )
|
||||
or explain( $res->[2]->[0], 'Macros not well computed' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">authGroup</div>%,
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">authGroup</div>%,
|
||||
'Found group "authGroup"' )
|
||||
or explain( $res->[2]->[0], 'Group "authgroup"' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">realAuthGroup</div>%,
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">realAuthGroup</div>%,
|
||||
'Found group "realAuthGroup"' )
|
||||
or explain( $res->[2]->[0], 'Found group "realAuthGroup"' );
|
||||
count(7);
|
||||
|
|
|
@ -166,7 +166,8 @@ ok( $res->[2]->[0] !~ m%emptyHeader: %, 'emptyHeader not found' )
|
|||
or explain( $res->[2]->[0], 'Header Key: emptyHeader' );
|
||||
ok( $res->[2]->[0] =~ m%: rtyler%, 'Found rtyler' )
|
||||
or explain( $res->[2]->[0], 'Header Value: rtyler' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">su</div>%,
|
||||
'Found su' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: su' );
|
||||
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
|
||||
or explain( $res->[2]->[0], 'Attribute Value uid' );
|
||||
|
|
|
@ -429,7 +429,8 @@ ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
|
|||
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
|
||||
ok( $res->[2]->[0] =~ m%: rtyler<br/>%, 'Found rtyler' )
|
||||
or explain( $res->[2]->[0], 'Header Value: rtyler' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">su</div>%,
|
||||
'Found su' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: su' );
|
||||
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
|
||||
or explain( $res->[2]->[0], 'Attribute Value uid' );
|
||||
|
@ -489,7 +490,8 @@ ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
|
|||
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
|
||||
ok( $res->[2]->[0] =~ m%: rtyler<br/>%, 'Found rtyler' )
|
||||
or explain( $res->[2]->[0], 'Header Value: rtyler' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">su</div>%,
|
||||
'Found su' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: su' );
|
||||
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
|
||||
or explain( $res->[2]->[0], 'Attribute Value uid' );
|
||||
|
|
|
@ -226,7 +226,7 @@ m%<div class="alert alert-success"><div class="text-center"><b><span trspan="all
|
|||
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
|
||||
ok( $res->[2]->[0] =~ m%: dwho<br/>%, 'Found dwho' )
|
||||
or explain( $res->[2]->[0], 'Header Value: dwho' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">su</div>%, 'Found su' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: su' );
|
||||
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
|
||||
or explain( $res->[2]->[0], 'Attribute Value uid' );
|
||||
|
|
|
@ -127,13 +127,13 @@ ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
|
|||
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
|
||||
ok( $res->[2]->[0] =~ m%: dwho<br/>%, 'Found dwho' )
|
||||
or explain( $res->[2]->[0], 'Header Value: dwho' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">su</div>%, 'Found su' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: su' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">su_test</div>%, 'Found su_test' )
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">su_test</div>%, 'Found su_test' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: su_test' );
|
||||
ok( $res->[2]->[0] !~ m%<div class="col">_test_</div>%, 'NOT found _test_' )
|
||||
ok( $res->[2]->[0] !~ m%<div class="card-text text-left ml-2">_test_</div>%, 'NOT found _test_' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: _test_' );
|
||||
ok( $res->[2]->[0] !~ m%<div class="col">test_su</td>%, 'NOT found test_su' )
|
||||
ok( $res->[2]->[0] !~ m%<div class="card-text text-left ml-2">test_su</td>%, 'NOT found test_su' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: test_su' );
|
||||
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
|
||||
or explain( $res->[2]->[0], 'Attribute Value uid' );
|
||||
|
|
|
@ -116,12 +116,12 @@ ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
|
|||
ok( $res->[2]->[0] =~ m%<span trspan="groups_sso">%,
|
||||
'Found trspan="groups_sso"' )
|
||||
or explain( $res->[2]->[0], 'trspan="groups_sso"' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found SSO group "su"' )
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">su</div>%, 'Found SSO group "su"' )
|
||||
or explain( $res->[2]->[0], 'Found SSO group "su"' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">su_test</div>%,
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">su_test</div>%,
|
||||
'Found SSO group "su_test"' )
|
||||
or explain( $res->[2]->[0], 'Found SSO group "su_test"' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">test_su</div>%,
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">test_su</div>%,
|
||||
'Found SSO group "test_su"' )
|
||||
or explain( $res->[2]->[0], 'Found SSO group "test_su"' );
|
||||
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
|
||||
|
@ -135,13 +135,13 @@ ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
|
|||
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
|
||||
ok( $res->[2]->[0] =~ m%: dwho<br/>%, 'Found dwho' )
|
||||
or explain( $res->[2]->[0], 'Header Value: dwho' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">su</div>%, 'Found su' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: su' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">su_test</div>%, 'Found su_test' )
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">su_test</div>%, 'Found su_test' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: su_test' );
|
||||
ok( $res->[2]->[0] !~ m%<div class="col">_test_</div>%, 'NOT found _test_' )
|
||||
ok( $res->[2]->[0] !~ m%<div class="card-text text-left ml-2">_test_</div>%, 'NOT found _test_' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: _test_' );
|
||||
ok( $res->[2]->[0] =~ m%<div class="col">test_su</div>%, 'Found test_su' )
|
||||
ok( $res->[2]->[0] =~ m%<div class="card-text text-left ml-2">test_su</div>%, 'Found test_su' )
|
||||
or explain( $res->[2]->[0], 'SSO Groups: test_su' );
|
||||
ok( $res->[2]->[0] =~ m%<td scope="row">_whatToTrace</td>%,
|
||||
'Found _whatToTrace' )
|
||||
|
|
|
@ -29,6 +29,7 @@ SKIP: {
|
|||
u2fSelfRegistration => 1,
|
||||
u2fActivation => 1,
|
||||
u2fAuthnLevel => 5,
|
||||
restSessionServer =>1,
|
||||
skipUpgradeConfirmation => 1,
|
||||
sfManagerRule => '$uid eq "dwho"',
|
||||
portalMainLogo => 'common/logos/logo_llng_old.png',
|
||||
|
@ -151,6 +152,7 @@ SKIP: {
|
|||
'Post code'
|
||||
);
|
||||
$id = expectCookie($res);
|
||||
expectSessionAttributes($client, $id, _2f => "totp");
|
||||
|
||||
# Get 2F register form
|
||||
ok(
|
||||
|
@ -440,6 +442,7 @@ JjTJecOOS+88fK8qL1TrYv5rapIdqUI7aQ==
|
|||
'Push U2F signature'
|
||||
);
|
||||
$id = expectCookie($res);
|
||||
expectSessionAttributes($client, $id, _2f => "u");
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/2fregisters',
|
||||
|
|
|
@ -84,6 +84,7 @@ ok(
|
|||
);
|
||||
count(1);
|
||||
my $id = expectCookie($res);
|
||||
expectSessionAttributes($client, $id, _2f => "work");
|
||||
$client->logout($id);
|
||||
|
||||
clean_sessions();
|
||||
|
@ -167,6 +168,7 @@ ok(
|
|||
);
|
||||
count(1);
|
||||
$id = expectCookie($res);
|
||||
expectSessionAttributes($client, $id, _2f => "home");
|
||||
|
||||
# Verify Authn Level
|
||||
ok( $res = $client->_get("/sessions/global/$id"), 'Get session' );
|
||||
|
|
|
@ -56,6 +56,7 @@ C<LLNG::Manager::Test::_post()> call I<(see below)>.
|
|||
use strict;
|
||||
use Data::Dumper;
|
||||
use File::Find;
|
||||
use JSON;
|
||||
use LWP::UserAgent;
|
||||
use Time::Fake;
|
||||
use URI::Escape;
|
||||
|
@ -376,6 +377,31 @@ sub expectAuthenticatedAs {
|
|||
count(1);
|
||||
}
|
||||
|
||||
=head4 expectSessionAttributes($app,$id,%attributes)
|
||||
|
||||
Verify that the session contains attributes with these values
|
||||
|
||||
=cut
|
||||
|
||||
sub expectSessionAttributes {
|
||||
my ( $app, $id, %attributes ) = @_;
|
||||
my $res;
|
||||
ok(
|
||||
$res = $app->_get("/sessions/global/$id"),
|
||||
"Get session using restSessionServer"
|
||||
);
|
||||
count(1);
|
||||
expectOK($res);
|
||||
ok( $res = eval { from_json( $res->[2]->[0] ) },
|
||||
"Deserialize session content" );
|
||||
count(1);
|
||||
for my $attr ( keys %attributes ) {
|
||||
is( $res->{$attr}, $attributes{$attr},
|
||||
"Session has correct value for $attr" );
|
||||
count(1);
|
||||
}
|
||||
}
|
||||
|
||||
=head4 expectOK($res)
|
||||
|
||||
Verify that returned code is 200
|
||||
|
|
|
@ -205,7 +205,7 @@ Requires: lemonldap-ng-test = %{version}-%{release}
|
|||
# ! Not available in Centos7, you need to install lemonldap-ng-selinux manually
|
||||
# This ensures that the *-selinux package and all it’s dependencies are not pulled
|
||||
# into containers and other systems that do not use SELinux
|
||||
Requires: (%{name}-selinux if selinux-policy-%{selinuxtype})
|
||||
Requires: (%{name}-selinux = %{version}-%{release} if selinux-policy-%{selinuxtype})
|
||||
%endif
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user