Skip to content

Commit 93c4cd8

Browse files
authored
Merge pull request #2 from panorama-ed/fixes-from-pulls-45-and-47
Fixes from pull awslabs#45 and awslabs#47
2 parents 30534b7 + 105df98 commit 93c4cd8

File tree

5 files changed

+60
-26
lines changed

5 files changed

+60
-26
lines changed

README.md

+9-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
> Helping you populate AWS SSO directly with your Google Apps users
1010
11-
SSO Sync will run on any platform that Go can build for. It is available in the [AWS Serverless Application Repository](https://console.aws.amazon.com/lambda/home#/create/app?applicationId=arn:aws:serverlessrepo:us-east-2:004480582608:applications/SSOSync)
11+
SSO Sync will run on any platform that Go can build for. It is available in the [AWS Serverless Application Repository](https://console.aws.amazon.com/lambda/home#/create/app?applicationId=arn:aws:serverlessrepo:eu-west-1:084703771460:applications/ssosync).
1212

1313
> :warning: there are breaking changes for versions `>= 0.02`
1414
@@ -133,8 +133,12 @@ Flags:
133133

134134
The function has `two behaviour` and these are controlled by the `--sync-method` flag, this behavior could be
135135

136-
1. `groups`: __(default)__ The sync procedure work base on Groups, gets the Google Workspace groups and their members, then creates in AWS SSO the users (members of the Google Workspace groups), then the groups and at the end assign the users to their respective groups.
137-
2. `users_groups`: __(original behavior, previous versions)__ The sync procedure is simple, gets the Google Workspace users and creates these in AWS SSO Users; then gets Google Workspace groups and creates these in AWS SSO Groups and assigns users to belong to the AWS SSO Groups.
136+
1. `groups`: __(default)__
137+
* The sync procedure work base on Groups, gets the Google Workspace groups and their members, then creates in AWS SSO the users (members of the Google Workspace groups), then the groups and at the end assign the users to their respective groups.
138+
* This method use: `Google Workspace groups name` --> `AWS SSO groups name`
139+
2. `users_groups`: __(original behavior, previous versions)__
140+
* The sync procedure is simple, gets the Google Workspace users and creates these in AWS SSO Users; then gets Google Workspace groups and creates these in AWS SSO Groups and assigns users to belong to the AWS SSO Groups.
141+
* This method use: `Google Workspace groups email` --> `AWS SSO groups name`
138142

139143
Flags Notes:
140144

@@ -148,6 +152,7 @@ NOTES:
148152

149153
1. Depending on the number of users and groups you have, maybe you can get `AWS SSO SCIM API rate limits errors`, and more frequently happens if you execute the sync many times in a short time.
150154
2. Depending on the number of users and groups you have, `--debug` flag generate too much logs lines in your AWS Lambda function. So test it in locally with the `--debug` flag enabled and disable it when you use a AWS Lambda function.
155+
3. `--sync-method "Groups"` and `--sync-method "users_groups"` are incompatible, because the first use the Google group name as an AWS group name and the second one use the Google group email, take this into consideration.
151156

152157
## AWS Lambda Usage
153158

@@ -157,7 +162,7 @@ the pricing for AWS Lambda and CloudWatch before continuing.
157162
Running ssosync once means that any changes to your Google directory will not appear in
158163
AWS SSO. To sync. regularly, you can run ssosync via AWS Lambda.
159164

160-
:warning: You find it in the [AWS Serverless Application Repository](https://eu-west-1.console.aws.amazon.com/lambda/home#/create/app?applicationId=arn:aws:serverlessrepo:us-east-2:004480582608:applications/SSOSync).
165+
:warning: You find it in the [AWS Serverless Application Repository](https://console.aws.amazon.com/lambda/home#/create/app?applicationId=arn:aws:serverlessrepo:eu-west-1:084703771460:applications/ssosync).
161166

162167
## SAM
163168

internal/aws/client.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ func (c *client) IsUserInGroup(u *User, g *Group) (bool, error) {
180180
startURL.RawQuery = q.Encode()
181181
resp, err := c.sendRequest(http.MethodGet, startURL.String())
182182
if err != nil {
183+
log.WithFields(log.Fields{"user": u.Username, "group": g.DisplayName}).Error(string(resp))
183184
return false, err
184185
}
185186

@@ -222,10 +223,13 @@ func (c *client) groupChangeOperation(op OperationType, u *User, g *Group) error
222223
}
223224

224225
startURL.Path = path.Join(startURL.Path, fmt.Sprintf("/Groups/%s", g.ID))
225-
_, err = c.sendRequestWithBody(http.MethodPatch, startURL.String(), *gc)
226+
227+
resp, err := c.sendRequestWithBody(http.MethodPatch, startURL.String(), *gc)
226228
if err != nil {
229+
log.WithFields(log.Fields{"operations": op, "user": u.Username, "group": g.DisplayName}).Error(string(resp))
227230
return err
228231
}
232+
log.WithFields(log.Fields{"operations": op, "user": u.Username, "group": g.DisplayName}).Debug(string(resp))
229233

230234
return nil
231235
}
@@ -257,6 +261,7 @@ func (c *client) FindUserByEmail(email string) (*User, error) {
257261

258262
resp, err := c.sendRequest(http.MethodGet, startURL.String())
259263
if err != nil {
264+
log.WithFields(log.Fields{"email": email}).Error(string(resp))
260265
return nil, err
261266
}
262267

@@ -284,6 +289,7 @@ func (c *client) FindUserByID(id string) (*User, error) {
284289

285290
resp, err := c.sendRequest(http.MethodGet, startURL.String())
286291
if err != nil {
292+
log.WithFields(log.Fields{"id": id}).Error(string(resp))
287293
return nil, err
288294
}
289295

@@ -317,6 +323,7 @@ func (c *client) FindGroupByDisplayName(name string) (*Group, error) {
317323

318324
resp, err := c.sendRequest(http.MethodGet, startURL.String())
319325
if err != nil {
326+
log.WithFields(log.Fields{"name": name}).Error(string(resp))
320327
return nil, err
321328
}
322329

@@ -348,6 +355,7 @@ func (c *client) CreateUser(u *User) (*User, error) {
348355
startURL.Path = path.Join(startURL.Path, "/Users")
349356
resp, err := c.sendRequestWithBody(http.MethodPost, startURL.String(), *u)
350357
if err != nil {
358+
log.WithFields(log.Fields{"user": u.Username}).Error(string(resp))
351359
return nil, err
352360
}
353361

@@ -378,6 +386,7 @@ func (c *client) UpdateUser(u *User) (*User, error) {
378386
startURL.Path = path.Join(startURL.Path, fmt.Sprintf("/Users/%s", u.ID))
379387
resp, err := c.sendRequestWithBody(http.MethodPut, startURL.String(), *u)
380388
if err != nil {
389+
log.WithFields(log.Fields{"user": u.Username}).Error(string(resp))
381390
return nil, err
382391
}
383392

@@ -405,11 +414,14 @@ func (c *client) DeleteUser(u *User) error {
405414
}
406415

407416
startURL.Path = path.Join(startURL.Path, fmt.Sprintf("/Users/%s", u.ID))
408-
_, err = c.sendRequest(http.MethodDelete, startURL.String())
417+
resp, err := c.sendRequest(http.MethodDelete, startURL.String())
409418
if err != nil {
419+
log.WithFields(log.Fields{"user": u.Username}).Error(string(resp))
410420
return err
411421
}
412422

423+
log.WithFields(log.Fields{"user": u.Username}).Debug(string(resp))
424+
413425
return nil
414426
}
415427

@@ -428,6 +440,7 @@ func (c *client) CreateGroup(g *Group) (*Group, error) {
428440
startURL.Path = path.Join(startURL.Path, "/Groups")
429441
resp, err := c.sendRequestWithBody(http.MethodPost, startURL.String(), *g)
430442
if err != nil {
443+
log.WithFields(log.Fields{"group": g.DisplayName}).Error(string(resp))
431444
return nil, err
432445
}
433446

@@ -471,6 +484,7 @@ func (c *client) GetGroups() ([]*Group, error) {
471484

472485
resp, err := c.sendRequest(http.MethodGet, startURL.String())
473486
if err != nil {
487+
log.Error(string(resp))
474488
return nil, err
475489
}
476490

@@ -513,6 +527,7 @@ func (c *client) GetGroupMembers(g *Group) ([]*User, error) {
513527

514528
resp, err := c.sendRequest(http.MethodGet, startURL.String())
515529
if err != nil {
530+
log.WithFields(log.Fields{"group": g.DisplayName}).Error(string(resp))
516531
return nil, err
517532
}
518533

@@ -548,6 +563,7 @@ func (c *client) GetUsers() ([]*User, error) {
548563

549564
resp, err := c.sendRequest(http.MethodGet, startURL.String())
550565
if err != nil {
566+
log.Error(string(resp))
551567
return nil, err
552568
}
553569

internal/google/client.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func (c *client) GetDeletedUsers() ([]*admin.User, error) {
7575
// GetGroupMembers will get the members of the group specified
7676
func (c *client) GetGroupMembers(g *admin.Group) ([]*admin.Member, error) {
7777
m := make([]*admin.Member, 0)
78-
err := c.service.Members.List(g.Id).Pages(context.TODO(), func(members *admin.Members) error {
78+
err := c.service.Members.List(g.Id).Pages(c.ctx, func(members *admin.Members) error {
7979
m = append(m, members.Members...)
8080
return nil
8181
})
@@ -134,12 +134,12 @@ func (c *client) GetGroups(query string) ([]*admin.Group, error) {
134134
var err error
135135

136136
if query != "" {
137-
err = c.service.Groups.List().Customer("my_customer").Query(query).Pages(context.TODO(), func(groups *admin.Groups) error {
137+
err = c.service.Groups.List().Customer("my_customer").Query(query).Pages(c.ctx, func(groups *admin.Groups) error {
138138
g = append(g, groups.Groups...)
139139
return nil
140140
})
141141
} else {
142-
err = c.service.Groups.List().Customer("my_customer").Pages(context.TODO(), func(groups *admin.Groups) error {
142+
err = c.service.Groups.List().Customer("my_customer").Pages(c.ctx, func(groups *admin.Groups) error {
143143
g = append(g, groups.Groups...)
144144
return nil
145145
})

internal/sync.go

+29-16
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,17 @@ func (s *syncGSuite) SyncGroupsUsers(query string) error {
277277
if err != nil {
278278
return err
279279
}
280+
281+
// Filter groups
280282
filteredGoogleGroups := []*admin.Group{}
281283
for _, g := range googleGroups {
284+
285+
// bacaudse is in flag --ignore-groups
282286
if s.ignoreGroup(g.Email) {
283-
log.WithField("group", g.Email).Debug("ignoring group")
287+
log.WithField("group", g.Email).Warn("ignoring group, using --ignore-groups")
284288
continue
285289
}
290+
286291
filteredGoogleGroups = append(filteredGoogleGroups, g)
287292
}
288293
googleGroups = filteredGoogleGroups
@@ -359,14 +364,18 @@ func (s *syncGSuite) SyncGroupsUsers(query string) error {
359364
// add aws users (added in google)
360365
log.Debug("creating aws users added in google")
361366
for _, awsUser := range addAWSUsers {
362-
363-
log := log.WithFields(log.Fields{"user": awsUser.Username})
364-
365-
log.Info("creating user")
366-
_, err := s.aws.CreateUser(awsUser)
367-
if err != nil {
368-
log.Error("error creating user")
369-
return err
367+
// Due to limits in users listing, the user may already exists
368+
// see https://docs.aws.amazon.com/singlesignon/latest/developerguide/listusers.html
369+
user, _ := s.aws.FindUserByEmail(awsUser.Username)
370+
if user == nil {
371+
log := log.WithFields(log.Fields{"user": awsUser.Username})
372+
373+
log.Info("creating user")
374+
_, err := s.aws.CreateUser(awsUser)
375+
if err != nil {
376+
log.Error("error creating user")
377+
return err
378+
}
370379
}
371380
}
372381

@@ -377,7 +386,7 @@ func (s *syncGSuite) SyncGroupsUsers(query string) error {
377386
log := log.WithFields(log.Fields{"group": awsGroup.DisplayName})
378387

379388
log.Info("creating group")
380-
_, err := s.aws.CreateGroup(awsGroup)
389+
awsGroupFull, err := s.aws.CreateGroup(awsGroup)
381390
if err != nil {
382391
log.Error("creating group")
383392
return err
@@ -394,7 +403,7 @@ func (s *syncGSuite) SyncGroupsUsers(query string) error {
394403
}
395404

396405
log.WithField("user", awsUserFull.Username).Info("adding user to group")
397-
err = s.aws.AddUserToGroup(awsUserFull, awsGroup)
406+
err = s.aws.AddUserToGroup(awsUserFull, awsGroupFull)
398407
if err != nil {
399408
return err
400409
}
@@ -508,12 +517,16 @@ func (s *syncGSuite) getGoogleGroupsAndUsers(googleGroups []*admin.Group) ([]*ad
508517
return nil, nil, err
509518
}
510519

511-
membersUsers = append(membersUsers, u[0])
512-
513-
_, ok := gUniqUsers[m.Email]
514-
if !ok {
515-
gUniqUsers[m.Email] = u[0]
520+
if len(u) != 0 {
521+
membersUsers = append(membersUsers, u[0])
522+
_, ok := gUniqUsers[m.Email]
523+
if !ok {
524+
gUniqUsers[m.Email] = u[0]
525+
}
526+
} else {
527+
log.WithField("member", m.Email).Warn("ignoring group member because it is not a user, looks like a group inside the group")
516528
}
529+
517530
}
518531
gGroupsUsers[g.Name] = membersUsers
519532
}

internal/sync_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ package internal
1717

1818
import (
1919
"encoding/json"
20-
"log"
2120
"reflect"
2221
"testing"
2322

2423
"github.com/awslabs/ssosync/internal/aws"
24+
log "github.com/sirupsen/logrus"
2525
admin "google.golang.org/api/admin/directory/v1"
2626
)
2727

0 commit comments

Comments
 (0)