Skip to content

Commit 4aa7e68

Browse files
authored
Merge pull request #2268 from snuggie12/mh-2111-nested-groups
Resolves #2111 Option to fetch transitive group membership
2 parents a15cd87 + ee5b5b2 commit 4aa7e68

File tree

1 file changed

+48
-20
lines changed

1 file changed

+48
-20
lines changed

connector/google/google.go

+48-20
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ type Config struct {
4949
// The email of a GSuite super user which the service account will impersonate
5050
// when listing groups
5151
AdminEmail string
52+
53+
// If this field is true, fetch direct group membership and transitive group membership
54+
FetchTransitiveGroupMembership bool `json:"fetchTransitiveGroupMembership"`
5255
}
5356

5457
// Open returns a connector which can be used to login users through Google.
@@ -87,13 +90,14 @@ func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, e
8790
verifier: provider.Verifier(
8891
&oidc.Config{ClientID: clientID},
8992
),
90-
logger: logger,
91-
cancel: cancel,
92-
hostedDomains: c.HostedDomains,
93-
groups: c.Groups,
94-
serviceAccountFilePath: c.ServiceAccountFilePath,
95-
adminEmail: c.AdminEmail,
96-
adminSrv: srv,
93+
logger: logger,
94+
cancel: cancel,
95+
hostedDomains: c.HostedDomains,
96+
groups: c.Groups,
97+
serviceAccountFilePath: c.ServiceAccountFilePath,
98+
adminEmail: c.AdminEmail,
99+
fetchTransitiveGroupMembership: c.FetchTransitiveGroupMembership,
100+
adminSrv: srv,
97101
}, nil
98102
}
99103

@@ -103,16 +107,17 @@ var (
103107
)
104108

105109
type googleConnector struct {
106-
redirectURI string
107-
oauth2Config *oauth2.Config
108-
verifier *oidc.IDTokenVerifier
109-
cancel context.CancelFunc
110-
logger log.Logger
111-
hostedDomains []string
112-
groups []string
113-
serviceAccountFilePath string
114-
adminEmail string
115-
adminSrv *admin.Service
110+
redirectURI string
111+
oauth2Config *oauth2.Config
112+
verifier *oidc.IDTokenVerifier
113+
cancel context.CancelFunc
114+
logger log.Logger
115+
hostedDomains []string
116+
groups []string
117+
serviceAccountFilePath string
118+
adminEmail string
119+
fetchTransitiveGroupMembership bool
120+
adminSrv *admin.Service
116121
}
117122

118123
func (c *googleConnector) Close() error {
@@ -214,7 +219,7 @@ func (c *googleConnector) createIdentity(ctx context.Context, identity connector
214219

215220
var groups []string
216221
if s.Groups && c.adminSrv != nil {
217-
groups, err = c.getGroups(claims.Email)
222+
groups, err = c.getGroups(claims.Email, c.fetchTransitiveGroupMembership)
218223
if err != nil {
219224
return identity, fmt.Errorf("google: could not retrieve groups: %v", err)
220225
}
@@ -240,7 +245,7 @@ func (c *googleConnector) createIdentity(ctx context.Context, identity connector
240245

241246
// getGroups creates a connection to the admin directory service and lists
242247
// all groups the user is a member of
243-
func (c *googleConnector) getGroups(email string) ([]string, error) {
248+
func (c *googleConnector) getGroups(email string, fetchTransitiveGroupMembership bool) ([]string, error) {
244249
var userGroups []string
245250
var err error
246251
groupsList := &admin.Groups{}
@@ -254,14 +259,24 @@ func (c *googleConnector) getGroups(email string) ([]string, error) {
254259
for _, group := range groupsList.Groups {
255260
// TODO (joelspeed): Make desired group key configurable
256261
userGroups = append(userGroups, group.Email)
262+
263+
// getGroups takes a user's email/alias as well as a group's email/alias
264+
if fetchTransitiveGroupMembership {
265+
transitiveGroups, err := c.getGroups(group.Email, fetchTransitiveGroupMembership)
266+
if err != nil {
267+
return nil, fmt.Errorf("could not list transitive groups: %v", err)
268+
}
269+
270+
userGroups = append(userGroups, transitiveGroups...)
271+
}
257272
}
258273

259274
if groupsList.NextPageToken == "" {
260275
break
261276
}
262277
}
263278

264-
return userGroups, nil
279+
return uniqueGroups(userGroups), nil
265280
}
266281

267282
// createDirectoryService loads a google service account credentials file,
@@ -296,3 +311,16 @@ func createDirectoryService(serviceAccountFilePath string, email string) (*admin
296311
}
297312
return srv, nil
298313
}
314+
315+
// uniqueGroups returns the unique groups of a slice
316+
func uniqueGroups(groups []string) []string {
317+
keys := make(map[string]struct{})
318+
unique := []string{}
319+
for _, group := range groups {
320+
if _, exists := keys[group]; !exists {
321+
keys[group] = struct{}{}
322+
unique = append(unique, group)
323+
}
324+
}
325+
return unique
326+
}

0 commit comments

Comments
 (0)