From e0f970326fd7ffc0ed7275ecf304fe86299cc790 Mon Sep 17 00:00:00 2001 From: Wilhansen Li Date: Tue, 19 Aug 2014 15:49:14 +0800 Subject: [PATCH] Implement SSO overriding avatars. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implemented by having Discourse download the image from the provided URL and treating it as a custom upload. Adds two more parameters to the SSO site’s response: * `avatar_url` specifies the URL of the overriding avatar. * `avatar_force_update` Discourse does not re-download avatars that has already been download from the same URL. Setting this to true forces Discourse to re-download the avatar in `avatar_url` Note that both parameters are ignored if `sso_overrides_avatar` is set to false. --- .../discourse/controllers/preferences.js.es6 | 1 + .../templates/user/preferences.js.handlebars | 4 ++-- app/models/discourse_single_sign_on.rb | 23 +++++++++++++++++++ app/models/single_sign_on_record.rb | 19 +++++++-------- config/locales/server.en.yml | 1 + config/site_settings.yml | 3 +++ ...nal_avatar_url_to_single_sign_on_record.rb | 5 ++++ lib/single_sign_on.rb | 2 +- 8 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 db/migrate/20140817011612_add_external_avatar_url_to_single_sign_on_record.rb diff --git a/app/assets/javascripts/discourse/controllers/preferences.js.es6 b/app/assets/javascripts/discourse/controllers/preferences.js.es6 index 0394fe857..9ed837fd3 100644 --- a/app/assets/javascripts/discourse/controllers/preferences.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences.js.es6 @@ -12,6 +12,7 @@ export default ObjectController.extend({ allowAvatarUpload: Discourse.computed.setting('allow_uploaded_avatars'), allowUserLocale: Discourse.computed.setting('allow_user_locale'), + ssoOverridesAvatar: Discourse.computed.setting('sso_overrides_avatar'), selectedCategories: function(){ return [].concat(this.get("watchedCategories"), this.get("trackedCategories"), this.get("mutedCategories")); diff --git a/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars b/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars index f5406e2da..ceadd2260 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars +++ b/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars @@ -82,9 +82,9 @@ {{bound-avatar model "large"}} {{#if allowAvatarUpload}} - {{else}} + {{else}} {{#unless ssoOverridesAvatar}} - {{/if}} + {{/unless}} {{/if}} diff --git a/app/models/discourse_single_sign_on.rb b/app/models/discourse_single_sign_on.rb index 52eff1357..a7826f83d 100644 --- a/app/models/discourse_single_sign_on.rb +++ b/app/models/discourse_single_sign_on.rb @@ -121,9 +121,32 @@ class DiscourseSingleSignOn < SingleSignOn user.name = User.suggest_name(name || username || email) end + if SiteSetting.sso_overrides_avatar && ( + avatar_force_update == "true" || + avatar_force_update.to_i != 0 || + sso_record.external_avatar_url != avatar_url) + begin + tempfile = FileHelper.download(avatar_url, 1.megabyte, "sso-avatar") + + upload = Upload.create_for(user.id, tempfile, "external-avatar", File.size(tempfile.path), { origin: avatar_url }) + + user.uploaded_avatar_id = upload.id + + if !user.user_avatar.contains_upload?(upload.id) + user.user_avatar.custom_upload_id = upload.id + end + rescue SocketError + # skip saving, we are not connected to the net + Rails.logger.warn "Failed to download external avatar: #{avatar_url}, socket error - user id #{ user.id }" + ensure + tempfile.close! if tempfile && tempfile.respond_to?(:close!) + end + end + # change external attributes for sso record sso_record.external_username = username sso_record.external_email = email sso_record.external_name = name + sso_record.external_avatar_url = avatar_url end end diff --git a/app/models/single_sign_on_record.rb b/app/models/single_sign_on_record.rb index e58d17409..7f444a2c5 100644 --- a/app/models/single_sign_on_record.rb +++ b/app/models/single_sign_on_record.rb @@ -6,15 +6,16 @@ end # # Table name: single_sign_on_records # -# id :integer not null, primary key -# user_id :integer not null -# external_id :string(255) not null -# last_payload :text not null -# created_at :datetime -# updated_at :datetime -# external_username :string(255) -# external_email :string(255) -# external_name :string(255) +# id :integer not null, primary key +# user_id :integer not null +# external_id :string(255) not null +# last_payload :text not null +# created_at :datetime +# updated_at :datetime +# external_username :string(255) +# external_email :string(255) +# external_name :string(255) +# external_avatar_url :string(255) # # Indexes # diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 322d2276a..44be22dcd 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -769,6 +769,7 @@ en: sso_overrides_email: "Overrides local email with external site email from SSO payload (WARNING: discrepancies can occur due to normalization of local emails)" sso_overrides_username: "Overrides local username with external site username from SSO payload (WARNING: discrepancies can occur due to differences in username length/requirements)" sso_overrides_name: "Overrides local name with external site name from SSO payload (WARNING: discrepancies can occur due to normalization of local names)" + sso_overrides_avatar: "Overrides user avatar with external site avatar from SSO payload. If enabled, disabling allow_uploaded_avatars is highly recommended" enable_local_logins: "Enable local username and password login based accounts. (Note: this must be enabled for invites to work)" allow_new_registrations: "Allow new user registrations. Uncheck this to prevent anyone from creating a new account." diff --git a/config/site_settings.yml b/config/site_settings.yml index 3acece680..dac388c7e 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -229,6 +229,9 @@ login: sso_overrides_email: false sso_overrides_username: false sso_overrides_name: false + sso_overrides_avatar: + default: false + client: true users: diff --git a/db/migrate/20140817011612_add_external_avatar_url_to_single_sign_on_record.rb b/db/migrate/20140817011612_add_external_avatar_url_to_single_sign_on_record.rb new file mode 100644 index 000000000..926615c55 --- /dev/null +++ b/db/migrate/20140817011612_add_external_avatar_url_to_single_sign_on_record.rb @@ -0,0 +1,5 @@ +class AddExternalAvatarUrlToSingleSignOnRecord < ActiveRecord::Migration + def change + add_column :single_sign_on_records, :external_avatar_url, :string + end +end \ No newline at end of file diff --git a/lib/single_sign_on.rb b/lib/single_sign_on.rb index 4e2e83312..bd01633c9 100644 --- a/lib/single_sign_on.rb +++ b/lib/single_sign_on.rb @@ -1,5 +1,5 @@ class SingleSignOn - ACCESSORS = [:nonce, :name, :username, :email, + ACCESSORS = [:nonce, :name, :username, :email, :avatar_url, :avatar_force_update, :about_me, :external_id] FIXNUMS = [] NONCE_EXPIRY_TIME = 10.minutes