diff --git a/app/views/profiles/_email_settings.html.haml b/app/views/profiles/_email_settings.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..fb4da08e129c89e132792a1f94087c07d616987d --- /dev/null +++ b/app/views/profiles/_email_settings.html.haml @@ -0,0 +1,16 @@ +- form = local_assigns.fetch(:form) +- readonly = @user.read_only_attribute?(:email) +- email_change_disabled = local_assigns.fetch(:email_change_disabled, nil) +- read_only_help_text = readonly ? s_("Profiles|Your email address was automatically set based on your %{provider_label} account") % { provider_label: attribute_provider_label(:email) } : user_email_help_text(@user) +- help_text = email_change_disabled ? s_("Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO.") % { group_name: @user.managing_group.name } : read_only_help_text + += form.text_field :email, required: true, class: 'input-lg', value: (@user.email unless @user.temp_oauth_email?), help: help_text.html_safe, readonly: readonly || email_change_disabled += form.select :public_email, options_for_select(@user.all_emails, selected: @user.public_email), + { help: s_("Profiles|This email will be displayed on your public profile"), include_blank: s_("Profiles|Do not show on profile") }, + control_class: 'select2 input-lg', disabled: email_change_disabled +- commit_email_link_url = help_page_path('user/profile/index', anchor: 'commit-email', target: '_blank') +- commit_email_link_start = ''.html_safe % { url: commit_email_link_url } +- commit_email_docs_link = s_('Profiles|This email will be used for web based operations, such as edits and merges. %{commit_email_link_start}Learn more%{commit_email_link_end}').html_safe % { commit_email_link_start: commit_email_link_start, commit_email_link_end: ''.html_safe } += form.select :commit_email, options_for_select(commit_email_select_options(@user), selected: selected_commit_email(@user)), + { help: commit_email_docs_link }, + control_class: 'select2 input-lg', disabled: email_change_disabled diff --git a/app/views/profiles/notifications/_email_settings.html.haml b/app/views/profiles/notifications/_email_settings.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..34dcf8f5402d5c718d0857d74f46cf08f910ff00 --- /dev/null +++ b/app/views/profiles/notifications/_email_settings.html.haml @@ -0,0 +1,6 @@ +- form = local_assigns.fetch(:form) +.form-group + = form.label :notification_email, class: "label-bold" + = form.select :notification_email, @user.all_emails, { include_blank: false }, class: "select2", disabled: local_assigns.fetch(:email_change_disabled, nil) + .help-block + = local_assigns.fetch(:help_text, nil) diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml index 712eb2a4573f9149c25e3c50db99acd49462fae0..e616e5546b31fff531f02d6442a97a386318db37 100644 --- a/app/views/profiles/notifications/show.html.haml +++ b/app/views/profiles/notifications/show.html.haml @@ -22,9 +22,7 @@ Global notification settings = form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications prepend-top-default' } do |f| - .form-group - = f.label :notification_email, class: "label-bold" - = f.select :notification_email, @user.all_emails, { include_blank: false }, class: "select2" + = render_if_exists 'profiles/notifications/email_settings', form: f = label_tag :global_notification_level, "Global notification level", class: "label-bold" %br diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 4d3d92d09c05a8b40da1e913e2fa1046c475df24..1fffea08dae6f6ff2c84c44b263870e0e429797b 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -83,18 +83,7 @@ = f.text_field :name, label: 'Full name', required: true, title: s_("Profiles|Using emojis in names seems fun, but please try to set a status message instead"), wrapper: { class: 'col-md-9 qa-full-name' }, help: s_("Profiles|Enter your name, so people you know can recognize you") = f.text_field :id, readonly: true, label: 'User ID', wrapper: { class: 'col-md-3' } - - if @user.read_only_attribute?(:email) - = f.text_field :email, required: true, class: 'input-lg', readonly: true, help: s_("Profiles|Your email address was automatically set based on your %{provider_label} account") % { provider_label: attribute_provider_label(:email) } - - else - = f.text_field :email, required: true, class: 'input-lg', value: (@user.email unless @user.temp_oauth_email?), - help: user_email_help_text(@user) - = f.select :public_email, options_for_select(@user.all_emails, selected: @user.public_email), - { help: s_("Profiles|This email will be displayed on your public profile"), include_blank: s_("Profiles|Do not show on profile") }, - control_class: 'select2 input-lg' - - commit_email_docs_link = link_to s_('Profiles|Learn more'), help_page_path('user/profile/index', anchor: 'commit-email', target: '_blank') - = f.select :commit_email, options_for_select(commit_email_select_options(@user), selected: selected_commit_email(@user)), - { help: s_("Profiles|This email will be used for web based operations, such as edits and merges. %{learn_more}").html_safe % { learn_more: commit_email_docs_link } }, - control_class: 'select2 input-lg' + = render_if_exists 'profiles/email_settings', form: f = f.text_field :skype, class: 'input-md', placeholder: s_("Profiles|username") = f.text_field :linkedin, class: 'input-md', help: s_("Profiles|Your LinkedIn profile name from linkedin.com/in/profilename") = f.text_field :twitter, class: 'input-md', placeholder: s_("Profiles|@username") diff --git a/ee/app/models/saml_provider.rb b/ee/app/models/saml_provider.rb index ca332995b18f43081efbb2e831384879553b521f..83f4e28b5dcf317e03467a054d25a7c4333a3cac 100644 --- a/ee/app/models/saml_provider.rb +++ b/ee/app/models/saml_provider.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class SamlProvider < ActiveRecord::Base + USER_ATTRIBUTES_LOCKED_FOR_MANAGED_ACCOUNTS = %i(email public_email commit_email notification_email).freeze + belongs_to :group has_many :identities diff --git a/ee/app/services/ee/users/update_service.rb b/ee/app/services/ee/users/update_service.rb index 1640e8ea41fd06f8851d769eeb3309d4e929c491..d9c75e789a852122d094d64828cedccf22594870 100644 --- a/ee/app/services/ee/users/update_service.rb +++ b/ee/app/services/ee/users/update_service.rb @@ -3,6 +3,7 @@ module EE module Users module UpdateService + extend ::Gitlab::Utils::Override include EE::Audit::Changes # rubocop: disable Cop/InjectEnterpriseEditionModule private @@ -19,6 +20,12 @@ def notify_success(user_exists) def model @user end + + override :assign_attributes + def assign_attributes + params.reject! { |key, _| SamlProvider::USER_ATTRIBUTES_LOCKED_FOR_MANAGED_ACCOUNTS.include?(key.to_sym) } if model.group_managed_account? + super + end end end end diff --git a/ee/app/views/profiles/_email_settings.html.haml b/ee/app/views/profiles/_email_settings.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..2873d28c0787fe0d9d4252d60f7a7864edf18b63 --- /dev/null +++ b/ee/app/views/profiles/_email_settings.html.haml @@ -0,0 +1,3 @@ +- group_managed_account = @user.group_managed_account? + += render_ce 'profiles/email_settings', form: form, email_change_disabled: group_managed_account diff --git a/ee/app/views/profiles/notifications/_email_settings.html.haml b/ee/app/views/profiles/notifications/_email_settings.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..eb68bc3a389e0a7781c9906a3869b1f27ee15839 --- /dev/null +++ b/ee/app/views/profiles/notifications/_email_settings.html.haml @@ -0,0 +1,4 @@ +- group_managed_account = @user.group_managed_account? +- help_text = group_managed_account ? s_("Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO.").html_safe % { group_name: @user.managing_group.name } : nil += render_ce 'profiles/notifications/email_settings', email_change_disabled: group_managed_account, help_text: help_text, form: form + diff --git a/ee/changelogs/unreleased/force-notification-to-saml-email-ee.yml b/ee/changelogs/unreleased/force-notification-to-saml-email-ee.yml new file mode 100644 index 0000000000000000000000000000000000000000..55049c02a412d3654a19e627f3fc86f98532f17a --- /dev/null +++ b/ee/changelogs/unreleased/force-notification-to-saml-email-ee.yml @@ -0,0 +1,5 @@ +--- +title: Block possibility to change email for users with group managed account +merge_request: 9712 +author: +type: added diff --git a/ee/spec/services/users/update_service_spec.rb b/ee/spec/services/users/update_service_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..b5446d874d3f95ffac63be759b90fb6411f25071 --- /dev/null +++ b/ee/spec/services/users/update_service_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Users::UpdateService do + let(:user) { create(:user) } + + describe '#execute' do + it 'does not update email if an user has group managed account' do + allow(user).to receive(:group_managed_account?).and_return(true) + + expect do + update_user(user, { email: 'foreign@email' }) + end.not_to change { user.reload.email } + end + + it 'does not update commit email if an user has group managed account' do + allow(user).to receive(:group_managed_account?).and_return(true) + + expect do + update_user(user, { commit_email: 'foreign@email' }) + end.not_to change { user.reload.commit_email } + end + + it 'does not update public if an user has group managed account' do + allow(user).to receive(:group_managed_account?).and_return(true) + + expect do + update_user(user, { public_email: 'foreign@email' }) + end.not_to change { user.reload.public_email } + end + + it 'does not update public if an user has group managed account' do + allow(user).to receive(:group_managed_account?).and_return(true) + + expect do + update_user(user, { notification_email: 'foreign@email' }) + end.not_to change { user.reload.notification_email } + end + + def update_user(user, opts) + described_class.new(user, opts.merge(user: user)).execute! + end + end +end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 773186c445f4252c911242b3be73fb57721418fd..8d74b65b57da710ab6a69ee6dcd93c56f083b06d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -7788,7 +7788,7 @@ msgstr "" msgid "Profiles|This email will be displayed on your public profile" msgstr "" -msgid "Profiles|This email will be used for web based operations, such as edits and merges. %{learn_more}" +msgid "Profiles|This email will be used for web based operations, such as edits and merges. %{commit_email_link_start}Learn more%{commit_email_link_end}" msgstr "" msgid "Profiles|This emoji and message will appear on your profile and throughout the interface." @@ -11732,6 +11732,9 @@ msgstr "" msgid "Your U2F device was registered!" msgstr "" +msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO." +msgstr "" + msgid "Your applications (%{size})" msgstr ""