auth

Paddy 2015-01-18 Parent:e000b1c24fc0 Child:d30a3a12d387

124:d14f0a81498c Go to Latest

auth/authcode_test.go

Fill out token.CreatedFrom. Add a GrantType.AuditString() string method that will return a string for an audit log. Basically, it returns enough information to identify how the token got created. For client credentials, that's just the string "client_credentials". For user credentials, that's just the string "credentials". For auth codes, that's "authcode:", followed by the code used. For refresh tokens, that's "refresh_token:", followed by the refresh token used.

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