Skip to content

Commit

Permalink
Fixes zammad#4889 - Third-party authorization handling is not using t…
Browse files Browse the repository at this point in the history
…he unique identifier correctly (uid).
  • Loading branch information
dominikklein committed Oct 19, 2023
1 parent abf5295 commit 07e8af4
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 17 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
# database (copy from config/database/database.yml, or use `rails bs:init`)
/config/database.yml

# storage (copy from config/zammad/storage.yml.dist)
/config/zammad/storage.yml

# local backup config file
/contrib/backup/config

Expand Down
30 changes: 13 additions & 17 deletions app/models/authorization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,45 +62,41 @@ def self.find_from_hash(hash)

def self.create_from_hash(hash, user = nil)

if !user && Setting.get('auth_third_party_auto_link_at_inital_login') && hash['info'] && hash['info']['email'].present?
user = User.find_by(email: hash['info']['email'].downcase)
end

if !user
user = User.create_from_hash!(hash)
end
auth_provider = "#{PROVIDER_CLASS_PREFIX}#{hash['provider'].camelize}".constantize.new(hash, user)

# save/update avatar
if hash['info'].present? && hash['info']['image'].present?
avatar = Avatar.add(
object: 'User',
o_id: user.id,
o_id: auth_provider.user.id,
url: hash['info']['image'],
source: hash['provider'],
source: auth_provider.name,
deletable: true,
updated_by_id: user.id,
created_by_id: user.id,
updated_by_id: auth_provider.user.id,
created_by_id: auth_provider.user.id,
)

# update user link
if avatar && user.image != avatar.store_hash
user.image = avatar.store_hash
user.save
if avatar && auth_provider.user.image != avatar.store_hash
auth_provider.user.image = avatar.store_hash
auth_provider.user.save
end
end

Authorization.create!(
user: user,
uid: hash['uid'],
user: auth_provider.user,
uid: auth_provider.uid,
username: hash['info']['nickname'] || hash['info']['username'] || hash['info']['name'] || hash['info']['email'] || hash['username'],
provider: hash['provider'],
provider: auth_provider.name,
token: hash['credentials']['token'],
secret: hash['credentials']['secret']
)
end

private

PROVIDER_CLASS_PREFIX = 'Authorization::Provider::'.freeze

def delete_user_cache
return if !user

Expand Down
37 changes: 37 additions & 0 deletions app/models/authorization/provider.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/

class Authorization::Provider
include Mixin::RequiredSubPaths

attr_reader :auth_hash, :user, :info, :uid

def initialize(auth_hash, user = nil)
@auth_hash = auth_hash
@uid = auth_hash['uid']
@info = auth_hash['info'] || {}

@user = user.presence || fetch_user
end

def name
self.class.name.demodulize.downcase
end

private

def fetch_user
if Setting.get('auth_third_party_auto_link_at_inital_login')
user = find_user

return user if user.present?
end

User.create_from_hash!(auth_hash)
end

def find_user
return if info['email'].nil?

User.find_by(email: info['email'].downcase)
end
end
4 changes: 4 additions & 0 deletions app/models/authorization/provider/facebook.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/

class Authorization::Provider::Facebook < Authorization::Provider
end
4 changes: 4 additions & 0 deletions app/models/authorization/provider/github.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/

class Authorization::Provider::GitHub < Authorization::Provider
end
4 changes: 4 additions & 0 deletions app/models/authorization/provider/gitlab.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/

class Authorization::Provider::GitLab < Authorization::Provider
end
4 changes: 4 additions & 0 deletions app/models/authorization/provider/google_oauth2.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/

class Authorization::Provider::GoogleOauth2 < Authorization::Provider
end
4 changes: 4 additions & 0 deletions app/models/authorization/provider/linkedin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/

class Authorization::Provider::Linkedin < Authorization::Provider
end
4 changes: 4 additions & 0 deletions app/models/authorization/provider/microsoft_office365.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/

class Authorization::Provider::MicrosoftOffice365 < Authorization::Provider
end
15 changes: 15 additions & 0 deletions app/models/authorization/provider/saml.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/

class Authorization::Provider::Saml < Authorization::Provider
private

def find_user
user = User.find_by(login: uid)

if !user && !Setting.get('user_email_multiple_use') && info['email'].present?
user = User.find_by(email: info['email'].downcase)
end

user
end
end
4 changes: 4 additions & 0 deletions app/models/authorization/provider/twitter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/

class Authorization::Provider::Twitter < Authorization::Provider
end
4 changes: 4 additions & 0 deletions app/models/authorization/provider/weibo.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/

class Authorization::Provider::Weibo < Authorization::Provider
end
66 changes: 66 additions & 0 deletions spec/models/authorization_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,72 @@
end
end

describe 'Account linking' do
let(:auth_hash) do
{
'info' => auth_info,
'uid' => auth_uid,
'provider' => provider,
'credentials' => auth_credentials,
}
end
let(:auth_info) { {} }
let(:auth_uid) { SecureRandom.uuid }
let(:auth_credentials) do
{
'token' => '1234',
'secret' => '1234',
}
end
let(:provider) { 'saml' }
let(:user) { create(:user, login: auth_uid) }

before do
Setting.set('auth_third_party_auto_link_at_inital_login', true)

user
end

shared_examples 'links account with email address' do |type:|
let(:provider) { type }

it 'linked account' do
authorization = described_class.create_from_hash(auth_hash)

expect(authorization.user_id).to eq(user.id)
end
end

context 'when saml is the provider' do
context 'when auth provider provides no email address' do
it 'linked account with uid' do
authorization = described_class.create_from_hash(auth_hash)

expect(authorization.user_id).to eq(user.id)
end
end
end

context 'when auth provider provides an email address' do
let(:email) { '[email protected]' }
let(:auth_info) do
{
'email' => email,
}
end
let(:user) { create(:user, login: auth_uid, email: email) }

include_examples 'links account with email address', type: 'github'
include_examples 'links account with email address', type: 'gitlab'
include_examples 'links account with email address', type: 'twitter'
include_examples 'links account with email address', type: 'facebook'
include_examples 'links account with email address', type: 'linkedin'
include_examples 'links account with email address', type: 'microsoft_office365'
include_examples 'links account with email address', type: 'google_oauth2'
include_examples 'links account with email address', type: 'weibo'
end
end

describe 'Account linking notification', sends_notification_emails: true do
subject(:authorization) { create(:authorization, user: agent, provider: provider) }

Expand Down

0 comments on commit 07e8af4

Please sign in to comment.