Skip to content

Commit

Permalink
[feature] Allow existing users to log-in with SSO
Browse files Browse the repository at this point in the history
Previously, a user could only log in with one method. They could use
credentials or an SSO provider, but they couldn't use SSO once they were
registered with credentials. And once they were registered using one SSO
provider, they couldn't log in with any others.

This commit introduces the ability to associate multiple SSO providers
with a user, and allows the use of SSO for previously-registered users.
  • Loading branch information
hosamaly committed Aug 4, 2023
1 parent cd6116d commit 5c7123d
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 12 deletions.
8 changes: 5 additions & 3 deletions app/models/identity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ def self.find_with_omniauth(auth)
def self.create_with_omniauth(auth)
Rails.logger.debug('Creating user from')
Rails.logger.debug(auth)
user = User.create_with_omniauth(auth.info, auth.provider)
Rails.logger.debug(user.inspect)
create(uid: auth['uid'], provider: auth['provider'], user_id: user.id)
transaction do
user = User.create_with_omniauth(auth.info, auth.provider)
Rails.logger.debug(user.inspect)
create!(uid: auth['uid'], provider: auth['provider'], user_id: user.id)
end
end
end
16 changes: 7 additions & 9 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -574,15 +574,13 @@ def tag_recommendations(allow_run=true)
end

def self.create_with_omniauth(info, _provider)
user = {
email: info['email'],
password: Devise.friendly_token[0, 20],
confirmed_at: Time.now.utc.to_datetime.to_s,
confirmation_token: nil,
first_name: info.first_name,
last_name: info.last_name
}
create!(user)
find_or_create_by!(email: info.email) do |user|
user.password = Devise.friendly_token[0, 20]
user.confirmed_at = Time.now.utc.to_datetime.to_s
user.confirmation_token = nil
user.first_name = info.first_name
user.last_name = info.last_name
end
end

def active_for_authentication?
Expand Down
51 changes: 51 additions & 0 deletions test/models/identity_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
require 'test_helper'

class IdentityTest < ActiveSupport::TestCase
def user_info
@user_info ||= OmniAuth::AuthHash.new(
name: 'Mr X',
first_name: 'Mr',
last_name: 'X',
email: 'mr.x@example.com',
nickname: 'mr.x@example.com'
)
end

def omniauth_hash
@omniauth_hash ||= OmniAuth::AuthHash.new(
provider: %w[azure_activedirectory_v2 facebook github gitlab google_oauth2 twitter].sample,
uid: 'e3b8c0b1-68de-454e-8cdb-d7e2d8e9390a',
info: user_info
)
end

def create_user
User.destroy_by(email: user_info.email) # if it exists
User.create!(
password: 'Password #123456',
**user_info.slice(:email, :first_name, :last_name)
)
end

test 'it creates new users' do
identity = assert_difference -> {User.count + Identity.count}, 2 do
Identity.create_with_omniauth(omniauth_hash)
end

assert_equal omniauth_hash.uid, identity.uid

user = identity.user
assert_equal user_info.email, user.email
assert_equal user_info.first_name, user.first_name
assert_equal user_info.last_name, user.last_name
end

test 'it associates existing users with new SSO identities' do
user = create_user
identity = assert_difference -> {Identity.count} do
Identity.create_with_omniauth(omniauth_hash)
end

assert_equal user.id, identity.user_id
end
end

0 comments on commit 5c7123d

Please sign in to comment.