@@ -0,0 +1,151 @@
1+package providers
2+
3+import (
4+ "net/http"
5+ "net/http/httptest"
6+ "net/url"
7+ "testing"
8+
9+ "github.com/bmizerany/assert"
10+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
11+)
12+
13+const imaginaryAccessToken = "imaginary_access_token"
14+const bearerAccessToken = "Bearer " + imaginaryAccessToken
15+
16+func testKeycloakProvider(hostname, group string) *KeycloakProvider {
17+ p := NewKeycloakProvider(
18+ &ProviderData{
19+ ProviderName: "",
20+ LoginURL: &url.URL{},
21+ RedeemURL: &url.URL{},
22+ ProfileURL: &url.URL{},
23+ ValidateURL: &url.URL{},
24+ Scope: ""})
25+
26+ if group != "" {
27+ p.SetGroup(group)
28+ }
29+
30+ if hostname != "" {
31+ updateURL(p.Data().LoginURL, hostname)
32+ updateURL(p.Data().RedeemURL, hostname)
33+ updateURL(p.Data().ProfileURL, hostname)
34+ updateURL(p.Data().ValidateURL, hostname)
35+ }
36+ return p
37+}
38+
39+func testKeycloakBackend(payload string) *httptest.Server {
40+ path := "/api/v3/user"
41+
42+ return httptest.NewServer(http.HandlerFunc(
43+ func(w http.ResponseWriter, r *http.Request) {
44+ url := r.URL
45+ if url.Path != path {
46+ w.WriteHeader(404)
47+ } else if r.Header.Get("Authorization") != bearerAccessToken {
48+ w.WriteHeader(403)
49+ } else {
50+ w.WriteHeader(200)
51+ w.Write([]byte(payload))
52+ }
53+ }))
54+}
55+
56+func TestKeycloakProviderDefaults(t *testing.T) {
57+ p := testKeycloakProvider("", "")
58+ assert.NotEqual(t, nil, p)
59+ assert.Equal(t, "Keycloak", p.Data().ProviderName)
60+ assert.Equal(t, "https://keycloak.org/oauth/authorize",
61+ p.Data().LoginURL.String())
62+ assert.Equal(t, "https://keycloak.org/oauth/token",
63+ p.Data().RedeemURL.String())
64+ assert.Equal(t, "https://keycloak.org/api/v3/user",
65+ p.Data().ValidateURL.String())
66+ assert.Equal(t, "api", p.Data().Scope)
67+}
68+
69+func TestKeycloakProviderOverrides(t *testing.T) {
70+ p := NewKeycloakProvider(
71+ &ProviderData{
72+ LoginURL: &url.URL{
73+ Scheme: "https",
74+ Host: "example.com",
75+ Path: "/oauth/auth"},
76+ RedeemURL: &url.URL{
77+ Scheme: "https",
78+ Host: "example.com",
79+ Path: "/oauth/token"},
80+ ValidateURL: &url.URL{
81+ Scheme: "https",
82+ Host: "example.com",
83+ Path: "/api/v3/user"},
84+ Scope: "profile"})
85+ assert.NotEqual(t, nil, p)
86+ assert.Equal(t, "Keycloak", p.Data().ProviderName)
87+ assert.Equal(t, "https://example.com/oauth/auth",
88+ p.Data().LoginURL.String())
89+ assert.Equal(t, "https://example.com/oauth/token",
90+ p.Data().RedeemURL.String())
91+ assert.Equal(t, "https://example.com/api/v3/user",
92+ p.Data().ValidateURL.String())
93+ assert.Equal(t, "profile", p.Data().Scope)
94+}
95+
96+func TestKeycloakProviderGetEmailAddress(t *testing.T) {
97+ b := testKeycloakBackend("{\"email\": \"michael.bland@gsa.gov\"}")
98+ defer b.Close()
99+
100+ bURL, _ := url.Parse(b.URL)
101+ p := testKeycloakProvider(bURL.Host, "")
102+
103+ session := &sessions.SessionState{AccessToken: imaginaryAccessToken}
104+ email, err := p.GetEmailAddress(session)
105+ assert.Equal(t, nil, err)
106+ assert.Equal(t, "michael.bland@gsa.gov", email)
107+}
108+
109+func TestKeycloakProviderGetEmailAddressAndGroup(t *testing.T) {
110+ b := testKeycloakBackend("{\"email\": \"michael.bland@gsa.gov\", \"groups\": [\"test-grp1\", \"test-grp2\"]}")
111+ defer b.Close()
112+
113+ bURL, _ := url.Parse(b.URL)
114+ p := testKeycloakProvider(bURL.Host, "test-grp1")
115+
116+ session := &sessions.SessionState{AccessToken: imaginaryAccessToken}
117+ email, err := p.GetEmailAddress(session)
118+ assert.Equal(t, nil, err)
119+ assert.Equal(t, "michael.bland@gsa.gov", email)
120+}
121+
122+// Note that trying to trigger the "failed building request" case is not
123+// practical, since the only way it can fail is if the URL fails to parse.
124+func TestKeycloakProviderGetEmailAddressFailedRequest(t *testing.T) {
125+ b := testKeycloakBackend("unused payload")
126+ defer b.Close()
127+
128+ bURL, _ := url.Parse(b.URL)
129+ p := testKeycloakProvider(bURL.Host, "")
130+
131+ // We'll trigger a request failure by using an unexpected access
132+ // token. Alternatively, we could allow the parsing of the payload as
133+ // JSON to fail.
134+ session := &sessions.SessionState{AccessToken: "unexpected_access_token"}
135+ email, err := p.GetEmailAddress(session)
136+ assert.NotEqual(t, nil, err)
137+ assert.Equal(t, "", email)
138+}
139+
140+func TestKeycloakProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) {
141+ b := testKeycloakBackend("{\"foo\": \"bar\"}")
142+ defer b.Close()
143+
144+ bURL, _ := url.Parse(b.URL)
145+ p := testKeycloakProvider(bURL.Host, "")
146+
147+ session := &sessions.SessionState{AccessToken: imaginaryAccessToken}
148+ email, err := p.GetEmailAddress(session)
149+ assert.NotEqual(t, nil, err)
150+ assert.Equal(t, "", email)
151+}