auth

Paddy 2014-11-02 Parent:c29c7df35905 Child:55d5107e8805

65:f97ca45d5657 Go to Latest

auth/http_test.go

Fix bug with response_type redirect, add tests. Test that we redirect with an error when an invalid response_type is supplied. Fix a bug that would not add any of our parameters to the redirect URL.

History
1 package auth
3 import (
4 "html/template"
5 "net/http"
6 "net/http/httptest"
7 "net/url"
8 "testing"
9 "time"
11 "code.secondbit.org/uuid"
12 )
14 const (
15 scopeSet = 1 << iota
16 stateSet
17 uriSet
18 )
20 func stripParam(param string, u *url.URL) {
21 q := u.Query()
22 q.Del(param)
23 u.RawQuery = q.Encode()
24 }
26 func TestGetGrantCodeSuccess(t *testing.T) {
27 t.Parallel()
28 store := NewMemstore()
29 testContext := Context{
30 template: template.Must(template.New(getGrantTemplateName).Parse("Get auth grant")),
31 clients: store,
32 grants: store,
33 profiles: store,
34 tokens: store,
35 }
36 client := Client{
37 ID: uuid.NewID(),
38 Secret: "super secret!",
39 OwnerID: uuid.NewID(),
40 Name: "My test client",
41 Logo: "https://secondbit.org/logo.png",
42 Website: "https://secondbit.org",
43 Type: "public",
44 }
45 uri, err := url.Parse("https://test.secondbit.org/redirect")
46 if err != nil {
47 t.Fatal("Can't parse URL:", err)
48 }
49 endpoint := Endpoint{
50 ID: uuid.NewID(),
51 ClientID: client.ID,
52 URI: *uri,
53 Added: time.Now(),
54 }
55 err = testContext.SaveClient(client)
56 if err != nil {
57 t.Fatal("Can't store client:", err)
58 }
59 err = testContext.AddEndpoint(client.ID, endpoint)
60 if err != nil {
61 t.Fatal("Can't store endpoint:", err)
62 }
63 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
64 if err != nil {
65 t.Fatal("Can't build request:", err)
66 }
67 for i := 0; i < 1<<3; i++ {
68 w := httptest.NewRecorder()
69 params := url.Values{}
70 // see OAuth 2.0 spec, section 4.1.1
71 params.Set("response_type", "code")
72 params.Set("client_id", client.ID.String())
73 if i&uriSet != 0 {
74 params.Set("redirect_uri", endpoint.URI.String())
75 }
76 if i&scopeSet != 0 {
77 params.Set("scope", "testscope")
78 }
79 if i&stateSet != 0 {
80 params.Set("state", "my super secure state string")
81 }
82 req.URL.RawQuery = params.Encode()
83 GetGrantHandler(w, req, testContext)
84 if w.Code != http.StatusOK {
85 t.Errorf("Expected status code to be %d, got %d for %s", http.StatusOK, w.Code, req.URL.String())
86 }
87 if w.Body.String() != "Get auth grant" {
88 t.Errorf("Expected body to be `%s`, got `%s` for %s", "Get auth grant", w.Body.String(), req.URL.String())
89 }
90 }
91 }
93 func TestGetGrantCodeInvalidClient(t *testing.T) {
94 t.Parallel()
95 store := NewMemstore()
96 testContext := Context{
97 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")),
98 clients: store,
99 grants: store,
100 profiles: store,
101 tokens: store,
102 }
103 client := Client{
104 ID: uuid.NewID(),
105 Secret: "super secret!",
106 OwnerID: uuid.NewID(),
107 Name: "My test client",
108 Type: "public",
109 }
110 err := testContext.SaveClient(client)
111 if err != nil {
112 t.Fatal("Can't store client:", err)
113 }
114 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
115 if err != nil {
116 t.Fatal("Can't build request:", err)
117 }
118 w := httptest.NewRecorder()
119 params := url.Values{}
120 params.Set("response_type", "code")
121 params.Set("redirect_uri", "https://test.secondbit.org/")
122 req.URL.RawQuery = params.Encode()
123 GetGrantHandler(w, req, testContext)
124 if w.Code != http.StatusBadRequest {
125 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
126 }
127 if w.Body.String() != "Client ID must be specified in the request." {
128 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "Client ID must be specified in the request.", w.Body.String())
129 }
130 w = httptest.NewRecorder()
131 params.Set("client_id", "Not an ID")
132 req.URL.RawQuery = params.Encode()
133 GetGrantHandler(w, req, testContext)
134 if w.Code != http.StatusBadRequest {
135 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
136 }
137 if w.Body.String() != "client_id is not a valid Client ID." {
138 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "client_id is not a valid Client ID.", w.Body.String())
139 }
140 w = httptest.NewRecorder()
141 params.Set("client_id", uuid.NewID().String())
142 req.URL.RawQuery = params.Encode()
143 GetGrantHandler(w, req, testContext)
144 if w.Code != http.StatusBadRequest {
145 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
146 }
147 if w.Body.String() != "The specified Client couldn&rsquo;t be found." {
148 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The specified Client couldn&rsquo;t be found.", w.Body.String())
149 }
150 }
152 func TestGetGrantCodeInvalidURI(t *testing.T) {
153 t.Parallel()
154 store := NewMemstore()
155 testContext := Context{
156 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")),
157 clients: store,
158 grants: store,
159 profiles: store,
160 tokens: store,
161 }
162 client := Client{
163 ID: uuid.NewID(),
164 Secret: "super secret!",
165 OwnerID: uuid.NewID(),
166 Name: "My test client",
167 Type: "public",
168 }
169 uri, err := url.Parse("https://test.secondbit.org/redirect")
170 if err != nil {
171 t.Fatal("Can't parse URL:", err)
172 }
173 err = testContext.SaveClient(client)
174 if err != nil {
175 t.Fatal("Can't store client:", err)
176 }
177 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
178 if err != nil {
179 t.Fatal("Can't build request:", err)
180 }
181 w := httptest.NewRecorder()
182 params := url.Values{}
183 params.Set("response_type", "code")
184 params.Set("client_id", client.ID.String())
185 req.URL.RawQuery = params.Encode()
186 GetGrantHandler(w, req, testContext)
187 if w.Code != http.StatusBadRequest {
188 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
189 }
190 if w.Body.String() != "The redirect_uri specified is not valid." {
191 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
192 }
193 endpoint := Endpoint{
194 ID: uuid.NewID(),
195 ClientID: client.ID,
196 URI: *uri,
197 Added: time.Now(),
198 }
199 err = testContext.AddEndpoint(client.ID, endpoint)
200 if err != nil {
201 t.Fatal("Can't store endpoint:", err)
202 }
203 w = httptest.NewRecorder()
204 params.Set("redirect_uri", "https://test.secondbit.org/wrong")
205 req.URL.RawQuery = params.Encode()
206 GetGrantHandler(w, req, testContext)
207 if w.Code != http.StatusBadRequest {
208 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
209 }
210 if w.Body.String() != "The redirect_uri specified is not valid." {
211 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
212 }
213 endpoint2 := Endpoint{
214 ID: uuid.NewID(),
215 ClientID: client.ID,
216 URI: *uri,
217 Added: time.Now(),
218 }
219 err = testContext.AddEndpoint(client.ID, endpoint2)
220 if err != nil {
221 t.Fatal("Can't store endpoint:", err)
222 }
223 w = httptest.NewRecorder()
224 params.Set("redirect_uri", "")
225 req.URL.RawQuery = params.Encode()
226 GetGrantHandler(w, req, testContext)
227 if w.Code != http.StatusBadRequest {
228 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
229 }
230 if w.Body.String() != "The redirect_uri specified is not valid." {
231 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
232 }
233 w = httptest.NewRecorder()
234 params.Set("redirect_uri", "://not a URL")
235 req.URL.RawQuery = params.Encode()
236 GetGrantHandler(w, req, testContext)
237 if w.Code != http.StatusBadRequest {
238 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
239 }
240 if w.Body.String() != "The redirect_uri specified is not valid." {
241 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
242 }
243 }
245 func TestGetGrantCodeInvalidResponseType(t *testing.T) {
246 t.Parallel()
247 store := NewMemstore()
248 testContext := Context{
249 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")),
250 clients: store,
251 grants: store,
252 profiles: store,
253 tokens: store,
254 }
255 client := Client{
256 ID: uuid.NewID(),
257 Secret: "super secret!",
258 OwnerID: uuid.NewID(),
259 Name: "My test client",
260 Logo: "https://secondbit.org/logo.png",
261 Website: "https://secondbit.org",
262 Type: "public",
263 }
264 uri, err := url.Parse("https://test.secondbit.org/redirect")
265 if err != nil {
266 t.Fatal("Can't parse URL:", err)
267 }
268 endpoint := Endpoint{
269 ID: uuid.NewID(),
270 ClientID: client.ID,
271 URI: *uri,
272 Added: time.Now(),
273 }
274 err = testContext.SaveClient(client)
275 if err != nil {
276 t.Fatal("Can't store client:", err)
277 }
278 err = testContext.AddEndpoint(client.ID, endpoint)
279 if err != nil {
280 t.Fatal("Can't store endpoint:", err)
281 }
282 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
283 if err != nil {
284 t.Fatal("Can't build request:", err)
285 }
286 params := url.Values{}
287 params.Set("response_type", "totally not code")
288 params.Set("client_id", client.ID.String())
289 params.Set("redirect_uri", endpoint.URI.String())
290 params.Set("scope", "testscope")
291 params.Set("state", "my super secure state string")
292 req.URL.RawQuery = params.Encode()
293 w := httptest.NewRecorder()
294 GetGrantHandler(w, req, testContext)
295 if w.Code != http.StatusFound {
296 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
297 }
298 redirectedTo := w.Header().Get("Location")
299 red, err := url.Parse(redirectedTo)
300 if err != nil {
301 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err)
302 }
303 if red.Query().Get("error") != "invalid_request" {
304 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "invalid_request", red.Query().Get("error"))
305 }
306 stripParam("error", red)
307 if red.Query().Get("state") != params.Get("state") {
308 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state"))
309 }
310 stripParam("state", red)
311 if red.String() != endpoint.URI.String() {
312 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String())
313 }
314 stripParam("response_type", req.URL)
315 w = httptest.NewRecorder()
316 GetGrantHandler(w, req, testContext)
317 if w.Code != http.StatusFound {
318 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
319 }
320 redirectedTo = w.Header().Get("Location")
321 red, err = url.Parse(redirectedTo)
322 if err != nil {
323 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err)
324 }
325 if red.Query().Get("error") != "invalid_request" {
326 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "invalid_request", red.Query().Get("error"))
327 }
328 stripParam("error", red)
329 if red.Query().Get("state") != params.Get("state") {
330 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state"))
331 }
332 stripParam("state", red)
333 if red.String() != endpoint.URI.String() {
334 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String())
335 }
336 }