Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2cdefe7

Browse files
committed
feat: implement patch and get api methods for role sync
1 parent12c7af7 commit2cdefe7

File tree

6 files changed

+260
-18
lines changed

6 files changed

+260
-18
lines changed

‎coderd/idpsync/idpsync.go‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ type IDPSync interface {
5454
SiteRoleSyncEnabled()bool
5555
// RoleSyncSettings is similar to GroupSyncSettings. See GroupSyncSettings for
5656
// rational.
57-
RoleSyncSettings() runtimeconfig.RuntimeEntry[*RoleSyncSettings]
57+
RoleSyncSettings(ctx context.Context,orgID uuid.UUID,db database.Store) (*RoleSyncSettings,error)
58+
UpdateRoleSettings(ctx context.Context,orgID uuid.UUID,db database.Store,settingsRoleSyncSettings)error
5859
// ParseRoleClaims takes claims from an OIDC provider, and returns the params
5960
// for role syncing. Most of the logic happens in SyncRoles.
6061
ParseRoleClaims(ctx context.Context,mergedClaims jwt.MapClaims) (RoleParams,*HTTPError)

‎coderd/idpsync/role.go‎

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/coder/coder/v2/coderd/rbac/rolestore"
1717
"github.com/coder/coder/v2/coderd/runtimeconfig"
1818
"github.com/coder/coder/v2/coderd/util/slice"
19+
"github.com/coder/coder/v2/codersdk"
1920
)
2021

2122
typeRoleParamsstruct {
@@ -41,8 +42,26 @@ func (AGPLIDPSync) SiteRoleSyncEnabled() bool {
4142
returnfalse
4243
}
4344

44-
func (sAGPLIDPSync)RoleSyncSettings() runtimeconfig.RuntimeEntry[*RoleSyncSettings] {
45-
returns.Role
45+
func (sAGPLIDPSync)UpdateRoleSettings(ctx context.Context,orgID uuid.UUID,db database.Store,settingsRoleSyncSettings)error {
46+
orgResolver:=s.Manager.OrganizationResolver(db,orgID)
47+
err:=s.SyncSettings.Role.SetRuntimeValue(ctx,orgResolver,&settings)
48+
iferr!=nil {
49+
returnxerrors.Errorf("update role sync settings: %w",err)
50+
}
51+
52+
returnnil
53+
}
54+
55+
func (sAGPLIDPSync)RoleSyncSettings(ctx context.Context,orgID uuid.UUID,db database.Store) (*RoleSyncSettings,error) {
56+
rlv:=s.Manager.OrganizationResolver(db,orgID)
57+
settings,err:=s.Role.Resolve(ctx,rlv)
58+
iferr!=nil {
59+
if!xerrors.Is(err,runtimeconfig.ErrEntryNotFound) {
60+
returnnil,xerrors.Errorf("resolve role sync settings: %w",err)
61+
}
62+
return&RoleSyncSettings{},nil
63+
}
64+
returnsettings,nil
4665
}
4766

4867
func (sAGPLIDPSync)ParseRoleClaims(_ context.Context,_ jwt.MapClaims) (RoleParams,*HTTPError) {
@@ -85,15 +104,12 @@ func (s AGPLIDPSync) SyncRoles(ctx context.Context, db database.Store, user data
85104
allExpected:=make([]rbac.RoleIdentifier,0)
86105
for_,member:=rangeorgMemberships {
87106
orgID:=member.OrganizationMember.OrganizationID
88-
orgResolver:=s.Manager.OrganizationResolver(tx,orgID)
89-
settings,err:=s.RoleSyncSettings().Resolve(ctx,orgResolver)
107+
settings,err:=s.RoleSyncSettings(ctx,orgID,tx)
90108
iferr!=nil {
91-
if!xerrors.Is(err,runtimeconfig.ErrEntryNotFound) {
92-
returnxerrors.Errorf("resolve group sync settings: %w",err)
93-
}
94109
// No entry means no role syncing for this organization
95110
continue
96111
}
112+
97113
ifsettings.Field=="" {
98114
// Explicitly disabled role sync for this organization
99115
continue
@@ -261,14 +277,7 @@ func (AGPLIDPSync) RolesFromClaim(field string, claims jwt.MapClaims) ([]string,
261277
returnparsedRoles,nil
262278
}
263279

264-
typeRoleSyncSettingsstruct {
265-
// Field selects the claim field to be used as the created user's
266-
// groups. If the group field is the empty string, then no group updates
267-
// will ever come from the OIDC provider.
268-
Fieldstring`json:"field"`
269-
// Mapping maps from an OIDC group --> Coder organization role
270-
Mappingmap[string][]string`json:"mapping"`
271-
}
280+
typeRoleSyncSettings codersdk.RoleSyncSettings
272281

273282
func (s*RoleSyncSettings)Set(vstring)error {
274283
returnjson.Unmarshal([]byte(v),s)

‎codersdk/idpsync.go‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,40 @@ func (c *Client) PatchGroupIDPSyncSettings(ctx context.Context, orgID string, re
6060
varrespGroupSyncSettings
6161
returnresp,json.NewDecoder(res.Body).Decode(&resp)
6262
}
63+
64+
typeRoleSyncSettingsstruct {
65+
// Field selects the claim field to be used as the created user's
66+
// groups. If the group field is the empty string, then no group updates
67+
// will ever come from the OIDC provider.
68+
Fieldstring`json:"field"`
69+
// Mapping maps from an OIDC group --> Coder organization role
70+
Mappingmap[string][]string`json:"mapping"`
71+
}
72+
73+
func (c*Client)RoleIDPSyncSettings(ctx context.Context,orgIDstring) (RoleSyncSettings,error) {
74+
res,err:=c.Request(ctx,http.MethodGet,fmt.Sprintf("/api/v2/organizations/%s/settings/idpsync/roles",orgID),nil)
75+
iferr!=nil {
76+
returnRoleSyncSettings{},xerrors.Errorf("make request: %w",err)
77+
}
78+
deferres.Body.Close()
79+
80+
ifres.StatusCode!=http.StatusOK {
81+
returnRoleSyncSettings{},ReadBodyAsError(res)
82+
}
83+
varrespRoleSyncSettings
84+
returnresp,json.NewDecoder(res.Body).Decode(&resp)
85+
}
86+
87+
func (c*Client)PatchRoleIDPSyncSettings(ctx context.Context,orgIDstring,reqRoleSyncSettings) (RoleSyncSettings,error) {
88+
res,err:=c.Request(ctx,http.MethodPatch,fmt.Sprintf("/api/v2/organizations/%s/settings/idpsync/roles",orgID),req)
89+
iferr!=nil {
90+
returnRoleSyncSettings{},xerrors.Errorf("make request: %w",err)
91+
}
92+
deferres.Body.Close()
93+
94+
ifres.StatusCode!=http.StatusOK {
95+
returnRoleSyncSettings{},ReadBodyAsError(res)
96+
}
97+
varrespRoleSyncSettings
98+
returnresp,json.NewDecoder(res.Body).Decode(&resp)
99+
}

‎enterprise/coderd/coderd.go‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,9 +286,18 @@ func New(ctx context.Context, options *Options) (_ *API, err error) {
286286
r.Post("/organizations/{organization}/members/roles",api.postOrgRoles)
287287
r.Put("/organizations/{organization}/members/roles",api.putOrgRoles)
288288
r.Delete("/organizations/{organization}/members/roles/{roleName}",api.deleteOrgRole)
289+
})
290+
291+
r.Group(func(r chi.Router) {
292+
r.Use(
293+
apiKeyMiddleware,
294+
httpmw.ExtractOrganizationParam(api.Database),
295+
)
289296
r.Route("/organizations/{organization}/settings",func(r chi.Router) {
290297
r.Get("/idpsync/groups",api.groupIDPSyncSettings)
291298
r.Patch("/idpsync/groups",api.patchGroupIDPSyncSettings)
299+
r.Get("/idpsync/roles",api.roleIDPSyncSettings)
300+
r.Patch("/idpsync/roles",api.patchRoleIDPSyncSettings)
292301
})
293302
})
294303

‎enterprise/coderd/idpsync.go‎

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
// @Produce json
1818
// @Tags Enterprise
1919
// @Param organization path string true "Organization ID" format(uuid)
20-
// @Success 200 {object}idpsync.GroupSyncSettings
20+
// @Success 200 {object}codersdk.GroupSyncSettings
2121
// @Router /organizations/{organization}/settings/idpsync/groups [get]
2222
func (api*API)groupIDPSyncSettings(rw http.ResponseWriter,r*http.Request) {
2323
ctx:=r.Context()
@@ -45,7 +45,7 @@ func (api *API) groupIDPSyncSettings(rw http.ResponseWriter, r *http.Request) {
4545
// @Produce json
4646
// @Tags Enterprise
4747
// @Param organization path string true "Organization ID" format(uuid)
48-
// @Success 200 {object}idpsync.GroupSyncSettings
48+
// @Success 200 {object}codersdk.GroupSyncSettings
4949
// @Router /organizations/{organization}/settings/idpsync/groups [patch]
5050
func (api*API)patchGroupIDPSyncSettings(rw http.ResponseWriter,r*http.Request) {
5151
ctx:=r.Context()
@@ -77,3 +77,70 @@ func (api *API) patchGroupIDPSyncSettings(rw http.ResponseWriter, r *http.Reques
7777

7878
httpapi.Write(ctx,rw,http.StatusOK,settings)
7979
}
80+
81+
// @Summary Get role IdP Sync settings by organization
82+
// @ID get-role-idp-sync-settings-by-organization
83+
// @Security CoderSessionToken
84+
// @Produce json
85+
// @Tags Enterprise
86+
// @Param organization path string true "Organization ID" format(uuid)
87+
// @Success 200 {object} codersdk.RoleSyncSettings
88+
// @Router /organizations/{organization}/settings/idpsync/roles [get]
89+
func (api*API)roleIDPSyncSettings(rw http.ResponseWriter,r*http.Request) {
90+
ctx:=r.Context()
91+
org:=httpmw.OrganizationParam(r)
92+
93+
if!api.Authorize(r,policy.ActionRead,rbac.ResourceIdpsyncSettings.InOrg(org.ID)) {
94+
httpapi.Forbidden(rw)
95+
return
96+
}
97+
98+
//nolint:gocritic // Requires system context to read runtime config
99+
sysCtx:=dbauthz.AsSystemRestricted(ctx)
100+
settings,err:=api.IDPSync.RoleSyncSettings(sysCtx,org.ID,api.Database)
101+
iferr!=nil {
102+
httpapi.InternalServerError(rw,err)
103+
return
104+
}
105+
106+
httpapi.Write(ctx,rw,http.StatusOK,settings)
107+
}
108+
109+
// @Summary Update role IdP Sync settings by organization
110+
// @ID update-role-idp-sync-settings-by-organization
111+
// @Security CoderSessionToken
112+
// @Produce json
113+
// @Tags Enterprise
114+
// @Param organization path string true "Organization ID" format(uuid)
115+
// @Success 200 {object} codersdk.RoleSyncSettings
116+
// @Router /organizations/{organization}/settings/idpsync/roles [patch]
117+
func (api*API)patchRoleIDPSyncSettings(rw http.ResponseWriter,r*http.Request) {
118+
ctx:=r.Context()
119+
org:=httpmw.OrganizationParam(r)
120+
121+
if!api.Authorize(r,policy.ActionUpdate,rbac.ResourceIdpsyncSettings.InOrg(org.ID)) {
122+
httpapi.Forbidden(rw)
123+
return
124+
}
125+
126+
varreq idpsync.RoleSyncSettings
127+
if!httpapi.Read(ctx,rw,r,&req) {
128+
return
129+
}
130+
131+
//nolint:gocritic // Requires system context to update runtime config
132+
sysCtx:=dbauthz.AsSystemRestricted(ctx)
133+
err:=api.IDPSync.UpdateRoleSettings(sysCtx,org.ID,api.Database,req)
134+
iferr!=nil {
135+
httpapi.InternalServerError(rw,err)
136+
return
137+
}
138+
139+
settings,err:=api.IDPSync.RoleSyncSettings(sysCtx,org.ID,api.Database)
140+
iferr!=nil {
141+
httpapi.InternalServerError(rw,err)
142+
return
143+
}
144+
145+
httpapi.Write(ctx,rw,http.StatusOK,settings)
146+
}

‎enterprise/coderd/idpsync_test.go‎

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,122 @@ func TestPostGroupSyncConfig(t *testing.T) {
170170
require.Equal(t,http.StatusForbidden,apiError.StatusCode())
171171
})
172172
}
173+
174+
funcTestGetRoleSyncConfig(t*testing.T) {
175+
t.Parallel()
176+
177+
t.Run("OK",func(t*testing.T) {
178+
t.Parallel()
179+
180+
dv:=coderdtest.DeploymentValues(t)
181+
dv.Experiments= []string{
182+
string(codersdk.ExperimentCustomRoles),
183+
string(codersdk.ExperimentMultiOrganization),
184+
}
185+
186+
owner,_,_,user:=coderdenttest.NewWithAPI(t,&coderdenttest.Options{
187+
Options:&coderdtest.Options{
188+
DeploymentValues:dv,
189+
},
190+
LicenseOptions:&coderdenttest.LicenseOptions{
191+
Features: license.Features{
192+
codersdk.FeatureCustomRoles:1,
193+
codersdk.FeatureMultipleOrganizations:1,
194+
},
195+
},
196+
})
197+
orgAdmin,_:=coderdtest.CreateAnotherUser(t,owner,user.OrganizationID,rbac.ScopedRoleOrgAdmin(user.OrganizationID))
198+
199+
ctx:=testutil.Context(t,testutil.WaitShort)
200+
settings,err:=orgAdmin.PatchRoleIDPSyncSettings(ctx,user.OrganizationID.String(), codersdk.RoleSyncSettings{
201+
Field:"august",
202+
Mapping:map[string][]string{
203+
"foo": {"bar"},
204+
},
205+
})
206+
require.NoError(t,err)
207+
require.Equal(t,"august",settings.Field)
208+
require.Equal(t,map[string][]string{"foo": {"bar"}},settings.Mapping)
209+
210+
settings,err=orgAdmin.RoleIDPSyncSettings(ctx,user.OrganizationID.String())
211+
require.NoError(t,err)
212+
require.Equal(t,"august",settings.Field)
213+
require.Equal(t,map[string][]string{"foo": {"bar"}},settings.Mapping)
214+
})
215+
}
216+
217+
funcTestPostRoleSyncConfig(t*testing.T) {
218+
t.Parallel()
219+
220+
t.Run("OK",func(t*testing.T) {
221+
t.Parallel()
222+
223+
dv:=coderdtest.DeploymentValues(t)
224+
dv.Experiments= []string{
225+
string(codersdk.ExperimentCustomRoles),
226+
string(codersdk.ExperimentMultiOrganization),
227+
}
228+
229+
owner,user:=coderdenttest.New(t,&coderdenttest.Options{
230+
Options:&coderdtest.Options{
231+
DeploymentValues:dv,
232+
},
233+
LicenseOptions:&coderdenttest.LicenseOptions{
234+
Features: license.Features{
235+
codersdk.FeatureCustomRoles:1,
236+
codersdk.FeatureMultipleOrganizations:1,
237+
},
238+
},
239+
})
240+
241+
orgAdmin,_:=coderdtest.CreateAnotherUser(t,owner,user.OrganizationID,rbac.ScopedRoleOrgAdmin(user.OrganizationID))
242+
243+
// Test as org admin
244+
ctx:=testutil.Context(t,testutil.WaitShort)
245+
settings,err:=orgAdmin.PatchRoleIDPSyncSettings(ctx,user.OrganizationID.String(), codersdk.RoleSyncSettings{
246+
Field:"august",
247+
})
248+
require.NoError(t,err)
249+
require.Equal(t,"august",settings.Field)
250+
251+
fetchedSettings,err:=orgAdmin.RoleIDPSyncSettings(ctx,user.OrganizationID.String())
252+
require.NoError(t,err)
253+
require.Equal(t,"august",fetchedSettings.Field)
254+
})
255+
256+
t.Run("NotAuthorized",func(t*testing.T) {
257+
t.Parallel()
258+
259+
dv:=coderdtest.DeploymentValues(t)
260+
dv.Experiments= []string{
261+
string(codersdk.ExperimentCustomRoles),
262+
string(codersdk.ExperimentMultiOrganization),
263+
}
264+
265+
owner,user:=coderdenttest.New(t,&coderdenttest.Options{
266+
Options:&coderdtest.Options{
267+
DeploymentValues:dv,
268+
},
269+
LicenseOptions:&coderdenttest.LicenseOptions{
270+
Features: license.Features{
271+
codersdk.FeatureCustomRoles:1,
272+
codersdk.FeatureMultipleOrganizations:1,
273+
},
274+
},
275+
})
276+
277+
member,_:=coderdtest.CreateAnotherUser(t,owner,user.OrganizationID)
278+
279+
ctx:=testutil.Context(t,testutil.WaitShort)
280+
_,err:=member.PatchRoleIDPSyncSettings(ctx,user.OrganizationID.String(), codersdk.RoleSyncSettings{
281+
Field:"august",
282+
})
283+
varapiError*codersdk.Error
284+
require.ErrorAs(t,err,&apiError)
285+
require.Equal(t,http.StatusForbidden,apiError.StatusCode())
286+
287+
_,err=member.RoleIDPSyncSettings(ctx,user.OrganizationID.String())
288+
require.ErrorAs(t,err,&apiError)
289+
require.Equal(t,http.StatusForbidden,apiError.StatusCode())
290+
})
291+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp