03 March 2008

Shibboleth and Rails

My company wrote a Rails application for a client at a major university that was intended to authenticate via Shibboleth to the campus's single-sign-on site. The application is fronted by a cluster of mongrel servers which are proxied by Apache 2.2.

The idea is to authenticate against Shibboleth which will set the REMOTE_USER variable in Apache to the authenticated user's username. The Rails application would then authorize against that REMOTE_USER variable.

The Shibboleth setup went okay and I was able to secure the site. The problem, however, was that the REMOTE_USER variable was not showing up in the request.env hash in Rails as it should.

Ultimately, the fix was to include this chunk of code in my Apache virtual host config file.

RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (^(.+?)@.+$)
RewriteRule . - [E=RU:%2]
RequestHeader add X-Forwarded-User %{RU}e

What this did was to take the remote user variable that gets set by Shibboleth and write it to a new header. That header, in turn, gets renamed by mongrel as HTTP_X_FORWARDED_USER. In the Rails app, I could then read the value of request.env['
HTTP_X_FORWARDED_USER'] in my authorization routine.

Oh, and that regex in the RewriteCond line was to strip of the "@foo.edu" that gets set even though Shibboleth was configured to strip that off.

Credit for this solution goes to the author of the post at http://www.ruby-forum.com/topic/83067#151189.


  1. i have to do this exact scenario. do you have code or further details about how you integrated shib and rails?

  2. Well, assuming that you have Shibboleth installed and configured, the key chunk is those lines in the post that go into your virtual host section for Apache.

    Other than that, here's a throw-away authorization routine for Rails. YMMV.

    (Oh, and I apologize about the lack of formatting. Blogger won't let me use span or pre html tags in comments. Grrr.)

    class ApplicationController < ActionController::Base


    #Check that an authenticated user is permitted to use this system.

    def authorize

    login_name = request.env["HTTP_X_FORWARDED_USER"]

    unless login_name
    #Send to error page
    flash[:notice] = "Could not resolve your NetID, Please log in using Shibboleth"
    redirect_to(:controller => :login, :action => :error_page )

    user = User.find(:first, :conditions => ["login_name = ?", login_name])
    unless user
    flash[:notice] = "You are not authorized to use this application"
    redirect_to(:controller => :login, :action => :error_page )


  3. can u please explain which shibboleth should be installed to get this results? I mean the SP or the IDP? And they can be tested with testshib to get this result or we have to install them locally to test this?


  4. @navo: Sorry, no comprendo. Seriously, I don't know much about Shibboleth at all. It was already running on the box that I inherited and had to make work with Rails.

  5. Would the same be accomplished by using

    ShibUseHeaders On


    see: https://spaces.internet2.edu/display/SHIB2/NativeSPApacheConfig

  6. Hi all,
    I am using IDP initiated single sign on, can anyone explain me how to extract attributes using shibboleth in SP.

    The SP is a ruby on rails application using Apache + Mongrel configuration.

  7. The problem with this solution is that now anyone can attack your security by sending an actual X-Forwarded-User header in their HTTP request, and your Rails app will just trust that they are who they say they are. Or am I missing a part of that invocation that guards against that?

    Any idea why Rails is having trouble getting the actual ENV variables that apache is setting?

  8. @bibwild You're absolutely correct. The original solution is weak in that regard. Since then, I have done an install of Shib2 and RoR using Apache + Passenger, i.e., no Mongrel. The latest version of Passenger at the time (>2.2.4 I think) had no problems handling the ENV variables set by Apache. Using Passenger may not be an option if you are serving your RoR app. up on Windows though.