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:

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.

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.