diff --git a/doc/api/saml.md b/doc/api/saml.md index 6b2e7cffaabe9df9a3d0b7833cb656f6267c1ce4..b1d7692fbaf6d6a49becdfeaf0067bfc5f7fead6 100644 --- a/doc/api/saml.md +++ b/doc/api/saml.md @@ -22,7 +22,7 @@ Supported attributes: | Attribute | Type | Required | Description | |:------------------|:--------|:---------|:----------------------| -| `id` | integer | Yes | Group ID for the group to return SAML identities. | +| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) | If successful, returns [`200`](rest/index.md#status-codes) and the following response attributes: @@ -49,6 +49,36 @@ Example response: ] ``` +## Get a single SAML identity + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123591) in GitLab 16.1. + +```plaintext +GET /groups/:id/saml/:uid +``` + +Supported attributes: + +| Attribute | Type | Required | Description | +| --------- | -------------- | -------- | ------------------------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) | +| `uid` | string | yes | External UID of the user. | + +Example request: + +```shell +curl --location --request GET "https://gitlab.example.com/api/v4/groups/33/saml/sydney_jones" --header "" +``` + +Example response: + +```json +{ + "extern_uid": "4", + "user_id": 48 +} +``` + ## Update `extern_uid` field for a SAML identity Update `extern_uid` field for a SAML identity: @@ -58,13 +88,14 @@ Update `extern_uid` field for a SAML identity: | `id/externalId` | `extern_uid` | ```plaintext -PATCH groups/:groups_id/saml/:uid +PATCH /groups/:id/saml/:uid ``` -Parameters: +Supported attributes: | Attribute | Type | Required | Description | | --------- | ------ | -------- | ------------------------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) | | `uid` | string | yes | External UID of the user. | Example request: diff --git a/doc/api/scim.md b/doc/api/scim.md index 6e022afb2f5efc3153a4b6fd623a0f45b08fa7e3..df0d90756d26d04307c349e7357550cd9ae2a836 100644 --- a/doc/api/scim.md +++ b/doc/api/scim.md @@ -28,7 +28,7 @@ Supported attributes: | Attribute | Type | Required | Description | |:------------------|:--------|:---------|:----------------------| -| `id` | integer | Yes | Return SCIM identities for the given group ID. | +| `id` | integer/string | Yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) | If successful, returns [`200`](rest/index.md#status-codes) and the following response attributes: @@ -58,6 +58,37 @@ curl --location --request GET "https://gitlab.example.com/api/v4/groups/33/scim/ --header "PRIVATE-TOKEN: " ``` +## Get a single SCIM identity + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123591) in GitLab 16.1. + +```plaintext +GET /groups/:id/scim/:uid +``` + +Supported attributes: + +| Attribute | Type | Required | Description | +| --------- | ------- | -------- | ------------------------- | +| `id` | integer | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) | +| `uid` | string | yes | External UID of the user. | + +Example request: + +```shell +curl --location --request GET "https://gitlab.example.com/api/v4/groups/33/scim/sydney_jones" --header "" +``` + +Example response: + +```json +{ + "extern_uid": "4", + "user_id": 48, + "active": true +} +``` + ## Update `extern_uid` field for a SCIM identity > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227841) in GitLab 15.5. @@ -76,6 +107,7 @@ Parameters: | Attribute | Type | Required | Description | | --------- | ------ | -------- | ------------------------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) | | `uid` | string | yes | External UID of the user. | Example request: diff --git a/ee/lib/api/provider_identity.rb b/ee/lib/api/provider_identity.rb index 42f7494ac9a7df744afa93f5535c4d1ab6141dfe..ad208961e783e28873b2a565e5ab4175e6267e75 100644 --- a/ee/lib/api/provider_identity.rb +++ b/ee/lib/api/provider_identity.rb @@ -31,6 +31,21 @@ class ProviderIdentity < ::API::Base end end + desc 'Get a single identity for a user' do + success EE::API::Entities::IdentityDetail + end + params do + requires :uid, type: String, desc: 'External UID of the user' + end + get ':uid', format: false, requirements: { uid: API::NO_SLASH_URL_PART_REGEX } do + group = find_group(params[:id]) + identity = find_provider_identity(provider_type, params[:uid], group) + + not_found!('Identity') unless identity + + present identity, with: EE::API::Entities::IdentityDetail + end + desc 'Update extern_uid for the user' do success EE::API::Entities::IdentityDetail end diff --git a/ee/spec/requests/api/provider_identity_spec.rb b/ee/spec/requests/api/provider_identity_spec.rb index a8c4fdacc59177299d37dd0f325e557a84433ed1..61c2c1683b193c68e8ebd4960dc065d131269862 100644 --- a/ee/spec/requests/api/provider_identity_spec.rb +++ b/ee/spec/requests/api/provider_identity_spec.rb @@ -6,6 +6,7 @@ include ApiHelpers let_it_be(:owner) { create(:user) } + let_it_be(:maintainer) { create(:user) } let_it_be(:guest_user_1) { create(:user) } let_it_be(:guest_user_2) { create(:user) } let(:current_user) { nil } @@ -14,6 +15,7 @@ group = create(:group) group.add_guest(guest_user_1) group.add_guest(guest_user_2) + group.add_maintainer(maintainer) group.add_owner(owner) group end @@ -61,7 +63,7 @@ subject(:get_identities) { get api("/groups/#{group.id}/#{provider_type}/identities", current_user) } context "when user is not a group owner" do - let(:current_user) { guest_user_1 } + let(:current_user) { maintainer } it "throws unauthorized error" do get_identities @@ -101,6 +103,40 @@ end end + context "when GET identity" do + subject(:get_identity) do + get api("/groups/#{group.id}/#{provider_type}/#{provider_extern_uid_1}", current_user) + end + + context "when user is not a group owner" do + let(:current_user) { maintainer } + + it "throws unauthorized error" do + get_identity + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context "when user is group owner" do + let(:current_user) { owner } + + it "returns the identity" do + get_identity + + if identity_type == ScimIdentity + expect(json_response).to match( + a_hash_including("extern_uid" => provider_extern_uid_1, "user_id" => guest_user_1.id, "active" => true) + ) + else + expect(json_response).to match( + a_hash_including("extern_uid" => provider_extern_uid_1, "user_id" => guest_user_1.id) + ) + end + end + end + end + context "when PATCH uid" do subject(:patch_identities) do patch api("/groups/#{group.id}/#{provider_type}/#{uid}", current_user), @@ -109,7 +145,7 @@ context "when user is not a group owner" do let(:uid) { provider_extern_uid_1 } - let(:current_user) { guest_user_1 } + let(:current_user) { maintainer } let(:extern_uid) { 'updated_uid' } it "throws forbidden error" do