diff --git a/go.mod b/go.mod index bca685c7..fb20897f 100644 --- a/go.mod +++ b/go.mod @@ -13,15 +13,11 @@ require ( github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.4.0 github.com/stretchr/testify v1.5.1 - go.uber.org/zap v1.15.0 - golang.org/x/mod v0.3.0 // indirect golang.org/x/net v0.0.0-20200505041828-1ed23360d12c // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect - golang.org/x/tools v0.0.0-20200519205726-57a9e4404bf7 // indirect google.golang.org/api v0.24.0 google.golang.org/appengine v1.6.6 // indirect google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84 // indirect google.golang.org/grpc v1.29.1 // indirect - honnef.co/go/tools v0.0.1-2020.1.4 // indirect ) diff --git a/go.sum b/go.sum index 9a708f85..9c2c0f34 100644 --- a/go.sum +++ b/go.sum @@ -154,8 +154,6 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -194,7 +192,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -204,7 +201,6 @@ github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -213,16 +209,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -260,8 +248,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -348,8 +334,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -366,8 +350,6 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 h1:kDtqNkeBrZb8B+atrj50B5XLHpzXXqcCdZPP/ApQ5NY= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200519205726-57a9e4404bf7 h1:nm4zDh9WvH4jiuUpMY5RUsvOwrtTVVAsUaCdLW71hfY= -golang.org/x/tools v0.0.0-20200519205726-57a9e4404bf7/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -451,8 +433,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/aws/client.go b/internal/aws/client.go index c2958360..62ec8652 100644 --- a/internal/aws/client.go +++ b/internal/aws/client.go @@ -23,7 +23,6 @@ import ( "net/http" "net/url" "path" - "strconv" log "github.com/sirupsen/logrus" ) @@ -42,7 +41,7 @@ const ( // IClient represents an interface of methods used // to communicate with AWS SSO type Client interface { - GetGroups() (*map[string]Group, error) + FindGroupByDisplayName(string) (*Group, error) IsUserInGroup(*User, *Group) (bool, error) FindUserByEmail(string) (*User, error) CreateUser(*User) (*User, error) @@ -144,69 +143,6 @@ func (c *client) sendRequest(method string, url string) (response []byte, err er return } -func (c *client) getGroupPage(sURL *url.URL, startIndex int) (results *GroupFilterResults, err error) { - startURL, err := url.Parse(sURL.String()) - if err != nil { - return - } - - q := startURL.Query() - q.Add("count", "10") - q.Add("startIndex", strconv.Itoa(startIndex)) - startURL.RawQuery = q.Encode() - - resp, err := c.sendRequest(http.MethodGet, startURL.String()) - if err != nil { - return - } - - var r GroupFilterResults - err = json.Unmarshal(resp, &r) - if err != nil { - return - } - - results = &r - - return -} - -// GetGroups will retrieve a map of Groups from AWS SSO. The map -// is keyed by the Display Name of the group. -func (c *client) GetGroups() (results *map[string]Group, err error) { - startURL, err := url.Parse(c.endpointURL.String()) - if err != nil { - return - } - - startURL.Path = path.Join(startURL.Path, "/Groups") - - var resultGroup = make(map[string]Group) - - si := 1 - for { - log.WithFields(log.Fields{"startIndex": si}).Debug("Getting Groups Page") - - r, err := c.getGroupPage(startURL, si) - if err != nil { - return nil, err - } - - for _, group := range r.Resources { - log.WithFields(log.Fields{"group": group.DisplayName}).Debug("Add group to map") - resultGroup[group.DisplayName] = group - } - - si = si + 10 - if si > r.TotalResults { - log.WithFields(log.Fields{"totalResults": r.TotalResults}).Debug("Last Page obtained") - break - } - } - - return &resultGroup, nil -} - // IsUserInGroup will determine if user (u) is in group (g) func (c *client) IsUserInGroup(u *User, g *Group) (present bool, err error) { if g == nil { @@ -327,6 +263,40 @@ func (c *client) FindUserByEmail(email string) (*User, error) { return &r.Resources[0], nil } +// FindGroupByDisplayName will find the group by its displayname. +func (c *client) FindGroupByDisplayName(name string) (*Group, error) { + startURL, err := url.Parse(c.endpointURL.String()) + if err != nil { + return nil, err + } + + filter := fmt.Sprintf("displayName eq \"%s\"", name) + + startURL.Path = path.Join(startURL.Path, "/Groups") + q := startURL.Query() + q.Add("filter", filter) + + startURL.RawQuery = q.Encode() + + resp, err := c.sendRequest(http.MethodGet, startURL.String()) + if err != nil { + return nil, err + } + + var r GroupFilterResults + err = json.Unmarshal(resp, &r) + if err != nil { + return nil, err + } + + if r.TotalResults != 1 { + err = fmt.Errorf("%s not found in AWS SSO", name) + return nil, err + } + + return &r.Resources[0], nil +} + // CreateUser will create the user specified func (c *client) CreateUser(u *User) (user *User, err error) { startURL, err := url.Parse(c.endpointURL.String()) diff --git a/internal/aws/client_test.go b/internal/aws/client_test.go index c953d5ed..e568d707 100644 --- a/internal/aws/client_test.go +++ b/internal/aws/client_test.go @@ -82,93 +82,6 @@ func TestNewClient(t *testing.T) { assert.Nil(t, c) } -func TestClient_GetGroups(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - x := mock.NewMockIHttpClient(ctrl) - - c, err := NewClient(x, &Config{ - Endpoint: "https://scim.example.com/", - Token: "bearerToken", - }) - assert.NoError(t, err) - - r := ` -{ - "totalResults": 3, - "itemsPerPage": 3, - "startIndex": 1, - "schemas": [ - "urn:ietf:params:scim:api:messages:2.0:ListResponse" - ], - "Resources": [ - { - "id": "93671c1e63-b32d7ffd-6695-4d8e-8f30-f1c4abadbe72", - "meta": { - "resourceType": "Group", - "created": "2020-04-30T12:50:43Z", - "lastModified": "2020-04-30T12:50:43Z" - }, - "schemas": [ - "urn:ietf:params:scim:schemas:core:2.0:Group" - ], - "displayName": "TestGroup1", - "members": [] - }, - { - "id": "93671c1e63-f3a32834-f790-4259-9edd-ad0371ed3207", - "meta": { - "resourceType": "Group", - "created": "2020-04-24T10:06:15Z", - "lastModified": "2020-04-24T10:06:15Z" - }, - "schemas": [ - "urn:ietf:params:scim:schemas:core:2.0:Group" - ], - "displayName": "TestGroup2", - "members": [] - }, - { - "id": "93671c1e63-a4acfeba-7a08-4854-9037-492248940c3d", - "meta": { - "resourceType": "Group", - "created": "2020-04-30T12:43:14Z", - "lastModified": "2020-04-30T12:43:14Z" - }, - "schemas": [ - "urn:ietf:params:scim:schemas:core:2.0:Group" - ], - "displayName": "TestGroup3", - "members": [] - } - ] -}` - - calledURL, _ := url.Parse("https://scim.example.com/Groups?count=10&startIndex=1") - - req := httpReqMatcher{httpReq: &http.Request{ - URL: calledURL, - Method: http.MethodGet, - }} - - // We only have enough groups for one page, so we should only - // see one call. - x.EXPECT().Do(&req).MaxTimes(1).Return(&http.Response{ - Status: "OK", - StatusCode: 200, - Body: nopCloser{bytes.NewBufferString(r)}, - }, nil) - - groups, err := c.GetGroups() - - assert.NoError(t, err) - - // Check there's only user - assert.Equal(t, len(*groups), 3) - assert.Contains(t, *groups, "TestGroup1") -} - func TestSendRequestBadUrl(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/internal/sync.go b/internal/sync.go index 44387c75..406af561 100644 --- a/internal/sync.go +++ b/internal/sync.go @@ -22,7 +22,6 @@ import ( "github.com/awslabs/ssosync/internal/aws" "github.com/awslabs/ssosync/internal/config" "github.com/awslabs/ssosync/internal/google" - "go.uber.org/zap" log "github.com/sirupsen/logrus" admin "google.golang.org/api/admin/directory/v1" @@ -110,12 +109,6 @@ func (s *syncGSuite) SyncUsers() error { // SyncGroups will sync groups from Google -> AWS SSO func (s *syncGSuite) SyncGroups() error { - log.Debug("get sso groups") - awsGroups, err := s.aws.GetGroups() - if err != nil { - return err - } - log.Debug("get google groups") googleGroups, err := s.google.GetGroups() if err != nil { @@ -133,10 +126,15 @@ func (s *syncGSuite) SyncGroups() error { var group *aws.Group - if awsGroup, ok := (*awsGroups)[g.Name]; ok { + gg, err := s.aws.FindGroupByDisplayName(g.Name) + if err != nil { + return err + } + + if gg != nil { log.Debug("Found group") - correlatedGroups[awsGroup.DisplayName] = &awsGroup - group = &awsGroup + correlatedGroups[gg.DisplayName] = gg + group = gg } else { log.Info("Creating group in AWS") newGroup, err := s.aws.CreateGroup(aws.NewGroup(g.Name)) @@ -189,16 +187,16 @@ func (s *syncGSuite) SyncGroups() error { } } - log.Info("Clean up AWS groups") - for _, g := range *awsGroups { - if _, ok := correlatedGroups[g.DisplayName]; !ok { - log.Info("Delete Group in AWS", zap.String("group", g.DisplayName)) - err := s.aws.DeleteGroup(&g) - if err != nil { - return err - } - } - } + // log.Info("Clean up AWS groups") + // for _, g := range awsGroups { + // if _, ok := correlatedGroups[g.DisplayName]; !ok { + // log.Info("Delete Group in AWS", zap.String("group", g.DisplayName)) + // err := s.aws.DeleteGroup(&g) + // if err != nil { + // return err + // } + // } + // } return nil }