Regarding Rails Application Login - ruby-on-rails

I am trying to deploy my rails application. I have a small requirement here.
I am not using Devise. I am providing user to login via his username and password. But now I also want to provide user to login via his email too.
How can I make this work. It should work for username and also for email.
My access controller login action is like this:
def attempt_login
if params[:username].present? && params[:password].present?
p 'Fields Check'
found_user = User.where(:username => params[:username]).first
p "#{#found_user.inspect}"
if found_user
authorized_user = found_user.authenticate(params[:password])
end
end
p "#{authorized_user.inspect}"
if authorized_user
if authorized_user.email_confirmed
# mark user as logged in
session[:user_id] = authorized_user.id
session[:username] = authorized_user.username
redirect_to(:controller => 'users',:action => 'index')
else
flash[:error] = 'Please activate your account by following the
instructions in the account confirmation email you received to proceed'
redirect_to(:controller => 'home',:action => 'index')
end
else
p "Not a Registered User"
flash[:error] = "Invalid username/password combination."
redirect_to(:controller => 'home',:action => 'index')
end
end
Thanks in advance :)

You just have to change the initial check as follows
if (params[:username].present? || params[:email].present?) && params[:password].present?
and then the query to find the user
User.where('username= ? OR email= ?', params[:username], params[:email]).first

Related

rails 4 - role based authorization from scratch

I have recently started learning rails and had to develop an application with three roles: user(admin), student, instructor. I wrote the following code myself. but the problem is that it makes the role of all active users similar to the most recent login. For example, if admin was logged in and later a student logs in and then if admin refreshes her page, she will also become a student. What i should change in my code to fix this problem? And if it is not possible to implement it like this way, suggest me how i should fix this problem. thanks.
here is my users_controller code:
def login
if session[:user_id]!=nil
redirect_to(:action => 'index')
end
end
def attempt_login
if params[:username].present? && params[:password].present?
found_user = User.where(:username => params[:username]).first
if found_user
authorized_user = found_user.authenticate(params[:password])
if authorized_user
flash[:notice] = "Welcome! You are LoggedIn"
session[:user_id] = authorized_user.id
redirect_to(:action => 'index')
return
end
end
found_student = Student.where(:username => params[:username]).first
if found_student
student_id = Student.authenticate( params[:username],params[:password])
if student_id
flash[:notice] = "Welcome! You are LoggedIn"
session[:user_id] = student_id
redirect_to(:action => 'student_index')
return
end
end
found_instructor = Instructor.where(:username => params[:username]).first
if found_instructor
instructor_id = Instructor.authenticate( params[:username],params[:password])
if instructor_id
flash[:notice] = "Welcome! You are LoggedIn"
session[:user_id] = instructor_id
redirect_to(:action => 'instructor_index')
return
end
end
flash[:notice] = "Invalid username/Password combination."
redirect_to(:action => 'login')
end
end
def logout
flash[:notice]="Logged out"
session[:user_id] = nil
redirect_to(:action => "login")
end
and here is my application_controller.rb code
def require_login
unless session[:user_id] or config.my_config
flash[:notice] = "You are not Logged In"
redirect_to :root
return false
else
return true
end
end
It seems to me that you're sharing the same session key session[:user_id] to store the ID of User, Student and Instructor. How do you differentiate between the three kinds of logged in users?
It's possible that if a logged in Student visits the instructor_index path, then the student's ID would be used to load a Instructor with the same ID, and a view for an instructor would be rendered. I don't see any code to indicate otherwise.
I would have expected such a system to store both a session[:user_id], and a session[:user_type] to ensure that it's possible to exactly identify the logged in person.

How to set timeout for rails HTTP authentication?

I am using rails HTTP digest authentication on some of my website's controller. It is working fine for my purpose but it timeout very quick.
How can I adjust the timeout parameter for HTTP digest authentication?
How can I implement logout for HTTP basic authentication?
Thanks,
If a user leaves the site, or closes their browser, etc, and you would like them to stay logged in:
In your SessionsController:
def create
member = Member.find_by_user_name(params[:user_name])
if member && member.authenticate(params[:password])
session[:member_id] = member.id
if params["remember_me"] == "1"
cookies[:digest] = {:value => member.password_digest, :expires => Time.now + 720000}
else
cookies[:digest] = nil
end
redirect_to (url_to_go_to_after_login), :notice => "Logged in!"
else
redirect_to (login_url), :alert => "Invalid email or password"
end
end
How to log out a user:
def destroy
session[:member_id] = nil
cookies[:digest] = nil
redirect_to url_to_go_to_after_logout, :notice => "Logged out!"
end
How to log in a user from the rememberme cookie:
def new
if member = Member.find_by_password_digest(cookies[:digest])
session[:member_id] = member.id
redirect_to (url_to_go_to_after_login), :notice => "Hello#{member.first_name}"
end
end
To set the expire time for later (should work in rails > 2.3 https://github.com/rails/rails/blob/2-3-stable/actionpack/lib/action_controller/session/abstract_store.rb#L175 ):
Your::Application.config.session_store :active_record_store, {
key: "your_session_id",
domain: ".your-domain.com",
expire_after: 48.hours,
}

Devise and Omniauth

I'm trying to integrate Devise with Omniauth and have some troubles with them both. The main problem is to bind Devise User model with Omniauth authentications. I want a simple way to associate my user, with external providers like facebook, twitter, g+ and so on.
One of the most annoying issues that arise with my application is:
If an user registered on my site with devise (I call it local user), that means, provided an email and a password, when user tries to login with twitter, the system asks for mail confirmation. If that mail already exists, then user have to provide another mail. I want instead that he can confirm with a password that it is actually his email. How to do that? How can I override that template?
This is my authentications controller:
class AuthenticationsController < ApplicationController
def index
#authentications = Authentication.all
end
def create
#authentication = Authentication.new(params[:authentication])
if #authentication.save
redirect_to authentications_url, :notice => "Successfully created authentication."
else
render :action => 'new'
end
end
def destroy
#authentication = Authentication.find(params[:id])
#authentication.destroy
redirect_to authentications_url, :notice => "Successfully destroyed authentication."
end
def twitter
omni = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omni['provider'], omni['uid'])
if authentication
flash[:notice] = "Logged in Successfully"
sign_in_and_redirect User.find(authentication.user_id)
elsif current_user
token = omni['credentials'].token
token_secret = omni['credentials'].secret
current_user.authentications.create!(:provider => omni['provider'], :uid => omni['uid'], :token => token, :token_secret => token_secret)
flash[:notice] = "Authentication successful."
sign_in_and_redirect current_user
else
user = User.new
user.apply_omniauth(omni)
if user.save
flash[:notice] = "Logged in."
sign_in_and_redirect User.find(user.id)
else
session[:omniauth] = omni.except('extra')
p session
redirect_to new_user_registration_path
end
end
end
end
I also have no idea where new_users_registration_path is.

email access using facebook authentication rails

I am unable to access the user email through facebook authentication.
my code in authentication controller
def facebook
omni= request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omni['provider'],omni['uid'])
if authentication
flash[:notice]="Logged in successfully"
sign_in_and_redirect User.find(authentication.user_id)
elsif current_user
token=omni['credentials'].token
token_secret=omni['credentials'].secret
current_user.authentications.create!(:provider=>omni['provider'],:uid=>omni['uid'],:token=>token,:token_secret=>token_secret)
flash[:notice]="Authentication successful."
sign_in_and_redirect current_user
else
user=User.new
# user.email=omni['extra']['raw_info'].email
user.apply_omniauth(omni)
if user.save
flash[:notice]="Logged in."
sign_in_and_redirect User.find(user.id)
else
session[:omniauth]=omni.except('extra')
redirect_to new_user_registration_path
end
end
end
devise.rb
config.omniauth :facebook, 'xxxxxxxxxxxxxxx851','xxxxxxxxxxxxxxxxxxd47aae3', {:scope => ' email,publish_stream,offline_access' ,:display => 'popup'}
in user model
def apply_omniauth(omni)
authentications.build(:provider => omni['provider'],
:uid=>omni['uid'],
:token=>omni['credentials'].token,
:token_secret=>omni['credentials'].secret,
)
x=omni["info"]["name"].split # split the full name into first and last name
self.first_name=x[0]
self.last_name=x[1]
self.profile_name=omni['info']['nickname']
end
Is their something in the code?
Last, I remember, email can be found at omni.info.email.
Also, I advice you to use . notation here, instead of hash.

User Authentication: Providing separate errors for invalid email/password entry

In my Rails app I'm trying to produce a separate flash.now[:alert] for invalid :email and :password, respectively. So if a user enters the correct email but wrong password, the :alert warns the user of an invalid password and vice versa. Here's what I have in my SessionsController:
def create
if user = User.authenticate(params[:email], params[:password])
session[:user_id] = user.id
redirect_to user.profile, :notice => "Logged in successfully"
elsif user.email != params[:email]
session[:email] = #user.email
flash.now[:alert] = "Invalid email. Try again!"
render :action => 'new'
else
session[:password] = #user.password
flash.now[:alert] = "Invalid password. Try again!"
render :action => 'new'
end
end
Rendering this gives me an undefined method for email. Can anyone help me figure out what I'm doing wrong?
DISCLAIMER: Obviously this is a really bad idea as an attacker could keep on trying emails until he found one that did match and then he could start trying passwords for this email he knows exists at your database, but you're asking, so it's up to you deciding to do this or not.
Your authenticate method obviously only returns the user if the email and password did match, change your authenticate method to return a boolean and a user if there is any available. It would look somewhat like this:
def authenticate(email, password)
u = first(:conditions => {:email => email, :state => 'active'})
u && u.authenticated?(password) ? [true, u] : [false, u]
end
Then, at your controller:
def create
result , user = User.authenticate(params[:email], params[:password])
if result
session[:user_id] = user.id
redirect_to user.profile, :notice => "Logged in successfully"
elsif user
session[:email] = #user.email
flash.now[:alert] = "Invalid email. Try again!"
render :action => 'new'
else
session[:password] = #user.password
flash.now[:alert] = "Invalid password. Try again!"
render :action => 'new'
end
end
And this should work.

Resources