Manage virtual hosts
====================

LemonLDAP::NG configuration is build around Apache or Nginx virtual
hosts. Each virtual host is a protected resource, with access rules,
headers, POST data and options.

Apache configuration
--------------------

To protect a virtual host in Apache, the LemonLDAP::NG Handler must be
activated (see
:ref:`Apache global configuration<configlocation-apache>`).

Then you can take any virtual host, and simply add this line to protect
it:

.. code-block:: apache

   PerlHeaderParserHandler Lemonldap::NG::Handler::ApacheMP2

Hosted application
~~~~~~~~~~~~~~~~~~

Example of a protected virtual host for a local application:

.. code-block:: apache

   <VirtualHost *:80>
           ServerName localsite.example.com

           PerlHeaderParserHandler Lemonldap::NG::Handler::ApacheMP2

           DocumentRoot /var/www/localsite

           ErrorLog /var/log/apache2/localsite_error.log
           CustomLog /var/log/apache2/localsite_access.log combined

   </VirtualHost>

Reverse proxy
~~~~~~~~~~~~~

Example of a protected virtual host with LemonLDAP::NG as reverse proxy:

.. code-block:: apache

   <VirtualHost *:80>
           ServerName application.example.com

           PerlHeaderParserHandler Lemonldap::NG::Handler::ApacheMP2

           # Reverse-Proxy
           ProxyPass / http://private-name/
           # Change "Location" header in redirections
           ProxyPassReverse / http://private-name/
           # Change domain cookies
           ProxyPassReverseCookieDomain private-name application.example.com

           ErrorLog /var/log/apache2/proxysite_error.log
           CustomLog /var/log/apache2/proxysite_access.log combined
   </VirtualHost>

Same with remote server configured with the same host name:

.. code-block:: apache

   <VirtualHost *:80>
           ServerName application.example.com

           PerlHeaderParserHandler Lemonldap::NG::Handler::ApacheMP2

           # Reverse-Proxy
           ProxyPass / http://APPLICATION_IP/

           ProxyPreserveHost on

           ErrorLog /var/log/apache2/proxysite_error.log
           CustomLog /var/log/apache2/proxysite_access.log combined
   </VirtualHost>


.. note::

    The ``ProxyPreserveHost`` directive will forward the Host header
    to the protected application. To learn more about using Apache as
    reverse-proxy, see `Apache
    documentation <http://httpd.apache.org/docs/current/mod/mod_proxy.html>`__.



.. tip::

    Some applications need the ``REMOTE_USER`` environment
    variable to get the connected user, which is not set in reverse-proxy
    mode. In this case, see
    :doc:`how convert header into environment variable<header_remote_user_conversion>`.

Add a floating menu
~~~~~~~~~~~~~~~~~~~

A little floating menu can be added to application with this simple
Apache configuration:

.. code-block:: apache

   PerlModule Lemonldap::NG::Handler::ApacheMP2::Menu
   PerlOutputFilterHandler Lemonldap::NG::Handler::ApacheMP2::Menu->run

Pages where this menu is displayed can be restricted, for example:

.. code-block:: apache

   <Location /var/www/html/index.php>
   PerlOutputFilterHandler Lemonldap::NG::Handler::ApacheMP2::Menu->run
   </Location>


.. attention::

    You need to disable mod_deflate to use the floating
    menu

Nginx configuration
-------------------

To protect a virtual host in Nginx, the LemonLDAP::NG FastCGI server
must be launched (see
:doc:`LemonLDAP::NG FastCGI server<fastcgiserver>`).

Then you can take any virtual host and modify it:

-  Declare the /lmauth endpoint

.. code-block:: nginx

     location = /lmauth {
       internal;
       include /etc/nginx/fastcgi_params;
       fastcgi_pass unix:/var/run/llng-fastcgi-server/llng-fastcgi.sock;

       # Drop post datas
       fastcgi_pass_request_body  off;
       fastcgi_param CONTENT_LENGTH "";

       # Keep original hostname
       fastcgi_param HOST $http_host;

       # Keep original request (LLNG server will receive /lmauth)
       fastcgi_param X_ORIGINAL_URI $original_uri;
     }

-  Protect the application (/ or /path/to/protect):

.. code-block:: nginx

     location /path/to/protect {
       auth_request /lmauth;
       set $original_uri $uri$is_args$args;
       auth_request_set $lmremote_user $upstream_http_lm_remote_user;
       auth_request_set $lmlocation $upstream_http_location;
       auth_request_set $cookie_value $upstream_http_set_cookie;
       add_header Set-Cookie $cookie_value;
       error_page 401 $lmlocation;
       try_files $uri $uri/ =404;

       # ...
     }

-  Use LUA or set manually the headers:

.. code-block:: nginx

     location /path/to/protect {

       # ...

       # IF LUA IS SUPPORTED
       #include /etc/lemonldap-ng/nginx-lua-headers.conf;

       # ELSE
       # Set manually your headers
       #auth_request_set $authuser $upstream_http_auth_user;
       #proxy_set_header Auth-User $authuser;
       # OR
       #fastcgi_param HTTP_AUTH_USER $authuser;

       # Then (if LUA not supported), change cookie header to hide LLNG cookie
       #auth_request_set $lmcookie $upstream_http_cookie;
       #proxy_set_header Cookie: $lmcookie;
       # OR in the corresponding block
       #fastcgi_param HTTP_COOKIE $lmcookie;

       # Set REMOTE_USER (for FastCGI apps only)
       #fastcgi_param REMOTE_USER $lmremote_user;
     }

.. _hosted-application-1:

Hosted application
~~~~~~~~~~~~~~~~~~

Example of a protected virtual host for a local application:

.. code-block:: nginx

   # Log format
   include /path/to/lemonldap-ng/nginx-lmlog.conf;
   server {
     listen 80;
     server_name myserver;
     root /var/www/html;
     # Internal authentication request
     location = /lmauth {
       internal;
       include /etc/nginx/fastcgi_params;
       fastcgi_pass /path/to/llng-fastcgi-server.sock;
       # Drop post datas
       fastcgi_pass_request_body  off;
       fastcgi_param CONTENT_LENGTH "";
       # Keep original hostname
       fastcgi_param HOST $http_host;
       # Keep original request (LLNG server will receive /lmauth)
       fastcgi_param X_ORIGINAL_URI $original_uri;
     }

     # Client requests
     location ~ \.php$ {
       auth_request /lmauth;
       set $original_uri $uri$is_args$args;
       auth_request_set $lmremote_user $upstream_http_lm_remote_user;
       auth_request_set $lmlocation $upstream_http_location;
       error_page 401 $lmlocation;
       try_files $uri $uri/ =404;
       include fastcgi_params;
       try_files $fastcgi_script_name =404;
       fastcgi_pass /path/to/php-fpm/socket;
       fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
       fastcgi_intercept_errors on;
       fastcgi_split_path_info ^(.+\.php)(/.+)$;
       fastcgi_hide_header X-Powered-By;

       ##################################
       # PASSING HEADERS TO APPLICATION #
       ##################################
       # IF LUA IS SUPPORTED
       #include /path/to/nginx-lua-headers.conf

       # ELSE
       # Set manually your headers
       #auth_request_set $authuser $upstream_http_auth_user;
       #fastcgi_param HTTP_AUTH_USER $authuser;
     }
     location / {
       try_files $uri $uri/ =404;
     }
   }

.. _reverse-proxy-1:

Reverse proxy
~~~~~~~~~~~~~

\* Example of a protected reverse-proxy:

.. code-block:: nginx

   # Log format
   include /path/to/lemonldap-ng/nginx-lmlog.conf;
   server {
     listen 80;
     server_name myserver;
     root /var/www/html;
     # Internal authentication request
     location = /lmauth {
       internal;
       include /etc/nginx/fastcgi_params;
       fastcgi_pass /path/to/llng-fastcgi-server.sock;
       # Drop post datas
       fastcgi_pass_request_body  off;
       fastcgi_param CONTENT_LENGTH "";
       # Keep original hostname
       fastcgi_param HOST $http_host;
       # Keep original request (LLNG server will receive /lmauth)
       fastcgi_param X_ORIGINAL_URI  $original_uri;
     }

     # Client requests
     location / {
       auth_request /lmauth;
       set $original_uri $uri$is_args$args;
       auth_request_set $lmremote_user $upstream_http_lm_remote_user;
       auth_request_set $lmlocation $upstream_http_location;
       error_page 401 $lmlocation;

       proxy_pass http://remote.server/;
       include /etc/nginx/proxy_params;

       ##################################
       # PASSING HEADERS TO APPLICATION #
       ##################################
       # IF LUA IS SUPPORTED
       #include /path/to/nginx-lua-headers.conf

       # ELSE
       # Set manually your headers
       #auth_request_set $authuser $upstream_http_auth_user;
       #proxy_set_header HTTP_AUTH_USER $authuser;
     }
   }

\* Example of a Nginx Virtual Host using uWSGI with many URIs protected
by different types of handler :

.. code-block:: nginx

   # Log format
   include /path/to/lemonldap-ng/nginx-lmlog.conf;
   server {
     listen 80;
     server_name myserver;
     root /var/www/html;

    # Internal MAIN handler authentication request
     location = /lmauth {
       internal;
       # uWSGI Configuration
       include /etc/nginx/uwsgi_params;
       uwsgi_pass 127.0.0.1:5000;
       uwsgi_pass_request_body  off;
       uwsgi_param CONTENT_LENGTH "";
       uwsgi_param HOST $http_host;
       uwsgi_param X_ORIGINAL_URI  $original_uri;
       # Improve performances
       uwsgi_buffer_size 32k;
       uwsgi_buffers 32 32k;
     }

     # Internal AUTH_BASIC handler authentication request
     location = /lmauth-basic {
       internal;
       # uWSGI Configuration
       include /etc/nginx/uwsgi_params;
       uwsgi_pass 127.0.0.1:5000;
       uwsgi_pass_request_body  off;
       uwsgi_param CONTENT_LENGTH "";
       uwsgi_param HOST $http_host;
       uwsgi_param X_ORIGINAL_URI  $original_uri;
       uwsgi_param VHOSTTYPE AuthBasic;
       # Improve performances
       uwsgi_buffer_size 32k;
       uwsgi_buffers 32 32k;
     }

     # Internal SERVICE_TOKEN handler authentication request
     location = /lmauth-service {
       internal;
       # uWSGI Configuration
       include /etc/nginx/uwsgi_params;
       uwsgi_pass 127.0.0.1:5000;
       uwsgi_pass_request_body  off;
       uwsgi_param CONTENT_LENGTH "";
       uwsgi_param HOST $http_host;
       uwsgi_param X_ORIGINAL_URI  $original_uri;
       uwsgi_param VHOSTTYPE ServiceToken;
       # Improve performances
       uwsgi_buffer_size 32k;
       uwsgi_buffers 32 32k;
     }

     # Client requests
     location / {
       ##################################
       # CALLING AUTHENTICATION         #
       ##################################
       auth_request /lmauth;
       set $original_uri $uri$is_args$args;
       auth_request_set $lmremote_user $upstream_http_lm_remote_user;
       auth_request_set $lmremote_custom $upstream_http_lm_remote_custom;
       auth_request_set $lmlocation $upstream_http_location;
       # Remove this for AuthBasic handler
       error_page 401 $lmlocation;

       ##################################
       # PASSING HEADERS TO APPLICATION #
       ##################################
       # IF LUA IS SUPPORTED
       include /etc/nginx/nginx-lua-headers.conf;
     }

     location /AuthBasic/ {
       ##################################
       # CALLING AUTHENTICATION         #
       ##################################
       auth_request /lmauth-basic;
       set $original_uri $uri$is_args$args;
       auth_request_set $lmremote_user $upstream_http_lm_remote_user;
       auth_request_set $lmremote_custom $upstream_http_lm_remote_custom;
       auth_request_set $lmlocation $upstream_http_location;
       # Remove this for AuthBasic handler
       #error_page 401 $lmlocation;

       ##################################
       # PASSING HEADERS TO APPLICATION #
       ##################################
       # IF LUA IS SUPPORTED
       include /etc/nginx/nginx-lua-headers.conf;
     }

     location /web-service/ {
       ##################################
       # CALLING AUTHENTICATION         #
       ##################################
       auth_request /lmauth-service;
       set $original_uri $uri$is_args$args;
       auth_request_set $lmremote_user $upstream_http_lm_remote_user;
       auth_request_set $lmlocation $upstream_http_location;
       # Remove this for AuthBasic handler
       error_page 401 $lmlocation;

       ##################################
       # PASSING HEADERS TO APPLICATION #
       ##################################
       # IF LUA IS SUPPORTED
       include /etc/nginx/nginx-lua-headers.conf;
     }
   }

.. _configvhost-lemonldapng-configuration:

LemonLDAP::NG configuration
---------------------------

A virtual host protected by LemonLDAP::NG Handler must be registered in
LemonLDAP::NG configuration.

To do this, use the Manager, and go in ``Virtual Hosts`` branch. You can
add, delete or modify a virtual host here. Enter the exact virtual host
name (for example ``test.example.com``) or use a wildcard (for example
``*.example.com``).

A virtual host contains:

-  Access rules: check user's right on URL patterns
-  HTTP headers: forge information sent to protected applications
-  POST data: use form replay
-  Options: redirection port and protocol

Access rules and HTTP headers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

See :doc:`Writing rules and headers<writingrulesand_headers>` to
learn how to configure access control and HTTP headers sent to
application by LL::NG.


.. attention::

    With **Nginx**-based ReverseProxy, header directives can
    be appended by a LUA script.

    To send more than **TEN** headers to protected applications, you have to
    edit and modify :

    ``/etc/nginx/nginx-lua-headers.conf``


.. danger::

    \* **Nginx** gets rid of any empty headers. There is no
    point of passing along empty values to another server; it would only
    serve to bloat the request. In other words, headers with **empty values
    are completely removed** from the passed request.

    \* **Nginx**, by default, will consider any header that **contains
    underscores as invalid**. It will remove these from the proxied request.
    If you wish to have Nginx interpret these as valid, you can set the
    ``underscores_in_headers`` directive to “on”, otherwise your headers
    will never make it to the backend server.

POST data
~~~~~~~~~

See :doc:`Form replay<formreplay>` to learn how to configure form
replay to POST data on protected applications.

Options
~~~~~~~

Some options are available:

-  Port: used to build redirection URL *(when user is not logged, or for
   CDA requests)*
-  HTTPS: used to build redirection URL
-  Maintenance mode: reject all requests with a maintenance message
-  Aliases: list of aliases for this virtual host *(avoid to rewrite
   rules,...)*
-  Type: handler type (normal,
   :doc:`ServiceToken Handler<servertoserver>`,
   :doc:`DevOps Handler<devopshandler>`,...)
-  Authentication level required: this option avoids to reject user with
   a rule based on ``$_authenticationLevel``. When user hasn't got the
   required level, he is redirected to an upgrade page in the portal.
   This level is applied to ALL VirtualHost locations.
-  ServiceToken timeout: The Service Token is only available during 30
   seconds by default. This TTL can be customized for each virtual host.


.. danger::

    A same virtual host can serve many locations. Each
    location can be protected by a different type of handler :

    ::

       server test1.example.com 80
         location ^/AuthBasic  => AuthBasic handler
         location ^/AuthCookie => Main handler

    Keep in mind that AuthBasic handler use "Login/Password" to authenticate
    users. If you set "Authentication level required" option to "5" by
    example, AuthBasic requests will be ALWAYS rejected because AuthBasic
    authentication level is lower than required level.


.. attention::

    A negative or null ServiceToken timeout value will be
    overloaded by ``handlerServiceTokenTTL`` (30 seconds by default).


"Port" and "HTTPS" options are used to build redirection URL *(when user
is not logged, or for CDA requests)*. By default, default values are
used. These options are only here to override default values.
