Reputation: 9693
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?
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.
Upvotes: 1
Views: 1592
Reputation: 18835
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
Upvotes: 1