git.iko.soy/typeable/oauth2-proxy
on master help sign in
providers: iterate across all pages from /user/orgs github endpoint.
882fcf0Mark Maglana
providers/github.go+43−27
@@ -8,6 +8,7 @@ import (
8 "net/http"
8 "net/http"
9 "net/url"
9 "net/url"
10 "path"
10 "path"
11+ "strconv"
11 "strings"
12 "strings"
12)
13)
13
14
@@ -61,36 +62,51 @@ func (p *GitHubProvider) hasOrg(accessToken string) (bool, error) {
61 Login string `json:"login"`
62 Login string `json:"login"`
62 }
63 }
63
64
64− params := url.Values{
65+ type orgsPage []struct {
65− "limit": {"100"},
66+ Login string `json:"login"`
66 }
67 }
67
68
68− endpoint := &url.URL{
69+ pn := 1
69− Scheme: p.ValidateURL.Scheme,
70+ for {
70− Host: p.ValidateURL.Host,
71+ params := url.Values{
71− Path: path.Join(p.ValidateURL.Path, "/user/orgs"),
72+ "limit": {"200"},
72− RawQuery: params.Encode(),
73+ "page": {strconv.Itoa(pn)},
73− }
74− req, _ := http.NewRequest("GET", endpoint.String(), nil)
75− req.Header.Set("Accept", "application/vnd.github.v3+json")
76− req.Header.Set("Authorization", fmt.Sprintf("token %s", accessToken))
77− resp, err := http.DefaultClient.Do(req)
78− if err != nil {
79− return false, err
80− }
74+ }
81
75
82− body, err := ioutil.ReadAll(resp.Body)
76+ endpoint := &url.URL{
83− resp.Body.Close()
77+ Scheme: p.ValidateURL.Scheme,
84− if err != nil {
78+ Host: p.ValidateURL.Host,
85− return false, err
79+ Path: path.Join(p.ValidateURL.Path, "/user/orgs"),
86− }
80+ RawQuery: params.Encode(),
87− if resp.StatusCode != 200 {
81+ }
88− return false, fmt.Errorf(
82+ req, _ := http.NewRequest("GET", endpoint.String(), nil)
89− "got %d from %q %s", resp.StatusCode, endpoint.String(), body)
83+ req.Header.Set("Accept", "application/vnd.github.v3+json")
84+ req.Header.Set("Authorization", fmt.Sprintf("token %s", accessToken))
85+ resp, err := http.DefaultClient.Do(req)
86+ if err != nil {
87+ return false, err
90− }
88+ }
91
89
90+ body, err := ioutil.ReadAll(resp.Body)
91+ resp.Body.Close()
92+ if err != nil {
93+ return false, err
94+ }
95+ if resp.StatusCode != 200 {
96+ return false, fmt.Errorf(
97+ "got %d from %q %s", resp.StatusCode, endpoint.String(), body)
98+ }
99+
100+ var op orgsPage
92− if err := json.Unmarshal(body, &orgs); err != nil {
101+ if err := json.Unmarshal(body, &op); err != nil {
93− return false, err
102+ return false, err
103+ }
104+ if len(op) == 0 {
105+ break
106+ }
107+
108+ orgs = append(orgs, op...)
109+ pn += 1
94 }
110 }
95
111
96 var presentOrgs []string
112 var presentOrgs []string
@@ -118,7 +134,7 @@ func (p *GitHubProvider) hasOrgAndTeam(accessToken string) (bool, error) {
118 }
134 }
119
135
120 params := url.Values{
136 params := url.Values{
121− "limit": {"100"},
137+ "limit": {"200"},
122 }
138 }
123
139
124 endpoint := &url.URL{
140 endpoint := &url.URL{
providers/github_test.go+37−10
@@ -27,23 +27,32 @@ func testGitHubProvider(hostname string) *GitHubProvider {
27 return p
27 return p
28}
28}
29
29
30−func testGitHubBackend(payload string) *httptest.Server {
30+func testGitHubBackend(payload []string) *httptest.Server {
31− pathToQueryMap := map[string]string{
31+ pathToQueryMap := map[string][]string{
32− "/user": "",
32+ "/user": []string{""},
33− "/user/emails": "",
33+ "/user/emails": []string{""},
34+ "/user/orgs": []string{"limit=200&page=1", "limit=200&page=2", "limit=200&page=3"},
34 }
35 }
35
36
36 return httptest.NewServer(http.HandlerFunc(
37 return httptest.NewServer(http.HandlerFunc(
37 func(w http.ResponseWriter, r *http.Request) {
38 func(w http.ResponseWriter, r *http.Request) {
38 url := r.URL
39 url := r.URL
39 query, ok := pathToQueryMap[url.Path]
40 query, ok := pathToQueryMap[url.Path]
41+ validQuery := false
42+ index := 0
43+ for i, q := range query {
44+ if q == url.RawQuery {
45+ validQuery = true
46+ index = i
47+ }
48+ }
40 if !ok {
49 if !ok {
41 w.WriteHeader(404)
50 w.WriteHeader(404)
42− } else if url.RawQuery != query {
51+ } else if !validQuery {
43 w.WriteHeader(404)
52 w.WriteHeader(404)
44 } else {
53 } else {
45 w.WriteHeader(200)
54 w.WriteHeader(200)
46− w.Write([]byte(payload))
55+ w.Write([]byte(payload[index]))
47 }
56 }
48 }))
57 }))
49}
58}
@@ -89,11 +98,29 @@ func TestGitHubProviderOverrides(t *testing.T) {
89}
98}
90
99
91func TestGitHubProviderGetEmailAddress(t *testing.T) {
100func TestGitHubProviderGetEmailAddress(t *testing.T) {
92− b := testGitHubBackend(`[ {"email": "michael.bland@gsa.gov", "primary": true} ]`)
101+ b := testGitHubBackend([]string{`[ {"email": "michael.bland@gsa.gov", "primary": true} ]`})
102+ defer b.Close()
103+
104+ bURL, _ := url.Parse(b.URL)
105+ p := testGitHubProvider(bURL.Host)
106+
107+ session := &SessionState{AccessToken: "imaginary_access_token"}
108+ email, err := p.GetEmailAddress(session)
109+ assert.Equal(t, nil, err)
110+ assert.Equal(t, "michael.bland@gsa.gov", email)
111+}
112+
113+func TestGitHubProviderGetEmailAddressWithOrg(t *testing.T) {
114+ b := testGitHubBackend([]string{
115+ `[ {"email": "michael.bland@gsa.gov", "primary": true, "login":"testorg"} ]`,
116+ `[ {"email": "michael.bland1@gsa.gov", "primary": true, "login":"testorg1"} ]`,
117+ `[ ]`,
118+ })
93 defer b.Close()
119 defer b.Close()
94
120
95 bURL, _ := url.Parse(b.URL)
121 bURL, _ := url.Parse(b.URL)
96 p := testGitHubProvider(bURL.Host)
122 p := testGitHubProvider(bURL.Host)
123+ p.Org = "testorg1"
97
124
98 session := &SessionState{AccessToken: "imaginary_access_token"}
125 session := &SessionState{AccessToken: "imaginary_access_token"}
99 email, err := p.GetEmailAddress(session)
126 email, err := p.GetEmailAddress(session)
@@ -104,7 +131,7 @@ func TestGitHubProviderGetEmailAddress(t *testing.T) {
104// Note that trying to trigger the "failed building request" case is not
131// Note that trying to trigger the "failed building request" case is not
105// practical, since the only way it can fail is if the URL fails to parse.
132// practical, since the only way it can fail is if the URL fails to parse.
106func TestGitHubProviderGetEmailAddressFailedRequest(t *testing.T) {
133func TestGitHubProviderGetEmailAddressFailedRequest(t *testing.T) {
107− b := testGitHubBackend("unused payload")
134+ b := testGitHubBackend([]string{"unused payload"})
108 defer b.Close()
135 defer b.Close()
109
136
110 bURL, _ := url.Parse(b.URL)
137 bURL, _ := url.Parse(b.URL)
@@ -120,7 +147,7 @@ func TestGitHubProviderGetEmailAddressFailedRequest(t *testing.T) {
120}
147}
121
148
122func TestGitHubProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) {
149func TestGitHubProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) {
123− b := testGitHubBackend("{\"foo\": \"bar\"}")
150+ b := testGitHubBackend([]string{"{\"foo\": \"bar\"}"})
124 defer b.Close()
151 defer b.Close()
125
152
126 bURL, _ := url.Parse(b.URL)
153 bURL, _ := url.Parse(b.URL)
@@ -133,7 +160,7 @@ func TestGitHubProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) {
133}
160}
134
161
135func TestGitHubProviderGetUserName(t *testing.T) {
162func TestGitHubProviderGetUserName(t *testing.T) {
136− b := testGitHubBackend(`{"email": "michael.bland@gsa.gov", "login": "mbland"}`)
163+ b := testGitHubBackend([]string{`{"email": "michael.bland@gsa.gov", "login": "mbland"}`})
137 defer b.Close()
164 defer b.Close()
138
165
139 bURL, _ := url.Parse(b.URL)
166 bURL, _ := url.Parse(b.URL)