vendredi 17 avril 2015

Session hijack on OmniAuth

Im using OmniAuth on Ruby on Rails4. But some user report, When he use sign in using OmniAuth hee can be other user, like session hijack.


Im not sure my code has some problem... This code's purpose is that user can login either facebook twitter and email using one account.




  • When user does not provide email address, Email is going to be random@example.com




  • User can remove social record from registrations_controller



  • When they did not register password or email they can't remove social record(because if they can, and they logout they never access an account)


here is my code.


omniauth_callbacks_controller.rb



<pre>class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

def facebook
if user_signed_in?
user = User.find(current_user.id)
social = Social.find_by(user_id: current_user.id, provider: "facebook")
unless social
social = Social.new(
uid: request.env["omniauth.auth"].uid,
username: request.env["omniauth.auth"].extra.raw_info.name, #facebook username
provider: request.env["omniauth.auth"].provider,
token: request.env["omniauth.auth"].credentials.token
)
begin
user.socials << social
rescue
flash[:danger] = t("messages.error")
else
ensure
redirect_to user_path
end
end

else
social = Social.find_by(:provider => request.env["omniauth.auth"].provider, :uid => request.env["omniauth.auth"].uid)

if social
user = User.find(social.user_id)
if user
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
flash["facebook"] = true
sign_in_and_redirect user, :event => :authentication
else
redirect_to root_path
end
else
if request.env["omniauth.auth"].info.email.present?
email = request.env["omniauth.auth"].info.email
user = User.find_by_email(request.env["omniauth.auth"].info.email)
else
email = User.create_unique_email
end
unless user
user = User.create(
email: email,
confirmation_token: nil,
confirmed_at: Time.now
)
end
social = Social.new(
uid: request.env["omniauth.auth"].uid,
username: request.env["omniauth.auth"].extra.raw_info.name,
provider: request.env["omniauth.auth"].provider,
token: request.env["omniauth.auth"].credentials.token
)
user.socials << social
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
flash["facebook"] = true
sign_in_and_redirect user, :event => :authentication

end
end
end

def twitter
if user_signed_in?

user = User.find(current_user.id)
social = Social.find_by(user_id: current_user.id, provider: "twitter")
unless social
social = Social.new(
username: request.env["omniauth.auth"].info.nickname,
provider: request.env["omniauth.auth"].provider,
uid: request.env["omniauth.auth"].uid,
token: request.env["omniauth.auth"].credentials.token,
secret: request.env["omniauth.auth"].credentials.secret
)
begin
user.socials << social
rescue
flash[:danger] = t("messages.error")
else
ensure
redirect_to user_path
end
end

else
social = Social.find_by(:provider => request.env["omniauth.auth"].provider, :uid => request.env["omniauth.auth"].uid)
if social
user = User.find(social.user_id)
if user
set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
flash["twitter"] = true
sign_in_and_redirect user, :event => :authentication
else
redirect_to user_path
end
else
user = User.create(
email: User.create_unique_email,
confirmation_token: nil,
confirmed_at: Time.now
)
social = Social.new(
username: request.env["omniauth.auth"].info.nickname,
provider: request.env["omniauth.auth"].provider,
uid: request.env["omniauth.auth"].uid,
token: request.env["omniauth.auth"].credentials.token,
secret: request.env["omniauth.auth"].credentials.secret
)
user.socials << social
set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
flash["twitter"] = true
sign_in_and_redirect user, :event => :authentication
end
end
end

private
def sign_in_and_redirect(resource_or_scope, *args)
options = args.extract_options!
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource = args.last || resource_or_scope
sign_in(scope, resource, options)
redirect_to user_path
end


end


And schema is this



create_table "socials", force: true do |t|
t.integer "user_id"
t.string "uid", default: "", null: false
t.string "provider", default: "", null: false
t.string "username"
t.string "token"
t.datetime "created_at"
t.datetime "updated_at"
t.string "secret"
end

create_table "users", force: true do |t|
t.string "email", default: ""
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.datetime "created_at"
t.datetime "updated_at"
end

add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true


registrations_controller.rb



def remove_social
begin

if current_user.email.blank? || current_user.encrypted_password.blank?
raise t("messages.error")
end
if current_user.unconfirmed_email.present?
raise t("messages.error")
end
if /example.com/ =~ current_user.email
raise t("messages.error")
end

social = Social.where(user_id: current_user.id, provider: params[:social]).first
if social.destroy
flash[:success] = t("messages.success")
else
raise flash[:danger] = t("messages.error")
end

rescue => e
flash[:danger] = e.message
else
flash[:success] = t("messages.success")
ensure
redirect_to root_path
end


end


Aucun commentaire:

Enregistrer un commentaire