coder/coderd/apikey/apikey_test.go

175 lines
4.9 KiB
Go

package apikey_test
import (
"crypto/sha256"
"strings"
"testing"
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/coderd/apikey"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbtime"
)
func TestGenerate(t *testing.T) {
t.Parallel()
type testcase struct {
name string
params apikey.CreateParams
fail bool
}
cases := []testcase{
{
name: "OK",
params: apikey.CreateParams{
UserID: uuid.New(),
LoginType: database.LoginTypeOIDC,
DefaultLifetime: time.Duration(0),
ExpiresAt: time.Now().Add(time.Hour),
LifetimeSeconds: int64(time.Hour.Seconds()),
TokenName: "hello",
RemoteAddr: "1.2.3.4",
Scope: database.APIKeyScopeApplicationConnect,
},
},
{
name: "InvalidScope",
params: apikey.CreateParams{
UserID: uuid.New(),
LoginType: database.LoginTypeOIDC,
DefaultLifetime: time.Duration(0),
ExpiresAt: time.Now().Add(time.Hour),
LifetimeSeconds: int64(time.Hour.Seconds()),
TokenName: "hello",
RemoteAddr: "1.2.3.4",
Scope: database.APIKeyScope("test"),
},
fail: true,
},
{
name: "DeploymentSessionDuration",
params: apikey.CreateParams{
UserID: uuid.New(),
LoginType: database.LoginTypeOIDC,
DefaultLifetime: time.Hour,
LifetimeSeconds: 0,
ExpiresAt: time.Time{},
TokenName: "hello",
RemoteAddr: "1.2.3.4",
Scope: database.APIKeyScopeApplicationConnect,
},
},
{
name: "LifetimeSeconds",
params: apikey.CreateParams{
UserID: uuid.New(),
LoginType: database.LoginTypeOIDC,
DefaultLifetime: time.Duration(0),
LifetimeSeconds: int64(time.Hour.Seconds()),
ExpiresAt: time.Time{},
TokenName: "hello",
RemoteAddr: "1.2.3.4",
Scope: database.APIKeyScopeApplicationConnect,
},
},
{
name: "DefaultIP",
params: apikey.CreateParams{
UserID: uuid.New(),
LoginType: database.LoginTypeOIDC,
DefaultLifetime: time.Duration(0),
ExpiresAt: time.Now().Add(time.Hour),
LifetimeSeconds: int64(time.Hour.Seconds()),
TokenName: "hello",
RemoteAddr: "",
Scope: database.APIKeyScopeApplicationConnect,
},
},
{
name: "DefaultScope",
params: apikey.CreateParams{
UserID: uuid.New(),
LoginType: database.LoginTypeOIDC,
DefaultLifetime: time.Duration(0),
ExpiresAt: time.Now().Add(time.Hour),
LifetimeSeconds: int64(time.Hour.Seconds()),
TokenName: "hello",
RemoteAddr: "1.2.3.4",
Scope: "",
},
},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
key, keystr, err := apikey.Generate(tc.params)
if tc.fail {
require.Error(t, err)
return
}
require.NoError(t, err)
require.NotEmpty(t, keystr)
require.NotEmpty(t, key.ID)
require.NotEmpty(t, key.HashedSecret)
// Assert the string secret is formatted correctly
keytokens := strings.Split(keystr, "-")
require.Len(t, keytokens, 2)
require.Equal(t, key.ID, keytokens[0])
// Assert that the hashed secret is correct.
hashed := sha256.Sum256([]byte(keytokens[1]))
assert.ElementsMatch(t, hashed, key.HashedSecret[:])
assert.Equal(t, tc.params.UserID, key.UserID)
assert.WithinDuration(t, dbtime.Now(), key.CreatedAt, time.Second*5)
assert.WithinDuration(t, dbtime.Now(), key.UpdatedAt, time.Second*5)
if tc.params.LifetimeSeconds > 0 {
assert.Equal(t, tc.params.LifetimeSeconds, key.LifetimeSeconds)
} else if !tc.params.ExpiresAt.IsZero() {
// Should not be a delta greater than 5 seconds.
assert.InDelta(t, time.Until(tc.params.ExpiresAt).Seconds(), key.LifetimeSeconds, 5)
} else {
assert.Equal(t, int64(tc.params.DefaultLifetime.Seconds()), key.LifetimeSeconds)
}
if !tc.params.ExpiresAt.IsZero() {
assert.Equal(t, tc.params.ExpiresAt.UTC(), key.ExpiresAt)
} else if tc.params.LifetimeSeconds > 0 {
assert.WithinDuration(t, dbtime.Now().Add(time.Duration(tc.params.LifetimeSeconds)*time.Second), key.ExpiresAt, time.Second*5)
} else {
assert.WithinDuration(t, dbtime.Now().Add(tc.params.DefaultLifetime), key.ExpiresAt, time.Second*5)
}
if tc.params.RemoteAddr != "" {
assert.Equal(t, tc.params.RemoteAddr, key.IPAddress.IPNet.IP.String())
} else {
assert.Equal(t, "0.0.0.0", key.IPAddress.IPNet.IP.String())
}
if tc.params.Scope != "" {
assert.Equal(t, tc.params.Scope, key.Scope)
} else {
assert.Equal(t, database.APIKeyScopeAll, key.Scope)
}
if tc.params.TokenName != "" {
assert.Equal(t, tc.params.TokenName, key.TokenName)
}
if tc.params.LoginType != "" {
assert.Equal(t, tc.params.LoginType, key.LoginType)
}
})
}
}