Edgewall Software
Modify

Ticket #4733 (new enhancement)

Opened 3 years ago

Last modified 3 weeks ago

Option for all login links to use HTTPS

Reported by: jeffcorbets@… Owned by: jonas
Priority: normal Milestone: next-major-0.1X
Component: general Version:
Severity: normal Keywords: secure, login, https
Cc: felix.schwarz@…, trac-bugs@…

Description

It would be nice if trac could automatically use the https protocol in creating links to login with an appropriately configured web server.

I have tried a number of mod_rewrite rules and LocationMatch directives, but have not been successful in getting logins for multiple trac projects to be re-directed to the secure server for processing.

Attachments

Change History

comment:1 Changed 3 years ago by cboos

  • Milestone set to 0.12

We could define a new front-end setting, similar to TracUriRoot, e.g. TracLoginUri.

comment:2 Changed 3 years ago by jeffcorbets@…

It would be nice to see this incorporated as soon as possible, hopefully no later than 0.11. The proposed additional option seems like a fine solution to me.

comment:3 Changed 3 years ago by dacat

The following is the solution I have implemented to do what I believe jeffcorbets@… is trying to achieve.

Make Trac use SSL for login links on a Multi-Environment Setup

Summary

After implementing the following solution..

  • All the Environments Login links will force an SSL connection.
  • All other pages that are not Login pages will be served up on a non-ssl connection.

Assumptions

This solution assumes the following

  • You have a working Apache2 web server configured.
  • You have a working Trac installation.
  • You have root on the machine your are attempting to configure.
  • You have a working SSL configuration.

Solution

For this solution to work you need

  • Two Virtual Hosts configured
    • One vhost that listens on yourhost:80
    • One vhost that listens on yourhost:443

Let:

host_name
be the FQDN of your Apache web server.
myvhost.conf
be the name of the apache configuration file for your virtual host that listens on port 80
myvhost-ssl.conf
be the name of the apache configuration file for your virtual host that listens on port 443 and has SSL enabled

Apache Virutal Host Configuration Changes

myvhost.conf changes

  1. Move you Trac specific directives into myvhost.conf
  2. Add the RedirectMatch Directive into myhost.conf
  3. Should look something like this
    <IfModule mod_python.c>
     RedirectMatch /([^/]+)/login https://host_name/trac/$1/login
     <Location /trac >
       SetHandler mod_python
       PythonHandler trac.web.modpython_frontend
       PythonOption TracEnvParentDir /path/to/trac/projects/         
     </Location>
    </IfModule>
    

myvhost-ssl.conf changes

  1. Add a LocationMatch Directive for the login page.
  2. Add a RedirectMatch Directive to redirect all other Trac pages.
  3. Should look something like
    <IfModule mod_python.c>
      RedirectMatch "/trac/([^/]+($|/))(?!login$)" http://host_name/trac/$1
      <LocationMatch /trac/[^/]+/login>
        SSLRequireSSL
        SetHandler mod_python
        PythonHandler trac.web.modpython_frontend
        PythonOption TracEnvParentDir /path/to/trac/projects/         
        AuthType Basic
        AuthName "Trac"
        AuthUserFile /path/to/your/auth/file
        Require valid-user
      </LocationMatch>
    </IfModule>
    

Make sure you change the parameters above to match your installation of Trac.

Execution Flow

What should happen after the changes are implemented is the following:

  1. User clicks on 'login' on the non-ssl port 80 vhost
  2. The RecirectMatch in myvhost.conf fires redirecting the user to the SSL site on port 443 site.
  3. The LocationMatch directive in myvhost-ssl.conf fires and pops up the authentication window you will see https://yourhost identified in the authentication window.
  4. After the user authenticates, Trac redirects the user to the Trac page, where the user clicked login, on the SSL site port 443 vhost.
  5. The RedirectMatch in myvhost-ssl.conf fires redirecting the user to the Trac wiki for the environment they are using on the non-ssl port 80 vhost

Conclusion

I have attempted to test this solution extensively.

  • I watched the apache ssl request logs to make sure ssl requests are being made.
  • I clicked through all seven of my Trac projects and they function normally.
  • I've modified urls by hand to see what the effects would be and everything appears to function normally.

I really do hope this helps people. Questions Comments? my email is dacat_spamalot_ATunt.edu remove _spamalot_ to send mail

comment:4 Changed 3 years ago by jeffcorbets

That solutions works fairly well. I wish it would return the user to the page they tried to log in from after authentication instead of the wiki every time, but beggars cannot be choosers.

Also, my setup makes extensive use of LDAP for authentication. For each project I create, right now I hand add it to the configuration file so that the required (LDAP) group is different for each project. Is there anyway that can be simplified using the LocationMatch directive by actually capturing the regular expression group and then using it later in the Require group ... directive??

comment:5 Changed 3 years ago by shap

The proposed redirect solution looks pretty good. Returning to the same page requires putting some kind of query string into the login URI.

However, this solution is not complete, because password changes are not guarded. Also, a case can be made that administration pages want to be SSL-guarded as well. Getting all of this right requires that the core be in on the joke, and it requires much more than just a secure login URI.

comment:6 Changed 2 years ago by Martin <martin@…>

FYI, this configuracion didn't work for me (don't know why). I made two rewrite rules in the ssl.conf file and I get excelent redirection both ways.

In trac.conf I have something like:

    Redirect /cursos/login https://mytracserver/cursos/login
 
   <Location /cursos>
              Allow from all
              SetHandler mod_python
              PythonInterpreter main_interpreter
              PythonHandler trac.web.modpython_frontend
              PythonOption TracEnv /var/lib/trac/cursos
              PythonOption TracUriRoot /cursos
              SetEnv PYTHON_EGG_CACHE /tmp/
    </Location>

On the ssl.conf I have this:

   RewriteEngine On
   RewriteRule ^/cursos/login     https://mytracserver/cursos/login  [L]
   RewriteRule ^/cursos/(.*)     http://mytracserver/cursos/$1  [L]

   <Location /cursos/>
         Allow from all
         SetHandler mod_python
         PythonInterpreter main_interpreter
         PythonHandler trac.web.modpython_frontend
         PythonOption TracEnv /var/lib/trac/cursos
         PythonOption TracUriRoot /cursos
         SetEnv PYTHON_EGG_CACHE /tmp/
   </Location>

Hope it helps anybody.

comment:7 follow-up: ↓ 8 Changed 2 years ago by robin-trac@…

Hi,

I was looking into doing something similar to this and asked on #trac IRC. I was told that once logged in sensitive data is transferred for every request (login details) so it is sensible to remain in https after logging in.

R.

comment:8 in reply to: ↑ 7 Changed 2 years ago by nkantrowitz

Replying to robin-trac@robinbowes.com:

I was looking into doing something similar to this and asked on #trac IRC. I was told that once logged in sensitive data is transferred for every request (login details) so it is sensible to remain in https after logging in.

The username and password are not sent again, but a login cookie is. This original credentials can't be retrieved even with this cookie, but an attacker could impersonate the user until the cookie expires and is reissued (every 8 hours IIRC).

comment:9 follow-up: ↓ 18 Changed 18 months ago by djs@…

We're using an apache rewrite to send the request back to the referring page:

        RewriteEngine on
        # Go to the referer if there is one
        RewriteCond %{REQUEST_URI} !/trac/(.*)/login$
        RewriteCond %{HTTP_REFERER} ^http://mytracserver/trac/.*
        RewriteRule . %{HTTP_REFERER} [R]

        # If not, go to wherever Trac wants to go
        RewriteCond %{REQUEST_URI} !/trac/(.*)/login$
        RewriteCond %{HTTP_REFERER} !^http://mytracserver/trac/.*
        RewriteRule ^/trac/(.*)$ http://mytracserver/trac/$1 [R]

comment:10 Changed 17 months ago by Felix Schwarz <felix.schwarz@…>

  • Cc felix.schwarz@… added

comment:11 Changed 16 months ago by Olivier Mehani <shtrom-trac@…>

I'm using the standalone tracd server and successfully did something quite similar to djs. I have two virtual hosts acting as proxies to the actual tracd port.

Connection on port 80 is transparently proxied until a login URL is found, in which case the user's browser is redirected to the same URL on port 443. After logging in, there is little point in returning the user to unencrypted HTTP (though there is no more point in keeping him using HTTPS, except for lazyness (: ), so nothing is done about it.

The HTTP VirtualHost:

<VirtualHost *:80>
    ServerName mytracserver
    DocumentRoot /htdocs/trac

    RewriteEngine On
    RewriteRule ^/([^/]+)/login     https://mytracserver/$1/login  [R]
    RewriteRule ^/(.*)     http://localhost:8080/$1 [P]
    <Directory proxy:http://localhost:8080>
            Order allow,deny
            Allow from all
    </Directory>
</VirtualHost>

and the SSL VirtualHost:

<VirtualHost *:443>
    ServerName mytracserver
    DocumentRoot /htdocs/trac

    ProxyRequests off
    ProxyPass / http://localhost:8080/
    ProxyPassReverse / http://localhost:8080/
    <Directory proxy:http://localhost:8080>
            Order allow,deny
            Allow from all
    </Directory>
    # Other standard SSL configuration goes here
</VirtualHost>

comment:12 Changed 12 months ago by AllenJB <trac-bugs@…>

  • Cc trac-bugs@… added

comment:13 follow-up: ↓ 14 Changed 10 months ago by madyogi

Well,
As far as I think the virtual hosts don't share cookies/session name-spaces between themselves. The Apache goal was to make virtual hosts work as totally separate physical boxes, beside what about security??? If one redirects to https using rewrite rules and logs in, as long as he/she stays there, will be able to use privileged trac account possibilities. But whenever one goes back to http (different virtual host) the information about being logged in will disappear... At least it should!!! (The great truth about login cookie from the post above.)

If you do something like:

http (80) virtual host, knows about <location /trac > only and
https (443) virtual host, knows about <location /trac/login > only.
These are two (virtual) hosts not one physical apache, using two transmission protocols (http/https) for the same purpose.
If you connect the cookie data with a specific session opened one one virtual host how do you want the cookie to still be there, accessible from a different session?
It's quite easy to redirect one from http to https and make the trac page look the same on both hosts. Next, when you rewrite the URI that  https://.../trac/login redirects back to  http://.../trac, you will make a loop, not giving a chance to log in. Or you don't do it and using other tricks you stay at https and user logs in. (That's what I managed to do using myvhost and myvhost-ssl post from above). After all, when he/she clicks a link and comes back to http, he/she will not be logged in because http virtual host never received users login/password data (login cookie). Though they (it) still exist(s) when one goes back to https again...

Or, am I wrong???

Beside, Trac had not to be a MasterCard? PIN tracking tool, at least as long as you don't use your credit card number as a login and a PIN number as a password... (Though it would be a great extension too...)

comment:14 in reply to: ↑ 13 Changed 10 months ago by Felix Schwarz <felix.schwarz@…>

Replying to madyogi:

As far as I think the virtual hosts don't share cookies/session name-spaces between themselves. The Apache goal was to make virtual hosts work as totally separate physical boxes, beside what about security??? If one redirects to https using rewrite rules and logs in, as long as he/she stays there, will be able to use privileged trac account possibilities. But whenever one goes back to http (different virtual host) the information about being logged in will disappear... At least it should!!!

I'm not sure that I understood you correctly. However if both virtual hosts serve the same domain name (just http/https) and trac does not mark the cookie as 'https only', the cookie can be used with the non-encrypted pages as well.

comment:15 follow-up: ↓ 16 Changed 10 months ago by anonymous

Well, you understood me fine,
I thought about the previous post this morning and I guess that I wrote it a bit wrong way, sorry for that.

The reason I wrote the previous post was that I've created some time ago my own trac and mod-python extension – a new pythonathenhandler function. The goal was to authenticate users basing on MySQL database content and not using local .htpassword file. I did it and the extension works well, as long as I use single virtual host environment. Note I'm not python / apache internals guru.

Plenty of people write that BasicAuth? over SSL can be done! Whenever I tried to spread the trac over two virtual machines the authentication failed. Whenever I stayed at https I was authenticated and whenever I came back to http the authentication credentials were lost... :( The same thing happened when I used my own pythonauthenhandler function.

So is SSL Basicauth really possible, is there something rally bad with my vhost environment?

comment:16 in reply to: ↑ 15 Changed 10 months ago by Felix Schwarz <felix.schwarz@…>

Replying to anonymous:

So is SSL Basicauth really possible, is there something rally bad with my vhost environment?

Yes, it is. I'm using it on a daily basis.

comment:17 Changed 10 months ago by madyogi

I did a bit more extensive tests this Sunday because the entire thing doesn't make me sleep well.
Used a bit simpler server side tool - PHP and observed the "sess*" files that server creates. I used two virtual hosts for tests - result:
 http://www.myhost.com is not the same as  https://ssl.myhost.com so optimistically thinking – I was partially right here but:
 http://www.myhost.com seams to be the same as  https://www.myhost.com, so at this point I was wrong and you are right! PERIOD

Yes, I've learned something!

Back to Trac.
It took me entire morning to figure out how to make it and finally it works as it supposed to. User enters http, clicks [login], is being redirected to https virtual host, authenticates and is being automatically redirected back to http site. It's worth to mention here that https box is not a dedicated host for Trac only, it also hosts a different encrypted content at the same port (443).

I had to put this into my vhost.conf file:

RewriteEngine On
# Redirect was not working as it should for me... :(
RewriteRule ^/trac/login https://www.myhost.com/trac/login [R]
<Location /trac >
    SetHandler mod_python
    PythonInterpreter main_interpreter
    PythonHandler trac.web.modpython_frontend
    PythonOption TracEnv /pub/trac/myproject
    PythonOption TracEnvIndexTemplate /pub/trac/myproject/templates
    # PythonOption TracEnvParentDir /pub/trac
</Location>

And this into vhost-ssl.conf:

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/trac       [NC]
RewriteRule !^/trac/login http://www.myhost.com%{REQUEST_URI}
# Same story with RedirectMatch – not working, had strange issues with
# CSS stylesheets.
<LocationMatch "/trac/login" >
    SetHandler mod_python
    PythonInterpreter main_interpreter
    PythonOption TracEnv /pub/trac/myproject
    PythonOption TracEnvIndexTemplate /pub/trac/myproject/templates
    # PythonOption TracEnvParentDir /pub/trac
    PythonHandler trac.web.modpython_frontend

    # Use a MySQLdb and mod_python to read users data from SQL tables
    # instead of .htpasswd file. Don't use it if you use htpassword.
    # PythonAuthenHandler tpm_handler
    # PythonDebug On
    # AuthBasicAuthoritative Off
    AuthType Basic
    AuthName "Authorized users area."
    Require valid-user
</LocationMatch>

Hope this will be helpful to others and Felix thanks for your opinion...

I'm using Trac 0.11.5 (out of the box), Apache 2.2.11 (Unix) with Python 2.6 and mod_python-3.3.1 + a tiny C code patch (all compiled on my own from sources).

comment:18 in reply to: ↑ 9 Changed 4 months ago by ronalde

Replying to djs@…:

We're using an apache rewrite to send the request back to the referring page:

Maybe it's worth noting that this should be applied in ssl vhost.

For future reference I'll include our complete setup:

  • multi repositories under /trac
  • custom trac projects index page
  • use of mod_wsgi
  • only https for authentication; everything else via http
  • use of basis ldap authentication

Custom index page for trac root /var/www/multitrac/generated-index/html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      xmlns:py="http://genshi.edgewall.org/"
      xmlns:xi="http://www.w3.org/2001/XInclude">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Generated Trac Index</title>
    <style type="text/css" title="Standaard (Scherm)" media="all">
      @import url("/stylesheets/screen.css");
    </style>
  </head>
  <body>
    <div id="contents">
      <h1>Projects </h1>

      <!-- start #generated -->
      <!-- only display trac projects which do not start with 'Archive' -->
      <div id="generated" class="project"
           py:for="project in projects"
           py:if="project.name.startswith('Archive') == False">
        <h2>
          <!-- replace 'Trac - '  by empty string in description -->
          <a href="$project.href"
             title="$project.description">
            ${project.name.replace(Trac - ','')}
          </a>
        </h2>

        <p>$project.description</p>
      </div><!-- end #generated -->

    </div><!-- end #contents -->
  </body>
</html>

wsgi script in /etc/trac/wsgi/multitrac.wsgi

# application script to enable apache wsgi hosting of trac
# see:
#  * http://trac.edgewall.org/wiki/TracModWSGI
#  * http://code.google.com/p/modwsgi/wiki/IntegrationWithTrac

import sys
sys.stdout = sys.stderr

import os
os.environ['TRAC_ENV_PARENT_DIR'] = '/var/lib/trac'
os.environ['PYTHON_EGG_CACHE'] = '/var/cache/trac'
os.environ['TRAC_ENV_INDEX_TEMPLATE'] = '/var/www/multitrac/trac/index-generated.html'

import trac.web.main

application = trac.web.main.dispatch_request

apache 2 virtual host in /etc/apacha2/sites-available/multitrac

# /etc/apache2/sites-available/multitrac
#
# reference:
#  * only logins via https: http://trac.edgewall.org/ticket/4733
#  * usage of mod_wsgi for trac: http://code.google.com/p/modwsgi/wiki/IntegrationWithTrac
#  * overview of apache mod_rewrite: http://httpd.apache.org/docs/trunk/rewrite/intro.html

<VirtualHost *:80>
    # static root for other pages and htdocs
    DocumentRoot /var/www/multitrac
    ServerName multitrac

    # trac: rewrite to https:// when uri is trac login page
    RewriteEngine on
    RewriteRule ^/trac/([[:alnum:]]+)/login https://multitrac/trac/$1/login [R]

    # trac: match root uri for trac handling
    WSGIScriptAliasMatch ^/trac  /etc/trac/wsgi/multitrac.wsgi

    <Directory /etc/trac/wsgi>
        WSGIApplicationGroup %{GLOBAL}
        # trac: root for trac projects
        SetEnv trac.env_parent_dir /var/lib/trac
        Order deny,allow
        Allow from all
    </Directory>

    <IfModule mod_mem_cache.c>
        CacheEnable mem /
        # cache memory in KB
        MCacheSize 1000000
        MCacheMaxObjectSize 6400000
        MCacheMaxObjectCount 1009
    </IfModule>
</VirtualHost>

<VirtualHost *:443>
    DocumentRoot /var/www/multitrac
    ServerName multitrac

    # ssl-cettings; certificate is generated using cacert
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/ssl-cert-multitrac.pem
    SSLCertificateKeyFile /etc/ssl/private/ssl-key-multitrac.pem

    RewriteEngine on
    # trac: redirect to non-https connection when uri is not login-uri
    # trac: go back to the http referer if there is one
    RewriteCond %{REQUEST_URI} !/trac/[[:alnum:]]+/login$
    RewriteCond %{HTTP_REFERER} ^http://multitrac/trac/.*
    RewriteRule . %{HTTP_REFERER} [R]

    # trac: if there is no referrer, go to the original requested http uri
    RewriteCond %{REQUEST_URI} !/trac/[[:alnum:]]+/login$
    RewriteCond %{HTTP_REFERER} !^http://multitrac/trac/.*
    RewriteRule ^/trac/(.*)$ http://multitrac/trac/$1 [R]

   # trac: define wsgi application
    WSGIScriptAliasMatch ^/trac  /etc/trac/wsgi/multitrac.wsgi

    <Directory /etc/trac/wsgi>
        WSGIApplicationGroup %{GLOBAL}
        # trac: root for trac projects
        SetEnv trac.env_parent_dir /var/lib/trac
        Order deny,allow
        Allow from all
    </Directory>

    # trac: match login page for specific trac project
    <LocationMatch "/trac/[[:alnum:]]+/login">
        AuthType Basic
        AuthName "Multitrac - LDAP-Authentication"
        AuthBasicProvider ldap
        AuthzLDAPAuthoritative off
        AuthLDAPURL "ldaps://ldaphost/dc=search,dc=base?uid?sub?(objectClass=employee)"
        Require valid-user
    </LocationMatch>

</VirtualHost>

Last edited 4 months ago by osimons (previous) (diff)

comment:19 Changed 7 weeks ago by Oliver Tappe <zooey@…>

I'm a bit confused as to why the posted solutions switch away from https as soon as the login page has been left. AFAICS, this means that every security-related cookie (or other information) will travel unprotected through the net, once a person is logged on.

A couple of months ago, I have activated http-digest authentication on our trac installation in order to protect the passwords, which works just fine, but still has the disadvantage of allowing session hijacking by some man-in-the-middle grabbing the cookies. I tried that myself at the time and was easily able to take over a session of someone else and change his password.

That's what makes me believe that the redirection from https back to http should be done on the 'logout' page, not on everything that's not 'login'.

Or am I being daft?

cheers,

Oliver

comment:20 Changed 7 weeks ago by labs@…

The redirecting trick based upon the referer doesn't seem to work with me. After the credentials are securely entered on the /login/ page, trac is redirecting back to the home page, not to the original refering page.

Do other people get this to work? Or do I need to patch the login page somehow?

best,
Dirk

comment:21 Changed 3 weeks ago by labs@…

Replying to myself:

I fixed this double referer issue in the AccountManagerPlugin?. See here  http://trac-hacks.org/ticket/3783#comment:6

Dirk

View

Add a comment

Modify Ticket

Change Properties
<Author field>
Action
as new
as The resolution will be set. Next status will be 'closed'
to The owner will be changed from jonas. Next status will be 'new'
The owner will be changed from jonas to anonymous. Next status will be 'assigned'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.