How to Catch a Status 401 with htpasswd?


#1

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!


#2

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.


#3

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.


#4

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.


#5

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.


#6

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?


#7

any takers on help with this? :slight_smile:

thank you


#8

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.