I am using Devise to authenticate users to my Ruby on Rails application. Up to this point, I have been using the standard Cookie-based session to authenticate users, but now I have requirements to allow a token-based authentication, and I implemented this through a custom Warden strategy.
For the sake of this example, my custom strategy code is:
module Devise
module Strategies
class CustomAuthenticatable < Base
def valid?
params.has_key? :email
end
def authenticate!
success!(User.find_by(email: params[:email]))
#fail
end
end
end
end
So this works as expected for the first request: when I GET /api/my_controller/url?email=user#example.com the user is authenticated, and I get the expected response.
But wait: when I then make a second request: GET /api/my_controller/url, the user is still authenticated.
Upon further inspection, I see that a Set-Cookie is being sent, with a Devise session.
So here's my question:
How do I disable the Set-Cookie when using a custom strategy?
You can prevent the creation of a session, like described in here.
Prevent session creation on rails 3.2.2 for RESTful api
resource = warden.authenticate!(:scope => resource_name, :store => !(request.format.xml? || request.format.json?))
For some other options, please consider Rails 3 disabling session cookies.
Related
I'm in the process of setting up Doorkeeper and OAuth2 for one of my Rails Applications. My goal is to allow api access to a user depending on their access_token, so that only a user can see their 'user_show' json. So far I have my development and production applications set up and authorized on the 'oauth2/applications' route.
My '/config/initializers/doorkeeper.rb'
Doorkeeper.configure do
# Change the ORM that doorkeeper will use.
# Currently supported options are :active_record, :mongoid2, :mongoid3,
# :mongoid4, :mongo_mapper
orm :active_record
# This block will be called to check whether the resource owner is authenticated or not.
resource_owner_authenticator do
# Put your resource owner authentication logic here.
# Example implementation:
User.find_by_id(session[:current_user_id]) || redirect_to('/')
end
end
and my '/api/v1/user/controller.rb' looks as such:
class Api::V1::UserController < Api::ApiController
include ActionController::MimeResponds
before_action :doorkeeper_authorize!
def index
user = User.find(doorkeeper_token.resource_owner_id)
respond_with User.all
end
def show
user = User.find(doorkeeper_token.resource_owner_id)
respond_with user
end
end
I have tried to gain access to the OAuth Applications table to see what is being created but I cannot access it in the rails console.
Thanks in advance for the insight!
It seems that Doorkeeper doesn't find any token.
Make sure you're sending it, either from url with ?access_token=#{token} or ?bearer_token=#{token}, either giving this token in headers using Bearer Authorization.
You also need to have in mind that a token could be associated only to an app, without a resource owner. So resource_owner_id value could be nil even with a valid token. It depends on what grant flow you're using (client credential flow is not associated with a resource owner). See https://github.com/doorkeeper-gem/doorkeeper/wiki#flows
For the OAuth tables, try with Doorkeeper::AccessToken.all in a rails console.
Hope this helped
with omniauth in my app, to have a user use Google oAuth2 to authenticate I redirect the user to:
/users/auth/google_oauth2
If the users approves the request, then the AuthenticationsController#create is called.
With AuthenticationsController#create - I can add event tracking to record the # of users who approve google auth. What I don't have is the number that I sent to approve meaning I don't have a conversion rate.
How can I track the # of people who hit the URL around making requests to connect.
A nasty solution would be to build a filter around the method Strategy#request_call and do the tracking there.
Inside an initializer:
OmniAuth::Strategy.class_eval do
def request_call_with_tracking
log :info, "Im running before the actual request_call"
Tracker.hit(name) #name will return the provider
request_call_without_tracking
end
alias_method_chain :request_call, :tracking
end
You can achieve this by using the OmniAuth setup phase. You can pass a :setup option to an OmniAuth provider, with a proc which will be executed before the authentication is performed. You can add event tracking inside this proc.
So if you have some tracker class, you can do this:
use OmniAuth::Builder do
provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'],
:setup => lambda { |env|
Tracker.track
}
end
For more information check out Avdi Grimm's great blog post about the subject.
I want to use devise' token_authenticatable helper to authenticate users against the system.
I found some older documentations where a method named valid_authentication_token?(...) is used but couldn't find the same in newer devise version.
So what's the right way to authenticate a user?
Should I request the Model for user with named token and checking if email-adresses match?
Thanks a lot for your help.
PascalTurbo
If you add
t.token_authenticatable
to you user ActionRecord, and add
devise :token_authenticatable
to your User model
and specify which param is your token key in config/initializer/devise, something like this:
config.token_authentication_key = :auth_token
then controllers that use
before_filter :authenticate_user! # Tell devise to use :user map
to authenticate. after the authenticate_user!, individual methods can test using
user_signed_in?
will authorize users either by the login session or the devise authorization token that is passed on the query string or passed using HTTP basic authentication. See Devise helper code for details.
I have a rails app hosted on Heroku that am restricting access to by using a proxy service. The external server acts as intermediary for all requests and handles user authentication. Once a user has authenticated, the server (I think LDAP) adds the user name to the request header and redirects them to my app.
I would like to use the username from the request header to authenticate users in my app. Basically if the user doesn't exist I would create a user with that username (no password required) and if not I would just log them in. I will be storing the users in my app's database.
How should I do this? Is it possible to use Devise for this purpose?
Edit: I got it working with Devise/custom Warden strategy like this:
# config/initializers/my_strategy.rb
Warden::Strategies.add(:my_strategy) do
def valid?
true
end
def authenticate!
if !request.headers["my_key"]
fail!("You are not authorized to view this site.")
redirect!("proxy_url")
else
username = request.headers["my_key"]
user = User.find_by_username(username)
if user.nil?
user = User.create(:username => username)
end
success!(user)
end
end
end
#config/initializers/devise.rb
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift :my_strategy
end
I need to make this as bullet proof as possible. Are there other security measures can I take to make sure someone can't spoof the request header and access my site?
I think using devise can be a little more overkill, but you can. You just need define a warden strategie. in devise or use only warden in this purpose.
I am trying to create a session explicitly like this UserSession.create(#user, true) but the session is not getting created, current_user is nil.
But when I do this, I get < #UserSession: {:unauthorized_record=>""}>us = UserSession.create(#user, true)
RAILS_DEFAULT_LOGGER.info(us.inspect) #=> UserSession: {:unauthorized_record=>""}
I had a look at Authlogic::Session::UnauthorizedRecord here it says
Be careful with this, because Authlogic is assuming that you have already confirmed that the user is who he says he is. For example, this is the method used to persist the session internally. Authlogic finds the user with the persistence token. At this point we know the user is who he says he is, so Authlogic just creates a session with the record. This is particularly useful for 3rd party authentication methods, such as OpenID. Let that method verify the identity, once it’s verified, pass the object and create a session.
which is exactly what I am trying to do (i am authenticating using omniauth and creating session using authlogic).
How do I fix this, so that I can get a valid session in current_user ?
I had a similar issue caused by the persistence_token being nil on the user. Reset it before creating the UserSession. So...
#user.reset_persistence_token!
UserSession.create(#user, true)
I'm not sure about the .create(object, bool) method signature, but the following works using authlogic.
class Api::ApiBaseController < ApplicationController
protected
def verify_token
return false if params[:token].blank?
#session = UserSession.new(User.find_by_single_access_token(params[:token]))
#session.save
end
end
If that doesn't work for you -- I think the #user isn't being set correctly.
If you map the active_record_store to the authlogic user_sessions table your session information will be stored in the database, and you will be able to store larger sets of data.
Inside your config folder:
config/initializers/session_store.rb
Comment out App::Application.config.session_store :cookie_store, :key => '_App_session'
Add or uncomment App::Application.config.session_store :active_record_store
Inside of config/application.rb
At the end of the class for you application add:
ActiveRecord::SessionStore::Session.table_name = 'user_sessions'
Restart your app, and any information stored in the user session will be saved in the authlogic user_sessions table.
Goto: http://apidock.com/rails/ActiveRecord/SessionStore
For more information
For now you can replace
UserSession.create #user
to
UserSession.create :email => #user.email, :password => #user.password
not a big deal.
But that caught me other way. I forgot that my user got active? == false when created. I've set it to true and session is created.
I ran into this problem today. In my case it ended up being related to CSRF tokens.
We are creating a user and session in our app in response to an OAuth callback. It appears that if the CSRF token is invalid, which would be the case when coming from a third party, authlogic won't create the user session.
Can't verify CSRF token authenticity
The fix was simple:
class Oauth::UserSessionsController < ApplicationController
skip_before_action :verify_authenticity_token, only: :callback
def new
# code removed...
end
def callback
# code removed...
UserSession.create(#user)
redirect_to root_path
end
end