@@ -20,7 +20,7 @@ func (r *schemaResolver) SettingsSubject(ctx context.Context, args *struct{ ID g
2020 return nil , err
2121 }
2222
23- return settingsSubjectForNode (ctx , n )
23+ return settingsSubjectForNodeAndCheckAccess (ctx , n )
2424}
2525
2626var errUnknownSettingsSubject = errors .New ("unknown settings subject" )
@@ -31,29 +31,46 @@ type settingsSubjectResolver struct {
3131 site * siteResolver
3232 org * OrgResolver
3333 user * UserResolver
34+
35+ // 🚨 SECURITY: Only the settingsSubjectForNodeAndCheckAccess function can set this. It is used
36+ // to ensure that access checks have been run on this value, so that we don't leak settings to
37+ // an unauthorized viewer by an accidental bypass of access checks. This struct type is
38+ // naturally constructed all over the place (because many types of nodes have settings), and it
39+ // was too easy to bypass the access check accidentally.
40+ checkedAccess_DO_NOT_SET_THIS_MANUALLY_OR_YOU_WILL_LEAK_SECRETS bool
41+ }
42+
43+ func (r * settingsSubjectResolver ) assertCheckedAccess () {
44+ if ! r .checkedAccess_DO_NOT_SET_THIS_MANUALLY_OR_YOU_WILL_LEAK_SECRETS {
45+ panic ("settingsSubjectResolver.assertCheckedAccess: access checks have not been run on this value" )
46+ }
3447}
3548
3649func resolverForSubject (ctx context.Context , logger log.Logger , db database.DB , subject api.SettingsSubject ) (* settingsSubjectResolver , error ) {
37- switch {
38- case subject .Default :
50+ if subject .Default {
3951 return & settingsSubjectResolver {defaultSettings : newDefaultSettingsResolver (db )}, nil
52+ }
53+
54+ var (
55+ node Node
56+ err error
57+ )
58+ switch {
4059 case subject .Site :
41- return & settingsSubjectResolver { site : NewSiteResolver (logger , db )}, nil
60+ node = NewSiteResolver (logger , db )
4261 case subject .Org != nil :
43- org , err := OrgByIDInt32 (ctx , db , * subject .Org )
44- if err != nil {
45- return nil , err
46- }
47- return & settingsSubjectResolver {org : org }, nil
62+ node , err = OrgByIDInt32 (ctx , db , * subject .Org )
4863 case subject .User != nil :
49- user , err := UserByIDInt32 (ctx , db , * subject .User )
50- if err != nil {
51- return nil , err
52- }
53- return & settingsSubjectResolver {user : user }, nil
64+ node , err = UserByIDInt32 (ctx , db , * subject .User )
5465 default :
55- return nil , errors .New ("subject must have exactly one field set" )
66+ panic ("subject must have exactly one field set" )
67+ }
68+ if err != nil {
69+ return nil , err
5670 }
71+
72+ // 🚨 SECURITY: Call settingsSubjectForNode to reuse the security checks implemented there.
73+ return settingsSubjectForNodeAndCheckAccess (ctx , node )
5774}
5875
5976func resolversForSubjects (ctx context.Context , logger log.Logger , db database.DB , subjects []api.SettingsSubject ) (_ []* settingsSubjectResolver , err error ) {
@@ -67,12 +84,22 @@ func resolversForSubjects(ctx context.Context, logger log.Logger, db database.DB
6784 return res , nil
6885}
6986
70- // settingsSubjectForNode fetches the settings subject for the given Node. If
71- // the node is not a valid settings subject, an error is returned.
72- func settingsSubjectForNode (ctx context.Context , n Node ) (* settingsSubjectResolver , error ) {
87+ // settingsSubjectForNodeAndCheckAccess fetches the settings subject for the given Node. If the node
88+ // is not a valid settings subject, an error is returned.
89+ //
90+ // 🚨 SECURITY: This function also ensures that the actor is permitted to view the node's settings.
91+ // It is the ONLY place that the
92+ // (settingsSubjectResolver).checkedAccess_DO_NOT_SET_THIS_MANUALLY_OR_YOU_WILL_LEAK_SECRETS field
93+ // can be set.
94+ func settingsSubjectForNodeAndCheckAccess (ctx context.Context , n Node ) (* settingsSubjectResolver , error ) {
95+ var subject settingsSubjectResolver
96+
7397 switch s := n .(type ) {
98+ case * defaultSettingsResolver :
99+ subject .defaultSettings = s
100+
74101 case * siteResolver :
75- return & settingsSubjectResolver { site : s }, nil
102+ subject . site = s
76103
77104 case * UserResolver :
78105 // 🚨 SECURITY: Only the authenticated user can view their settings on
@@ -82,23 +109,35 @@ func settingsSubjectForNode(ctx context.Context, n Node) (*settingsSubjectResolv
82109 return nil , err
83110 }
84111 } else {
85- // 🚨 SECURITY: Only the user and site admins are allowed to view the user's settings.
112+ // 🚨 SECURITY: The user and site admins are allowed to view the user's settings otherwise .
86113 if err := auth .CheckSiteAdminOrSameUser (ctx , s .db , s .user .ID ); err != nil {
87114 return nil , err
88115 }
89116 }
90- return & settingsSubjectResolver { user : s }, nil
117+ subject . user = s
91118
92119 case * OrgResolver :
93- // 🚨 SECURITY: Check that the current user is a member of the org.
94- if err := auth .CheckOrgAccessOrSiteAdmin (ctx , s .db , s .org .ID ); err != nil {
95- return nil , err
120+ if dotcom .SourcegraphDotComMode () {
121+ // 🚨 SECURITY: Only org members (not any site admin) can view org settings on Sourcegraph.com.
122+ if err := auth .CheckOrgAccess (ctx , s .db , s .org .ID ); err != nil {
123+ return nil , err
124+ }
125+ } else {
126+ // 🚨 SECURITY: Org members or site admins can view the org settings otherwise.
127+ if err := auth .CheckOrgAccessOrSiteAdmin (ctx , s .db , s .org .ID ); err != nil {
128+ return nil , err
129+ }
96130 }
97- return & settingsSubjectResolver { org : s }, nil
131+ subject . org = s
98132
99133 default :
100134 return nil , errUnknownSettingsSubject
101135 }
136+
137+ // 🚨 SECURITY: This is the ONLY place that this field can be set.
138+ subject .checkedAccess_DO_NOT_SET_THIS_MANUALLY_OR_YOU_WILL_LEAK_SECRETS = true
139+
140+ return & subject , nil
102141}
103142
104143func (s * settingsSubjectResolver ) ToDefaultSettings () (* defaultSettingsResolver , bool ) {
@@ -115,6 +154,8 @@ func (s *settingsSubjectResolver) ToUser() (*UserResolver, bool) { return s.user
115154
116155func (s * settingsSubjectResolver ) toSubject () api.SettingsSubject {
117156 switch {
157+ case s .defaultSettings != nil :
158+ return api.SettingsSubject {Default : true }
118159 case s .site != nil :
119160 return api.SettingsSubject {Site : true }
120161 case s .org != nil :
@@ -186,21 +227,21 @@ func (s *settingsSubjectResolver) ViewerCanAdminister(ctx context.Context) (bool
186227 }
187228}
188229
189- func (s * settingsSubjectResolver ) SettingsCascade () (* settingsCascade , error ) {
230+ func (s * settingsSubjectResolver ) SettingsCascade (ctx context. Context ) (* settingsCascade , error ) {
190231 switch {
191232 case s .defaultSettings != nil :
192- return s .defaultSettings .SettingsCascade (), nil
233+ return s .defaultSettings .SettingsCascade (ctx )
193234 case s .site != nil :
194- return s .site .SettingsCascade (), nil
235+ return s .site .SettingsCascade (ctx )
195236 case s .org != nil :
196- return s .org .SettingsCascade (), nil
237+ return s .org .SettingsCascade (ctx )
197238 case s .user != nil :
198- return s .user .SettingsCascade (), nil
239+ return s .user .SettingsCascade (ctx )
199240 default :
200241 return nil , errUnknownSettingsSubject
201242 }
202243}
203244
204- func (s * settingsSubjectResolver ) ConfigurationCascade () (* settingsCascade , error ) {
205- return s .SettingsCascade ()
245+ func (s * settingsSubjectResolver ) ConfigurationCascade (ctx context. Context ) (* settingsCascade , error ) {
246+ return s .SettingsCascade (ctx )
206247}
0 commit comments