auth

Paddy 2015-12-14 Parent:581c60f8dd23

181:b7e685839a1b Go to Latest

auth/token_test.go

Break out scopes and events. This repo has gotten unwieldy, and there are portions of it that need to be imported by a large number of other packages. For example, scopes will be used in almost every API we write. Rather than importing the entirety of this codebase into every API we write, I've opted to move the scope logic out into a scopes package, with a subpackage for the defined types, which is all most projects actually want to import. We also define some event type constants, and importing those shouldn't require a project to import all our dependencies, either. So I made an events subpackage that just holds those constants. This package has become a little bit of a red-headed stepchild and is do for a refactor, but I'm trying to put that off as long as I can. The refactoring of our scopes stuff has left a bug wherein a token can be granted for scopes that don't exist. I'm going to need to revisit that, and also how to limit scopes to only be granted to the users that should be able to request them. But that's a battle for another day.

History
paddy@28 1 package auth
paddy@28 2
paddy@28 3 import (
paddy@155 4 "os"
paddy@28 5 "testing"
paddy@28 6 "time"
paddy@28 7
paddy@181 8 "code.secondbit.org/scopes.hg/types"
paddy@107 9 "code.secondbit.org/uuid.hg"
paddy@28 10 )
paddy@28 11
paddy@155 12 func init() {
paddy@155 13 if os.Getenv("PG_TEST_DB") != "" {
paddy@155 14 p, err := NewPostgres(os.Getenv("PG_TEST_DB"))
paddy@155 15 if err != nil {
paddy@155 16 panic(err)
paddy@155 17 }
paddy@155 18 tokenStores = append(tokenStores, &p)
paddy@155 19 }
paddy@155 20 }
paddy@155 21
paddy@57 22 var tokenStores = []tokenStore{NewMemstore()}
paddy@28 23
paddy@35 24 func compareTokens(token1, token2 Token) (success bool, field string, val1, val2 interface{}) {
paddy@35 25 if token1.AccessToken != token2.AccessToken {
paddy@35 26 return false, "access token", token1.AccessToken, token2.AccessToken
paddy@35 27 }
paddy@35 28 if token1.RefreshToken != token2.RefreshToken {
paddy@35 29 return false, "refresh token", token1.RefreshToken, token2.RefreshToken
paddy@35 30 }
paddy@35 31 if !token1.Created.Equal(token2.Created) {
paddy@35 32 return false, "created", token1.Created, token2.Created
paddy@35 33 }
paddy@97 34 if token1.CreatedFrom != token2.CreatedFrom {
paddy@97 35 return false, "created from", token1.CreatedFrom, token2.CreatedFrom
paddy@97 36 }
paddy@35 37 if token1.ExpiresIn != token2.ExpiresIn {
paddy@35 38 return false, "expires in", token1.ExpiresIn, token2.ExpiresIn
paddy@35 39 }
paddy@35 40 if token1.TokenType != token2.TokenType {
paddy@35 41 return false, "token type", token1.TokenType, token2.TokenType
paddy@35 42 }
paddy@135 43 if len(token1.Scopes) != len(token2.Scopes) {
paddy@135 44 return false, "scopes", token1.Scopes, token2.Scopes
paddy@135 45 }
paddy@135 46 for pos, scope := range token1.Scopes {
paddy@135 47 if scope != token2.Scopes[pos] {
paddy@135 48 return false, "scopes", token1.Scopes, token2.Scopes
paddy@135 49 }
paddy@35 50 }
paddy@35 51 if !token1.ProfileID.Equal(token2.ProfileID) {
paddy@35 52 return false, "profile ID", token1.ProfileID, token2.ProfileID
paddy@35 53 }
paddy@97 54 if token1.Revoked != token2.Revoked {
paddy@97 55 return false, "revoked", token1.Revoked, token2.Revoked
paddy@97 56 }
paddy@35 57 return true, "", nil, nil
paddy@35 58 }
paddy@35 59
paddy@28 60 func TestTokenStoreSuccess(t *testing.T) {
paddy@37 61 t.Parallel()
paddy@28 62 token := Token{
paddy@28 63 AccessToken: "access",
paddy@28 64 RefreshToken: "refresh",
paddy@149 65 Created: time.Now().Round(time.Millisecond),
paddy@28 66 ExpiresIn: 3600,
paddy@28 67 TokenType: "bearer",
paddy@181 68 Scopes: scopeTypes.StringsToScopes([]string{"scope"}),
paddy@28 69 ProfileID: uuid.NewID(),
paddy@28 70 }
paddy@35 71 for _, store := range tokenStores {
paddy@116 72 context := Context{tokens: store}
paddy@127 73 retrievedAccess, err := context.GetToken(token.AccessToken, false)
paddy@127 74 if err == nil {
paddy@127 75 t.Errorf("Expected ErrTokenNotFound from %T, got %+v", store, retrievedAccess)
paddy@127 76 } else if err != ErrTokenNotFound {
paddy@127 77 t.Errorf("Expected ErrTokenNotFound from %T, got %s", store, err)
paddy@127 78 }
paddy@127 79 retrievedRefresh, err := context.GetToken(token.RefreshToken, true)
paddy@127 80 if err == nil {
paddy@127 81 t.Errorf("Expected ErrTokenNotFound from %T, got %+v", store, retrievedRefresh)
paddy@127 82 } else if err != ErrTokenNotFound {
paddy@127 83 t.Errorf("Expected ErrTokenNotFound from %T, got %s", store, err)
paddy@127 84 }
paddy@168 85 err = context.RevokeToken(token.RefreshToken)
paddy@127 86 if err != ErrTokenNotFound {
paddy@127 87 t.Errorf("Expected ErrTokenNotFound from %T, got %s", store, err)
paddy@127 88 }
paddy@127 89 err = context.SaveToken(token)
paddy@28 90 if err != nil {
paddy@37 91 t.Errorf("Error saving token to %T: %s", store, err)
paddy@37 92 }
paddy@116 93 err = context.SaveToken(token)
paddy@37 94 if err != ErrTokenAlreadyExists {
paddy@37 95 t.Errorf("Expected ErrTokenAlreadyExists from %T, got %s", store, err)
paddy@28 96 }
paddy@127 97 retrievedAccess, err = context.GetToken(token.AccessToken, false)
paddy@28 98 if err != nil {
paddy@35 99 t.Errorf("Error retrieving token from %T: %s", store, err)
paddy@28 100 }
paddy@35 101 success, field, expectation, result := compareTokens(token, retrievedAccess)
paddy@35 102 if !success {
paddy@35 103 t.Errorf("Expected field %s to be %v, but got %v from %T", field, expectation, result, store)
paddy@35 104 }
paddy@127 105 retrievedRefresh, err = context.GetToken(token.RefreshToken, true)
paddy@28 106 if err != nil {
paddy@35 107 t.Errorf("Error retrieving refresh token from %T: %s", store, err)
paddy@28 108 }
paddy@35 109 success, field, expectation, result = compareTokens(token, retrievedRefresh)
paddy@35 110 if !success {
paddy@35 111 t.Errorf("Expected field %s to be %v, but got %v from %T", field, expectation, result, store)
paddy@35 112 }
paddy@116 113 retrievedProfile, err := context.GetTokensByProfileID(token.ProfileID, 25, 0)
paddy@28 114 if err != nil {
paddy@35 115 t.Errorf("Error retrieving token by profile from %T: %s", store, err)
paddy@28 116 }
paddy@28 117 if len(retrievedProfile) != 1 {
paddy@35 118 t.Errorf("Expected 1 token retrieved by profile ID from %T, got %+v", store, retrievedProfile)
paddy@28 119 }
paddy@35 120 success, field, expectation, result = compareTokens(token, retrievedProfile[0])
paddy@35 121 if !success {
paddy@35 122 t.Errorf("Expected field %s to be %v, but got %v from %T", field, expectation, result, store)
paddy@35 123 }
paddy@168 124 err = context.RevokeToken(token.RefreshToken)
paddy@97 125 if err != nil {
paddy@97 126 t.Errorf("Error revoking token in %T: %s", store, err)
paddy@97 127 }
paddy@116 128 retrievedRevoked, err := context.GetToken(token.AccessToken, false)
paddy@97 129 if err != nil {
paddy@97 130 t.Errorf("Error retrieving token from %T: %s", store, err)
paddy@97 131 }
paddy@97 132 token.Revoked = true
paddy@97 133 success, field, expectation, result = compareTokens(token, retrievedRevoked)
paddy@97 134 if !success {
paddy@97 135 t.Errorf("Expected field %s to be %v, but got %v from %T", field, expectation, result, store)
paddy@97 136 }
paddy@28 137 }
paddy@28 138 }
paddy@128 139
paddy@128 140 // BUG(paddy): We need to test the refreshTokenValidate function.
paddy@128 141 // BUG(paddy): We need to test the refreshTokenInvalidate function.