mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore: add api endpoints to get idp field values (#16063)
Supports coder/internal#210
This commit is contained in:
Generated
+92
@@ -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": [
|
||||
|
||||
Generated
+84
@@ -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": [
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Generated
+80
@@ -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 |
|
||||
|
||||
<h3 id="get-the-organization-idp-sync-claim-field-values-responseschema">Response Schema</h3>
|
||||
|
||||
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 |
|
||||
|
||||
<h3 id="get-the-idp-sync-claim-field-values-responseschema">Response Schema</h3>
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Get organization IdP Sync settings
|
||||
|
||||
### Code samples
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user