123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- class Authorization < ApplicationModel
- belongs_to :user, optional: true
- after_create :delete_user_cache, :notification_send
- after_update :delete_user_cache
- after_destroy :delete_user_cache
- validates :user_id, presence: true
- validates :uid, presence: true, uniqueness: { case_sensitive: true, scope: :provider }
- validates :provider, presence: true
- def self.find_from_hash(hash)
- auth = Authorization.find_by(provider: hash['provider'], uid: hash['uid'])
- if auth
- # update auth tokens
- auth.update!(
- token: hash['credentials']['token'],
- secret: hash['credentials']['secret']
- )
- # update username of auth entry if empty
- if !auth.username && hash['info']['nickname'].present?
- auth.update!(
- username: hash['info']['nickname'],
- )
- end
- # update firstname/lastname if needed
- user = User.find(auth.user_id)
- if user.firstname.blank? && user.lastname.blank?
- if hash['info']['first_name'].present? && hash['info']['last_name'].present?
- user.firstname = hash['info']['first_name']
- user.lastname = hash['info']['last_name']
- elsif hash['info']['display_name'].present?
- user.firstname = hash['info']['display_name']
- end
- end
- # update image if needed
- if hash['info']['image'].present?
- avatar = Avatar.add(
- object: 'User',
- o_id: user.id,
- url: hash['info']['image'],
- source: hash['provider'],
- deletable: true,
- updated_by_id: user.id,
- created_by_id: user.id,
- )
- if avatar && user.image != avatar.store_hash
- user.image = avatar.store_hash
- end
- end
- if user.changed?
- user.save
- end
- end
- auth
- end
- def self.create_from_hash(hash, user = nil)
- 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: auth_provider.user.id,
- url: hash['info']['image'],
- source: auth_provider.name,
- deletable: true,
- updated_by_id: auth_provider.user.id,
- created_by_id: auth_provider.user.id,
- )
- # update user link
- 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: auth_provider.user,
- uid: auth_provider.uid,
- username: hash['info']['nickname'] || hash['info']['username'] || hash['info']['name'] || hash['info']['email'] || hash['username'],
- 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
- user.touch # rubocop:disable Rails/SkipsModelValidations
- end
- # An account is considered linked if the user originates from a source other than the current authorization provider.
- def linked_account?
- user.source != provider
- end
- def notification_send
- # Send a notification only if the feature is turned on and the account is linked.
- return if !Setting.get('auth_third_party_linking_notification') || !user || !linked_account?
- template = 'user_auth_provider'
- if user.email.blank?
- Rails.logger.info { "Unable to send a notification (#{template}) to user_id: #{user.id} be cause of missing email address." }
- return
- end
- Rails.logger.debug { "Send notification (#{template}) to: #{user.email}" }
- NotificationFactory::Mailer.notification(
- template: template,
- user: user,
- objects: {
- user: user,
- provider: provider_name(provider),
- }
- )
- end
- def provider_name(provider)
- return saml_display_name(provider) if provider == 'saml'
- provider_title(provider)
- end
- # In case of SAML authentication provider, there is a separate display name setting that may be defined.
- def saml_display_name(provider)
- begin
- Setting.get('auth_saml_credentials')['display_name']
- rescue
- provider_title(provider)
- end
- end
- def provider_title(provider)
- begin
- Setting.find_by(name: "auth_#{provider}").preferences['title_i18n'].shift
- rescue
- provider
- end
- end
- end
|