Commit 6f8b7545 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'sync-email-from-omniauth-ee' into 'master'

Sync email address from specified omniauth provider [EE]

See merge request !2072
parents 1d3405dd 8ad86cc9
...@@ -9,7 +9,7 @@ class ProfilesController < Profiles::ApplicationController ...@@ -9,7 +9,7 @@ class ProfilesController < Profiles::ApplicationController
end end
def update def update
user_params.except!(:email) if @user.ldap_user? user_params.except!(:email) if @user.external_email?
respond_to do |format| respond_to do |format|
if @user.update_attributes(user_params) if @user.update_attributes(user_params)
...@@ -76,7 +76,7 @@ class ProfilesController < Profiles::ApplicationController ...@@ -76,7 +76,7 @@ class ProfilesController < Profiles::ApplicationController
end end
def user_params def user_params
params.require(:user).permit( @user_params ||= params.require(:user).permit(
:avatar, :avatar,
:bio, :bio,
:email, :email,
......
module ProfilesHelper
def email_provider_label
return unless current_user.external_email?
current_user.email_provider.present? ? Gitlab::OAuth::Provider.label_for(current_user.email_provider) : "LDAP"
end
end
...@@ -49,10 +49,10 @@ ...@@ -49,10 +49,10 @@
.form-group .form-group
= f.label :email, class: "label-light" = f.label :email, class: "label-light"
- if @user.ldap_user? && @user.ldap_email? - if @user.external_email?
= f.text_field :email, class: "form-control", required: true, readonly: true = f.text_field :email, class: "form-control", required: true, readonly: true
%span.help-block.light %span.help-block.light
Your email address was automatically set based on the LDAP server. Your email address was automatically set based on your #{email_provider_label} account.
- else - else
- if @user.temp_oauth_email? - if @user.temp_oauth_email?
= f.text_field :email, class: "form-control", required: true, value: nil = f.text_field :email, class: "form-control", required: true, value: nil
......
---
title: Sync email address from specified omniauth provider
merge_request: 11268
author: Robin Bobbitt
...@@ -432,6 +432,10 @@ production: &base ...@@ -432,6 +432,10 @@ production: &base
# showing GitLab's sign-in page (default: show the GitLab sign-in page) # showing GitLab's sign-in page (default: show the GitLab sign-in page)
# auto_sign_in_with_provider: saml # auto_sign_in_with_provider: saml
# Sync user's email address from the specified Omniauth provider every time the user logs
# in (default: nil). And consequently make this field read-only.
# sync_email_from_provider: cas3
# CAUTION! # CAUTION!
# This allows users to login without having a user account first. Define the allowed providers # This allows users to login without having a user account first. Define the allowed providers
# using an array, e.g. ["saml", "twitter"], or as true/false to allow all providers or none. # using an array, e.g. ["saml", "twitter"], or as true/false to allow all providers or none.
......
...@@ -190,6 +190,7 @@ Settings.omniauth['external_providers'] = [] if Settings.omniauth['external_prov ...@@ -190,6 +190,7 @@ Settings.omniauth['external_providers'] = [] if Settings.omniauth['external_prov
Settings.omniauth['block_auto_created_users'] = true if Settings.omniauth['block_auto_created_users'].nil? Settings.omniauth['block_auto_created_users'] = true if Settings.omniauth['block_auto_created_users'].nil?
Settings.omniauth['auto_link_ldap_user'] = false if Settings.omniauth['auto_link_ldap_user'].nil? Settings.omniauth['auto_link_ldap_user'] = false if Settings.omniauth['auto_link_ldap_user'].nil?
Settings.omniauth['auto_link_saml_user'] = false if Settings.omniauth['auto_link_saml_user'].nil? Settings.omniauth['auto_link_saml_user'] = false if Settings.omniauth['auto_link_saml_user'].nil?
Settings.omniauth['sync_email_from_provider'] ||= nil
Settings.omniauth['providers'] ||= [] Settings.omniauth['providers'] ||= []
Settings.omniauth['cas3'] ||= Settingslogic.new({}) Settings.omniauth['cas3'] ||= Settingslogic.new({})
......
class RenameUsersLdapEmailToExternalEmail < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
rename_column_concurrently :users, :ldap_email, :external_email
end
def down
cleanup_concurrent_column_rename :users, :external_email, :ldap_email
end
end
class AddEmailProviderToUsers < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :users, :email_provider, :string
end
end
class CleanupUsersLdapEmailRename < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
cleanup_concurrent_column_rename :users, :ldap_email, :external_email
end
def down
rename_column_concurrently :users, :external_email, :ldap_email
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170602003304) do ActiveRecord::Schema.define(version: 20170603200744) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -1640,7 +1640,6 @@ ActiveRecord::Schema.define(version: 20170602003304) do ...@@ -1640,7 +1640,6 @@ ActiveRecord::Schema.define(version: 20170602003304) do
t.text "note" t.text "note"
t.string "unlock_token" t.string "unlock_token"
t.datetime "otp_grace_period_started_at" t.datetime "otp_grace_period_started_at"
t.boolean "ldap_email", default: false, null: false
t.boolean "external", default: false t.boolean "external", default: false
t.string "incoming_email_token" t.string "incoming_email_token"
t.string "organization" t.string "organization"
...@@ -1653,6 +1652,8 @@ ActiveRecord::Schema.define(version: 20170602003304) do ...@@ -1653,6 +1652,8 @@ ActiveRecord::Schema.define(version: 20170602003304) do
t.boolean "support_bot" t.boolean "support_bot"
t.string "preferred_language" t.string "preferred_language"
t.string "rss_token" t.string "rss_token"
t.boolean "external_email", default: false, null: false
t.string "email_provider"
end end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
......
...@@ -70,7 +70,7 @@ module Gitlab ...@@ -70,7 +70,7 @@ module Gitlab
found_user = Gitlab::LDAP::Person.find_by_dn(ldap_identity.extern_uid, adapter) found_user = Gitlab::LDAP::Person.find_by_dn(ldap_identity.extern_uid, adapter)
return found_user if found_user return found_user if found_user
if user.ldap_email? if user.external_email? && [nil, provider].include?(user.email_provider)
Gitlab::LDAP::Person.find_by_email(user.email, adapter) Gitlab::LDAP::Person.find_by_email(user.email, adapter)
end end
end end
......
...@@ -41,11 +41,6 @@ module Gitlab ...@@ -41,11 +41,6 @@ module Gitlab
def update_user_attributes def update_user_attributes
if persisted? if persisted?
if auth_hash.has_email?
gl_user.skip_reconfirmation!
gl_user.email = auth_hash.email
end
# find_or_initialize_by doesn't update `gl_user.identities`, and isn't autosaved. # find_or_initialize_by doesn't update `gl_user.identities`, and isn't autosaved.
identity = gl_user.identities.find { |identity| identity.provider == auth_hash.provider } identity = gl_user.identities.find { |identity| identity.provider == auth_hash.provider }
identity ||= gl_user.identities.build(provider: auth_hash.provider) identity ||= gl_user.identities.build(provider: auth_hash.provider)
...@@ -55,10 +50,6 @@ module Gitlab ...@@ -55,10 +50,6 @@ module Gitlab
# For an existing identity with no change in DN, this line changes nothing. # For an existing identity with no change in DN, this line changes nothing.
identity.extern_uid = auth_hash.uid identity.extern_uid = auth_hash.uid
end end
gl_user.ldap_email = auth_hash.has_email?
gl_user
end end
def changed? def changed?
...@@ -69,6 +60,10 @@ module Gitlab ...@@ -69,6 +60,10 @@ module Gitlab
ldap_config.block_auto_created_users ldap_config.block_auto_created_users
end end
def sync_email_from_provider?
true
end
def allowed? def allowed?
Gitlab::LDAP::Access.allowed?(gl_user) Gitlab::LDAP::Access.allowed?(gl_user)
end end
......
...@@ -12,6 +12,7 @@ module Gitlab ...@@ -12,6 +12,7 @@ module Gitlab
def initialize(auth_hash) def initialize(auth_hash)
self.auth_hash = auth_hash self.auth_hash = auth_hash
update_email
end end
def persisted? def persisted?
...@@ -174,6 +175,22 @@ module Gitlab ...@@ -174,6 +175,22 @@ module Gitlab
} }
end end
def sync_email_from_provider?
auth_hash.provider.to_s == Gitlab.config.omniauth.sync_email_from_provider.to_s
end
def update_email
if auth_hash.has_email? && sync_email_from_provider?
if persisted?
gl_user.skip_reconfirmation!
gl_user.email = auth_hash.email
end
gl_user.external_email = true
gl_user.email_provider = auth_hash.provider
end
end
def log def log
Gitlab::AppLogger Gitlab::AppLogger
end end
......
require('spec_helper')
describe ProfilesController do
describe "PUT update" do
it "allows an email update from a user without an external email address" do
user = create(:user)
sign_in(user)
put :update,
user: { email: "john@gmail.com", name: "John" }
user.reload
expect(response.status).to eq(302)
expect(user.unconfirmed_email).to eq('john@gmail.com')
end
it "ignores an email update from a user with an external email address" do
ldap_user = create(:omniauth_user, external_email: true)
sign_in(ldap_user)
put :update,
user: { email: "john@gmail.com", name: "John" }
ldap_user.reload
expect(response.status).to eq(302)
expect(ldap_user.unconfirmed_email).not_to eq('john@gmail.com')
end
end
end
require 'rails_helper'
describe ProfilesHelper do
describe '#email_provider_label' do
it "returns nil for users without external email" do
user = create(:user)
allow(helper).to receive(:current_user).and_return(user)
expect(helper.email_provider_label).to be_nil
end
it "returns omniauth provider label for users with external email" do
stub_cas_omniauth_provider
cas_user = create(:omniauth_user, provider: 'cas3', external_email: true, email_provider: 'cas3')
allow(helper).to receive(:current_user).and_return(cas_user)
expect(helper.email_provider_label).to eq('CAS')
end
it "returns 'LDAP' for users with external email but no email provider" do
ldap_user = create(:omniauth_user, external_email: true)
allow(helper).to receive(:current_user).and_return(ldap_user)
expect(helper.email_provider_label).to eq('LDAP')
end
end
def stub_cas_omniauth_provider
provider = OpenStruct.new(
'name' => 'cas3',
'label' => 'CAS'
)
stub_omniauth_setting(providers: [provider])
end
end
...@@ -8,14 +8,14 @@ describe Gitlab::LDAP::Access, lib: true do ...@@ -8,14 +8,14 @@ describe Gitlab::LDAP::Access, lib: true do
describe '#find_ldap_user' do describe '#find_ldap_user' do
it 'finds a user by dn first' do it 'finds a user by dn first' do
expect(Gitlab::LDAP::Person).to receive(:find_by_dn).and_return(:ldap_user) expect(Gitlab::LDAP::Person).to receive(:find_by_dn).and_return(:ldap_user)
expect(user).not_to receive(:ldap_email?) expect(user).not_to receive(:external_email?)
access.find_ldap_user access.find_ldap_user
end end
it 'finds a user by email if the email came from LDAP' do it 'finds a user by email if the email came from LDAP' do
expect(Gitlab::LDAP::Person).to receive(:find_by_dn).and_return(nil) expect(Gitlab::LDAP::Person).to receive(:find_by_dn).and_return(nil)
expect(user).to receive(:ldap_email?).and_return(true) expect(user).to receive(:external_email?).and_return(true)
expect(Gitlab::LDAP::Person).to receive(:find_by_email) expect(Gitlab::LDAP::Person).to receive(:find_by_email)
access.find_ldap_user access.find_ldap_user
......
...@@ -37,7 +37,7 @@ describe Gitlab::LDAP::User, lib: true do ...@@ -37,7 +37,7 @@ describe Gitlab::LDAP::User, lib: true do
end end
it "does not mark existing ldap user as changed" do it "does not mark existing ldap user as changed" do
create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain', ldap_email: true) create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain', external_email: true, email_provider: 'ldapmain')
expect(ldap_user.changed?).to be_falsey expect(ldap_user.changed?).to be_falsey
end end
end end
...@@ -141,8 +141,12 @@ describe Gitlab::LDAP::User, lib: true do ...@@ -141,8 +141,12 @@ describe Gitlab::LDAP::User, lib: true do
expect(ldap_user.gl_user.email).to eq(info[:email]) expect(ldap_user.gl_user.email).to eq(info[:email])
end end
it "has ldap_email set to true" do it "has external_email set to true" do
expect(ldap_user.gl_user.ldap_email?).to be(true) expect(ldap_user.gl_user.external_email?).to be(true)
end
it "has email_provider set to provider" do
expect(ldap_user.gl_user.email_provider).to eql 'ldapmain'
end end
end end
...@@ -155,8 +159,8 @@ describe Gitlab::LDAP::User, lib: true do ...@@ -155,8 +159,8 @@ describe Gitlab::LDAP::User, lib: true do
expect(ldap_user.gl_user.temp_oauth_email?).to be(true) expect(ldap_user.gl_user.temp_oauth_email?).to be(true)
end end
it "has ldap_email set to false" do it "has external_email set to false" do
expect(ldap_user.gl_user.ldap_email?).to be(false) expect(ldap_user.gl_user.external_email?).to be(false)
end end
end end
end end
......
...@@ -28,11 +28,11 @@ describe Gitlab::OAuth::User, lib: true do ...@@ -28,11 +28,11 @@ describe Gitlab::OAuth::User, lib: true do
end end
end end
describe '#save' do def stub_omniauth_config(messages)
def stub_omniauth_config(messages) allow(Gitlab.config.omniauth).to receive_messages(messages)
allow(Gitlab.config.omniauth).to receive_messages(messages) end
end
describe '#save' do
def stub_ldap_config(messages) def stub_ldap_config(messages)
allow(Gitlab::LDAP::Config).to receive_messages(messages) allow(Gitlab::LDAP::Config).to receive_messages(messages)
end end
...@@ -377,4 +377,40 @@ describe Gitlab::OAuth::User, lib: true do ...@@ -377,4 +377,40 @@ describe Gitlab::OAuth::User, lib: true do
end end
end end
end end
describe 'updating email' do
let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
before do
stub_omniauth_config(sync_email_from_provider: 'my-provider')
end
context "when provider sets an email" do
it "updates the user email" do
expect(gl_user.email).to eq(info_hash[:email])
end
it "has external_email set to true" do
expect(gl_user.external_email?).to be(true)
end
it "has email_provider set to provider" do
expect(gl_user.email_provider).to eql 'my-provider'
end
end
context "when provider doesn't set an email" do
before do
info_hash.delete(:email)
end
it "does not update the user email" do
expect(gl_user.email).not_to eq(info_hash[:email])
end
it "has external_email set to false" do
expect(gl_user.external_email?).to be(false)
end
end
end
end end
...@@ -25,6 +25,10 @@ module StubConfiguration ...@@ -25,6 +25,10 @@ module StubConfiguration
allow(Gitlab.config.mattermost).to receive_messages(messages) allow(Gitlab.config.mattermost).to receive_messages(messages)
end end
def stub_omniauth_setting(messages)
allow(Gitlab.config.omniauth).to receive_messages(messages)
end
private private
# Modifies stubbed messages to also stub possible predicate versions # Modifies stubbed messages to also stub possible predicate versions
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment