8000 feat: get and update group IdP Sync settings by aslilac · Pull Request #14647 · coder/coder · GitHub
[go: up one dir, main page]

Skip to content

feat: get and update group IdP Sync settings #14647

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add unit test to enforce unauthorized
  • Loading branch information
Emyrk committed Sep 16, 2024
commit 86ba866e44f0d5184f3ac22664846da7763c3d56
4 changes: 2 additions & 2 deletions codersdk/idpsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ func (c *Client) GroupIDPSyncSettings(ctx context.Context, orgID string) (GroupS
return resp, json.NewDecoder(res.Body).Decode(&resp)
}

func (c *Client) PostGroupIDPSyncSettings(ctx context.Context, orgID string, req GroupSyncSettings) (GroupSyncSettings, error) {
res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/organizations/%s/settings/idpsync/groups", orgID), req)
func (c *Client) PatchGroupIDPSyncSettings(ctx context.Context, orgID string, req GroupSyncSettings) (GroupSyncSettings, error) {
res, err := c.Request(ctx, http.MethodPatch, fmt.Sprintf("/api/v2/organizations/%s/settings/idpsync/groups", orgID), req)
if err != nil {
return GroupSyncSettings{}, xerrors.Errorf("make request: %w", err)
}
Expand Down
24 changes: 21 additions & 3 deletions enterprise/coderd/idpsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package coderd
import (
"net/http"

"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/coderd/httpmw"
"github.com/coder/coder/v2/coderd/idpsync"
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/rbac/policy"
)

// @Summary Get group IdP Sync settings by organization
Expand All @@ -20,9 +23,17 @@ func (api *API) groupIDPSyncSettings(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
org := httpmw.OrganizationParam(r)

if !api.Authorize(r, policy.ActionRead, rbac.ResourceIdpsyncSettings.InOrg(org.ID)) {
httpapi.Forbidden(rw)
return
}

rlv := api.Options.RuntimeConfig.OrganizationResolver(api.Database, org.ID)
runtimeConfigEntry := api.IDPSync.GroupSyncSettings()
settings, err := runtimeConfigEntry.Resolve(ctx, rlv)

//nolint:gocritic // Requires system context to read runtime config
sysCtx := dbauthz.AsSystemRestricted(ctx)
settings, err := runtimeConfigEntry.Resolve(sysCtx, rlv)
if err != nil {
httpapi.InternalServerError(rw, err)
return
Expand All @@ -43,6 +54,11 @@ func (api *API) patchGroupIDPSyncSettings(rw http.ResponseWriter, r *http.Reques
ctx := r.Context()
org := httpmw.OrganizationParam(r)

if !api.Authorize(r, policy.ActionUpdate, rbac.ResourceIdpsyncSettings.InOrg(org.ID)) {
httpapi.Forbidden(rw)
return
}
Comment on lines +54 to +57
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until we find another solution, I'm doing rbac checks at the api level.


var req idpsync.GroupSyncSettings
if !httpapi.Read(ctx, rw, r, &req) {
return
Expand All @@ -51,13 +67,15 @@ func (api *API) patchGroupIDPSyncSettings(rw http.ResponseWriter, r *http.Reques
rlv := api.Options.RuntimeConfig.OrganizationResolver(api.Database, org.ID)
runtimeConfigEntry := api.IDPSync.GroupSyncSettings()

err := runtimeConfigEntry.SetRuntimeValue(ctx, rlv, &req)
//nolint:gocritic // Requires system context to update runtime config
sysCtx := dbauthz.AsSystemRestricted(ctx)
err := runtimeConfigEntry.SetRuntimeValue(sysCtx, rlv, &req)
if err != nil {
httpapi.InternalServerError(rw, err)
return
}

settings, err := runtimeConfigEntry.Resolve(ctx, rlv)
settings, err := runtimeConfigEntry.Resolve(sysCtx, rlv)
if err != nil {
httpapi.InternalServerError(rw, err)
return
Expand Down
51 changes: 45 additions & 6 deletions enterprise/coderd/idpsync_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package coderd_test

import (
"net/http"
"testing"

"github.com/stretchr/testify/require"

"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/idpsync"
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/runtimeconfig"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/enterprise/coderd/coderdenttest"
Expand Down Expand Up @@ -63,7 +65,7 @@ func TestPostGroupSyncConfig(t *testing.T) {
string(codersdk.ExperimentMultiOrganization),
}

client, db, user := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
owner, user := coderdenttest.New(t, &coderdenttest.Options{
Options: &coderdtest.Options{
DeploymentValues: dv,
},
Expand All @@ -75,17 +77,54 @@ func TestPostGroupSyncConfig(t *testing.T) {
},
})

orgAdmin, _ := coderdtest.CreateAnotherUser(t, owner, user.OrganizationID, rbac.ScopedRoleOrgAdmin(user.OrganizationID))

// Test as org admin
ctx := testutil.Context(t, testutil.WaitShort)
settings, err := client.PostGroupIDPSyncSettings(ctx, user.OrganizationID.String(), codersdk.GroupSyncSettings{
settings, err := orgAdmin.PatchGroupIDPSyncSettings(ctx, user.OrganizationID.String(), codersdk.GroupSyncSettings{
Field: "august",
})
require.NoError(t, err)
require.Equal(t, "august", settings.Field)

dbresv := runtimeconfig.OrganizationResolver(user.OrganizationID, runtimeconfig.NewStoreResolver(db))
entry := runtimeconfig.MustNew[*idpsync.GroupSyncSettings]("group-sync-settings")
dbSettings, err := entry.Resolve(ctx, dbresv)
fetchedSettings, err := orgAdmin.GroupIDPSyncSettings(ctx, user.OrganizationID.String())
require.NoError(t, err)
require.Equal(t, "august", dbSettings.Field)
require.Equal(t, "august", fetchedSettings.Field)
})

t.Run("NotAuthorized", func(t *testing.T) {
t.Parallel()

dv := coderdtest.DeploymentValues(t)
dv.Experiments = []string{
string(codersdk.ExperimentCustomRoles),
string(codersdk.ExperimentMultiOrganization),
}

owner, user := coderdenttest.New(t, &coderdenttest.Options{
Options: &coderdtest.Options{
DeploymentValues: dv,
},
LicenseOptions: &coderdenttest.LicenseOptions{
Features: license.Features{
codersdk.FeatureCustomRoles: 1,
codersdk.FeatureMultipleOrganizations: 1,
},
},
})

member, _ := coderdtest.CreateAnotherUser(t, owner, user.OrganizationID)

ctx := testutil.Context(t, testutil.WaitShort)
_, err := member.PatchGroupIDPSyncSettings(ctx, user.OrganizationID.String(), codersdk.GroupSyncSettings{
Field: "august",
})
var apiError *codersdk.Error
require.ErrorAs(t, err, &apiError)
require.Equal(t, http.StatusForbidden, apiError.StatusCode())

_, err = member.GroupIDPSyncSettings(ctx, user.OrganizationID.String())
require.ErrorAs(t, err, &apiError)
require.Equal(t, http.StatusForbidden, apiError.StatusCode())
})
}
Loading
0