How to Catch a Status 401 with htpasswd?

Hi All,

I would love to hear your thoughts on this.

I am using the htpasswd plugin located here:
http://wota.jp/svn/rails/plugins/branches/stable/htpasswd/

To validate access against a .htpasswd file. The plugin is working
great but currently if you fail to get the PW correct and generate a 401
(Unauthorized) the user is presented with a completely blank page.

My goal is to at least redirect them to the home page or present a
message saying their login attempts have failed.

Here is what i have tried:
#application.rb
  rescue_from Htpasswd::UnknownUserAccount, :with => :http_status_code

def http_status_code
  redirect_to "http://someplace.com"
end

^---- The above does nothing and does NOT catch anything. I have tried
with Htpasswd::Error, and ActiveResource::UnauthorizedAccess --
nothing.

I have also tried a before filter with a method in application.rb
calling htpasswd but i get an error saying the htpasswd method does not
exist.

Any input or even a starting place where i can begin researching would
be great .

THANK YOU!

If anyone has a suggestion for a starting point on where I can begin
trying to figure this out i'd really appreciate hearing it.

thanks

Mm Zz wrote:

In ./lib/htpasswd/auths/base.rb I found two exceptions that are raised for an
invalid account and password: Htpasswd::UnknownUserAccount and
Htpasswd::IncorrectPassword.

Try rescuing the latter. See if that does the trick.

Sorry for replying twice... caught this after I sent the first one.

All of your error classes are in ./lib/htpasswd/class_methods.rb:

  class Error < StandardError; end
  class HeaderNotFound < Error; end
  class UnknownSchemeError < Error; end
  class NotAuthorizedError < Error; end
  class ConfigurationError < Error; end

  class UnknownAccessControl < ConfigurationError; end
  class AuthSchemesNotDefined < ConfigurationError; end
  class IncorrectPassword < NotAuthorizedError; end
  class UnknownUserAccount < NotAuthorizedError; end

There's your two classes at the bottom. I would suggest rescuing
Htpasswd::NotAuthorizedError, so that you catch both incorrect passwords and
unknown accounts. That would be a more secure way to go, so you don't
inadvertently reveal which user accounts are valid.

Hi Patrick,

Thank you so much for taking the time to look into the plugin's code and
offering advice.

I gave it a shot and it appears my rescue_from is being ignored:

This is what i have in application.rb (just for testing)

  ##application.rb
  rescue_from Htpasswd::NotAuthorizedError, :with => :badlogin
  def badlogin
    redirect_to "http://www.google.com"
  end

when the pw box comes up, i put in bad login info... and it just loops
infinitely prompting me with the login/pw fields.

In my server log i have this over and over:

Processing PostsController#index (for 127.0.0.1 at 2008-10-18 15:54:41)
[GET]
  Session ID:
BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo
SGFzaHsABjoKQHVzZWR7AA==--b13da02c3dcb245cb43911897a5d940881991d88
  Parameters: {"action"=>"index", "controller"=>"posts"}
Htpasswd is enabled with {:schemes=>#<Set: {:basic}>}
Htpasswd accepts authorization header: 'Basic YXdlZmF3ZWY6'
Htpasswd error(Htpasswd::UnknownUserAccount):
Htpasswd::UnknownUserAccount
Htpasswd sending authenticate header: 'Basic realm="Authorization"'
Filter chain halted as [:htpasswd_authorize] rendered_or_redirected.
Completed in 0.00386 (259 reqs/sec) | Rendering: 0.00101 (26%) | DB:
0.00000 (0%) | 401 Unauthorized [http://localhost/posts]

Looking at the bottom of
http://wota.jp/svn/rails/plugins/branches/stable/htpasswd/lib/htpasswd/class_methods.rb
it appears the plugin is rescuing it's own error?

Do you think it is stepping in before my "rescue_from"? If so, is it
possible to work around that some how?

thx again.

I see the following starting on line 70 of
http://wota.jp/svn/rails/plugins/branches/stable/htpasswd/lib/htpasswd/class_methods.rb
:

  rescue Htpasswd::Error => error
    logger.debug "Htpasswd error(%s): %s" % [error.class, error.message]

Since i do notice this debug statement is printed in my dev log, is it
safe to say the error is rescued before my "rescue_from" is triggered?

any takers on help with this? :slight_smile:

thank you

Mm Zz wrote:

any takers on help with this? :slight_smile:

thank you

Here is the solution thanks to an Awesome gent in #rubyonrails....

Since
http://wota.jp/svn/rails/plugins/branches/stable/htpasswd/lib/htpasswd/class_methods.rb
is rescuing Htpasswd::Error => error around line 70, i overrode the
htpasswd_authorize method by doing the following:

- Created lib/hacks/htpasswd_hack.rb
- Dropped the following into that file:
module Htpasswd

  protected
  def htpasswd_authorize
    logger.debug "Htpasswd is enabled with %s" %
htpasswd_options.inspect
    username = Auths.scheme(self).authorize(htpasswd_acls)
    logger.debug "Htpasswd authorize user '%s'" % username
    @htpasswd_authorized_username = username
    return true
  rescue Htpasswd::Error => error
    logger.debug "Htpasswd error(%s): %s" % [error.class, error.message]
    strongest_auth = htpasswd_options[:schemes].map{|scheme|
Auths[scheme]}.sort.last or raise AuthSchemesNotDefined
    response.headers['WWW-Authenticate'] =
strongest_auth.new(htpasswd_options).server_header
    logger.debug "Htpasswd sending authenticate header: '%s'"%
response.headers['WWW-Authenticate']

    #render :nothing => true, :status => 401
    # DO SOMETHING FANCY WITH THE 401 HERE
    render :action => "show_home_page", :layout=> false , :status =>
401
    return false
  end

end

- In application.rb added this on line 1:
require 'lib/hacks/htpasswd_hack'

And finally i ended all that by dancing a jig.

THANKS to Patrick for responding to my help request.