Store strategy name in the Rails 3 log for Warden - ruby-on-rails

we are using Warden for authentication and we have so many strategies it is difficult to track which one has been successful. Instead putting lines like
Rails.logger.debug "Authenticated with SSO" if user
to every strategy I would like to put one simple line somewhere to log the strategy message. It is available in the Warden somewhere because it stores the successful message:
success!(username, message)
How to do that? What is the best place to put this line in?
I guess I need a callback or something like that:
https://github.com/hassox/warden/wiki/Callbacks

Got it:
Warden::Manager.after_authentication do |user,auth,opts|
user = user.username if user.respond_to? :username
message = auth.winning_strategy.message
Rails.logger.info "User #{user} authenticated: #{auth.winning_strategy.message}"
end
And in the strategies:
success!(u, "with LDAP")
for example. That works.

Related

Using Devise/DatabaseAuthenticatable module to check password/salt a string

I'm building an app that uses Devise to manage user state. I'm also building an API in that same app that receives a username and password from a POST request
What I'm trying to accomplish is:
Get the user by username from the database (done, straightforward)
Use Devise::Models::DatabaseAuthenticatable to take the password the user passed in, encrypt it, compare it against the encrypted_password field on the User model and if they're the same, proceed with the rest of my code
The second bullet above is what I'm having trouble with. In a console, I can't seem to get an instance of the module Devise::Models::DatabaseAuthenticatable to try the various instance methods that you can find here in the docs.
Any help would be greatly appreciated!
If I understood your question correctly, you can use .valid_password? devise method. Something like that:
#assuming you'll receive nested params like user[email], user[password]...
user_params = params.require(:user).permit(:email, :password)
user = User.find_by(email: user_params[:email])
return head 403 if user.nil?
valid = user.valid_password?(user_params[:password]) #true or false...
return head 403 unless valid
sign_in(user) #devise helper: if you want to sign in that user
You can also check another approachs, like devise token auth gem.

Use devise for a model other than user

So, I am somewhat new to rails and devise, so I apologize in advance if this is a basic question. I couldn't find any information on this anywhere, and I searched thoroughly. This also makes me wonder if Devise is the right tool for this, but here we go:
I have an app where devise user authentication works great, I got it, implemented it correctly and it works.
In my app, users can belong to a group, and this group has a password that a user must enter to 'join' the group.
I successfully added devise :database_authenticatable to my model, and when I create it an encrypted password is created.
My problem, is that I cannot authenticate this! I have a form where the user joins the group, searching for their group, then entering the password for it.
This is what I tried:
def join
#home = Home.find_for_authentication(params[:_id]) # method i found that devise uses
if #home.valid_password?(params[:password]);
render :json => {success: true}
else
render :json => {success: false, message: "Invalid password"}
end
end
This gives me the error: can't dup NilClass
on this line: #home = Home.find_for_authentication(params[:_id])
What is the problem?
The problem will be here:
Home.find_for_authentication(params[:_id])
I've never used database_authenticatable before (will research it, thanks!), so I checked the Devise docs for you
The method they recommend:
User.find(1).valid_password?('password123') # returns true/false
--
Object?
The method you've used has a doc:
Find first record based on conditions given (ie by the sign in form).
This method is always called during an authentication process but it
may be wrapped as well. For instance, database authenticatable
provides a find_for_database_authentication that wraps a call to
this method. This allows you to customize both database
authenticatable or the whole authenticate stack by customize
find_for_authentication.
Overwrite to add customized conditions, create a join, or maybe use a
namedscope to filter records while authenticating
The actual code looks like this:
def self.find_for_authentication(tainted_conditions)
find_first_by_auth_conditions(tainted_conditions)
end
Looking at this code, it seems to me passing a single param is not going to cut it. You'll either need an object (hence User.find([id])), or you'll need to send a series of params to the method
I then found this:
class User
def self.authenticate(username, password)
user = User.find_for_authentication(:username => username)
user.valid_password?(password) ? user : nil
end
end
I would recommend doing this:
#home = Home.find_for_authentication(id: params[:_id])
...

Does devise have 'callback'?

After a user log in, I want to manually log this event and increment a counter column in database.
Is there something like after_login in Devise? Just as ActiveRecord's before_save?
Devise uses Warden behind the scenes and Warden supplies you with a number of callbacks:
https://github.com/hassox/warden/wiki/callbacks
Have a look at the after_authentication callback. That's what you are looking for.
Code:
Warden::Manager.after_authentication do |user, auth, opts|
# your code here..
end
You can simply create a new initializer file and put the code there. (Like /config/initializers/warden_callbacks.rb)

Where should warden callbacks be placed in a rails app?

I'm relatively new to rails. I have Devise set up, and want to run some callback code after users sign in.
Looking at the Warden wiki page, I can use the "after_set_user" callback to perform this logic, for example:
Warden::Manager.after_set_user do |user, auth, opts|
unless user.active?
auth.logout
throw(:warden, :message => "User not active")
end
end
However, I'm not sure where I should be storing this stuff. My first thought is that I could put it in config/initializers/devise.rb. Is that correct? It doesn't feel right putting what is essentially controller code in the config directory.
Warden hooks need to be required when your application is booting, so inside Devise's initializer at config/initializers/devise.rb is a good candidate.
However, the behavior you want to achieve will be better accomplished by using this Devise feature:
https://github.com/plataformatec/devise/wiki/How-To:-Customize-user-account-status-validation-when-logging-in

Advice on HTTP authentication scheme (using request headers)

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.

Resources