diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index bd4b310fcbf..58d0506c07d 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -42,10 +42,8 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController def handle_omniauth if current_user - # Change a logged-in user's authentication method: - current_user.extern_uid = oauth['uid'] - current_user.provider = oauth['provider'] - current_user.save + # Add new authentication method + current_user.identities.find_or_create_by(extern_uid: oauth['uid'], provider: oauth['provider']) redirect_to profile_path else @user = Gitlab::OAuth::User.new(oauth) @@ -53,6 +51,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController # Only allow properly saved users to login. if @user.persisted? && @user.valid? + # binding.pry sign_in_and_redirect(@user.gl_user) else error_message = diff --git a/app/helpers/profile_helper.rb b/app/helpers/profile_helper.rb index 0b375558305..816074e0247 100644 --- a/app/helpers/profile_helper.rb +++ b/app/helpers/profile_helper.rb @@ -1,6 +1,6 @@ module ProfileHelper def oauth_active_class(provider) - if current_user.provider == provider.to_s + if current_user.identities.exists?(provider: provider.to_s) 'active' end end diff --git a/app/models/identity.rb b/app/models/identity.rb new file mode 100644 index 00000000000..e6af93bcc50 --- /dev/null +++ b/app/models/identity.rb @@ -0,0 +1,7 @@ +class Identity < ActiveRecord::Base + belongs_to :user + + validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} + + scope :ldap, -> { where('provider LIKE ?', 'ldap%') } +end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index 1cddd85ada0..0cf0946593c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -79,6 +79,7 @@ class User < ActiveRecord::Base # Profile has_many :keys, dependent: :destroy has_many :emails, dependent: :destroy + has_many :identities, dependent: :destroy # Groups has_many :members, dependent: :destroy @@ -113,7 +114,6 @@ class User < ActiveRecord::Base validates :name, presence: true validates :email, presence: true, email: {strict_mode: true}, uniqueness: true validates :bio, length: { maximum: 255 }, allow_blank: true - validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} validates :username, presence: true, uniqueness: { case_sensitive: false }, exclusion: { in: Gitlab::Blacklist.path }, @@ -178,7 +178,6 @@ class User < ActiveRecord::Base scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) } scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all } scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') } - scope :ldap, -> { where('provider LIKE ?', 'ldap%') } scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active } # diff --git a/db/migrate/20141121161704_add_identity_table.rb b/db/migrate/20141121161704_add_identity_table.rb new file mode 100644 index 00000000000..7d019c65ee1 --- /dev/null +++ b/db/migrate/20141121161704_add_identity_table.rb @@ -0,0 +1,21 @@ +class AddIdentityTable < ActiveRecord::Migration + def up + create_table :identities do |t| + t.string :extern_uid + t.string :provider + t.references :user + end + + add_index :identities, :user_id + + User.where("provider is not NULL").find_each do |user| + execute "INSERT INTO identities(provider, extern_uid, user_id) VALUES('#{user.provider}', '#{user.extern_uid}', '#{user.id}')" + end + + #TODO remove user's columns extern_uid and provider + end + + def down +#TODO + end +end diff --git a/db/schema.rb b/db/schema.rb index 68d1080b6ee..34f991e5cf2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,11 +11,20 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20141121133009) do +ActiveRecord::Schema.define(version: 20141121161704) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "appearances", force: true do |t| + t.string "title" + t.text "description" + t.string "logo" + t.integer "updated_by" + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "broadcast_messages", force: true do |t| t.text "message", null: false t.datetime "starts_at" @@ -74,6 +83,29 @@ ActiveRecord::Schema.define(version: 20141121133009) do add_index "forked_project_links", ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree + create_table "git_hooks", force: true do |t| + t.string "force_push_regex" + t.string "delete_branch_regex" + t.string "commit_message_regex" + t.boolean "deny_delete_tag" + t.integer "project_id" + t.datetime "created_at" + t.datetime "updated_at" + t.string "username_regex" + t.string "email_regex" + t.string "author_email_regex" + t.boolean "member_check", default: false, null: false + t.string "file_name_regex" + end + + create_table "identities", force: true do |t| + t.string "extern_uid" + t.string "provider" + t.integer "user_id" + end + + add_index "identities", ["user_id"], name: "index_identities_on_user_id", using: :btree + create_table "issues", force: true do |t| t.string "title" t.integer "assignee_id" @@ -130,6 +162,15 @@ ActiveRecord::Schema.define(version: 20141121133009) do add_index "labels", ["project_id"], name: "index_labels_on_project_id", using: :btree + create_table "ldap_group_links", force: true do |t| + t.string "cn", null: false + t.integer "group_access", null: false + t.integer "group_id", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.string "provider" + end + create_table "members", force: true do |t| t.integer "access_level", null: false t.integer "source_id", null: false @@ -209,6 +250,8 @@ ActiveRecord::Schema.define(version: 20141121133009) do t.string "type" t.string "description", default: "", null: false t.string "avatar" + t.string "ldap_cn" + t.integer "ldap_access" end add_index "namespaces", ["name"], name: "index_namespaces_on_name", using: :btree @@ -240,6 +283,14 @@ ActiveRecord::Schema.define(version: 20141121133009) do add_index "notes", ["project_id"], name: "index_notes_on_project_id", using: :btree add_index "notes", ["updated_at"], name: "index_notes_on_updated_at", using: :btree + create_table "project_group_links", force: true do |t| + t.integer "project_id", null: false + t.integer "group_id", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.integer "group_access", default: 30, null: false + end + create_table "projects", force: true do |t| t.string "name" t.string "path" @@ -247,21 +298,22 @@ ActiveRecord::Schema.define(version: 20141121133009) do t.datetime "created_at" t.datetime "updated_at" t.integer "creator_id" - t.boolean "issues_enabled", default: true, null: false - t.boolean "wall_enabled", default: true, null: false - t.boolean "merge_requests_enabled", default: true, null: false - t.boolean "wiki_enabled", default: true, null: false + t.boolean "issues_enabled", default: true, null: false + t.boolean "wall_enabled", default: true, null: false + t.boolean "merge_requests_enabled", default: true, null: false + t.boolean "wiki_enabled", default: true, null: false t.integer "namespace_id" - t.string "issues_tracker", default: "gitlab", null: false + t.string "issues_tracker", default: "gitlab", null: false t.string "issues_tracker_id" - t.boolean "snippets_enabled", default: true, null: false + t.boolean "snippets_enabled", default: true, null: false t.datetime "last_activity_at" t.string "import_url" - t.integer "visibility_level", default: 0, null: false - t.boolean "archived", default: false, null: false + t.integer "visibility_level", default: 0, null: false + t.boolean "archived", default: false, null: false t.string "import_status" - t.float "repository_size", default: 0.0 - t.integer "star_count", default: 0, null: false + t.float "repository_size", default: 0.0 + t.integer "star_count", default: 0, null: false + t.text "merge_requests_template" end add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree @@ -327,12 +379,12 @@ ActiveRecord::Schema.define(version: 20141121133009) do end create_table "users", force: true do |t| - t.string "email", default: "", null: false - t.string "encrypted_password", default: "", null: false + t.string "email", default: "", null: false + t.string "encrypted_password", default: "", null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0 + t.integer "sign_in_count", default: 0 t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" t.string "current_sign_in_ip" @@ -340,24 +392,24 @@ ActiveRecord::Schema.define(version: 20141121133009) do t.datetime "created_at" t.datetime "updated_at" t.string "name" - t.boolean "admin", default: false, null: false - t.integer "projects_limit", default: 10 - t.string "skype", default: "", null: false - t.string "linkedin", default: "", null: false - t.string "twitter", default: "", null: false + t.boolean "admin", default: false, null: false + t.integer "projects_limit", default: 10 + t.string "skype", default: "", null: false + t.string "linkedin", default: "", null: false + t.string "twitter", default: "", null: false t.string "authentication_token" - t.integer "theme_id", default: 1, null: false + t.integer "theme_id", default: 1, null: false t.string "bio" - t.integer "failed_attempts", default: 0 + t.integer "failed_attempts", default: 0 t.datetime "locked_at" t.string "extern_uid" t.string "provider" t.string "username" - t.boolean "can_create_group", default: true, null: false - t.boolean "can_create_team", default: true, null: false + t.boolean "can_create_group", default: true, null: false + t.boolean "can_create_team", default: true, null: false t.string "state" - t.integer "color_scheme_id", default: 1, null: false - t.integer "notification_level", default: 1, null: false + t.integer "color_scheme_id", default: 1, null: false + t.integer "notification_level", default: 1, null: false t.datetime "password_expires_at" t.integer "created_by_id" t.string "avatar" @@ -365,9 +417,10 @@ ActiveRecord::Schema.define(version: 20141121133009) do t.datetime "confirmed_at" t.datetime "confirmation_sent_at" t.string "unconfirmed_email" - t.boolean "hide_no_ssh_key", default: false - t.string "website_url", default: "", null: false + t.boolean "hide_no_ssh_key", default: false + t.string "website_url", default: "", null: false t.datetime "last_credential_check_at" + t.datetime "admin_email_unsubscribed_at" end add_index "users", ["admin"], name: "index_users_on_admin", using: :btree diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb index 3176e9790a7..827a33b5217 100644 --- a/lib/gitlab/ldap/user.rb +++ b/lib/gitlab/ldap/user.rb @@ -12,9 +12,10 @@ module Gitlab class << self def find_by_uid_and_provider(uid, provider) # LDAP distinguished name is case-insensitive - ::User. + identity = ::Identity. where(provider: [provider, :ldap]). where('lower(extern_uid) = ?', uid.downcase).last + identity && identity.user end end @@ -34,7 +35,7 @@ module Gitlab end def find_by_email - model.find_by(email: auth_hash.email) + User.find_by(email: auth_hash.email) end def update_user_attributes diff --git a/lib/gitlab/oauth/user.rb b/lib/gitlab/oauth/user.rb index 47f62153a50..7c1970eb8e5 100644 --- a/lib/gitlab/oauth/user.rb +++ b/lib/gitlab/oauth/user.rb @@ -27,11 +27,9 @@ module Gitlab def save unauthorized_to_create unless gl_user + gl_user.save! if needs_blocking? - gl_user.save! gl_user.block - else - gl_user.save! end log.info "(OAuth) saving user #{auth_hash.email} from login with extern_uid => #{auth_hash.uid}" @@ -70,24 +68,23 @@ module Gitlab end def find_by_uid_and_provider - model.where(provider: auth_hash.provider, extern_uid: auth_hash.uid).last + identity = Identity.find_by(provider: auth_hash.provider, extern_uid: auth_hash.uid) + identity && identity.user end def build_new_user - model.new(user_attributes).tap do |user| - user.skip_confirmation! - end + user = User.new(user_attributes) + user.skip_confirmation! + user.identities.new(extern_uid: auth_hash.uid, provider: auth_hash.provider) end def user_attributes { - extern_uid: auth_hash.uid, - provider: auth_hash.provider, name: auth_hash.name, username: auth_hash.username, email: auth_hash.email, password: auth_hash.password, - password_confirmation: auth_hash.password, + password_confirmation: auth_hash.password } end @@ -95,10 +92,6 @@ module Gitlab Gitlab::AppLogger end - def model - ::User - end - def raise_unauthorized_to_create raise StandardError.new("Unauthorized to create user, signup disabled for #{auth_hash.provider}") end