@@ -0,0 +1,170 @@
1+package providers
2+
3+import (
4+ "log"
5+ "net/http"
6+ "net/http/httptest"
7+ "net/url"
8+ "testing"
9+
10+ "github.com/stretchr/testify/assert"
11+
12+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
13+)
14+
15+func testBitbucketProvider(hostname, team string, repository string) *BitbucketProvider {
16+ p := NewBitbucketProvider(
17+ &ProviderData{
18+ ProviderName: "",
19+ LoginURL: &url.URL{},
20+ RedeemURL: &url.URL{},
21+ ProfileURL: &url.URL{},
22+ ValidateURL: &url.URL{},
23+ Scope: ""})
24+
25+ if team != "" {
26+ p.SetTeam(team)
27+ }
28+
29+ if repository != "" {
30+ p.SetRepository(repository)
31+ }
32+
33+ if hostname != "" {
34+ updateURL(p.Data().LoginURL, hostname)
35+ updateURL(p.Data().RedeemURL, hostname)
36+ updateURL(p.Data().ProfileURL, hostname)
37+ updateURL(p.Data().ValidateURL, hostname)
38+ }
39+ return p
40+}
41+
42+func testBitbucketBackend(payload string) *httptest.Server {
43+ paths := map[string]bool{
44+ "/2.0/user/emails": true,
45+ "/2.0/teams": true,
46+ }
47+
48+ return httptest.NewServer(http.HandlerFunc(
49+ func(w http.ResponseWriter, r *http.Request) {
50+ url := r.URL
51+ if !paths[url.Path] {
52+ log.Printf("%s not in %+v\n", url.Path, paths)
53+ w.WriteHeader(404)
54+ } else if r.URL.Query().Get("access_token") != "imaginary_access_token" {
55+ w.WriteHeader(403)
56+ } else {
57+ w.WriteHeader(200)
58+ w.Write([]byte(payload))
59+ }
60+ }))
61+}
62+
63+func TestBitbucketProviderDefaults(t *testing.T) {
64+ p := testBitbucketProvider("", "", "")
65+ assert.NotEqual(t, nil, p)
66+ assert.Equal(t, "Bitbucket", p.Data().ProviderName)
67+ assert.Equal(t, "https://bitbucket.org/site/oauth2/authorize",
68+ p.Data().LoginURL.String())
69+ assert.Equal(t, "https://bitbucket.org/site/oauth2/access_token",
70+ p.Data().RedeemURL.String())
71+ assert.Equal(t, "https://api.bitbucket.org/2.0/user/emails",
72+ p.Data().ValidateURL.String())
73+ assert.Equal(t, "email", p.Data().Scope)
74+}
75+
76+func TestBitbucketProviderScopeAdjustForTeam(t *testing.T) {
77+ p := testBitbucketProvider("", "test-team", "")
78+ assert.NotEqual(t, nil, p)
79+ assert.Equal(t, "email team", p.Data().Scope)
80+}
81+
82+func TestBitbucketProviderScopeAdjustForRepository(t *testing.T) {
83+ p := testBitbucketProvider("", "", "rest-repo")
84+ assert.NotEqual(t, nil, p)
85+ assert.Equal(t, "email repository", p.Data().Scope)
86+}
87+
88+func TestBitbucketProviderOverrides(t *testing.T) {
89+ p := NewBitbucketProvider(
90+ &ProviderData{
91+ LoginURL: &url.URL{
92+ Scheme: "https",
93+ Host: "example.com",
94+ Path: "/oauth/auth"},
95+ RedeemURL: &url.URL{
96+ Scheme: "https",
97+ Host: "example.com",
98+ Path: "/oauth/token"},
99+ ValidateURL: &url.URL{
100+ Scheme: "https",
101+ Host: "example.com",
102+ Path: "/api/v3/user"},
103+ Scope: "profile"})
104+ assert.NotEqual(t, nil, p)
105+ assert.Equal(t, "Bitbucket", p.Data().ProviderName)
106+ assert.Equal(t, "https://example.com/oauth/auth",
107+ p.Data().LoginURL.String())
108+ assert.Equal(t, "https://example.com/oauth/token",
109+ p.Data().RedeemURL.String())
110+ assert.Equal(t, "https://example.com/api/v3/user",
111+ p.Data().ValidateURL.String())
112+ assert.Equal(t, "profile", p.Data().Scope)
113+}
114+
115+func TestBitbucketProviderGetEmailAddress(t *testing.T) {
116+ b := testBitbucketBackend("{\"values\": [ { \"email\": \"michael.bland@gsa.gov\", \"is_primary\": true } ] }")
117+ defer b.Close()
118+
119+ bURL, _ := url.Parse(b.URL)
120+ p := testBitbucketProvider(bURL.Host, "", "")
121+
122+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
123+ email, err := p.GetEmailAddress(session)
124+ assert.Equal(t, nil, err)
125+ assert.Equal(t, "michael.bland@gsa.gov", email)
126+}
127+
128+func TestBitbucketProviderGetEmailAddressAndGroup(t *testing.T) {
129+ b := testBitbucketBackend("{\"values\": [ { \"email\": \"michael.bland@gsa.gov\", \"is_primary\": true, \"username\": \"bioinformatics\" } ] }")
130+ defer b.Close()
131+
132+ bURL, _ := url.Parse(b.URL)
133+ p := testBitbucketProvider(bURL.Host, "bioinformatics", "")
134+
135+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
136+ email, err := p.GetEmailAddress(session)
137+ assert.Equal(t, nil, err)
138+ assert.Equal(t, "michael.bland@gsa.gov", email)
139+}
140+
141+// Note that trying to trigger the "failed building request" case is not
142+// practical, since the only way it can fail is if the URL fails to parse.
143+func TestBitbucketProviderGetEmailAddressFailedRequest(t *testing.T) {
144+ b := testBitbucketBackend("unused payload")
145+ defer b.Close()
146+
147+ bURL, _ := url.Parse(b.URL)
148+ p := testBitbucketProvider(bURL.Host, "", "")
149+
150+ // We'll trigger a request failure by using an unexpected access
151+ // token. Alternatively, we could allow the parsing of the payload as
152+ // JSON to fail.
153+ session := &sessions.SessionState{AccessToken: "unexpected_access_token"}
154+ email, err := p.GetEmailAddress(session)
155+ assert.NotEqual(t, nil, err)
156+ assert.Equal(t, "", email)
157+}
158+
159+func TestBitbucketProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) {
160+ b := testBitbucketBackend("{\"foo\": \"bar\"}")
161+ defer b.Close()
162+
163+ bURL, _ := url.Parse(b.URL)
164+ p := testBitbucketProvider(bURL.Host, "", "")
165+
166+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
167+ email, err := p.GetEmailAddress(session)
168+ assert.Equal(t, "", email)
169+ assert.Equal(t, nil, err)
170+}