1

I am developing a rails application, that allows optional HTTP basic authentication.

Authorization should be allowed, but not mandatory.

To do this, I am trying to use a before_action inside the application controller, that will try to find a user matching the given credentials and either write that user or nil into a global variable.

I tried this, but the block for authenticate_with_http_basic doesn't seem to be called at all (The console doesn't show the username and password, that I supplied, however logging outside of the block works):

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception


  before_action :authenticate

    def authenticate
        authenticate_with_http_basic do |username, password|
            logger.info "Login:"+username+"  "+password
            @auth_user = User.authenticate(username, password)
        end
    end

end

And I tried this:

def authenticate
    if user = authenticate_with_http_basic { |username, password| User.authenticate(username, password) }
        @auth_user = user
    end
end

I also tried this, which throws an error undefined method 'split' for nil:NilClass. When looking at the documentation, I see that split is being called on part of the request. Am I doing something wrong with just assuming the request variable should be accessible from a before_action inside the application controller?

def authenticate
    username, password = ActionController::HttpAuthentication::Basic::user_name_and_password(request);
    logger.info "Login:"+username+"  "+password
    @auth_user = User.authenticate(username, password)
end

I just need a simple function that gives me username and password as string variables. What am I doing wrong? Is there another way to accomplish that seemingly simple functionality?

Update

The things I tried seem to work. My only mistake was to use a regular webbrowser to debug my API. Most web browsers don't send authorization to the server, before they get a www-authenticate header back, even if the user explicitly included it in the URL.

As long as it is just used as an API or accessed through other ways, this should not be a limitation. However, this kind of optional authorization, that does not present an authorization dialog doesn't work with regular browsers (at least not as a HTTP authorization). It is not a problem with Rails, just the way browsers are built.

1 Answer 1

1

you might just be using the wrong method. this is one of the examples from ApiDock:

class AdminController < ApplicationController
  before_filter :authenticate

  def authenticate
    authenticate_or_request_with_http_basic('Administration') do |username, password|
      username == 'admin' && password == 'password'
    end
  end
end

see this question for more details: In Ruby on Rails, what does authenticate_with_http_basic do?

UPDATE

i don't see any problems without requesting basic auth. it works as expected:

class HomeController < ApplicationController
  before_action :authenticate

  private

  def authenticate
    authenticate_with_http_basic do |username, password|
      logger.info "try basic-auth without requesting it: username=#{username} password=#{password}"
    end
  end
end

calling an action with credentials:

curl -I "http://uschi:[email protected]:5000/"

gives the following logs:

[hamburg.onruby.dev] [127.0.0.1] [044cb7ea-56a9-4f] Started HEAD "/" for 127.0.0.1 at 2013-10-21 17:40:54 +0200
[hamburg.onruby.dev] [127.0.0.1] [044cb7ea-56a9-4f] Processing by HomeController#index as */*
[hamburg.onruby.dev] [127.0.0.1] [044cb7ea-56a9-4f] try basic-auth without requesting it: username=uschi password=muschi
Sign up to request clarification or add additional context in comments.

2 Comments

I do not want to request authentication though. In most cases, even without information I need a 200 status code returned. How can I prevent this function from actually doing the authentication request?
Technically, it seems like what I have been doing has been working all along. The only thing, that took me half a day to figure out is that browsers do not supply any HTTP authentication, unless they are explicitly asked to by the server (even if it is supplied as part of the url). Solution: what I am trying to do doesn't work in web browsers. Curl did the trick for me and since I am building an app-backend, I'm sure, this should not be an issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.