Devise custom authentication without a password - ruby-on-rails

In my app I need to have a database authentication but without a password. Just by entering your phone number. When the user sings up he enter phone number, adress and name and no password.
Is it real? Just can't figure out how to make it.
Thanks for help in advance!

Figured out like this:
In devise_no_pass.rb initializer add:
require 'devise/strategies/authenticatable'
module Devise
module Strategies
class DeviseNoPass < Authenticatable
def authenticate!
return super unless params[:customer_sign_in]
customer = Customer.find_by_phone(params[:customer_sign_in]
customer ? success!(customer) : raise
end
end
end
end
Warden::Strategies.add(:devise_no_pass, Devise::Strategies::DeviseNoPass)
In devise.rb:
config.warden do |manager|
manager.default_strategies(:scope => :customer).unshift :devise_no_pass
end

Related

Ruby on rails - Devise registrations blank password

I'd like to build a web app based on ruby on rails. For authentication I am using the devise gem. Everything is good : I can create accounts, login, logout etc.
But here I have an issue. I'd like to be able to sign up without providing password but still have the ability to register with password for another account.
I've set the password lenght from 0 to 128 on config/initializers/devise.rb
config.password_length = 0..128
But what are the next steps to do what I want?
Thank you
Ok, I reply here as answer.
Thanks to Ammar Shah i figured out how to get users with password and users without password.
First of all create a file in lib/devise/strategies (create the folders) named database_authenticatable.rb with following code :
require 'devise/strategies/authenticatable'
module Devise
module Strategies
# Default strategy for signing in a user, based on their email and password in the database.
class DatabaseAuthenticatable < Authenticatable
def authenticate!
if password.blank?
authentication_hash[:encrypted_password] = ''
end
resource = mapping.to.find_for_database_authentication(authentication_hash)
hashed = false
if validate(resource){ hashed = true; resource.valid_password?(password) }
remember_me(resource)
resource.after_database_authentication
success!(resource)
end
mapping.to.new.password = password if !hashed && Devise.paranoid
fail(:not_found_in_database) unless resource
end
end
end
end
Warden::Strategies.add(:database_authenticatable, Devise::Strategies::DatabaseAuthenticatable)
Then in the devise_create_user.rb migration add :
t.string :remember_token
Finally in user.rb model :
before_create :remember_value
def valid_password?(password)
if password.blank?
true
else
super
end
end
def password_required?
new_record? ? false : super
end
def remember_value
self.remember_token ||= Devise.friendly_token
end
Thank you Ammar Shah for helping me !
Reset password length in config/initializers/devise.rb to the default value and use this answer to make password optional.
Also, here is a complete implementation of gradual engagement feature in devise wiki. It depends what exactly you want you achieve.

Rails 4.2.6 - Devise 4.2.2 - Default Auth

I am looking to set a secondary password by which I can authenticate a user for a login as from admin. The reason for this work around is the front end is a single page application.
Each user has been given a unique login_as string. now I need to configure Devise to compare the login_as if the password fails.
Any help is appreciated. I am of course open to an alternative solution if there is a better way.
Thanks.
This post from Duncan Robertson was very helpful in solving my issue. I essentially created an override strategy and called it in the devise.rb file. I had some concern regarding tampering with a large user base but it has proved successful. By adding a column to users named ":signin_as" and then setting it to a default unique string with a rake I then had what I needed to fallback on if the initial sign in failed.
the override strategy (config/initializers/auth_override.rb)
module Devise
module Strategies
class AuthOverride < Authenticatable
def custom_auth(user, signin_as)
if user[:signin_as] == signin_as
return true
else
return false
end
end
def authenticate!
user = User.find_by_email(email)
if user
if user.valid_password?(params[:password])
success!(user)
elsif custom_auth(user, params[:password])
success!(user)
else
fail
end
else
fail
end
end
end
end
end
including the strategy in devise (config/initializers/devise.rb)
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift :auth_override
end

Rails & Devise: Require user to confirm email for specific functionality, but allow them to login before confirming

After a user signs up, I want to lead them to their dashboard. For full features they need to confirm their email.
Right now, when I add :confirmable to the User model, the user is unable to login.
How can I achieve this functionality?
just write in devise.rb
config.allow_unconfirmed_access_for = nil
write an validation in application.rb
def is_confirmed?
if user_signed_in?
if current_user.confirmed?
return true
else
flash[:notice] = "You are not allow to view this page."
redirect_to dashboard_path # your dashboard path
end
end
end
use in your contoller
before_action :is_confirmed?, except: [:dashbord]
I think you can achieve this with devise and allowing-unconfirmed-access
Just add extreamely long period to allow them to login and then just check if the user has confirmed email — show them all dashboard content and vice versa.
Or you can just skip :confirmable validation at all.
Hope this helps.
Check out this wiki page https://github.com/plataformatec/devise/wiki/How-To:-Add-:confirmable-to-Users
# Solution 1
Your can config in devise.rb something like:
config.allow_unconfirmed_access_for = nil
So it means user can access without any confirmation, but for instance:
config.allow_unconfirmed_access_for = 1.hour
So they can access in 1 hour without confirmation
# Solution 2
# in User.rb
protected
def confirmation_required?
false
end
So now use can access anything without confirmation but I think the solution #1 is more efficient!

Authenticate custom strategy without creating Devise user

My setup: Rails 3.0.9, Ruby 1.9.2, Devise 1.3.4, Warden 1.0.4
I'm trying to figure out if it possible to authenticate a custom strategy and not have to create a devise user in the process upon successful authentication. In my config.warden block, the authentication works fine but if I don't create a Devise user, I won't be authenticated. My ideal scenario requires me to either successfully authenticate against a 3rd party provider and sign into my app (using Devise without a corresponding Devise user record) or if I fail to authenticate, then try Devise standard login path.
Here is the devise.rb code snippet I got working but I have to create a devise user for the authentication to work, this is something I wish to avoid
config.warden do |manager|
manager.strategies.add(:custom_strategy) do
def valid?
params[:user] && params[:user][:email] && params[:user][:password]
end
def authenticate!
...perform authentication against 3rd party provider...
if successful_authentication
u = User.find_or_initialize_by_email(params[:user][:email])
if u.new_record?
u.app = 'blah'
u.save
end
success!(u)
end
end
end
manager.default_strategies(:scope => :user).unshift :custom_strategy
end
I realized the question is old but I saw it a couple of time when I was searching for a solution to similar thing so I decided to post the answer in case anyone in the future stumbles upon similar issue. Hope this will help!
I recently had to do similar thing -> had users in my database that were authenticated with some devise/warden strategies but had created another app that has to have access to some of the endpoints to my application. Basically I wanted to do a HMAC authentication.
But I didn't want to involve any user objects in that process and here is what I had to do (provided that you already have you custom strategy that authenticates incoming request without using user object)
create a fake user model that is used so that devise wont blow op. You dont have to create any database table for that
mine looked similar to below:
class Worker # no need to create a table for him
extend ActiveModel::Callbacks
extend Devise::Models
include ActiveModel::Validations
include Concerns::ObjectlessAuthenticatable
define_model_callbacks :validation
attr_accessor :id
def persisted
false
end
def initialize(id)
#id = id
end
def self.serialize_from_session(id)
self.new(id: id)
end
def self.serialize_into_session(record)
[record.id]
end
def self.http_authenticatable
false
end
end
then in devise initializer (/initializers/devise.rb) I've added separate authentication strategy like below:
...
config.warden do |manager|
manager.scope_defaults :user, :strategies => [
...strategies i was using for users
]
manager.scope_defaults :worker, :strategies => [:worker_authentication], store: false, action: 'unautenticated_worker'
manager.failure_app = CustomFailingApp
end
...
then in routes.rb I had to create a mapping for devise to use like so
devise_for :worker # you can pass some custom options here
then wherever I needed to authenticate the worker, not the user I just had to call (in the controller) authenticate_worker!
I would expect that this is against the design of devise where all actions are done using restful routes for a resource. That said, the comments in Warden's success! method say:
# Parameters:
# user - The user object to login. This object can be anything you have setup to serialize in and out of the session
So could you not change the object u to some other object that represents the user, like a plain old Hash?

Filtering users who are able to sign in with Devise

I have a Rails app using Devise for authentication. Users belong to Dealers and I want to prevent users who belong to disabled dealers from being able to sign in.
Is there a straightforward way to extend Devise's authentication finder so that it will not include users from deleted dealers? Perhaps using a named scope on User?
Cheers
Tristan
Turns out all I needed to do was override my user model's find_for_authentication method:
class User < ActiveRecord::Base
...
# Intercept Devise to check if DealershipUser's Dealership is active
def self.find_for_authentication(conditions)
user = super
return nil if user.is_a?(DealershipUser) && user.dealership.deleted?
user
end
...
end
Find the user in the normal way by calling super.
I'm using STI so I check that the user is a DealershipUser and then check if the dealership is deleted (acts_as_paranoid).
Return the user.
This is a very specific solution for my scenario but you could override find_for_authentication however you like provided you return the user afterwards.
Searching Stackoverflow.com gave me this question/answer: Custom authentication strategy for devise
Basically, you have to implement a custom authentication strategy at Warden's level (that underlies Devise). For my project, I did the following:
In config/initializers/devise.rb:
Devise.setup do |config|
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift :user_has_login_access
end
end
Warden::Strategies.add(:user_has_login_access) do
def valid?
# pass the commit parameter as 'login' or something like that, so that this strategy only activates when the user is trying to login
params[:commit] == 'login'
end
def authenticate!
u = User.find_by_email(params[:user][:email])
if u.can_login? # retrieves boolean value stored in the User model, set wherever
success! u
else
fail! "Account does not have login privilages."
end
end
end
You can read more about custom Warden strategies here: https://github.com/hassox/warden/wiki/Strategies
Hope that helps!

Resources