@@ -25,6 +25,7 @@ const (
2525 errEmptyOIDCCallbackParams = Error ("empty OIDC callback params" )
2626 errNoOIDCIDToken = Error ("could not extract ID Token for OIDC callback" )
2727 errOIDCAllowedDomains = Error ("authenticated principal does not match any allowed domain" )
28+ errOIDCAllowedGroups = Error ("authenticated principal is not in any allowed group" )
2829 errOIDCAllowedUsers = Error ("authenticated principal does not match any allowed user" )
2930 errOIDCInvalidMachineState = Error ("requested machine state key expired before authorisation completed" )
3031 errOIDCNodeKeyMissing = Error ("could not get node key from cache" )
@@ -209,6 +210,10 @@ func (h *Headscale) OIDCCallback(
209210 return
210211 }
211212
213+ if err := validateOIDCAllowedGroups (writer , h .cfg .OIDC .AllowedGroups , claims ); err != nil {
214+ return
215+ }
216+
212217 if err := validateOIDCAllowedUsers (writer , h .cfg .OIDC .AllowedUsers , claims ); err != nil {
213218 return
214219 }
@@ -404,6 +409,39 @@ func validateOIDCAllowedDomains(
404409 return nil
405410}
406411
412+ // validateOIDCAllowedGroups checks if AllowedGroups is provided,
413+ // and that the user has one group in the list.
414+ // claims.Groups can be populated by adding a client scope named
415+ // 'groups' that contains group membership.
416+ func validateOIDCAllowedGroups (
417+ writer http.ResponseWriter ,
418+ allowedGroups []string ,
419+ claims * IDTokenClaims ,
420+ ) error {
421+ if len (allowedGroups ) > 0 {
422+ for _ , group := range allowedGroups {
423+ if IsStringInSlice (claims .Groups , group ) {
424+ return nil
425+ }
426+ }
427+
428+ log .Error ().Msg ("authenticated principal not in any allowed groups" )
429+ writer .Header ().Set ("Content-Type" , "text/plain; charset=utf-8" )
430+ writer .WriteHeader (http .StatusBadRequest )
431+ _ , err := writer .Write ([]byte ("unauthorized principal (allowed groups)" ))
432+ if err != nil {
433+ log .Error ().
434+ Caller ().
435+ Err (err ).
436+ Msg ("Failed to write response" )
437+ }
438+
439+ return errOIDCAllowedGroups
440+ }
441+
442+ return nil
443+ }
444+
407445// validateOIDCAllowedUsers checks that if AllowedUsers is provided,
408446// that the authenticated principal is part of that list.
409447func validateOIDCAllowedUsers (
0 commit comments