Use REMOTE_USER server variable (via Siteminder Web agent) for login

871 views
Skip to first unread message

Robert Jacobson

unread,
Aug 5, 2015, 9:36:27 AM8/5/15
to Trac Users

I'm need help setting up Trac 1.0.8 (CentOS 6.6, Apache 2.2.15, Python 2.6.6 and WSGI) to use Siteminder Web Agent for login.  Siteminder is a SSO solution -- there's an Apache agent for it.  In short, it sets server variables like REMOTE_USER to the logged-in user's username.

First I installed Trac and set it up with Apache and WSGI.  This seems to work just fine.

I verified that Siteminder is setting REMOTE_USER by temporarily setting up Apache to point it to a PHP script to output the variables:
ScriptAlias /trac/login "/data/www/cgi-bin-trac/outputvars.php"
I took that out after verifying SiteMinder was working as expected.

I then tried using the setup specified at http://trac.edgewall.org/wiki/TracStandalone to use REMOTE_USER for login.  i.e. I put the remote-user-auth.py script in $ENV/plugins, and modified trac.ini (added the line "obey_remote_user_header = true" to [trac]).

Now when I go to /trac/login, I'm sent briefly to Siteminder's login page, as expected.  After login, I'm returned to the trac site.  The header says "Logged in as username", but the page has the error message:


Trac Error

Authentication information not available. Please refer to the installation documentation.


Then if I visit any other trac page, the header no longer shows me as logged in.

I tried doing:
trac-admin /data/www/html/trac/testproject permission add username TRAC_ADMIN
And that gives me an "Admin" tab briefly after login, but again if I click it or any other page it is like I'm not logged in.

I'm not sure where to go from here, so I would greatly appreciate any assistance. 

RjOllos

unread,
Aug 5, 2015, 1:18:32 PM8/5/15
to Trac Users
Please take a look in the log file and post the traceback associated with the Trac Error:

 

Robert Jacobson

unread,
Aug 5, 2015, 2:05:43 PM8/5/15
to Trac Users

RjOllos

unread,
Aug 5, 2015, 2:53:07 PM8/5/15
to Trac Users


On Wednesday, August 5, 2015 at 11:05:43 AM UTC-7, Robert Jacobson wrote:

I didn't look at the error message carefully enough, so I pointed you to the wrong location in the code where the exception is being raised. 


Could you post your Apache site configuration?


Robert Jacobson

unread,
Aug 5, 2015, 3:15:17 PM8/5/15
to Trac Users


I assume you do NOT need to see the SiteMinder stuff in httpd.conf. 

trac.conf:

LoadModule wsgi_module modules/mod_wsgi.so
#WSGIScriptAlias /wsgi_app /data/www/html/test.wsgi
#WSGIScriptAlias /wsgi_app2 /data/www/html/test.py

Alias /trac/chrome/common /data/www/html/trac/testproject/deploy/htdocs/common
Alias /trac/chrome/site /data/www/html/trac/testproject/deploy/htdocs/site

<Directory "/data/www/html/trac/testproject/deploy/trac/htdocs">
  Order allow,deny
  Allow from all
</Directory>

WSGIScriptAlias /trac /data/www/html/trac/testproject/deploy/cgi-bin/trac.wsgi

<Directory /data/www/html/trac/testproject/deploy/cgi-bin>
    WSGIApplicationGroup %{GLOBAL}
    Order deny,allow
    Allow from all
</Directory>

# This is commented out because nothing worked when it was in effect.
#<Location "/trac/login">
  #RequestHeader set REMOTE_USER %{REMOTE_USER}s
#</Location>



trac.wsgi:

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C)2008-2009 Edgewall Software
# Copyright (C) 2008 Noah Kantrowitz <email@removed>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Noah Kantrowitz <
email@removed>
import os

def application(environ, start_request):
    if not 'trac.env_parent_dir' in environ:
        environ.setdefault('trac.env_path', '/data/www/html/trac/testproject')
    if 'PYTHON_EGG_CACHE' in environ:
        os.environ['PYTHON_EGG_CACHE'] = environ['PYTHON_EGG_CACHE']
    elif 'trac.env_path' in environ:
        os.environ['PYTHON_EGG_CACHE'] = \
            os.path.join(environ['trac.env_path'], '.egg-cache')
    elif 'trac.env_parent_dir' in environ:
        os.environ['PYTHON_EGG_CACHE'] = \
            os.path.join(environ['trac.env_path'], '.egg-cache')
    elif 'trac.env_parent_dir' in environ:
        os.environ['PYTHON_EGG_CACHE'] = \
            os.path.join(environ['trac.env_parent_dir'], '.egg-cache')
    from trac.web.main import dispatch_request
    return dispatch_request(environ, start_request)




RjOllos

unread,
Aug 5, 2015, 3:42:50 PM8/5/15
to Trac Users


On Wednesday, August 5, 2015 at 12:15:17 PM UTC-7, Robert Jacobson wrote:


I assume you do NOT need to see the SiteMinder stuff in httpd.conf. 

trac.conf:

LoadModule wsgi_module modules/mod_wsgi.so
#WSGIScriptAlias /wsgi_app /data/www/html/test.wsgi
#WSGIScriptAlias /wsgi_app2 /data/www/html/test.py

Alias /trac/chrome/common /data/www/html/trac/testproject/deploy/htdocs/common
Alias /trac/chrome/site /data/www/html/trac/testproject/deploy/htdocs/site

<Directory "/data/www/html/trac/testproject/deploy/trac/htdocs">
  Order allow,deny
  Allow from all
</Directory>

WSGIScriptAlias /trac /data/www/html/trac/testproject/deploy/cgi-bin/trac.wsgi

<Directory /data/www/html/trac/testproject/deploy/cgi-bin>
    WSGIApplicationGroup %{GLOBAL}
    Order deny,allow
    Allow from all
</Directory>

# This is commented out because nothing worked when it was in effect.
#<Location "/trac/login">
  #RequestHeader set REMOTE_USER %{REMOTE_USER}s
#</Location>

I'd be interested to see the SiteMinder stuff if it's a Location directive for a path.

It appears you aren't running TracStandalone with mod_proxy, so I'm not sure you need to use the configuration discussed in TracStandalone#Authenticationfortracdbehindaproxy.

Robert Jacobson

unread,
Aug 5, 2015, 3:58:53 PM8/5/15
to Trac Users

No "Location" directives -- Siteminder is loaded as a module :

LoadModule sm_module "/usr/local/webagent/bin/libmod_sm22.so"
SmInitFile "/etc/httpd/conf/WebAgent.conf"


I'm not behind a proxy -- but I couldn't figure out a way for Trac to just use the REMOTE_USER header.  I tried disabling the plugin (remote-user-auth.py) but then when I try "login" I get the same error (Authentication information not available) , but the header stays at "login" .  This is from trac.log:  (note, no "myusername"):

2015-08-05 15:57:39,160 Trac[main] DEBUG: Dispatching <RequestWithSession "GET '/login/'">
2015-08-05 15:57:39,172 Trac[api] WARNING: Unable to find repository '(default)' for synchronization
2015-08-05 15:57:39,174 Trac[main] WARNING: [128.183.232.222] HTTPInternalError: 500 Trac Error (Authentication information not available. Please refer to the <a href="/trac/wiki/TracInstall#ConfiguringAuthentication" title="Configuring Authentication">installation documentation</a>.)
2015-08-05 15:57:39,176 Trac[session] DEBUG: Retrieving session for ID '18a1d9e1907fa10c73e81b38'
2015-08-05 15:57:39,330 Trac[chrome] DEBUG: Prepare chrome data for request


RjOllos

unread,
Aug 5, 2015, 4:15:05 PM8/5/15
to Trac Users
lkraav, who wrote the content on the TracStandalone#Authenticationfortracdbehindaproxy page after getting mod_proxy working with TracStandalone, suggested just changing the path of the Location directive:

<Location "/trac">
  RequestHeader set REMOTE_USER %{REMOTE_USER}s
</Location>

Leho Kraav

unread,
Aug 5, 2015, 4:24:20 PM8/5/15
to trac-...@googlegroups.com
On 05.08.2015 23:15, RjOllos wrote:
>
>
> lkraav, who wrote the content on
> the TracStandalone#Authenticationfortracdbehindaproxy page after getting
> mod_proxy working with TracStandalone, suggested just changing the path
> of the Location directive:
>
> <Location "/trac">
> RequestHeader set REMOTE_USER %{REMOTE_USER}s
> </Location>

That I did. I'm running this with Apache mod_proxy + tracd. I'm not sure
how this works out when there's a module trying to pass the header over
to a Location block, but give it a shot and let us know.

Robert Jacobson

unread,
Aug 5, 2015, 7:30:32 PM8/5/15
to trac-...@googlegroups.com

If I use that Location parameter:
1) With remote-user-auth.py disabled:
- login never results in an actual login
2) With remote-user-auth.py enabled:
- trac header says "logged in as (null) "

We reconfigured SiteMinder to "protect" (i.e. require redirect to login) from "/trac/login" to "/trac", and seems to "work"; i.e. I can now login and stay logged in. However:
- Simply visiting /trac automatically redirects to the SiteMinder login page. I don't really want this; I'd rather people only have to login if they want to edit something in Trac (i.e. I want them to have to click the "Login" link first)
- visiting /trac/login results in a "Authentication information not available" error from Trac. (but I am, in fact, logged in)

RjOllos

unread,
Aug 5, 2015, 8:39:30 PM8/5/15
to Trac Users
On Wednesday, August 5, 2015 at 4:30:32 PM UTC-7, Robert Jacobson wrote:

If I use that Location parameter:
    1)  With remote-user-auth.py disabled:
        - login never results in an actual login
    2)  With remote-user-auth.py enabled:
        - trac header says "logged in as (null) "

The second finding seems to suggests that REMOTE_USER has the value NULL in the Apache environment. But wouldn't that be translated to None in Python?

This page suggests that SiteMinder sets the SM_USER variable:

Maybe you could change the plugin: req.get_header('Remote-User')  -> req.get_header('Sm-User') 
 
We reconfigured SiteMinder to "protect" (i.e. require redirect to login) from "/trac/login" to "/trac", and seems to "work"; i.e. I can now login and stay logged in.  However:
    -  Simply visiting /trac automatically redirects to the SiteMinder login page.  I don't really want this; I'd rather people only have to login if they want to edit something in Trac (i.e. I want them to have to click the "Login" link first)
    -  visiting /trac/login results in a "Authentication information not available" error from Trac. (but I am, in fact, logged in)

Robert Jacobson

unread,
Aug 6, 2015, 10:18:58 AM8/6/15
to Trac Users

You're right, Siteminder doesn't set REMOTE_USER by default -- it does set SM_USER.  But it can be (and currently is) configured to set REMOTE_USER in addition to setting SM_USER.

Is REMOTE_USER required to be set on any other request besides the login request?  I ask because Siteminder only sets the header on "protected" URLs -- so I need to know if setting the header on /trac/login *should be* sufficient.  So far in my testing this has not worked.

I temporarily configured Siteminder to protect "/trac*", and I am now automatically logged in when I visit the site.  I don't have to click "login" to be logged in.  However, this is not what I want -- I want users to have to explicitly click login to be logged in (be anonymous unless they login).

RjOllos

unread,
Aug 6, 2015, 4:55:15 PM8/6/15
to Trac Users


On Thursday, August 6, 2015 at 7:18:58 AM UTC-7, Robert Jacobson wrote:

You're right, Siteminder doesn't set REMOTE_USER by default -- it does set SM_USER.  But it can be (and currently is) configured to set REMOTE_USER in addition to setting SM_USER.

Has the server been configured to set REMOTE_USER throughout our discussion in this thread, or is that a recent configuration change?

Robert Jacobson

unread,
Aug 6, 2015, 6:22:19 PM8/6/15
to Trac Users

It's been that way the whole time.

RjOllos

unread,
Aug 6, 2015, 10:10:21 PM8/6/15
to Trac Users
On Thursday, August 6, 2015 at 3:22:19 PM UTC-7, Robert Jacobson wrote:

It's been that way the whole time.

I think you probably don't need or want to use remote-user-auth.py, the plugin for "authentication behind a proxy". The solution seems to be useful for the case when Trac is running in a different process and the Apache environment is not available to Trac.

In your case Trac is running in Apache and the REMOTE_USER variable is available in the environment. This is the variable that the LoginModule uses for login, so you are probably better off disabling remote-user-auth.py.

Based on what I understand about Apache configuration, the key here seems to be figuring out how to set the Location block. Normally the authentication method (1) goes in the block, but I don't understand how this will work with SiteMinder.

Would the following make any sense, after disabling remote-user-auth.py?

<Location "/trac/login">
  Require valid-user
</Location>

Maybe we are approaching this wrong though. In the configuration guide for MoinMoin they implement redirects (2).

Robert Jacobson

unread,
Aug 6, 2015, 10:59:16 PM8/6/15
to Trac Users

I agree that it's strange to need the remote-auth-user plugin, and I originally thought login would work without it -- but I couldn't get it to work before (it's the first thing I tried!) -- and I still can't.

I did the following:
1)  disabled remote-user-auth.* component in trac.ini
2)  in trac.conf, set Location /trac/login as you specified

Result:  trac home page is OK.  When I visit /trac/login, I get redirected to the Siteminder login page, and after I login, back to my site (/trac/login again), at which point I get an Apache "Internal Server Error":

[Thu Aug 06 22:40:32 2015] [crit] [client 192.168.10.10] configuration error:  couldn't perform authentication. AuthType not set!: /trac/login, referer: https://siteminder-server/auth/redirect.aspx?authtype=ldap20&target=https://192.168.10.10/trac/login

This is expected, as according to the Apache docs, "Require must be accompanied by AuthName and AuthType directives"

None of the AuthTypes available make sense.  And AFAICT Siteminder doesn't provide an AuthType itself.

Just to confirm -- if I remove the "Location" settings from trac.conf, and alias /trac/login to my outputvars.php script (in trac.conf):

ScriptAlias /trac/login "/data/www/cgi-bin-trac/outputvars.php"

I can see that after the Siteminder login, REMOTE_USER is in fact set in the header.  I just don't know how to configure Trac to use it!  The proxy config on TracStandalone is the only example I could find.

Robert Jacobson

unread,
Aug 6, 2015, 11:25:49 PM8/6/15
to Trac Users

I'm curious about one thing in the trac.log:

2015-08-06 23:24:48,064 Trac[main] DEBUG: Dispatching <RequestWithSession "GET '/login'">

The trac login url is /trac/login -- why is it showing /login?

RjOllos

unread,
Aug 7, 2015, 1:11:01 AM8/7/15
to Trac Users
That appears to be intentional in the code. RequestWithSession's __repr__ method is being called, which print the value of  environ['PATH_INFO']. environ['PATH_INFO'] is manipulated in request_dispatcher to remove the environment name from PATH_INFO. request_dispatcher is called from the trac.wsgi script:

Jun Omae

unread,
Aug 7, 2015, 9:16:51 PM8/7/15
to trac-...@googlegroups.com
On Thu, Aug 6, 2015 at 8:30 AM, Robert Jacobson <ter...@gmail.com> wrote:
>
> If I use that Location parameter:
> 1) With remote-user-auth.py disabled:
> - login never results in an actual login
> 2) With remote-user-auth.py enabled:
> - trac header says "logged in as (null) "
>
> We reconfigured SiteMinder to "protect" (i.e. require redirect to login) from "/trac/login" to "/trac", and seems to "work"; i.e. I can now login and stay logged in. However:
> - Simply visiting /trac automatically redirects to the SiteMinder login page. I don't really want this; I'd rather people only have to login if they want to edit something in Trac (i.e. I want them to have to click the "Login" link first)
> - visiting /trac/login results in a "Authentication information not available" error from Trac. (but I am, in fact, logged in)

REMOTE_USER variable is NOT a HTTP header, so that RequestHeader
directive doesn't work for setting REMOTE_USER variable.

Instead, try to set REMOTE_USER with username on SM_USER in trac.wsgi:
refs http://trac.edgewall.org/wiki/TracModWSGI#GettingTractoworknicelywithSSPIandRequireGroup.

====
...

def application(environ, start_request):
# Set authenticated username on CA SiteMinder to REMOTE_USER variable
if 'SM_USER' in environ:
environ['REMOTE_USER'] = environ['SM_USER']
if not 'trac.env_parent_dir' in environ:
environ.setdefault('trac.env_path', '/data/www/html/trac/testproject')
...
===

--
Jun Omae <jun...@gmail.com> (大前 潤)

Robert Jacobson

unread,
Aug 8, 2015, 7:34:59 AM8/8/15
to Trac Users

Thanks for trying to help!

I'll make one important note:  Siteminder only sets the REMOTE_USER (and/or SM_USER) in the header when you're at a "protected" URL.  In the current config, that's only /trac/login.  I'm sure this is happening; see below.

I made the change you suggested, but I still cannot login.  I tried both with and without the Location setting for /trac/login:

<Location "/trac/login">
WSGIPassAuthorization On
#  RequestHeader set REMOTE_USER %{SM_USER}s
</Location>

Two things:  I don't think the code you suggested is ever being executed.  I added some debug:

import os
import sys

def application(environ, start_request):
    print >> sys.stderr, "trac.wsgi: FOOBAR"
    # Set authenticated username on CA SiteMinder to REMOTE_USER variable
    if 'SM_USER' in environ:
        print >> sys.stderr, "trac.wsgi: setting REMOTE_USER to SM_USER"
        environ['REMOTE_USER'] = environ['SM_USER']

I get "trac.wsgi: FOOBAR" in httpd error_log, but never "trac.wsgi: setting REMOTE_USER to SM_USER".

The code below is how I checked to make sure Siteminder is setting the REMOTE_USER variable in the header (in remote-user-auth.py). 

    def authenticate(self, req):
        authname = None
        if self.obey_remote_user_header and req.get_header('Remote-User'):
            self.env.log.debug("remote-user-auth: Remote-User is: " + req.get_header('Remote-User'))
            authname = req.remote_user
        elif 'trac_auth' in req.incookie:
            self.env.log.debug("remote-user-auth: using incookie")
            authname = self._get_name_for_cookie(req,
                                                 req.incookie['trac_auth'])
        if not req.get_header('Remote-User'):
            self.env.log.debug("remote-user-auth: NO Remote-User set")
            """raise TracError('NO REMOTE USER')"""
        return authname

In the trac.log file, when I visit /trac/login (WITHOUT the Location "RequestHeader set" declaration above), I do see that REMOTE_USER must be set in the request header:

2015-08-08 07:28:08,279 Trac[main] DEBUG: Dispatching <RequestWithSession "GET '/login'">
2015-08-08 07:28:08,286 Trac[api] WARNING: Unable to find repository '(default)' for synchronization
2015-08-08 07:28:08,288 Trac[main] WARNING: [127.0.0.1] HTTPInternalError: 500 Trac Error (Authentication information not available. Please refer to the <a href="/trac/wiki/TracInstall#ConfiguringAuthentication" title="Configuring Authentication">installation documentation</a>.)
2015-08-08 07:28:08,289 Trac[remote-user-auth] DEBUG: remote-user-auth: Remote-User is: rjacobso
2015-08-08 07:28:08,290 Trac[session] DEBUG: Retrieving session for ID '7437970e40bc6d6f7eeb0f99'

One thing that concerns me is that trac says the ID is 7437970e40bc6d6f7eeb0f99.  Where is this number coming from?  Shouldn't it be the username?  

If I change Apache to Basic authentication (using htpasswd file), the session line does contain:

2015-08-08 07:33:26,270 Trac[session] DEBUG: Retrieving session for ID u'rjacobson'

Jun Omae

unread,
Aug 8, 2015, 8:17:06 AM8/8/15
to trac-...@googlegroups.com
On Sat, Aug 8, 2015 at 8:34 PM, Robert Jacobson <ter...@gmail.com> wrote:
> I'll make one important note: Siteminder only sets the REMOTE_USER (and/or
> SM_USER) in the header when you're at a "protected" URL. In the current
> config, that's only /trac/login. I'm sure this is happening; see below.
>
> I made the change you suggested, but I still cannot login. I tried both
> with and without the Location setting for /trac/login:
>
> <Location "/trac/login">
> WSGIPassAuthorization On
> # RequestHeader set REMOTE_USER %{SM_USER}s
> </Location>
>
> Two things: I don't think the code you suggested is ever being executed. I
> added some debug:
>
> import os
> import sys
>
> def application(environ, start_request):
> print >> sys.stderr, "trac.wsgi: FOOBAR"
> # Set authenticated username on CA SiteMinder to REMOTE_USER variable
> if 'SM_USER' in environ:
> print >> sys.stderr, "trac.wsgi: setting REMOTE_USER to SM_USER"
> environ['REMOTE_USER'] = environ['SM_USER']
>
> I get "trac.wsgi: FOOBAR" in httpd error_log, but never "trac.wsgi: setting
> REMOTE_USER to SM_USER".

Oh, sorry. I just mistake. Replace SM_USER with HTTP_SM_USER.

def application(environ, start_request):
# Set authenticated username on CA SiteMinder to REMOTE_USER variable
if 'HTTP_SM_USER' in environ:
environ['REMOTE_USER'] = environ['HTTP_SM_USER']
...

If the issue is still not solved, please confirm what name in
"environ" is using for username from SiteMinder to dump all of
"environ" when visiting /trac/login like this:

def application(environ, start_request):
print >>sys.stderr, repr(environ)
# Set authenticated username on CA SiteMinder to REMOTE_USER variable
if 'HTTP_SM_USER' in environ:
environ['REMOTE_USER'] = environ['HTTP_SM_USER']
...

Robert Jacobson

unread,
Aug 8, 2015, 9:11:22 AM8/8/15
to Trac Users

Wow, thank you so much -- that worked!  I can now login to trac properly.  I love you!  :)

I had one minor issue but I fixed it.  Siteminder put a space on the end of HTTP_SM_USER (e.g. "rjacobso ").

I simply changed the code to strip() the space:

        environ['REMOTE_USER'] = environ['HTTP_SM_USER'].strip()

and now REMOTE_USER is properly set to "rjacobso".

Robert Jacobson

unread,
Aug 8, 2015, 9:54:36 AM8/8/15
to Trac Users

I've added a section to the wiki about how to configure Trac for SiteMinder authentication:

Ryan Ollos

unread,
Aug 8, 2015, 9:18:55 PM8/8/15
to Trac Users
On Sat, Aug 8, 2015 at 6:54 AM, Robert Jacobson <ter...@gmail.com> wrote:

I've added a section to the wiki about how to configure Trac for SiteMinder authentication:


Excellent! I didn't think this one would be solved. Thank you for adding the documentation. 
Reply all
Reply to author
Forward
0 new messages