From ddf7e6ae78cc87314d081427f00d54f203cfd60a Mon Sep 17 00:00:00 2001 From: Robin Bobbitt Date: Wed, 15 Feb 2017 20:44:36 -0500 Subject: [PATCH] Implement search by extern_uid in Users API --- app/models/identity.rb | 2 ++ .../unreleased/query-users-by-extern-uid.yml | 4 +++ doc/api/users.md | 12 +++++++++ lib/api/users.rb | 22 +++++++++------ spec/requests/api/users_spec.rb | 27 +++++++++++++++++++ 5 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 changelogs/unreleased/query-users-by-extern-uid.yml diff --git a/app/models/identity.rb b/app/models/identity.rb index 3bacc450e6e..920a25932b4 100644 --- a/app/models/identity.rb +++ b/app/models/identity.rb @@ -7,6 +7,8 @@ class Identity < ActiveRecord::Base validates :extern_uid, allow_blank: true, uniqueness: { scope: :provider } validates :user_id, uniqueness: { scope: :provider } + scope :with_extern_uid, ->(provider, extern_uid) { where(extern_uid: extern_uid, provider: provider) } + def ldap? provider.starts_with?('ldap') end diff --git a/changelogs/unreleased/query-users-by-extern-uid.yml b/changelogs/unreleased/query-users-by-extern-uid.yml new file mode 100644 index 00000000000..39d1cf8d3f3 --- /dev/null +++ b/changelogs/unreleased/query-users-by-extern-uid.yml @@ -0,0 +1,4 @@ +--- +title: Implement search by extern_uid in Users API +merge_request: 10509 +author: Robin Bobbitt diff --git a/doc/api/users.md b/doc/api/users.md index 2ada4d09c84..604acedb4a2 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -130,6 +130,18 @@ For example: GET /users?username=jack_smith ``` +You can also lookup users by external UID and provider: + +``` +GET /users?extern_uid=:extern_uid&provider=:provider +``` + +For example: + +``` +GET /users?extern_uid=1234567&provider=github +``` + You can search for users who are external with: `/users?external=true` ## Single user diff --git a/lib/api/users.rb b/lib/api/users.rb index eedc59f8636..d474467c8e9 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -39,10 +39,13 @@ module API params do # CE optional :username, type: String, desc: 'Get a single user with a specific username' + optional :extern_uid, type: String, desc: 'Get a single user with a specific external authentication provider UID' + optional :provider, type: String, desc: 'The external provider' optional :search, type: String, desc: 'Search for a username' optional :active, type: Boolean, default: false, desc: 'Filters only active users' optional :external, type: Boolean, default: false, desc: 'Filters only external users' optional :blocked, type: Boolean, default: false, desc: 'Filters only blocked users' + all_or_none_of :extern_uid, :provider use :pagination end @@ -51,14 +54,17 @@ module API render_api_error!("Not authorized.", 403) end - if params[:username].present? - users = User.where(username: params[:username]) - else - users = User.all - users = users.active if params[:active] - users = users.search(params[:search]) if params[:search].present? - users = users.blocked if params[:blocked] - users = users.external if params[:external] && current_user.admin? + authenticated_as_admin! if params[:external].present? || (params[:extern_uid].present? && params[:provider].present?) + + users = User.all + users = User.where(username: params[:username]) if params[:username] + users = users.active if params[:active] + users = users.search(params[:search]) if params[:search].present? + users = users.blocked if params[:blocked] + + if current_user.admin? + users = users.joins(:identities).merge(Identity.with_extern_uid(params[:provider], params[:extern_uid])) if params[:extern_uid] && params[:provider] + users = users.external if params[:external] end entity = current_user.admin? ? Entities::UserPublic : Entities::UserBasic diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index f793c0db2f3..a4c7b6bd020 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -72,6 +72,12 @@ describe API::Users, api: true do expect(json_response).to be_an Array expect(json_response.first['username']).to eq(omniauth_user.username) end + + it "returns a 403 when non-admin user searches by external UID" do + get api("/users?extern_uid=#{omniauth_user.identities.first.extern_uid}&provider=#{omniauth_user.identities.first.provider}", user) + + expect(response).to have_http_status(403) + end end context "when admin" do @@ -100,6 +106,27 @@ describe API::Users, api: true do expect(json_response).to be_an Array expect(json_response).to all(include('external' => true)) end + + it "returns one user by external UID" do + get api("/users?extern_uid=#{omniauth_user.identities.first.extern_uid}&provider=#{omniauth_user.identities.first.provider}", admin) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(1) + expect(json_response.first['username']).to eq(omniauth_user.username) + end + + it "returns 400 error if provider with no extern_uid" do + get api("/users?extern_uid=#{omniauth_user.identities.first.extern_uid}", admin) + + expect(response).to have_http_status(400) + end + + it "returns 400 error if provider with no extern_uid" do + get api("/users?provider=#{omniauth_user.identities.first.provider}", admin) + + expect(response).to have_http_status(400) + end end end