diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 0b4778a20cbce..a23488052007a 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -3170,6 +3170,52 @@ const docTemplate = `{ } } }, + "/organizations/{organization}/settings/idpsync/field-values": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Enterprise" + ], + "summary": "Get the organization idp sync claim field values", + "operationId": "get-the-organization-idp-sync-claim-field-values", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Organization ID", + "name": "organization", + "in": "path", + "required": true + }, + { + "type": "string", + "format": "string", + "description": "Claim Field", + "name": "claimField", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, "/organizations/{organization}/settings/idpsync/groups": { "get": { "security": [ @@ -3952,6 +3998,52 @@ const docTemplate = `{ } } }, + "/settings/idpsync/field-values": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Enterprise" + ], + "summary": "Get the idp sync claim field values", + "operationId": "get-the-idp-sync-claim-field-values", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Organization ID", + "name": "organization", + "in": "path", + "required": true + }, + { + "type": "string", + "format": "string", + "description": "Claim Field", + "name": "claimField", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, "/settings/idpsync/organization": { "get": { "security": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index e9fbb8a5a9083..67d394ae67c25 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -2788,6 +2788,48 @@ } } }, + "/organizations/{organization}/settings/idpsync/field-values": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Enterprise"], + "summary": "Get the organization idp sync claim field values", + "operationId": "get-the-organization-idp-sync-claim-field-values", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Organization ID", + "name": "organization", + "in": "path", + "required": true + }, + { + "type": "string", + "format": "string", + "description": "Claim Field", + "name": "claimField", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, "/organizations/{organization}/settings/idpsync/groups": { "get": { "security": [ @@ -3478,6 +3520,48 @@ } } }, + "/settings/idpsync/field-values": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Enterprise"], + "summary": "Get the idp sync claim field values", + "operationId": "get-the-idp-sync-claim-field-values", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Organization ID", + "name": "organization", + "in": "path", + "required": true + }, + { + "type": "string", + "format": "string", + "description": "Claim Field", + "name": "claimField", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, "/settings/idpsync/organization": { "get": { "security": [ diff --git a/codersdk/idpsync.go b/codersdk/idpsync.go index 3a2e707ccb623..2cc1f51ee3011 100644 --- a/codersdk/idpsync.go +++ b/codersdk/idpsync.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "net/http" + "net/url" "regexp" "github.com/google/uuid" @@ -163,3 +164,35 @@ func (c *Client) GetOrganizationAvailableIDPSyncFields(ctx context.Context, orgI var resp []string return resp, json.NewDecoder(res.Body).Decode(&resp) } + +func (c *Client) GetIDPSyncFieldValues(ctx context.Context, claimField string) ([]string, error) { + qv := url.Values{} + qv.Add("claimField", claimField) + res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/settings/idpsync/field-values?%s", qv.Encode()), nil) + if err != nil { + return nil, xerrors.Errorf("make request: %w", err) + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return nil, ReadBodyAsError(res) + } + var resp []string + return resp, json.NewDecoder(res.Body).Decode(&resp) +} + +func (c *Client) GetOrganizationIDPSyncFieldValues(ctx context.Context, orgID string, claimField string) ([]string, error) { + qv := url.Values{} + qv.Add("claimField", claimField) + res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/organizations/%s/settings/idpsync/field-values?%s", orgID, qv.Encode()), nil) + if err != nil { + return nil, xerrors.Errorf("make request: %w", err) + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return nil, ReadBodyAsError(res) + } + var resp []string + return resp, json.NewDecoder(res.Body).Decode(&resp) +} diff --git a/docs/reference/api/enterprise.md b/docs/reference/api/enterprise.md index 21a46e92cba08..80515f3ee7bef 100644 --- a/docs/reference/api/enterprise.md +++ b/docs/reference/api/enterprise.md @@ -1830,6 +1830,46 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/setting To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Get the organization idp sync claim field values + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/settings/idpsync/field-values?claimField=string \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /organizations/{organization}/settings/idpsync/field-values` + +### Parameters + +| Name | In | Type | Required | Description | +|----------------|-------|----------------|----------|-----------------| +| `organization` | path | string(uuid) | true | Organization ID | +| `claimField` | query | string(string) | true | Claim Field | + +### Example responses + +> 200 Response + +```json +[ + "string" +] +``` + +### Responses + +| Status | Meaning | Description | Schema | +|--------|---------------------------------------------------------|-------------|-----------------| +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | array of string | + +

Response Schema

+ +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## Get group IdP Sync settings by organization ### Code samples @@ -2536,6 +2576,46 @@ curl -X GET http://coder-server:8080/api/v2/settings/idpsync/available-fields \ To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Get the idp sync claim field values + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/settings/idpsync/field-values?claimField=string \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /settings/idpsync/field-values` + +### Parameters + +| Name | In | Type | Required | Description | +|----------------|-------|----------------|----------|-----------------| +| `organization` | path | string(uuid) | true | Organization ID | +| `claimField` | query | string(string) | true | Claim Field | + +### Example responses + +> 200 Response + +```json +[ + "string" +] +``` + +### Responses + +| Status | Meaning | Description | Schema | +|--------|---------------------------------------------------------|-------------|-----------------| +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | array of string | + +

Response Schema

+ +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## Get organization IdP Sync settings ### Code samples diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index 71273ff97fd75..90042bf0997fc 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -297,6 +297,7 @@ func New(ctx context.Context, options *Options) (_ *API, err error) { r.Patch("/", api.patchOrganizationIDPSyncSettings) }) r.Get("/available-fields", api.deploymentIDPSyncClaimFields) + r.Get("/field-values", api.deploymentIDPSyncClaimFieldValues) }) }) @@ -311,6 +312,7 @@ func New(ctx context.Context, options *Options) (_ *API, err error) { r.Patch("/idpsync/groups", api.patchGroupIDPSyncSettings) r.Get("/idpsync/roles", api.roleIDPSyncSettings) r.Patch("/idpsync/roles", api.patchRoleIDPSyncSettings) + r.Get("/idpsync/field-values", api.organizationIDPSyncClaimFieldValues) }) }) diff --git a/enterprise/coderd/idpsync.go b/enterprise/coderd/idpsync.go index e7346f8406844..192d61ea996c6 100644 --- a/enterprise/coderd/idpsync.go +++ b/enterprise/coderd/idpsync.go @@ -363,3 +363,63 @@ func (api *API) idpSyncClaimFields(orgID uuid.UUID, rw http.ResponseWriter, r *h httpapi.Write(ctx, rw, http.StatusOK, fields) } + +// @Summary Get the organization idp sync claim field values +// @ID get-the-organization-idp-sync-claim-field-values +// @Security CoderSessionToken +// @Produce json +// @Tags Enterprise +// @Param organization path string true "Organization ID" format(uuid) +// @Param claimField query string true "Claim Field" format(string) +// @Success 200 {array} string +// @Router /organizations/{organization}/settings/idpsync/field-values [get] +func (api *API) organizationIDPSyncClaimFieldValues(rw http.ResponseWriter, r *http.Request) { + org := httpmw.OrganizationParam(r) + api.idpSyncClaimFieldValues(org.ID, rw, r) +} + +// @Summary Get the idp sync claim field values +// @ID get-the-idp-sync-claim-field-values +// @Security CoderSessionToken +// @Produce json +// @Tags Enterprise +// @Param organization path string true "Organization ID" format(uuid) +// @Param claimField query string true "Claim Field" format(string) +// @Success 200 {array} string +// @Router /settings/idpsync/field-values [get] +func (api *API) deploymentIDPSyncClaimFieldValues(rw http.ResponseWriter, r *http.Request) { + // nil uuid implies all organizations + api.idpSyncClaimFieldValues(uuid.Nil, rw, r) +} + +func (api *API) idpSyncClaimFieldValues(orgID uuid.UUID, rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + claimField := r.URL.Query().Get("claimField") + if claimField == "" { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: "claimField query parameter is required", + }) + return + } + fieldValues, err := api.Database.OIDCClaimFieldValues(ctx, database.OIDCClaimFieldValuesParams{ + OrganizationID: orgID, + ClaimField: claimField, + }) + + if httpapi.IsUnauthorizedError(err) { + // Give a helpful error. The user could read the org, so this does not + // leak anything. + httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{ + Message: "You do not have permission to view the IDP claim field values", + Detail: fmt.Sprintf("%s.read permission is required", rbac.ResourceIdpsyncSettings.Type), + }) + return + } + if err != nil { + httpapi.InternalServerError(rw, err) + return + } + + httpapi.Write(ctx, rw, http.StatusOK, fieldValues) +} diff --git a/enterprise/coderd/userauth_test.go b/enterprise/coderd/userauth_test.go index 28257078ebb36..d3e997608f316 100644 --- a/enterprise/coderd/userauth_test.go +++ b/enterprise/coderd/userauth_test.go @@ -178,6 +178,14 @@ func TestUserOIDC(t *testing.T) { require.NoError(t, err) require.ElementsMatch(t, fields, orgFields) + fieldValues, err := runner.AdminClient.GetIDPSyncFieldValues(ctx, "organization") + require.NoError(t, err) + require.ElementsMatch(t, []string{"first", "second"}, fieldValues) + + orgFieldValues, err := runner.AdminClient.GetOrganizationIDPSyncFieldValues(ctx, orgOne.ID.String(), "organization") + require.NoError(t, err) + require.ElementsMatch(t, []string{"first", "second"}, orgFieldValues) + // When: they are manually added to the fourth organization, a new sync // should remove them. _, err = runner.AdminClient.PostOrganizationMember(ctx, orgThree.ID, "alice") pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy