Edgewall Software
Modify

Opened 17 years ago

Last modified 9 years ago

#4733 new enhancement

Option for all login links to use HTTPS

Reported by: jeffcorbets@… Owned by:
Priority: normal Milestone: next-major-releases
Component: general Version:
Severity: normal Keywords: secure, login, https
Cc: felix.schwarz@…, trac-bugs@…, ethan.jucovy@… Branch:
Release Notes:
API Changes:
Internal Changes:

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 (0)

Change History (26)

comment:1 by Christian Boos, 17 years ago

Milestone: 0.12

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

comment:2 by jeffcorbets@…, 17 years ago

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 by dacat, 17 years ago

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 by jeffcorbets, 17 years ago

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 by shap, 17 years ago

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 by Martin <martin@…>, 16 years ago

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 by robin-trac@…, 16 years ago

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.

in reply to:  7 comment:8 by Noah Kantrowitz, 16 years ago

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 by djs@…, 15 years ago

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 by Felix Schwarz <felix.schwarz@…>, 15 years ago

Cc: felix.schwarz@… added

comment:11 by Olivier Mehani <shtrom-trac@…>, 15 years ago

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 by AllenJB <trac-bugs@…>, 15 years ago

Cc: trac-bugs@… added

comment:13 by madyogi, 15 years ago

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

in reply to:  13 comment:14 by Felix Schwarz <felix.schwarz@…>, 15 years ago

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 by anonymous, 15 years ago

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?

in reply to:  15 comment:16 by Felix Schwarz <felix.schwarz@…>, 15 years ago

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 by madyogi, 15 years ago

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

in reply to:  9 comment:18 by ronalde, 14 years ago

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

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>

Version 0, edited 14 years ago by ronalde (next)

comment:19 by Oliver Tappe <zooey@…>, 14 years ago

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 by labs@…, 14 years ago

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 by labs@…, 14 years ago

Replying to myself:

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

Dirk

in reply to:  19 comment:22 by Oleg, 12 years ago

Replying to Oliver Tappe <zooey@…>:

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?

In our case, if session is intercepted it is not critical, because wiki stores its history and there are no big secrets. What is important, is to protect the password, because it comes from university wide LDAP and it gives access to a lot more than wiki, e.g. email accounts.

comment:23 by ethan.jucovy@…, 11 years ago

Note that if you use an Apache RewriteRule to kick users over from http://hostname/path/login to https://hotname/path/login (as described in comment:11, comment:17 and comment:18) then you may need to use the [NE] (no-escape) flag in your Apache configuration:

    RewriteRule ^/([^/]+)/login     https://mytracserver/$1/login  [R, NE]

Otherwise Apache will re-escape the ?referer= querystring that Trac has created and already escaped, which will result in unusable ?referer arguments like ?referer=http%253A%252F%252Fthe_host%252Fthe_project%252Ftimeline.

This problem doesn't seem to happen if you use RedirectMatch.

See th:comment:ticket:2210:36 for a bit more detail about this problem.

in reply to:  1 comment:24 by ethan.jucovy@…, 11 years ago

Replying to cboos:

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

I think that having a trac_login_uri setting would be insufficient. That would only cause Trac's own generated links to point to an HTTPS URL. But plugin code already exists that generates links to the login URL (using req.href.login() hopefully) so, unless the Href object were changed to check the login_uri setting, plugin code might still generate bad links. And, more importantly, even if all plugin code in the wild were changed, users could still type in the URL http://hostname/login/ and submit the form over HTTP without ever noticing anything was wrong.

I think a better approach would be to implement something like the Apache rewrite code described in comments within Trac itself — that is, to intercept HTTP requests to /login/ using an IRequestFilter and raise a redirect to the same URL over HTTPS. This way no existing link-generation code, or user bookmarks, would need to change in order for an installation to be secure by default.

A user would still be able to manually construct an HTTP POST request to the /login/ handler over unsecured HTTP, but:

  1. there would be no way for the user to view the login form in the browser over HTTP, so this would have to be a deliberate choice by a user who knows how to manually construct an HTTP POST request, instead of an inadvertent form submission in a browser
  2. even if a user did do this for some reason, the IRequestFilter would still intercept the HTTP request, and return a redirect to the HTTPS URL. So the POST contents themselves might be leaked (potential credentials) but not the server's response to the authentication attempt (verification that the credentials work)

This approach would not address cases where authentication occurs in Apache itself (since Apache would present and validate an auth challenge before any Trac code is reached) so for those cases a login_uri setting might still be useful. But:

  1. this approach would work for cases where authentication occurs in Python code, for example when the installation uses the AccountManager plugin for login. Since this scenario only exists when plugins are installed, I'm not sure it makes sense for the HTTPS-only feature itself to exist in Trac core.
  2. for cases where login is set up in Apache, the problem can and should also be fixed in the Apache configuration — by ensuring that the authentication challenge on /login only occurs in the HTTPS configuration, and that in the HTTP configuration the /login path results in a redirect, per the solution in the above comments.

I've implemented this as a new feature in the th:wiki:PermRedirectPlugin — see th:comment:ticket:10642:1 for details.

So, in short, I think the most important aspect of this feature should always be handled either in Apache configuration (per the above comments) or in plugin code (where it now exists, in th:wiki:PermRedirectPlugin). A login_uri setting might still be useful, but seems less important, and also (in order to be a comprehensive solution) might open a whole can of worms about the Href() object.

So I think it would make sense for this ticket to be marked wontfix.

comment:25 by ethan.jucovy@…, 11 years ago

Cc: ethan.jucovy@… added

comment:26 by Ryan J Ollos, 9 years ago

Owner: Jonas Borgström removed

Modify Ticket

Change Properties
Set your email in Preferences
Action
as new The ticket will remain with no owner.
The ticket will be disowned.
as The resolution will be set. Next status will be 'closed'.
The owner will be changed from (none) to anonymous. Next status will be 'assigned'.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.