# 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 Apache global configuration).

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

    PerlHeaderParserHandler Lemonldap::NG::Handler::ApacheMP2

### Hosted application

Example of a protected virtual host for a local application:

    <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:

    <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:

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

The `ProxyPreserveHost` directive will forward the Host header to the protected application.
To learn more about using Apache as reverse-proxy, see Apache documentation.
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 how convert header into environment variable.

### Add a floating menu

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

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

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

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

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 LemonLDAP::NG FastCGI server).

Then you can take any virtual host and modify it:

- Declare the /lmauth endpoint

      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  $request_uri;
      }

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

      location /path/to/protect {
        auth_request /lmauth;
        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:

      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

Example of a protected virtual host for a local application:

    # 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  $request_uri;
      }

      # Client requests
      location ~ \.php$ {
        auth_request /lmauth;
        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

* Example of a protected reverse-proxy:

    # 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  $request_uri;
      }

      # Client requests
      location / {
        auth_request /lmauth;
        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 :

    # 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  $request_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  $request_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  $request_uri;
        uwsgi_param VHOSTTYPE ServiceToken;
        # Improve performances
        uwsgi_buffer_size 32k;
        uwsgi_buffers 32 32k;
      }

      # Client requests
      location / {
        ##################################
        # CALLING AUTHENTICATION         #
        ##################################
        auth_request /lmauth;
        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;
        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;
        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;
      }
    }

## 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 Writing rules and headers to learn how to configure access control and HTTP headers sent to application by LL::NG.

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`

* 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 Form replay 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, ServiceToken Handler, DevOps Handler,...)
- 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.

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.

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.