auth

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

130:6c755b23ec80 Go to Latest

auth/authcode_test.go

Change normalization flags to a constant. Let's use a constant so we can ensure we're using the same flags everywhere. Otherwise, we can get weird data corruption because we use the wrong flags.

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