This commit is contained in:
+263
@@ -0,0 +1,263 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
||||
"github.com/go-webauthn/webauthn/metadata"
|
||||
"github.com/go-webauthn/webauthn/testing/mocks"
|
||||
)
|
||||
|
||||
func TestValidateMetadata(t *testing.T) {
|
||||
aaguid := uuid.MustParse("0865c31d-05dc-4fb1-adce-3227bfb19967")
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
setup func(t *testing.T) metadata.Provider
|
||||
aaguid uuid.UUID
|
||||
attestationType string
|
||||
attestationFormat string
|
||||
x5cs []any
|
||||
err *Error
|
||||
}{
|
||||
{
|
||||
name: "ShouldReturnNilForNilProvider",
|
||||
setup: func(t *testing.T) metadata.Provider { return nil },
|
||||
attestationFormat: "packed",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturnNilForNoneFormat",
|
||||
setup: func(t *testing.T) metadata.Provider { return mocks.NewMockMetadataProvider(gomock.NewController(t)) },
|
||||
attestationFormat: "none",
|
||||
},
|
||||
{
|
||||
name: "ShouldFailWhenGetEntryReturnsError",
|
||||
setup: func(t *testing.T) metadata.Provider {
|
||||
ctrl := gomock.NewController(t)
|
||||
mds := mocks.NewMockMetadataProvider(ctrl)
|
||||
mds.EXPECT().GetEntry(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("db error"))
|
||||
|
||||
return mds
|
||||
},
|
||||
aaguid: aaguid,
|
||||
attestationFormat: "packed",
|
||||
err: &Error{Type: "invalid_metadata", Details: "", DevInfo: "Failed to validate authenticator metadata for Authenticator Attestation GUID '0865c31d-05dc-4fb1-adce-3227bfb19967'. Error occurred retrieving the metadata entry: db error"},
|
||||
},
|
||||
{
|
||||
name: "ShouldReturnNilWhenEntryNilAndValidationNotRequired",
|
||||
setup: func(t *testing.T) metadata.Provider {
|
||||
ctrl := gomock.NewController(t)
|
||||
mds := mocks.NewMockMetadataProvider(ctrl)
|
||||
mds.EXPECT().GetEntry(gomock.Any(), gomock.Any()).Return(nil, nil)
|
||||
mds.EXPECT().GetValidateEntry(gomock.Any()).Return(false)
|
||||
|
||||
return mds
|
||||
},
|
||||
aaguid: aaguid,
|
||||
attestationFormat: "packed",
|
||||
},
|
||||
{
|
||||
name: "ShouldFailWhenEntryNilAndValidationRequired",
|
||||
setup: func(t *testing.T) metadata.Provider {
|
||||
ctrl := gomock.NewController(t)
|
||||
mds := mocks.NewMockMetadataProvider(ctrl)
|
||||
mds.EXPECT().GetEntry(gomock.Any(), gomock.Any()).Return(nil, nil)
|
||||
mds.EXPECT().GetValidateEntry(gomock.Any()).Return(true)
|
||||
|
||||
return mds
|
||||
},
|
||||
aaguid: aaguid,
|
||||
attestationFormat: "packed",
|
||||
err: &Error{Type: "invalid_metadata", Details: "", DevInfo: "Failed to validate authenticator metadata for Authenticator Attestation GUID '0865c31d-05dc-4fb1-adce-3227bfb19967'. The authenticator has no registered metadata."},
|
||||
},
|
||||
{
|
||||
name: "ShouldReturnNilForZeroAAGUIDWhenPermitted",
|
||||
setup: func(t *testing.T) metadata.Provider {
|
||||
ctrl := gomock.NewController(t)
|
||||
mds := mocks.NewMockMetadataProvider(ctrl)
|
||||
mds.EXPECT().GetEntry(gomock.Any(), gomock.Any()).Return(nil, nil)
|
||||
mds.EXPECT().GetValidateEntryPermitZeroAAGUID(gomock.Any()).Return(true)
|
||||
|
||||
return mds
|
||||
},
|
||||
aaguid: uuid.Nil,
|
||||
attestationFormat: "packed",
|
||||
},
|
||||
{
|
||||
name: "ShouldFailWhenAttestationTypeMismatch",
|
||||
setup: func(t *testing.T) metadata.Provider {
|
||||
ctrl := gomock.NewController(t)
|
||||
mds := mocks.NewMockMetadataProvider(ctrl)
|
||||
entry := &metadata.Entry{
|
||||
MetadataStatement: metadata.Statement{
|
||||
AttestationTypes: metadata.AuthenticatorAttestationTypes{metadata.BasicFull},
|
||||
},
|
||||
}
|
||||
mds.EXPECT().GetEntry(gomock.Any(), gomock.Any()).Return(entry, nil)
|
||||
mds.EXPECT().GetValidateAttestationTypes(gomock.Any()).Return(true)
|
||||
|
||||
return mds
|
||||
},
|
||||
aaguid: aaguid,
|
||||
attestationType: "wrong-type",
|
||||
attestationFormat: "packed",
|
||||
err: &Error{Type: "invalid_metadata", Details: "", DevInfo: "Failed to validate authenticator metadata for Authenticator Attestation GUID '0865c31d-05dc-4fb1-adce-3227bfb19967'. The attestation type 'wrong-type' is not known to be used by this authenticator."},
|
||||
},
|
||||
{
|
||||
name: "ShouldFailWhenStatusValidationFails",
|
||||
setup: func(t *testing.T) metadata.Provider {
|
||||
ctrl := gomock.NewController(t)
|
||||
mds := mocks.NewMockMetadataProvider(ctrl)
|
||||
entry := &metadata.Entry{
|
||||
MetadataStatement: metadata.Statement{
|
||||
AttestationTypes: metadata.AuthenticatorAttestationTypes{metadata.BasicFull},
|
||||
},
|
||||
StatusReports: []metadata.StatusReport{{Status: metadata.Revoked}},
|
||||
}
|
||||
mds.EXPECT().GetEntry(gomock.Any(), gomock.Any()).Return(entry, nil)
|
||||
mds.EXPECT().GetValidateAttestationTypes(gomock.Any()).Return(false)
|
||||
mds.EXPECT().GetValidateStatus(gomock.Any()).Return(true)
|
||||
mds.EXPECT().ValidateStatusReports(gomock.Any(), gomock.Any()).Return(fmt.Errorf("revoked"))
|
||||
|
||||
return mds
|
||||
},
|
||||
aaguid: aaguid,
|
||||
attestationType: string(metadata.BasicFull),
|
||||
attestationFormat: "packed",
|
||||
err: &Error{Type: "invalid_metadata", Details: "", DevInfo: "Failed to validate authenticator metadata for Authenticator Attestation GUID '0865c31d-05dc-4fb1-adce-3227bfb19967'. Error occurred validating the authenticator status: revoked"},
|
||||
},
|
||||
{
|
||||
name: "ShouldReturnNilWhenTrustAnchorValidationWithNoX5Cs",
|
||||
setup: func(t *testing.T) metadata.Provider {
|
||||
ctrl := gomock.NewController(t)
|
||||
mds := mocks.NewMockMetadataProvider(ctrl)
|
||||
entry := &metadata.Entry{
|
||||
MetadataStatement: metadata.Statement{
|
||||
AttestationTypes: metadata.AuthenticatorAttestationTypes{metadata.BasicFull},
|
||||
},
|
||||
}
|
||||
mds.EXPECT().GetEntry(gomock.Any(), gomock.Any()).Return(entry, nil)
|
||||
mds.EXPECT().GetValidateAttestationTypes(gomock.Any()).Return(false)
|
||||
mds.EXPECT().GetValidateStatus(gomock.Any()).Return(false)
|
||||
mds.EXPECT().GetValidateTrustAnchor(gomock.Any()).Return(true)
|
||||
|
||||
return mds
|
||||
},
|
||||
aaguid: aaguid,
|
||||
attestationType: string(metadata.BasicFull),
|
||||
attestationFormat: "packed",
|
||||
x5cs: nil,
|
||||
},
|
||||
{
|
||||
name: "ShouldFailWhenX5CNotBytes",
|
||||
setup: func(t *testing.T) metadata.Provider {
|
||||
ctrl := gomock.NewController(t)
|
||||
mds := mocks.NewMockMetadataProvider(ctrl)
|
||||
entry := &metadata.Entry{
|
||||
MetadataStatement: metadata.Statement{
|
||||
AttestationTypes: metadata.AuthenticatorAttestationTypes{metadata.BasicFull},
|
||||
},
|
||||
}
|
||||
mds.EXPECT().GetEntry(gomock.Any(), gomock.Any()).Return(entry, nil)
|
||||
mds.EXPECT().GetValidateAttestationTypes(gomock.Any()).Return(false)
|
||||
mds.EXPECT().GetValidateStatus(gomock.Any()).Return(false)
|
||||
mds.EXPECT().GetValidateTrustAnchor(gomock.Any()).Return(true)
|
||||
|
||||
return mds
|
||||
},
|
||||
aaguid: aaguid,
|
||||
attestationType: string(metadata.BasicFull),
|
||||
attestationFormat: "packed",
|
||||
x5cs: []any{"not-bytes"},
|
||||
err: &Error{Type: "invalid_metadata", Details: "Failed to parse attestation certificate from x5c during attestation validation for Authenticator Attestation GUID '0865c31d-05dc-4fb1-adce-3227bfb19967'.", DevInfo: "The 1st certificate in the attestation was type 'string' but '[]byte' was expected"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
mds := tc.setup(t)
|
||||
|
||||
assert.Equal(t, tc.err, ValidateMetadata(context.Background(), mds, tc.aaguid, tc.attestationType, tc.attestationFormat, tc.x5cs))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoopOrdinalNumber(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
n int
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "ShouldReturn1st",
|
||||
n: 0,
|
||||
expected: "1st",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturn2nd",
|
||||
n: 1,
|
||||
expected: "2nd",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturn3rd",
|
||||
n: 2,
|
||||
expected: "3rd",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturn4th",
|
||||
n: 3,
|
||||
expected: "4th",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturn10th",
|
||||
n: 9,
|
||||
expected: "10th",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturn11th",
|
||||
n: 10,
|
||||
expected: "11th",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturn12th",
|
||||
n: 11,
|
||||
expected: "12th",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturn13th",
|
||||
n: 12,
|
||||
expected: "13th",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturn21st",
|
||||
n: 20,
|
||||
expected: "21st",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturn22nd",
|
||||
n: 21,
|
||||
expected: "22nd",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturn23rd",
|
||||
n: 22,
|
||||
expected: "23rd",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturn100th",
|
||||
n: 99,
|
||||
expected: "100th",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert.Equal(t, tc.expected, loopOrdinalNumber(tc.n))
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user