Merge branch 'v2.0'
This commit is contained in:
commit
5496d798a3
|
@ -55,9 +55,6 @@ build_centos_7:
|
|||
script:
|
||||
- rm -f /etc/yum.repos.d/CentOS-Sources.repo
|
||||
- yum -y install epel-release
|
||||
- yum -y install python-pip
|
||||
- pip install -U pip
|
||||
- pip install sphinx==1.8.5 sphinx-rtd_theme==0.4.3
|
||||
- make rpm-dist
|
||||
- ci-build-pkg
|
||||
artifacts:
|
||||
|
@ -65,19 +62,19 @@ build_centos_7:
|
|||
paths:
|
||||
- result/*
|
||||
|
||||
#build_centos_8:
|
||||
# image: buildpkg/centos:8
|
||||
# stage: build
|
||||
# script:
|
||||
# - yum-config-manager --enable PowerTools
|
||||
# - yum-config-manager --enable AppStream
|
||||
# - yum -y install epel-release
|
||||
# - make rpm-dist
|
||||
# - ci-build-pkg
|
||||
# artifacts:
|
||||
# expire_in: 1 day
|
||||
# paths:
|
||||
# - result/*
|
||||
build_centos_8:
|
||||
image: buildpkg/centos:8
|
||||
stage: build
|
||||
script:
|
||||
- yum-config-manager --enable PowerTools
|
||||
- yum-config-manager --enable AppStream
|
||||
- yum -y install epel-release
|
||||
- make rpm-dist
|
||||
- ci-build-pkg
|
||||
artifacts:
|
||||
expire_in: 1 day
|
||||
paths:
|
||||
- result/*
|
||||
|
||||
sign:
|
||||
image: buildpkg/debian:stretch
|
||||
|
|
31
Makefile
31
Makefile
|
@ -96,6 +96,9 @@ APACHEFILENOTIFDIR=$(DATADIR)/notifications
|
|||
# LL::NG captcha dir
|
||||
CAPTCHADIR=$(DATADIR)/captcha
|
||||
|
||||
# LL::NG cache dir
|
||||
CACHEDIR=$(DATADIR)/cache
|
||||
|
||||
# Apache user/group
|
||||
APACHEUSER=
|
||||
APACHEGROUP=
|
||||
|
@ -178,6 +181,7 @@ RAPACHEPSESSIONFILEDIR=$(DESTDIR)/$(APACHEPSESSIONFILEDIR)
|
|||
RAPACHEPSESSIONFILELOCKDIR=$(DESTDIR)/$(APACHEPSESSIONFILELOCKDIR)
|
||||
RFILENOTIFDIR=$(DESTDIR)/$(APACHEFILENOTIFDIR)
|
||||
RCAPTCHADIR=$(DESTDIR)/$(CAPTCHADIR)
|
||||
RCACHEDIR=$(DESTDIR)/$(CACHEDIR)
|
||||
RFASTCGISOCKDIR=$(DESTDIR)/$(FASTCGISOCKDIR)
|
||||
|
||||
VERSION=`head -n1 changelog |sed -e 's/lemonldap-ng (//' -e 's/).*$$//'`
|
||||
|
@ -747,7 +751,7 @@ install_site: install_manager_site install_portal_site install_handler_site inst
|
|||
@echo "5 - Connect to Manager at http://manager.${DNSDOMAIN}/ to edit configuration"
|
||||
@echo
|
||||
@if [ ! "$(APACHEUSER)" ]; then \
|
||||
echo;echo " Warning, since APACHEUSER was not set, $(APACHESESSIONFILEDIR), $(APACHEPSESSIONFILEDIR), $(CAPTCHADIR) and $(CONFDIR) have permissive permissions."; \
|
||||
echo;echo " Warning, since APACHEUSER was not set, $(APACHESESSIONFILEDIR), $(APACHEPSESSIONFILEDIR), $(CAPTCHADIR), $(CACHEDIR) and $(CONFDIR) have permissive permissions."; \
|
||||
echo " Fix them by yourself to restrict their view to apache process only"; \
|
||||
fi
|
||||
@echo
|
||||
|
@ -904,7 +908,7 @@ install_doc_site:
|
|||
rm -rvf $(DOCLIBSTOREMOVEFORDEBIAN); \
|
||||
fi && cd -
|
||||
|
||||
install_conf_dir: install_sessions_dir install_notif_dir install_captcha_dir
|
||||
install_conf_dir: install_sessions_dir install_notif_dir install_captcha_dir install_cache_dir
|
||||
# Configuration files install
|
||||
@install -v -d $(RCONFDIR) $(RFILECONFIGDIR) $(RTOOLSDIR)
|
||||
@if [ "$(ERASECONFIG)" -eq "1" ]; then \
|
||||
|
@ -915,7 +919,8 @@ install_conf_dir: install_sessions_dir install_notif_dir install_captcha_dir
|
|||
@$(PERL) -i -pe 's/__DNSDOMAIN__/$(DNSDOMAIN)/g;\
|
||||
s#__SESSIONDIR__#$(APACHESESSIONFILEDIR)#g;\
|
||||
s#__PSESSIONDIR__#$(APACHEPSESSIONFILEDIR)#g;\
|
||||
s#__NOTIFICATIONDIR__#$(APACHEFILENOTIFDIR)#g;' $(RFILECONFIGDIR)/lmConf-1.json
|
||||
s#__NOTIFICATIONDIR__#$(APACHEFILENOTIFDIR)#g;\
|
||||
s#__CACHEDIR__#$(CACHEDIR)#g;' $(RFILECONFIGDIR)/lmConf-1.json
|
||||
@if [ "$(APACHEUSER)" != "" ]; then \
|
||||
chown $(APACHEUSER) $(RFILECONFIGDIR) || exit 1; \
|
||||
if [ "$(APACHEGROUP)" != "" ]; then \
|
||||
|
@ -927,7 +932,8 @@ install_conf_dir: install_sessions_dir install_notif_dir install_captcha_dir
|
|||
fi
|
||||
@cp $(SRCCOMMONDIR)/tools/lmConfig.* $(SRCCOMMONDIR)/tools/apache-session-mysql.sql $(RTOOLSDIR)
|
||||
@cp $(SRCCOMMONDIR)/tools/sso.schema $(RTOOLSDIR)
|
||||
$(PERL) -i -pe 's/__DNSDOMAIN__/$(DNSDOMAIN)/g' $(RCONFDIR)/$(CONFFILENAME)
|
||||
$(PERL) -i -pe 's/__DNSDOMAIN__/$(DNSDOMAIN)/g; s#__CACHEDIR__#$(CACHEDIR)#g;' \
|
||||
$(RCONFDIR)/$(CONFFILENAME)
|
||||
@rm -rf $$(find $(RCONFDIR) $(RFILECONFIGDIR) $(RTOOLSDIR) -type d -name .svn)
|
||||
|
||||
install_sessions_dir:
|
||||
|
@ -969,6 +975,19 @@ install_captcha_dir:
|
|||
chmod 777 $(RCAPTCHADIR); \
|
||||
fi
|
||||
|
||||
install_cache_dir:
|
||||
@install -m 777 -v -d $(RCACHEDIR)
|
||||
# Fix captcha directory permissions
|
||||
@if [ "$(APACHEUSER)" != "" ]; then \
|
||||
chown $(APACHEUSER) $(RCACHEDIR) || exit 1; \
|
||||
if [ "$(APACHEGROUP)" != "" ]; then \
|
||||
chgrp $(APACHEGROUP) $(RCACHEDIR) || exit 1; \
|
||||
fi; \
|
||||
chmod 770 $(RCACHEDIR); \
|
||||
else \
|
||||
chmod 777 $(RCACHEDIR); \
|
||||
fi
|
||||
|
||||
postconf_hosts:
|
||||
@cat ${CONFDIR}/for_etc_hosts >> /etc/hosts
|
||||
@echo "/etc/hosts was updated"
|
||||
|
@ -1152,12 +1171,12 @@ documentation:
|
|||
echo "Skipped documentation building" ;\
|
||||
else \
|
||||
sphinx-build -b html -d /tmp/doctrees \
|
||||
-Dhtml_theme_path=. -Dhtml_theme=manager_doc_theme \
|
||||
-Dhtml_theme=bootstrap\
|
||||
doc/sources/admin/ doc/pages/documentation/current/ ;\
|
||||
fi
|
||||
|
||||
website_documentation:
|
||||
sphinx-build -b html -d /tmp/doctrees \
|
||||
LLNGSPHINXWEBSITE=1 sphinx-build -b html -d /tmp/doctrees \
|
||||
doc/sources/admin/ "$(WEBSITE_DIR)"
|
||||
|
||||
test-diff:
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
"localSessionStorage" : "Cache::FileCache",
|
||||
"localSessionStorageOptions" : {
|
||||
"cache_depth" : 3,
|
||||
"cache_root" : "/tmp",
|
||||
"cache_root" : "__CACHEDIR__",
|
||||
"default_expires_in" : 600,
|
||||
"directory_umask" : "007",
|
||||
"namespace" : "lemonldap-ng-sessions"
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
auth_request_set $headervalue15 $upstream_http_headervalue15;
|
||||
auth_request_set $lmcookie $upstream_http_cookie;
|
||||
access_by_lua '
|
||||
i = 1
|
||||
local i = 1
|
||||
ngx.req.set_header("Cookie",ngx.var.lmcookie)
|
||||
while true do
|
||||
if ngx.var["headername"..i] ~= nil then
|
||||
|
|
2
debian/control
vendored
2
debian/control
vendored
|
@ -53,7 +53,7 @@ Build-Depends-Indep: libapache-session-perl <!nocheck>,
|
|||
libxml-libxml-perl <!nocheck>,
|
||||
libxml-libxslt-perl <!nocheck>,
|
||||
python3-sphinx,
|
||||
python3-sphinx-rtd-theme,
|
||||
python3-sphinx-bootstrap-theme,
|
||||
perl
|
||||
Standards-Version: 4.5.0
|
||||
Vcs-Browser: https://salsa.debian.org/perl-team/modules/packages/lemonldap-ng
|
||||
|
|
1
debian/liblemonldap-ng-common-perl.dirs
vendored
1
debian/liblemonldap-ng-common-perl.dirs
vendored
|
@ -1,3 +1,4 @@
|
|||
/var/cache/lemonldap-ng
|
||||
/var/lib/lemonldap-ng/conf
|
||||
/var/lib/lemonldap-ng/sessions/lock
|
||||
/var/lib/lemonldap-ng/psessions/lock
|
||||
|
|
7
debian/rules
vendored
7
debian/rules
vendored
|
@ -5,6 +5,7 @@
|
|||
|
||||
LMSHAREDIR=/usr/share/lemonldap-ng
|
||||
LMVARDIR =/var/lib/lemonldap-ng
|
||||
LMCACHEDIR =/var/cache/lemonldap-ng
|
||||
TMP = $(CURDIR)/debian/tmp
|
||||
|
||||
CONFDIR=/etc/lemonldap-ng
|
||||
|
@ -22,6 +23,7 @@ CAPTCHADIR=$(LMVARDIR)/captcha
|
|||
override_dh_auto_configure:
|
||||
$(MAKE) configure STORAGECONFFILE=/etc/lemonldap-ng/lemonldap-ng.ini \
|
||||
DATADIR=$(LMVARDIR) \
|
||||
CACHEDIR=$(LMCACHEDIR) \
|
||||
PERLOPTIONS="INSTALLDIRS=vendor"
|
||||
|
||||
override_dh_auto_build:
|
||||
|
@ -45,6 +47,7 @@ override_dh_auto_install:
|
|||
CONFDIR=/etc/lemonldap-ng \
|
||||
CRONDIR=/etc/cron.d \
|
||||
DATADIR=$(LMVARDIR) \
|
||||
CACHEDIR=$(LMCACHEDIR) \
|
||||
APACHEUSER=www-data \
|
||||
APACHEGROUP=www-data \
|
||||
DEFDOCDIR=/usr/share/doc/lemonldap-ng-doc \
|
||||
|
@ -70,6 +73,7 @@ override_dh_fixperms:
|
|||
debian/*/$(PSESSIONSDIR)/lock \
|
||||
debian/*/$(NOTIFICATIONSDIR) \
|
||||
debian/liblemonldap-ng-common-perl/$(CONFSTORAGEDIR) \
|
||||
debian/liblemonldap-ng-common-perl/$(LMCACHEDIR) \
|
||||
debian/liblemonldap-ng-portal-perl/$(CAPTCHADIR)
|
||||
chgrp www-data debian/liblemonldap-ng-common-perl/$(LMINIFILE) \
|
||||
debian/liblemonldap-ng-common-perl/$(FIRSTCONFFILE)
|
||||
|
@ -77,6 +81,7 @@ override_dh_fixperms:
|
|||
debian/*/$(PSESSIONSDIR) debian/*/$(PSESSIONSDIR)/lock \
|
||||
debian/*/$(NOTIFICATIONSDIR) \
|
||||
debian/liblemonldap-ng-portal-perl/$(CAPTCHADIR)
|
||||
chmod 750 debian/liblemonldap-ng-common-perl/$(CONFSTORAGEDIR)
|
||||
chmod 750 debian/liblemonldap-ng-common-perl/$(CONFSTORAGEDIR) \
|
||||
debian/liblemonldap-ng-common-perl/$(LMCACHEDIR)
|
||||
chmod 640 debian/liblemonldap-ng-common-perl/$(FIRSTCONFFILE) \
|
||||
debian/liblemonldap-ng-common-perl/$(LMINIFILE)
|
||||
|
|
|
@ -1 +1 @@
|
|||
3.0.18
|
||||
3.0.20
|
File diff suppressed because it is too large
Load Diff
|
@ -26,14 +26,15 @@ Configuration
|
|||
Pre-requisites
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
In this guide, it is assumed that you have followed the `Jitsi Meet
|
||||
This documentation assumes that you have already installed a :doc:`Nginx-based <../confignginx>`
|
||||
LemonLDAP::NG Handler on your Jitsi server.
|
||||
|
||||
You need to install Nginx before Jitsi Meet. If you install Jitsi Meet first,
|
||||
the Jitsi Meet installer will not generate a Nginx configuration file.
|
||||
|
||||
We assume that you have followed the `Jitsi Meet
|
||||
quick
|
||||
start <https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md>`__
|
||||
and that **you have installed Nginx on your Jitsi Meet server first**
|
||||
|
||||
If you have not done that, the Jitsi Meet installer will not generate a
|
||||
Nginx configuration file for you. This is not a problem is you are
|
||||
already using your own reverse proxy.
|
||||
|
||||
Jitsi Meet configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -59,26 +60,29 @@ configuration file:
|
|||
::
|
||||
|
||||
|
||||
location = /lmauth {
|
||||
internal;
|
||||
include /etc/nginx/fastcgi_params;
|
||||
fastcgi_pass unix:/var/run/llng-fastcgi-server/llng-fastcgi.sock;
|
||||
fastcgi_pass_request_body off;
|
||||
fastcgi_param CONTENT_LENGTH "";
|
||||
fastcgi_param HOST $http_host;
|
||||
fastcgi_param X_ORIGINAL_URI $request_uri;
|
||||
}
|
||||
# This block lets Nginx know how to contact the local LLNG handler
|
||||
# for authentication
|
||||
location = /lmauth {
|
||||
internal;
|
||||
include /etc/nginx/fastcgi_params;
|
||||
fastcgi_pass unix:/var/run/llng-fastcgi-server/llng-fastcgi.sock;
|
||||
fastcgi_pass_request_body off;
|
||||
fastcgi_param CONTENT_LENGTH "";
|
||||
fastcgi_param HOST $http_host;
|
||||
fastcgi_param X_ORIGINAL_URI $request_uri;
|
||||
}
|
||||
|
||||
# Protect only the /login/ URL
|
||||
# You may want to change this is your goal is to make the whole Jitsi Meet instance private
|
||||
|
||||
location /login/ {
|
||||
|
||||
# Protect the current path with LLNG
|
||||
auth_request /lmauth;
|
||||
auth_request_set $lmremote_user $upstream_http_lm_remote_user;
|
||||
auth_request_set $lmlocation $upstream_http_location;
|
||||
error_page 401 $lmlocation;
|
||||
|
||||
# Transmis user information to Jitsi through HTTP headers
|
||||
auth_request_set $mail $upstream_http_mail;
|
||||
proxy_set_header mail $mail;
|
||||
auth_request_set $displayname $upstream_http_displayName;
|
||||
|
@ -86,6 +90,7 @@ configuration file:
|
|||
auth_request_set $lmcookie $upstream_http_cookie;
|
||||
proxy_set_header Cookie: $lmcookie;
|
||||
|
||||
# Proxy requests to Jitsi Meet
|
||||
proxy_pass http://127.0.0.1:8888/login;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ Authentication Users Password
|
|||
Presentation
|
||||
------------
|
||||
|
||||
The Active Directory module is based on the
|
||||
:doc:`LDAP module<authldap>`, with these features:
|
||||
The Active Directory module is based on
|
||||
:doc:`LDAP module<authldap>`, with the following features:
|
||||
|
||||
- Specific default values for filters to match AD schema
|
||||
- Compatible password modification
|
||||
|
@ -30,7 +30,7 @@ implemented its own policy. LemonLDAP::NG implements partially the
|
|||
policy:
|
||||
|
||||
- when pwdLastSet = 0 in the user entry, it means that password has
|
||||
been reset, and a form is presented to the user for him to change his
|
||||
been reset, and a form is displayed to the user to change his
|
||||
password.
|
||||
- when computed virtual attribute 'msDS-User-Account-Control-Computed'
|
||||
as 6th flag set to 8, the password is considered expired (support
|
||||
|
|
|
@ -18,7 +18,7 @@ example Kerberos, Radius, OTP, etc.
|
|||
|
||||
.. attention::
|
||||
|
||||
To authenticate users using Kerberos, you can now use
|
||||
To authenticate users by using Kerberos, you can now use
|
||||
the new :doc:`Kerberos authentication module<authkerberos>` which allow
|
||||
one to chain Kerberos in a :doc:`combination<authcombination>`\
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ Authentication Users Password
|
|||
Presentation
|
||||
------------
|
||||
|
||||
LL::NG is able to transfer (trough REST or SOAP) authentication
|
||||
LL::NG is able to send (through REST or SOAP) authentication
|
||||
credentials to another LL::NG portal, like a proxy.
|
||||
|
||||
|
||||
|
@ -39,10 +39,10 @@ Then, go in ``Proxy parameters``:
|
|||
same as previous for SOAP, same with "/session/my" for REST)
|
||||
- **Cookie name** (optional): name of the cookie of internal portal, if
|
||||
different from external portal
|
||||
- **Authentication level**: level given to this authentication
|
||||
- **Authentication level**: authentication level for Proxy module
|
||||
- **Use SOAP instead of REST**: use a deprecated SOAP server instead of
|
||||
a REST one (you must set it if internal portal version is < 2.0). In
|
||||
this case, "Portal URL" parameter must contains SOAP endpoint
|
||||
this case, "Portal URL" parameter must contain SOAP endpoint
|
||||
(generally http://auth.example.com/index.pl/sessions for 1.9 and
|
||||
earlier, http://auth.example.com/sessions for 2.0)
|
||||
|
||||
|
@ -50,14 +50,14 @@ Internal portal
|
|||
~~~~~~~~~~~~~~~
|
||||
|
||||
The portal must be configured to accept REST or SOAP authentication
|
||||
requests if you've choose to use SOAP. See:
|
||||
requests if you chose to use SOAP. See:
|
||||
:doc:`REST server plugin<restservices>` or
|
||||
:doc:`SOAP session backend<soapsessionbackend>` *(deprecated)*.
|
||||
|
||||
SOAP compatibility with 1.9 server
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you Proxy is a 2.0.x and your server is a 1.9.x, you should add this
|
||||
If your Proxy is a 2.0.x and your server is a 1.9.x, you should add this
|
||||
in your lemonldap-ng.ini:
|
||||
|
||||
.. code-block:: ini
|
||||
|
|
|
@ -34,7 +34,7 @@ Then, go in ``Slave parameters``:
|
|||
- **Master's IP address**: the IP addresses of servers which are
|
||||
accredited to authenticate user. This is a security point, to prevent
|
||||
someone to create a session by sending custom headers. You can set
|
||||
one or several IP addresses, separated by spaces, or let this
|
||||
one or several IP addresses, spaces separated, or let this
|
||||
parameter empty to disable the checking.
|
||||
- **Control header name**: header that contains a value to control. Let
|
||||
this parameter empty to disable the checking.
|
||||
|
|
|
@ -20,6 +20,15 @@ Go in Manager, ``General Parameters`` » ``Advanced Parameters`` »
|
|||
``Security`` » ``Brute-force attack protection`` » ``Activation``\ and
|
||||
set to ``On``.
|
||||
|
||||
- **Parameters**:
|
||||
|
||||
- **Activation**: Enable/disable brute force attack protection
|
||||
- **Lock time**: Waiting time before another login attempt
|
||||
- **Allowed failed login**: Number of failed login attempts allowed before account is locked
|
||||
- **Incremental lock**: Enable/disable incremental lock times
|
||||
- **Incremental lock times**: List of comma separated lock time values in seconds
|
||||
|
||||
|
||||
Incremental lock time enabled
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -35,33 +44,29 @@ in ``lemonldap-ng.ini`` [portal] section:
|
|||
[portal]
|
||||
bruteForceProtectionIncrementalTempo = 1
|
||||
|
||||
Lock time increases between each failed login attempt. To modify lock
|
||||
time values ('5 15 60 300 600' seconds by default) or max lock time
|
||||
value (900 seconds by default) edit ``lemonldap-ng.ini`` in [portal]
|
||||
section:
|
||||
Lock time increases between each failed login attempt after allowed failed logins.
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[portal]
|
||||
bruteForceProtectionLockTimes = '5 15 60 300 600'
|
||||
bruteForceProtectionLockTimes = 5, 15, 60, 300, 600
|
||||
bruteForceProtectionMaxLockTime = 900
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Max lock time value is used by this plugin if a lock time is
|
||||
missing (number of failed logins higher than listed lock time values).
|
||||
Max lock time value is used if a lock time is missing
|
||||
(number of failed logins higher than listed lock time values).
|
||||
Lock time values can not be higher than max lock time.
|
||||
|
||||
|
||||
Incremental lock time disabled
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
After ``bruteForceProtectionMaxFailed`` failed login attempts, user must
|
||||
wait ``bruteForceProtectionTempo`` seconds before trying to log in
|
||||
again. To modify waiting time (30 seconds by default), MaxAge between
|
||||
current and last stored failed login (300 seconds by default) or number
|
||||
of allowed failed login attempts (3 by default) edit
|
||||
``lemonldap-ng.ini`` in [portal] section:
|
||||
After allowed failed login attempts, user must
|
||||
wait the lock time before trying to log in again.
|
||||
To modify delta (MaxAge) between current and last stored
|
||||
failed login (300 seconds by default) edit ``lemonldap-ng.ini`` in [portal] section:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
|
@ -72,7 +77,12 @@ of allowed failed login attempts (3 by default) edit
|
|||
|
||||
|
||||
.. attention::
|
||||
Number of failed login attempts history might be also higher than
|
||||
number of incremental lock time value plus allowed failed login attempts.
|
||||
Incremental lock time values list will be truncated if not.
|
||||
|
||||
|
||||
.. danger::
|
||||
Number of failed login attempts stored in history MUST
|
||||
be higher than allowed failed logins for this plugin takes effect.
|
||||
See :doc:`History plugin<loginhistory>`
|
|
@ -19,7 +19,7 @@ Let's go
|
|||
|
||||
- Prepare your new lemonldap-ng.ini file
|
||||
- Configure your new backend (create SQL database,...)
|
||||
- Launch that:
|
||||
- Launch the following command:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
|
@ -29,6 +29,14 @@ Let's go
|
|||
all LL::NG servers
|
||||
- Restart all your Apache servers
|
||||
|
||||
.. note::
|
||||
|
||||
Since LemonLDAP 2.0.9, you don't need the ``--current`` and ``--new`` options
|
||||
when migrating from the default file-based backend. Simply run
|
||||
`convertConfig` to migrate from the default configuration backend to the
|
||||
currently configured backend.
|
||||
|
||||
|
||||
See also
|
||||
--------
|
||||
|
||||
|
|
|
@ -456,3 +456,52 @@ To update the master encryption key:
|
|||
set \
|
||||
key 'xxxxxxxxxxxxxxx'
|
||||
|
||||
|
||||
|
||||
Sessions Management
|
||||
-------------------
|
||||
.. versionadded:: 2.0.9
|
||||
|
||||
|
||||
Get the content of a session ::
|
||||
|
||||
lemonldap-ng-sessions get 9684dd2a6489bf2be2fbdd799a8028e3
|
||||
|
||||
Get the content of a persistent session ::
|
||||
|
||||
lemonldap-ng-sessions get --persistent dwho
|
||||
|
||||
Search all sessions by username ::
|
||||
|
||||
lemonldap-ng-sessions search --where uid=dwho
|
||||
|
||||
Modify session ::
|
||||
|
||||
lemonldap-ng-sessions setKey 9684dd2a6489bf2be2fbdd799a8028e3 \
|
||||
authenticationLevel 1
|
||||
|
||||
Second Factors management
|
||||
-------------------------
|
||||
|
||||
.. versionadded:: 2.0.9
|
||||
|
||||
List second factors of a user ::
|
||||
|
||||
lemonldap-ng-sessions secondfactors get dwho
|
||||
|
||||
Deregister Yubikey of a user ::
|
||||
|
||||
lemonldap-ng-sessions secondfactors delType dwho UBK
|
||||
|
||||
OIDC Consents management
|
||||
------------------------
|
||||
|
||||
.. versionadded:: 2.0.9
|
||||
|
||||
List consents of a user ::
|
||||
|
||||
lemonldap-ng-sessions consents get dwho
|
||||
|
||||
Revoke consents on OIDC provider 'test' for a user::
|
||||
|
||||
lemonldap-ng-sessions consents delete dwho test
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
import sphinx_bootstrap_theme
|
||||
import os
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
|
@ -48,7 +50,7 @@ master_doc = 'start'
|
|||
|
||||
# General information about the project.
|
||||
project = u'LemonLDAP::NG'
|
||||
copyright = u'2019, LemonLDAP::NG'
|
||||
copyright = u'2020, LemonLDAP::NG'
|
||||
author = u'LemonLDAP::NG'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
|
@ -118,20 +120,25 @@ todo_include_todos = False
|
|||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
#html_theme_path = [ '.' ]
|
||||
html_theme_path = sphinx_bootstrap_theme.get_html_theme_path()
|
||||
|
||||
# For website
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme = 'bootstrap'
|
||||
|
||||
# For embedded doc
|
||||
#html_theme = 'my_theme'
|
||||
html_theme_options = {
|
||||
'globaltoc_includehidden': False,
|
||||
'navbar_sidebarrel': False,
|
||||
'navbar_pagenav': False,
|
||||
'globaltoc_depth': 0,
|
||||
'navbar_fixed_top': "false",
|
||||
'navbar_class': "hidden",
|
||||
}
|
||||
|
||||
if 'LLNGSPHINXWEBSITE' in os.environ:
|
||||
import sphinx_rtd_theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_options = {}
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# html_theme_options = {}
|
||||
|
||||
|
|
|
@ -133,9 +133,10 @@ Install dependencies
|
|||
aptitude install nginx nginx-extras # install Nginx
|
||||
cpanm perltidy@20181120
|
||||
|
||||
For SAML:
|
||||
|
||||
::
|
||||
|
||||
SAML :
|
||||
aptitude install liblasso-perl libglib-perl
|
||||
|
||||
Working Project
|
||||
|
@ -188,3 +189,20 @@ Other commands
|
|||
make manifest # to update manifest
|
||||
make tidy # to magnify perl files (perl best pratices)
|
||||
|
||||
Documentation
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Install dependencies:
|
||||
|
||||
::
|
||||
|
||||
apt install python3-sphinx python3-sphinx-bootstrap-theme
|
||||
|
||||
Then edit sources in doc/sources/admin.
|
||||
|
||||
You can check the result with:
|
||||
|
||||
::
|
||||
|
||||
make documentation
|
||||
firefox doc/pages/documentation/current/start.html
|
||||
|
|
|
@ -1,397 +0,0 @@
|
|||
|
||||
Error at "source" (line 10, column 18):
|
||||
unexpected "R"
|
||||
expecting "{{"
|
||||
| dwho | ''$env->{REMOTE_ADDR} eq '192.168.42.42' '' |
|
||||
^
|
||||
|
||||
Error at "source" (line 7, column 21):
|
||||
unexpected "}"
|
||||
expecting "{{"
|
||||
===== Available $ENV{} variables =====
|
||||
^
|
||||
/home/maxbes/proj/doc/authcustom.rst:46: WARNING: Explicit markup ends without a blank line; unexpected unindent.
|
||||
/home/maxbes/proj/doc/authopenidconnect.rst:235: WARNING: image file not readable: section>openidconnectclaims&noheader
|
||||
/home/maxbes/proj/doc/authopenidconnect.rst:235: WARNING: image file not readable: section>openidconnectclaims&noheader
|
||||
/home/maxbes/proj/doc/aws.rst:45: WARNING: Cannot analyze code. No Pygments lexer found for "ldif".
|
||||
/home/maxbes/proj/doc/behindproxyminihowto.rst:89: WARNING: image file not readable: documentation/reverseproxy.png
|
||||
/home/maxbes/proj/doc/behindproxyminihowto.rst:89: WARNING: image file not readable: documentation/reverseproxy.png
|
||||
/home/maxbes/proj/doc/browseablesessionbackend.rst:162: WARNING: Explicit markup ends without a blank line; unexpected unindent.
|
||||
/home/maxbes/proj/doc/cda.rst:29: WARNING: image file not readable: section>..presentation#cross_domain_authentication_cda&noheader
|
||||
/home/maxbes/proj/doc/cda.rst:29: WARNING: image file not readable: section>..presentation#cross_domain_authentication_cda&noheader
|
||||
/home/maxbes/proj/doc/exportedvars.rst:49: WARNING: image file not readable: page>performances#macros_and_groups&noheader
|
||||
/home/maxbes/proj/doc/exportedvars.rst:49: WARNING: image file not readable: page>performances#macros_and_groups&noheader
|
||||
/home/maxbes/proj/doc/fusiondirectory.rst:34: WARNING: image file not readable: applications/fusiondirectory-logo.jpg
|
||||
/home/maxbes/proj/doc/fusiondirectory.rst:34: WARNING: image file not readable: applications/fusiondirectory-logo.jpg
|
||||
/home/maxbes/proj/doc/idpopenidconnect.rst:213: WARNING: image file not readable: section>openidconnectclaims&noheader
|
||||
/home/maxbes/proj/doc/idpopenidconnect.rst:213: WARNING: image file not readable: section>openidconnectclaims&noheader
|
||||
/home/maxbes/proj/doc/installdeb.rst:171: WARNING: image file not readable: rpm-gpg-key-ow2
|
||||
/home/maxbes/proj/doc/installdeb.rst:171: WARNING: image file not readable: rpm-gpg-key-ow2
|
||||
/home/maxbes/proj/doc/installrpm.rst:216: WARNING: image file not readable: rpm-gpg-key-ow2
|
||||
/home/maxbes/proj/doc/installrpm.rst:216: WARNING: image file not readable: rpm-gpg-key-ow2
|
||||
/home/maxbes/proj/doc/installsles.rst:247: WARNING: image file not readable: rpm-gpg-key-ow2
|
||||
/home/maxbes/proj/doc/installsles.rst:247: WARNING: image file not readable: rpm-gpg-key-ow2
|
||||
/home/maxbes/proj/doc/mediawiki.rst:96: WARNING: Explicit markup ends without a blank line; unexpected unindent.
|
||||
/home/maxbes/proj/doc/mediawiki.rst:110: WARNING: Explicit markup ends without a blank line; unexpected unindent.
|
||||
/home/maxbes/proj/doc/performances.rst:307: WARNING: Cannot analyze code. No Pygments lexer found for "ldif".
|
||||
/home/maxbes/proj/doc/portalcustom.rst:22: WARNING: Bullet list ends without a blank line; unexpected unindent.
|
||||
/home/maxbes/proj/doc/prereq.rst:212: WARNING: image file not readable: ../llng_deps.png
|
||||
/home/maxbes/proj/doc/prereq.rst:212: WARNING: image file not readable: ../llng_deps.png
|
||||
/home/maxbes/proj/doc/rbac.rst:71: WARNING: Cannot analyze code. No Pygments lexer found for "ldif".
|
||||
/home/maxbes/proj/doc/renater.rst:174: WARNING: image file not readable: logos/1renater.png
|
||||
/home/maxbes/proj/doc/renater.rst:174: WARNING: image file not readable: logos/1renater.png
|
||||
/home/maxbes/proj/doc/salesforce.rst:122: WARNING: image file not readable: applications/salesforce-logo.jpg
|
||||
/home/maxbes/proj/doc/salesforce.rst:122: WARNING: image file not readable: applications/salesforce-logo.jpg
|
||||
/home/maxbes/proj/doc/sap.rst:18: WARNING: image file not readable: applications/SAPLogo.gif
|
||||
/home/maxbes/proj/doc/sap.rst:18: WARNING: image file not readable: applications/SAPLogo.gif
|
||||
/home/maxbes/proj/doc/servertoserver.rst:44: WARNING: image file not readable: ../server_to_server.png
|
||||
/home/maxbes/proj/doc/servertoserver.rst:44: WARNING: image file not readable: ../server_to_server.png
|
||||
/home/maxbes/proj/doc/sqlsessionbackend.rst:11: SEVERE: Unexpected section title or transition.
|
||||
|
||||
....
|
||||
/home/maxbes/proj/doc/ssoaas.rst:22: WARNING: Inline emphasis start-string without end-string.
|
||||
/home/maxbes/proj/doc/.applications2.swp.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/activedirectoryminihowto.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/adfs.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/alfresco.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/applications.1.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/applications2.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authad.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authapache.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authbasic.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authcas.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authchoice.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authcombination.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authcustom.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authdbi.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authdemo.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authfacebook.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authgpg.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authkerberos.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authldap.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authlinkedin.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authmulti.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authnull.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authopenid.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authopenidconnect.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authopenidconnect_franceconnect.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authopenidconnect_google.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authpam.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authproxy.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authradius.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authremote.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authrest.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authsaml.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authslave.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authssl.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authtwitter.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authwebid.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/authyubikey.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/autosignin.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/aws.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/behindproxyminihowto.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/browseablesessionbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/bruteforceprotection.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/bugzilla.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/captcha.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/cda.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/changeconfbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/checkstate.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/cli_examples.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/configapache.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/configlocation.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/confignginx.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/configplack.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/configvhost.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/cornerstone.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/customfunctions.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/customhandlers.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/devopshandler.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/devopssthandler.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/django.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/docker.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/dokuwiki.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/dos.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/drupal.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/error.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/exploit.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/exportedvars.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/extendedfunctions.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/external2f.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/fastcgi.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/fastcgiserver.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/federationproxy.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/fileconfbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/filesessionbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/forcereauthn.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/formreplay.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/fusiondirectory.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/gitlab.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/glpi.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/googleapps.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/grr.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/handlerarch.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/handlerauthbasic.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/header_remote_user_conversion.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/highavailability.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/idpcas.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/idpopenid.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/idpopenidconnect.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/idpsaml.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/installdeb.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/installrpm.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/installsles.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/installtarball.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/issuerdbget.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/kerberos.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/ldapconfbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/ldapminihowto.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/ldapsessionbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/liferay.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/limesurvey.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/localconfbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/loginhistory.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/logoutforward.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/logs.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/mail2f.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/managerprotection.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/managertests.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/mediawiki.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/memcachedsessionbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/mitm.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/mongodbconfbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/mongodbsessionbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/monitoring.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/mrtg.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/mysqlminihowto.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/nextcloud.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/nodehandler.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/nosqlsessionbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/notifications.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/obm.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/office365.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/openidconnectservice.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/parameterlist.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/passwordstore.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/performances.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/phpldapadmin.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/platformsoverview.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/plugincustom.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/portal.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/portalcustom.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/portalmenu.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/portalservers.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/prereq.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/psgi.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/public_pages.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/rbac.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/redirections.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/register.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/renater.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/resetpassword.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/rest2f.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/restconfbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/restminihowto.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/restservices.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/restsessionbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/roundcube.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/safejail.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/salesforce.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/samlservice.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/sap.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/secondfactor.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/securetoken.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/security.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/selfmadeapplication.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/selinux.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/servertoserver.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/sessions.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/simplesamlphp.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/smtp.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/soapconfbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/soapservices.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/soapsessionbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/spring.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/sqlconfbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/sqlsessionbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/ssoaas.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/ssocookie.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/status.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/stayconnected.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/symfony.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/sympa.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/tomcat.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/totp2f.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/u2f.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/upgrade.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/utotp2f.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/variables.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/wordpress.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/writingrulesand_headers.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/xwiki.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/yamlconfbackend.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/yubikey2f.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/zimbra.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/zimbra2.rst:: WARNING: document isn't included in any toctree
|
||||
/home/maxbes/proj/doc/applications2.rst:28: WARNING: unknown document: applications/authbasic
|
||||
/home/maxbes/proj/doc/applications2.rst:39: WARNING: unknown document: applications/adfs
|
||||
/home/maxbes/proj/doc/applications2.rst:39: WARNING: unknown document: applications/adfs
|
||||
/home/maxbes/proj/doc/applications2.rst:40: WARNING: unknown document: applications/alfresco
|
||||
/home/maxbes/proj/doc/applications2.rst:40: WARNING: unknown document: applications/alfresco
|
||||
/home/maxbes/proj/doc/applications2.rst:41: WARNING: unknown document: applications/aws
|
||||
/home/maxbes/proj/doc/applications2.rst:41: WARNING: unknown document: applications/aws
|
||||
/home/maxbes/proj/doc/applications2.rst:42: WARNING: unknown document: applications/bugzilla
|
||||
/home/maxbes/proj/doc/applications2.rst:42: WARNING: unknown document: applications/bugzilla
|
||||
/home/maxbes/proj/doc/applications2.rst:43: WARNING: unknown document: applications/cornerstone
|
||||
/home/maxbes/proj/doc/applications2.rst:43: WARNING: unknown document: applications/cornerstone
|
||||
/home/maxbes/proj/doc/applications2.rst:44: WARNING: unknown document: applications/django
|
||||
/home/maxbes/proj/doc/applications2.rst:44: WARNING: unknown document: applications/django
|
||||
/home/maxbes/proj/doc/applications2.rst:46: WARNING: unknown document: applications/dokuwiki
|
||||
/home/maxbes/proj/doc/applications2.rst:46: WARNING: unknown document: applications/dokuwiki
|
||||
/home/maxbes/proj/doc/applications2.rst:47: WARNING: unknown document: applications/drupal
|
||||
/home/maxbes/proj/doc/applications2.rst:47: WARNING: unknown document: applications/drupal
|
||||
/home/maxbes/proj/doc/applications2.rst:48: WARNING: unknown document: applications/fusiondirectory
|
||||
/home/maxbes/proj/doc/applications2.rst:48: WARNING: unknown document: applications/fusiondirectory
|
||||
/home/maxbes/proj/doc/applications2.rst:49: WARNING: unknown document: applications/gitlab
|
||||
/home/maxbes/proj/doc/applications2.rst:49: WARNING: unknown document: applications/gitlab
|
||||
/home/maxbes/proj/doc/applications2.rst:50: WARNING: unknown document: applications/glpi
|
||||
/home/maxbes/proj/doc/applications2.rst:50: WARNING: unknown document: applications/glpi
|
||||
/home/maxbes/proj/doc/applications2.rst:51: WARNING: unknown document: applications/googleapps
|
||||
/home/maxbes/proj/doc/applications2.rst:51: WARNING: unknown document: applications/googleapps
|
||||
/home/maxbes/proj/doc/applications2.rst:53: WARNING: unknown document: applications/grr
|
||||
/home/maxbes/proj/doc/applications2.rst:53: WARNING: unknown document: applications/grr
|
||||
/home/maxbes/proj/doc/applications2.rst:54: WARNING: unknown document: applications/liferay
|
||||
/home/maxbes/proj/doc/applications2.rst:54: WARNING: unknown document: applications/liferay
|
||||
/home/maxbes/proj/doc/applications2.rst:55: WARNING: unknown document: applications/limesurvey
|
||||
/home/maxbes/proj/doc/applications2.rst:55: WARNING: unknown document: applications/limesurvey
|
||||
/home/maxbes/proj/doc/applications2.rst:56: WARNING: unknown document: applications/mediawiki
|
||||
/home/maxbes/proj/doc/applications2.rst:56: WARNING: unknown document: applications/mediawiki
|
||||
/home/maxbes/proj/doc/applications2.rst:57: WARNING: unknown document: applications/nextcloud
|
||||
/home/maxbes/proj/doc/applications2.rst:57: WARNING: unknown document: applications/nextcloud
|
||||
/home/maxbes/proj/doc/applications2.rst:59: WARNING: unknown document: applications/obm
|
||||
/home/maxbes/proj/doc/applications2.rst:59: WARNING: unknown document: applications/obm
|
||||
/home/maxbes/proj/doc/applications2.rst:60: WARNING: unknown document: applications/office365
|
||||
/home/maxbes/proj/doc/applications2.rst:60: WARNING: unknown document: applications/office365
|
||||
/home/maxbes/proj/doc/applications2.rst:61: WARNING: unknown document: applications/phpldapadmin
|
||||
/home/maxbes/proj/doc/applications2.rst:61: WARNING: unknown document: applications/phpldapadmin
|
||||
/home/maxbes/proj/doc/applications2.rst:62: WARNING: unknown document: applications/roundcube
|
||||
/home/maxbes/proj/doc/applications2.rst:62: WARNING: unknown document: applications/roundcube
|
||||
/home/maxbes/proj/doc/applications2.rst:63: WARNING: unknown document: <applications/salesforce>
|
||||
/home/maxbes/proj/doc/applications2.rst:63: WARNING: unknown document: applications/salesforce
|
||||
/home/maxbes/proj/doc/applications2.rst:64: WARNING: unknown document: applications/sap
|
||||
/home/maxbes/proj/doc/applications2.rst:64: WARNING: unknown document: applications/sap
|
||||
/home/maxbes/proj/doc/applications2.rst:65: WARNING: unknown document: applications/simplesamlphp
|
||||
/home/maxbes/proj/doc/applications2.rst:65: WARNING: unknown document: applications/simplesamlphp
|
||||
/home/maxbes/proj/doc/applications2.rst:67: WARNING: unknown document: applications/spring
|
||||
/home/maxbes/proj/doc/applications2.rst:67: WARNING: unknown document: applications/spring
|
||||
/home/maxbes/proj/doc/applications2.rst:68: WARNING: unknown document: applications/symfony
|
||||
/home/maxbes/proj/doc/applications2.rst:68: WARNING: unknown document: applications/symfony
|
||||
/home/maxbes/proj/doc/applications2.rst:69: WARNING: unknown document: applications/sympa
|
||||
/home/maxbes/proj/doc/applications2.rst:69: WARNING: unknown document: applications/sympa
|
||||
/home/maxbes/proj/doc/applications2.rst:70: WARNING: unknown document: applications/tomcat
|
||||
/home/maxbes/proj/doc/applications2.rst:70: WARNING: unknown document: applications/tomcat
|
||||
/home/maxbes/proj/doc/applications2.rst:71: WARNING: unknown document: applications/wordpress
|
||||
/home/maxbes/proj/doc/applications2.rst:71: WARNING: unknown document: applications/wordpress
|
||||
/home/maxbes/proj/doc/applications2.rst:72: WARNING: unknown document: applications/xwiki
|
||||
/home/maxbes/proj/doc/applications2.rst:72: WARNING: unknown document: applications/xwiki
|
||||
/home/maxbes/proj/doc/applications2.rst:73: WARNING: unknown document: applications/zimbra
|
||||
/home/maxbes/proj/doc/applications2.rst:73: WARNING: unknown document: applications/zimbra
|
||||
/home/maxbes/proj/doc/authopenidconnect.rst:41: WARNING: unknown document: <authopenidconnect_google>
|
||||
/home/maxbes/proj/doc/authopenidconnect.rst:41: WARNING: unknown document: <authopenidconnect_franceconnect>
|
||||
/home/maxbes/proj/doc/authproxy.rst:47: WARNING: unknown document: /documentation/2.0/restservices
|
||||
/home/maxbes/proj/doc/authssl.rst:24: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/authssl.rst:268: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/browseablesessionbackend.rst:7: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/browseablesessionbackend.rst:7: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/browseablesessionbackend.rst:35: WARNING: unknown document: session::browseable
|
||||
/home/maxbes/proj/doc/browseablesessionbackend.rst:102: WARNING: unknown document: session::browseable
|
||||
/home/maxbes/proj/doc/browseablesessionbackend.rst:128: WARNING: unknown document: /documentation/latest/sessions
|
||||
/home/maxbes/proj/doc/browseablesessionbackend.rst:135: WARNING: unknown document: session::browseable
|
||||
/home/maxbes/proj/doc/cli_examples.rst:99: WARNING: unknown document: ldap://ldap.example.com
|
||||
/home/maxbes/proj/doc/configlocation.rst:27: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/extendedfunctions.rst:165: WARNING: unknown document: applications/authbasic
|
||||
/home/maxbes/proj/doc/extendedfunctions.rst:262: WARNING: unknown document: /documentation/2.0/servertoserver
|
||||
/home/maxbes/proj/doc/formreplay.rst:18: WARNING: unknown document: applications
|
||||
/home/maxbes/proj/doc/googleapps.rst:140: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/handlerarch.rst:9: WARNING: unknown document: platform::main)//
|
||||
/home/maxbes/proj/doc/handlerarch.rst:30: WARNING: unknown document: /documentation/latest/applications/zimbra
|
||||
/home/maxbes/proj/doc/installdeb.rst:93: WARNING: unknown document: /download
|
||||
/home/maxbes/proj/doc/installdeb.rst:162: WARNING: unknown document: /download
|
||||
/home/maxbes/proj/doc/installrpm.rst:100: WARNING: unknown document: /download
|
||||
/home/maxbes/proj/doc/installsles.rst:92: WARNING: unknown document: /download
|
||||
/home/maxbes/proj/doc/installsles.rst:241: WARNING: unknown document: /download
|
||||
/home/maxbes/proj/doc/installtarball.rst:7: WARNING: unknown document: /download
|
||||
/home/maxbes/proj/doc/liferay.rst:85: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/memcachedsessionbackend.rst:12: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/memcachedsessionbackend.rst:13: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/mongodbsessionbackend.rst:10: WARNING: unknown document: session::mongodb
|
||||
/home/maxbes/proj/doc/parameterlist.rst:175: WARNING: unknown document: ldap::search
|
||||
/home/maxbes/proj/doc/performances.rst:174: WARNING: unknown document: session::mysql
|
||||
/home/maxbes/proj/doc/performances.rst:189: WARNING: unknown document: session::flex
|
||||
/home/maxbes/proj/doc/performances.rst:209: WARNING: unknown document: session::mysql
|
||||
/home/maxbes/proj/doc/performances.rst:214: WARNING: unknown document: session::browseable
|
||||
/home/maxbes/proj/doc/performances.rst:231: WARNING: unknown document: session::browseable
|
||||
/home/maxbes/proj/doc/performances.rst:241: WARNING: unknown document: session::memcached
|
||||
/home/maxbes/proj/doc/performances.rst:253: WARNING: unknown document: session::browseable
|
||||
/home/maxbes/proj/doc/platformsoverview.rst:9: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/platformsoverview.rst:23: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/platformsoverview.rst:24: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/platformsoverview.rst:24: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/platformsoverview.rst:55: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/platformsoverview.rst:64: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/portal.rst:91: WARNING: unknown document: /documentation/presentation
|
||||
/home/maxbes/proj/doc/prereq.rst:52: WARNING: unknown document: http::headers
|
||||
/home/maxbes/proj/doc/prereq.rst:53: WARNING: unknown document: http::request
|
||||
/home/maxbes/proj/doc/restconfbackend.rst:19: WARNING: unknown document: /documentation/1.0/fileconfbackend
|
||||
/home/maxbes/proj/doc/restconfbackend.rst:19: WARNING: unknown document: /documentation/1.0/sqlconfbackend
|
||||
/home/maxbes/proj/doc/restconfbackend.rst:19: WARNING: unknown document: /documentation/1.0/ldapconfbackend
|
||||
/home/maxbes/proj/doc/samlservice.rst:424: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/selfmadeapplication.rst:19: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/servertoserver.rst:11: WARNING: unknown document: /documentation/2.0/securetoken
|
||||
/home/maxbes/proj/doc/sessions.rst:36: WARNING: unknown document: session::generate
|
||||
/home/maxbes/proj/doc/soapconfbackend.rst:25: WARNING: unknown document: /documentation/1.0/fileconfbackend
|
||||
/home/maxbes/proj/doc/soapconfbackend.rst:25: WARNING: unknown document: /documentation/1.0/sqlconfbackend
|
||||
/home/maxbes/proj/doc/soapconfbackend.rst:25: WARNING: unknown document: /documentation/1.0/ldapconfbackend
|
||||
/home/maxbes/proj/doc/sqlsessionbackend.rst:49: WARNING: unknown document: /documentation/latest/sessions
|
||||
/home/maxbes/proj/doc/sqlsessionbackend.rst:106: WARNING: unknown document: /documentation/latest/sessions
|
||||
/home/maxbes/proj/doc/ssocookie.rst:7: WARNING: unknown document: /documentation/presentation
|
||||
/home/maxbes/proj/doc/ssocookie.rst:7: WARNING: unknown document: /documentation/presentation
|
||||
/home/maxbes/proj/doc/start.rst:7: WARNING: unknown document: /documentation/presentation
|
||||
/home/maxbes/proj/doc/start.rst:8: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/start.rst:9: WARNING: unknown document: /documentation/quickstart
|
||||
/home/maxbes/proj/doc/start.rst:221: WARNING: unknown document: applications/zimbra
|
||||
/home/maxbes/proj/doc/start.rst:278: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/start.rst:278: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/start.rst:281: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/start.rst:281: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/start.rst:285: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/start.rst:285: WARNING: unknown document: /documentation/features
|
||||
/home/maxbes/proj/doc/start.rst:296: WARNING: unknown document: writingrulesand headers
|
||||
/home/maxbes/proj/doc/start.rst:298: WARNING: unknown document: applications
|
||||
/home/maxbes/proj/doc/start.rst:309: WARNING: unknown document: applications
|
||||
/home/maxbes/proj/doc/start.rst:313: WARNING: unknown document: applications/adfs
|
||||
/home/maxbes/proj/doc/start.rst:315: WARNING: unknown document: applications/alfresco
|
||||
/home/maxbes/proj/doc/start.rst:317: WARNING: unknown document: applications/bugzilla
|
||||
/home/maxbes/proj/doc/start.rst:319: WARNING: unknown document: applications/dokuwiki
|
||||
/home/maxbes/proj/doc/start.rst:321: WARNING: unknown document: applications/drupal
|
||||
/home/maxbes/proj/doc/start.rst:323: WARNING: unknown document: applications/fusiondirectory
|
||||
/home/maxbes/proj/doc/start.rst:325: WARNING: unknown document: applications/gitlab
|
||||
/home/maxbes/proj/doc/start.rst:327: WARNING: unknown document: applications/glpi
|
||||
/home/maxbes/proj/doc/start.rst:329: WARNING: unknown document: applications/liferay
|
||||
/home/maxbes/proj/doc/start.rst:331: WARNING: unknown document: applications/mediawiki
|
||||
/home/maxbes/proj/doc/start.rst:333: WARNING: unknown document: applications/nextcloud
|
||||
/home/maxbes/proj/doc/start.rst:335: WARNING: unknown document: applications/simplesamlphp
|
||||
/home/maxbes/proj/doc/start.rst:337: WARNING: unknown document: applications/wordpress
|
||||
/home/maxbes/proj/doc/start.rst:339: WARNING: unknown document: applications/xwiki
|
||||
/home/maxbes/proj/doc/start.rst:341: WARNING: unknown document: applications/zimbra
|
||||
/home/maxbes/proj/doc/start.rst:407: WARNING: unknown document: /bugreport
|
||||
/home/maxbes/proj/doc/tomcat.rst:37: WARNING: unknown document: /download
|
||||
/home/maxbes/proj/doc/tomcat.rst:53: WARNING: unknown document:
|
||||
/home/maxbes/proj/doc/tomcat.rst:92: WARNING: unknown document: /download
|
||||
/home/maxbes/proj/doc/u2f.rst:63: WARNING: unknown document: about:config
|
||||
/home/maxbes/proj/doc/upgrade.rst:139: WARNING: unknown document: /documentation/2.0/behindproxyminihowto
|
||||
/home/maxbes/proj/doc/upgrade.rst:170: WARNING: unknown document: /documentation/2.0/cda
|
||||
/home/maxbes/proj/doc/upgrade.rst:170: WARNING: unknown document: /documentation/latest/applications/zimbra
|
||||
/home/maxbes/proj/doc/upgrade.rst:170: WARNING: unknown document: /documentation/2.0/handlerarch
|
||||
/home/maxbes/proj/doc/upgrade.rst:177: WARNING: unknown document: /documentation/2.0/ssocookie
|
||||
/home/maxbes/proj/doc/variables.rst:64: WARNING: unknown document: /documentation/2.0/behindproxyminihowto
|
|
@ -26,4 +26,11 @@ it in [configuration] section in your lemonldap-ng.ini file:
|
|||
[configuration]
|
||||
type = File
|
||||
dirName = /var/lib/lemonldap-ng/conf
|
||||
prettyPrint = 1
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
* `dirName`: directory under which the configuration files will be stored. It must be writable by your webserver account
|
||||
* `prettyPrint`: store files in a readable. Set it to 0 to get a small performance increase when loading/saving configuration
|
||||
|
|
|
@ -17,7 +17,7 @@ Configuration
|
|||
-------------
|
||||
|
||||
This feature can be enabled and configured in Manager, in
|
||||
``General Parameters`` » ``Advanced Parameters`` » ``Login History``.
|
||||
``General Parameters`` » ``Plugins`` » ``Login History``.
|
||||
You can define how many logins and failed logins will be stored.
|
||||
|
||||
A login is considered as successful if user get authenticated and is
|
||||
|
|
|
@ -78,19 +78,37 @@ Logout:
|
|||
|
||||
[notice] User clement.oudot has been disconnected from LDAP (81.20.13.21)
|
||||
|
||||
Access to an SAML SP:
|
||||
Access to a CAS application non registered in configuration (when CAS server is open):
|
||||
|
||||
::
|
||||
|
||||
[notice] User clement.oudot is authorized to access to sp-example-entityid
|
||||
[notice] SAML authentication response sent to SAML SP sp-example for clement.oudot
|
||||
[notice] User clement.oudot is redirected to https://cas.service.url
|
||||
|
||||
Access to an OIDC RP:
|
||||
Access to a CAS application whose configuration key is ``app-example``:
|
||||
|
||||
::
|
||||
|
||||
[notice] User clement.oudot is authorized to access to app-example
|
||||
|
||||
Access to an SAML SP whose configuration key is ``sp-example``:
|
||||
|
||||
::
|
||||
|
||||
[notice] User clement.oudot is authorized to access to sp-example
|
||||
|
||||
Access to an OIDC RP whose configuration key is ``rp-example``:
|
||||
|
||||
::
|
||||
|
||||
[notice] User clement.oudot is authorized to access to rp-example
|
||||
|
||||
Access to a Get application whose vhost configuration key is ``host.example.com``:
|
||||
|
||||
::
|
||||
|
||||
[notice] User clement.oudot is authorized to access to host.example.com
|
||||
|
||||
|
||||
Default loggers
|
||||
---------------
|
||||
|
||||
|
@ -152,6 +170,18 @@ You can choose facility in lemonldap-ng.ini file. Default values:
|
|||
syslogFacility = daemon
|
||||
userSyslogFacility = auth
|
||||
|
||||
You can also override options. Default values:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
syslogOptions = cons,pid,ndelay
|
||||
userSyslogOptions = cons,pid,ndelay
|
||||
|
||||
|
||||
.. tip:: You can find more information on Syslog options in
|
||||
`Sys::Syslog <https://metacpan.org/pod/Sys::Syslog>`__ Perl
|
||||
module.
|
||||
|
||||
Log4perl
|
||||
~~~~~~~~
|
||||
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
{# Support for Sphinx 1.3+ page_source_suffix, but don't break old builds. #}
|
||||
|
||||
{% if page_source_suffix %}
|
||||
{% set suffix = page_source_suffix %}
|
||||
{% else %}
|
||||
{% set suffix = source_suffix %}
|
||||
{% endif %}
|
||||
|
||||
{% if meta is defined and meta is not none %}
|
||||
{% set check_meta = True %}
|
||||
{% else %}
|
||||
{% set check_meta = False %}
|
||||
{% endif %}
|
||||
|
||||
{% if check_meta and 'github_url' in meta %}
|
||||
{% set display_github = True %}
|
||||
{% endif %}
|
||||
|
||||
{% if check_meta and 'bitbucket_url' in meta %}
|
||||
{% set display_bitbucket = True %}
|
||||
{% endif %}
|
||||
|
||||
{% if check_meta and 'gitlab_url' in meta %}
|
||||
{% set display_gitlab = True %}
|
||||
{% endif %}
|
||||
|
||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||
|
||||
<ul class="wy-breadcrumbs">
|
||||
{% block breadcrumbs %}
|
||||
<li><a href="{{ pathto(master_doc) }}">{{ _('Docs') }}</a> »</li>
|
||||
{% for doc in parents %}
|
||||
<li><a href="{{ doc.link|e }}">{{ doc.title }}</a> »</li>
|
||||
{% endfor %}
|
||||
<li>{{ title }}</li>
|
||||
{% endblock %}
|
||||
{% block breadcrumbs_aside %}
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
{% if hasdoc(pagename) %}
|
||||
{% if display_github %}
|
||||
{% if check_meta and 'github_url' in meta %}
|
||||
<!-- User defined GitHub URL -->
|
||||
<a href="{{ meta['github_url'] }}" class="fa fa-github"> {{ _('Edit on GitHub') }}</a>
|
||||
{% else %}
|
||||
<a href="https://{{ github_host|default("github.com") }}/{{ github_user }}/{{ github_repo }}/{{ theme_vcs_pageview_mode|default("blob") }}/{{ github_version }}{{ conf_py_path }}{{ pagename }}{{ suffix }}" class="fa fa-github"> {{ _('Edit on GitHub') }}</a>
|
||||
{% endif %}
|
||||
{% elif display_bitbucket %}
|
||||
{% if check_meta and 'bitbucket_url' in meta %}
|
||||
<!-- User defined Bitbucket URL -->
|
||||
<a href="{{ meta['bitbucket_url'] }}" class="fa fa-bitbucket"> {{ _('Edit on Bitbucket') }}</a>
|
||||
{% else %}
|
||||
<a href="https://bitbucket.org/{{ bitbucket_user }}/{{ bitbucket_repo }}/src/{{ bitbucket_version}}{{ conf_py_path }}{{ pagename }}{{ suffix }}?mode={{ theme_vcs_pageview_mode|default("view") }}" class="fa fa-bitbucket"> {{ _('Edit on Bitbucket') }}</a>
|
||||
{% endif %}
|
||||
{% elif display_gitlab %}
|
||||
{% if check_meta and 'gitlab_url' in meta %}
|
||||
<!-- User defined GitLab URL -->
|
||||
<a href="{{ meta['gitlab_url'] }}" class="fa fa-gitlab"> {{ _('Edit on GitLab') }}</a>
|
||||
{% else %}
|
||||
<a href="https://{{ gitlab_host|default("gitlab.com") }}/{{ gitlab_user }}/{{ gitlab_repo }}/{{ theme_vcs_pageview_mode|default("blob") }}/{{ gitlab_version }}{{ conf_py_path }}{{ pagename }}{{ suffix }}" class="fa fa-gitlab"> {{ _('Edit on GitLab') }}</a>
|
||||
{% endif %}
|
||||
{% elif show_source and source_url_prefix %}
|
||||
<a href="{{ source_url_prefix }}{{ pagename }}{{ suffix }}">{{ _('View page source') }}</a>
|
||||
{% elif show_source and has_source and sourcename %}
|
||||
<a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow"> {{ _('View page source') }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endblock %}
|
||||
</ul>
|
||||
|
||||
{% if (theme_prev_next_buttons_location == 'top' or theme_prev_next_buttons_location == 'both') and (next or prev) %}
|
||||
<div class="rst-breadcrumbs-buttons" role="navigation" aria-label="breadcrumb navigation">
|
||||
{% if next %}
|
||||
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
|
||||
{% endif %}
|
||||
{% if prev %}
|
||||
<a href="{{ prev.link|e }}" class="btn btn-neutral float-left" title="{{ prev.title|striptags|e }}" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<hr/>
|
||||
</div>
|
|
@ -1,54 +0,0 @@
|
|||
<footer>
|
||||
{% if (theme_prev_next_buttons_location == 'bottom' or theme_prev_next_buttons_location == 'both') and (next or prev) %}
|
||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||
{% if next %}
|
||||
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}" accesskey="n" rel="next">{{ _('Next') }} <span class="fa fa-arrow-circle-right"></span></a>
|
||||
{% endif %}
|
||||
{% if prev %}
|
||||
<a href="{{ prev.link|e }}" class="btn btn-neutral float-left" title="{{ prev.title|striptags|e }}" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left"></span> {{ _('Previous') }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<hr/>
|
||||
|
||||
<div role="contentinfo">
|
||||
<p>
|
||||
{%- if show_copyright %}
|
||||
{%- if hasdoc('copyright') %}
|
||||
{% trans path=pathto('copyright'), copyright=copyright|e %}© <a href="{{ path }}">Copyright</a> {{ copyright }}{% endtrans %}
|
||||
{%- else %}
|
||||
{% trans copyright=copyright|e %}© Copyright {{ copyright }}{% endtrans %}
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
|
||||
{%- if build_id and build_url %}
|
||||
{% trans build_url=build_url, build_id=build_id %}
|
||||
<span class="build">
|
||||
Build
|
||||
<a href="{{ build_url }}">{{ build_id }}</a>.
|
||||
</span>
|
||||
{% endtrans %}
|
||||
{%- elif commit %}
|
||||
{% trans commit=commit %}
|
||||
<span class="commit">
|
||||
Revision <code>{{ commit }}</code>.
|
||||
</span>
|
||||
{% endtrans %}
|
||||
{%- elif last_updated %}
|
||||
<span class="lastupdated">
|
||||
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
|
||||
</span>
|
||||
{%- endif %}
|
||||
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{%- if show_sphinx %}
|
||||
{% trans %}Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/rtfd/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>{% endtrans %}.
|
||||
{%- endif %}
|
||||
|
||||
{%- block extrafooter %} {% endblock %}
|
||||
|
||||
</footer>
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
{# TEMPLATE VAR SETTINGS #}
|
||||
{%- set url_root = pathto('', 1) %}
|
||||
{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
|
||||
{%- if not embedded and docstitle %}
|
||||
{%- set titlesuffix = " — "|safe + docstitle|e %}
|
||||
{%- else %}
|
||||
{%- set titlesuffix = "" %}
|
||||
{%- endif %}
|
||||
{%- set lang_attr = 'en' if language == None else (language | replace('_', '-')) %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="{{ lang_attr }}" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="{{ lang_attr }}" > <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
{{ metatags }}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% block htmltitle %}
|
||||
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{# JAVASCRIPTS #}
|
||||
<script type="text/javascript" src="{{ pathto('_static/js/modernizr.min.js', 1) }}"></script>
|
||||
{%- if not embedded %}
|
||||
{# XXX Sphinx 1.8.0 made this an external js-file, quick fix until we refactor the template to inherert more blocks directly from sphinx #}
|
||||
{% if sphinx_version >= "1.8.0" %}
|
||||
<script type="text/javascript" id="documentation_options" data-url_root="{{ pathto('', 1) }}" src="{{ pathto('_static/documentation_options.js', 1) }}"></script>
|
||||
{%- for scriptfile in script_files %}
|
||||
{{ js_tag(scriptfile) }}
|
||||
{%- endfor %}
|
||||
{% else %}
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'{{ url_root }}',
|
||||
VERSION:'{{ release|e }}',
|
||||
LANGUAGE:'{{ language }}',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'{{ '' if no_search_suffix else file_suffix }}',
|
||||
HAS_SOURCE: {{ has_source|lower }},
|
||||
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
|
||||
};
|
||||
</script>
|
||||
{%- for scriptfile in script_files %}
|
||||
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
|
||||
{%- endfor %}
|
||||
{% endif %}
|
||||
<script type="text/javascript" src="{{ pathto('_static/js/theme.js', 1) }}"></script>
|
||||
{%- endif %}
|
||||
|
||||
{# CSS #}
|
||||
<link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
|
||||
{%- for css in css_files %}
|
||||
{%- if css|attr("rel") %}
|
||||
<link rel="{{ css.rel }}" href="{{ pathto(css.filename, 1) }}" type="text/css"{% if css.title is not none %} title="{{ css.title }}"{% endif %} />
|
||||
{%- else %}
|
||||
<link rel="stylesheet" href="{{ pathto(css, 1) }}" type="text/css" />
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
{%- for cssfile in extra_css_files %}
|
||||
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||
{%- endfor %}
|
||||
|
||||
{%- block linktags %}
|
||||
{%- if hasdoc('about') %}
|
||||
<link rel="author" title="{{ _('About these documents') }}" href="{{ pathto('about') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('genindex') %}
|
||||
<link rel="index" title="{{ _('Index') }}" href="{{ pathto('genindex') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('search') %}
|
||||
<link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('copyright') %}
|
||||
<link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
|
||||
{%- endif %}
|
||||
{%- if next %}
|
||||
<link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}" />
|
||||
{%- endif %}
|
||||
{%- if prev %}
|
||||
<link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}" />
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- block extrahead %} {% endblock %}
|
||||
</head>
|
||||
|
||||
<body class="wy-body-for-nav">
|
||||
|
||||
<div class="wy-nav-content">
|
||||
{%- block content %}
|
||||
<div class="rst-content">
|
||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||
{%- block document %}
|
||||
<div itemprop="articleBody">
|
||||
{% block body %}{% endblock %}
|
||||
</div>
|
||||
{% if self.comments()|trim %}
|
||||
<div class="articleComments">
|
||||
{% block comments %}{% endblock %}
|
||||
</div>
|
||||
{% endif%}
|
||||
</div>
|
||||
{%- endblock %}
|
||||
{% include "footer.html" %}
|
||||
</div>
|
||||
{%- endblock %}
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,50 +0,0 @@
|
|||
{#
|
||||
basic/search.html
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Template for the search page.
|
||||
|
||||
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{%- extends "layout.html" %}
|
||||
{% set title = _('Search') %}
|
||||
{% set script_files = script_files + ['_static/searchtools.js'] %}
|
||||
{% block footer %}
|
||||
<script type="text/javascript">
|
||||
jQuery(function() { Search.loadIndex("{{ pathto('searchindex.js', 1) }}"); });
|
||||
</script>
|
||||
{# this is used when loading the search index using $.ajax fails,
|
||||
such as on Chrome for documents on localhost #}
|
||||
<script type="text/javascript" id="searchindexloader"></script>
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<noscript>
|
||||
<div id="fallback" class="admonition warning">
|
||||
<p class="last">
|
||||
{% trans %}Please activate JavaScript to enable the search
|
||||
functionality.{% endtrans %}
|
||||
</p>
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
{% if search_performed %}
|
||||
<h2>{{ _('Search Results') }}</h2>
|
||||
{% if not search_results %}
|
||||
<p>{{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div id="search-results">
|
||||
{% if search_results %}
|
||||
<ul>
|
||||
{% for href, caption, context in search_results %}
|
||||
<li>
|
||||
<a href="{{ pathto(item.href) }}">{{ caption }}</a>
|
||||
<p class="context">{{ context|e }}</p>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,9 +0,0 @@
|
|||
{%- if builder != 'singlehtml' %}
|
||||
<div role="search">
|
||||
<form id="rtd-search-form" class="wy-form" action="{{ pathto('search') }}" method="get">
|
||||
<input type="text" name="q" placeholder="{{ _('Search docs') }}" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
</div>
|
||||
{%- endif %}
|
|
@ -1,2 +0,0 @@
|
|||
[theme]
|
||||
inherit = sphinx_rtd_theme
|
|
@ -1,37 +0,0 @@
|
|||
{% if READTHEDOCS %}
|
||||
{# Add rst-badge after rst-versions for small badge style. #}
|
||||
<div class="rst-versions" data-toggle="rst-versions" role="note" aria-label="versions">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
<span class="fa fa-book"> Read the Docs</span>
|
||||
v: {{ current_version }}
|
||||
<span class="fa fa-caret-down"></span>
|
||||
</span>
|
||||
<div class="rst-other-versions">
|
||||
<dl>
|
||||
<dt>{{ _('Versions') }}</dt>
|
||||
{% for slug, url in versions %}
|
||||
<dd><a href="{{ url }}">{{ slug }}</a></dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ _('Downloads') }}</dt>
|
||||
{% for type, url in downloads %}
|
||||
<dd><a href="{{ url }}">{{ type }}</a></dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ _('On Read the Docs') }}</dt>
|
||||
<dd>
|
||||
<a href="//{{ PRODUCTION_DOMAIN }}/projects/{{ slug }}/?fromdocs={{ slug }}">{{ _('Project Home') }}</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="//{{ PRODUCTION_DOMAIN }}/builds/{{ slug }}/?fromdocs={{ slug }}">{{ _('Builds') }}</a>
|
||||
</dd>
|
||||
</dl>
|
||||
<hr/>
|
||||
{% trans %}Free document hosting provided by <a href="http://www.readthedocs.org">Read the Docs</a>.{% endtrans %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
@ -15,23 +15,23 @@ Perl module.
|
|||
In the manager: set
|
||||
`Apache::Session::Browseable::Redis <https://metacpan.org/pod/Apache::Session::Browseable::Redis>`__
|
||||
in ``General parameters`` » ``Sessions`` » ``Session storage`` »
|
||||
``Apache::Session module`` and add the following parameters (case
|
||||
sensitive):
|
||||
``Apache::Session module`` and add the connection parameters for your Redis server(s).
|
||||
|
||||
Parameters:
|
||||
This backend uses the perl bindings for Redis database provided by the `Redis perl module <https://metacpan.org/pod/Redis>`__.
|
||||
A complete list of supported constructor/connection options can be found in the `module documentation <https://metacpan.org/pod/Redis>`__.
|
||||
|
||||
============= ==================== ===============================================
|
||||
Name Comment Example
|
||||
============= ==================== ===============================================
|
||||
**server** Redis server 127.0.0.1:6379
|
||||
**sentinels** Redis sentinels list 127.0.0.1:26379,127.0.0.2:26379,127.0.0.3:26379
|
||||
============= ==================== ===============================================
|
||||
E.g., Parameters (case sensitive):
|
||||
|
||||
You can specify either a single Redis server or a list of Sentinel hosts
|
||||
using the \*sentinels\* module parameter
|
||||
============= =========================== ===============================================
|
||||
Name Comment Example
|
||||
============= =========================== ===============================================
|
||||
**server** Redis server @ IP:PORT 127.0.0.1:6379
|
||||
**sock** Redis server @ unix socket unix:/path/to/redis.sock
|
||||
**sentinels** Redis sentinels list 127.0.0.1:26379,127.0.0.2:26379,127.0.0.3:26379
|
||||
**password** password (== requirepass) ChangeMe
|
||||
**select** Redis DB 1
|
||||
============= =========================== ===============================================
|
||||
|
||||
You can find the complete list of supported options on the `Redis perl module
|
||||
documentation <https://metacpan.org/pod/Redis#new>`__.
|
||||
|
||||
Security
|
||||
--------
|
||||
|
|
|
@ -620,12 +620,11 @@ Configuration backend parameters
|
|||
Full name Key name Configuration backend
|
||||
============================================================================= ==================== ===========================================================
|
||||
Configuration load timeout confTimeout all backends (default: 10)
|
||||
Directory dirName :doc:`File<fileconfbackend>`
|
||||
DBI connection string dbiChain :doc:`CDBI / RDBI<sqlconfbackend>`
|
||||
DBI user dbiUser
|
||||
DBI password dbiPassword
|
||||
DBI table name dbiTable
|
||||
Storage directory dirName :doc:`File<fileconfbackend>` / :doc:`YAML<yamlconfbackend>`
|
||||
Directory dirName :doc:`File<fileconfbackend>` / :doc:`YAML<yamlconfbackend>`
|
||||
LDAP server ldapServer :doc:`LDAP<ldapconfbackend>`
|
||||
LDAP port ldapPort
|
||||
LDAP base ldapConfBase
|
||||
|
@ -638,6 +637,7 @@ Certificate authorities file ca
|
|||
Certificate authorities directory caPath
|
||||
MongoDB database dbName :doc:`MongoDB<mongodbconfbackend>`
|
||||
MongoDB collection collectionName
|
||||
Pretty print prettyPrint :doc:`File<fileconfbackend>`
|
||||
REST base URL baseUrl :doc:`REST<restconfbackend>`
|
||||
REST realm realm
|
||||
REST user user
|
||||
|
|
|
@ -128,7 +128,7 @@ Then adapt your Nginx configuration to use this uWSGI app.
|
|||
Configuration
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
To serve large requests with uWsgi, you could have to modify in uWsgi
|
||||
To serve large requests with uWSGI, you could have to modify in uWSGI
|
||||
and/or Nginx init files several options. Example:
|
||||
|
||||
.. code-block:: ini
|
||||
|
@ -146,6 +146,31 @@ and/or Nginx init files several options. Example:
|
|||
uwsgi_read_timeout 120;
|
||||
uwsgi_send_timeout 120;
|
||||
|
||||
.. note::
|
||||
Nginx natively includes support for upstream servers speaking the uwsgi protocol since version 0.8.40.
|
||||
To improve performances, you can switch from a TCP socket to an Unix Domain Socket by editing
|
||||
``llng-server.yaml``:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
uwsgi:
|
||||
plugins: psgi
|
||||
socket: /tmp/uwsgi.sock
|
||||
|
||||
and adapting Nignx configuration files:
|
||||
|
||||
.. code-block:: nginx
|
||||
|
||||
# OR TO USE uWSGI
|
||||
include /etc/nginx/uwsgi_params;
|
||||
uwsgi_pass unix:///tmp/uwsgi.sock;
|
||||
uwsgi_param LLTYPE psgi;
|
||||
uwsgi_param SCRIPT_FILENAME $document_root$sc;
|
||||
uwsgi_param SCRIPT_NAME $sc;
|
||||
# Uncomment this if you use Auth SSL:
|
||||
#uwsgi_param SSL_CLIENT_S_DN_CN $ssl_client_s_dn_cn;
|
||||
|
||||
|
||||
Protect a PSGI application
|
||||
--------------------------
|
||||
|
||||
|
|
|
@ -7,22 +7,15 @@ Quick start tutorial
|
|||
This tutorial will guide you into a minimal
|
||||
installation and configuration procedure. You need some prerequisites:
|
||||
|
||||
- A computer with a GNU/Linux recent distribution (Debian, Ubuntu,
|
||||
CentOS, RHEL, ...) with root privileges
|
||||
- A web browser
|
||||
- The possibility to update your local ``hosts`` file, or an easy
|
||||
access to your DNS server
|
||||
- A cup of coffee (or tea, we are open minded)
|
||||
- Root access to a Debian, Ubuntu, CentOS or RHEL test system
|
||||
- A web browser
|
||||
- A cup of coffee (or tea, we are open minded)
|
||||
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
You should install Lemonldap::NG using packages, but you can also
|
||||
install it from
|
||||
:doc:`the tarball<installtarball>`.
|
||||
|
||||
Debian / Ubuntu
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -40,27 +33,38 @@ CentOS / RHEL
|
|||
::
|
||||
|
||||
curl https://lemonldap-ng.org/_media/rpm-gpg-key-ow2 > /etc/pki/rpm-gpg/RPM-GPG-KEY-OW2
|
||||
echo "[lemonldap-ng]
|
||||
echo '[lemonldap-ng]
|
||||
name=LemonLDAP::NG packages
|
||||
baseurl=https://lemonldap-ng.org/redhat/stable/$releasever/noarch
|
||||
enabled=1
|
||||
gpgcheck=1
|
||||
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OW2" > /etc/yum.repos.d/lemonldap-ng.repo
|
||||
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OW2' > /etc/yum.repos.d/lemonldap-ng.repo
|
||||
yum update
|
||||
yum install epel-release
|
||||
yum install lemonldap-ng
|
||||
|
||||
SSO domain configuration
|
||||
------------------------
|
||||
|
||||
LemonLDAP::NG needs all its components to be served on the same DNS domain.
|
||||
|
||||
If you can edit your `/etc/hosts` file or have access to a DNS server, check :ref:`quickstart_own_domain`, if you have no way to modify your DNS configuration, check :ref:`quickstart_nipio`.
|
||||
|
||||
.. _quickstart_own_domain:
|
||||
|
||||
Using your own domain
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The defaut SSO domain is ``example.com``. You can keep it for your tests
|
||||
or change it, for example for ``mydomain.com``:
|
||||
|
||||
::
|
||||
|
||||
sed -i 's/example\.com/mydomain.com/g' /etc/lemonldap-ng/* /var/lib/lemonldap-ng/conf/lmConf-1.json
|
||||
sed -i 's/example\.com/mydomain.com/g' /etc/nginx/conf.d/*
|
||||
sed -i 's/example\.com/mydomain.com/g' /etc/httpd/conf.d/*
|
||||
sed -i 's/example\.com/mydomain.com/g' /etc/apache2/sites-available/*
|
||||
sed -i 's/example\.com/mydomain.com/g' \
|
||||
/etc/lemonldap-ng/* /var/lib/lemonldap-ng/conf/lmConf-1.json \
|
||||
/etc/nginx/conf.d/* \
|
||||
/etc/httpd/conf.d/* \
|
||||
/etc/apache2/sites-available/*
|
||||
|
||||
In order to be able to test, update your DNS or your local ``hosts``
|
||||
file to map this names to the SSO server IP:
|
||||
|
@ -70,20 +74,63 @@ file to map this names to the SSO server IP:
|
|||
- test1.mydomain.com
|
||||
- test2.mydomain.com
|
||||
|
||||
For example on your local computer:
|
||||
For example on your local computer (adjust your server IP and test domain)
|
||||
|
||||
::
|
||||
|
||||
echo "192.168.1.30 auth.mydomain.com manager.mydomain.com test1.mydomain.com test2.mydomain.com" >> /etc/hosts
|
||||
|
||||
.. _quickstart_nipio:
|
||||
|
||||
Using nip.io (or other DNS wildcard services)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you cannot edit /etc/hosts or your DNS zone, don't give up yet, you can use services such as http://nip.io, http://xip.io, https://sslip.io/, or others.
|
||||
|
||||
For example, if your server IP is 192.168.12.13, you can use 192-168-12-13.nip.io as your SSO domain:
|
||||
|
||||
::
|
||||
|
||||
sed -i 's/example\.com/192-168-12-13.nip.io/g' \
|
||||
/etc/lemonldap-ng/* /var/lib/lemonldap-ng/conf/lmConf-1.json \
|
||||
/etc/nginx/conf.d/* \
|
||||
/etc/httpd/conf.d/* \
|
||||
/etc/apache2/sites-available/*
|
||||
|
||||
.. warning::
|
||||
|
||||
nip.io, xip.io or any DNS wildcard services mentionned in this section are not affiliated with the LemonLDAP::NG project in any way. These services will receive DNS requests that will allow them to know your test server's IP address. If this is an issue for you, do not use these services.
|
||||
|
||||
Run
|
||||
---
|
||||
|
||||
Since LemonLDAP::NG 1.2, the
|
||||
:doc:`demonstration backend<authdemo>` is
|
||||
configured by default.
|
||||
Starting services
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Demonstration backend has hard coded user accounts:
|
||||
Debian / Ubuntu
|
||||
'''''''''''''''
|
||||
|
||||
Enable the Nginx virtualhosts and restart the web server and LemonLDAP::NG server to apply the configuration changes ::
|
||||
|
||||
cd /etc/nginx/sites-enabled
|
||||
ln -s ../sites-available/*nginx* .
|
||||
systemctl restart lemonldap-ng-fastcgi-server
|
||||
systemctl restart nginx
|
||||
|
||||
CentOS / RHEL
|
||||
'''''''''''''
|
||||
|
||||
Enable and start httpd ::
|
||||
|
||||
systemctl enable httpd
|
||||
systemctl start httpd
|
||||
|
||||
|
||||
Open SSO session
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Go on http://auth.mydomain.com and log with one of the demonstration
|
||||
account.
|
||||
|
||||
====== ======== =============
|
||||
Login Password Role
|
||||
|
@ -93,12 +140,6 @@ msmith msmith user
|
|||
dwho dwho administrator
|
||||
====== ======== =============
|
||||
|
||||
Open SSO session
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Go on http://auth.mydomain.com and log with one of the demonstration
|
||||
account.
|
||||
|
||||
Access protected application
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@ Disk cache (sessions an configuration)
|
|||
|
||||
::
|
||||
|
||||
chcon -R -t httpd_sys_rw_content_t /tmp
|
||||
chcon -R -t httpd_sys_rw_content_t /var/cache/lemonldap-ng
|
||||
|
||||
To persist the rule:
|
||||
|
||||
::
|
||||
|
||||
semanage fcontext -a -t http_sys_content_t /tmp
|
||||
semanage fcontext -a -t http_sys_content_t /var/cache/lemonldap-ng
|
||||
|
||||
LDAP
|
||||
----
|
||||
|
|
|
@ -29,13 +29,17 @@ To edit SSO cookie parameters, go in Manager, ``General Parameters`` >
|
|||
only one session is created in session database
|
||||
|
||||
- **Javascript protection**: set httpOnly flag, to prevent cookie from
|
||||
being caught by javascript code
|
||||
being leaked by malicious javascript code
|
||||
- **Cookie expiration time**: by default, SSO cookie is a session
|
||||
cookie, which means it will be destroyed when browser is closed. You
|
||||
can change this behavior by setting a cookie expiration time. It must
|
||||
be an integer. **Cookie Expiration Time** value is a number of
|
||||
seconds until the cookie expires. Set a zero value to disable
|
||||
expiration time and use a session cookie.
|
||||
- **Cookie SameSite value**: the value of the SameSite cookie attribute. By
|
||||
default, LemonLDAP::NG will set it to "Lax" in most cases, and "None" if you
|
||||
use SAML. Using "None" requres Secured Cookies, and accessing applications
|
||||
over HTTPS on most web browsers.
|
||||
|
||||
|
||||
.. danger::
|
||||
|
|
|
@ -22,6 +22,20 @@ backups and a rollback plan ready!
|
|||
|
||||
- | Bad default value to display OIDC Consents tab has been fixed.
|
||||
| The default value is ``$_oidcConsents``
|
||||
- Some user log messages have been modified, check :doc:`logs documentation <logs>`
|
||||
(see also `#2244 <https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues/2244>`__)
|
||||
- SAML SOAP calls are now using ``text/xml`` instead of ``application/xml`` as the MIME Content Type, as required by `the SOAP standard <https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383526>`__
|
||||
- The default config/session cache directory has been moved from ``/tmp`` to
|
||||
``/var/cache/lemonldap-ng`` in order to avoid `issues with cache purges
|
||||
<https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/-/issues/2254>`__ when
|
||||
using Systemd. This change is only applied to new installations. If your
|
||||
installation is experiencing cache purge issues, you
|
||||
need to manually change your existing
|
||||
``localSessionStorageOptions/cache_root`` parameter from ``/tmp`` to
|
||||
``/var/cache/lemonldap-ng``.
|
||||
- This release fixes several issues when using ``SameSite=None``. The new
|
||||
default value of the SameSite configuration parameter will set SameSite to
|
||||
``Lax`` unless you are using SAML, which requires ``None``
|
||||
|
||||
2.0.8
|
||||
-----
|
||||
|
|
|
@ -36,6 +36,8 @@ In the manager (second factors), you just have to enable it:
|
|||
what you are doing
|
||||
- **Allow users to remove Yubikey**: If enabled, users can unregister
|
||||
Yubikey device.
|
||||
- **Get Yubikey ID from session attribute**: If non-empty, the Yubikey ID will
|
||||
be read from this session attribute. This allows external provisionning of Yubikeys.
|
||||
- **Lifetime**: Unlimited by default. Set a Time To Live in seconds.
|
||||
TTL is checked at each login process if set. If TTL is expired,
|
||||
relative Yubikey is removed.
|
||||
|
|
|
@ -2,7 +2,7 @@ openapi: 3.0.1
|
|||
info:
|
||||
title: LemonLDAP::NG Manager API
|
||||
description: The Manager API allows an administrator to modify the LemonLDAP::NG configuration programmatically. It is not meant to be accessed by end users. The client libraries mentionned in examples can be generated from doc/sources/manager-api/openapi-spec.yaml
|
||||
version: 2.0.8
|
||||
version: 2.0.9
|
||||
servers:
|
||||
- url: /api/v1
|
||||
tags:
|
||||
|
@ -14,6 +14,16 @@ tags:
|
|||
description: Registered Second Factors
|
||||
|
||||
paths:
|
||||
/api/v1/status:
|
||||
get:
|
||||
summary: Check the status of the API
|
||||
operationId: status
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/StatusResponse'
|
||||
503:
|
||||
$ref: '#/components/responses/StatusResponse'
|
||||
|
||||
/api/v1/providers/saml/sp:
|
||||
post:
|
||||
tags:
|
||||
|
@ -348,6 +358,174 @@ paths:
|
|||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/api/v1/providers/cas/app:
|
||||
post:
|
||||
tags:
|
||||
- casapp
|
||||
summary: Create a new CAS Application
|
||||
operationId: addcasapp
|
||||
requestBody:
|
||||
description: CAS Application to add
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CasApp'
|
||||
required: true
|
||||
responses:
|
||||
201:
|
||||
$ref: '#/components/responses/Created'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
409:
|
||||
$ref: '#/components/responses/Conflict'
|
||||
|
||||
/api/v1/providers/cas/app/findByConfKey:
|
||||
get:
|
||||
tags:
|
||||
- casapp
|
||||
summary: Finds CAS applications by configuration key
|
||||
description: Takes a search pattern to be tested against existing applications
|
||||
operationId: findCasAppByConfKey
|
||||
parameters:
|
||||
- name: pattern
|
||||
in: query
|
||||
description: Search pattern
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
examples:
|
||||
any:
|
||||
summary: Any value
|
||||
value: "*"
|
||||
prefix:
|
||||
summary: Given prefix
|
||||
value: "zone1-*"
|
||||
anywhere:
|
||||
summary: Substring
|
||||
value: "something"
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/ManyCasApp'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
|
||||
/api/v1/providers/cas/app/findByServiceUrl:
|
||||
get:
|
||||
tags:
|
||||
- casapp
|
||||
summary: Get CAS Application by Service URL
|
||||
operationId: findCasAppByServiceUrl
|
||||
parameters:
|
||||
- name: serviceUrl
|
||||
in: query
|
||||
description: Service URL to search
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
example: http://mycasapp.example.com/
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/OneCasApp'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/api/v1/providers/cas/app/{confKey}:
|
||||
get:
|
||||
tags:
|
||||
- casapp
|
||||
summary: Get CAS Application by configuration key
|
||||
description: Returns a single Application
|
||||
operationId: getCasAppByConfKey
|
||||
parameters:
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of CAS Application
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/OneCasApp'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
put:
|
||||
tags:
|
||||
- casapp
|
||||
summary: Replaces a CAS Application
|
||||
operationId: replaceCasApp
|
||||
parameters:
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of CAS Application that needs to be replaced
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CasApp'
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/NoContent'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
409:
|
||||
$ref: '#/components/responses/Conflict'
|
||||
patch:
|
||||
tags:
|
||||
- casapp
|
||||
summary: Updates a CAS Application.
|
||||
operationId: updateCasApp
|
||||
parameters:
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of CAS Application that needs to be updated
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CasAppUpdate'
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/NoContent'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
409:
|
||||
$ref: '#/components/responses/Conflict'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- casapp
|
||||
summary: Deletes a CAS Application
|
||||
operationId: deleteCasApp
|
||||
parameters:
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of CAS Application to delete
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/NoContent'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
'/api/v1/secondFactor/{uid}':
|
||||
description: Second factors for a particular user
|
||||
parameters:
|
||||
|
@ -380,7 +558,6 @@ paths:
|
|||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
|
||||
'/api/v1/secondFactor/{uid}/type/{type}':
|
||||
description: Second factors of a given type for a particular user
|
||||
parameters:
|
||||
|
@ -406,7 +583,6 @@ paths:
|
|||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
|
||||
delete:
|
||||
summary: Delete all second factors of a given type for a user
|
||||
description: ''
|
||||
|
@ -419,7 +595,6 @@ paths:
|
|||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
|
||||
'/api/v1/secondFactor/{uid}/id/{id}':
|
||||
description: Second factors of a given id for a particular user
|
||||
parameters:
|
||||
|
@ -445,7 +620,6 @@ paths:
|
|||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
|
||||
delete:
|
||||
summary: Delete a second factors for a user
|
||||
description: ''
|
||||
|
@ -458,9 +632,394 @@ paths:
|
|||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/api/v1/menu/cat:
|
||||
post:
|
||||
tags:
|
||||
- menucat
|
||||
summary: Create a new Menu Category
|
||||
operationId: addMenuCat
|
||||
requestBody:
|
||||
description: Menu Category to add
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MenuCat'
|
||||
required: true
|
||||
responses:
|
||||
201:
|
||||
$ref: '#/components/responses/Created'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
409:
|
||||
$ref: '#/components/responses/Conflict'
|
||||
|
||||
/api/v1/menu/cat/findByConfKey:
|
||||
get:
|
||||
tags:
|
||||
- menucat
|
||||
summary: Finds Menu Categories by configuration key
|
||||
description: Takes a search pattern to be tested against existing categories
|
||||
operationId: findMenuCatByConfKey
|
||||
parameters:
|
||||
- name: pattern
|
||||
in: query
|
||||
description: Search pattern
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
examples:
|
||||
any:
|
||||
summary: Any value
|
||||
value: "*"
|
||||
prefix:
|
||||
summary: Given prefix
|
||||
value: "zone1-*"
|
||||
anywhere:
|
||||
summary: Substring
|
||||
value: "something"
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/ManyMenuCat'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
|
||||
/api/v1/menu/cat/{confKey}:
|
||||
get:
|
||||
tags:
|
||||
- menucat
|
||||
summary: Get Menu Category by configuration key
|
||||
description: Returns a single Category
|
||||
operationId: getMenuCatByConfKey
|
||||
parameters:
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of Menu Category
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/OneMenuCat'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
put:
|
||||
tags:
|
||||
- menucat
|
||||
summary: Replaces a Menu Category
|
||||
operationId: replaceMenuCat
|
||||
parameters:
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of Menu Category that needs to be replaced
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MenuCat'
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/NoContent'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
409:
|
||||
$ref: '#/components/responses/Conflict'
|
||||
patch:
|
||||
tags:
|
||||
- menucat
|
||||
summary: Updates a Menu Category
|
||||
operationId: updateMenuCat
|
||||
parameters:
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of Menu Category that needs to be updated
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MenuCatUpdate'
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/NoContent'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
409:
|
||||
$ref: '#/components/responses/Conflict'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- menucat
|
||||
summary: Deletes a Menu Category
|
||||
operationId: deleteMenuCat
|
||||
parameters:
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of Menu Category to delete
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/NoContent'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/api/v1/menu/app/{cat}:
|
||||
get:
|
||||
tags:
|
||||
- menuapp
|
||||
summary: Get Menu Applications within a Menu Category
|
||||
description: Return existing applications within a menu category
|
||||
operationId: getMenuApps
|
||||
parameters:
|
||||
- name: cat
|
||||
in: path
|
||||
description: Configuration key of Menu Category to work with
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/menuCatConfKey'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/ManyMenuApp'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
post:
|
||||
tags:
|
||||
- menuapp
|
||||
summary: Create a new Menu Application within a Menu Category
|
||||
operationId: addMenuApp
|
||||
parameters:
|
||||
- name: cat
|
||||
in: path
|
||||
description: Configuration key of Menu Category to work with
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/menuCatConfKey'
|
||||
requestBody:
|
||||
description: Menu Application to add
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MenuApp'
|
||||
required: true
|
||||
responses:
|
||||
201:
|
||||
$ref: '#/components/responses/Created'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
409:
|
||||
$ref: '#/components/responses/Conflict'
|
||||
|
||||
/api/v1/menu/app/{cat}/findByConfKey:
|
||||
get:
|
||||
tags:
|
||||
- menuapp
|
||||
summary: Finds Menu Applications by configuration key within a Menu Category
|
||||
description: Takes a search pattern to be tested against existing applications within a menu category
|
||||
operationId: findMenuAppByConfKey
|
||||
parameters:
|
||||
- name: cat
|
||||
in: path
|
||||
description: Configuration key of Menu Category to work with
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/menuCatConfKey'
|
||||
- name: pattern
|
||||
in: query
|
||||
description: Search pattern
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
examples:
|
||||
any:
|
||||
summary: Any value
|
||||
value: "*"
|
||||
prefix:
|
||||
summary: Given prefix
|
||||
value: "zone1-*"
|
||||
anywhere:
|
||||
summary: Substring
|
||||
value: "something"
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/ManyMenuApp'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
|
||||
/api/v1/menu/app/{cat}/{confKey}:
|
||||
get:
|
||||
tags:
|
||||
- menuapp
|
||||
summary: Get Menu Application within a Menu Category by configuration key
|
||||
description: Returns a single application
|
||||
operationId: getMenuAppByConfKey
|
||||
parameters:
|
||||
- name: cat
|
||||
in: path
|
||||
description: Configuration key of Menu Category to work with
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/menuCatConfKey'
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of Menu Application
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/OneMenuApp'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
put:
|
||||
tags:
|
||||
- menuapp
|
||||
summary: Replaces a Menu Application
|
||||
operationId: replaceMenuApp
|
||||
parameters:
|
||||
- name: cat
|
||||
in: path
|
||||
description: Configuration key of Menu Category to work with
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/menuCatConfKey'
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of Menu Application that needs to be replaced
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MenuApp'
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/NoContent'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
409:
|
||||
$ref: '#/components/responses/Conflict'
|
||||
patch:
|
||||
tags:
|
||||
- menuapp
|
||||
summary: Updates a Menu Application
|
||||
operationId: updateMenuApp
|
||||
parameters:
|
||||
- name: cat
|
||||
in: path
|
||||
description: Configuration key of Menu Category to work with
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/menuCatConfKey'
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of Menu Application that needs to be updated
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MenuAppUpdate'
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/NoContent'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
409:
|
||||
$ref: '#/components/responses/Conflict'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- menuapp
|
||||
summary: Deletes a Menu Application
|
||||
operationId: deleteMenuApp
|
||||
parameters:
|
||||
- name: cat
|
||||
in: path
|
||||
description: Configuration key of Menu Category to work with
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/menuCatConfKey'
|
||||
- name: confKey
|
||||
in: path
|
||||
description: Configuration key of Menu Application to delete
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/NoContent'
|
||||
400:
|
||||
$ref: '#/components/responses/Error'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Status:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Descriptive name of the software
|
||||
version:
|
||||
type: string
|
||||
description: Version of the LemonLDAP::NG software
|
||||
status_sessions:
|
||||
type: string
|
||||
description: Status of the sessions database
|
||||
enum:
|
||||
- ok
|
||||
- ko
|
||||
- unknown
|
||||
status_psessions:
|
||||
type: string
|
||||
description: Status of the psessions database
|
||||
enum:
|
||||
- ok
|
||||
- ko
|
||||
- unknown
|
||||
status_config:
|
||||
type: string
|
||||
description: Status of the configuration database
|
||||
enum:
|
||||
- ok
|
||||
- ko
|
||||
status:
|
||||
type: string
|
||||
description: Global status
|
||||
enum:
|
||||
- ok
|
||||
- ko
|
||||
confKey:
|
||||
type: string
|
||||
pattern: '^\w[\w\.\-]*$'
|
||||
|
@ -490,7 +1049,6 @@ components:
|
|||
type: object
|
||||
example:
|
||||
myMacroName: "$macro(rule)"
|
||||
|
||||
options:
|
||||
$ref: '#/components/schemas/samlOptions'
|
||||
SamlSpUpdate:
|
||||
|
@ -498,7 +1056,6 @@ components:
|
|||
properties:
|
||||
metadata:
|
||||
type: string
|
||||
|
||||
example: '<?xml version="1.0"?><EntityDescriptor...'
|
||||
macros:
|
||||
type: object
|
||||
|
@ -565,10 +1122,11 @@ components:
|
|||
- persistent
|
||||
- transient
|
||||
- encrypted
|
||||
|
||||
samlAttribute:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
mandatory:
|
||||
type: boolean
|
||||
friendlyName:
|
||||
|
@ -576,6 +1134,7 @@ components:
|
|||
format:
|
||||
type: string
|
||||
example: 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic'
|
||||
|
||||
OidcRp:
|
||||
required:
|
||||
- confKey
|
||||
|
@ -673,7 +1232,6 @@ components:
|
|||
type: string
|
||||
userIDAttr:
|
||||
type: string
|
||||
|
||||
OidcRpUpdate:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -696,6 +1254,54 @@ components:
|
|||
options:
|
||||
$ref: '#/components/schemas/OidcOptions'
|
||||
|
||||
CasApp:
|
||||
required:
|
||||
- confKey
|
||||
type: object
|
||||
properties:
|
||||
confKey:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
exportedVars:
|
||||
type: object
|
||||
default:
|
||||
cn: cn
|
||||
mail: mail
|
||||
uid: uid
|
||||
macros:
|
||||
type: object
|
||||
example:
|
||||
myMacroName: "$macro(rule)"
|
||||
options:
|
||||
$ref: '#/components/schemas/casOptions'
|
||||
CasAppUpdate:
|
||||
type: object
|
||||
properties:
|
||||
macros:
|
||||
type: object
|
||||
example:
|
||||
myMacroName: "$macro(rule)"
|
||||
exportedVars:
|
||||
type: object
|
||||
default:
|
||||
cn: cn
|
||||
mail: mail
|
||||
uid: uid
|
||||
options:
|
||||
$ref: '#/components/schemas/casOptions'
|
||||
casOptions:
|
||||
required:
|
||||
- service
|
||||
type: object
|
||||
properties:
|
||||
service:
|
||||
type: string
|
||||
userAttribute:
|
||||
type: string
|
||||
default: none
|
||||
rule:
|
||||
type: string
|
||||
default: none
|
||||
|
||||
SecondFactor:
|
||||
type: object
|
||||
required:
|
||||
|
@ -717,8 +1323,97 @@ components:
|
|||
items:
|
||||
$ref: "#/components/schemas/SecondFactor"
|
||||
|
||||
menuCatConfKey:
|
||||
type: string
|
||||
pattern: '^\w[\w\.\-]*$'
|
||||
MenuCat:
|
||||
required:
|
||||
- confKey
|
||||
- catname
|
||||
type: object
|
||||
properties:
|
||||
confKey:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
catname:
|
||||
type: string
|
||||
order:
|
||||
type: integer
|
||||
MenuCatUpdate:
|
||||
type: object
|
||||
properties:
|
||||
catname:
|
||||
type: string
|
||||
order:
|
||||
type: integer
|
||||
MenuApp:
|
||||
required:
|
||||
- confKey
|
||||
type: object
|
||||
properties:
|
||||
confKey:
|
||||
$ref: '#/components/schemas/confKey'
|
||||
order:
|
||||
type: integer
|
||||
options:
|
||||
$ref: '#/components/schemas/MenuAppOptions'
|
||||
MenuAppOptions:
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
tooltip:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
logo:
|
||||
type: string
|
||||
default: network.png
|
||||
enum:
|
||||
- attach.png
|
||||
- bell.png
|
||||
- bookmark.png
|
||||
- configure.png
|
||||
- database.png
|
||||
- demo.png
|
||||
- folder.png
|
||||
- gear.png
|
||||
- help.png
|
||||
- llng.png
|
||||
- mailappt.png
|
||||
- money.png
|
||||
- network.png
|
||||
- terminal.png
|
||||
- thumbnail.png
|
||||
- tux.png
|
||||
- web.png
|
||||
- (Any reference to an available image in app logo folder)
|
||||
display:
|
||||
type: string
|
||||
default: auto
|
||||
enum:
|
||||
- 'on'
|
||||
- 'off'
|
||||
- auto
|
||||
- (Any special rule to apply for example "$uid eq 'dwho'")
|
||||
MenuAppUpdate:
|
||||
type: object
|
||||
properties:
|
||||
order:
|
||||
type: integer
|
||||
options:
|
||||
$ref: '#/components/schemas/MenuAppOptions'
|
||||
|
||||
responses:
|
||||
StatusResponse:
|
||||
description: Response to API health check
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Status'
|
||||
NoContent:
|
||||
description: Successful modification
|
||||
Created:
|
||||
|
@ -735,6 +1430,12 @@ components:
|
|||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SamlSp'
|
||||
OneCasApp:
|
||||
description: Return a CAS Provider
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CasApp'
|
||||
ManyOidcRp:
|
||||
description: Return a list of OpenID Connect Providers
|
||||
content:
|
||||
|
@ -751,6 +1452,14 @@ components:
|
|||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/SamlSp'
|
||||
ManyCasApp:
|
||||
description: Return a list of CAS Providers
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/CasApp'
|
||||
NotFound:
|
||||
description: The specified resource was not found
|
||||
content:
|
||||
|
@ -781,5 +1490,31 @@ components:
|
|||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/SecondFactors"
|
||||
|
||||
|
||||
OneMenuCat:
|
||||
description: Return a Menu Category
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MenuCat'
|
||||
ManyMenuCat:
|
||||
description: Return a list of Menu Categories
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/MenuCat'
|
||||
OneMenuApp:
|
||||
description: Return a Menu Application
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MenuApp'
|
||||
ManyMenuApp:
|
||||
description: Return a list of Menu Applications
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/MenuApp'
|
||||
|
|
|
@ -66,6 +66,7 @@ lib/Lemonldap/NG/Common/Session.pm
|
|||
lib/Lemonldap/NG/Common/Session/REST.pm
|
||||
lib/Lemonldap/NG/Common/TOTP.pm
|
||||
lib/Lemonldap/NG/Common/UserAgent.pm
|
||||
lib/Lemonldap/NG/Common/Util.pm
|
||||
Makefile.PL
|
||||
MANIFEST This list of files
|
||||
META.json
|
||||
|
|
|
@ -69,7 +69,9 @@ logLevel = warn
|
|||
; For Syslog logging, you can also overwrite facilities. Default values:
|
||||
;logger = Lemonldap::NG::Common::Logger::Syslog
|
||||
;syslogFacility = daemon
|
||||
;syslogOptions = cons,pid,ndelay
|
||||
;userSyslogFacility = auth
|
||||
;userSyslogOptions = cons,pid,ndelay
|
||||
;
|
||||
; 2.2 - Using Log4perl
|
||||
;
|
||||
|
@ -109,6 +111,8 @@ checkTime = 1
|
|||
;
|
||||
; type = File ; or type = YAMLFile
|
||||
; dirName = /var/lib/lemonldap-ng/conf
|
||||
; ; Optimize JSON for readability instead of performance
|
||||
; prettyPrint = 1
|
||||
;
|
||||
; * RDBI/CDBI : you have to set 'dbiChain' (required) and 'dbiUser' and 'dbiPassword'
|
||||
; if needed. Example:
|
||||
|
@ -154,6 +158,8 @@ checkTime = 1
|
|||
|
||||
type=File
|
||||
dirName=/var/lib/lemonldap-ng/conf
|
||||
; Optimize for readability instead of performance
|
||||
prettyPrint = 1
|
||||
|
||||
; LOCAL CACHE CONFIGURATION
|
||||
;
|
||||
|
@ -165,7 +171,7 @@ dirName=/var/lib/lemonldap-ng/conf
|
|||
; 'namespace' => 'lemonldap-ng-config',\
|
||||
; 'default_expires_in' => 600, \
|
||||
; 'directory_umask' => '007', \
|
||||
; 'cache_root' => '/tmp', \
|
||||
; 'cache_root' => '__CACHEDIR__', \
|
||||
; 'cache_depth' => 3, \
|
||||
; }
|
||||
localStorage=Cache::FileCache
|
||||
|
@ -173,7 +179,7 @@ localStorageOptions={ \
|
|||
'namespace' => 'lemonldap-ng-config',\
|
||||
'default_expires_in' => 600, \
|
||||
'directory_umask' => '007', \
|
||||
'cache_root' => '/tmp', \
|
||||
'cache_root' => '__CACHEDIR__', \
|
||||
'cache_depth' => 3, \
|
||||
}
|
||||
|
||||
|
@ -323,7 +329,7 @@ languages = en, fr, vi, it, ar, de, fi, tr, pl
|
|||
; 'namespace' => 'lemonldap-ng-sessions', \
|
||||
; 'default_expires_in' => 600, \
|
||||
; 'directory_umask' => '007', \
|
||||
; 'cache_root' => '/tmp', \
|
||||
; 'cache_root' => '__CACHEDIR__', \
|
||||
; 'cache_depth' => 3, \
|
||||
; }
|
||||
|
||||
|
|
|
@ -3,12 +3,11 @@ package Lemonldap::NG::Common::CliSessions;
|
|||
use strict;
|
||||
use Mouse;
|
||||
use JSON;
|
||||
use Digest::MD5 qw(md5_hex);
|
||||
use MIME::Base64;
|
||||
use Lemonldap::NG::Common::Conf;
|
||||
use Lemonldap::NG::Common::Logger::Std;
|
||||
use Lemonldap::NG::Common::Apache::Session;
|
||||
use Lemonldap::NG::Common::Session;
|
||||
use Lemonldap::NG::Common::Util qw/getPSessionID genId2F/;
|
||||
|
||||
our $VERSION = '2.0.8';
|
||||
|
||||
|
@ -118,7 +117,7 @@ sub _get_one_session {
|
|||
# Handle --persistent
|
||||
elsif ( $self->opts->{persistent} ) {
|
||||
$backendStorage = "persistentStorage";
|
||||
$id = $self->_md5hash($id);
|
||||
$id = getPSessionID($id);
|
||||
}
|
||||
|
||||
# In any case, fall back to global storage if we couldn't find the backend
|
||||
|
@ -195,23 +194,9 @@ sub get {
|
|||
return 0;
|
||||
}
|
||||
|
||||
# Return md5(s)
|
||||
# TODO factor with portal function
|
||||
sub _md5hash {
|
||||
my ( $self, $s ) = @_;
|
||||
return substr( Digest::MD5::md5_hex($s), 0, 32 );
|
||||
}
|
||||
|
||||
# TODO factor with manager API function
|
||||
sub _genId2F {
|
||||
my ( $self, $device ) = @_;
|
||||
return encode_base64( "$device->{epoch}::$device->{type}::$device->{name}",
|
||||
"" );
|
||||
}
|
||||
|
||||
sub _get_psession {
|
||||
my ( $self, $uid ) = @_;
|
||||
my $psession_id = $self->_md5hash($uid);
|
||||
my $psession_id = getPSessionID($uid);
|
||||
my $res = $self->_get_one_session( $psession_id, 'persistent' );
|
||||
die "Could not get psession for user $uid" unless $res;
|
||||
return $res;
|
||||
|
@ -287,7 +272,7 @@ sub secondfactors_get {
|
|||
my $target = shift;
|
||||
my $o = $self->stdout;
|
||||
my $consents = $self->_get_psession_special( $target, '_2fDevices',
|
||||
sub { $self->_genId2F( $_[0] ) } );
|
||||
sub { genId2F( $_[0] ) } );
|
||||
print $o $self->_to_json($consents);
|
||||
return 0;
|
||||
}
|
||||
|
@ -308,7 +293,7 @@ sub secondfactors_delete {
|
|||
my @ids = @_;
|
||||
return unless @ids;
|
||||
$self->_del_psession_special( $target, '_2fDevices',
|
||||
sub { $self->_genId2F( $_[0] ) }, @ids );
|
||||
sub { genId2F( $_[0] ) }, @ids );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,18 @@ sub store {
|
|||
return UNKNOWN_ERROR;
|
||||
}
|
||||
binmode(FILE);
|
||||
my $f = to_json( $fields, { allow_nonref => 1 } );
|
||||
my $json_options = {
|
||||
allow_nonref => 1,
|
||||
(
|
||||
$self->{prettyPrint}
|
||||
? (
|
||||
pretty => 1,
|
||||
canonical => 1
|
||||
)
|
||||
: ()
|
||||
)
|
||||
};
|
||||
my $f = to_json( $fields, $json_options );
|
||||
print FILE $f;
|
||||
close FILE;
|
||||
umask($mask);
|
||||
|
|
|
@ -23,6 +23,7 @@ use constant HANDLERSECTION => "handler";
|
|||
use constant MANAGERSECTION => "manager";
|
||||
use constant SESSIONSEXPLORERSECTION => "sessionsExplorer";
|
||||
use constant APPLYSECTION => "apply";
|
||||
|
||||
our $hashParameters = qr/^(?:(?:l(?:o(?:ca(?:lSessionStorageOption|tionRule)|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|(?:(?:d(?:emo|bi)|facebook|webID)ExportedVa|exported(?:Heade|Va)|issuerDBGetParamete)r|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|macro)s|o(?:idc(?:S(?:ervice(?:DynamicRegistrationEx(?:portedVar|traClaim)s|MetaDataAuthnContext)|torageOptions)|RPMetaData(?:(?:Option(?:sExtraClaim)?|ExportedVar|Macro)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node))|penIdExportedVars)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option|Macro)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars|fExtra)|c(?:as(?:A(?:ppMetaData(?:(?:ExportedVar|Option|Macro)s|Node)|ttributes)|S(?:rvMetaData(?:(?:ExportedVar|Option)s|Node)|torageOptions))|(?:ustom(?:Plugins|Add)Param|ombModule)s)|p(?:ersistentStorageOptions|o(?:rtalSkinRules|st))|a(?:ut(?:hChoiceMod|oSigninR)ules|pplicationList)|v(?:hostOptions|irtualHost)|S(?:MTPTLSOpts|SLVarIf))$/;
|
||||
our $boolKeys = qr/^(?:s(?:aml(?:IDP(?:MetaDataOptions(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|IsPassiv)e|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Force(?:Authn|UTF8)|StoreSAMLToken|RelayStateURL)|SSODescriptorWantAuthnRequestsSigned)|S(?:P(?:MetaDataOptions(?:(?:CheckS[LS]OMessageSignatur|OneTimeUs)e|EnableIDPInitiatedURL|ForceUTF8)|SSODescriptor(?:WantAssertion|AuthnRequest)sSigned)|erviceUseCertificateInResponse)|DiscoveryProtocol(?:Activation|IsPassive)|CommonDomainCookieActivation|UseQueryStringSpecific|MetadataForceUTF8)|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|kipRenewConfirmation|fRemovedUseNotif|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:Allow(?:PasswordGrant|Offline)|Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|GeneratePassword|PasswordPolicy)|ErrorOn(?:ExpiredSession|MailNotFound)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|o(?:ntextSwitchingStopWithLogout|mpactConf|rsEnabled)|heck(?:State|User|XSS)|da)|no(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|re(?:st(?:(?:Password|Session|Config|Auth)Server|ExportSecretKeys)|freshSessions)|br(?:uteForceProtection(?:IncrementalTempo)?|owsersDontStorePassword)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|d(?:isablePersistentStorage|biDynamicHashEnabled)|g(?:roupsBeforeMacros|lobalLogoutTimer)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|(?:activeTim|wsdlServ)er|krb(?:RemoveDomain|ByJs))$/;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ sub defaultValues {
|
|||
'authentication' => 'Demo',
|
||||
'available2F' => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey,Radius',
|
||||
'available2FSelfRegistration' => 'TOTP,U2F,Yubikey',
|
||||
'bruteForceProtectionLockTimes' => '5 15 60 300 600',
|
||||
'bruteForceProtectionLockTimes' => '5, 15, 60, 300, 600',
|
||||
'bruteForceProtectionMaxAge' => 300,
|
||||
'bruteForceProtectionMaxFailed' => 3,
|
||||
'bruteForceProtectionMaxLockTime' => 900,
|
||||
|
@ -140,7 +140,6 @@ sub defaultValues {
|
|||
'ldapGroupObjectClass' => 'groupOfNames',
|
||||
'ldapPasswordResetAttribute' => 'pwdReset',
|
||||
'ldapPasswordResetAttributeValue' => 'TRUE',
|
||||
'ldapPort' => 389,
|
||||
'ldapPwdEnc' => 'utf-8',
|
||||
'ldapSearchDeref' => 'find',
|
||||
'ldapServer' => 'ldap://localhost',
|
||||
|
@ -153,7 +152,7 @@ sub defaultValues {
|
|||
'localSessionStorage' => 'Cache::FileCache',
|
||||
'localSessionStorageOptions' => {
|
||||
'cache_depth' => 3,
|
||||
'cache_root' => '/tmp',
|
||||
'cache_root' => '/var/cache/lemonldap-ng',
|
||||
'default_expires_in' => 600,
|
||||
'directory_umask' => '007',
|
||||
'namespace' => 'lemonldap-ng-sessions'
|
||||
|
@ -246,26 +245,27 @@ sub defaultValues {
|
|||
'portalDisplayGeneratePassword' => 1,
|
||||
'portalDisplayLoginHistory' => 1,
|
||||
'portalDisplayLogout' => 1,
|
||||
'portalDisplayOidcConsents' => '$_oidcConsents',
|
||||
'portalDisplayRefreshMyRights' => 1,
|
||||
'portalDisplayRegister' => 1,
|
||||
'portalErrorOnExpiredSession' => 1,
|
||||
'portalForceAuthnInterval' => 5,
|
||||
'portalMainLogo' => 'common/logos/logo_llng_400px.png',
|
||||
'portalPingInterval' => 60000,
|
||||
'portalRequireOldPassword' => 1,
|
||||
'portalSkin' => 'bootstrap',
|
||||
'portalUserAttr' => '_user',
|
||||
'proxyAuthnLevel' => 2,
|
||||
'radius2fActivation' => 0,
|
||||
'radius2fTimeout' => 20,
|
||||
'radiusAuthnLevel' => 3,
|
||||
'randomPasswordRegexp' => '[A-Z]{3}[a-z]{5}.\\d{2}',
|
||||
'redirectFormMethod' => 'get',
|
||||
'registerDB' => 'Null',
|
||||
'registerTimeout' => 0,
|
||||
'registerUrl' => 'http://auth.example.com/register',
|
||||
'reloadTimeout' => 5,
|
||||
'portalDisplayOidcConsents' =>
|
||||
'$_oidcConsents && $_oidcConsents =~ /\\w+/',
|
||||
'portalDisplayRefreshMyRights' => 1,
|
||||
'portalDisplayRegister' => 1,
|
||||
'portalErrorOnExpiredSession' => 1,
|
||||
'portalForceAuthnInterval' => 5,
|
||||
'portalMainLogo' => 'common/logos/logo_llng_400px.png',
|
||||
'portalPingInterval' => 60000,
|
||||
'portalRequireOldPassword' => 1,
|
||||
'portalSkin' => 'bootstrap',
|
||||
'portalUserAttr' => '_user',
|
||||
'proxyAuthnLevel' => 2,
|
||||
'radius2fActivation' => 0,
|
||||
'radius2fTimeout' => 20,
|
||||
'radiusAuthnLevel' => 3,
|
||||
'randomPasswordRegexp' => '[A-Z]{3}[a-z]{5}.\\d{2}',
|
||||
'redirectFormMethod' => 'get',
|
||||
'registerDB' => 'Null',
|
||||
'registerTimeout' => 0,
|
||||
'registerUrl' => 'http://auth.example.com/register',
|
||||
'reloadTimeout' => 5,
|
||||
'remoteGlobalStorage' => 'Lemonldap::NG::Common::Apache::Session::SOAP',
|
||||
'remoteGlobalStorageOptions' => {
|
||||
'ns' =>
|
||||
|
@ -276,7 +276,7 @@ sub defaultValues {
|
|||
'rest2fActivation' => 0,
|
||||
'restAuthnLevel' => 2,
|
||||
'restClockTolerance' => 15,
|
||||
'sameSite' => 'None',
|
||||
'sameSite' => '',
|
||||
'samlAttributeAuthorityDescriptorAttributeServiceSOAP' =>
|
||||
'urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/AA/SOAP;',
|
||||
'samlAuthnContextMapKerberos' => 4,
|
||||
|
|
|
@ -769,8 +769,8 @@ sub metadata {
|
|||
return $self->sendJSONresponse(
|
||||
$req,
|
||||
$self->currentConf,
|
||||
forceJSON => 1,
|
||||
headers => [
|
||||
pretty => 1,
|
||||
headers => [
|
||||
'Content-Disposition' => "Attachment; filename=lmConf-$c.json"
|
||||
],
|
||||
);
|
||||
|
|
|
@ -11,11 +11,13 @@ sub new {
|
|||
my $self = bless {}, $class;
|
||||
if ( $args{user} ) {
|
||||
$self->{facility} = $conf->{userSyslogFacility} || 'auth';
|
||||
$self->{options} = $conf->{userSyslogOptions} || 'cons,pid,ndelay';
|
||||
}
|
||||
else {
|
||||
$self->{facility} = $conf->{syslogFacility} || 'daemon';
|
||||
$self->{options} = $conf->{syslogOptions} || 'cons,pid,ndelay';
|
||||
}
|
||||
eval { openlog( 'LLNG', 'cons,pid,ndelay', $self->{facility} ) };
|
||||
eval { openlog( 'LLNG', $self->{options}, $self->{facility} ) };
|
||||
no warnings 'redefine';
|
||||
my $show = 1;
|
||||
foreach (qw(error warn notice info debug)) {
|
||||
|
|
|
@ -126,7 +126,23 @@ sub sendJSONresponse {
|
|||
$args{headers} ||= [ $req->spliceHdrs ];
|
||||
my $type = 'application/json; charset=utf-8';
|
||||
if ( ref $j ) {
|
||||
eval { $j = $_json->encode($j); };
|
||||
eval {
|
||||
if ( $args{pretty} ) {
|
||||
|
||||
# This avoids changing the settings of the $_json reference
|
||||
$j = to_json(
|
||||
$j,
|
||||
{
|
||||
allow_nonref => 1,
|
||||
pretty => 1,
|
||||
canonical => 1
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
$j = $_json->encode($j);
|
||||
}
|
||||
};
|
||||
return $self->sendError( $req, $@ ) if ($@);
|
||||
}
|
||||
return [ $args{code}, [ 'Content-Type' => $type, @{ $args{headers} } ],
|
||||
|
|
|
@ -132,6 +132,7 @@ sub BUILD {
|
|||
if ( $self->{info} ) {
|
||||
foreach ( keys %{ $self->{info} } ) {
|
||||
next if ( $_ eq "_session_id" and $data->{_session_id} );
|
||||
next if ( $_ eq "_session_kind" and $data->{_session_kind});
|
||||
if ( defined $self->{info}->{$_} ) {
|
||||
$data->{$_} = $self->{info}->{$_};
|
||||
}
|
||||
|
|
115
lemonldap-ng-common/lib/Lemonldap/NG/Common/Util.pm
Normal file
115
lemonldap-ng-common/lib/Lemonldap/NG/Common/Util.pm
Normal file
|
@ -0,0 +1,115 @@
|
|||
package Lemonldap::NG::Common::Util;
|
||||
require Exporter;
|
||||
|
||||
use Digest::MD5;
|
||||
use MIME::Base64 qw/encode_base64/;
|
||||
|
||||
use 5.10.0;
|
||||
|
||||
our $VERSION = '2.0.9';
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT_OK = qw(getSameSite getPSessionID genId2F);
|
||||
|
||||
sub getPSessionID {
|
||||
my ($uid) = @_;
|
||||
return substr( Digest::MD5::md5_hex($uid), 0, 32 );
|
||||
}
|
||||
|
||||
sub genId2F {
|
||||
my ( $device ) = @_;
|
||||
return encode_base64( "$device->{epoch}::$device->{type}::$device->{name}",
|
||||
"" );
|
||||
}
|
||||
|
||||
|
||||
sub getSameSite {
|
||||
my ($conf) = @_;
|
||||
|
||||
# Initialize cookie SameSite value
|
||||
unless ( $conf->{sameSite} ) {
|
||||
|
||||
# SAML requires SameSite=None for POST bindings
|
||||
if ( $conf->{issuerDBSAMLActivation}
|
||||
or keys %{ $conf->{samlIDPMetaDataXML} } )
|
||||
{
|
||||
return "None";
|
||||
}
|
||||
else {
|
||||
return "Lax";
|
||||
}
|
||||
|
||||
# if CDA, OIDC, CAS: Lax
|
||||
# TODO: try to detect when we can use 'Strict'?
|
||||
# Any scenario that uses pdata to save state during login,
|
||||
# Issuers, and CDA all require at least Lax
|
||||
}
|
||||
else {
|
||||
return $conf->{sameSite};
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
=encoding utf8
|
||||
|
||||
Lemonldap::NG::Common::Util - Utility class for LemonLDAP::NG
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This package contains various functions that need to be shared between
|
||||
modules.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head3 getPSessionID($uid)
|
||||
|
||||
This method computes the psession ID from the user login
|
||||
|
||||
=head3 genId2F($device)
|
||||
|
||||
This method computes the unique ID of each 2F device, for use with the API and CLI
|
||||
|
||||
=head3 getSameSite($conf)
|
||||
|
||||
Try to find a sensible value for the SameSite cookie attribute.
|
||||
If the user has overriden it, return the forced value
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over
|
||||
|
||||
=item LemonLDAP::NG team L<http://lemonldap-ng.org/team>
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUG REPORT
|
||||
|
||||
Use OW2 system to report bug or ask for features:
|
||||
L<https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues>
|
||||
|
||||
=head1 DOWNLOAD
|
||||
|
||||
Lemonldap::NG is available at
|
||||
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
See COPYING file for details.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see L<http://www.gnu.org/licenses/>.
|
||||
|
||||
=cut
|
|
@ -72,6 +72,16 @@ unless ($new) {
|
|||
exit 5;
|
||||
}
|
||||
|
||||
my $oldtype = $old->{type} =~ s/^Lemonldap::NG::Common::Conf::Backends:://r;
|
||||
my $newtype = $new->{type} =~ s/^Lemonldap::NG::Common::Conf::Backends:://r;
|
||||
print STDERR "Converting from " . $oldtype . " to " . $newtype . "\n";
|
||||
|
||||
if ( $oldtype eq $newtype ) {
|
||||
print STDERR "\nWARNING: "
|
||||
. "converting configuration without changing backend type.\n"
|
||||
. "Make sure you know what you are doing.\n\n";
|
||||
}
|
||||
|
||||
my @available;
|
||||
if ( $opts{latest} ) {
|
||||
@available = $old->lastCfg();
|
||||
|
@ -88,7 +98,7 @@ foreach my $e ( @available, @dstavailable ) { $tmp{$e}++ }
|
|||
my @isect = grep { $tmp{$_} > 1 } keys %tmp;
|
||||
|
||||
if ( @isect and not $opts{overwrite} ) {
|
||||
print STDERR "Warning, " . @isect
|
||||
print STDERR "WARNING: " . @isect
|
||||
. " existing configurations found in destination \n";
|
||||
print STDERR " use --overwrite to overwrite existing configurations\n";
|
||||
exit 8;
|
||||
|
|
|
@ -55,6 +55,7 @@ t/64-Lemonldap-NG-Handler-PSGI-DevOps.t
|
|||
t/65-Lemonldap-NG-Handler-Nginx-ServiceToken.t
|
||||
t/65-Lemonldap-NG-Handler-PSGI-ServiceToken.t
|
||||
t/66-Lemonldap-NG-Handler-PSGI-wildcard.t
|
||||
t/67-Lemonldap-NG-Handler-PSGI-vhostoptions-with-reload.t
|
||||
t/67-Lemonldap-NG-Handler-PSGI-vhostoptions.t
|
||||
t/68-Lemonldap-NG-Handler-PSGI-Zimbra.t
|
||||
t/69-Lemonldap-NG-Handler-PSGI-SecureToken.t
|
||||
|
|
|
@ -7,8 +7,8 @@ our $VERSION = '2.1.0';
|
|||
sub fetchId {
|
||||
my ( $class, $req ) = @_;
|
||||
my $token = $req->{env}->{HTTP_X_LLNG_TOKEN};
|
||||
return $class->Lemonldap::NG::Handler::Main::fetchId($req) unless ($token);
|
||||
$class->logger->debug('Found token header');
|
||||
return $class->Lemonldap::NG::Handler::Main::fetchId($req) unless ($token =~ /\w+/);
|
||||
$class->logger->debug("Found token: $token");
|
||||
|
||||
# Decrypt token
|
||||
my $s = $class->tsv->{cipher}->decrypt($token);
|
||||
|
@ -16,6 +16,8 @@ sub fetchId {
|
|||
# Token format:
|
||||
# time:_session_id:vhost1:vhost2:serviceHeader1=value1:serviceHeader2=value2,...
|
||||
my ( $t, $_session_id, @vhosts ) = split /:/, $s;
|
||||
$class->logger->debug("Found epoch: $t");
|
||||
$class->logger->debug("Found _session_id: $_session_id");
|
||||
|
||||
# Looking for service headers
|
||||
my $vhost = $class->resolveAlias($req);
|
||||
|
@ -43,6 +45,7 @@ sub fetchId {
|
|||
"$vhost not authorized in token (" . join( ', ', @vhosts ) . ')' );
|
||||
return 0;
|
||||
}
|
||||
$class->logger->debug( 'Found VHosts: ' . join ', ', @vhosts );
|
||||
|
||||
# Is token in good interval ?
|
||||
my $ttl =
|
||||
|
|
|
@ -259,7 +259,7 @@ sub run {
|
|||
}
|
||||
}
|
||||
else {
|
||||
print STDERR "Status: Unknown command line : $_";
|
||||
print STDERR "Status: Unknown command line -> $_";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -553,9 +553,8 @@ sub conditionSub {
|
|||
eval 'use Apache2::Filter' unless ( $INC{"Apache2/Filter.pm"} );
|
||||
return (
|
||||
sub {
|
||||
|
||||
my ($req) = @_;
|
||||
$class->localUnlog;
|
||||
$class->localUnlog( $req, @_ );
|
||||
$req->{env}->{'psgi.r'}->add_output_filter(
|
||||
sub {
|
||||
my $r = $_[0]->r;
|
||||
|
|
|
@ -452,7 +452,7 @@ sub fetchId {
|
|||
my $value =
|
||||
$lookForHttpCookie
|
||||
? ( $t =~ /${cn}http=([^,; ]+)/o ? $1 : 0 )
|
||||
: ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 );
|
||||
: ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 );
|
||||
|
||||
if ( $value && $lookForHttpCookie && $class->tsv->{securedCookie} == 3 ) {
|
||||
$value = $class->tsv->{cipher}->decryptHex( $value, "http" );
|
||||
|
@ -621,7 +621,7 @@ sub _isHttps {
|
|||
return $class->tsv->{https}->{_};
|
||||
}
|
||||
else {
|
||||
return ( ( uc( $req->{env}->{HTTPS} ) || "OFF" ) eq "ON" );
|
||||
return ( uc( $req->{env}->{HTTPS} || "OFF" ) eq "ON" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
use Test::More;
|
||||
use JSON;
|
||||
use MIME::Base64;
|
||||
use Data::Dumper;
|
||||
use URI::Escape;
|
||||
|
||||
require 't/test-psgi-lib.pm';
|
||||
|
||||
init(
|
||||
'Lemonldap::NG::Handler::PSGI',
|
||||
{
|
||||
locationRules => {},
|
||||
exportedHeaders => {},
|
||||
https => undef,
|
||||
port => undef,
|
||||
maintenance => undef,
|
||||
}
|
||||
);
|
||||
|
||||
my $res;
|
||||
|
||||
ok( $res = $client->_get('/'), 'Unauthentified query' );
|
||||
ok( ref($res) eq 'ARRAY', 'Response is an array' ) or explain( $res, 'array' );
|
||||
ok( $res->[0] == 302, 'Code is 302' ) or explain( $res->[0], 302 );
|
||||
|
||||
my $conf;
|
||||
eval {
|
||||
local $/ = undef;
|
||||
open my $file, 't/lmConf-1.json' or die $!;
|
||||
$conf = JSON::from_json(<$file>);
|
||||
close $file;
|
||||
};
|
||||
fail $@ if $@;
|
||||
$conf->{vhostOptions} = {
|
||||
'test1.example.com' => {
|
||||
vhostHttps => 1,
|
||||
vhostPort => 443,
|
||||
},
|
||||
};
|
||||
Lemonldap::NG::Handler::Main->configReload($conf);
|
||||
fail $@ if $@;
|
||||
ok( $res = $client->_get('/'), 'Unauthentified query' );
|
||||
ok( ref($res) eq 'ARRAY', 'Response is an array' ) or explain( $res, 'array' );
|
||||
ok( $res->[0] == 302, 'Code is 302' ) or explain( $res->[0], 302 );
|
||||
my %h = @{ $res->[1] };
|
||||
ok(
|
||||
$h{Location} eq 'http://auth.example.com/?url='
|
||||
. uri_escape( encode_base64( 'https://test1.example.com/', '' ) ),
|
||||
'Redirection points to portal and site is https'
|
||||
)
|
||||
or explain(
|
||||
\%h,
|
||||
'Location => http://auth.example.com/?url='
|
||||
. uri_escape( encode_base64( 'https://test1.example.com/', '' ) )
|
||||
);
|
||||
|
||||
count(7);
|
||||
done_testing( count() );
|
||||
clean();
|
|
@ -10,6 +10,7 @@ lib/Lemonldap/NG/Manager/2ndFA.pm
|
|||
lib/Lemonldap/NG/Manager/Api.pm
|
||||
lib/Lemonldap/NG/Manager/Api/2F.pm
|
||||
lib/Lemonldap/NG/Manager/Api/Common.pm
|
||||
lib/Lemonldap/NG/Manager/Api/Misc.pm
|
||||
lib/Lemonldap/NG/Manager/Api/Providers/OidcRp.pm
|
||||
lib/Lemonldap/NG/Manager/Api/Providers/SamlSp.pm
|
||||
lib/Lemonldap/NG/Manager/Attributes.pm
|
||||
|
|
|
@ -4,7 +4,6 @@ use 5.10.0;
|
|||
use utf8;
|
||||
use strict;
|
||||
use Mouse;
|
||||
use MIME::Base64 qw(encode_base64 decode_base64);
|
||||
|
||||
use Lemonldap::NG::Common::Session;
|
||||
use Lemonldap::NG::Common::Conf::Constants;
|
||||
|
|
|
@ -10,10 +10,14 @@ extends 'Lemonldap::NG::Manager::Plugin',
|
|||
'Lemonldap::NG::Common::Session::REST';
|
||||
|
||||
use Lemonldap::NG::Manager::Api::2F;
|
||||
use Lemonldap::NG::Manager::Api::Misc;
|
||||
use Lemonldap::NG::Manager::Api::Providers::OidcRp;
|
||||
use Lemonldap::NG::Manager::Api::Providers::SamlSp;
|
||||
use Lemonldap::NG::Manager::Api::Providers::CasApp;
|
||||
use Lemonldap::NG::Manager::Api::Menu::Cat;
|
||||
use Lemonldap::NG::Manager::Api::Menu::App;
|
||||
|
||||
our $VERSION = '2.0.8';
|
||||
our $VERSION = '2.0.9';
|
||||
|
||||
#############################
|
||||
# I. INITIALIZATION METHODS #
|
||||
|
@ -30,6 +34,7 @@ sub init {
|
|||
->addRoute(
|
||||
api => {
|
||||
v1 => {
|
||||
status => 'status',
|
||||
providers => {
|
||||
oidc => {
|
||||
rp => {
|
||||
|
@ -53,6 +58,17 @@ sub init {
|
|||
':confKey' => 'getSamlSpByConfKey'
|
||||
},
|
||||
},
|
||||
cas => {
|
||||
app => {
|
||||
findByConfKey => {
|
||||
':uPattern' => 'findCasAppByConfKey'
|
||||
},
|
||||
findByServiceUrl => {
|
||||
':uServiceUrl' => 'findCasAppsByServiceUrl'
|
||||
},
|
||||
':confKey' => 'getCasAppByConfKey'
|
||||
},
|
||||
},
|
||||
},
|
||||
secondFactor => {
|
||||
':uid' => {
|
||||
|
@ -65,6 +81,24 @@ sub init {
|
|||
'*' => 'getSecondFactors'
|
||||
},
|
||||
},
|
||||
menu => {
|
||||
cat => {
|
||||
findByConfKey => {
|
||||
':uPattern' => 'findMenuCatByConfKey'
|
||||
},
|
||||
':confKey' => {
|
||||
'*' => 'getMenuCatByConfKey'
|
||||
}
|
||||
},
|
||||
app => {
|
||||
':confKey' => {
|
||||
findByConfKey => {
|
||||
':uPattern' => 'findMenuAppByConfKey'
|
||||
},
|
||||
':appConfKey' => 'getMenuApp'
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
['GET']
|
||||
|
@ -80,6 +114,15 @@ sub init {
|
|||
saml => {
|
||||
sp => 'addSamlSp'
|
||||
},
|
||||
cas => {
|
||||
app => 'addCasApp'
|
||||
},
|
||||
},
|
||||
menu => {
|
||||
cat => 'addMenuCat',
|
||||
app => {
|
||||
':confKey' => 'addMenuApp'
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -96,6 +139,17 @@ sub init {
|
|||
saml => {
|
||||
sp => { ':confKey' => 'replaceSamlSp' }
|
||||
},
|
||||
cas => {
|
||||
app => { ':confKey' => 'replaceCasApp' }
|
||||
},
|
||||
},
|
||||
menu => {
|
||||
cat => { ':confKey' => 'replaceMenuCat' },
|
||||
app => {
|
||||
':confKey' => {
|
||||
':appConfKey' => 'replaceMenuApp'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -112,6 +166,17 @@ sub init {
|
|||
saml => {
|
||||
sp => { ':confKey' => 'updateSamlSp' }
|
||||
},
|
||||
cas => {
|
||||
app => { ':confKey' => 'updateCasApp' }
|
||||
},
|
||||
},
|
||||
menu => {
|
||||
cat => { ':confKey' => 'updateMenuCat' },
|
||||
app => {
|
||||
':confKey' => {
|
||||
':appConfKey' => 'updateMenuApp'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -128,6 +193,9 @@ sub init {
|
|||
saml => {
|
||||
sp => { ':confKey' => 'deleteSamlSp' }
|
||||
},
|
||||
cas => {
|
||||
app => { ':confKey' => 'deleteCasApp' }
|
||||
},
|
||||
},
|
||||
secondFactor => {
|
||||
':uid' => {
|
||||
|
@ -140,6 +208,14 @@ sub init {
|
|||
'*' => 'deleteSecondFactors'
|
||||
},
|
||||
},
|
||||
menu => {
|
||||
cat => { ':confKey' => 'deleteMenuCat' },
|
||||
app => {
|
||||
':confKey' => {
|
||||
':appConfKey' => 'deleteMenuApp'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
['DELETE']
|
||||
|
|
|
@ -8,9 +8,9 @@ use 5.10.0;
|
|||
use utf8;
|
||||
use Mouse;
|
||||
use JSON;
|
||||
use MIME::Base64;
|
||||
|
||||
use Lemonldap::NG::Common::Session;
|
||||
use Lemonldap::NG::Common::Util qw/genId2F/;
|
||||
|
||||
sub getSecondFactors {
|
||||
my ( $self, $req ) = @_;
|
||||
|
@ -155,12 +155,12 @@ sub _get2F {
|
|||
);
|
||||
push @secondFactors,
|
||||
{
|
||||
id => $self->_genId2F($device),
|
||||
id => genId2F($device),
|
||||
type => $device->{type},
|
||||
name => $device->{name}
|
||||
}
|
||||
unless ( ( defined $type and $type ne $device->{type} )
|
||||
or ( defined $id and $id ne $self->_genId2F($device) ) );
|
||||
or ( defined $id and $id ne genId2F($device) ) );
|
||||
}
|
||||
}
|
||||
$self->logger->debug(
|
||||
|
@ -168,26 +168,6 @@ sub _get2F {
|
|||
return { res => 'ok', secondFactors => [@secondFactors] };
|
||||
}
|
||||
|
||||
sub _genId2F {
|
||||
my ( $self, $device ) = @_;
|
||||
return encode_base64( "$device->{epoch}::$device->{type}::$device->{name}",
|
||||
"" );
|
||||
}
|
||||
|
||||
sub _getPersistentMod {
|
||||
my ($self) = @_;
|
||||
my $mod = $self->sessionTypes->{persistent};
|
||||
$mod->{options}->{backend} = $mod->{module};
|
||||
return $mod;
|
||||
}
|
||||
|
||||
sub _getSSOMod {
|
||||
my ($self) = @_;
|
||||
my $mod = $self->sessionTypes->{global};
|
||||
$mod->{options}->{backend} = $mod->{module};
|
||||
return $mod;
|
||||
}
|
||||
|
||||
sub _getSessions2F {
|
||||
my ( $self, $mod, $kind, $key, $uid ) = @_;
|
||||
$self->logger->debug("Looking for sessions for uid $uid ...");
|
||||
|
@ -245,14 +225,13 @@ sub _delete2FFromSessions {
|
|||
if (
|
||||
( defined $type or defined $id )
|
||||
and ( ( defined $type and $type ne $element->{type} )
|
||||
or
|
||||
( defined $id and $id ne $self->_genId2F($element) ) )
|
||||
or ( defined $id and $id ne genId2F($element) ) )
|
||||
)
|
||||
{
|
||||
push @keep, $element;
|
||||
}
|
||||
else {
|
||||
$removed->{ $self->_genId2F($element) } = "removed";
|
||||
$removed->{ genId2F($element) } = "removed";
|
||||
}
|
||||
}
|
||||
if ( ( $total - scalar @keep ) > 0 ) {
|
||||
|
|
|
@ -112,4 +112,18 @@ sub _getRegexpFromPattern {
|
|||
return qr/$pattern/;
|
||||
}
|
||||
|
||||
sub _getPersistentMod {
|
||||
my ($self) = @_;
|
||||
my $mod = $self->sessionTypes->{persistent};
|
||||
$mod->{options}->{backend} = $mod->{module};
|
||||
return $mod;
|
||||
}
|
||||
|
||||
sub _getSSOMod {
|
||||
my ($self) = @_;
|
||||
my $mod = $self->sessionTypes->{global};
|
||||
$mod->{options}->{backend} = $mod->{module};
|
||||
return $mod;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
408
lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api/Menu/App.pm
Normal file
408
lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api/Menu/App.pm
Normal file
|
@ -0,0 +1,408 @@
|
|||
package Lemonldap::NG::Manager::Api::Menu::App;
|
||||
|
||||
our $VERSION = '2.0.9';
|
||||
|
||||
package Lemonldap::NG::Manager::Api;
|
||||
|
||||
use 5.10.0;
|
||||
use utf8;
|
||||
use Mouse;
|
||||
use Lemonldap::NG::Manager::Conf::Parser;
|
||||
use Data::Dumper;
|
||||
|
||||
extends 'Lemonldap::NG::Manager::Api::Common';
|
||||
|
||||
sub getMenuApp {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my $catConfKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'Category confKey is missing', 400 );
|
||||
|
||||
my $appConfKey = $req->params('appConfKey');
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf;
|
||||
|
||||
# Check if catConfKey is defined
|
||||
return $self->sendError( $req,
|
||||
"Menu category '$catConfKey' not found", 404 )
|
||||
unless ( defined $conf->{applicationList}->{$catConfKey} );
|
||||
|
||||
if ( defined $appConfKey ) {
|
||||
|
||||
# Return one application referenced with this appConfKey
|
||||
$self->logger->debug(
|
||||
"[API] Menu application $appConfKey from category $catConfKey configuration requested"
|
||||
);
|
||||
|
||||
my $menuApp =
|
||||
$self->_getMenuAppByConfKey( $conf, $catConfKey, $appConfKey );
|
||||
|
||||
# Return 404 if not found
|
||||
return $self->sendError(
|
||||
$req,
|
||||
"Menu application '$appConfKey' from category '$catConfKey' not found",
|
||||
404
|
||||
) unless ( defined $menuApp );
|
||||
|
||||
return $self->sendJSONresponse( $req, $menuApp );
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
# Return all applications for this category
|
||||
$self->logger->debug(
|
||||
"[API] Menu applications from category $catConfKey configuration requested"
|
||||
);
|
||||
|
||||
my $cat = $conf->{applicationList}->{$catConfKey};
|
||||
|
||||
my @menuApps =
|
||||
map {
|
||||
$self->_isCatApp( $cat->{$_} )
|
||||
? $self->_getMenuAppByConfKey( $conf, $catConfKey, $_ )
|
||||
: ()
|
||||
}
|
||||
keys %{$cat};
|
||||
|
||||
return $self->sendJSONresponse( $req, [@menuApps] );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sub findMenuAppByConfKey {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my $catConfKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'Category confKey is missing', 400 );
|
||||
|
||||
my $pattern = (
|
||||
defined $req->params('uPattern')
|
||||
? $req->params('uPattern')
|
||||
: ( defined $req->params('pattern') ? $req->params('pattern') : undef )
|
||||
);
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: pattern is missing', 400 )
|
||||
unless ( defined $pattern );
|
||||
|
||||
unless ( $pattern = $self->_getRegexpFromPattern($pattern) ) {
|
||||
return $self->sendError( $req, 'Invalid input: pattern is invalid',
|
||||
400 );
|
||||
}
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Find Menu Applications from category $catConfKey by confKey regexp $pattern requested"
|
||||
);
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf;
|
||||
|
||||
# Check if catConfKey is defined
|
||||
return $self->sendError( $req,
|
||||
"Menu category '$catConfKey' not found", 404 )
|
||||
unless ( defined $conf->{applicationList}->{$catConfKey} );
|
||||
|
||||
my $cat = $conf->{applicationList}->{$catConfKey};
|
||||
|
||||
my @menuApps =
|
||||
map {
|
||||
$self->_isCatApp( $cat->{$_} )
|
||||
&& $_ =~ $pattern
|
||||
? $self->_getMenuAppByConfKey( $conf, $catConfKey, $_ )
|
||||
: ()
|
||||
}
|
||||
keys %{$cat};
|
||||
|
||||
return $self->sendJSONresponse( $req, [@menuApps] );
|
||||
}
|
||||
|
||||
sub addMenuApp {
|
||||
my ( $self, $req ) = @_;
|
||||
my $add = $req->jsonBodyToObj;
|
||||
|
||||
my $catConfKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'Category confKey is missing', 400 );
|
||||
|
||||
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
|
||||
unless ($add);
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is missing', 400 )
|
||||
unless ( defined $add->{confKey} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is not a string',
|
||||
400 )
|
||||
if ( ref $add->{confKey} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey contains invalid characters',
|
||||
400 )
|
||||
unless ( $add->{confKey} =~ '^\w[\w\.\-]*$' );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: name is missing', 400 )
|
||||
unless ( defined $add->{options} && defined $add->{options}{name} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: name is not a string', 400 )
|
||||
if ( ref $add->{options}{name} );
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Add Menu Application from category $catConfKey with confKey $add->{confKey} requested"
|
||||
);
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
# Check if catConfKey is defined
|
||||
return $self->sendError( $req,
|
||||
"Menu category '$catConfKey' not found", 404 )
|
||||
unless ( defined $conf->{applicationList}->{$catConfKey} );
|
||||
|
||||
return $self->sendError(
|
||||
$req,
|
||||
"Invalid input: A Menu Application with confKey $add->{confKey} already exists in category $catConfKey",
|
||||
409
|
||||
)
|
||||
if (
|
||||
defined $self->_getMenuAppByConfKey( $conf, $catConfKey,
|
||||
$add->{confKey} ) );
|
||||
|
||||
my $res =
|
||||
$self->_pushMenuApp( $conf, $catConfKey, $add->{confKey}, $add, 1 );
|
||||
|
||||
return $self->sendError( $req, $res->{msg}, 400 )
|
||||
unless ( $res->{res} eq 'ok' );
|
||||
|
||||
return $self->sendJSONresponse(
|
||||
$req,
|
||||
{ message => "Successful operation" },
|
||||
code => 201
|
||||
);
|
||||
}
|
||||
|
||||
sub updateMenuApp {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my $catConfKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'Category confKey is missing', 400 );
|
||||
|
||||
my $appConfKey = $req->params('appConfKey')
|
||||
or return $self->sendError( $req, 'Application confKey is missing', 400 );
|
||||
|
||||
my $update = $req->jsonBodyToObj;
|
||||
|
||||
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
|
||||
unless ($update);
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Menu application $appConfKey from category $catConfKey configuration update requested"
|
||||
);
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
# Return 404 if not found
|
||||
|
||||
return $self->sendError( $req,
|
||||
"Menu category '$catConfKey' not found", 404 )
|
||||
unless ( defined $self->_getMenuCatByConfKey( $conf, $catConfKey ) );
|
||||
|
||||
return $self->sendError(
|
||||
$req,
|
||||
"Menu application '$appConfKey' from category '$catConfKey' not found",
|
||||
404
|
||||
)
|
||||
unless (
|
||||
defined $self->_getMenuAppByConfKey( $conf, $catConfKey, $appConfKey )
|
||||
);
|
||||
|
||||
my $res =
|
||||
$self->_pushMenuApp( $conf, $catConfKey, $appConfKey, $update, 0 );
|
||||
|
||||
return $self->sendError( $req, $res->{msg}, 400 )
|
||||
unless ( $res->{res} eq 'ok' );
|
||||
|
||||
return $self->sendJSONresponse( $req, undef, code => 204 );
|
||||
}
|
||||
|
||||
sub replaceMenuApp {
|
||||
my ( $self, $req ) = @_;
|
||||
my $catConfKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'Category confKey is missing', 400 );
|
||||
|
||||
my $appConfKey = $req->params('appConfKey')
|
||||
or return $self->sendError( $req, 'Application confKey is missing', 400 );
|
||||
|
||||
my $replace = $req->jsonBodyToObj;
|
||||
|
||||
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
|
||||
unless ($replace);
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is missing', 400 )
|
||||
unless ( defined $replace->{confKey} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is not a string',
|
||||
400 )
|
||||
if ( ref $replace->{confKey} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey contains invalid characters',
|
||||
400 )
|
||||
unless ( $replace->{confKey} =~ '^\w[\w\.\-]*$' );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: name is missing', 400 )
|
||||
unless ( defined $replace->{options}
|
||||
&& defined $replace->{options}{name} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: name is not a string', 400 )
|
||||
if ( ref $replace->{options}{name} );
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Menu application $appConfKey from category $catConfKey configuration replace requested"
|
||||
);
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
# Return 404 if not found
|
||||
|
||||
return $self->sendError( $req,
|
||||
"Menu category '$catConfKey' not found", 404 )
|
||||
unless ( defined $self->_getMenuCatByConfKey( $conf, $catConfKey ) );
|
||||
|
||||
return $self->sendError(
|
||||
$req,
|
||||
"Menu application '$appConfKey' from category '$catConfKey' not found",
|
||||
404
|
||||
)
|
||||
unless (
|
||||
defined $self->_getMenuAppByConfKey( $conf, $catConfKey, $appConfKey )
|
||||
);
|
||||
|
||||
my $res =
|
||||
$self->_pushMenuApp( $conf, $catConfKey, $appConfKey, $replace, 1 );
|
||||
return $self->sendError( $req, $res->{msg}, 400 )
|
||||
unless ( $res->{res} eq 'ok' );
|
||||
|
||||
return $self->sendJSONresponse( $req, undef, code => 204 );
|
||||
}
|
||||
|
||||
sub deleteMenuApp {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my $catConfKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'Category confKey is missing', 400 );
|
||||
|
||||
my $appConfKey = $req->params('appConfKey')
|
||||
or return $self->sendError( $req, 'Application confKey is missing', 400 );
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Menu Application $appConfKey from category $catConfKey configuration delete requested"
|
||||
);
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
return $self->sendError( $req,
|
||||
"Menu category '$catConfKey' not found", 404 )
|
||||
unless ( defined $self->_getMenuCatByConfKey( $conf, $catConfKey ) );
|
||||
|
||||
my $delete = $self->_getMenuAppByConfKey( $conf, $catConfKey, $appConfKey );
|
||||
|
||||
# Return 404 if not found
|
||||
|
||||
return $self->sendError( $req,
|
||||
"Menu category '$appConfKey' not found", 404 )
|
||||
unless ( defined $delete );
|
||||
|
||||
delete $conf->{applicationList}->{$catConfKey}->{$appConfKey};
|
||||
|
||||
# Save configuration
|
||||
$self->_confAcc->saveConf($conf);
|
||||
|
||||
return $self->sendJSONresponse( $req, undef, code => 204 );
|
||||
}
|
||||
|
||||
sub _isCatApp {
|
||||
my ( $self, $candidate ) = @_;
|
||||
|
||||
# Check if candidate is a hash, has "type" defined and if "type" equals "application".
|
||||
return
|
||||
ref $candidate eq ref {}
|
||||
&& defined $candidate->{type}
|
||||
&& $candidate->{type} eq 'application';
|
||||
}
|
||||
|
||||
sub _getMenuAppByConfKey {
|
||||
my ( $self, $conf, $catConfKey, $appConfKey ) = @_;
|
||||
|
||||
# Check if catConfKey is defined
|
||||
return undef unless ( defined $conf->{applicationList}->{$catConfKey} );
|
||||
|
||||
# Check if appConfKey is defined
|
||||
return undef
|
||||
unless ( defined $conf->{applicationList}->{$catConfKey}->{$appConfKey} );
|
||||
|
||||
my $cat = $conf->{applicationList}->{$catConfKey};
|
||||
|
||||
my $menuApp = { confKey => $appConfKey };
|
||||
|
||||
$menuApp->{order} = $cat->{$appConfKey}->{order}
|
||||
if ( defined $cat->{$appConfKey}->{order} );
|
||||
|
||||
# Get options
|
||||
my $options = {};
|
||||
for my $configOption ( keys %{ $cat->{$appConfKey}->{options} } ) {
|
||||
$options->{ $self->_translateOptionConfToApi($configOption) } =
|
||||
$cat->{$appConfKey}->{options}->{$configOption};
|
||||
}
|
||||
|
||||
$menuApp->{options} = $options;
|
||||
|
||||
return $menuApp;
|
||||
}
|
||||
|
||||
sub _pushMenuApp {
|
||||
my ( $self, $conf, $catConfKey, $appConfKey, $push, $replace ) = @_;
|
||||
|
||||
if ($replace) {
|
||||
$conf->{applicationList}->{$catConfKey}->{$appConfKey} = {};
|
||||
$conf->{applicationList}->{$catConfKey}->{$appConfKey}->{type} =
|
||||
"application";
|
||||
$conf->{applicationList}->{$catConfKey}->{$appConfKey}->{options} = {};
|
||||
$conf->{applicationList}->{$catConfKey}->{$appConfKey}->{options}
|
||||
->{display} = "auto";
|
||||
$conf->{applicationList}->{$catConfKey}->{$appConfKey}->{options}
|
||||
->{logo} = "network.png";
|
||||
}
|
||||
|
||||
$conf->{applicationList}->{$catConfKey}->{$appConfKey}->{order} =
|
||||
$push->{order}
|
||||
if ( defined $push->{order} );
|
||||
|
||||
if ( defined $push->{options} ) {
|
||||
foreach ( keys %{ $push->{options} } ) {
|
||||
$conf->{applicationList}->{$catConfKey}->{$appConfKey}->{options}
|
||||
->{$_} = $push->{options}->{$_};
|
||||
}
|
||||
}
|
||||
|
||||
# Test new configuration
|
||||
my $parser = Lemonldap::NG::Manager::Conf::Parser->new( {
|
||||
refConf => $self->_confAcc->getConf,
|
||||
newConf => $conf,
|
||||
req => {},
|
||||
}
|
||||
);
|
||||
unless ( $parser->testNewConf( $self->p ) ) {
|
||||
return {
|
||||
res => 'ko',
|
||||
code => 400,
|
||||
msg => "Configuration error: "
|
||||
. join( ". ", map { $_->{message} } @{ $parser->errors } ),
|
||||
};
|
||||
}
|
||||
|
||||
# Save configuration
|
||||
$self->_confAcc->saveConf($conf);
|
||||
|
||||
return { res => 'ok' };
|
||||
}
|
||||
|
||||
1;
|
270
lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api/Menu/Cat.pm
Normal file
270
lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api/Menu/Cat.pm
Normal file
|
@ -0,0 +1,270 @@
|
|||
package Lemonldap::NG::Manager::Api::Menu::Cat;
|
||||
|
||||
our $VERSION = '2.0.9';
|
||||
|
||||
package Lemonldap::NG::Manager::Api;
|
||||
|
||||
use 5.10.0;
|
||||
use utf8;
|
||||
use Mouse;
|
||||
use Lemonldap::NG::Manager::Conf::Parser;
|
||||
|
||||
extends 'Lemonldap::NG::Manager::Api::Common';
|
||||
|
||||
sub getMenuCatByConfKey {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my $confKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'confKey is missing', 400 );
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Menu Category $confKey configuration requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf;
|
||||
|
||||
my $menuCat = $self->_getMenuCatByConfKey( $conf, $confKey );
|
||||
|
||||
# Return 404 if not found
|
||||
return $self->sendError( $req, "Menu category '$confKey' not found", 404 )
|
||||
unless ( defined $menuCat );
|
||||
|
||||
return $self->sendJSONresponse( $req, $menuCat );
|
||||
}
|
||||
|
||||
sub findMenuCatByConfKey {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my $pattern = (
|
||||
defined $req->params('uPattern')
|
||||
? $req->params('uPattern')
|
||||
: ( defined $req->params('pattern') ? $req->params('pattern') : undef )
|
||||
);
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: pattern is missing', 400 )
|
||||
unless ( defined $pattern );
|
||||
|
||||
unless ( $pattern = $self->_getRegexpFromPattern($pattern) ) {
|
||||
return $self->sendError( $req, 'Invalid input: pattern is invalid',
|
||||
400 );
|
||||
}
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Find Menu Categories by confKey regexp $pattern requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf;
|
||||
|
||||
my @menuCats =
|
||||
map { $_ =~ $pattern ? $self->_getMenuCatByConfKey( $conf, $_ ) : () }
|
||||
keys %{ $conf->{applicationList} };
|
||||
|
||||
return $self->sendJSONresponse( $req, [@menuCats] );
|
||||
}
|
||||
|
||||
sub addMenuCat {
|
||||
my ( $self, $req ) = @_;
|
||||
my $add = $req->jsonBodyToObj;
|
||||
|
||||
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
|
||||
unless ($add);
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is missing', 400 )
|
||||
unless ( defined $add->{confKey} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is not a string',
|
||||
400 )
|
||||
if ( ref $add->{confKey} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey contains invalid characters',
|
||||
400 )
|
||||
unless ( $add->{confKey} =~ '^\w[\w\.\-]*$' );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: catname is missing', 400 )
|
||||
unless ( defined $add->{catname} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: catname is not a string',
|
||||
400 )
|
||||
if ( ref $add->{catname} );
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Add Menu Category with confKey $add->{confKey} requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
return $self->sendError(
|
||||
$req,
|
||||
"Invalid input: A Menu Category with confKey $add->{confKey} already exists",
|
||||
409
|
||||
) if ( defined $self->_getMenuCatByConfKey( $conf, $add->{confKey} ) );
|
||||
|
||||
my $res = $self->_pushMenuCat( $conf, $add->{confKey}, $add, 1 );
|
||||
|
||||
return $self->sendError( $req, $res->{msg}, 400 )
|
||||
unless ( $res->{res} eq 'ok' );
|
||||
|
||||
return $self->sendJSONresponse(
|
||||
$req,
|
||||
{ message => "Successful operation" },
|
||||
code => 201
|
||||
);
|
||||
}
|
||||
|
||||
sub updateMenuCat {
|
||||
my ( $self, $req ) = @_;
|
||||
my $confKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'confKey is missing', 400 );
|
||||
|
||||
my $update = $req->jsonBodyToObj;
|
||||
|
||||
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
|
||||
unless ($update);
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Menu Category $confKey configuration update requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
my $current = $self->_getMenuCatByConfKey( $conf, $confKey );
|
||||
|
||||
# Return 404 if not found
|
||||
|
||||
return $self->sendError( $req, "Menu category '$confKey' not found", 404 )
|
||||
unless ( defined $current );
|
||||
|
||||
my $res = $self->_pushMenuCat( $conf, $confKey, $update, 0 );
|
||||
|
||||
return $self->sendError( $req, $res->{msg}, 400 )
|
||||
unless ( $res->{res} eq 'ok' );
|
||||
|
||||
return $self->sendJSONresponse( $req, undef, code => 204 );
|
||||
}
|
||||
|
||||
sub replaceMenuCat {
|
||||
my ( $self, $req ) = @_;
|
||||
my $confKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'confKey is missing', 400 );
|
||||
|
||||
my $replace = $req->jsonBodyToObj;
|
||||
|
||||
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
|
||||
unless ($replace);
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is missing', 400 )
|
||||
unless ( defined $replace->{confKey} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is not a string',
|
||||
400 )
|
||||
if ( ref $replace->{confKey} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey contains invalid characters',
|
||||
400 )
|
||||
unless ( $replace->{confKey} =~ '^\w[\w\.\-]*$' );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: catname is missing', 400 )
|
||||
unless ( defined $replace->{catname} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: catname is not a string',
|
||||
400 )
|
||||
if ( ref $replace->{catname} );
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Menu Category $confKey configuration replace requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
# Return 404 if not found
|
||||
|
||||
return $self->sendError( $req, "Menu category '$confKey' not found", 404 )
|
||||
unless ( defined $self->_getMenuCatByConfKey( $conf, $confKey ) );
|
||||
|
||||
my $res = $self->_pushMenuCat( $conf, $confKey, $replace, 1 );
|
||||
return $self->sendError( $req, $res->{msg}, 400 )
|
||||
unless ( $res->{res} eq 'ok' );
|
||||
|
||||
return $self->sendJSONresponse( $req, undef, code => 204 );
|
||||
}
|
||||
|
||||
sub deleteMenuCat {
|
||||
my ( $self, $req ) = @_;
|
||||
my $confKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'confKey is missing', 400 );
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Menu Category $confKey configuration delete requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
my $delete = $self->_getMenuCatByConfKey( $conf, $confKey );
|
||||
|
||||
# Return 404 if not found
|
||||
|
||||
return $self->sendError( $req, "Menu category '$confKey' not found", 404 )
|
||||
unless ( defined $delete );
|
||||
|
||||
delete $conf->{applicationList}->{$confKey};
|
||||
|
||||
# Save configuration
|
||||
$self->_confAcc->saveConf($conf);
|
||||
|
||||
return $self->sendJSONresponse( $req, undef, code => 204 );
|
||||
}
|
||||
|
||||
sub _getMenuCatByConfKey {
|
||||
my ( $self, $conf, $confKey ) = @_;
|
||||
|
||||
# Check if confKey is defined
|
||||
return undef unless ( defined $conf->{applicationList}->{$confKey} );
|
||||
|
||||
my $menuCat = {
|
||||
confKey => $confKey,
|
||||
catname => $conf->{applicationList}->{$confKey}->{catname}
|
||||
};
|
||||
|
||||
$menuCat->{order} = $conf->{applicationList}->{$confKey}->{order}
|
||||
if ( defined $conf->{applicationList}->{$confKey}->{order} );
|
||||
|
||||
return $menuCat;
|
||||
}
|
||||
|
||||
sub _pushMenuCat {
|
||||
my ( $self, $conf, $confKey, $push, $replace ) = @_;
|
||||
|
||||
if ($replace) {
|
||||
$conf->{applicationList}->{$confKey} = {};
|
||||
$conf->{applicationList}->{$confKey}->{type} = "category";
|
||||
}
|
||||
|
||||
$conf->{applicationList}->{$confKey}->{order} = $push->{order}
|
||||
if ( defined $push->{order} );
|
||||
|
||||
$conf->{applicationList}->{$confKey}->{catname} = $push->{catname}
|
||||
if ( defined $push->{catname} );
|
||||
|
||||
# Test new configuration
|
||||
my $parser = Lemonldap::NG::Manager::Conf::Parser->new( {
|
||||
refConf => $self->_confAcc->getConf,
|
||||
newConf => $conf,
|
||||
req => {},
|
||||
}
|
||||
);
|
||||
unless ( $parser->testNewConf( $self->p ) ) {
|
||||
return {
|
||||
res => 'ko',
|
||||
code => 400,
|
||||
msg => "Configuration error: "
|
||||
. join( ". ", map { $_->{message} } @{ $parser->errors } ),
|
||||
};
|
||||
}
|
||||
|
||||
# Save configuration
|
||||
$self->_confAcc->saveConf($conf);
|
||||
|
||||
return { res => 'ok' };
|
||||
}
|
||||
|
||||
1;
|
130
lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api/Misc.pm
Normal file
130
lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api/Misc.pm
Normal file
|
@ -0,0 +1,130 @@
|
|||
# Miscenalleous endpoints
|
||||
package Lemonldap::NG::Manager::Api::Misc;
|
||||
|
||||
our $VERSION = '2.0.8';
|
||||
|
||||
package Lemonldap::NG::Manager::Api;
|
||||
extends 'Lemonldap::NG::Manager::Api::Common';
|
||||
|
||||
# Health-check endpoint
|
||||
sub status {
|
||||
my ( $self, $req ) = @_;
|
||||
my $code = 200;
|
||||
my $response = {
|
||||
name => "LemonLDAP::NG Manager API",
|
||||
version => $Lemonldap::NG::Manager::VERSION,
|
||||
status => "ok",
|
||||
status_config => "ok",
|
||||
status_sessions => "ok",
|
||||
status_psessions => "ok",
|
||||
};
|
||||
|
||||
# Test configuration backend
|
||||
my $conf =
|
||||
$self->_confAcc->getDBConf( { cfgNum => $self->_confAcc->lastCfg } );
|
||||
unless ( $conf->{cfgNum} ) {
|
||||
$code = 503;
|
||||
$response->{status} = "ko";
|
||||
$response->{status_config} = "ko";
|
||||
|
||||
}
|
||||
|
||||
# Test session backend
|
||||
my $status = $self->_getSessionDBState( $self->_getSSOMod );
|
||||
if ( $status == 0 ) {
|
||||
$code = 503;
|
||||
$response->{status} = "ko";
|
||||
$response->{status_sessions} = "ko";
|
||||
}
|
||||
elsif ( $status == 2 ) {
|
||||
$response->{status_sessions} = "unknown";
|
||||
}
|
||||
|
||||
# Test psession backend
|
||||
$status = $self->_getSessionDBState( $self->_getPersistentMod );
|
||||
if ( $status == 0 ) {
|
||||
$code = 503;
|
||||
$response->{status} = "ko";
|
||||
$response->{status_psessions} = "ko";
|
||||
}
|
||||
elsif ( $status == 2 ) {
|
||||
$response->{status_psessions} = "unknown";
|
||||
}
|
||||
|
||||
return $self->sendJSONresponse(
|
||||
$req, $response,
|
||||
code => $code,
|
||||
pretty => 1
|
||||
);
|
||||
}
|
||||
|
||||
# Apache::Session has no API for healthchecking yet. Until it does, we have to
|
||||
# break the encapsulation model to get the info. This needs to be reworked.
|
||||
# So far, we only implement the check for:
|
||||
# * Apache::Session::DBI
|
||||
# * Apache::Session::Browseable::DBI (Postgresq, MySQL)
|
||||
# * Apache::Session::MongoDB
|
||||
#
|
||||
# Returns 0 for ko, 1 for ok and 2 for unknown
|
||||
sub _getSessionDBState {
|
||||
my ( $self, $mod ) = @_;
|
||||
|
||||
my $fakeobj;
|
||||
|
||||
eval { $fakeobj = $self->_getObjectSessionModule($mod); };
|
||||
|
||||
# If we could not instanciate the session module directly, bail
|
||||
return 2 unless $fakeobj;
|
||||
|
||||
my $fakeobj_store = $fakeobj->{object_store};
|
||||
|
||||
# If the Apache::Session object does not have an object store, bail
|
||||
return 2 unless $fakeobj_store;
|
||||
|
||||
# Handle DBI-type session stores
|
||||
if ( $fakeobj->{object_store}->isa("Apache::Session::Store::DBI") ) {
|
||||
#
|
||||
# The 'connection' method will fail if the DB is unreachable
|
||||
# this is good enough a test for now
|
||||
eval { $fakeobj->{object_store}->connection($fakeobj) };
|
||||
if ($@) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Handle MongoDB
|
||||
if ( $fakeobj->{object_store}->isa("Apache::Session::Store::MongoDB") ) {
|
||||
|
||||
# Try to find collection
|
||||
eval {
|
||||
$fakeobj->{object_store}->connection($fakeobj);
|
||||
$fakeobj->{object_store}->{collection}->estimated_document_count;
|
||||
};
|
||||
if ($@) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
# We don't know
|
||||
return 2;
|
||||
|
||||
}
|
||||
|
||||
sub _getObjectSessionModule {
|
||||
my ( $self, $mod ) = @_;
|
||||
my $class = $mod->{module};
|
||||
eval "require $class;";
|
||||
|
||||
my $fakeSession = { args => $mod->{options}, };
|
||||
bless $fakeSession, $class;
|
||||
$fakeSession->populate;
|
||||
return $fakeSession;
|
||||
}
|
||||
|
||||
1;
|
|
@ -0,0 +1,407 @@
|
|||
package Lemonldap::NG::Manager::Api::Providers::CasApp;
|
||||
|
||||
our $VERSION = '2.0.9';
|
||||
|
||||
package Lemonldap::NG::Manager::Api;
|
||||
|
||||
use 5.10.0;
|
||||
use utf8;
|
||||
use Mouse;
|
||||
use Lemonldap::NG::Manager::Conf::Parser;
|
||||
|
||||
extends 'Lemonldap::NG::Manager::Api::Common';
|
||||
|
||||
|
||||
sub getCasAppByConfKey {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my $confKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'confKey is missing', 400 );
|
||||
|
||||
$self->logger->debug("[API] CAS App $confKey configuration requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf;
|
||||
|
||||
my $casApp = $self->_getCasAppByConfKey( $conf, $confKey );
|
||||
|
||||
# Return 404 if not found
|
||||
return $self->sendError( $req,
|
||||
"CAS application '$confKey' not found", 404 )
|
||||
unless ( defined $casApp );
|
||||
|
||||
return $self->sendJSONresponse( $req, $casApp );
|
||||
}
|
||||
|
||||
sub findCasAppByConfKey {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my $pattern = (
|
||||
defined $req->params('uPattern')
|
||||
? $req->params('uPattern')
|
||||
: ( defined $req->params('pattern') ? $req->params('pattern') : undef )
|
||||
);
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: pattern is missing', 400 )
|
||||
unless ( defined $pattern );
|
||||
|
||||
unless ( $pattern = $self->_getRegexpFromPattern($pattern) ) {
|
||||
return $self->sendError( $req, 'Invalid input: pattern is invalid',
|
||||
400 );
|
||||
}
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Find CAS Apps by confKey regexp $pattern requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf;
|
||||
|
||||
my @casApps =
|
||||
map { $_ =~ $pattern ? $self->_getCasAppByConfKey( $conf, $_ ) : () }
|
||||
keys %{ $conf->{casAppMetaDataOptions} };
|
||||
|
||||
return $self->sendJSONresponse( $req, [@casApps] );
|
||||
}
|
||||
|
||||
sub findCasAppsByServiceUrl {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my $serviceUrl = (
|
||||
defined $req->params('uServiceUrl') ? $req->params('uServiceUrl')
|
||||
: (
|
||||
defined $req->params('serviceUrl') ? $req->params('serviceUrl')
|
||||
: undef
|
||||
)
|
||||
);
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: serviceUrl is missing', 400 )
|
||||
unless ( defined $serviceUrl );
|
||||
|
||||
$self->logger->debug("[API] Find CAS Apps by service URL $serviceUrl requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf;
|
||||
|
||||
my $casApp = $self->_getCasAppByServiceUrl( $conf, $serviceUrl );
|
||||
return $self->sendError( $req,
|
||||
"CAS application with service '$serviceUrl' not found", 404 )
|
||||
unless ( defined $casApp );
|
||||
|
||||
return $self->sendJSONresponse( $req, $casApp );
|
||||
}
|
||||
|
||||
sub addCasApp {
|
||||
my ( $self, $req ) = @_;
|
||||
my $add = $req->jsonBodyToObj;
|
||||
|
||||
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
|
||||
unless ($add);
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is missing', 400 )
|
||||
unless ( defined $add->{confKey} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is not a string',
|
||||
400 )
|
||||
if ( ref $add->{confKey} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: service is missing', 400 )
|
||||
unless ( defined $add->{options}->{service} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: service is not a string',
|
||||
400 )
|
||||
if ( ref $add->{options}->{service} );
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] Add CAS App with confKey $add->{confKey} requested"
|
||||
);
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
return $self->sendError(
|
||||
$req,
|
||||
"Invalid input: A CAS App with confKey $add->{confKey} already exists",
|
||||
409
|
||||
) if ( defined $self->_getCasAppByConfKey( $conf, $add->{confKey} ) );
|
||||
|
||||
my $res =
|
||||
$self->_getCasAppByServiceUrl( $conf, $add->{options}->{service} );
|
||||
if ( defined $res ) {
|
||||
my $conflict = $res->{options}->{service};
|
||||
return $self->sendError(
|
||||
$req,
|
||||
"Invalid input: A CAS application with service URL $conflict already exists",
|
||||
409
|
||||
);
|
||||
}
|
||||
|
||||
$res = $self->_pushCasApp( $conf, $add->{confKey}, $add, 1 );
|
||||
|
||||
return $self->sendError( $req, $res->{msg}, 400 )
|
||||
unless ( $res->{res} eq 'ok' );
|
||||
|
||||
return $self->sendJSONresponse(
|
||||
$req,
|
||||
{ message => "Successful operation" },
|
||||
code => 201
|
||||
);
|
||||
}
|
||||
|
||||
sub updateCasApp {
|
||||
my ( $self, $req ) = @_;
|
||||
my $confKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'confKey is missing', 400 );
|
||||
|
||||
my $update = $req->jsonBodyToObj;
|
||||
|
||||
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
|
||||
unless ($update);
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] CAS App $confKey configuration update requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
my $current = $self->_getCasAppByConfKey( $conf, $confKey );
|
||||
|
||||
# Return 404 if not found
|
||||
|
||||
return $self->sendError( $req,
|
||||
"CAS application '$confKey' not found", 404 )
|
||||
unless ( defined $current );
|
||||
|
||||
# check if new clientID exists already
|
||||
my $res = $self->_isNewCasAppServiceUrlUnique( $conf, $confKey, $update );
|
||||
|
||||
return $self->sendError( $req, $res->{msg}, 409 )
|
||||
unless ( $res->{res} eq 'ok' );
|
||||
|
||||
$res = $self->_pushCasApp( $conf, $confKey, $update, 0 );
|
||||
|
||||
return $self->sendError( $req, $res->{msg}, 400 )
|
||||
unless ( $res->{res} eq 'ok' );
|
||||
|
||||
return $self->sendJSONresponse( $req, undef, code => 204 );
|
||||
}
|
||||
|
||||
sub replaceCasApp {
|
||||
my ( $self, $req ) = @_;
|
||||
my $confKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'confKey is missing', 400 );
|
||||
|
||||
my $replace = $req->jsonBodyToObj;
|
||||
|
||||
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
|
||||
unless ($replace);
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is missing', 400 )
|
||||
unless ( defined $replace->{confKey} );
|
||||
|
||||
return $self->sendError( $req, 'Invalid input: confKey is not a string',
|
||||
400 )
|
||||
if ( ref $replace->{confKey} );
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] CAS App $confKey configuration replace requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
# Return 404 if not found
|
||||
|
||||
return $self->sendError( $req,
|
||||
"CAS application '$confKey' not found", 404 )
|
||||
unless ( defined $self->_getCasAppByConfKey( $conf, $confKey ) );
|
||||
|
||||
# check if new clientID exists already
|
||||
my $res = $self->_isNewCasAppServiceUrlUnique( $conf, $confKey, $replace );
|
||||
return $self->sendError( $req, $res->{msg}, 409 )
|
||||
unless ( $res->{res} eq 'ok' );
|
||||
|
||||
$res = $self->_pushCasApp( $conf, $confKey, $replace, 1 );
|
||||
return $self->sendError( $req, $res->{msg}, 400 )
|
||||
unless ( $res->{res} eq 'ok' );
|
||||
|
||||
return $self->sendJSONresponse( $req, undef, code => 204 );
|
||||
}
|
||||
|
||||
sub deleteCasApp {
|
||||
my ( $self, $req ) = @_;
|
||||
my $confKey = $req->params('confKey')
|
||||
or return $self->sendError( $req, 'confKey is missing', 400 );
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] CAS App $confKey configuration delete requested");
|
||||
|
||||
# Get latest configuration
|
||||
my $conf = $self->_confAcc->getConf( { noCache => 1 } );
|
||||
|
||||
my $delete = $self->_getCasAppByConfKey( $conf, $confKey );
|
||||
|
||||
# Return 404 if not found
|
||||
|
||||
return $self->sendError( $req,
|
||||
"CAS application '$confKey' not found", 404 )
|
||||
unless ( defined $delete );
|
||||
|
||||
delete $conf->{casAppMetaDataOptions}->{$confKey};
|
||||
delete $conf->{casAppMetaDataExportedVars}->{$confKey};
|
||||
delete $conf->{casAppMetaDataMacros}->{$confKey};
|
||||
|
||||
# Save configuration
|
||||
$self->_confAcc->saveConf($conf);
|
||||
|
||||
return $self->sendJSONresponse( $req, undef, code => 204 );
|
||||
}
|
||||
|
||||
|
||||
sub _getCasAppByConfKey {
|
||||
my ( $self, $conf, $confKey ) = @_;
|
||||
|
||||
# Check if confKey is defined
|
||||
return undef unless ( defined $conf->{casAppMetaDataOptions}->{$confKey} );
|
||||
|
||||
# Get exported vars
|
||||
my $exportedVars = $conf->{casAppMetaDataExportedVars}->{$confKey};
|
||||
|
||||
# # Get extra claim
|
||||
# my $extraClaims = $conf->{casAppMetaDataOptionsExtraClaims}->{$confKey};
|
||||
|
||||
# Get macros
|
||||
my $macros = $conf->{casAppMetaDataMacros}->{$confKey} || {};
|
||||
|
||||
# Get options
|
||||
my $options = {};
|
||||
for
|
||||
my $configOption ( keys %{ $conf->{casAppMetaDataOptions}->{$confKey} } )
|
||||
{
|
||||
$options->{ $self->_translateOptionConfToApi($configOption) } =
|
||||
$conf->{casAppMetaDataOptions}->{$confKey}->{$configOption};
|
||||
}
|
||||
|
||||
return {
|
||||
confKey => $confKey,
|
||||
exportedVars => $exportedVars,
|
||||
macros => $macros,
|
||||
options => $options
|
||||
};
|
||||
}
|
||||
|
||||
sub _getCasAppByServiceUrl {
|
||||
my ( $self, $conf, $serviceUrl ) = @_;
|
||||
|
||||
my ($serviceHost) = $serviceUrl =~ m#^(https?://[^/]+)(?:/.*)?$#;
|
||||
return undef unless $serviceHost;
|
||||
foreach ( keys %{ $conf->{casAppMetaDataOptions} } ) {
|
||||
my $url =
|
||||
$conf->{casAppMetaDataOptions}->{$_}->{casAppMetaDataOptionsService};
|
||||
my ($curHost) = $url =~ m#^(https?://[^/]+)(?:/.*)?$#;
|
||||
if ( $serviceHost eq $curHost ) {
|
||||
return $self->_getCasAppByConfKey( $conf, $_ );
|
||||
}
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub _isNewCasAppServiceUrlUnique {
|
||||
my ( $self, $conf, $confKey, $casApp ) = @_;
|
||||
my $curServiceUrl = $self->_getCasAppByConfKey( $conf, $confKey )->{options}->{service};
|
||||
my $newServiceUrl = $casApp->{options}->{service} || "";
|
||||
if ( $newServiceUrl ne '' && $newServiceUrl ne $curServiceUrl ) {
|
||||
return {
|
||||
res => 'ko',
|
||||
msg =>
|
||||
"A CAS application with service URL '$newServiceUrl' already exists"
|
||||
}
|
||||
if ( defined $self->_getCasAppByServiceUrl( $conf, $newServiceUrl ) );
|
||||
}
|
||||
|
||||
return { res => 'ok' };
|
||||
}
|
||||
|
||||
sub _pushCasApp {
|
||||
my ( $self, $conf, $confKey, $push, $replace ) = @_;
|
||||
|
||||
my $translatedOptions = {};
|
||||
if ($replace) {
|
||||
$conf->{casAppMetaDataOptions}->{$confKey} = {};
|
||||
$conf->{casAppMetaDataExportedVars}->{$confKey} = {};
|
||||
$conf->{casAppMetaDataMacros}->{$confKey} = {};
|
||||
$translatedOptions = $self->_getDefaultValues('casAppMetaDataNodes');
|
||||
}
|
||||
|
||||
if ( defined $push->{options} ) {
|
||||
|
||||
foreach ( keys %{ $push->{options} } ) {
|
||||
$translatedOptions->{ $self->_translateOptionApiToConf( $_,
|
||||
'casApp' ) } = $push->{options}->{$_};
|
||||
}
|
||||
|
||||
my $res = $self->_hasAllowedAttributes( $translatedOptions,
|
||||
'casAppMetaDataNode' );
|
||||
return $res unless ( $res->{res} eq 'ok' );
|
||||
|
||||
foreach ( keys %{$translatedOptions} ) {
|
||||
$conf->{casAppMetaDataOptions}->{$confKey}->{$_} =
|
||||
$translatedOptions->{$_};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( defined $push->{exportedVars} ) {
|
||||
if ( $self->_isSimpleKeyValueHash( $push->{exportedVars} ) ) {
|
||||
foreach ( keys %{ $push->{exportedVars} } ) {
|
||||
$conf->{casAppMetaDataExportedVars}->{$confKey}->{$_} =
|
||||
$push->{exportedVars}->{$_};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return {
|
||||
res => 'ko',
|
||||
msg =>
|
||||
"Invalid input: exportedVars is not a hash object with \"key\":\"value\" attributes"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if ( defined $push->{macros} ) {
|
||||
if ( $self->_isSimpleKeyValueHash( $push->{macros} ) ) {
|
||||
foreach ( keys %{ $push->{macros} } ) {
|
||||
$conf->{casAppMetaDataMacros}->{$confKey}->{$_} =
|
||||
$push->{macros}->{$_};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return {
|
||||
res => 'ko',
|
||||
msg =>
|
||||
"Invalid input: macros is not a hash object with \"key\":\"value\" attributes"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
# Test new configuration
|
||||
my $parser = Lemonldap::NG::Manager::Conf::Parser->new( {
|
||||
refConf => $self->_confAcc->getConf,
|
||||
newConf => $conf,
|
||||
req => {},
|
||||
}
|
||||
);
|
||||
unless ( $parser->testNewConf( $self->p ) ) {
|
||||
return {
|
||||
res => 'ko',
|
||||
code => 400,
|
||||
msg => "Configuration error: "
|
||||
. join( ". ", map { $_->{message} } @{ $parser->errors } ),
|
||||
};
|
||||
}
|
||||
|
||||
# Save configuration
|
||||
$self->_confAcc->saveConf($conf);
|
||||
|
||||
return { res => 'ok' };
|
||||
}
|
||||
|
||||
1;
|
|
@ -252,7 +252,7 @@ m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\
|
|||
'form' => 'text',
|
||||
'msgFail' => '__badUrl__',
|
||||
'test' =>
|
||||
qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-9]*[a-zA-Z0-9]|[a-zA-Z])[.]?)|(?:[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+)))(?::(?:(?:[0-9]*)))?(?:\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+\$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*)(?:;(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+\$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*))*)(?:\/(?:(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+\$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*)(?:;(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+\$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*))*))*))(?:[?](?:(?:(?:[;\/?:@&=+\$,a-zA-Z0-9\-_.!~*'()]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*)))?))?)/
|
||||
qr/(?:^$|(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-9]*[a-zA-Z0-9]|[a-zA-Z])[.]?)|(?:[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+)))(?::(?:(?:[0-9]*)))?(?:\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+\$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*)(?:;(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+\$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*))*)(?:\/(?:(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+\$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*)(?:;(?:(?:[a-zA-Z0-9\-_.!~*'():@&=+\$,]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*))*))*))(?:[?](?:(?:(?:[;\/?:@&=+\$,a-zA-Z0-9\-_.!~*'()]+|(?:%[a-fA-F0-9][a-fA-F0-9]))*)))?))?))/
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -636,7 +636,7 @@ sub attributes {
|
|||
'type' => 'bool'
|
||||
},
|
||||
'bruteForceProtectionLockTimes' => {
|
||||
'default' => '5 15 60 300 600',
|
||||
'default' => '5, 15, 60, 300, 600',
|
||||
'type' => 'text'
|
||||
},
|
||||
'bruteForceProtectionMaxAge' => {
|
||||
|
@ -1651,8 +1651,7 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
|
|||
'type' => 'text'
|
||||
},
|
||||
'ldapPort' => {
|
||||
'default' => 389,
|
||||
'type' => 'int'
|
||||
'type' => 'int'
|
||||
},
|
||||
'ldapPpolicyControl' => {
|
||||
'default' => 0,
|
||||
|
@ -1743,7 +1742,7 @@ m[^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
|||
'localSessionStorageOptions' => {
|
||||
'default' => {
|
||||
'cache_depth' => 3,
|
||||
'cache_root' => '/tmp',
|
||||
'cache_root' => '/var/cache/lemonldap-ng',
|
||||
'default_expires_in' => 600,
|
||||
'directory_umask' => '007',
|
||||
'namespace' => 'lemonldap-ng-sessions'
|
||||
|
@ -2581,7 +2580,7 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
|
|||
'type' => 'boolOrExpr'
|
||||
},
|
||||
'portalDisplayOidcConsents' => {
|
||||
'default' => '$_oidcConsents',
|
||||
'default' => '$_oidcConsents && $_oidcConsents =~ /\\w+/',
|
||||
'type' => 'boolOrExpr'
|
||||
},
|
||||
'portalDisplayPasswordPolicy' => {
|
||||
|
@ -2922,8 +2921,12 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
|
|||
'type' => 'url'
|
||||
},
|
||||
'sameSite' => {
|
||||
'default' => 'None',
|
||||
'default' => '',
|
||||
'select' => [ {
|
||||
'k' => '',
|
||||
'v' => ''
|
||||
},
|
||||
{
|
||||
'k' => 'Strict',
|
||||
'v' => 'Strict'
|
||||
},
|
||||
|
|
|
@ -326,6 +326,12 @@ use constant HANDLERSECTION => "handler";
|
|||
use constant MANAGERSECTION => "manager";
|
||||
use constant SESSIONSEXPLORERSECTION => "sessionsExplorer";
|
||||
use constant APPLYSECTION => "apply";
|
||||
|
||||
# Default configuration backend
|
||||
use constant DEFAULTCONFBACKEND => "File";
|
||||
use constant DEFAULTCONFBACKENDOPTIONS => (
|
||||
dirName => '/usr/local/lemonldap-ng/data/conf',
|
||||
);
|
||||
$confConstants
|
||||
our \@sessionTypes = ( '$sessionTypes' );
|
||||
|
||||
|
@ -348,6 +354,8 @@ our %EXPORT_TAGS = (
|
|||
MANAGERSECTION
|
||||
SESSIONSEXPLORERSECTION
|
||||
APPLYSECTION
|
||||
DEFAULTCONFBACKEND
|
||||
DEFAULTCONFBACKENDOPTIONS
|
||||
NO
|
||||
\$hashParameters
|
||||
\@sessionTypes
|
||||
|
@ -425,7 +433,7 @@ sub buildZeroConf {
|
|||
open( F, '>', $self->firstLmConfFile ) or die($!);
|
||||
my $tmp = Lemonldap::NG::Manager::Conf::Zero::zeroConf(
|
||||
'__DNSDOMAIN__', '__SESSIONDIR__',
|
||||
'__PSESSIONDIR__', '__NOTIFICATIONDIR__'
|
||||
'__PSESSIONDIR__', '__NOTIFICATIONDIR__', '__CACHEDIR__'
|
||||
);
|
||||
$tmp->{cfgNum} = 1;
|
||||
print F $jsonEnc->encode($tmp);
|
||||
|
|
|
@ -30,9 +30,10 @@ sub perlExpr {
|
|||
return $err ? ( -1, "__badExpression__: $err" ) : (1);
|
||||
}
|
||||
|
||||
my $url = $RE{URI}{HTTP}{ -scheme => "https?" };
|
||||
$url =~ s/(?<=[^\\])\$/\\\$/g;
|
||||
$url = qr/$url/;
|
||||
my $url_re = $RE{URI}{HTTP}{ -scheme => "https?" };
|
||||
$url_re =~ s/(?<=[^\\])\$/\\\$/g;
|
||||
my $url = qr/$url_re/;
|
||||
my $urlOrEmpty = qr/(?:^$|$url_re)/;
|
||||
|
||||
sub types {
|
||||
return {
|
||||
|
@ -51,7 +52,7 @@ sub types {
|
|||
},
|
||||
url => {
|
||||
form => 'text',
|
||||
test => $url,
|
||||
test => $urlOrEmpty,
|
||||
msgFail => '__badUrl__',
|
||||
},
|
||||
PerlModule => {
|
||||
|
@ -844,7 +845,7 @@ sub attributes {
|
|||
},
|
||||
bruteForceProtectionLockTimes => {
|
||||
type => 'text',
|
||||
default => '5 15 60 300 600',
|
||||
default => '5, 15, 60, 300, 600',
|
||||
documentation =>
|
||||
'Incremental lock time values for brute force attack protection',
|
||||
},
|
||||
|
@ -1099,7 +1100,7 @@ sub attributes {
|
|||
},
|
||||
portalDisplayOidcConsents => {
|
||||
type => 'boolOrExpr',
|
||||
default => '$_oidcConsents',
|
||||
default => '$_oidcConsents && $_oidcConsents =~ /\w+/',
|
||||
documentation => 'Display OIDC consent tab in portal',
|
||||
},
|
||||
portalDisplayGeneratePassword => {
|
||||
|
@ -1165,11 +1166,12 @@ sub attributes {
|
|||
sameSite => {
|
||||
type => 'select',
|
||||
select => [
|
||||
{ k => '', v => '' },
|
||||
{ k => 'Strict', v => 'Strict' },
|
||||
{ k => 'Lax', v => 'Lax' },
|
||||
{ k => 'None', v => 'None' },
|
||||
],
|
||||
default => 'None',
|
||||
default => '',
|
||||
documentation => 'Cookie SameSite value',
|
||||
flags => 'hp',
|
||||
},
|
||||
|
@ -1346,7 +1348,7 @@ sub attributes {
|
|||
'namespace' => 'lemonldap-ng-sessions',
|
||||
'default_expires_in' => 600,
|
||||
'directory_umask' => '007',
|
||||
'cache_root' => '/tmp',
|
||||
'cache_root' => '/var/cache/lemonldap-ng',
|
||||
'cache_depth' => 3,
|
||||
},
|
||||
documentation => 'Sessions cache module options',
|
||||
|
@ -3130,7 +3132,6 @@ sub attributes {
|
|||
},
|
||||
ldapPort => {
|
||||
type => 'int',
|
||||
default => 389,
|
||||
documentation => 'LDAP port',
|
||||
},
|
||||
ldapServer => {
|
||||
|
|
|
@ -642,7 +642,8 @@ sub tree {
|
|||
'notificationStorageOptions',
|
||||
{
|
||||
title => 'serverNotification',
|
||||
help => 'notifications.html#notification-server',
|
||||
help =>
|
||||
'notifications.html#notification-server',
|
||||
nodes => [
|
||||
'notificationServer',
|
||||
'notificationDefaultCond',
|
||||
|
@ -971,7 +972,10 @@ sub tree {
|
|||
form => 'simpleInputContainer',
|
||||
nodes => [
|
||||
'bruteForceProtection',
|
||||
'bruteForceProtectionTempo',
|
||||
'bruteForceProtectionMaxFailed',
|
||||
'bruteForceProtectionIncrementalTempo',
|
||||
'bruteForceProtectionLockTimes',
|
||||
]
|
||||
},
|
||||
'lwpOpts',
|
||||
|
|
|
@ -159,7 +159,7 @@ sub prx {
|
|||
# - getConfByNum: override SUPER method to be able to use Zero
|
||||
# - newConf()
|
||||
# - newRawConf(): restore a saved conf
|
||||
# - applyConf(): called by the 2 previous to prevent other servers that a new
|
||||
# - applyConf(): called by the 2 previous to inform other servers that a new
|
||||
# configuration is available
|
||||
|
||||
sub getConfByNum {
|
||||
|
@ -229,7 +229,7 @@ sub newConf {
|
|||
|
||||
if ( $cfgNum ne $req->params('cfgNum') ) { $parser->confChanged(1); }
|
||||
|
||||
my $res = { result => $parser->check($self) };
|
||||
my $res = { result => $parser->check($self->p) };
|
||||
|
||||
# "message" fields: note that words enclosed by "__" (__word__) will be
|
||||
# translated
|
||||
|
@ -328,7 +328,7 @@ sub newRawConf {
|
|||
}
|
||||
|
||||
## @method private applyConf()
|
||||
# Try to prevent other servers declared in `reloadUrls` that a new
|
||||
# Try to inform other servers declared in `reloadUrls` that a new
|
||||
# configuration is available.
|
||||
#
|
||||
#@return reload status as boolean
|
||||
|
@ -352,6 +352,7 @@ sub applyConf {
|
|||
# Parse apply values
|
||||
while ( my ( $host, $request ) = each %reloadUrls ) {
|
||||
my $r = HTTP::Request->new( 'GET', "http://$host$request" );
|
||||
$self->logger->debug("Sending reload request to $host");
|
||||
if ( $request =~ /^https?:\/\/[^\/]+.*$/ ) {
|
||||
my $url = URI::URL->new($request);
|
||||
my $targetUrl = $url->scheme . "://" . $host;
|
||||
|
|
|
@ -3,6 +3,7 @@ package Lemonldap::NG::Manager::Conf::Tests;
|
|||
use utf8;
|
||||
use Lemonldap::NG::Common::Regexp;
|
||||
use Lemonldap::NG::Handler::Main;
|
||||
use Lemonldap::NG::Common::Util qw(getSameSite);
|
||||
|
||||
our $VERSION = '2.1.0';
|
||||
|
||||
|
@ -253,8 +254,6 @@ sub tests {
|
|||
return ( 1, "Cookie TTL should be higher or equal than one hour" )
|
||||
unless ( $conf->{cookieExpiration} >= 3600
|
||||
|| $conf->{cookieExpiration} == 0 );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -264,8 +263,6 @@ sub tests {
|
|||
return ( -1, "Session timeout should be higher than ten minutes" )
|
||||
unless ( $conf->{timeout} > 600
|
||||
|| $conf->{timeout} == 0 );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -277,8 +274,6 @@ sub tests {
|
|||
)
|
||||
unless ( $conf->{timeoutActivity} > 59
|
||||
|| $conf->{timeoutActivity} == 0 );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -291,8 +286,6 @@ sub tests {
|
|||
if ( $conf->{timeoutActivity}
|
||||
and $conf->{timeoutActivity} <=
|
||||
$conf->{timeoutActivityInterval} );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -337,12 +330,10 @@ sub tests {
|
|||
return ( 1, "SMTP authentication failed" )
|
||||
unless $smtp->auth( $conf->{SMTPAuthUser},
|
||||
$conf->{SMTPAuthPass} );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
# SAML entity ID must be uniq
|
||||
# SAML entity ID must be unique
|
||||
samlIDPEntityIdUniqueness => sub {
|
||||
return 1
|
||||
unless ( $conf->{samlIDPMetaDataXML}
|
||||
|
@ -440,8 +431,6 @@ sub tests {
|
|||
unless ( $conf->{combination} );
|
||||
return ( 0, 'userDB must be set to "Same" to enable Combination' )
|
||||
unless ( $conf->{userDB} eq "Same" );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -481,8 +470,6 @@ sub tests {
|
|||
"Auth::Yubikey_WebClient module is required to enable Yubikey"
|
||||
) if ($@);
|
||||
}
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -520,8 +507,6 @@ sub tests {
|
|||
unless ( $conf->{totp2fRange} );
|
||||
return ( 1, "TOTP interval should be higher than 10s" )
|
||||
unless ( $conf->{totp2fInterval} > 10 );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -569,7 +554,6 @@ sub tests {
|
|||
|| $conf->{'totp2fSelfRegistration'} );
|
||||
$msg = "A self registrable module should be enabled to require 2FA"
|
||||
unless ($ok);
|
||||
|
||||
return ( 1, $msg );
|
||||
},
|
||||
|
||||
|
@ -582,8 +566,6 @@ sub tests {
|
|||
return ( 0, "External 2F Validate command must be set" )
|
||||
unless ( defined $conf->{ext2FValidateCommand} );
|
||||
}
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -594,8 +576,6 @@ sub tests {
|
|||
unless ( $conf->{formTimeout} > 30 );
|
||||
return ( 1, "XSRF form token TTL should not be higher than 2mn" )
|
||||
if ( $conf->{formTimeout} > 120 );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -606,8 +586,6 @@ sub tests {
|
|||
unless ( $conf->{issuersTimeout} > 30 );
|
||||
return ( 1, "Issuers token TTL should not be higher than 2mn" )
|
||||
if ( $conf->{issuersTimeout} > 120 );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -616,21 +594,16 @@ sub tests {
|
|||
return 1 unless ( $conf->{portalDisplayResetPassword} );
|
||||
return ( 1, "Number of reset password retries should not be null" )
|
||||
unless ( $conf->{passwordResetAllowedRetries} );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
# Warn if ldapPpolicyControl is used with AD (#2007)
|
||||
|
||||
ppolicyAd => sub {
|
||||
if ( $conf->{ldapPpolicyControl}
|
||||
and $conf->{authentication} eq "AD" )
|
||||
{
|
||||
return ( 1,
|
||||
return ( 1,
|
||||
"LDAP password policy control should be disabled when using AD authentication"
|
||||
);
|
||||
}
|
||||
)
|
||||
if ( $conf->{ldapPpolicyControl}
|
||||
and $conf->{authentication} eq "AD" );
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -643,8 +616,18 @@ sub tests {
|
|||
return ( 1,
|
||||
'Number of failed logins must be higher than 2 to enable "BruteForceProtection" plugin'
|
||||
) unless ( $conf->{failedLoginNumber} > 2 );
|
||||
|
||||
# Return
|
||||
return ( 1,
|
||||
'Number of failed logins history must be higher than allowed failed logins plus lock time values'
|
||||
)
|
||||
if ( $conf->{bruteForceProtectionIncrementalTempo}
|
||||
&& $conf->{failedLoginNumber} <=
|
||||
$conf->{bruteForceProtectionMaxFailed} +
|
||||
$conf->{bruteForceProtectionLockTimes} );
|
||||
return ( 1,
|
||||
'Number of failed logins history must be higher than allowed failed logins'
|
||||
)
|
||||
unless ( $conf->{failedLoginNumber} >
|
||||
$conf->{bruteForceProtectionMaxFailed} );
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -656,8 +639,6 @@ sub tests {
|
|||
)
|
||||
unless ( $conf->{requireToken}
|
||||
or $conf->{captcha_mail_enabled} );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -668,8 +649,6 @@ sub tests {
|
|||
)
|
||||
if ( $conf->{impersonationRule}
|
||||
&& $conf->{contextSwitchingRule} );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -693,8 +672,6 @@ sub tests {
|
|||
return ( 1,
|
||||
"BruteForceProtection plugin enabled WITHOUT persistent session storage"
|
||||
) if ( $conf->{bruteForceProtection} );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -709,8 +686,6 @@ sub tests {
|
|||
return ( 1,
|
||||
"XML::LibXSLT module is required to enable old format notifications"
|
||||
) if ($@);
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -724,8 +699,6 @@ sub tests {
|
|||
return ( 1,
|
||||
"DateTime::Format::RFC3339 module is required to enable CertificateResetByMail plugin"
|
||||
) if ($@);
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
@ -770,6 +743,71 @@ sub tests {
|
|||
return 1;
|
||||
},
|
||||
|
||||
# OIDC RP Client ID must exist and be unique
|
||||
oidcRPClientIdUniqueness => sub {
|
||||
return 1
|
||||
unless ( $conf->{oidcRPMetaDataOptions}
|
||||
and %{ $conf->{oidcRPMetaDataOptions} } );
|
||||
my @msg;
|
||||
my $res = 1;
|
||||
my %clientIds;
|
||||
foreach
|
||||
my $clientConfKey ( keys %{ $conf->{oidcRPMetaDataOptions} } )
|
||||
{
|
||||
my $clientId = $conf->{oidcRPMetaDataOptions}->{$clientConfKey}
|
||||
->{oidcRPMetaDataOptionsClientID};
|
||||
unless ($clientId) {
|
||||
push @msg,
|
||||
"$clientConfKey OIDC Relying Party has no Client ID";
|
||||
$res = 0;
|
||||
next;
|
||||
}
|
||||
|
||||
if ( defined $clientIds{$clientId} ) {
|
||||
push @msg,
|
||||
"$clientConfKey and $clientIds{$clientId} have the same Client ID";
|
||||
$res = 0;
|
||||
next;
|
||||
}
|
||||
$clientIds{$clientId} = $clientConfKey;
|
||||
}
|
||||
return ( $res, join( ', ', @msg ) );
|
||||
},
|
||||
|
||||
# CAS APP URL must be unique
|
||||
casAppHostnameUniqueness => sub {
|
||||
return 1
|
||||
unless ( $conf->{casAppMetaDataOptions}
|
||||
and %{ $conf->{casAppMetaDataOptions} } );
|
||||
my @msg;
|
||||
my $res = 1;
|
||||
my %casHosts;
|
||||
foreach my $casConfKey ( keys %{ $conf->{casAppMetaDataOptions} } )
|
||||
{
|
||||
my $appUrl =
|
||||
$conf->{casAppMetaDataOptions}->{$casConfKey}
|
||||
->{casAppMetaDataOptionsService}
|
||||
|| "";
|
||||
$appUrl =~ m#^(https?://[^/]+)(/.*)?$#;
|
||||
my $appHost = $1;
|
||||
unless ($appHost) {
|
||||
push @msg,
|
||||
"$clientConfKey CAS Application has no Service URL";
|
||||
$res = 0;
|
||||
next;
|
||||
}
|
||||
|
||||
if ( defined $casHosts{$appHost} ) {
|
||||
push @msg,
|
||||
"$casConfKey and $casHosts{$appHost} have the same Service hostname";
|
||||
$res = 0;
|
||||
next;
|
||||
}
|
||||
$casHosts{$appHost} = $casConfKey;
|
||||
}
|
||||
return ( $res, join( ', ', @msg ) );
|
||||
},
|
||||
|
||||
# Notification system required with removed SF notification
|
||||
sfRemovedNotification => sub {
|
||||
return 1 unless ( $conf->{sfRemovedMsgRule} );
|
||||
|
@ -778,6 +816,32 @@ sub tests {
|
|||
) if ( $conf->{sfRemovedUseNotif} and not $conf->{notification} );
|
||||
return 1;
|
||||
},
|
||||
|
||||
# noAjaxHook and krbByJs are incompatible (#2237)
|
||||
noAjaxHookwithKrb => sub {
|
||||
return ( 1,
|
||||
'noAjaxHook is not compatible with'
|
||||
. ' AJAX Kerberos authentication' )
|
||||
if ( $conf->{noAjaxHook} and $conf->{krbByJs} );
|
||||
return 1;
|
||||
},
|
||||
|
||||
# Cookie SameSite=None requires Secure flag
|
||||
# Same with SameSite=(auto) and SAML issuer in use
|
||||
SameSiteNoneWithSecure => sub {
|
||||
return ( 1, 'SameSite value = None requires the secured flag' )
|
||||
if ( getSameSite($conf) eq 'None' and !$conf->{securedCookie} );
|
||||
return 1;
|
||||
},
|
||||
|
||||
# Secure cookies require HTTPS
|
||||
SecureCookiesRequireHttps => sub {
|
||||
return ( 1, 'Secure cookies require a HTTPS portal URL' )
|
||||
if ( $conf->{securedCookie} == 1
|
||||
and $conf->{portal}
|
||||
and $conf->{portal} !~ /^https:/ );
|
||||
return 1;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,12 @@ package Lemonldap::NG::Manager::Conf::Zero;
|
|||
our $VERSION = '2.1.0';
|
||||
|
||||
sub zeroConf {
|
||||
my ( $domain, $sessionDir, $persistentSessionDir, $notificationDir ) = @_;
|
||||
my ( $domain, $sessionDir, $persistentSessionDir, $notificationDir, $cacheDir ) = @_;
|
||||
$domain ||= 'example.com';
|
||||
$sessionDir ||= '/var/lib/lemonldap-ng/sessions';
|
||||
$persistentSessionDir ||= '/var/lib/lemonldap-ng/psessions';
|
||||
$notificationDir ||= '/var/lib/lemonldap-ng/notifications';
|
||||
$cacheDir ||= '/var/cache/lemonldap-ng/';
|
||||
return {
|
||||
'timeout' => 72000,
|
||||
'loginHistoryEnabled' => 1,
|
||||
|
@ -187,7 +188,7 @@ sub zeroConf {
|
|||
'namespace' => 'lemonldap-ng-sessions',
|
||||
'default_expires_in' => 600,
|
||||
'directory_umask' => '007',
|
||||
'cache_root' => '/tmp',
|
||||
'cache_root' => "$cacheDir",
|
||||
'cache_depth' => 3,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -154,7 +154,11 @@ sub notifications {
|
|||
or die "Unknown type $type";
|
||||
|
||||
# Case 1: a notification is required
|
||||
return $self->notification( $req, $notif, $type ) if ($notif);
|
||||
if ($notif) {
|
||||
my $params = $req->parameters();
|
||||
return $self->notification( $req, $notif, $type, $params->{uid},
|
||||
$params->{reference} );
|
||||
}
|
||||
|
||||
# Case 2: list
|
||||
my $params = $req->parameters();
|
||||
|
@ -175,7 +179,8 @@ sub notifications {
|
|||
$value = qr/^$value$/;
|
||||
foreach my $k ( keys %$notifs ) {
|
||||
delete $notifs->{$k}
|
||||
unless ( $notifs->{$k}->{$field} =~ $value );
|
||||
unless ( $notifs->{$k}->{$field}
|
||||
&& $notifs->{$k}->{$field} =~ $value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -238,10 +243,10 @@ sub notifications {
|
|||
}
|
||||
|
||||
sub notification {
|
||||
my ( $self, $req, $id, $type ) = @_;
|
||||
my ( $self, $req, $id, $type, $uid, $ref ) = @_;
|
||||
|
||||
if ( $type eq 'actives' ) {
|
||||
my ( $uid, $ref ) = ( $id =~ /([^_]+?)_(.+)/ );
|
||||
( $uid, $ref ) = ( $id =~ /([^_]+?)_(.+)/ );
|
||||
my $n = $self->notifAccess->get( $uid, $ref );
|
||||
unless ($n) {
|
||||
$self->userLogger->notice(
|
||||
|
@ -258,8 +263,20 @@ sub notification {
|
|||
{ result => 1, count => 1, notifications => [ values %$n ] } );
|
||||
}
|
||||
else {
|
||||
my $n = $self->notifAccess->getAccepted( $uid, $ref );
|
||||
unless ($n) {
|
||||
$self->userLogger->notice(
|
||||
"Notification $ref not found for user $uid");
|
||||
return $self->sendJSONresponse(
|
||||
$req,
|
||||
{
|
||||
result => 0,
|
||||
error => "Notification $ref not found for user $uid"
|
||||
}
|
||||
);
|
||||
}
|
||||
return $self->sendJSONresponse( $req,
|
||||
{ result => 1, count => 1, done => $id } );
|
||||
{ result => 1, count => 1, done => $id, notifications => [ values %$n ] } );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use Lemonldap::NG::Common::Conf;
|
|||
use Lemonldap::NG::Common::Conf::Constants;
|
||||
use Lemonldap::NG::Manager::Conf::Parser;
|
||||
use Lemonldap::NG::Handler::Main::Jail;
|
||||
use Lemonldap::NG::Manager::Cli::Lib;
|
||||
use Data::Dumper;
|
||||
use English qw(-no_match_vars);
|
||||
use File::Temp;
|
||||
|
@ -11,6 +12,8 @@ use POSIX qw(setuid setgid);
|
|||
use Safe;
|
||||
use strict;
|
||||
|
||||
my $cli = Lemonldap::NG::Manager::Cli::Lib->new;
|
||||
|
||||
eval {
|
||||
setgid( ( getgrnam('__APACHEGROUP__') )[2] );
|
||||
setuid( ( getpwnam('__APACHEUSER__') )[2] );
|
||||
|
@ -73,7 +76,7 @@ if (`diff $refFile $editFile`) {
|
|||
req => 1,
|
||||
}
|
||||
);
|
||||
unless ( $parser->testNewConf(undef) ) {
|
||||
unless ( $parser->testNewConf( $cli->mgr ) ) {
|
||||
print STDERR "Configuration seems to have some errors:\n ";
|
||||
print STDERR Dumper(
|
||||
{ errors => $parser->errors, warnings => $parser->warnings } );
|
||||
|
|
|
@ -108,8 +108,10 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
|||
|
||||
# Delete 2FA device
|
||||
$scope.delete2FA = (type, epoch) ->
|
||||
item = angular.element(".data-#{epoch}")
|
||||
item.remove()
|
||||
#item = angular.element(".data-#{epoch}")
|
||||
items = document.querySelectorAll(".data-#{epoch}")
|
||||
for e in items
|
||||
e.remove()
|
||||
$scope.waiting = true
|
||||
$http['delete']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?type=#{type}&epoch=#{epoch}").then (response) ->
|
||||
$scope.waiting = false
|
||||
|
|
|
@ -206,26 +206,29 @@ llapp.controller 'NotificationsExplorerCtrl', [ '$scope', '$translator', '$locat
|
|||
$scope.currentScope = scope
|
||||
node = scope.$modelValue
|
||||
notificationId = node.notification
|
||||
query = ''
|
||||
if $scope.type == 'actives'
|
||||
notificationId = "#{node.uid}_#{node.reference}"
|
||||
$http.get("#{scriptname}notifications/#{$scope.type}/#{notificationId}").then (response) ->
|
||||
if $scope.type == 'done'
|
||||
query = "?uid=#{node.uid}&reference=#{node.reference}"
|
||||
$http.get("#{scriptname}notifications/#{$scope.type}/#{notificationId}#{query}").then (response) ->
|
||||
$scope.currentNotification =
|
||||
uid: node.uid
|
||||
reference: node.reference
|
||||
condition: node.condition
|
||||
if $scope.type == 'actives'
|
||||
try
|
||||
console.log "Try to parse a JSON formated notification..."
|
||||
notif = JSON.parse response.data.notifications
|
||||
$scope.currentNotification.date = $scope.notifDate(notif.date)
|
||||
$scope.currentNotification.text = notif.text
|
||||
$scope.currentNotification.title = notif.title
|
||||
$scope.currentNotification.subtitle = notif.subtitle
|
||||
catch e
|
||||
console.log "Unable to parse JSON"
|
||||
$scope.currentNotification.notifications = response.data.notifications
|
||||
else
|
||||
if $scope.type == 'done'
|
||||
$scope.currentNotification.done = response.data.done
|
||||
try
|
||||
console.log "Try to parse a JSON formated notification..."
|
||||
notif = JSON.parse response.data.notifications
|
||||
$scope.currentNotification.date = $scope.notifDate(notif.date)
|
||||
$scope.currentNotification.text = notif.text
|
||||
$scope.currentNotification.title = notif.title
|
||||
$scope.currentNotification.subtitle = notif.subtitle
|
||||
$scope.currentNotification.check = notif.check
|
||||
catch e
|
||||
console.log "Unable to parse JSON"
|
||||
$scope.currentNotification.notifications = response.data.notifications
|
||||
$scope.waiting = false
|
||||
, (resp) ->
|
||||
$scope.waiting = false
|
||||
|
|
|
@ -42,9 +42,9 @@
|
|||
<input class="form-control" ng-model="t[1]" />
|
||||
</td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data[5],$index)"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data[5],$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign"
|
||||
ng-click="menuClick({title:'newCmbOver', action:'newChoiceOver'})" />
|
||||
ng-click="menuClick({title:'newCmbOver', action:'newChoiceOver'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
<input class="form-control" ng-model="c.data[4]" aria-describedby="condlabel">
|
||||
</td>
|
||||
<td width="5%">
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newChain',action: 'newAuthChoice'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newChain',action: 'newAuthChoice'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
<tr ng-repeat="s in currentNode.nodes">
|
||||
<td><input class="form-control" ng-model="s.title"/></td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addAppCasPartner',action:'addCasApp'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addAppCasPartner',action:'addCasApp'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
<tr ng-repeat="s in currentNode.nodes">
|
||||
<td><input class="form-control" ng-model="s.title"/></td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addSrvCasPartner',action:'addCasSrv'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addSrvCasPartner',action:'addCasSrv'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<th width="25%" trspan="name"></th>
|
||||
<th width="25%" trspan="type"></th>
|
||||
<th width="35%" trspan="use"></th>
|
||||
<th />
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -23,9 +23,9 @@
|
|||
</td>
|
||||
<td>
|
||||
<select class="form-control" ng-model="currentNode.data.for">
|
||||
<option value="0" ng-selected="currentNode.data.for==0" trspan="authAndUserdb">
|
||||
<option value="1" ng-selected="currentNode.data.for==1" trspan="authOnly">
|
||||
<option value="2" ng-selected="currentNode.data.for==2" trspan="userdbOnly">
|
||||
<option value="0" ng-selected="currentNode.data.for==0" trspan="authAndUserdb"></option>
|
||||
<option value="1" ng-selected="currentNode.data.for==1" trspan="authOnly"></option>
|
||||
<option value="2" ng-selected="currentNode.data.for==2" trspan="userdbOnly"></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -41,8 +41,8 @@
|
|||
<input class="form-control" ng-model="t[1]" />
|
||||
</td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data.over,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newCmbOver'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data.over,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newCmbOver'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<th width="25%" trspan="name"></th>
|
||||
<th width="25%" trspan="type"></th>
|
||||
<th width="35%" trspan="use"></th>
|
||||
<th />
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -23,14 +23,14 @@
|
|||
</td>
|
||||
<td>
|
||||
<select class="form-control" ng-model="s.data.for">
|
||||
<option value="0" ng-selected="s.data.for==0" trspan="authAndUserdb">
|
||||
<option value="1" ng-selected="s.data.for==1" trspan="authOnly">
|
||||
<option value="2" ng-selected="s.data.for==2" trspan="userdbOnly">
|
||||
<option value="0" ng-selected="s.data.for==0" trspan="authAndUserdb"></option>
|
||||
<option value="1" ng-selected="s.data.for==1" trspan="authOnly"></option>
|
||||
<option value="2" ng-selected="s.data.for==2" trspan="userdbOnly"></option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newCmbMod'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newCmbMod'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -16,8 +16,8 @@ Special container to show hash in hash
|
|||
<th width="40%" trspan="keys"></th>
|
||||
<th width="40%" trspan="values"></th>
|
||||
<th>
|
||||
<span class="link text-success glyphicon glyphicon-plus-sign" ng-click="n.h.push({'k':'key','v':'uid'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data,$index)"/>
|
||||
<span class="link text-success glyphicon glyphicon-plus-sign" ng-click="n.h.push({'k':'key','v':'uid'})"></span>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data,$index)"></span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -26,7 +26,7 @@ Special container to show hash in hash
|
|||
<td><input class="form-control" ng-model="get.k"/></td>
|
||||
<td><input class="form-control" ng-model="get.v"/></td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="n.h.splice($index,1)"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="n.h.splice($index,1)"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<th width="20%" trspan="comments"></th>
|
||||
<th width="30%" trspan="rules"></th>
|
||||
<th width="50%" trspan="messages"></th>
|
||||
<th />
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -23,8 +23,8 @@
|
|||
<input class="form-control" ng-model="s.re" ng-change="changeRuleTitle(s)"/>
|
||||
</td>
|
||||
<td>
|
||||
<span ng-model="s.title" class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newGrantRule',action:'newGrantRule'})"/>
|
||||
<span ng-model="s.title" class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newGrantRule',action:'newGrantRule'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
</div>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th trspan="value" />
|
||||
<th trspan="value"></th>
|
||||
<td><input id="intinput" type="number" class="form-control" ng-model="currentNode.data"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
<table class="table">
|
||||
<tr>
|
||||
<th><span trspan="hashkey"></span></th>
|
||||
<td><input id="hashkeyinput" class="form-control" ng-model="currentNode.title"/>
|
||||
<td><input id="hashkeyinput" class="form-control" ng-model="currentNode.title"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span trspan="value"></span></th>
|
||||
<td><input id="hashvalueinput" class="form-control" ng-model="currentNode.data"/>
|
||||
<td><input id="hashvalueinput" class="form-control" ng-model="currentNode.data"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
<td><input class="form-control" ng-model="s.title"/></td>
|
||||
<td><input id-"hv-{{s.title}}" class="form-control" ng-model="s.data"/></td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newEntry',action:'newHashEntry'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newEntry',action:'newHashEntry'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -29,28 +29,28 @@
|
|||
</button>
|
||||
</div>
|
||||
<div class="col-md-11">
|
||||
<input id="ilogo" type="search" list="logos" class="form-control" ng-model="currentNode.data.logo"/></td>
|
||||
<input id="ilogo" type="search" list="logos" class="form-control" ng-model="currentNode.data.logo"/>
|
||||
<datalist id="logos">
|
||||
<option value="attach.png">
|
||||
<option value="bell.png">
|
||||
<option value="bookmark.png">
|
||||
<option value="configure.png">
|
||||
<option value="database.png">
|
||||
<option value="demo.png">
|
||||
<option value="docs.png">
|
||||
<option value="folder.png">
|
||||
<option value="gear.png">
|
||||
<option value="help.png">
|
||||
<option value="llng.png">
|
||||
<option value="mailappt.png">
|
||||
<option value="money.png">
|
||||
<option value="network.png">
|
||||
<option value="terminal.png">
|
||||
<option value="thumbnail.png">
|
||||
<option value="tools.png">
|
||||
<option value="tux.png">
|
||||
<option value="web.png">
|
||||
<option value="wheels.png">
|
||||
<option value="attach.png"></option>
|
||||
<option value="bell.png"></option>
|
||||
<option value="bookmark.png"></option>
|
||||
<option value="configure.png"></option>
|
||||
<option value="database.png"></option>
|
||||
<option value="demo.png"></option>
|
||||
<option value="docs.png"></option>
|
||||
<option value="folder.png"></option>
|
||||
<option value="gear.png"></option>
|
||||
<option value="help.png"></option>
|
||||
<option value="llng.png"></option>
|
||||
<option value="mailappt.png"></option>
|
||||
<option value="money.png"></option>
|
||||
<option value="network.png"></option>
|
||||
<option value="terminal.png"></option>
|
||||
<option value="thumbnail.png"></option>
|
||||
<option value="tools.png"></option>
|
||||
<option value="tux.png"></option>
|
||||
<option value="web.png"></option>
|
||||
<option value="wheels.png"></option>
|
||||
</datalist>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
<tr ng-repeat="s in currentNode.nodes">
|
||||
<td><input class="form-control" ng-model="s.title"/></td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addOidcOp'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addOidcOp'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
<tr ng-repeat="s in currentNode.nodes">
|
||||
<td><input class="form-control" ng-model="s.title"/></td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addOidcRp'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addOidcRp'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -26,15 +26,15 @@
|
|||
<tr>
|
||||
<th colspan="3">
|
||||
<span trspan="postedVars"></span>
|
||||
<span ng-if="!currentNode.data.vars.length" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newPostVar'})"/>
|
||||
<span ng-if="!currentNode.data.vars.length" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newPostVar'})"></span>
|
||||
</th>
|
||||
</tr>
|
||||
<tr ng-repeat="v in currentNode.data.vars">
|
||||
<td><input class="form-control" ng-model="v[0]"/></td>
|
||||
<td><input class="form-control" ng-model="v[1]"/></td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data.vars,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newPostVar'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data.vars,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newPostVar'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
<input class="form-control" ng-model="s.data.buttonSelector"/>
|
||||
</td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newPost'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newPost'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
</div>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th trspan="fileToUpload" />
|
||||
<th trspan="fileToUpload"></th>
|
||||
<td>
|
||||
<input id="fileinput" type="file" class="form-control" on-read-file="saveRawConf($fileContent)" />
|
||||
</td>
|
||||
<tr>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<script type="text/menu">
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<th trspan="regexps"></th>
|
||||
<th trspan="rules"></th>
|
||||
<th class="th_rulesAuthnLevel" trspan="rulesAuthnLevel"></th>
|
||||
<th class="th_rulesAuthnLevel" />
|
||||
<th class="th_rulesAuthnLevel"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -36,8 +36,8 @@
|
|||
<input class="form-control" placeholder="default" readonly/>
|
||||
</td>
|
||||
<td>
|
||||
<span ng-if="s.re!='default'" class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newRule'})"/>
|
||||
<span ng-if="s.re!='default'" class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newRule'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -40,8 +40,8 @@
|
|||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addSamlAttribute'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addSamlAttribute'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
<tr ng-repeat="s in currentNode.nodes">
|
||||
<td><input class="form-control" ng-model="s.title"/></td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addSamlIDPSamlPartner',action:'addSamlIDP'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addSamlIDPSamlPartner',action:'addSamlIDP'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
<tr ng-repeat="s in currentNode.nodes">
|
||||
<td><input class="form-control" ng-model="s.title"/></td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addSPSamlPartner',action:'addSamlSP'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.nodes,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'addSPSamlPartner',action:'addSamlSP'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</tr>
|
||||
<!-- URL -->
|
||||
<tr>
|
||||
<th><span trspan="url"></th>
|
||||
<th><span trspan="url"></span></th>
|
||||
<td><input id="saninput" class="form-control" ng-model="currentNode.data[1]"/></td>
|
||||
</tr>
|
||||
<!-- Return URL -->
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<th trspan="logo"></th>
|
||||
<th trspan="level"></th>
|
||||
<th trspan="rule"></th>
|
||||
<th />
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -49,8 +49,8 @@
|
|||
<input class="form-control" ng-model="t[1]" />
|
||||
</td>
|
||||
<td>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data.over,$index)"/>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newSfOver'})"/>
|
||||
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data.over,$index)"></span>
|
||||
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newSfOver'})"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user