Crivaledaz / Mattermost-LDAP

This module provides an external LDAP authentication in Mattermost for the Team Edition (free).
MIT License
359 stars 71 forks source link

HTTPS support #65

Closed xDFCx closed 4 years ago

xDFCx commented 4 years ago

Hello! First of all - thanks for this project, it is really helpful! I wanted to ask about using HTTPS. Is it true, that it will not work for now even if I use https in all URLs in configs? You wrote in todo list, that HTTPS support is upcoming. Do you have any plans when it will be released? My users often use MM outside the corp network, so using plain HTTP is highly insecure.

Crivaledaz commented 4 years ago

Hi,

Thank you for using Mattermost-LDAP. I am happy this project helps you.

To answer your question, Mattermost-LDAP is already compatible with HTTPS. However, HTTPS support adds some complexity and can be sources of issues with Mattermost and client browsers. That's the reason why it is not officially supported in the docker-compose implementation. When I have some time, I will document in detail this part in the Readme :)

So, there are two ways to enable HTTPS support on Mattermost-LDAP. Either you use a reverse proxy, like Nginx for example, or you configure HTTPS directly in the Apache server on the oauth server side. I recommend to use the first solution, to reduce possible issues. In fact, if you set up HTTPS on the Oauth server side, Mattermost and clients will talk with Oauth in HTTPS, which is a good thing, but if you use a self-signed certificate, Mattermost will never accept authentication from the Oauth server and will ever fail with the error "x509 certificate signed by unknown authority". Note, if you use trusted certificate, signed by a well known authority, you will not have this problem.

In other hand, with a reverse proxy you can put Mattermost and Mattermost-LDAP behind your reverse proxy and let them talk together in plain text HTTP, while connections with the client are in HTTPS. This is not the most secure way to do this, but the risk is mitigated since Mattermost and Mattermost-LDAP should be co-located, often on the same LAN. In this case, Mattermost will not raise the error "x509 certificate signed by unknown authority", and all communications between client/Oauth and client/mattermost will be encrypted.

For the first solution, refer to the Apache documentation : https://httpd.apache.org/docs/2.4/en/ssl/ssl_howto.html

For the second one, refer to the Matermost documentation : https://docs.mattermost.com/install/config-proxy-nginx.html. You just need to add the following rules before the location / block :

    location /oauth/gitlab/ {
      client_max_body_size 50M;
      proxy_set_header Connection "";
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Frame-Options SAMEORIGIN;
      proxy_buffers 256 16k;
      proxy_buffer_size 16k;
      proxy_read_timeout 600s;
      proxy_cache mattermost_cache;
      proxy_cache_revalidate on;
      proxy_cache_min_uses 2;
      proxy_cache_use_stale timeout;
      proxy_cache_lock on;
      proxy_pass http://mattermost;
    }

    location ~ /oauth/.*\.php$ {
      try_files $uri =404;
      fastcgi_pass php:9000;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      include fastcgi_params;
    }

    location /oauth/ {
      try_files $uri $uri/ =404;
    }

You can find this configuration in Demo/nginx.conf.

Do not forget to update URLs in the Gitlab section from Mattermost configuration. For the reverse proxy, you only need to convert the AuthEndpoint URL to HTTPS, while for the other solution you need to add HTTPS for all URL. Do not forget to update the redirect_url in the oauth_clients database if you use the Apache solution.

I hope this will help you to configure HTTPS for your solution, keep me informed.

Regards

xDFCx commented 4 years ago

Hi, My MM is running behind an nginx proxy with LE certs, so I edited nginx config to look like this:

server {
    if ($host = mattermost.company.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

   listen         192.168.111.138:80;
   server_name    mattermost.company.com;
   return         301 https://$server_name$request_uri;
}

server {
   listen 192.168.111.138:443 ssl;
   server_name mattermost.company.com;

   ssl on;
    ssl_certificate /etc/letsencrypt/live/mattermost.company.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/mattermost.company.com/privkey.pem; # managed by Certbot
   ssl_session_timeout 5m;
   ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
   ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
   ssl_prefer_server_ciphers on;
   ssl_session_cache shared:SSL:10m;

    location /oauth/gitlab/ {
      client_max_body_size 50M;
      proxy_set_header Connection "";
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Frame-Options SAMEORIGIN;
      proxy_buffers 256 16k;
      proxy_buffer_size 16k;
      proxy_read_timeout 600s;
      proxy_pass http://127.0.0.1:8065;
    }

    location ~ /oauth/.*\.php$ {
      try_files $uri =404;
      fastcgi_pass unix:/run/php/php7.4-fpm.sock;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      include fastcgi_params;
    }

    location /oauth/ {
      try_files $uri $uri/ =404;
    }
   location / {
      gzip off;
      proxy_http_version 1.1;
      proxy_set_header X-Forwarded-Ssl on;
      client_max_body_size 50M;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Frame-Options SAMEORIGIN;
#      include /etc/nginx/mime.types;
      proxy_pass http://127.0.0.1:8065;
   }

   location /.well-known {
      root /var/www/html;
   }

}

Also, I changed redirect_uri in postgresql db:

postgres=# \c oauth_db
You are now connected to database "oauth_db" as user "postgres".
oauth_db=# select * from oauth_clients;
 client_id | client_secret |                     redirect_uri                     |    grant_types     | scope | user_id
-----------+---------------+------------------------------------------------------+--------------------+-------+---------
 321654987 | 789456123     | https://mattermost.company.com/signup/gitlab/complete | authorization_code | api   |
(1 row)

And, of course, change URLs in MM config.json

<...>
    "GitLabSettings": {
        "Enable": true,
        "Secret": "789456123",
        "Id": "321654987",
        "Scope": "",
        "AuthEndpoint": "https://mattermost.company.com/oauth/resource.php",
        "TokenEndpoint": "https://mattermost.company.com/oauth/resource.php",
        "UserApiEndpoint": "https://mattermost.company.com/oauth/resource.php"
    },
<...>

And now I when I press GitLab button on login page I get HTTP 404 :( URL string in web browser looks like https://mattermost.company.com/oauth/resource.php?response_type=code&client_id=321654987&redirect_uri=https%3A%2F%2Fmattermost.company.com%2Fsignup%2Fgitlab%2Fcomplete&state=eyJhY3Rpb24iOiJsb2dpbiIsImlzTW9iaWxlIjoiZmFsc2UiLCJ0b2tlbiI6IjQ1NHE3cHBvbmEzN3U0cDY0Zm0xNTl5N2h5YjNmbnJvNzRtaDdteWE1MWI2NXN3OXA2aGlpMWF5bTFpdTc0eHQifQ%3D%3D Am I missing something?

Crivaledaz commented 4 years ago

Hi,

I have tried to support HTTPS on the Demo docker-compose implementation, and after some hours fighting against network issues, it's working.

In your case, you are getting HTTP 404 because you did not define the root directory for the ssl server. You must add the root line to precise to Nginx what is the oauth folder parent path. You can add this line right after server definition, like this :

server {
   listen 192.168.111.138:443 ssl;
   server_name mattermost.company.com;
   root /var/www/html; # Supposing the oauth folder is in /var/www/html

But even with this fix, I am afraid it will continue to fail (but no more 404 errors normally).

Let's resume, first of all you need to specify HTTPS in the SiteURL parameter in Mattermost config.json. For example, https://mattermost.company.com. In this case, in the Oauth database you should set the redirect_uri to https://mattermost.company.com/signup/gitlab/complete. According to your log, your configuration seems good.

Then, you need to configure the Gitlab settings in the Mattermost config.json file. Two possibilities here, either you have trusted certificates (works if you have added your CA to the system truststore), or you won't get rid of by certificate issue between Mattermost and Oauth server and you keep interaction between their in clear.

In the first case, you should use the following configuration (Note, this is NOT three times the same) :

"AuthEndpoint": "https://mattermost.company.com/oauth/authorize.php",
"TokenEndpoint": "https://mattermost.company.com/oauth/token.php",
"UserApiEndpoint": "https://mattermost.company.com/oauth/resource.php"

In this case, your Nginx configuration should work, but your certificate need to be added to the truststore.

In the second case, you should use the following configuration. Files reached are the same than previously, but this is localhost for communication between Mattermost and Oauth, and mattermost.company.com for communication with the client (Note : HTTP is used for localhost and HTTPS for mattermost.company.com) :

"AuthEndpoint": "https://mattermost.company.com/oauth/authorize.php",
"TokenEndpoint": "http://localhost/oauth/token.php",
"UserApiEndpoint": "https://localhost/oauth/resource.php"

In the other hand, we need to adapt the Nginx configuration, to perform HTTPS with the client and allow plain HTTP between Mattermost and the Oauth server. The HTTPS part is already covered by your Nginx configuration. However, you are forcing HTTP to redirect to HTTPS, which is what we want for clients, but not for Mattermost/Oauth communication. So we need to allow localhost on HTTP and keep it in HTTP.

To do that, we need to add the following section to the Nginx configuration (Note I redefine the root folder, since this is server specific.) :

server {
   listen       80;
   server_name  localhost;
   root         /var/www/html;
   index index.php index.html index.htm;
    location ~ /oauth/.*\.php$ {
      try_files $uri =404;
      fastcgi_pass php:9000;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      include fastcgi_params;
    }
    location /oauth/ {
      try_files $uri $uri/ =404;
    }
 }

Restarting Nginx and Mattermost, you should get a working HTTPS instance of Mattermost and Mattermost-LDAP.

I think I will write a complete and clean documentation about HTTPS support, in the next weeks. Just know it is easier to configure HTTPS for Matermost-LDAP in a Kubernetes cluster ;).

I hope this will help you to configure HTTPS, keep me informed.

Regards

xDFCx commented 4 years ago

Woohoo, it works! I added "root" directive in nginx config and changed endpoints URLs if MM config.json (can't understand how all 3 lines got same url - I was sure that edited them correctly). Thank you once again for you work and your help.