Problem with http_authentication + apache2 + mod_fcgid

Hi,

I’m using the http_authentication plugin, and everything’s working
fine in my development environment with webrick. However, when I run
on my production platform of apache2+mod_fcgid,
authenticate_or_request_with_http_basic() always returns false, and
(more interestingly) never processes the block. See example below.

Here’s my setup:

  • apache 2.0.55
  • libapache2-mod-fcgid 1.07-1
  • ruby 1.8.2-1
  • libfcgi-ruby1.8 0.8.6-1
  • rails 1.2.3
  • http_authentication r6836 from
    http://svn.rubyonrails.org/rails/plugins
    (hasn’t changed since 2006-12-02?)

For an example, in the following test code, the second debug message
(with username and password) is never reached.


class FooController < ApplicationController

before_filter :test_auth

def test_auth
logger.info “test_auth: debug about to authenticate”
authenticate_or_request_with_http_basic do |username, pass|
logger.info “test_auth: debug #{username}, #{pass}”
true
end
end

def index
end

end

When the above test code runs in webrick, all is well. Running in
apache2 + mod_fcgid, the following happens:

  1. message appears in the log:

Processing FooController#index (for 127.0.0.1 at 2007-05-25 15:32:05)
[GET]
Session ID: b633470f7d331ae1603204f5b879ece3
Parameters: {“action”=>“index”, “controller”=>“foo”}
test_auth: debug about to authenticate
Filter chain halted as
[#<ActionController::Filters::ClassMethods::SymbolFilter:0xb755ac18
@filter=:test_auth>] returned false.
Completed in 0.00040 (2487 reqs/sec) | Rendering: 0.00007 (17%) | 401
Unauthorized [http://scmodstest/foo/index]

  1. user is prompted by user agent (browser) for name and password.

  2. message appears in the log:

Processing FooController#index (for 127.0.0.1 at 2007-05-25 15:32:12)
[GET]
Session ID: b633470f7d331ae1603204f5b879ece3
Parameters: {“action”=>“index”, “controller”=>“foo”}
test_auth: debug about to authenticate
Filter chain halted as
[#<ActionController::Filters::ClassMethods::SymbolFilter:0xb74aee90
@filter=:test_auth>] returned false.
Completed in 0.00036 (2816 reqs/sec) | Rendering: 0.00007 (19%) | 401
Unauthorized [http://scmodstest/foo/index]

  1. lather, rinse, repeat.

Does anybody have any idea what’s going on here? Has anyone else had
similar problems in a similar environment? How about success in a
similar environment?

-mike

OK, figured this one out. In case anyone else is interested, here’s
the deal.

Apache does not, by default, pass authorization headers to CGI
scripts. You can read up a bit about this at:
http://wiki.rubyonrails.org/rails/pages/HowtoAuthenticateWithHTTP

Long story short, I had to modify the fcgid RewriteRule and make a
small change to the http_authentication code to allow it to recognize
REDIRECT_HTTP_AUTHORIZATION. I also applied a change from the Rails
edge version of http_authentication.

Patch below:

Index: public/.htaccess

— public/.htaccess (revision 819)
+++ public/.htaccess (revision 821)
@@ -31,7 +31,8 @@
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
#RewriteRule ^(.)$ dispatch.cgi [QSA,L]
-RewriteRule ^(.
)$ dispatch.fcgi [QSA,L]
+#RewriteRule ^(.)$ dispatch.fcgi [QSA,L]
+RewriteRule ^(.
)$ dispatch.fcgi [E=HTTP_AUTHORIZATION:%
{HTTP:Authorization},QSA,L]

In case Rails experiences terminal errors

Instead of displaying this message you can supply a file here which

will be rendered instead

Index: vendor/plugins/http_authentication/lib/http_authentication/
basic.rb

— vendor/plugins/http_authentication/lib/http_authentication/
basic.rb (revision 819)
+++ vendor/plugins/http_authentication/lib/http_authentication/
basic.rb (revision 821)
@@ -19,10 +19,10 @@
end

 def authenticate(controller, &login_procedure)
  •  if authorization(controller.request)
    
  •  if authorization(controller.request).blank?
    
  •    false
    
  •  else
    

login_procedure.call(*user_name_and_password(controller.request))

  •  else
    
  •    false
     end
    
    end

@@ -32,6 +32,7 @@

 def authorization(request)
   request.env['HTTP_AUTHORIZATION']   ||
  •  request.env['REDIRECT_HTTP_AUTHORIZATION']   ||
     request.env['X-HTTP_AUTHORIZATION'] ||
     request.env['X_HTTP_AUTHORIZATION']
    
    end