diff --git a/authn/authenticate.go b/authn/authenticate.go index 50373199c..a83d552c4 100644 --- a/authn/authenticate.go +++ b/authn/authenticate.go @@ -52,7 +52,8 @@ type Group struct { // Groups holds a slice of Group for marshalling from JSON type Groups struct { - Groups []Group `json:"value"` + NextLink string `json:"@odata.nextLink"` + Groups []Group `json:"value"` } // Auth holds state, configuration, and utilities needed for authentication. @@ -240,25 +241,39 @@ func (a *Auth) Redirect(w http.ResponseWriter, r *http.Request) { func (a *Auth) getGroups(token string) ([]Group, error) { var groups Groups - g, ok := a.groupsCache[token] - if ok && (time.Now().Sub(g.cacheTime) < a.cacheTTL) { - return g.groups, nil + gc, ok := a.groupsCache[token] + if ok && (time.Now().Sub(gc.cacheTime) < a.cacheTTL) && len(gc.groups) > 0 { + return gc.groups, nil } - req, err := http.NewRequest("GET", a.groupEndpoint, nil) - if err != nil { - return groups.Groups, errors.Wrap(err, "creating new request to group endpoint") + nextLink := a.groupEndpoint + for nextLink != "" { + req, err := http.NewRequest("GET", nextLink, nil) + if err != nil { + return nil, errors.Wrap(err, "creating new request to group endpoint") + } + + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token)) + response, err := http.DefaultClient.Do(req) + if err != nil { + return nil, errors.Wrap(err, "getting group membership info") + } + if response.StatusCode != http.StatusOK { + return nil, fmt.Errorf("getting group membership info: %s", response.Status) + } + + var g Groups + if err = json.NewDecoder(response.Body).Decode(&g); err != nil { + return groups.Groups, errors.Wrap(err, "failed unmarshalling group membership response") + } + + response.Body.Close() + groups.Groups = append(groups.Groups, g.Groups...) + nextLink = g.NextLink } - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token)) - response, err := http.DefaultClient.Do(req) - if err != nil { - return groups.Groups, errors.Wrap(err, "getting group membership info") - } - - defer response.Body.Close() - if err = json.NewDecoder(response.Body).Decode(&groups); err != nil { - return groups.Groups, errors.Wrap(err, "failed unmarshalling group membership response") + if len(groups.Groups) == 0 { + return nil, fmt.Errorf("no groups found") } a.groupsCache[token] = cachedGroups{ diff --git a/authn/authenticate_internal_test.go b/authn/authenticate_internal_test.go index 44c192d28..ca60b4c72 100644 --- a/authn/authenticate_internal_test.go +++ b/authn/authenticate_internal_test.go @@ -352,19 +352,36 @@ func TestGetGroups(t *testing.T) { cacheTime: time.Now(), groups: []Group{ { - GroupID: "i feel it in the water", - GroupName: "i feel it in the earth", + GroupID: "a han noston ned wilith", + GroupName: "I smell it in the air", }, }, }, } - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + srvNext := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, err := json.Marshal( Groups{ Groups: []Group{ { - GroupID: "much that once was is lost", - GroupName: "for none now live who remember it", + GroupID: "han mathon ne chae", + GroupName: "I feel it in the earth", + }, + }, + }, + ) + if err != nil { + t.Fatalf("unexpected error marshalling groups response: %v", err) + } + fmt.Fprintf(w, "%s", body) + })) + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + body, err := json.Marshal( + Groups{ + NextLink: srvNext.URL, + Groups: []Group{ + { + GroupID: "han mathon ne nen", + GroupName: "i feel it in the water", }, }, }, @@ -384,8 +401,8 @@ func TestGetGroups(t *testing.T) { token: "the world is changed", groups: []Group{ { - GroupID: "i feel it in the water", - GroupName: "i feel it in the earth", + GroupID: "a han noston ned wilith", + GroupName: "I smell it in the air", }, }, }, @@ -393,8 +410,12 @@ func TestGetGroups(t *testing.T) { token: "i smell it in the air", groups: []Group{ { - GroupID: "much that once was is lost", - GroupName: "for none now live who remember it", + GroupID: "han mathon ne nen", + GroupName: "i feel it in the water", + }, + { + GroupID: "han mathon ne chae", + GroupName: "I feel it in the earth", }, }, },