I am building an application in Rails 2.3.14 using Ruby 1.8.7.
My client has requested a very simple authentication on a webinars page.
I thought using http_auth would be very fitting, as it just needs a very basic username and password.
Now, she has requested that if they hit cancel or use the wrong information, they get redirected to a page that basically says "if you forget login information, contact us."
How do I make it so that when we get the "HTTP Basic: Access denied." error, I can instead redirect to a page? Or, instead, just customize this page with our custom styles/content?
Thanks in advance.
Here is the code from my webinars controller:
class WebinarsController < ApplicationController
before_filter :authenticate, :only => [:bpr]
def bpr
render :action => :bpr
end
protected
def authenticate
authenticate_or_request_with_http_basic do |username, password|
username == "abc" && password == "123"
end
end
end
If you look at the authenticate_or_request_with_http_basic source, you'll see this:
def authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)
authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm)
end
def authenticate_with_http_basic(&login_procedure)
HttpAuthentication::Basic.authenticate(request, &login_procedure)
end
#...
def authenticate(request, &login_procedure)
unless request.authorization.blank?
login_procedure.call(*user_name_and_password(request))
end
end
So your login_procedure block can do pretty much anything it wants as long as it returns true for a successful login. In particular, it can call redirect_to:
def authenticate
authenticate_or_request_with_http_basic do |username, password|
if(username == "abc" && password == "123")
true
else
redirect_to '/somewhere/else/with/instructions'
end
end
end
Related
I use Rails 5 API mode
routes.rb:
Rails.application.routes.draw do
constraints Basic do
mount Rswag::Ui::Engine => '/api-docs'
mount Rswag::Api::Engine => '/api-docs'
mount Sidekiq::Web => '/sidekiq'
# etc
end
end
constraints/basic.rb:
class Basic
def self.matches?(request)
authenticate_or_request_with_http_basic do |email, password|
email == 'foo' && password = 'bar'
end
end
end
But I'm getting an error:
NoMethodError (undefined method `authenticate_or_request_with_http_basic' for Basic:Class)
Can I use http basic auth in constraints?
I dont think you can use authenticate_or_request_with_http_basic method out of controllers scope. You can set up before_filter with auth check in general controller. Here is an example taken from docs comments:
class AdminController < ApplicationController
before_filter :authenticate
def authenticate
authenticate_or_request_with_http_basic('Administration') do |email, password|
email == 'foo' && password == 'bar'
end
end
end
Also here is what I found Rails Authentication Routing Constraints Considered Harmful.
That being said I think there is a way:
class Basic
def self.matches?(request)
if ActionController::HttpAuthentication::Basic.has_basic_credentials?(request)
credentials = ActionController::HttpAuthentication::Basic.decode_credentials(request)
email, password = credentials.split(':')
email == 'foo' && password == 'bar'
end
end
end
Here is docs on HTTP Basic authentication with examples
I've got a very basic website i'm building for a friend, he requires a 'password' on a page and if the user isn't successful he wants it to redirect to a contact me page.
I've currently got this...
before_filter :authenticate
def authenticate
authenticate_or_request_with_http_basic do |username, password|
if(username == "" && password == "***")
true
else
redirect_to '/pages/contact'
end
end
end
however it redirects to the contact page upon clicking on the link... how can I get it to prompt for the password?
Could you try this:
before_filter :authenticate
def authenticate
authenticate_or_request_with_http_basic do |username, password|
redirect_to '/pages/contact' unless (username == "" && password == "***")
end
end
Note:
Another suggestion, from your above code, I would like to suggest you to take a look this discussion: redirect_to is not return in Rails in order to avoid unexpected error.
I'm trying to check if my sessions works well with basic authentication. Here is my controller :
class ClientsController < ApplicationController
skip_before_filter :verify_authenticity_token
before_action :authenticate
def create
#client = Client.create!({
:user_id => #current_user.id
})
session[:client_id] = #client.id
render(:xml => { :status => 'OK' })
end
private
def authenticate
authenticate_or_request_with_http_basic do |username, password|
# User checking...
#current_user = checked_user
end
end
end
end
It's a very basic controller. But when I try to see if session[:client_id] is correctly set, it's just returning nil.
I didn't write the initialization of #user.
it "should create session" do
request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(#user.login, #password)
post :create
response.should be_success # not fail
Hash.from_xml(response.body)['hash']['status'].should == 'OK' # not fail
Client.last.user.should == #user # not fail
assigns(session[:client_id]).should == Client.last.id # Fail !
end
The error is that assigns(session[:client_id]) is nil... I'm totally sure the #client is initialized and the render is OK, but session seems not to be saved.
It's the first time I use rspec with session. Is it the correct writing of this test ?
Regards
So the issue is the line:
assigns(session[:client_id]).should == Client.last.id # Fail !
assigns is a method that is going to point to the equivalent instance method, so assigns(session[:client_id]) is going to check for #session[:client_id], which it won't find.
Also, the session hash is available in rspec so you can call it like you would in your controller, which is what you need to do here:
session[:client_id].should == Client.last.id # pass
I have the following configuration:
devise :database_authenticatable
config.http_authenticatable = true
on request:
http://user:password#localhost:3000/
Devise ignores the http auth login and redirects to login page
any thoughts?
Regards
What http_authenticatable give you is the ability to use your HTTP Basic Authentication credentials to log into its own authentication system. You still need to code the http_auth block by yourself, like this:
def authenticate
authenticate_or_request_with_http_basic do |username, password|
username == "foo" && password == "bar"
end
warden.custom_failure! if performed?
end
This code should go into your application controller. Make sure you are using warden.custom_failure!, otherwise the devise will enter an infinite loop of redirects.
This worked for me
before_filter :check_auth
def check_auth
authenticate_or_request_with_http_basic do |username,password|
resource = User.find(username)
if resource.valid_password?(password)
sign_in :user, resource
end
end
warden.custom_failure! if performed?
end
I want to create password protected model. For example Post on the blog. I want to store this password in the database. And if user wants to see password protected post he needs to write this password. If there is no password in database everyone can see this post, each post can have its own pass. How can I create something like this in RoR? I
I only have found basic HTTP auth:
before_filter :authenticate
#protected
def authenticate
authenticate_or_request_with_http_basic do |username, password|
username == "foo" && password == "bar"
end
end
but probably there is better solution for this? Do you have any ideas?
Something like this ?
def show
#post = Post.find(...)
if params[:post][:password].nil?
# Show a form with a password asked
elsif params[:post][:password] == #post.password
# Show post
else
flash[:error] = "Bad password"
# Render password form
end
end