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