auth

Paddy 2015-12-14 Parent:b7e685839a1b

182:cd5f07f9811b Go to Latest

auth/authcode_test.go

Update nsq import path. go-nsq has moved to nsqio/go-nsq, so we need to update the import path appropriately.

History
1 package auth
3 import (
4 "bytes"
5 "io/ioutil"
6 "net/http"
7 "net/http/httptest"
8 "net/url"
9 "os"
10 "strings"
11 "testing"
12 "time"
14 "code.secondbit.org/scopes.hg/types"
15 "code.secondbit.org/uuid.hg"
16 )
18 func init() {
19 if os.Getenv("PG_TEST_DB") != "" {
20 p, err := NewPostgres(os.Getenv("PG_TEST_DB"))
21 if err != nil {
22 panic(err)
23 }
24 authCodeStores = append(authCodeStores, &p)
25 }
26 }
28 var authCodeStores = []authorizationCodeStore{NewMemstore()}
30 func compareAuthorizationCodes(authCode1, authCode2 AuthorizationCode) (success bool, field string, authCode1val, authCode2val interface{}) {
31 if authCode1.Code != authCode2.Code {
32 return false, "code", authCode1.Code, authCode2.Code
33 }
34 if !authCode1.Created.Equal(authCode2.Created) {
35 return false, "created", authCode1.Created, authCode2.Created
36 }
37 if authCode1.ExpiresIn != authCode2.ExpiresIn {
38 return false, "expires in", authCode1.ExpiresIn, authCode2.ExpiresIn
39 }
40 if !authCode1.ClientID.Equal(authCode2.ClientID) {
41 return false, "client ID", authCode1.ClientID, authCode2.ClientID
42 }
43 if len(authCode1.Scopes) != len(authCode2.Scopes) {
44 return false, "scopes", authCode1.Scopes, authCode2.Scopes
45 }
46 for pos, scope := range authCode1.Scopes {
47 if scope != authCode2.Scopes[pos] {
48 return false, "scopes", authCode1.Scopes, authCode2.Scopes
49 }
50 }
51 if authCode1.RedirectURI != authCode2.RedirectURI {
52 return false, "redirect URI", authCode1.RedirectURI, authCode2.RedirectURI
53 }
54 if authCode1.State != authCode2.State {
55 return false, "state", authCode1.State, authCode2.State
56 }
57 if !authCode1.ProfileID.Equal(authCode2.ProfileID) {
58 return false, "profile ID", authCode1.ProfileID, authCode2.ProfileID
59 }
60 if authCode1.Used != authCode2.Used {
61 return false, "used", authCode1.Used, authCode2.Used
62 }
63 return true, "", nil, nil
64 }
66 func TestAuthorizationCodeStore(t *testing.T) {
67 t.Parallel()
68 authCode := AuthorizationCode{
69 Code: "code",
70 Created: time.Now().Round(time.Millisecond),
71 ExpiresIn: 180,
72 ClientID: uuid.NewID(),
73 Scopes: scopeTypes.StringsToScopes([]string{"scope"}),
74 RedirectURI: "redirectURI",
75 State: "state",
76 }
77 for _, store := range authCodeStores {
78 context := Context{authCodes: store}
79 err := context.SaveAuthorizationCode(authCode)
80 if err != nil {
81 t.Errorf("Error saving auth code to %T: %s", store, err)
82 }
83 err = context.SaveAuthorizationCode(authCode)
84 if err != ErrAuthorizationCodeAlreadyExists {
85 t.Errorf("Expected ErrAuthorizationCodeAlreadyExists from %T, got %+v", store, err)
86 }
87 retrieved, err := context.GetAuthorizationCode(authCode.Code)
88 if err != nil {
89 t.Errorf("Error retrieving auth code from %T: %s", store, err)
90 }
91 match, field, expectation, result := compareAuthorizationCodes(authCode, retrieved)
92 if !match {
93 t.Errorf("Expected `%v` in the `%s` field of auth code retrieved from %T, got `%v`", expectation, field, store, result)
94 }
95 err = context.UseAuthorizationCode(authCode.Code)
96 if err != nil {
97 t.Errorf("Error retrieving auth code from %T: %s", store, err)
98 }
99 retrieved, err = context.GetAuthorizationCode(authCode.Code)
100 if err != nil {
101 t.Errorf("Error retrieving auth code from %T: %s", store, err)
102 }
103 authCode.Used = true
104 match, field, expectation, result = compareAuthorizationCodes(authCode, retrieved)
105 if !match {
106 t.Errorf("Expected `%v` in the `%s` field of auth code retrieved from %T, got `%v`", expectation, field, store, result)
107 }
108 err = context.DeleteAuthorizationCode(authCode.Code)
109 if err != nil {
110 t.Errorf("Error removing auth code from %T: %s", store, err)
111 }
112 retrieved, err = context.GetAuthorizationCode(authCode.Code)
113 if err != ErrAuthorizationCodeNotFound {
114 t.Errorf("Expected ErrAuthorizationCodeNotFound from %T, got %+v and %+v", store, retrieved, err)
115 }
116 err = context.DeleteAuthorizationCode(authCode.Code)
117 if err != ErrAuthorizationCodeNotFound {
118 t.Errorf("Expected ErrAuthorizationCodeNotFound from %T, got %+v", store, err)
119 }
120 err = context.UseAuthorizationCode(authCode.Code)
121 if err != ErrAuthorizationCodeNotFound {
122 t.Errorf("Expected ErrAuthorizationCodeNotFound from %T, got %+v", store, err)
123 }
124 }
125 }
127 func TestAuthCodeGrantValidate(t *testing.T) {
128 t.Parallel()
129 store := NewMemstore()
130 testContext := Context{
131 clients: store,
132 authCodes: store,
133 profiles: store,
134 tokens: store,
135 sessions: store,
136 }
137 client := Client{
138 ID: uuid.NewID(),
139 Secret: "super secret!",
140 OwnerID: uuid.NewID(),
141 Name: "My test client",
142 Logo: "https://secondbit.org/logo.png",
143 Website: "https://secondbit.org/",
144 Type: "public",
145 }
146 endpoint := Endpoint{
147 ID: uuid.NewID(),
148 ClientID: client.ID,
149 URI: "https://test.secondbit.org/redirect",
150 Added: time.Now().Round(time.Millisecond),
151 }
152 err := testContext.SaveClient(client)
153 if err != nil {
154 t.Fatal("Can't store client:", err)
155 }
156 err = testContext.AddEndpoints([]Endpoint{endpoint})
157 if err != nil {
158 t.Fatal("Can't store endpoint:", err)
159 }
160 code := AuthorizationCode{
161 Code: "myauthcode",
162 Created: time.Now().Round(time.Millisecond),
163 ExpiresIn: 180,
164 ClientID: uuid.NewID(),
165 Scopes: scopeTypes.StringsToScopes([]string{"scope"}),
166 RedirectURI: "redirectURI",
167 State: "state",
168 }
169 err = testContext.SaveAuthorizationCode(code)
170 if err != nil {
171 t.Fatal("Can't add auth code:", err)
172 }
173 code2 := code
174 code2.Code = "otherauthcode"
175 code2.ClientID = client.ID
176 err = testContext.SaveAuthorizationCode(code2)
177 if err != nil {
178 t.Fatal("Can't add second auth code:", err)
179 }
180 req, err := http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
181 if err != nil {
182 t.Fatal("Can't build request:", err)
183 }
184 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
185 w := httptest.NewRecorder()
186 params := url.Values{}
187 body := bytes.NewBufferString(params.Encode())
188 req.Body = ioutil.NopCloser(body)
189 scope, profileID, valid := authCodeGrantValidate(w, req, testContext)
190 if valid {
191 t.Fatalf("Expected invalid auth code, got scope `%s` and profileID `%s`.", scope, profileID)
192 }
193 if w.Code != http.StatusBadRequest {
194 t.Errorf("Expected status %d, got %d", http.StatusBadRequest, w.Code)
195 }
196 expectedBody := `{"error":"invalid_request"}`
197 if strings.TrimSpace(w.Body.String()) != expectedBody {
198 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
199 }
201 req, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
202 if err != nil {
203 t.Fatal("Can't build request:", err)
204 }
205 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
206 w = httptest.NewRecorder()
207 params = url.Values{}
208 params.Set("code", "notmycode")
209 body = bytes.NewBufferString(params.Encode())
210 req.Body = ioutil.NopCloser(body)
211 err = req.ParseForm()
212 if err != nil {
213 t.Log(err)
214 }
215 scope, profileID, valid = authCodeGrantValidate(w, req, testContext)
216 if valid {
217 t.Fatalf("Expected invalid auth code, got scope `%s` and profileID `%s`.", scope, profileID)
218 }
219 if w.Code != http.StatusUnauthorized {
220 t.Errorf("Expected status %d, got %d", http.StatusUnauthorized, w.Code)
221 }
222 expectedBody = `{"error":"invalid_client"}`
223 if expectedBody != strings.TrimSpace(w.Body.String()) {
224 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
225 }
227 req, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
228 if err != nil {
229 t.Fatal("Can't build request:", err)
230 }
231 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
232 req.SetBasicAuth(client.ID.String(), client.Secret)
233 w = httptest.NewRecorder()
234 params = url.Values{}
235 params.Set("code", "notmycode")
236 body = bytes.NewBufferString(params.Encode())
237 req.Body = ioutil.NopCloser(body)
238 err = req.ParseForm()
239 if err != nil {
240 t.Log(err)
241 }
242 scope, profileID, valid = authCodeGrantValidate(w, req, testContext)
243 if valid {
244 t.Fatalf("Expected invalid auth code, got scope `%s` and profileID `%s`.", scope, profileID)
245 }
246 if w.Code != http.StatusBadRequest {
247 t.Errorf("Expected status %d, got %d", http.StatusUnauthorized, w.Code)
248 }
249 expectedBody = `{"error":"invalid_grant"}`
250 if expectedBody != strings.TrimSpace(w.Body.String()) {
251 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
252 }
254 req, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
255 if err != nil {
256 t.Fatal("Can't build request:", err)
257 }
258 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
259 req.SetBasicAuth(client.ID.String(), client.Secret)
260 w = httptest.NewRecorder()
261 params = url.Values{}
262 params.Set("code", code.Code)
263 params.Set("redirect_uri", "not my redirectURI")
264 body = bytes.NewBufferString(params.Encode())
265 req.Body = ioutil.NopCloser(body)
266 err = req.ParseForm()
267 if err != nil {
268 t.Log(err)
269 }
270 scope, profileID, valid = authCodeGrantValidate(w, req, testContext)
271 if valid {
272 t.Fatalf("Expected invalid auth code, got scope `%s` and profileID `%s`.", scope, profileID)
273 }
274 if w.Code != http.StatusBadRequest {
275 t.Errorf("Expected status %d, got %d", http.StatusUnauthorized, w.Code)
276 }
277 expectedBody = `{"error":"invalid_grant"}`
278 if expectedBody != strings.TrimSpace(w.Body.String()) {
279 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
280 }
282 req, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
283 if err != nil {
284 t.Fatal("Can't build request:", err)
285 }
286 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
287 req.SetBasicAuth(client.ID.String(), client.Secret)
288 w = httptest.NewRecorder()
289 params = url.Values{}
290 params.Set("code", code.Code)
291 params.Set("redirect_uri", code.RedirectURI)
292 body = bytes.NewBufferString(params.Encode())
293 req.Body = ioutil.NopCloser(body)
294 err = req.ParseForm()
295 if err != nil {
296 t.Log(err)
297 }
298 scope, profileID, valid = authCodeGrantValidate(w, req, testContext)
299 if valid {
300 t.Fatalf("Expected invalid auth code, got scope `%s` and profileID `%s`.", scope, profileID)
301 }
302 if w.Code != http.StatusBadRequest {
303 t.Errorf("Expected status %d, got %d", http.StatusUnauthorized, w.Code)
304 }
305 expectedBody = `{"error":"invalid_grant"}`
306 if expectedBody != strings.TrimSpace(w.Body.String()) {
307 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
308 }
310 req, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
311 if err != nil {
312 t.Fatal("Can't build request:", err)
313 }
314 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
315 req.SetBasicAuth(client.ID.String(), client.Secret)
316 w = httptest.NewRecorder()
317 params = url.Values{}
318 params.Set("code", code2.Code)
319 params.Set("redirect_uri", code2.RedirectURI)
320 body = bytes.NewBufferString(params.Encode())
321 req.Body = ioutil.NopCloser(body)
322 err = req.ParseForm()
323 if err != nil {
324 t.Log(err)
325 }
326 scope, profileID, valid = authCodeGrantValidate(w, req, testContext)
327 if !valid {
328 t.Fatalf("Expected valid auth code, was not valid.")
329 }
330 }
332 func TestAuthCodeGrantInvalidate(t *testing.T) {
333 t.Parallel()
334 store := NewMemstore()
335 testContext := Context{
336 clients: store,
337 authCodes: store,
338 profiles: store,
339 tokens: store,
340 sessions: store,
341 }
342 code := AuthorizationCode{
343 Code: "myauthcode",
344 Created: time.Now().Round(time.Millisecond),
345 ExpiresIn: 180,
346 ClientID: uuid.NewID(),
347 Scopes: scopeTypes.StringsToScopes([]string{"scope"}),
348 RedirectURI: "redirectURI",
349 State: "state",
350 }
351 err := testContext.SaveAuthorizationCode(code)
352 if err != nil {
353 t.Fatal("Can't add auth code:", err)
354 }
355 req, err := http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
356 if err != nil {
357 t.Fatal("Can't build request:", err)
358 }
359 err = authCodeGrantInvalidate(req, testContext)
360 if err != ErrAuthorizationCodeNotFound {
361 t.Errorf("Expected `%s`, got `%+v`", ErrAuthorizationCodeNotFound, err)
362 }
363 req, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
364 if err != nil {
365 t.Fatal("Can't build request:", err)
366 }
367 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
368 params := url.Values{}
369 params.Set("code", "notmycode")
370 body := bytes.NewBufferString(params.Encode())
371 req.Body = ioutil.NopCloser(body)
372 err = authCodeGrantInvalidate(req, testContext)
373 if err != ErrAuthorizationCodeNotFound {
374 t.Errorf("Expected `%s`, got `%+v`", ErrAuthorizationCodeNotFound, err)
375 }
376 req, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
377 if err != nil {
378 t.Fatal("Can't build request:", err)
379 }
380 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
381 params.Set("code", code.Code)
382 body = bytes.NewBufferString(params.Encode())
383 req.Body = ioutil.NopCloser(body)
384 err = authCodeGrantInvalidate(req, testContext)
385 if err != nil {
386 t.Error("Error invalidating auth code:", err)
387 }
388 authCode, err := testContext.GetAuthorizationCode(code.Code)
389 if err != nil {
390 t.Error("Error retrieving auth code:", err)
391 }
392 if !authCode.Used {
393 t.Error("Expected auth code to be used, was not.")
394 }
395 }