2022-03-03 11:20:43 +00:00
|
|
|
package totp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base32"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2022-04-07 23:01:01 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2022-03-03 11:20:43 +00:00
|
|
|
|
|
|
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestTOTPGenerateCustom(t *testing.T) {
|
2022-04-07 23:01:01 +00:00
|
|
|
testCases := []struct {
|
|
|
|
desc string
|
|
|
|
username, algorithm, secret string
|
|
|
|
digits, period, secretSize uint
|
|
|
|
err string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "ShouldGenerateSHA1",
|
|
|
|
username: "john",
|
|
|
|
algorithm: "SHA1",
|
|
|
|
digits: 6,
|
|
|
|
period: 30,
|
|
|
|
secretSize: 32,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "ShouldGenerateLongSecret",
|
|
|
|
username: "john",
|
|
|
|
algorithm: "SHA1",
|
|
|
|
digits: 6,
|
|
|
|
period: 30,
|
|
|
|
secretSize: 42,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "ShouldGenerateSHA256",
|
|
|
|
username: "john",
|
|
|
|
algorithm: "SHA256",
|
|
|
|
digits: 6,
|
|
|
|
period: 30,
|
|
|
|
secretSize: 32,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "ShouldGenerateSHA512",
|
|
|
|
username: "john",
|
|
|
|
algorithm: "SHA512",
|
|
|
|
digits: 6,
|
|
|
|
period: 30,
|
|
|
|
secretSize: 32,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "ShouldGenerateWithSecret",
|
|
|
|
username: "john",
|
|
|
|
algorithm: "SHA512",
|
|
|
|
secret: "ONTGOYLTMZQXGZDBONSGC43EMFZWMZ3BONTWMYLTMRQXGZBSGMYTEMZRMFYXGZDBONSA",
|
|
|
|
digits: 6,
|
|
|
|
period: 30,
|
|
|
|
secretSize: 32,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "ShouldGenerateWithBadSecretB32Data",
|
|
|
|
username: "john",
|
|
|
|
algorithm: "SHA512",
|
|
|
|
secret: "@#UNH$IK!J@N#EIKJ@U!NIJKUN@#WIK",
|
|
|
|
digits: 6,
|
|
|
|
period: 30,
|
|
|
|
secretSize: 32,
|
|
|
|
err: "totp generate failed: error decoding base32 string: illegal base32 data at input byte 0",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "ShouldGenerateWithBadSecretLength",
|
|
|
|
username: "john",
|
|
|
|
algorithm: "SHA512",
|
|
|
|
secret: "ONTGOYLTMZQXGZD",
|
|
|
|
digits: 6,
|
|
|
|
period: 30,
|
|
|
|
secretSize: 0,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-01-26 02:23:47 +00:00
|
|
|
totp := NewTimeBasedProvider(schema.TOTP{
|
2022-04-07 23:01:01 +00:00
|
|
|
Issuer: "Authelia",
|
|
|
|
Algorithm: "SHA1",
|
|
|
|
Digits: 6,
|
|
|
|
Period: 30,
|
|
|
|
SecretSize: 32,
|
2022-03-03 11:20:43 +00:00
|
|
|
})
|
|
|
|
|
2022-04-07 23:01:01 +00:00
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
|
|
c, err := totp.GenerateCustom(tc.username, tc.algorithm, tc.secret, tc.digits, tc.period, tc.secretSize)
|
|
|
|
if tc.err == "" {
|
|
|
|
assert.NoError(t, err)
|
|
|
|
require.NotNil(t, c)
|
|
|
|
assert.Equal(t, tc.period, c.Period)
|
|
|
|
assert.Equal(t, tc.digits, c.Digits)
|
|
|
|
assert.Equal(t, tc.algorithm, c.Algorithm)
|
|
|
|
|
|
|
|
expectedSecretLen := int(tc.secretSize)
|
|
|
|
if tc.secret != "" {
|
|
|
|
expectedSecretLen = base32.StdEncoding.WithPadding(base32.NoPadding).DecodedLen(len(tc.secret))
|
|
|
|
}
|
|
|
|
|
|
|
|
secret := make([]byte, expectedSecretLen)
|
|
|
|
|
|
|
|
n, err := base32.StdEncoding.WithPadding(base32.NoPadding).Decode(secret, c.Secret)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Len(t, secret, expectedSecretLen)
|
|
|
|
assert.Equal(t, expectedSecretLen, n)
|
|
|
|
} else {
|
|
|
|
assert.Nil(t, c)
|
|
|
|
assert.EqualError(t, err, tc.err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2022-03-03 11:20:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestTOTPGenerate(t *testing.T) {
|
|
|
|
skew := uint(2)
|
|
|
|
|
2023-01-26 02:23:47 +00:00
|
|
|
totp := NewTimeBasedProvider(schema.TOTP{
|
2022-04-07 23:01:01 +00:00
|
|
|
Issuer: "Authelia",
|
|
|
|
Algorithm: "SHA256",
|
|
|
|
Digits: 8,
|
|
|
|
Period: 60,
|
|
|
|
Skew: &skew,
|
|
|
|
SecretSize: 32,
|
2022-03-03 11:20:43 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
assert.Equal(t, uint(2), totp.skew)
|
|
|
|
|
|
|
|
config, err := totp.Generate("john")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Equal(t, "Authelia", config.Issuer)
|
|
|
|
|
|
|
|
assert.Less(t, time.Since(config.CreatedAt), time.Second)
|
|
|
|
assert.Greater(t, time.Since(config.CreatedAt), time.Second*-1)
|
|
|
|
|
|
|
|
assert.Equal(t, uint(8), config.Digits)
|
|
|
|
assert.Equal(t, uint(60), config.Period)
|
|
|
|
assert.Equal(t, "SHA256", config.Algorithm)
|
|
|
|
|
|
|
|
secret := make([]byte, base32.StdEncoding.WithPadding(base32.NoPadding).DecodedLen(len(config.Secret)))
|
|
|
|
|
|
|
|
_, err = base32.StdEncoding.WithPadding(base32.NoPadding).Decode(secret, config.Secret)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Len(t, secret, 32)
|
|
|
|
}
|