mirror of https://github.com/authelia/authelia.git
2219 lines
56 KiB
Go
2219 lines
56 KiB
Go
package configuration_test
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/ecdsa"
|
|
"crypto/ed25519"
|
|
"crypto/rsa"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"math"
|
|
"net/mail"
|
|
"net/url"
|
|
"os"
|
|
"reflect"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/authelia/authelia/v4/internal/configuration"
|
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
)
|
|
|
|
func TestStringToMailAddressHookFunc(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
desc: "ShouldDecodeMailAddress",
|
|
have: "james@example.com",
|
|
want: mail.Address{Name: "", Address: "james@example.com"},
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeMailAddressWithName",
|
|
have: "James <james@example.com>",
|
|
want: mail.Address{Name: "James", Address: "james@example.com"},
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeMailAddressWithEmptyString",
|
|
have: "",
|
|
want: mail.Address{},
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeInvalidMailAddress",
|
|
have: "fred",
|
|
want: mail.Address{},
|
|
err: "could not decode 'fred' to a mail.Address (RFC5322): mail: missing '@' or angle-addr",
|
|
decode: true,
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToMailAddressHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringToMailAddressHookFuncPointer(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
desc: "ShouldDecodeMailAddress",
|
|
have: "james@example.com",
|
|
want: &mail.Address{Name: "", Address: "james@example.com"},
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeMailAddressWithName",
|
|
have: "James <james@example.com>",
|
|
want: &mail.Address{Name: "James", Address: "james@example.com"},
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeMailAddressWithEmptyString",
|
|
have: "",
|
|
want: (*mail.Address)(nil),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeInvalidMailAddress",
|
|
have: "fred",
|
|
want: &mail.Address{},
|
|
err: "could not decode 'fred' to a *mail.Address (RFC5322): mail: missing '@' or angle-addr",
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToInt",
|
|
have: "fred",
|
|
want: testInt32Ptr(4),
|
|
decode: false,
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToMailAddressHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringToURLHookFunc(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
desc: "ShouldDecodeURL",
|
|
have: "https://www.example.com:9090/abc?test=true",
|
|
want: url.URL{Scheme: "https", Host: "www.example.com:9090", Path: "/abc", RawQuery: "test=true"},
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeURLEmptyString",
|
|
have: "",
|
|
want: url.URL{},
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToString",
|
|
have: "abc",
|
|
want: "",
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeURLWithUserAndPassword",
|
|
have: "https://john:abc123@www.example.com:9090/abc?test=true",
|
|
want: url.URL{Scheme: "https", Host: "www.example.com:9090", Path: "/abc", RawQuery: "test=true", User: url.UserPassword("john", "abc123")},
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeInt",
|
|
have: 5,
|
|
want: url.URL{},
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeBool",
|
|
have: true,
|
|
want: url.URL{},
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeBadURL",
|
|
have: "*(!&@#(!*^$%",
|
|
want: url.URL{},
|
|
err: "could not decode '*(!&@#(!*^$%' to a url.URL: parse \"*(!&@#(!*^$%\": invalid URL escape \"%\"",
|
|
decode: true,
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToURLHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringToURLHookFuncPointer(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
desc: "ShouldDecodeURL",
|
|
have: "https://www.example.com:9090/abc?test=true",
|
|
want: &url.URL{Scheme: "https", Host: "www.example.com:9090", Path: "/abc", RawQuery: "test=true"},
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeURLEmptyString",
|
|
have: "",
|
|
want: (*url.URL)(nil),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeURLWithUserAndPassword",
|
|
have: "https://john:abc123@www.example.com:9090/abc?test=true",
|
|
want: &url.URL{Scheme: "https", Host: "www.example.com:9090", Path: "/abc", RawQuery: "test=true", User: url.UserPassword("john", "abc123")},
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeInt",
|
|
have: 5,
|
|
want: &url.URL{},
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeBool",
|
|
have: true,
|
|
want: &url.URL{},
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeBadURL",
|
|
have: "*(!&@#(!*^$%",
|
|
want: &url.URL{},
|
|
err: "could not decode '*(!&@#(!*^$%' to a *url.URL: parse \"*(!&@#(!*^$%\": invalid URL escape \"%\"",
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToInt",
|
|
have: "fred",
|
|
want: testInt32Ptr(4),
|
|
decode: false,
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToURLHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestToTimeDurationHookFunc(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
desc: "ShouldDecodeFourtyFiveSeconds",
|
|
have: "45s",
|
|
want: time.Second * 45,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeOneMinute",
|
|
have: "1m",
|
|
want: time.Minute,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeTwoHours",
|
|
have: "2h",
|
|
want: time.Hour * 2,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeThreeDays",
|
|
have: "3d",
|
|
want: time.Hour * 24 * 3,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFourWeeks",
|
|
have: "4w",
|
|
want: time.Hour * 24 * 7 * 4,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFiveMonths",
|
|
have: "5M",
|
|
want: time.Hour * 24 * 30 * 5,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeSixYears",
|
|
have: "6y",
|
|
want: time.Hour * 24 * 365 * 6,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeInvalidString",
|
|
have: "abc",
|
|
want: time.Duration(0),
|
|
err: "could not decode 'abc' to a time.Duration: could not parse 'abc' as a duration",
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeIntToSeconds",
|
|
have: 60,
|
|
want: time.Second * 60,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt8ToSeconds",
|
|
have: int8(90),
|
|
want: time.Second * 90,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt16ToSeconds",
|
|
have: int16(90),
|
|
want: time.Second * 90,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt32ToSeconds",
|
|
have: int32(90),
|
|
want: time.Second * 90,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFloat64ToSeconds",
|
|
have: float64(90),
|
|
want: time.Second * 90,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFloat64ToSeconds",
|
|
have: math.MaxFloat64,
|
|
want: time.Duration(math.MaxInt64),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt64ToSeconds",
|
|
have: int64(120),
|
|
want: time.Second * 120,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeTimeDuration",
|
|
have: time.Second * 30,
|
|
want: time.Second * 30,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToString",
|
|
have: int64(30),
|
|
want: "",
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFromIntZero",
|
|
have: 0,
|
|
want: time.Duration(0),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldSkipParsingBoolean",
|
|
have: true,
|
|
want: time.Duration(0),
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeFromBool",
|
|
have: true,
|
|
want: true,
|
|
},
|
|
}
|
|
|
|
hook := configuration.ToTimeDurationHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestToTimeDurationHookFuncPointer(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
desc: "ShouldDecodeFourtyFiveSeconds",
|
|
have: "45s",
|
|
want: testTimeDurationPtr(time.Second * 45),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeOneMinute",
|
|
have: "1m",
|
|
want: testTimeDurationPtr(time.Minute),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeTwoHours",
|
|
have: "2h",
|
|
want: testTimeDurationPtr(time.Hour * 2),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeThreeDays",
|
|
have: "3d",
|
|
want: testTimeDurationPtr(time.Hour * 24 * 3),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFourWeeks",
|
|
have: "4w",
|
|
want: testTimeDurationPtr(time.Hour * 24 * 7 * 4),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFiveMonths",
|
|
have: "5M",
|
|
want: testTimeDurationPtr(time.Hour * 24 * 30 * 5),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeSixYears",
|
|
have: "6y",
|
|
want: testTimeDurationPtr(time.Hour * 24 * 365 * 6),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeInvalidString",
|
|
have: "abc",
|
|
want: testTimeDurationPtr(time.Duration(0)),
|
|
err: "could not decode 'abc' to a *time.Duration: could not parse 'abc' as a duration",
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeIntToSeconds",
|
|
have: 60,
|
|
want: testTimeDurationPtr(time.Second * 60),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt32ToSeconds",
|
|
have: int32(90),
|
|
want: testTimeDurationPtr(time.Second * 90),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt64ToSeconds",
|
|
have: int64(120),
|
|
want: testTimeDurationPtr(time.Second * 120),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeTimeDuration",
|
|
have: time.Second * 30,
|
|
want: testTimeDurationPtr(time.Second * 30),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToString",
|
|
have: int64(30),
|
|
want: &testString,
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFromIntZero",
|
|
have: 0,
|
|
want: testTimeDurationPtr(time.Duration(0)),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeFromBool",
|
|
have: true,
|
|
want: &testTrue,
|
|
decode: false,
|
|
},
|
|
}
|
|
|
|
hook := configuration.ToTimeDurationHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestToRefreshIntervalDurationHookFunc(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
desc: "ShouldDecodeFourtyFiveSeconds",
|
|
have: "45s",
|
|
want: schema.NewRefreshIntervalDuration(time.Second * 45),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeOneMinute",
|
|
have: "1m",
|
|
want: schema.NewRefreshIntervalDuration(time.Minute),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeTwoHours",
|
|
have: "2h",
|
|
want: schema.NewRefreshIntervalDuration(time.Hour * 2),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeThreeDays",
|
|
have: "3d",
|
|
want: schema.NewRefreshIntervalDuration(time.Hour * 24 * 3),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFourWeeks",
|
|
have: "4w",
|
|
want: schema.NewRefreshIntervalDuration(time.Hour * 24 * 7 * 4),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFiveMonths",
|
|
have: "5M",
|
|
want: schema.NewRefreshIntervalDuration(time.Hour * 24 * 30 * 5),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeSixYears",
|
|
have: "6y",
|
|
want: schema.NewRefreshIntervalDuration(time.Hour * 24 * 365 * 6),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeInvalidString",
|
|
have: "abc",
|
|
want: schema.RefreshIntervalDuration{},
|
|
err: "could not decode 'abc' to a schema.RefreshIntervalDuration: could not parse 'abc' as a duration",
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeIntToSeconds",
|
|
have: 60,
|
|
want: schema.NewRefreshIntervalDuration(time.Second * 60),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt8ToSeconds",
|
|
have: int8(90),
|
|
want: schema.NewRefreshIntervalDuration(time.Second * 90),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt16ToSeconds",
|
|
have: int16(90),
|
|
want: schema.NewRefreshIntervalDuration(time.Second * 90),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt32ToSeconds",
|
|
have: int32(90),
|
|
want: schema.NewRefreshIntervalDuration(time.Second * 90),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFloat64ToSeconds",
|
|
have: float64(90),
|
|
want: schema.NewRefreshIntervalDuration(time.Second * 90),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFloat64ToSeconds",
|
|
have: math.MaxFloat64,
|
|
want: schema.NewRefreshIntervalDuration(time.Duration(math.MaxInt64)),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt64ToSeconds",
|
|
have: int64(120),
|
|
want: schema.NewRefreshIntervalDuration(time.Second * 120),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeTimeDuration",
|
|
have: time.Second * 30,
|
|
want: schema.NewRefreshIntervalDuration(time.Second * 30),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToString",
|
|
have: int64(30),
|
|
want: "",
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFromIntZero",
|
|
have: 0,
|
|
want: schema.NewRefreshIntervalDuration(time.Duration(0)),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldSkipParsingBoolean",
|
|
have: true,
|
|
want: schema.RefreshIntervalDuration{},
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeFromBool",
|
|
have: true,
|
|
want: true,
|
|
},
|
|
}
|
|
|
|
hook := configuration.ToRefreshIntervalDurationHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTestToRefreshIntervalDurationHookFuncPointer(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
desc: "ShouldDecodeFourtyFiveSeconds",
|
|
have: "45s",
|
|
want: testRefreshIntervalDurationPtr(time.Second * 45),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeOneMinute",
|
|
have: "1m",
|
|
want: testRefreshIntervalDurationPtr(time.Minute),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeTwoHours",
|
|
have: "2h",
|
|
want: testRefreshIntervalDurationPtr(time.Hour * 2),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeThreeDays",
|
|
have: "3d",
|
|
want: testRefreshIntervalDurationPtr(time.Hour * 24 * 3),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFourWeeks",
|
|
have: "4w",
|
|
want: testRefreshIntervalDurationPtr(time.Hour * 24 * 7 * 4),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFiveMonths",
|
|
have: "5M",
|
|
want: testRefreshIntervalDurationPtr(time.Hour * 24 * 30 * 5),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeSixYears",
|
|
have: "6y",
|
|
want: testRefreshIntervalDurationPtr(time.Hour * 24 * 365 * 6),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeInvalidString",
|
|
have: "abc",
|
|
want: testRefreshIntervalDurationPtr(time.Duration(0)),
|
|
err: "could not decode 'abc' to a *schema.RefreshIntervalDuration: could not parse 'abc' as a duration",
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeIntToSeconds",
|
|
have: 60,
|
|
want: testRefreshIntervalDurationPtr(time.Second * 60),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt32ToSeconds",
|
|
have: int32(90),
|
|
want: testRefreshIntervalDurationPtr(time.Second * 90),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeInt64ToSeconds",
|
|
have: int64(120),
|
|
want: testRefreshIntervalDurationPtr(time.Second * 120),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeTimeDuration",
|
|
have: time.Second * 30,
|
|
want: testRefreshIntervalDurationPtr(time.Second * 30),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToString",
|
|
have: int64(30),
|
|
want: &testString,
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeFromIntZero",
|
|
have: 0,
|
|
want: testRefreshIntervalDurationPtr(time.Duration(0)),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeFromBool",
|
|
have: true,
|
|
want: &testTrue,
|
|
decode: false,
|
|
},
|
|
}
|
|
|
|
hook := configuration.ToRefreshIntervalDurationHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringToRegexpFunc(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
wantGrps []string
|
|
}{
|
|
{
|
|
desc: "ShouldNotDecodeRegexpWithOpenParenthesis",
|
|
have: "hello(test one two",
|
|
want: regexp.Regexp{},
|
|
err: "could not decode 'hello(test one two' to a regexp.Regexp: error parsing regexp: missing closing ): `hello(test one two`",
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeValidRegex",
|
|
have: "^(api|admin)$",
|
|
want: *regexp.MustCompile(`^(api|admin)$`),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeValidRegexWithGroupNames",
|
|
have: "^(?P<area>api|admin)(one|two)$",
|
|
want: *regexp.MustCompile(`^(?P<area>api|admin)(one|two)$`),
|
|
decode: true,
|
|
wantGrps: []string{"area"},
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeFromInt32",
|
|
have: int32(20),
|
|
want: regexp.Regexp{},
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeFromBool",
|
|
have: false,
|
|
want: regexp.Regexp{},
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToBool",
|
|
have: "^(?P<area>api|admin)(one|two)$",
|
|
want: testTrue,
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToInt32",
|
|
have: "^(?P<area>api|admin)(one|two)$",
|
|
want: testInt32Ptr(0),
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToMailAddress",
|
|
have: "^(?P<area>api|admin)(one|two)$",
|
|
want: mail.Address{},
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldErrOnDecodeEmptyString",
|
|
have: "",
|
|
want: regexp.Regexp{},
|
|
err: "could not decode an empty value to a regexp.Regexp: must have a non-empty value",
|
|
decode: true,
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToRegexpHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
|
|
var names []string
|
|
|
|
pattern := result.(regexp.Regexp)
|
|
for _, name := range pattern.SubexpNames() {
|
|
if name != "" {
|
|
names = append(names, name)
|
|
}
|
|
}
|
|
|
|
if len(tc.wantGrps) != 0 {
|
|
t.Run("MustHaveAllExpectedSubexpGroupNames", func(t *testing.T) {
|
|
for _, name := range tc.wantGrps {
|
|
assert.Contains(t, names, name)
|
|
}
|
|
})
|
|
t.Run("MustNotHaveUnexpectedSubexpGroupNames", func(t *testing.T) {
|
|
for _, name := range names {
|
|
assert.Contains(t, tc.wantGrps, name)
|
|
}
|
|
})
|
|
} else {
|
|
t.Run("MustHaveNoSubexpGroupNames", func(t *testing.T) {
|
|
assert.Len(t, names, 0)
|
|
})
|
|
}
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringToRegexpFuncPointers(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
wantGrps []string
|
|
}{
|
|
{
|
|
desc: "ShouldNotDecodeRegexpWithOpenParenthesis",
|
|
have: "hello(test one two",
|
|
want: ®exp.Regexp{},
|
|
err: "could not decode 'hello(test one two' to a *regexp.Regexp: error parsing regexp: missing closing ): `hello(test one two`",
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeValidRegex",
|
|
have: "^(api|admin)$",
|
|
want: regexp.MustCompile(`^(api|admin)$`),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeValidRegexWithGroupNames",
|
|
have: "^(?P<area>api|admin)(one|two)$",
|
|
want: regexp.MustCompile(`^(?P<area>api|admin)(one|two)$`),
|
|
decode: true,
|
|
wantGrps: []string{"area"},
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeFromInt32",
|
|
have: int32(20),
|
|
want: ®exp.Regexp{},
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeFromBool",
|
|
have: false,
|
|
want: ®exp.Regexp{},
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToBool",
|
|
have: "^(?P<area>api|admin)(one|two)$",
|
|
want: &testTrue,
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToInt32",
|
|
have: "^(?P<area>api|admin)(one|two)$",
|
|
want: &testZero,
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToMailAddress",
|
|
have: "^(?P<area>api|admin)(one|two)$",
|
|
want: &mail.Address{},
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeEmptyStringToNil",
|
|
have: "",
|
|
want: (*regexp.Regexp)(nil),
|
|
decode: true,
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToRegexpHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
|
|
pattern := result.(*regexp.Regexp)
|
|
|
|
if tc.want == (*regexp.Regexp)(nil) {
|
|
assert.Nil(t, pattern)
|
|
} else {
|
|
var names []string
|
|
|
|
for _, name := range pattern.SubexpNames() {
|
|
if name != "" {
|
|
names = append(names, name)
|
|
}
|
|
}
|
|
|
|
if len(tc.wantGrps) != 0 {
|
|
t.Run("MustHaveAllExpectedSubexpGroupNames", func(t *testing.T) {
|
|
for _, name := range tc.wantGrps {
|
|
assert.Contains(t, names, name)
|
|
}
|
|
})
|
|
t.Run("MustNotHaveUnexpectedSubexpGroupNames", func(t *testing.T) {
|
|
for _, name := range names {
|
|
assert.Contains(t, tc.wantGrps, name)
|
|
}
|
|
})
|
|
} else {
|
|
t.Run("MustHaveNoSubexpGroupNames", func(t *testing.T) {
|
|
assert.Len(t, names, 0)
|
|
})
|
|
}
|
|
}
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringToAddressHookFunc(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
have any
|
|
expected any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
name: "ShouldDecodeNonPtr",
|
|
have: "tcp://0.0.0.0:2020",
|
|
expected: MustParseAddress("tcp://0.0.0.0:2020"),
|
|
decode: true,
|
|
},
|
|
{
|
|
name: "ShouldDecodePtr",
|
|
have: "tcp://0.0.0.0:2020",
|
|
expected: MustParseAddressPtr("tcp://0.0.0.0:2020"),
|
|
decode: true,
|
|
},
|
|
{
|
|
name: "ShouldNotDecodeIntegerToCorrectType",
|
|
have: 1,
|
|
expected: schema.Address{},
|
|
decode: false,
|
|
},
|
|
{
|
|
name: "ShouldNotDecodeIntegerToCorrectTypePtr",
|
|
have: 1,
|
|
expected: &schema.Address{},
|
|
decode: false,
|
|
},
|
|
{
|
|
name: "ShouldNotDecodeIntegerPtrToCorrectType",
|
|
have: testInt32Ptr(1),
|
|
expected: schema.Address{},
|
|
decode: false,
|
|
},
|
|
{
|
|
name: "ShouldNotDecodeIntegerPtrToCorrectTypePtr",
|
|
have: testInt32Ptr(1),
|
|
expected: &schema.Address{},
|
|
decode: false,
|
|
},
|
|
{
|
|
name: "ShouldNotDecodeToString",
|
|
have: "tcp://0.0.0.0:2020",
|
|
expected: "",
|
|
decode: false,
|
|
},
|
|
{
|
|
name: "ShouldNotDecodeToIntPtr",
|
|
have: "tcp://0.0.0.0:2020",
|
|
expected: testInt32Ptr(1),
|
|
decode: false,
|
|
},
|
|
{
|
|
name: "ShouldNotDecodeToIntPtr",
|
|
have: "tcp://0.0.0.0:2020",
|
|
expected: testInt32Ptr(1),
|
|
decode: false,
|
|
},
|
|
{
|
|
name: "ShouldFailDecode",
|
|
have: "tcp://&!@^#*&!@#&*@!:2020",
|
|
expected: schema.Address{},
|
|
err: "could not decode 'tcp://&!@^#*&!@#&*@!:2020' to a schema.Address: could not parse string 'tcp://&!@^#*&!@#&*@!:2020' as address: expected format is [<scheme>://]<hostname>[:<port>]: parse \"tcp://&!@^\": invalid character \"^\" in host name",
|
|
decode: false,
|
|
},
|
|
{
|
|
name: "ShouldDecodeTCP",
|
|
have: "tcp://127.0.0.1",
|
|
expected: schema.AddressTCP{Address: MustParseAddress("tcp://127.0.0.1")},
|
|
err: "",
|
|
decode: true,
|
|
},
|
|
{
|
|
name: "ShouldDecodeTCPPtr",
|
|
have: "tcp://127.0.0.1",
|
|
expected: &schema.AddressTCP{Address: MustParseAddress("tcp://127.0.0.1")},
|
|
err: "",
|
|
decode: true,
|
|
},
|
|
{
|
|
name: "ShouldDecodeUDP",
|
|
have: "udp://127.0.0.1",
|
|
expected: schema.AddressUDP{Address: MustParseAddress("udp://127.0.0.1")},
|
|
err: "",
|
|
decode: true,
|
|
},
|
|
{
|
|
name: "ShouldDecodeUDPPtr",
|
|
have: "udp://127.0.0.1",
|
|
expected: &schema.AddressUDP{Address: MustParseAddress("udp://127.0.0.1")},
|
|
err: "",
|
|
decode: true,
|
|
},
|
|
{
|
|
name: "ShouldDecodeLDAP",
|
|
have: "ldap://127.0.0.1",
|
|
expected: schema.AddressLDAP{Address: MustParseAddress("ldap://127.0.0.1")},
|
|
err: "",
|
|
decode: true,
|
|
},
|
|
{
|
|
name: "ShouldDecodeLDAPPtr",
|
|
have: "ldap://127.0.0.1",
|
|
expected: &schema.AddressLDAP{Address: MustParseAddress("ldap://127.0.0.1")},
|
|
err: "",
|
|
decode: true,
|
|
},
|
|
{
|
|
name: "ShouldDecodeSMTP",
|
|
have: "smtp://127.0.0.1",
|
|
expected: schema.AddressSMTP{Address: MustParseAddress("smtp://127.0.0.1")},
|
|
err: "",
|
|
decode: true,
|
|
},
|
|
{
|
|
name: "ShouldDecodeSMTPPtr",
|
|
have: "smtp://127.0.0.1",
|
|
expected: &schema.AddressSMTP{Address: MustParseAddress("smtp://127.0.0.1")},
|
|
err: "",
|
|
decode: true,
|
|
},
|
|
{
|
|
name: "ShouldFailDecodeTCP",
|
|
have: "@@@@@@@",
|
|
expected: schema.AddressTCP{Address: MustParseAddress("tcp://127.0.0.1")},
|
|
err: "could not decode '@@@@@@@' to a schema.AddressTCP: error validating the address: the url 'tcp://%40%40%40%40%40%40@' appears to have user info but this is not valid for addresses",
|
|
decode: false,
|
|
},
|
|
{
|
|
name: "ShouldFailDecodeUDP",
|
|
have: "@@@@@@@",
|
|
expected: schema.AddressUDP{Address: MustParseAddress("udp://127.0.0.1")},
|
|
err: "could not decode '@@@@@@@' to a schema.AddressUDP: error validating the address: the url 'udp://%40%40%40%40%40%40@' appears to have user info but this is not valid for addresses",
|
|
decode: false,
|
|
},
|
|
{
|
|
name: "ShouldFailDecodeLDAP",
|
|
have: "@@@@@@@",
|
|
expected: schema.AddressLDAP{Address: MustParseAddress("ldap://127.0.0.1")},
|
|
err: "could not decode '@@@@@@@' to a schema.AddressLDAP: error validating the address: the url 'ldaps://%40%40%40%40%40%40@' appears to have user info but this is not valid for addresses",
|
|
decode: false,
|
|
},
|
|
{
|
|
name: "ShouldFailDecodeSMTP",
|
|
have: "@@@@@@@",
|
|
expected: schema.AddressSMTP{Address: MustParseAddress("smtp://127.0.0.1")},
|
|
err: "could not decode '@@@@@@@' to a schema.AddressSMTP: error validating the address: the url 'smtp://%40%40%40%40%40%40@' appears to have user info but this is not valid for addresses",
|
|
decode: false,
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToAddressHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
actual, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.expected), tc.have)
|
|
if tc.err != "" {
|
|
assert.EqualError(t, err, tc.err)
|
|
|
|
if !tc.decode {
|
|
assert.Nil(t, actual)
|
|
}
|
|
} else {
|
|
assert.NoError(t, err)
|
|
|
|
if tc.decode {
|
|
assert.Equal(t, tc.expected, actual)
|
|
} else {
|
|
assert.Equal(t, tc.have, actual)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringToPrivateKeyHookFunc(t *testing.T) {
|
|
var (
|
|
nilRSA *rsa.PrivateKey
|
|
nilECDSA *ecdsa.PrivateKey
|
|
nilCert *x509.Certificate
|
|
)
|
|
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
desc: "ShouldDecodeRSA1024PrivateKey",
|
|
have: x509PrivateKeyRSA1024,
|
|
want: MustParsePKCS8RSAPrivateKey(x509PrivateKeyRSA1024),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA2048PrivateKey",
|
|
have: x509PrivateKeyRSA2048,
|
|
want: MustParsePKCS8RSAPrivateKey(x509PrivateKeyRSA2048),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA4096PrivateKey",
|
|
have: x509PrivateKeyRSA4096,
|
|
want: MustParsePKCS8RSAPrivateKey(x509PrivateKeyRSA4096),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP224PrivateKey",
|
|
have: x509PrivateKeyECDSAP224,
|
|
want: MustParsePKCS8ECDSAPrivateKey(x509PrivateKeyECDSAP224),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP256PrivateKey",
|
|
have: x509PrivateKeyECDSAP256,
|
|
want: MustParsePKCS8ECDSAPrivateKey(x509PrivateKeyECDSAP256),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP384PrivateKey",
|
|
have: x509PrivateKeyECDSAP384,
|
|
want: MustParsePKCS8ECDSAPrivateKey(x509PrivateKeyECDSAP384),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP521PrivateKey",
|
|
have: x509PrivateKeyECDSAP521,
|
|
want: MustParsePKCS8ECDSAPrivateKey(x509PrivateKeyECDSAP521),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeEd25519PrivateKey",
|
|
have: x509PrivateKeyEd25519,
|
|
want: MustParsePKCS8Ed25519PrivateKey(x509PrivateKeyEd25519),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeToECDSAPrivateKey",
|
|
have: x509PrivateKeyRSA2048,
|
|
want: &ecdsa.PrivateKey{},
|
|
decode: true,
|
|
err: "could not decode to a *ecdsa.PrivateKey: the data is for a *rsa.PrivateKey not a *ecdsa.PrivateKey",
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeEmptyRSAKey",
|
|
have: "",
|
|
want: nilRSA,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeEmptyECDSAKey",
|
|
have: "",
|
|
want: nilECDSA,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeECDSAKeyToRSAKey",
|
|
have: x509PrivateKeyECDSAP521,
|
|
want: nilRSA,
|
|
decode: true,
|
|
err: "could not decode to a *rsa.PrivateKey: the data is for a *ecdsa.PrivateKey not a *rsa.PrivateKey",
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeRSAKeyToECDSAKey",
|
|
have: x509PrivateKeyRSA2048,
|
|
want: nilECDSA,
|
|
decode: true,
|
|
err: "could not decode to a *ecdsa.PrivateKey: the data is for a *rsa.PrivateKey not a *ecdsa.PrivateKey",
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeBadRSAPrivateKey",
|
|
have: x509PrivateKeyRSABad,
|
|
want: nilRSA,
|
|
decode: true,
|
|
err: "could not decode to a *rsa.PrivateKey: error occurred attempting to parse PEM block: either no PEM block was supplied or it was malformed",
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeBadRSAPrivateKeyTrailingData",
|
|
have: strings.ReplaceAll(x509PrivateKeyRSA2048, "END PRIVATE KEY-----", "END PRIVATE KEY---------"),
|
|
want: nilRSA,
|
|
decode: true,
|
|
err: "could not decode to a *rsa.PrivateKey: error occurred attempting to parse PEM block: either no PEM block was supplied or it was malformed",
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeBadRSAPrivateKeyTrailingDataDoubled",
|
|
have: x509PrivateKeyRSA2048 + x509PrivateKeyRSA2048,
|
|
want: nilRSA,
|
|
decode: true,
|
|
err: "could not decode to a *rsa.PrivateKey: error occurred attempting to parse PEM block: the block either had trailing data or was otherwise malformed",
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeBadECDSAPrivateKey",
|
|
have: x509PrivateKeyECBad,
|
|
want: nilECDSA,
|
|
decode: true,
|
|
err: "could not decode to a *ecdsa.PrivateKey: error occurred attempting to parse PEM block: either no PEM block was supplied or it was malformed",
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeCertificateToRSAPrivateKey",
|
|
have: x509CertificateRSA2048,
|
|
want: nilRSA,
|
|
decode: true,
|
|
err: "could not decode to a *rsa.PrivateKey: the data is for a *x509.Certificate not a *rsa.PrivateKey",
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeCertificateToECDSAPrivateKey",
|
|
have: x509CertificateRSA2048,
|
|
want: nilECDSA,
|
|
decode: true,
|
|
err: "could not decode to a *ecdsa.PrivateKey: the data is for a *x509.Certificate not a *ecdsa.PrivateKey",
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeRSAKeyToCertificate",
|
|
have: x509PrivateKeyRSA2048,
|
|
want: nilCert,
|
|
decode: false,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeECDSAKeyToCertificate",
|
|
have: x509PrivateKeyECDSAP521,
|
|
want: nilCert,
|
|
decode: false,
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToPrivateKeyHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringToX509CertificateHookFunc(t *testing.T) {
|
|
var nilkey *x509.Certificate
|
|
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
want any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
desc: "ShouldDecodeRSACertificate",
|
|
have: x509CertificateRSA2048,
|
|
want: MustParseX509Certificate(x509CertificateRSA2048),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSACertificate",
|
|
have: x509CertificateECDSAP521,
|
|
want: MustParseX509Certificate(x509CertificateECDSAP521),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeEd25519Certificate",
|
|
have: x509CertificateEd25519,
|
|
want: MustParseX509Certificate(x509CertificateEd25519),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSACACertificate",
|
|
have: x509CACertificateRSA2048,
|
|
want: MustParseX509Certificate(x509CACertificateRSA2048),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSACACertificate",
|
|
have: x509CACertificateECDSAP521,
|
|
want: MustParseX509Certificate(x509CACertificateECDSAP521),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeEd25519CACertificate",
|
|
have: x509CACertificateEd25519,
|
|
want: MustParseX509Certificate(x509CACertificateEd25519),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeEmptyCertificateToNil",
|
|
have: "",
|
|
want: nilkey,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeECDSAKeyToCertificate",
|
|
have: x509PrivateKeyECDSAP224,
|
|
want: nilkey,
|
|
decode: true,
|
|
err: "could not decode to a *x509.Certificate: the data is for a *ecdsa.PrivateKey not a *x509.Certificate",
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeBadRSAPrivateKeyToCertificate",
|
|
have: x509PrivateKeyRSABad,
|
|
want: nilkey,
|
|
decode: true,
|
|
err: "could not decode to a *x509.Certificate: error occurred attempting to parse PEM block: either no PEM block was supplied or it was malformed",
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToX509CertificateHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
result, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.want), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, result)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.want, result)
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringToPasswordDigestHookFunc(t *testing.T) {
|
|
var nilvalue *schema.PasswordDigest
|
|
|
|
testCases := []struct {
|
|
name string
|
|
have any
|
|
expected any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
"ShouldParse",
|
|
"$plaintext$example",
|
|
MustParsePasswordDigest("$plaintext$example"),
|
|
"",
|
|
true,
|
|
},
|
|
{
|
|
"ShouldParsePtr",
|
|
"$plaintext$example",
|
|
MustParsePasswordDigestPtr("$plaintext$example"),
|
|
"",
|
|
true,
|
|
},
|
|
{
|
|
"ShouldNotParseUnknown",
|
|
"$abc$example",
|
|
schema.PasswordDigest{},
|
|
"could not decode '$abc$example' to a schema.PasswordDigest: provided encoded hash has an invalid identifier: the identifier 'abc' is unknown to the decoder",
|
|
false,
|
|
},
|
|
{
|
|
"ShouldNotParseWrongType",
|
|
"$abc$example",
|
|
schema.TLSVersion{},
|
|
"",
|
|
false,
|
|
},
|
|
{
|
|
"ShouldNotParseWrongTypePtr",
|
|
"$abc$example",
|
|
&schema.TLSVersion{},
|
|
"",
|
|
false,
|
|
},
|
|
{
|
|
"ShouldNotParseEmptyString",
|
|
"",
|
|
schema.PasswordDigest{},
|
|
"could not decode an empty value to a schema.PasswordDigest: must have a non-empty value",
|
|
false,
|
|
},
|
|
{
|
|
"ShouldParseEmptyStringPtr",
|
|
"",
|
|
nilvalue,
|
|
"",
|
|
true,
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToPasswordDigestHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
actual, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.expected), tc.have)
|
|
if tc.err != "" {
|
|
assert.EqualError(t, err, tc.err)
|
|
|
|
if !tc.decode {
|
|
assert.Nil(t, actual)
|
|
}
|
|
} else {
|
|
assert.NoError(t, err)
|
|
|
|
if tc.decode {
|
|
assert.Equal(t, tc.expected, actual)
|
|
} else {
|
|
assert.Equal(t, tc.have, actual)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringToTLSVersionHookFunc(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
have any
|
|
expected any
|
|
err string
|
|
decode bool
|
|
}{
|
|
{
|
|
"ShouldParseTLS1.3",
|
|
"TLS1.3",
|
|
schema.TLSVersion{Value: tls.VersionTLS13},
|
|
"",
|
|
true,
|
|
},
|
|
{
|
|
"ShouldParseTLS1.3PTR",
|
|
"TLS1.3",
|
|
&schema.TLSVersion{Value: tls.VersionTLS13},
|
|
"",
|
|
true,
|
|
},
|
|
{
|
|
"ShouldParseTLS1.2",
|
|
"TLS1.2",
|
|
schema.TLSVersion{Value: tls.VersionTLS12},
|
|
"",
|
|
true,
|
|
},
|
|
{
|
|
"ShouldNotParseInt",
|
|
1,
|
|
&schema.TLSVersion{},
|
|
"",
|
|
false,
|
|
},
|
|
{
|
|
"ShouldNotParseNonVersion",
|
|
"1",
|
|
&schema.TLSVersion{},
|
|
"could not decode '1' to a *schema.TLSVersion: supplied tls version isn't supported",
|
|
false,
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToTLSVersionHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
actual, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.expected), tc.have)
|
|
if tc.err != "" {
|
|
assert.EqualError(t, err, tc.err)
|
|
|
|
if !tc.decode {
|
|
assert.Nil(t, actual)
|
|
}
|
|
} else {
|
|
assert.NoError(t, err)
|
|
|
|
if tc.decode {
|
|
assert.Equal(t, tc.expected, actual)
|
|
} else {
|
|
assert.Equal(t, tc.have, actual)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringToX509CertificateChainHookFunc(t *testing.T) {
|
|
var nilkey *schema.X509CertificateChain
|
|
|
|
testCases := []struct {
|
|
desc string
|
|
have any
|
|
expected any
|
|
err, verr string
|
|
decode bool
|
|
}{
|
|
{
|
|
desc: "ShouldDecodeRSA1024Certificate",
|
|
have: x509CertificateRSA1024,
|
|
expected: MustParseX509CertificateChain(x509CertificateRSA1024),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA1024CertificateNoPtr",
|
|
have: x509CertificateRSA1024,
|
|
expected: *MustParseX509CertificateChain(x509CertificateRSA1024),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA1024CACertificate",
|
|
have: x509CACertificateRSA1024,
|
|
expected: MustParseX509CertificateChain(x509CACertificateRSA1024),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA1024CACertificateNoPtr",
|
|
have: x509CACertificateRSA1024,
|
|
expected: *MustParseX509CertificateChain(x509CACertificateRSA1024),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA1024CertificateChain",
|
|
have: BuildChain(x509CertificateRSA1024, x509CACertificateRSA1024),
|
|
expected: MustParseX509CertificateChain(x509CertificateRSA1024, x509CACertificateRSA1024),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA1024CertificateChainNoPtr",
|
|
have: BuildChain(x509CertificateRSA1024, x509CACertificateRSA1024),
|
|
expected: *MustParseX509CertificateChain(x509CertificateRSA1024, x509CACertificateRSA1024),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA2048Certificate",
|
|
have: x509CertificateRSA2048,
|
|
expected: MustParseX509CertificateChain(x509CertificateRSA2048),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA2048CertificateNoPtr",
|
|
have: x509CertificateRSA2048,
|
|
expected: *MustParseX509CertificateChain(x509CertificateRSA2048),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA2048CACertificate",
|
|
have: x509CACertificateRSA2048,
|
|
expected: MustParseX509CertificateChain(x509CACertificateRSA2048),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA2048CACertificateNoPtr",
|
|
have: x509CACertificateRSA2048,
|
|
expected: *MustParseX509CertificateChain(x509CACertificateRSA2048),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA2048CertificateChain",
|
|
have: BuildChain(x509CertificateRSA2048, x509CACertificateRSA2048),
|
|
expected: MustParseX509CertificateChain(x509CertificateRSA2048, x509CACertificateRSA2048),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA2048CertificateChainNoPtr",
|
|
have: BuildChain(x509CertificateRSA2048, x509CACertificateRSA2048),
|
|
expected: *MustParseX509CertificateChain(x509CertificateRSA2048, x509CACertificateRSA2048),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA4096Certificate",
|
|
have: x509CertificateRSA4096,
|
|
expected: MustParseX509CertificateChain(x509CertificateRSA4096),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA4096CertificateNoPtr",
|
|
have: x509CertificateRSA4096,
|
|
expected: *MustParseX509CertificateChain(x509CertificateRSA4096),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA4096CACertificate",
|
|
have: x509CACertificateRSA4096,
|
|
expected: MustParseX509CertificateChain(x509CACertificateRSA4096),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA4096CACertificateNoPtr",
|
|
have: x509CACertificateRSA4096,
|
|
expected: *MustParseX509CertificateChain(x509CACertificateRSA4096),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA4096CertificateChain",
|
|
have: BuildChain(x509CertificateRSA4096, x509CACertificateRSA4096),
|
|
expected: MustParseX509CertificateChain(x509CertificateRSA4096, x509CACertificateRSA4096),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeRSA4096CertificateChainNoPtr",
|
|
have: BuildChain(x509CertificateRSA4096, x509CACertificateRSA4096),
|
|
expected: *MustParseX509CertificateChain(x509CertificateRSA4096, x509CACertificateRSA4096),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP224Certificate",
|
|
have: x509CertificateECDSAP224,
|
|
expected: MustParseX509CertificateChain(x509CertificateECDSAP224),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP224CertificateNoPtr",
|
|
have: x509CertificateECDSAP224,
|
|
expected: *MustParseX509CertificateChain(x509CertificateECDSAP224),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP224CACertificate",
|
|
have: x509CACertificateECDSAP224,
|
|
expected: MustParseX509CertificateChain(x509CACertificateECDSAP224),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP224CACertificateNoPtr",
|
|
have: x509CACertificateECDSAP224,
|
|
expected: *MustParseX509CertificateChain(x509CACertificateECDSAP224),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP224CertificateChain",
|
|
have: BuildChain(x509CertificateECDSAP224, x509CACertificateECDSAP224),
|
|
expected: MustParseX509CertificateChain(x509CertificateECDSAP224, x509CACertificateECDSAP224),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP224CertificateChainNoPtr",
|
|
have: BuildChain(x509CertificateECDSAP224, x509CACertificateECDSAP224),
|
|
expected: *MustParseX509CertificateChain(x509CertificateECDSAP224, x509CACertificateECDSAP224),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP256Certificate",
|
|
have: x509CertificateECDSAP256,
|
|
expected: MustParseX509CertificateChain(x509CertificateECDSAP256),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP256CertificateNoPtr",
|
|
have: x509CertificateECDSAP256,
|
|
expected: *MustParseX509CertificateChain(x509CertificateECDSAP256),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP256CACertificate",
|
|
have: x509CACertificateECDSAP256,
|
|
expected: MustParseX509CertificateChain(x509CACertificateECDSAP256),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP256CACertificateNoPtr",
|
|
have: x509CACertificateECDSAP256,
|
|
expected: *MustParseX509CertificateChain(x509CACertificateECDSAP256),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP256CertificateChain",
|
|
have: BuildChain(x509CertificateECDSAP256, x509CACertificateECDSAP256),
|
|
expected: MustParseX509CertificateChain(x509CertificateECDSAP256, x509CACertificateECDSAP256),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP256CertificateChainNoPtr",
|
|
have: BuildChain(x509CertificateECDSAP256, x509CACertificateECDSAP256),
|
|
expected: *MustParseX509CertificateChain(x509CertificateECDSAP256, x509CACertificateECDSAP256),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP384Certificate",
|
|
have: x509CertificateECDSAP384,
|
|
expected: MustParseX509CertificateChain(x509CertificateECDSAP384),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP384CertificateNoPtr",
|
|
have: x509CertificateECDSAP384,
|
|
expected: *MustParseX509CertificateChain(x509CertificateECDSAP384),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP384CACertificate",
|
|
have: x509CACertificateECDSAP384,
|
|
expected: MustParseX509CertificateChain(x509CACertificateECDSAP384),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP384CACertificateNoPtr",
|
|
have: x509CACertificateECDSAP384,
|
|
expected: *MustParseX509CertificateChain(x509CACertificateECDSAP384),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP384CertificateChain",
|
|
have: BuildChain(x509CertificateECDSAP384, x509CACertificateECDSAP384),
|
|
expected: MustParseX509CertificateChain(x509CertificateECDSAP384, x509CACertificateECDSAP384),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP384CertificateChainNoPtr",
|
|
have: BuildChain(x509CertificateECDSAP384, x509CACertificateECDSAP384),
|
|
expected: *MustParseX509CertificateChain(x509CertificateECDSAP384, x509CACertificateECDSAP384),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP521Certificate",
|
|
have: x509CertificateECDSAP521,
|
|
expected: MustParseX509CertificateChain(x509CertificateECDSAP521),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP521CertificateNoPtr",
|
|
have: x509CertificateECDSAP521,
|
|
expected: *MustParseX509CertificateChain(x509CertificateECDSAP521),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP521CACertificate",
|
|
have: x509CACertificateECDSAP521,
|
|
expected: MustParseX509CertificateChain(x509CACertificateECDSAP521),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP521CACertificateNoPtr",
|
|
have: x509CACertificateECDSAP521,
|
|
expected: *MustParseX509CertificateChain(x509CACertificateECDSAP521),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP521CertificateChain",
|
|
have: BuildChain(x509CertificateECDSAP521, x509CACertificateECDSAP521),
|
|
expected: MustParseX509CertificateChain(x509CertificateECDSAP521, x509CACertificateECDSAP521),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeECDSAP521CertificateChainNoPtr",
|
|
have: BuildChain(x509CertificateECDSAP521, x509CACertificateECDSAP521),
|
|
expected: *MustParseX509CertificateChain(x509CertificateECDSAP521, x509CACertificateECDSAP521),
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeBadRSACertificateChain",
|
|
have: BuildChain(x509CertificateRSA2048, x509CACertificateECDSAP521),
|
|
expected: MustParseX509CertificateChain(x509CertificateRSA2048, x509CACertificateECDSAP521),
|
|
verr: "certificate #1 in chain is not signed properly by certificate #2 in chain: x509: signature algorithm specifies an RSA public key, but have public key of type *ecdsa.PublicKey",
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeEmptyCertificateToNil",
|
|
have: "",
|
|
expected: nilkey,
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldDecodeEmptyCertificateToEmptyStruct",
|
|
have: "",
|
|
expected: schema.X509CertificateChain{},
|
|
decode: true,
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeECDSAKeyToCertificate",
|
|
have: x509PrivateKeyECDSAP224,
|
|
expected: nilkey,
|
|
decode: true,
|
|
err: "could not decode to a *schema.X509CertificateChain: the PEM data chain contains a PRIVATE KEY but only certificates are expected",
|
|
},
|
|
{
|
|
desc: "ShouldNotDecodeBadRSAPrivateKeyToCertificate",
|
|
have: x509PrivateKeyRSABad,
|
|
expected: nilkey,
|
|
decode: true,
|
|
err: "could not decode to a *schema.X509CertificateChain: invalid PEM block",
|
|
},
|
|
}
|
|
|
|
hook := configuration.StringToX509CertificateChainHookFunc()
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
actual, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.expected), tc.have)
|
|
|
|
switch {
|
|
case !tc.decode:
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.have, actual)
|
|
case tc.err == "":
|
|
assert.NoError(t, err)
|
|
require.Equal(t, tc.expected, actual)
|
|
|
|
if tc.expected == nilkey {
|
|
break
|
|
}
|
|
|
|
switch chain := actual.(type) {
|
|
case *schema.X509CertificateChain:
|
|
require.NotNil(t, chain)
|
|
|
|
if tc.verr == "" {
|
|
assert.NoError(t, chain.Validate())
|
|
} else {
|
|
assert.EqualError(t, chain.Validate(), tc.verr)
|
|
}
|
|
case schema.X509CertificateChain:
|
|
require.NotNil(t, chain)
|
|
|
|
if tc.verr == "" {
|
|
assert.NoError(t, chain.Validate())
|
|
} else {
|
|
assert.EqualError(t, chain.Validate(), tc.verr)
|
|
}
|
|
}
|
|
default:
|
|
assert.EqualError(t, err, tc.err)
|
|
assert.Nil(t, actual)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
var (
|
|
//nolint:gosec
|
|
x509PrivateKeyRSABad = `
|
|
-----BEGIN RSA PRIVATE KEY-----
|
|
bad key
|
|
-----END RSA PRIVATE KEY-----`
|
|
|
|
//nolint:gosec
|
|
x509PrivateKeyECBad = `
|
|
-----BEGIN EC PRIVATE KEY-----
|
|
bad key
|
|
-----END EC PRIVATE KEY-----`
|
|
)
|
|
|
|
func MustParsePKCS8RSAPrivateKey(data string) *rsa.PrivateKey {
|
|
return MustParsePKCS8PrivateKey(data).(*rsa.PrivateKey)
|
|
}
|
|
|
|
func MustParsePKCS8ECDSAPrivateKey(data string) *ecdsa.PrivateKey {
|
|
return MustParsePKCS8PrivateKey(data).(*ecdsa.PrivateKey)
|
|
}
|
|
|
|
func MustParsePKCS8Ed25519PrivateKey(data string) *ed25519.PrivateKey {
|
|
key := MustParsePKCS8PrivateKey(data).(ed25519.PrivateKey)
|
|
|
|
return &key
|
|
}
|
|
|
|
func MustParsePKCS8PrivateKey(data string) schema.CryptographicPrivateKey {
|
|
block, _ := pem.Decode([]byte(data))
|
|
if block == nil || block.Bytes == nil || len(block.Bytes) == 0 {
|
|
panic("not pem encoded")
|
|
}
|
|
|
|
if block.Type != "PRIVATE KEY" {
|
|
panic("not PKCS8 private key")
|
|
}
|
|
|
|
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if pkey, ok := key.(schema.CryptographicPrivateKey); ok {
|
|
return pkey
|
|
}
|
|
|
|
panic("key does not implement the required members")
|
|
}
|
|
|
|
func MustParseX509Certificate(data string) *x509.Certificate {
|
|
block, _ := pem.Decode([]byte(data))
|
|
if block == nil || len(block.Bytes) == 0 {
|
|
panic("not a PEM")
|
|
}
|
|
|
|
cert, err := x509.ParseCertificate(block.Bytes)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return cert
|
|
}
|
|
|
|
func BuildChain(pems ...string) string {
|
|
buf := bytes.Buffer{}
|
|
|
|
for i, data := range pems {
|
|
if i != 0 {
|
|
buf.WriteString("\n")
|
|
}
|
|
|
|
buf.WriteString(data)
|
|
}
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
func MustParseX509CertificateChain(datas ...string) *schema.X509CertificateChain {
|
|
chain, err := schema.NewX509CertificateChain(BuildChain(datas...))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return chain
|
|
}
|
|
|
|
func testInt32Ptr(i int32) *int32 {
|
|
return &i
|
|
}
|
|
|
|
func testTimeDurationPtr(t time.Duration) *time.Duration {
|
|
return &t
|
|
}
|
|
|
|
func testRefreshIntervalDurationPtr(t time.Duration) *schema.RefreshIntervalDuration {
|
|
x := schema.NewRefreshIntervalDuration(t)
|
|
|
|
return &x
|
|
}
|
|
|
|
var (
|
|
testTrue = true
|
|
testZero int32
|
|
testString = ""
|
|
)
|
|
|
|
func MustParseAddress(input string) schema.Address {
|
|
address, err := schema.NewAddress(input)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
addr := *address
|
|
|
|
return addr
|
|
}
|
|
|
|
func MustParseAddressPtr(input string) *schema.Address {
|
|
address, err := schema.NewAddress(input)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return address
|
|
}
|
|
|
|
func MustParsePasswordDigest(input string) schema.PasswordDigest {
|
|
digest, err := schema.DecodePasswordDigest(input)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return *digest
|
|
}
|
|
|
|
func MustParsePasswordDigestPtr(input string) *schema.PasswordDigest {
|
|
digest, err := schema.DecodePasswordDigest(input)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return digest
|
|
}
|
|
|
|
const (
|
|
pathCrypto = "./test_resources/crypto/%s.%s"
|
|
)
|
|
|
|
func MustLoadCryptoSet(alg string, legacy bool, extra ...string) (certCA, keyCA, cert, key string) {
|
|
extraAlt := make([]string, len(extra))
|
|
|
|
copy(extraAlt, extra)
|
|
|
|
if legacy {
|
|
extraAlt = append(extraAlt, "legacy")
|
|
}
|
|
|
|
return MustLoadCryptoRaw(true, alg, "crt", extra...), MustLoadCryptoRaw(true, alg, "pem", extra...), MustLoadCryptoRaw(false, alg, "crt", extraAlt...), MustLoadCryptoRaw(false, alg, "pem", extraAlt...)
|
|
}
|
|
|
|
func MustLoadCryptoRaw(ca bool, alg, ext string, extra ...string) string {
|
|
var fparts []string
|
|
|
|
if ca {
|
|
fparts = append(fparts, "ca")
|
|
}
|
|
|
|
fparts = append(fparts, strings.ToLower(alg))
|
|
|
|
if len(extra) != 0 {
|
|
fparts = append(fparts, extra...)
|
|
}
|
|
|
|
var (
|
|
data []byte
|
|
err error
|
|
)
|
|
|
|
if data, err = os.ReadFile(fmt.Sprintf(pathCrypto, strings.Join(fparts, "."), ext)); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return string(data)
|
|
}
|
|
|
|
var (
|
|
x509CertificateRSA1024, x509CertificateRSA2048, x509CertificateRSA4096, x509CertificateEd25519 string
|
|
x509CACertificateRSA1024, x509CACertificateRSA2048, x509CACertificateRSA4096, x509CACertificateEd25519 string
|
|
x509PrivateKeyRSA1024, x509PrivateKeyRSA2048, x509PrivateKeyRSA4096, x509PrivateKeyEd25519 string
|
|
x509CAPrivateKeyRSA1024, x509CAPrivateKeyRSA2048, x509CAPrivateKeyRSA4096, x509CAPrivateKeyEd25519 string
|
|
x509CertificateECDSAP224, x509CertificateECDSAP256, x509CertificateECDSAP384, x509CertificateECDSAP521 string
|
|
x509CACertificateECDSAP224, x509CACertificateECDSAP256, x509CACertificateECDSAP384, x509CACertificateECDSAP521 string
|
|
x509PrivateKeyECDSAP224, x509PrivateKeyECDSAP256, x509PrivateKeyECDSAP384, x509PrivateKeyECDSAP521 string
|
|
x509CAPrivateKeyECDSAP224, x509CAPrivateKeyECDSAP256, x509CAPrivateKeyECDSAP384, x509CAPrivateKeyECDSAP521 string
|
|
)
|
|
|
|
func init() {
|
|
x509CACertificateRSA1024, x509CAPrivateKeyRSA1024, x509CertificateRSA1024, x509PrivateKeyRSA1024 = MustLoadCryptoSet("RSA", false, "1024")
|
|
x509CACertificateRSA2048, x509CAPrivateKeyRSA2048, x509CertificateRSA2048, x509PrivateKeyRSA2048 = MustLoadCryptoSet("RSA", false, "2048")
|
|
x509CACertificateRSA4096, x509CAPrivateKeyRSA4096, x509CertificateRSA4096, x509PrivateKeyRSA4096 = MustLoadCryptoSet("RSA", false, "4096")
|
|
|
|
x509CACertificateECDSAP224, x509CAPrivateKeyECDSAP224, x509CertificateECDSAP224, x509PrivateKeyECDSAP224 = MustLoadCryptoSet("ECDSA", false, "P224")
|
|
x509CACertificateECDSAP256, x509CAPrivateKeyECDSAP256, x509CertificateECDSAP256, x509PrivateKeyECDSAP256 = MustLoadCryptoSet("ECDSA", false, "P256")
|
|
x509CACertificateECDSAP384, x509CAPrivateKeyECDSAP384, x509CertificateECDSAP384, x509PrivateKeyECDSAP384 = MustLoadCryptoSet("ECDSA", false, "P384")
|
|
x509CACertificateECDSAP521, x509CAPrivateKeyECDSAP521, x509CertificateECDSAP521, x509PrivateKeyECDSAP521 = MustLoadCryptoSet("ECDSA", false, "P521")
|
|
|
|
x509CACertificateEd25519, x509CAPrivateKeyEd25519, x509CertificateEd25519, x509PrivateKeyEd25519 = MustLoadCryptoSet("Ed25519", false)
|
|
}
|