auth

Paddy 2015-01-28 Parent:23c1a07c8a61 Child:d30a3a12d387

132:163ce22fa4c9 Go to Latest

auth/token_test.go

Enable CSRF protection, add expiration to sessions. Sessions gain a CSRF token, which is passed as a parameter to the login page. The login page now checks for that CSRF token, and logs a CSRF attempt if the token does not match. I also added an expiration to sessions, so they don't last forever. Sessions should be pretty short--we just need to stay logged in for long enough to approve the OAuth request. Everything after that should be cookie based. Finally, I added a configuration parameter to control whether the session cookie should be set to Secure, requiring the use of HTTPS. For production use, this flag is a requirement, but it makes testing extremely difficult, so we need a way to disable it.

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