git.iko.soy/typeable/oauth2-proxy
on f201dff help sign in
493 lines 15 kB history raw
1package providers
3import (
4 "context"
5 "net/http"
6 "net/http/httptest"
7 "net/url"
8 "testing"
10 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
11 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
12 . "github.com/onsi/gomega"
13 "github.com/stretchr/testify/assert"
16func testGitHubProvider(hostname string, opts options.GitHubOptions) *GitHubProvider {
17 p := NewGitHubProvider(
18 &ProviderData{
19 ProviderName: "",
20 LoginURL: &url.URL{},
21 RedeemURL: &url.URL{},
22 ProfileURL: &url.URL{},
23 ValidateURL: &url.URL{},
24 Scope: ""},
25 opts)
26 if hostname != "" {
27 updateURL(p.Data().LoginURL, hostname)
28 updateURL(p.Data().RedeemURL, hostname)
29 updateURL(p.Data().ProfileURL, hostname)
30 updateURL(p.Data().ValidateURL, hostname)
31 }
32 return p
35func testGitHubBackend(payloads map[string][]string) *httptest.Server {
36 pathToQueryMap := map[string][]string{
37 "/": {""},
38 "/repos/oauth2-proxy/oauth2-proxy": {""},
39 "/repos/oauth2-proxy/oauth2-proxy/collaborators/mbland": {""},
40 "/user": {""},
41 "/user/emails": {""},
42 "/user/orgs": {"page=1&per_page=100", "page=2&per_page=100", "page=3&per_page=100"},
43 // GitHub Enterprise Server API
44 "/api/v3": {""},
45 "/api/v3/user/emails": {""},
46 }
48 return httptest.NewServer(http.HandlerFunc(
49 func(w http.ResponseWriter, r *http.Request) {
50 query, ok := pathToQueryMap[r.URL.Path]
51 validQuery := false
52 index := 0
53 for i, q := range query {
54 if q == r.URL.RawQuery {
55 validQuery = true
56 index = i
57 }
58 }
59 payload := []string{}
60 if ok && validQuery {
61 payload, ok = payloads[r.URL.Path]
62 }
63 if !ok {
64 w.WriteHeader(404)
65 } else if !validQuery {
66 w.WriteHeader(404)
67 } else if payload[index] == "" {
68 w.WriteHeader(204)
69 } else {
70 w.WriteHeader(200)
71 w.Write([]byte(payload[index]))
72 }
73 }))
76func TestNewGitHubProvider(t *testing.T) {
77 g := NewWithT(t)
79 // Test that defaults are set when calling for a new provider with nothing set
80 providerData := NewGitHubProvider(&ProviderData{}, options.GitHubOptions{}).Data()
81 g.Expect(providerData.ProviderName).To(Equal("GitHub"))
82 g.Expect(providerData.LoginURL.String()).To(Equal(githubDefaultLoginURL.String()))
83 g.Expect(providerData.RedeemURL.String()).To(Equal(githubDefaultRedeemURL.String()))
84 g.Expect(providerData.ProfileURL.String()).To(Equal(""))
85 g.Expect(providerData.ValidateURL.String()).To(Equal("https://api.github.com/"))
86 g.Expect(providerData.Scope).To(Equal("user:email read:org"))
89func TestGitHubProviderOverrides(t *testing.T) {
90 p := NewGitHubProvider(
91 &ProviderData{
92 LoginURL: &url.URL{
93 Scheme: "https",
94 Host: "example.com",
95 Path: "/login/oauth/authorize"},
96 RedeemURL: &url.URL{
97 Scheme: "https",
98 Host: "example.com",
99 Path: "/login/oauth/access_token"},
100 ValidateURL: &url.URL{
101 Scheme: "https",
102 Host: "api.example.com",
103 Path: "/"},
104 Scope: "profile"},
105 options.GitHubOptions{})
106 assert.NotEqual(t, nil, p)
107 assert.Equal(t, "GitHub", p.Data().ProviderName)
108 assert.Equal(t, "https://example.com/login/oauth/authorize",
109 p.Data().LoginURL.String())
110 assert.Equal(t, "https://example.com/login/oauth/access_token",
111 p.Data().RedeemURL.String())
112 assert.Equal(t, "https://api.example.com/",
113 p.Data().ValidateURL.String())
114 assert.Equal(t, "profile", p.Data().Scope)
117func TestGitHubProvider_getEmail(t *testing.T) {
118 b := testGitHubBackend(map[string][]string{
119 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
120 })
121 defer b.Close()
123 bURL, _ := url.Parse(b.URL)
124 p := testGitHubProvider(bURL.Host, options.GitHubOptions{})
126 session := CreateAuthorizedSession()
127 err := p.getEmail(context.Background(), session)
128 assert.NoError(t, err)
129 assert.Equal(t, "michael.bland@gsa.gov", session.Email)
132func TestGitHubProvider_getEmailNotVerified(t *testing.T) {
133 b := testGitHubBackend(map[string][]string{
134 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": false, "primary": true} ]`},
135 })
136 defer b.Close()
138 bURL, _ := url.Parse(b.URL)
139 p := testGitHubProvider(bURL.Host, options.GitHubOptions{})
141 session := CreateAuthorizedSession()
142 err := p.getEmail(context.Background(), session)
143 assert.NoError(t, err)
144 assert.Empty(t, session.Email)
147func TestGitHubProvider_getEmailWithOrg(t *testing.T) {
148 b := testGitHubBackend(map[string][]string{
149 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
150 "/user/orgs": {
151 `[ {"login":"testorg"} ]`,
152 `[ {"login":"testorg1"} ]`,
153 `[ ]`,
154 },
155 })
156 defer b.Close()
158 bURL, _ := url.Parse(b.URL)
159 p := testGitHubProvider(bURL.Host,
160 options.GitHubOptions{
161 Org: "testorg1",
162 },
163 )
165 session := CreateAuthorizedSession()
166 err := p.getEmail(context.Background(), session)
167 assert.NoError(t, err)
168 assert.Equal(t, "michael.bland@gsa.gov", session.Email)
171func TestGitHubProvider_getEmailWithWriteAccessToPublicRepo(t *testing.T) {
172 b := testGitHubBackend(map[string][]string{
173 "/repo/oauth2-proxy/oauth2-proxy": {`{"permissions": {"pull": true, "push": true}, "private": false}`},
174 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
175 })
176 defer b.Close()
178 bURL, _ := url.Parse(b.URL)
179 p := testGitHubProvider(bURL.Host,
180 options.GitHubOptions{
181 Repo: "oauth2-proxy/oauth2-proxy",
182 Token: "token",
183 },
184 )
186 session := CreateAuthorizedSession()
187 err := p.getEmail(context.Background(), session)
188 assert.NoError(t, err)
189 assert.Equal(t, "michael.bland@gsa.gov", session.Email)
192func TestGitHubProvider_getEmailWithReadOnlyAccessToPrivateRepo(t *testing.T) {
193 b := testGitHubBackend(map[string][]string{
194 "/repo/oauth2-proxy/oauth2-proxy": {`{"permissions": {"pull": true, "push": false}, "private": true}`},
195 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
196 })
197 defer b.Close()
199 bURL, _ := url.Parse(b.URL)
200 p := testGitHubProvider(bURL.Host,
201 options.GitHubOptions{
202 Repo: "oauth2-proxy/oauth2-proxy",
203 Token: "token",
204 },
205 )
207 session := CreateAuthorizedSession()
208 err := p.getEmail(context.Background(), session)
209 assert.NoError(t, err)
210 assert.Equal(t, "michael.bland@gsa.gov", session.Email)
213func TestGitHubProvider_getEmailWithWriteAccessToPrivateRepo(t *testing.T) {
214 b := testGitHubBackend(map[string][]string{
215 "/repo/oauth2-proxy/oauth2-proxy": {`{"permissions": {"pull": true, "push": true}, "private": true}`},
216 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
217 })
218 defer b.Close()
220 bURL, _ := url.Parse(b.URL)
221 p := testGitHubProvider(bURL.Host,
222 options.GitHubOptions{
223 Repo: "oauth2-proxy/oauth2-proxy",
224 Token: "token",
225 },
226 )
228 session := CreateAuthorizedSession()
229 err := p.getEmail(context.Background(), session)
230 assert.NoError(t, err)
231 assert.Equal(t, "michael.bland@gsa.gov", session.Email)
234func TestGitHubProvider_checkRestrictionsWithNoAccessToPrivateRepo(t *testing.T) {
235 b := testGitHubBackend(map[string][]string{
236 "/repos/oauth2-proxy/oauth2-proxy": {`{}`},
237 })
238 defer b.Close()
240 bURL, _ := url.Parse(b.URL)
241 p := testGitHubProvider(bURL.Host,
242 options.GitHubOptions{
243 Repo: "oauth2-proxy/oauth2-proxy",
244 },
245 )
247 session := CreateAuthorizedSession()
248 err := p.checkRestrictions(context.Background(), session)
249 assert.Error(t, err)
250 assert.Empty(t, session.Email)
253func TestGitHubProvider_getEmailWithToken(t *testing.T) {
254 b := testGitHubBackend(map[string][]string{
255 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
256 })
257 defer b.Close()
259 bURL, _ := url.Parse(b.URL)
260 p := testGitHubProvider(bURL.Host,
261 options.GitHubOptions{
262 Repo: "oauth2-proxy/oauth2-proxy",
263 Token: "token",
264 },
265 )
267 session := CreateAuthorizedSession()
268 err := p.getEmail(context.Background(), session)
269 assert.NoError(t, err)
270 assert.Equal(t, "michael.bland@gsa.gov", session.Email)
273// Note that trying to trigger the "failed building request" case is not
274// practical, since the only way it can fail is if the URL fails to parse.
275func TestGitHubProvider_getEmailFailedRequest(t *testing.T) {
276 b := testGitHubBackend(map[string][]string{})
277 defer b.Close()
279 bURL, _ := url.Parse(b.URL)
280 p := testGitHubProvider(bURL.Host, options.GitHubOptions{})
282 // We'll trigger a request failure by using an unexpected access
283 // token. Alternatively, we could allow the parsing of the payload as
284 // JSON to fail.
285 session := &sessions.SessionState{AccessToken: "unexpected_access_token"}
286 err := p.getEmail(context.Background(), session)
287 assert.Error(t, err)
288 assert.Empty(t, session.Email)
291func TestGitHubProvider_getEmailNotPresentInPayload(t *testing.T) {
292 b := testGitHubBackend(map[string][]string{
293 "/user/emails": {`{"foo": "bar"}`},
294 })
295 defer b.Close()
297 bURL, _ := url.Parse(b.URL)
298 p := testGitHubProvider(bURL.Host, options.GitHubOptions{})
300 session := CreateAuthorizedSession()
301 err := p.getEmail(context.Background(), session)
302 assert.Error(t, err)
303 assert.Empty(t, session.Email)
306func TestGitHubProvider_getUser(t *testing.T) {
307 b := testGitHubBackend(map[string][]string{
308 "/user": {`{"email": "michael.bland@gsa.gov", "login": "mbland"}`},
309 })
310 defer b.Close()
312 bURL, _ := url.Parse(b.URL)
313 p := testGitHubProvider(bURL.Host, options.GitHubOptions{})
315 session := CreateAuthorizedSession()
316 err := p.getUser(context.Background(), session)
317 assert.NoError(t, err)
318 assert.Equal(t, "mbland", session.User)
321func TestGitHubProvider_getUserWithRepoAndToken(t *testing.T) {
322 b := testGitHubBackend(map[string][]string{
323 "/user": {`{"email": "michael.bland@gsa.gov", "login": "mbland"}`},
324 "/repos/oauth2-proxy/oauth2-proxy/collaborators/mbland": {""},
325 })
326 defer b.Close()
328 bURL, _ := url.Parse(b.URL)
329 p := testGitHubProvider(bURL.Host,
330 options.GitHubOptions{
331 Repo: "oauth2-proxy/oauth2-proxy",
332 Token: "token",
333 },
334 )
336 session := CreateAuthorizedSession()
337 err := p.getUser(context.Background(), session)
338 assert.NoError(t, err)
339 assert.Equal(t, "mbland", session.User)
342func TestGitHubProvider_getUserWithRepoAndTokenWithoutPushAccess(t *testing.T) {
343 b := testGitHubBackend(map[string][]string{})
344 defer b.Close()
346 bURL, _ := url.Parse(b.URL)
347 p := testGitHubProvider(bURL.Host,
348 options.GitHubOptions{
349 Repo: "oauth2-proxy/oauth2-proxy",
350 Token: "token",
351 },
352 )
354 session := CreateAuthorizedSession()
355 err := p.getUser(context.Background(), session)
356 assert.Error(t, err)
357 assert.Empty(t, session.User)
360func TestGitHubProvider_getEmailWithUsername(t *testing.T) {
361 b := testGitHubBackend(map[string][]string{
362 "/user": {`{"email": "michael.bland@gsa.gov", "login": "mbland"}`},
363 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
364 })
365 defer b.Close()
367 bURL, _ := url.Parse(b.URL)
368 p := testGitHubProvider(bURL.Host,
369 options.GitHubOptions{
370 Users: []string{"mbland", "octocat"},
371 },
372 )
374 session := CreateAuthorizedSession()
375 err := p.getEmail(context.Background(), session)
376 assert.NoError(t, err)
377 assert.Equal(t, "michael.bland@gsa.gov", session.Email)
380func TestGitHubProvider_checkRestrictionsWithNotAllowedUsername(t *testing.T) {
381 b := testGitHubBackend(map[string][]string{
382 "/user": {`{"email": "michael.bland@gsa.gov", "login": "mbland"}`},
383 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
384 })
385 defer b.Close()
387 bURL, _ := url.Parse(b.URL)
388 p := testGitHubProvider(bURL.Host,
389 options.GitHubOptions{
390 Users: []string{"octocat"},
391 },
392 )
394 session := CreateAuthorizedSession()
395 err := p.checkRestrictions(context.Background(), session)
396 assert.Error(t, err)
397 assert.Empty(t, session.Email)
400func TestGitHubProvider_getEmailWithUsernameAndNotBelongToOrg(t *testing.T) {
401 b := testGitHubBackend(map[string][]string{
402 "/user": {`{"email": "michael.bland@gsa.gov", "login": "mbland"}`},
403 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
404 "/user/orgs": {
405 `[ {"login":"testorg"} ]`,
406 `[ ]`,
407 },
408 })
409 defer b.Close()
411 bURL, _ := url.Parse(b.URL)
412 p := testGitHubProvider(bURL.Host,
413 options.GitHubOptions{
414 Org: "not_belog_to",
415 Users: []string{"mbland"},
416 },
417 )
419 session := CreateAuthorizedSession()
420 err := p.getEmail(context.Background(), session)
421 assert.NoError(t, err)
422 assert.Equal(t, "michael.bland@gsa.gov", session.Email)
425func TestGitHubProvider_getEmailWithUsernameAndNoAccessToPrivateRepo(t *testing.T) {
426 b := testGitHubBackend(map[string][]string{
427 "/user": {`{"email": "michael.bland@gsa.gov", "login": "mbland"}`},
428 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
429 "/repo/oauth2-proxy/oauth2-proxy": {`{}`},
430 })
431 defer b.Close()
433 bURL, _ := url.Parse(b.URL)
434 p := testGitHubProvider(bURL.Host,
435 options.GitHubOptions{
436 Repo: "oauth2-proxy/oauth2-proxy",
437 Token: "token",
438 Users: []string{"mbland"},
439 },
440 )
442 session := CreateAuthorizedSession()
443 err := p.getEmail(context.Background(), session)
444 assert.NoError(t, err)
445 assert.Equal(t, "michael.bland@gsa.gov", session.Email)
448func TestGitHubProvider_ValidateSessionWithBaseUrl(t *testing.T) {
449 b := testGitHubBackend(map[string][]string{
450 "/": {`[]`},
451 })
452 defer b.Close()
454 bURL, _ := url.Parse(b.URL)
455 p := testGitHubProvider(bURL.Host, options.GitHubOptions{})
457 session := CreateAuthorizedSession()
459 valid := p.ValidateSession(context.Background(), session)
460 assert.True(t, valid)
463func TestGitHubProvider_ValidateSessionWithEnterpriseBaseUrl(t *testing.T) {
464 b := testGitHubBackend(map[string][]string{
465 "/api/v3": {`[]`},
466 })
467 defer b.Close()
469 bURL, _ := url.Parse(b.URL)
470 p := testGitHubProvider(bURL.Host, options.GitHubOptions{})
471 p.ValidateURL.Path = "/api/v3"
473 session := CreateAuthorizedSession()
475 valid := p.ValidateSession(context.Background(), session)
476 assert.True(t, valid)
479func TestGitHubProvider_ValidateSessionWithUserEmails(t *testing.T) {
480 b := testGitHubBackend(map[string][]string{
481 "/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
482 })
483 defer b.Close()
485 bURL, _ := url.Parse(b.URL)
486 p := testGitHubProvider(bURL.Host, options.GitHubOptions{})
487 p.ValidateURL.Path = "/user/emails"
489 session := CreateAuthorizedSession()
491 valid := p.ValidateSession(context.Background(), session)
492 assert.True(t, valid)