Skip to content

Commit d5d0aa8

Browse files
committed
Token Management - Implementation
1 parent 9219edc commit d5d0aa8

File tree

2 files changed

+263
-0
lines changed

2 files changed

+263
-0
lines changed

token/token.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package token
2+
3+
import (
4+
"time"
5+
6+
"github.com/redis/go-redis/v9/auth"
7+
)
8+
9+
// Ensure Token implements the auth.Credentials interface.
10+
var _ auth.Credentials = (*Token)(nil)
11+
12+
// New creates a new token with the specified username, password, raw token, expiration time, received at time, and time to live.
13+
// NOTE: This won't do any validation on the token, expiresOn, receivedAt, or ttl. It will simply create a new token instance.
14+
func New(username, password, rawToken string, expiresOn, receivedAt time.Time, ttl int64) *Token {
15+
return &Token{
16+
username: username,
17+
password: password,
18+
expiresOn: expiresOn,
19+
receivedAt: receivedAt,
20+
ttl: ttl,
21+
rawToken: rawToken,
22+
}
23+
}
24+
25+
// Token represents parsed authentication token used to access the Redis server.
26+
// It implements the auth.Credentials interface.
27+
type Token struct {
28+
// username is the username of the user.
29+
username string
30+
// password is the password of the user.
31+
password string
32+
// expiresOn is the expiration time of the token.
33+
expiresOn time.Time
34+
// ttl is the time to live of the token.
35+
ttl int64
36+
// rawToken is the authentication token.
37+
rawToken string
38+
// receivedAt is the time when the token was received.
39+
receivedAt time.Time
40+
}
41+
42+
// BasicAuth returns the username and password for basic authentication.
43+
func (t *Token) BasicAuth() (string, string) {
44+
return t.username, t.password
45+
}
46+
47+
// RawCredentials returns the raw credentials for authentication.
48+
func (t *Token) RawCredentials() string {
49+
return t.rawToken
50+
}
51+
52+
// ExpirationOn returns the expiration time of the token.
53+
func (t *Token) ExpirationOn() time.Time {
54+
return t.expiresOn
55+
}
56+
57+
// Copy creates a copy of the token.
58+
func (t *Token) Copy() *Token {
59+
return copyToken(t)
60+
}
61+
62+
// compareCredentials two tokens if they are the same credentials
63+
func (t *Token) compareCredentials(token *Token) bool {
64+
return t.username == token.username && t.password == token.password
65+
}
66+
67+
// compareRawCredentials two tokens if they are the same raw credentials
68+
func (t *Token) compareRawCredentials(token *Token) bool {
69+
return t.rawToken == token.rawToken
70+
}
71+
72+
// compareToken compares two tokens if they are the same token
73+
func (t *Token) compareToken(token *Token) bool {
74+
return t.compareCredentials(token) && t.compareRawCredentials(token)
75+
}
76+
77+
// copyToken creates a copy of the token.
78+
func copyToken(token *Token) *Token {
79+
if token == nil {
80+
return nil
81+
}
82+
return New(token.username, token.password, token.rawToken, token.expiresOn, token.receivedAt, token.ttl)
83+
}

token/token_test.go

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package token
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestNew(t *testing.T) {
11+
t.Parallel()
12+
token := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
13+
assert.Equal(t, "username", token.username)
14+
assert.Equal(t, "password", token.password)
15+
assert.Equal(t, "rawToken", token.rawToken)
16+
assert.Equal(t, int64(3600), token.ttl)
17+
}
18+
19+
func TestBasicAuth(t *testing.T) {
20+
t.Parallel()
21+
token := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
22+
username, password := token.BasicAuth()
23+
assert.Equal(t, "username", username)
24+
assert.Equal(t, "password", password)
25+
}
26+
27+
func TestRawCredentials(t *testing.T) {
28+
t.Parallel()
29+
token := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
30+
rawCredentials := token.RawCredentials()
31+
assert.Equal(t, "rawToken", rawCredentials)
32+
}
33+
34+
func TestExpirationOn(t *testing.T) {
35+
t.Parallel()
36+
token := New("username", "password", "rawToken", time.Now().Add(1*time.Hour), time.Now(), 3600)
37+
expirationOn := token.ExpirationOn()
38+
assert.True(t, expirationOn.After(time.Now()))
39+
}
40+
41+
func TestTokenExpiration(t *testing.T) {
42+
t.Parallel()
43+
token := New("username", "password", "rawToken", time.Now().Add(1*time.Hour), time.Now(), 3600)
44+
assert.True(t, token.ExpirationOn().After(time.Now()))
45+
46+
token.expiresOn = time.Now().Add(-1 * time.Hour)
47+
assert.False(t, token.ExpirationOn().After(time.Now()))
48+
}
49+
50+
func TestTokenReceivedAt(t *testing.T) {
51+
t.Parallel()
52+
token := New("username", "password", "rawToken", time.Now(), time.Now().Add(1*time.Hour), 3600)
53+
assert.True(t, token.receivedAt.After(time.Now().Add(-1*time.Hour)))
54+
assert.True(t, token.receivedAt.Before(time.Now().Add(1*time.Hour)))
55+
}
56+
57+
func TestTokenTTL(t *testing.T) {
58+
t.Parallel()
59+
token := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
60+
assert.Equal(t, int64(3600), token.ttl)
61+
62+
token.ttl = 7200
63+
assert.Equal(t, int64(7200), token.ttl)
64+
}
65+
66+
func TestCopyToken(t *testing.T) {
67+
t.Parallel()
68+
token := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
69+
copiedToken := copyToken(token)
70+
71+
assert.Equal(t, token.username, copiedToken.username)
72+
assert.Equal(t, token.password, copiedToken.password)
73+
assert.Equal(t, token.rawToken, copiedToken.rawToken)
74+
assert.Equal(t, token.ttl, copiedToken.ttl)
75+
assert.Equal(t, token.expiresOn, copiedToken.expiresOn)
76+
assert.Equal(t, token.receivedAt, copiedToken.receivedAt)
77+
78+
// change the copied token
79+
copiedToken.expiresOn = time.Now().Add(-1 * time.Hour)
80+
assert.NotEqual(t, token.expiresOn, copiedToken.expiresOn)
81+
82+
// copy nil
83+
copiedToken = copyToken(nil)
84+
assert.Nil(t, copiedToken)
85+
// copy empty token
86+
copiedToken = copyToken(&Token{})
87+
assert.NotNil(t, copiedToken)
88+
anotherCopy := copiedToken.Copy()
89+
anotherCopy.rawToken = "changed"
90+
assert.NotEqual(t, copiedToken, anotherCopy)
91+
}
92+
93+
func TestTokenCompare(t *testing.T) {
94+
t.Parallel()
95+
// Create two tokens with the same credentials
96+
token1 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
97+
token2 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
98+
assert.True(t, token1.compareCredentials(token2))
99+
assert.True(t, token1.compareRawCredentials(token2))
100+
assert.True(t, token1.compareToken(token2))
101+
102+
// Create two tokens with different credentials and different raw credentials
103+
token3 := New("username", "differentPassword", "differentRawToken", time.Now(), time.Now(), 3600)
104+
assert.False(t, token1.compareCredentials(token3))
105+
assert.False(t, token1.compareRawCredentials(token3))
106+
assert.False(t, token1.compareToken(token3))
107+
108+
// Create token with same credentials but different rawCredentials
109+
token4 := New("username", "password", "differentRawToken", time.Now(), time.Now(), 3600)
110+
assert.False(t, token1.compareRawCredentials(token4))
111+
assert.False(t, token1.compareToken(token4))
112+
assert.True(t, token1.compareCredentials(token4))
113+
}
114+
115+
func BenchmarkNew(b *testing.B) {
116+
now := time.Now()
117+
b.ResetTimer()
118+
for i := 0; i < b.N; i++ {
119+
New("username", "password", "rawToken", now, now, 3600)
120+
}
121+
}
122+
123+
func BenchmarkBasicAuth(b *testing.B) {
124+
token := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
125+
b.ResetTimer()
126+
for i := 0; i < b.N; i++ {
127+
token.BasicAuth()
128+
}
129+
}
130+
131+
func BenchmarkRawCredentials(b *testing.B) {
132+
token := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
133+
b.ResetTimer()
134+
for i := 0; i < b.N; i++ {
135+
token.RawCredentials()
136+
}
137+
}
138+
139+
func BenchmarkExpirationOn(b *testing.B) {
140+
token := New("username", "password", "rawToken", time.Now().Add(1*time.Hour), time.Now(), 3600)
141+
b.ResetTimer()
142+
for i := 0; i < b.N; i++ {
143+
token.ExpirationOn()
144+
}
145+
}
146+
147+
func BenchmarkCopyToken(b *testing.B) {
148+
token := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
149+
b.ResetTimer()
150+
for i := 0; i < b.N; i++ {
151+
token.Copy()
152+
}
153+
}
154+
155+
func BenchmarkCompareCredentials(b *testing.B) {
156+
token1 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
157+
token2 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
158+
b.ResetTimer()
159+
for i := 0; i < b.N; i++ {
160+
token1.compareCredentials(token2)
161+
}
162+
}
163+
164+
func BenchmarkCompareRawCredentials(b *testing.B) {
165+
token1 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
166+
token2 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
167+
b.ResetTimer()
168+
for i := 0; i < b.N; i++ {
169+
token1.compareRawCredentials(token2)
170+
}
171+
}
172+
173+
func BenchmarkCompareToken(b *testing.B) {
174+
token1 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
175+
token2 := New("username", "password", "rawToken", time.Now(), time.Now(), 3600)
176+
b.ResetTimer()
177+
for i := 0; i < b.N; i++ {
178+
token1.compareToken(token2)
179+
}
180+
}

0 commit comments

Comments
 (0)