Opened 18 years ago
Last modified 10 years ago
#4733 new enhancement
Option for all login links to use HTTPS
Reported by: | 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)
follow-up: 24 comment:1 by , 18 years ago
Milestone: | → 0.12 |
---|
comment:2 by , 18 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 , 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
- Move you Trac specific directives into myvhost.conf
- Add the RedirectMatch Directive into myhost.conf
- 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
- Add a LocationMatch Directive for the login page.
- Add a RedirectMatch Directive to redirect all other Trac pages.
- 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:
- User clicks on 'login' on the non-ssl port 80 vhost
- The RecirectMatch in myvhost.conf fires redirecting the user to the SSL site on port 443 site.
- The LocationMatch directive in myvhost-ssl.conf fires and pops up the authentication window you will see https://yourhost identified in the authentication window.
- After the user authenticates, Trac redirects the user to the Trac page, where the user clicked login, on the SSL site port 443 vhost.
- 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 , 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 , 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 , 17 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.
follow-up: 8 comment:7 by , 17 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.
comment:8 by , 17 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).
follow-up: 18 comment:9 by , 16 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 , 16 years ago
Cc: | added |
---|
comment:11 by , 16 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 , 15 years ago
Cc: | added |
---|
follow-up: 14 comment:13 by , 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…)
comment:14 by , 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.
follow-up: 16 comment:15 by , 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?
comment:16 by , 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 , 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).
comment:18 by , 15 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
<!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>
follow-up: 22 comment:19 by , 15 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 , 15 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 , 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
comment:22 by , 13 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 , 12 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.
comment:24 by , 12 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:
- 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
- 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:
- 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.
- 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 , 12 years ago
Cc: | added |
---|
comment:26 by , 10 years ago
Owner: | removed |
---|
We could define a new front-end setting, similar to TracUriRoot, e.g. TracLoginUri.