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

Commit2a1e2d0

Browse files
committed
chore: remove old role sync, insert new idpsync package
1 parent601652c commit2a1e2d0

File tree

13 files changed

+160
-195
lines changed

13 files changed

+160
-195
lines changed

‎cli/server.go‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,6 @@ func createOIDCConfig(ctx context.Context, logger slog.Logger, vals *codersdk.De
187187
EmailField:vals.OIDC.EmailField.String(),
188188
AuthURLParams:vals.OIDC.AuthURLParams.Value,
189189
IgnoreUserInfo:vals.OIDC.IgnoreUserInfo.Value(),
190-
UserRoleField:vals.OIDC.UserRoleField.String(),
191-
UserRoleMapping:vals.OIDC.UserRoleMapping.Value,
192-
UserRolesDefault:vals.OIDC.UserRolesDefault.GetSlice(),
193190
SignInText:vals.OIDC.SignInText.String(),
194191
SignupsDisabledText:vals.OIDC.SignupsDisabledText.String(),
195192
IconURL:vals.OIDC.IconURL.String(),

‎coderd/coderd.go‎

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@ type Options struct {
181181
NetworkTelemetryBatchFrequency time.Duration
182182
NetworkTelemetryBatchMaxSizeint
183183
SwaggerEndpointbool
184-
SetUserSiteRolesfunc(ctx context.Context,logger slog.Logger,tx database.Store,userID uuid.UUID,roles []string)error
185184
TemplateScheduleStore*atomic.Pointer[schedule.TemplateScheduleStore]
186185
UserQuietHoursScheduleStore*atomic.Pointer[schedule.UserQuietHoursScheduleStore]
187186
AccessControlStore*atomic.Pointer[dbauthz.AccessControlStore]
@@ -373,14 +372,6 @@ func New(options *Options) *API {
373372
ifoptions.TracerProvider==nil {
374373
options.TracerProvider=trace.NewNoopTracerProvider()
375374
}
376-
ifoptions.SetUserSiteRoles==nil {
377-
options.SetUserSiteRoles=func(ctx context.Context,logger slog.Logger,_ database.Store,userID uuid.UUID,roles []string)error {
378-
logger.Warn(ctx,"attempted to assign OIDC user roles without enterprise license",
379-
slog.F("user_id",userID),slog.F("roles",roles),
380-
)
381-
returnnil
382-
}
383-
}
384375
ifoptions.TemplateScheduleStore==nil {
385376
options.TemplateScheduleStore=&atomic.Pointer[schedule.TemplateScheduleStore]{}
386377
}

‎coderd/idpsync/idpsync.go‎

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,24 @@ type IDPSync interface {
4343
// accessed concurrently. The settings are stored in the database.
4444
GroupSyncSettings(ctx context.Context,orgID uuid.UUID,db database.Store) (*GroupSyncSettings,error)
4545
UpdateGroupSettings(ctx context.Context,orgID uuid.UUID,db database.Store,settingsGroupSyncSettings)error
46+
47+
// RoleSyncEntitled returns true if the deployment is entitled to role syncing.
48+
RoleSyncEntitled()bool
49+
// OrganizationRoleSyncEnabled returns true if the organization has role sync
50+
// enabled.
51+
OrganizationRoleSyncEnabled(ctx context.Context,db database.Store,org uuid.UUID) (bool,error)
52+
// SiteRoleSyncEnabled returns true if the deployment has role sync enabled
53+
// at the site level.
54+
SiteRoleSyncEnabled()bool
55+
// RoleSyncSettings is similar to GroupSyncSettings. See GroupSyncSettings for
56+
// rational.
57+
RoleSyncSettings() runtimeconfig.RuntimeEntry[*RoleSyncSettings]
58+
// ParseRoleClaims takes claims from an OIDC provider, and returns the params
59+
// for role syncing. Most of the logic happens in SyncRoles.
60+
ParseRoleClaims(ctx context.Context,mergedClaims jwt.MapClaims) (RoleParams,*HTTPError)
61+
// SyncRoles assigns and removes users from roles based on the provided params.
62+
// Site & org roles are handled in this method.
63+
SyncRoles(ctx context.Context,db database.Store,user database.User,paramsRoleParams)error
4664
}
4765

4866
// AGPLIDPSync is the configuration for syncing user information from an external
@@ -77,9 +95,16 @@ type DeploymentSyncSettings struct {
7795
// Legacy deployment settings that only apply to the default org.
7896
LegacyDefaultOrgLegacySettings
7997

80-
// SiteRoleField syncs a user's site wide roles from an IDP.
81-
SiteRoleFieldstring
82-
SiteRoleMappingmap[string][]string
98+
// SiteRoleField selects the claim field to be used as the created user's
99+
// roles. If the field is the empty string, then no site role updates
100+
// will ever come from the OIDC provider.
101+
SiteRoleFieldstring
102+
// SiteRoleMapping controls how groups returned by the OIDC provider get mapped
103+
// to site roles within Coder.
104+
// map[oidcRoleName][]coderRoleName
105+
SiteRoleMappingmap[string][]string
106+
// SiteDefaultRoles is the default set of site roles to assign to a user if role sync
107+
// is enabled.
83108
SiteDefaultRoles []string
84109
}
85110

@@ -99,6 +124,10 @@ func FromDeploymentValues(dv *codersdk.DeploymentValues) DeploymentSyncSettings
99124
OrganizationMapping:dv.OIDC.OrganizationMapping.Value,
100125
OrganizationAssignDefault:dv.OIDC.OrganizationAssignDefault.Value(),
101126

127+
SiteRoleField:dv.OIDC.UserRoleField.Value(),
128+
SiteRoleMapping:dv.OIDC.UserRoleMapping.Value,
129+
SiteDefaultRoles:dv.OIDC.UserRolesDefault.Value(),
130+
102131
// TODO: Separate group field for allow list from default org.
103132
// Right now you cannot disable group sync from the default org and
104133
// configure an allow list.

‎coderd/idpsync/role.go‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,42 @@ import (
1919
)
2020

2121
typeRoleParamsstruct {
22-
// SyncEnabled if false will skip syncing the user's roles
23-
SyncEnabledbool
22+
// SyncEntitled if false will skip syncing the user's roles at
23+
// all levels.
24+
SyncEntitledbool
2425
SyncSiteWidebool
2526
SiteWideRoles []string
2627
// MergedClaims are passed to the organization level for syncing
2728
MergedClaims jwt.MapClaims
2829
}
2930

30-
func (AGPLIDPSync)RoleSyncEnabled()bool {
31+
func (AGPLIDPSync)RoleSyncEntitled()bool {
3132
// AGPL does not support syncing groups.
3233
returnfalse
3334
}
35+
36+
func (AGPLIDPSync)OrganizationRoleSyncEnabled(_ context.Context,_ database.Store,_ uuid.UUID) (bool,error) {
37+
returnfalse,nil
38+
}
39+
40+
func (AGPLIDPSync)SiteRoleSyncEnabled()bool {
41+
returnfalse
42+
}
43+
3444
func (sAGPLIDPSync)RoleSyncSettings() runtimeconfig.RuntimeEntry[*RoleSyncSettings] {
3545
returns.Role
3646
}
3747

3848
func (sAGPLIDPSync)ParseRoleClaims(_ context.Context,_ jwt.MapClaims) (RoleParams,*HTTPError) {
3949
returnRoleParams{
40-
SyncEnabled:s.RoleSyncEnabled(),
41-
SyncSiteWide:false,
50+
SyncEntitled:s.RoleSyncEntitled(),
51+
SyncSiteWide:s.SiteRoleSyncEnabled(),
4252
},nil
4353
}
4454

4555
func (sAGPLIDPSync)SyncRoles(ctx context.Context,db database.Store,user database.User,paramsRoleParams)error {
4656
// Nothing happens if sync is not enabled
47-
if!params.SyncEnabled {
57+
if!params.SyncEntitled {
4858
returnnil
4959
}
5060

‎coderd/idpsync/role_test.go‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ func TestRoleSyncTable(t *testing.T) {
212212

213213
// Do the role sync!
214214
err:=s.SyncRoles(ctx,db,user, idpsync.RoleParams{
215-
SyncEnabled:true,
215+
SyncEntitled:true,
216216
SyncSiteWide:false,
217217
MergedClaims:userClaims,
218218
})
@@ -264,7 +264,7 @@ func TestRoleSyncTable(t *testing.T) {
264264
}
265265

266266
err:=s.SyncRoles(ctx,db,user, idpsync.RoleParams{
267-
SyncEnabled:true,
267+
SyncEntitled:true,
268268
SyncSiteWide:true,
269269
SiteWideRoles: []string{
270270
rbac.RoleTemplateAdmin().Name,// Duplicate this value to test deduplication
@@ -353,7 +353,7 @@ func TestNoopNoDiff(t *testing.T) {
353353
RBACRoles:siteRoles,
354354
LoginType:database.LoginTypePassword,
355355
}, idpsync.RoleParams{
356-
SyncEnabled:true,
356+
SyncEntitled:true,
357357
SyncSiteWide:true,
358358
SiteWideRoles:siteRoles,
359359
MergedClaims: jwt.MapClaims{

‎coderd/members.go‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/coder/coder/v2/coderd/audit"
1212
"github.com/coder/coder/v2/coderd/database"
1313
"github.com/coder/coder/v2/coderd/database/db2sdk"
14+
"github.com/coder/coder/v2/coderd/database/dbauthz"
1415
"github.com/coder/coder/v2/coderd/database/dbtime"
1516
"github.com/coder/coder/v2/coderd/httpapi"
1617
"github.com/coder/coder/v2/coderd/httpmw"
@@ -215,6 +216,33 @@ func (api *API) putMemberRoles(rw http.ResponseWriter, r *http.Request) {
215216
aReq.Old=member.OrganizationMember.Auditable(member.Username)
216217
defercommitAudit()
217218

219+
// Keep this block scoping to prevent accidental use of the user variable.
220+
{
221+
// nolint:gocritic // The caller could be an org admin without this perm.
222+
// We need to disable manual role assignment if role sync is enabled for
223+
// the given organization.
224+
user,err:=api.Database.GetUserByID(dbauthz.AsSystemRestricted(ctx),member.UserID)
225+
iferr!=nil {
226+
httpapi.InternalServerError(rw,err)
227+
return
228+
}
229+
ifuser.LoginType==database.LoginTypeOIDC {
230+
// nolint:gocritic // fetching settings
231+
orgSync,err:=api.IDPSync.OrganizationRoleSyncEnabled(dbauthz.AsSystemRestricted(ctx),api.Database,organization.ID)
232+
iferr!=nil {
233+
httpapi.InternalServerError(rw,err)
234+
return
235+
}
236+
iforgSync {
237+
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
238+
Message:"Cannot modify roles for OIDC users when role sync is enabled. This organization member's roles are managed by the identity provider.",
239+
Detail:"'User Role Field' is set in the organization settings. Ask an administrator to adjust or disable these settings.",
240+
})
241+
return
242+
}
243+
}
244+
}
245+
218246
ifapiKey.UserID==member.OrganizationMember.UserID {
219247
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
220248
Message:"You cannot change your own organization roles.",

‎coderd/userauth.go‎

Lines changed: 12 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -740,17 +740,6 @@ type OIDCConfig struct {
740740
// support the userinfo endpoint, or if the userinfo endpoint causes
741741
// undesirable behavior.
742742
IgnoreUserInfobool
743-
// UserRoleField selects the claim field to be used as the created user's
744-
// roles. If the field is the empty string, then no role updates
745-
// will ever come from the OIDC provider.
746-
UserRoleFieldstring
747-
// UserRoleMapping controls how groups returned by the OIDC provider get mapped
748-
// to roles within Coder.
749-
// map[oidcRoleName][]coderRoleName
750-
UserRoleMappingmap[string][]string
751-
// UserRolesDefault is the default set of roles to assign to a user if role sync
752-
// is enabled.
753-
UserRolesDefault []string
754743
// SignInText is the text to display on the OIDC login button
755744
SignInTextstring
756745
// IconURL points to the URL of an icon to display on the OIDC login button
@@ -759,10 +748,6 @@ type OIDCConfig struct {
759748
SignupsDisabledTextstring
760749
}
761750

762-
func (cfgOIDCConfig)RoleSyncEnabled()bool {
763-
returncfg.UserRoleField!=""
764-
}
765-
766751
// @Summary OpenID Connect Callback
767752
// @ID openid-connect-callback
768753
// @Security CoderSessionToken
@@ -983,12 +968,6 @@ func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) {
983968

984969
ctx=slog.With(ctx,slog.F("email",email),slog.F("username",username),slog.F("name",name))
985970

986-
roles,roleErr:=api.oidcRoles(ctx,mergedClaims)
987-
ifroleErr!=nil {
988-
roleErr.Write(rw,r)
989-
return
990-
}
991-
992971
user,link,err:=findLinkedUser(ctx,api.Database,oidcLinkedID(idToken),email)
993972
iferr!=nil {
994973
logger.Error(ctx,"oauth2: unable to find linked user",slog.F("email",email),slog.Error(err))
@@ -1011,6 +990,12 @@ func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) {
1011990
return
1012991
}
1013992

993+
roleSync,roleSyncErr:=api.IDPSync.ParseRoleClaims(ctx,mergedClaims)
994+
ifroleSyncErr!=nil {
995+
roleSyncErr.Write(rw,r)
996+
return
997+
}
998+
1014999
// If a new user is authenticating for the first time
10151000
// the audit action is 'register', not 'login'
10161001
ifuser.ID==uuid.Nil {
@@ -1028,10 +1013,9 @@ func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) {
10281013
Username:username,
10291014
Name:name,
10301015
AvatarURL:picture,
1031-
UsingRoles:api.OIDCConfig.RoleSyncEnabled(),
1032-
Roles:roles,
10331016
OrganizationSync:orgSync,
10341017
GroupSync:groupSync,
1018+
RoleSync:roleSync,
10351019
DebugContext:OauthDebugContext{
10361020
IDTokenClaims:idtokenClaims,
10371021
UserInfoClaims:userInfoClaims,
@@ -1067,61 +1051,6 @@ func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) {
10671051
http.Redirect(rw,r,redirect,http.StatusTemporaryRedirect)
10681052
}
10691053

1070-
// oidcRoles returns the roles for the user from the OIDC claims.
1071-
// If the function returns false, then the caller should return early.
1072-
// All writes to the response writer are handled by this function.
1073-
// It would be preferred to just return an error, however this function
1074-
// decorates returned errors with the appropriate HTTP status codes and details
1075-
// that are hard to carry in a standard `error` without more work.
1076-
func (api*API)oidcRoles(ctx context.Context,mergedClaimsmap[string]interface{}) ([]string,*idpsync.HTTPError) {
1077-
roles:=api.OIDCConfig.UserRolesDefault
1078-
if!api.OIDCConfig.RoleSyncEnabled() {
1079-
returnroles,nil
1080-
}
1081-
1082-
rolesRow,ok:=mergedClaims[api.OIDCConfig.UserRoleField]
1083-
if!ok {
1084-
// If no claim is provided than we can assume the user is just
1085-
// a member. This is because there is no way to tell the difference
1086-
// between []string{} and nil for OIDC claims. IDPs omit claims
1087-
// if they are empty ([]string{}).
1088-
// Use []interface{}{} so the next typecast works.
1089-
rolesRow= []interface{}{}
1090-
}
1091-
1092-
parsedRoles,err:=idpsync.ParseStringSliceClaim(rolesRow)
1093-
iferr!=nil {
1094-
api.Logger.Error(ctx,"oidc claims user roles field was an unknown type",
1095-
slog.F("type",fmt.Sprintf("%T",rolesRow)),
1096-
slog.Error(err),
1097-
)
1098-
returnnil,&idpsync.HTTPError{
1099-
Code:http.StatusInternalServerError,
1100-
Msg:"Login disabled until OIDC config is fixed",
1101-
Detail:fmt.Sprintf("Roles claim must be an array of strings, type found: %T. Disabling role sync will allow login to proceed.",rolesRow),
1102-
RenderStaticPage:false,
1103-
}
1104-
}
1105-
1106-
api.Logger.Debug(ctx,"roles returned in oidc claims",
1107-
slog.F("len",len(parsedRoles)),
1108-
slog.F("roles",parsedRoles),
1109-
)
1110-
for_,role:=rangeparsedRoles {
1111-
ifmappedRoles,ok:=api.OIDCConfig.UserRoleMapping[role];ok {
1112-
iflen(mappedRoles)==0 {
1113-
continue
1114-
}
1115-
// Mapped roles are added to the list of roles
1116-
roles=append(roles,mappedRoles...)
1117-
continue
1118-
}
1119-
1120-
roles=append(roles,role)
1121-
}
1122-
returnroles,nil
1123-
}
1124-
11251054
// claimFields returns the sorted list of fields in the claims map.
11261055
funcclaimFields(claimsmap[string]interface{}) []string {
11271056
fields:= []string{}
@@ -1182,10 +1111,7 @@ type oauthLoginParams struct {
11821111
// OrganizationSync has the organizations that the user will be assigned to.
11831112
OrganizationSync idpsync.OrganizationParams
11841113
GroupSync idpsync.GroupParams
1185-
// Is UsingRoles is true, then the user will be assigned
1186-
// the roles provided.
1187-
UsingRolesbool
1188-
Roles []string
1114+
RoleSync idpsync.RoleParams
11891115

11901116
DebugContextOauthDebugContext
11911117

@@ -1394,37 +1320,10 @@ func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.C
13941320
returnxerrors.Errorf("sync groups: %w",err)
13951321
}
13961322

1397-
// Ensure roles are correct.
1398-
ifparams.UsingRoles {
1399-
ignored:=make([]string,0)
1400-
filtered:=make([]string,0,len(params.Roles))
1401-
for_,role:=rangeparams.Roles {
1402-
// TODO: This only supports mapping deployment wide roles. Organization scoped roles
1403-
// are unsupported.
1404-
if_,err:=rbac.RoleByName(rbac.RoleIdentifier{Name:role});err==nil {
1405-
filtered=append(filtered,role)
1406-
}else {
1407-
ignored=append(ignored,role)
1408-
}
1409-
}
1410-
1411-
//nolint:gocritic
1412-
err:=api.Options.SetUserSiteRoles(dbauthz.AsSystemRestricted(ctx),logger,tx,user.ID,filtered)
1413-
iferr!=nil {
1414-
return&idpsync.HTTPError{
1415-
Code:http.StatusBadRequest,
1416-
Msg:"Invalid roles through OIDC claims",
1417-
Detail:fmt.Sprintf("Error from role assignment attempt: %s",err.Error()),
1418-
RenderStaticPage:true,
1419-
}
1420-
}
1421-
iflen(ignored)>0 {
1422-
logger.Debug(ctx,"OIDC roles ignored in assignment",
1423-
slog.F("ignored",ignored),
1424-
slog.F("assigned",filtered),
1425-
slog.F("user_id",user.ID),
1426-
)
1427-
}
1323+
// Role sync needs to occur after org sync.
1324+
err=api.IDPSync.SyncRoles(ctx,tx,user,params.RoleSync)
1325+
iferr!=nil {
1326+
returnxerrors.Errorf("sync roles: %w",err)
14281327
}
14291328

14301329
needsUpdate:=false

‎coderd/users.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1162,7 +1162,7 @@ func (api *API) putUserRoles(rw http.ResponseWriter, r *http.Request) {
11621162
defercommitAudit()
11631163
aReq.Old=user
11641164

1165-
ifuser.LoginType==database.LoginTypeOIDC&&api.OIDCConfig.RoleSyncEnabled() {
1165+
ifuser.LoginType==database.LoginTypeOIDC&&api.IDPSync.SiteRoleSyncEnabled() {
11661166
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
11671167
Message:"Cannot modify roles for OIDC users when role sync is enabled.",
11681168
Detail:"'User Role Field' is set in the OIDC configuration. All role changes must come from the oidc identity provider.",

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp