Understanding Trac Authentication (trac+nginx+ldap)

687 views
Skip to first unread message

deadf00d

unread,
Jan 19, 2016, 9:51:29 AM1/19/16
to Trac Users
Hi all,

I'm trying to set up tracd behind nginx with LDAP authentication handled by nginx.
My approach is setting the REMOTE_USER header from nginx and using the
remote-user-auth.py script from http://trac.edgewall.org/wiki/TracStandalone#Authenticationfortracdbehindaproxy

The nginx/ldap part works fine and the user gets passed to trac, as you can see here (says 'angemeldet als alex'):
http://postimg.org/image/vtj2jpqih/

Yet, it displays "Trac Error Authentication information not available."
I'm reading all the documentation I can find on the issue and only get mor confused.

Is my approach (letting nginx handle the authentication) correct?
I was thinking that the remote user would be sufficient and thus no authentication data is needed at the trac side.
Or does trac require additional data besides the REMOTE_USER?

Kind regards and thanks in advance,
Alex

RjOllos

unread,
Jan 19, 2016, 2:50:24 PM1/19/16
to Trac Users
I'm unsure if REMOTE_USER and/or HTTP_REMOTE_USER needs to be set. I'll attempt to trace the flow in reverse.

If the site shows //Logged in as xxx//, then req.authname returned a valid value:

req.authname is set through a callback, which iterates over the IAuthenticator implementations:

When your "MyRemoteUserAuthenticator" authenticator executes, it calls get_header, which returns a value from the _inheaders dictionary:

req._inheaders is a callback that calls req._parse_headers:

From the logic in req._parse_headers, 
it looks like a call to req.get_headers('Remote-User') will only return a value if HTTP_REMOTE_USER is set.

So best I can infer, HTTP_REMOTE_USER is being set in your request, and therefore req.authname is being set.

On the other hand, when a request is sent to /login, req.remote_user must return the username otherwise the error is seen:

From the behavior you've described it sounds like req.remote_user is None. Therefore I infer that REMOTE_USER hasn't been set:

So it looks to me like HTTP_REMOTE_USER is set in the environ dictionary, but REMOTE_USER is not set.

What comes to mind is another configuration which was discussed on the mailing list a few weeks back:
I never understood why REMOTE_USER needed to be explicitly set.

This issue might be related:
 
Could you share your script that invokes tracd, as well as your Nginx configuration?

The following might be helpful:

- Ryan

Alexander Pokahr

unread,
Jan 20, 2016, 9:51:18 AM1/20/16
to trac-...@googlegroups.com
Dear Ryan,

thanks for your quick and detailed reply.

I think I understand the problem and it seems that your analysis regarding
REMOTE_USER and HTTP_REMOTE_USER is right. Yet, I do not understand how to fix this.
The TracModWSGI approach seems promising, but as I run tracd, I do not know
where to add the ''environ['REMOTE_USER'] = environ['HTTP_REMOTE_USER']" line.

I can't do it in remote-user-auth.py as far as I can see, because there I have no access to
'environ', right?

My setup is as follows:

Tracd started with "tracd -d -p 8080 --protocol=http -s /usr/local/trac/myproject".

Nginx conf:

ldap_server myldapserver {
          url "ldaps://ldap.mydomain.com:636/...";
          binddn "...";
          binddn_passwd "...";
          connect_timeout 5s;
          bind_timeout 5s;
          request_timeout 5s;
          satisfy any;
}

server {
    listen 80;
    server_name trac.mydomain.com;

    location / {
        proxy_pass http://trac.mydomain.com:8080;
    }
   
    location /login {
        proxy_pass http://trac.mydomain.com:8080;
        auth_ldap "Please enter your credentials for issue tracker";
        auth_ldap_servers myldapserver;
        proxy_set_header REMOTE_USER $remote_user;
    }
}

Any further help will be much appreciated.

Kind regards,
Alex
--
You received this message because you are subscribed to the Google Groups "Trac Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to trac-users+...@googlegroups.com.
To post to this group, send email to trac-...@googlegroups.com.
Visit this group at https://groups.google.com/group/trac-users.
For more options, visit https://groups.google.com/d/optout.

RjOllos

unread,
Jan 20, 2016, 8:05:26 PM1/20/16
to Trac Users
Did you try using the directive "proxy_pass_header Authorization;"? I'm not sure what the function is, but it is used in the authorization example on the TracNginxRecipe page.

Alexander Pokahr

unread,
Jan 22, 2016, 7:13:03 AM1/22/16
to trac-...@googlegroups.com
Hi Ryan,

thanks again for the quick reply.

I think, the 'proxy_pass_header Authorization' directive is only necessary,
when trac should handle authentication. Cf. https://en.wikipedia.org/wiki/Basic_access_authentication#Client_side
In my setting, I want nginx to handle (not pass) this authorization header.

Just to be sure, I tried with 'proxy_pass_header Authorization' as well, but this does not change anything.

Is there some place, where I can patch the ''environ['REMOTE_USER'] = environ['HTTP_REMOTE_USER']" line?
I'm new to python, so any directions would speed up my attempts.

I'm happy to help setting up some useful description for Trac with nginx, once this works out.
Not that I'm an nginx expert. Using it for a couple of month now...

Kind regards,
Alex

RjOllos

unread,
Jan 25, 2016, 4:43:03 AM1/25/16
to Trac Users


On Friday, January 22, 2016 at 4:13:03 AM UTC-8, deadf00d wrote:
Hi Ryan,

thanks again for the quick reply.

I think, the 'proxy_pass_header Authorization' directive is only necessary,
when trac should handle authentication. Cf. https://en.wikipedia.org/wiki/Basic_access_authentication#Client_side
In my setting, I want nginx to handle (not pass) this authorization header.

Just to be sure, I tried with 'proxy_pass_header Authorization' as well, but this does not change anything.

Is there some place, where I can patch the ''environ['REMOTE_USER'] = environ['HTTP_REMOTE_USER']" line?
I'm new to python, so any directions would speed up my attempts.

I'm happy to help setting up some useful description for Trac with nginx, once this works out.
Not that I'm an nginx expert. Using it for a couple of month now...

Kind regards,
Alex

I read through the following ticket again:

The following modification might solve the issue:

    def authenticate(self, req):
        if self.obey_remote_user_header and req.get_header('Remote-User'): 
            remote_user = req.get_header('Remote-User') 
            req.environ['REMOTE_USER'] = remote_user
return remote_user return None


RjOllos

unread,
Jan 25, 2016, 4:58:12 AM1/25/16
to Trac Users
If that doesn't work, we can possibly try to replace AuthenticationMiddleware by monkey-patching, implementing a solution similar to:


Alexander Pokahr

unread,
Jan 25, 2016, 11:40:22 AM1/25/16
to trac-...@googlegroups.com
Hi Ryan,

the patch works!
I can now authenticate in nginx and trac detects the authenticated user as expected.

Unfortunately, I still have some issues:

First, for some reason, the browser receives a location header like this:
Location: http://trac.mydomain.com:8080
The public page should rather be https://trac.mydomain.com/
After logging in, I can go back to the correct page and browse the page fine.
The redirect only happens on '/login' and '/logout'.

Second, I want to make use of LDAP groups, i.e., assign trac-admin rights
to members of a special group. Is there a way to pass this information from
nginx to trac? E.g. a REMOTE_GROUP(S) header?

Kind regards,
Alex

Jun Omae

unread,
Jan 25, 2016, 12:21:00 PM1/25/16
to trac-...@googlegroups.com
On Tue, Jan 26, 2016 at 1:40 AM, Alexander Pokahr <pok...@gmx.net> wrote:
> Hi Ryan,
>
> the patch works!
> I can now authenticate in nginx and trac detects the authenticated user as
> expected.
>
> Unfortunately, I still have some issues:
>
> First, for some reason, the browser receives a location header like this:
> Location: http://trac.mydomain.com:8080
> The public page should rather be https://trac.mydomain.com/
> After logging in, I can go back to the correct page and browse the page
> fine.
> The redirect only happens on '/login' and '/logout'.

I guess your Nginx configuration has the problems. Try like the following.

proxy_redirect http://trac.mydomain.com:8080/ /;

See also
- http://stackoverflow.com/a/20311241
- http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect

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

Alexander Pokahr

unread,
Jan 25, 2016, 12:25:28 PM1/25/16
to trac-...@googlegroups.com
Dear Jun Omae,

thanks for your reply, but I use proxy_pass and not proxy_redirect.
The directive works fine for other build tools (nexus, jenkins)
and also for all areas of trac, except /login and /logout.

Kind regards,
Alex

Jun Omae

unread,
Jan 25, 2016, 12:49:42 PM1/25/16
to trac-...@googlegroups.com
On Tue, Jan 26, 2016 at 2:25 AM, Alexander Pokahr <pok...@gmx.net> wrote:
> thanks for your reply, but I use proxy_pass and not proxy_redirect.
> The directive works fine for other build tools (nexus, jenkins)
> and also for all areas of trac, except /login and /logout.

I suggest both proxy_pass and proxy_redirect should be used.

server {
listen 80;
server_name trac.mydomain.com;

location / {
proxy_pass http://trac.mydomain.com:8080;
proxy_redirect http://trac.mydomain.com:8080 /;
# ^ must strip /
}

location /login {
proxy_pass http://trac.mydomain.com:8080/login;
proxy_redirect http://trac.mydomain.com:8080 /;
auth_ldap "Please enter your credentials for issue tracker";
auth_ldap_servers myldapserver;
proxy_set_header REMOTE_USER $remote_user;
}
}

RjOllos

unread,
Jan 25, 2016, 4:38:01 PM1/25/16
to Trac Users
On Monday, January 25, 2016 at 8:40:22 AM UTC-8, deadf00d wrote:
Hi Ryan,

the patch works!
I can now authenticate in nginx and trac detects the authenticated user as expected.

I thought about it some more last evening and I'm rather surprised that it works for you. Presumably the `perm` callback needs to be invoked to set req.environ['REMOTE_USER']. I don't see where the callback is invoked in either trac.web.main.dispatch_request or when the request is matched and processed in trac.web.auth:
 
I also don't see how the recipe discussed in #9206 can work, unless the Trac instance is not available to anonymous users. If none of the Trac paths can be accessed by anonymous users and the user is forced to authenticate through the web server first for any path, then login/logout buttons would be non-functional.

Unfortunately, I still have some issues:

First, for some reason, the browser receives a location header like this:
Location: http://trac.mydomain.com:8080
The public page should rather be https://trac.mydomain.com/
After logging in, I can go back to the correct page and browse the page fine.
The redirect only happens on '/login' and '/logout'.

Second, I want to make use of LDAP groups, i.e., assign trac-admin rights
to members of a special group. Is there a way to pass this information from
nginx to trac? E.g. a REMOTE_GROUP(S) header?

I think that DirectoryAuthPlugin may help you with that, or you may want to look at other plugins such as LdapPlugin. I'm not familiar with the details of the plugins.

RjOllos

unread,
Jan 25, 2016, 6:13:40 PM1/25/16
to Trac Users


On Monday, January 25, 2016 at 1:38:01 PM UTC-8, RjOllos wrote:
On Monday, January 25, 2016 at 8:40:22 AM UTC-8, deadf00d wrote:
Hi Ryan,

the patch works!
I can now authenticate in nginx and trac detects the authenticated user as expected.

I thought about it some more last evening and I'm rather surprised that it works for you. Presumably the `perm` callback needs to be invoked to set req.environ['REMOTE_USER']. I don't see where the callback is invoked in either trac.web.main.dispatch_request or when the request is matched and processed in trac.web.auth:
 
I also don't see how the recipe discussed in #9206 can work, unless the Trac instance is not available to anonymous users. If none of the Trac paths can be accessed by anonymous users and the user is forced to authenticate through the web server first for any path, then login/logout buttons would be non-functional.

Posted some more thoughts here:

Alexander Pokahr

unread,
Feb 18, 2016, 10:25:52 AM2/18/16
to trac-...@googlegroups.com
Dear all,

for the record, the following nginx.conf solved my port redirect issues:

server {
listen 80;
server_name trac.mydomain.com;

location / {
proxy_pass http://trac.mydomain.com:8080;
proxy_redirect http://trac.mydomain.com:8080
https://trac.mydomain.com;
}

location /login {
https://trac.mydomain.com;
auth_ldap "Please enter your credentials for issue tracker";
auth_ldap_servers myldapserver;
proxy_set_header REMOTE_USER $remote_user;
}
}

Cheers,
Alex
Reply all
Reply to author
Forward
0 new messages