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