mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-12 15:51:01 +00:00
Merge pull request #2011 from molecula/paginate
[FB-1303] Iterate through group membership http response
This commit is contained in:
commit
be17087a68
3 changed files with 123 additions and 46 deletions
|
|
@ -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.
|
||||
|
|
@ -128,6 +129,9 @@ func (a *Auth) Authenticate(ctx context.Context, bearer string) (*UserInfo, erro
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "refreshing token")
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("refreshing token: %s", resp.Status)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var t oauth2.Token
|
||||
if err := json.NewDecoder(resp.Body).Decode(&t); err != nil {
|
||||
|
|
@ -240,25 +244,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{
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ func TestAuthenticate(t *testing.T) {
|
|||
refresh: true,
|
||||
errOnRefresh: true,
|
||||
exp: -17764800,
|
||||
err: fmt.Errorf("decoding refreshed token: invalid character 'b' looking for beginning of value"),
|
||||
err: fmt.Errorf("refreshing token: 500 Internal Server Error"),
|
||||
},
|
||||
}
|
||||
for _, test := range cases {
|
||||
|
|
@ -352,19 +352,19 @@ 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",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -374,6 +374,25 @@ func TestGetGroups(t *testing.T) {
|
|||
}
|
||||
fmt.Fprintf(w, "%s", body)
|
||||
}))
|
||||
defer srvNext.Close()
|
||||
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",
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error marshalling groups response: %v", err)
|
||||
}
|
||||
fmt.Fprintf(w, "%s", body)
|
||||
}))
|
||||
defer srv.Close()
|
||||
a.groupEndpoint = srv.URL
|
||||
|
||||
for name, test := range map[string]struct {
|
||||
|
|
@ -384,8 +403,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 +412,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",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
|
@ -190,12 +191,42 @@ func readResponse(w *httptest.ResponseRecorder) ([]byte, error) {
|
|||
func TestAuthentication(t *testing.T) {
|
||||
type evaluate func(w *httptest.ResponseRecorder, data []byte)
|
||||
type endpoint func(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
type Group struct {
|
||||
GroupID string `json:"id"`
|
||||
GroupName string `json:"displayName"`
|
||||
}
|
||||
|
||||
// Groups holds a slice of Group for marshalling from JSON
|
||||
type Groups struct {
|
||||
NextLink string `json:"@odata.nextLink"`
|
||||
Groups []Group `json:"value"`
|
||||
}
|
||||
|
||||
groupSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
body, err := json.Marshal(
|
||||
Groups{
|
||||
Groups: []Group{
|
||||
{
|
||||
GroupID: "what are you?",
|
||||
GroupName: "i am a carbon-based bipedal life form descended from an ape",
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error marshalling groups response: %v", err)
|
||||
}
|
||||
fmt.Fprintf(w, "%s", body)
|
||||
}))
|
||||
defer groupSrv.Close()
|
||||
|
||||
var (
|
||||
ClientId = "e9088663-eb08-41d7-8f65-efb5f54bbb71"
|
||||
ClientSecret = "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
|
||||
AuthorizeURL = "https://login.microsoftonline.com/4a137d66-d161-4ae4-b1e6-07e9920874b8/oauth2/v2.0/authorize"
|
||||
TokenURL = "https://login.microsoftonline.com/4a137d66-d161-4ae4-b1e6-07e9920874b8/oauth2/v2.0/token"
|
||||
GroupEndpointURL = "https://graph.microsoft.com/v1.0/me/transitiveMemberOf/microsoft.graph.group?$count=true"
|
||||
GroupEndpointURL = groupSrv.URL
|
||||
LogoutURL = "https://login.microsoftonline.com/common/oauth2/v2.0/logout"
|
||||
Scopes = []string{"https://graph.microsoft.com/.default", "offline_access"}
|
||||
SecretKey = "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
|
||||
|
|
@ -650,29 +681,29 @@ func TestChkAuthN(t *testing.T) {
|
|||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
endpoint string
|
||||
token string
|
||||
handler http.HandlerFunc
|
||||
statusCode int
|
||||
name string
|
||||
endpoint string
|
||||
token string
|
||||
handler http.HandlerFunc
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "Valid",
|
||||
token: validToken,
|
||||
handler: h.chkAuthN(testingHandler),
|
||||
statusCode: http.StatusOK,
|
||||
name: "ValidToken-ButNotForMicrosoft",
|
||||
token: validToken,
|
||||
handler: h.chkAuthN(testingHandler),
|
||||
err: "authenticating: getting groups: getting group membership info",
|
||||
},
|
||||
{
|
||||
name: "Invalid",
|
||||
token: invalidToken,
|
||||
handler: h.chkAuthN(testingHandler),
|
||||
statusCode: http.StatusUnauthorized,
|
||||
name: "Invalid",
|
||||
token: invalidToken,
|
||||
handler: h.chkAuthN(testingHandler),
|
||||
err: "authenticating: parsing bearer token",
|
||||
},
|
||||
{
|
||||
name: "Expired",
|
||||
token: expiredToken,
|
||||
handler: h.chkAuthN(testingHandler),
|
||||
statusCode: http.StatusUnauthorized,
|
||||
name: "Expired",
|
||||
token: expiredToken,
|
||||
handler: h.chkAuthN(testingHandler),
|
||||
err: "authenticating: token is expired",
|
||||
},
|
||||
}
|
||||
for _, test := range cases {
|
||||
|
|
@ -682,8 +713,13 @@ func TestChkAuthN(t *testing.T) {
|
|||
r.Header.Add("Authorization", test.token)
|
||||
test.handler(w, r)
|
||||
resp := w.Result()
|
||||
if resp.StatusCode != test.statusCode {
|
||||
t.Fatalf("expected %v, got %v", test.statusCode, resp.StatusCode)
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.HasPrefix(string(body), test.err) {
|
||||
t.Fatalf("expected error %s, got: %s", test.err, string(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue