This commit is contained in:
+552
@@ -0,0 +1,552 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/go-webauthn/webauthn/protocol/webauthncbor"
|
||||
"github.com/go-webauthn/webauthn/protocol/webauthncose"
|
||||
)
|
||||
|
||||
func TestParseCredentialCreationResponse(t *testing.T) {
|
||||
type args struct {
|
||||
responseName string
|
||||
}
|
||||
|
||||
byteID, _ := base64.RawURLEncoding.DecodeString("6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g")
|
||||
byteAuthData, _ := base64.RawURLEncoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
|
||||
byteRPIDHash, _ := base64.RawURLEncoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA")
|
||||
byteCredentialPubKey, _ := base64.RawURLEncoding.DecodeString("pSJYIMfCKfxl2SvnqJIiHQysHmpmITNgtCkQ5ESExSRjqrhXAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNc")
|
||||
byteAttObject, _ := base64.RawURLEncoding.DecodeString("o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
|
||||
byteClientDataJSON, _ := base64.RawURLEncoding.DecodeString("eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ")
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args args
|
||||
expected *ParsedCredentialCreationData
|
||||
err string
|
||||
errType string
|
||||
errDetails string
|
||||
errInfo string
|
||||
}{
|
||||
{
|
||||
name: "ShouldParseCredentialRequest",
|
||||
args: args{
|
||||
responseName: "success",
|
||||
},
|
||||
expected: &ParsedCredentialCreationData{
|
||||
ParsedPublicKeyCredential: ParsedPublicKeyCredential{
|
||||
ParsedCredential: ParsedCredential{
|
||||
ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
Type: string(PublicKeyCredentialType),
|
||||
},
|
||||
RawID: byteID,
|
||||
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
|
||||
"appid": true,
|
||||
},
|
||||
AuthenticatorAttachment: Platform,
|
||||
},
|
||||
Response: ParsedAttestationResponse{
|
||||
CollectedClientData: CollectedClientData{
|
||||
Type: CeremonyType("webauthn.create"),
|
||||
Challenge: "W8GzFU8pGjhoRbWrLDlamAfq_y4S1CZG1VuoeRLARrE",
|
||||
Origin: "https://webauthn.io",
|
||||
},
|
||||
AttestationObject: AttestationObject{
|
||||
Format: "none",
|
||||
RawAuthData: byteAuthData,
|
||||
AuthData: AuthenticatorData{
|
||||
RPIDHash: byteRPIDHash,
|
||||
Counter: 0,
|
||||
Flags: 0x041,
|
||||
AttData: AttestedCredentialData{
|
||||
AAGUID: make([]byte, 16),
|
||||
CredentialID: byteID,
|
||||
CredentialPublicKey: byteCredentialPubKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
Transports: []AuthenticatorTransport{USB, NFC, "fake"},
|
||||
},
|
||||
Raw: CredentialCreationResponse{
|
||||
PublicKeyCredential: PublicKeyCredential{
|
||||
Credential: Credential{
|
||||
Type: string(PublicKeyCredentialType),
|
||||
ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
},
|
||||
RawID: byteID,
|
||||
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
|
||||
"appid": true,
|
||||
},
|
||||
AuthenticatorAttachment: "platform",
|
||||
},
|
||||
AttestationResponse: AuthenticatorAttestationResponse{
|
||||
AuthenticatorResponse: AuthenticatorResponse{
|
||||
ClientDataJSON: byteClientDataJSON,
|
||||
},
|
||||
AttestationObject: byteAttObject,
|
||||
Transports: []string{"usb", "nfc", "fake"},
|
||||
},
|
||||
},
|
||||
},
|
||||
err: "",
|
||||
},
|
||||
{
|
||||
name: "ShouldHandleTrailingData",
|
||||
args: args{
|
||||
responseName: "trailingData",
|
||||
},
|
||||
expected: nil,
|
||||
err: "Parse error for Registration",
|
||||
errType: "invalid_request",
|
||||
errDetails: "Parse error for Registration",
|
||||
errInfo: "body contains trailing data",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
for _, subtest := range []string{"Response", "ResponseBody", "Bytes"} {
|
||||
t.Run(subtest, func(t *testing.T) {
|
||||
var (
|
||||
actual *ParsedCredentialCreationData
|
||||
err error
|
||||
)
|
||||
|
||||
switch subtest {
|
||||
case "Response":
|
||||
body := io.NopCloser(bytes.NewReader([]byte(testCredentialRequestResponses[tc.args.responseName])))
|
||||
|
||||
request := &http.Request{
|
||||
Body: body,
|
||||
}
|
||||
|
||||
actual, err = ParseCredentialCreationResponse(request)
|
||||
case "ResponseBody":
|
||||
body := io.NopCloser(bytes.NewReader([]byte(testCredentialRequestResponses[tc.args.responseName])))
|
||||
|
||||
actual, err = ParseCredentialCreationResponseBody(body)
|
||||
case "Bytes":
|
||||
body := []byte(testCredentialRequestResponses[tc.args.responseName])
|
||||
|
||||
actual, err = ParseCredentialCreationResponseBytes(body)
|
||||
}
|
||||
|
||||
if tc.err != "" {
|
||||
assert.EqualError(t, err, tc.err)
|
||||
|
||||
AssertIsProtocolError(t, err, tc.errType, tc.errDetails, tc.errInfo)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.expected.ClientExtensionResults, actual.ClientExtensionResults)
|
||||
assert.Equal(t, tc.expected.ID, actual.ID)
|
||||
assert.Equal(t, tc.expected.Type, actual.Type)
|
||||
assert.Equal(t, tc.expected.ParsedCredential, actual.ParsedCredential)
|
||||
assert.Equal(t, tc.expected.ParsedPublicKeyCredential, actual.ParsedPublicKeyCredential)
|
||||
assert.Equal(t, tc.expected.Raw, actual.Raw)
|
||||
assert.Equal(t, tc.expected.RawID, actual.RawID)
|
||||
assert.Equal(t, tc.expected.Response.Transports, actual.Response.Transports)
|
||||
assert.Equal(t, tc.expected.Response.CollectedClientData, actual.Response.CollectedClientData)
|
||||
assert.Equal(t, tc.expected.Response.AttestationObject.AuthData.AttData.CredentialID, actual.Response.AttestationObject.AuthData.AttData.CredentialID)
|
||||
assert.Equal(t, tc.expected.Response.AttestationObject.Format, actual.Response.AttestationObject.Format)
|
||||
|
||||
var pkExpected, pkActual any
|
||||
|
||||
pkBytesExpected := tc.expected.Response.AttestationObject.AuthData.AttData.CredentialPublicKey
|
||||
assert.NoError(t, webauthncbor.Unmarshal(pkBytesExpected, &pkExpected))
|
||||
|
||||
pkBytesActual := actual.Response.AttestationObject.AuthData.AttData.CredentialPublicKey
|
||||
assert.NoError(t, webauthncbor.Unmarshal(pkBytesActual, &pkActual))
|
||||
|
||||
assert.Equal(t, pkExpected, pkActual)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsedCredentialCreationData_Verify(t *testing.T) {
|
||||
byteID, _ := base64.RawURLEncoding.DecodeString("6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g")
|
||||
byteChallenge, _ := base64.RawURLEncoding.DecodeString("W8GzFU8pGjhoRbWrLDlamAfq_y4S1CZG1VuoeRLARrE")
|
||||
byteAuthData, _ := base64.RawURLEncoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
|
||||
byteRPIDHash, _ := base64.RawURLEncoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA")
|
||||
byteCredentialPubKey, _ := base64.RawURLEncoding.DecodeString("pSJYIMfCKfxl2SvnqJIiHQysHmpmITNgtCkQ5ESExSRjqrhXAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNc")
|
||||
byteAttObject, _ := base64.RawURLEncoding.DecodeString("o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
|
||||
byteClientDataJSON, _ := base64.RawURLEncoding.DecodeString("eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ")
|
||||
|
||||
type fields struct {
|
||||
ParsedPublicKeyCredential ParsedPublicKeyCredential
|
||||
Response ParsedAttestationResponse
|
||||
Raw CredentialCreationResponse
|
||||
}
|
||||
|
||||
type args struct {
|
||||
storedChallenge URLEncodedBase64
|
||||
verifyUser bool
|
||||
relyingPartyID string
|
||||
relyingPartyOrigin []string
|
||||
credParams []CredentialParameter
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
expected []byte
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "SuccessfulVerificationTest",
|
||||
fields: fields{
|
||||
ParsedPublicKeyCredential: ParsedPublicKeyCredential{
|
||||
ParsedCredential: ParsedCredential{
|
||||
ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
Type: string(PublicKeyCredentialType),
|
||||
},
|
||||
RawID: byteID,
|
||||
},
|
||||
Response: ParsedAttestationResponse{
|
||||
CollectedClientData: CollectedClientData{
|
||||
Type: CeremonyType("webauthn.create"),
|
||||
Challenge: "W8GzFU8pGjhoRbWrLDlamAfq_y4S1CZG1VuoeRLARrE",
|
||||
Origin: "https://webauthn.io",
|
||||
},
|
||||
AttestationObject: AttestationObject{
|
||||
Format: "none",
|
||||
RawAuthData: byteAuthData,
|
||||
AuthData: AuthenticatorData{
|
||||
RPIDHash: byteRPIDHash,
|
||||
Counter: 0,
|
||||
Flags: 0x041,
|
||||
AttData: AttestedCredentialData{
|
||||
AAGUID: make([]byte, 16),
|
||||
CredentialID: byteID,
|
||||
CredentialPublicKey: byteCredentialPubKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Raw: CredentialCreationResponse{
|
||||
PublicKeyCredential: PublicKeyCredential{
|
||||
Credential: Credential{
|
||||
Type: string(PublicKeyCredentialType),
|
||||
ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
},
|
||||
RawID: byteID,
|
||||
},
|
||||
AttestationResponse: AuthenticatorAttestationResponse{
|
||||
AuthenticatorResponse: AuthenticatorResponse{
|
||||
ClientDataJSON: byteClientDataJSON,
|
||||
},
|
||||
AttestationObject: byteAttObject,
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
storedChallenge: URLEncodedBase64(byteChallenge),
|
||||
verifyUser: false,
|
||||
relyingPartyID: `webauthn.io`,
|
||||
relyingPartyOrigin: []string{`https://webauthn.io`},
|
||||
credParams: []CredentialParameter{{Type: "public-key", Algorithm: webauthncose.AlgES256}},
|
||||
},
|
||||
expected: []byte{0xa, 0xaf, 0x43, 0xda, 0x7e, 0xd3, 0x94, 0x98, 0x9b, 0xbc, 0x47, 0xcb, 0x0, 0x72, 0x6b, 0xbc, 0xf3, 0xa2, 0x4a, 0x49, 0x5f, 0x84, 0x4f, 0x45, 0x97, 0x91, 0x6a, 0x2d, 0xff, 0x47, 0xbc, 0xad},
|
||||
err: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
pcc := &ParsedCredentialCreationData{
|
||||
ParsedPublicKeyCredential: tc.fields.ParsedPublicKeyCredential,
|
||||
Response: tc.fields.Response,
|
||||
Raw: tc.fields.Raw,
|
||||
}
|
||||
|
||||
actual, err := pcc.Verify(tc.args.storedChallenge.String(), tc.args.relyingPartyID, tc.args.relyingPartyOrigin, nil, TopOriginExplicitVerificationMode, false, tc.args.verifyUser, false, nil, tc.args.credParams)
|
||||
|
||||
assert.Equal(t, tc.expected, actual)
|
||||
|
||||
if tc.err != "" {
|
||||
assert.EqualError(t, err, tc.err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCredentialCreationResponse_NilRequest(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
request *http.Request
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "ShouldFailNilRequest",
|
||||
request: nil,
|
||||
err: "No response given",
|
||||
},
|
||||
{
|
||||
name: "ShouldFailNilBody",
|
||||
request: &http.Request{},
|
||||
err: "No response given",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
result, err := ParseCredentialCreationResponse(tc.request)
|
||||
assert.Nil(t, result)
|
||||
assert.EqualError(t, err, tc.err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCredentialCreationResponse_Parse_Errors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
ccr CredentialCreationResponse
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "ShouldFailMissingID",
|
||||
ccr: CredentialCreationResponse{},
|
||||
err: "Parse error for Registration",
|
||||
},
|
||||
{
|
||||
name: "ShouldFailIDNotBase64",
|
||||
ccr: CredentialCreationResponse{
|
||||
PublicKeyCredential: PublicKeyCredential{
|
||||
Credential: Credential{
|
||||
ID: "not valid base64 %%%",
|
||||
},
|
||||
},
|
||||
},
|
||||
err: "Parse error for Registration",
|
||||
},
|
||||
{
|
||||
name: "ShouldFailMissingType",
|
||||
ccr: CredentialCreationResponse{
|
||||
PublicKeyCredential: PublicKeyCredential{
|
||||
Credential: Credential{
|
||||
ID: "dGVzdA",
|
||||
},
|
||||
},
|
||||
},
|
||||
err: "Parse error for Registration",
|
||||
},
|
||||
{
|
||||
name: "ShouldFailBadType",
|
||||
ccr: CredentialCreationResponse{
|
||||
PublicKeyCredential: PublicKeyCredential{
|
||||
Credential: Credential{
|
||||
ID: "dGVzdA",
|
||||
Type: "bad-type",
|
||||
},
|
||||
},
|
||||
},
|
||||
err: "Parse error for Registration",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
result, err := tc.ccr.Parse()
|
||||
assert.Nil(t, result)
|
||||
assert.EqualError(t, err, tc.err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAppID(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
ppkc ParsedPublicKeyCredential
|
||||
authExt AuthenticationExtensions
|
||||
credentialAttestationFormat string
|
||||
expectedAppID string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "ShouldReturnEmptyWhenAuthExtNil",
|
||||
ppkc: ParsedPublicKeyCredential{},
|
||||
authExt: nil,
|
||||
credentialAttestationFormat: string(AttestationFormatFIDOUniversalSecondFactor),
|
||||
expectedAppID: "",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturnEmptyWhenClientExtNil",
|
||||
ppkc: ParsedPublicKeyCredential{},
|
||||
authExt: AuthenticationExtensions{ExtensionAppID: "https://example.com"},
|
||||
credentialAttestationFormat: string(AttestationFormatFIDOUniversalSecondFactor),
|
||||
expectedAppID: "",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturnEmptyWhenNotFIDOU2F",
|
||||
ppkc: ParsedPublicKeyCredential{
|
||||
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
|
||||
ExtensionAppID: true,
|
||||
},
|
||||
},
|
||||
authExt: AuthenticationExtensions{ExtensionAppID: "https://example.com"},
|
||||
credentialAttestationFormat: "packed",
|
||||
expectedAppID: "",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturnEmptyWhenAppIDNotInClientExt",
|
||||
ppkc: ParsedPublicKeyCredential{
|
||||
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
|
||||
"other": "value",
|
||||
},
|
||||
},
|
||||
authExt: AuthenticationExtensions{ExtensionAppID: "https://example.com"},
|
||||
credentialAttestationFormat: string(AttestationFormatFIDOUniversalSecondFactor),
|
||||
expectedAppID: "",
|
||||
},
|
||||
{
|
||||
name: "ShouldFailWhenClientAppIDNotBool",
|
||||
ppkc: ParsedPublicKeyCredential{
|
||||
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
|
||||
ExtensionAppID: "not-a-bool",
|
||||
},
|
||||
},
|
||||
authExt: AuthenticationExtensions{ExtensionAppID: "https://example.com"},
|
||||
credentialAttestationFormat: string(AttestationFormatFIDOUniversalSecondFactor),
|
||||
err: "Client Output appid did not have the expected type",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturnEmptyWhenAppIDFalse",
|
||||
ppkc: ParsedPublicKeyCredential{
|
||||
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
|
||||
ExtensionAppID: false,
|
||||
},
|
||||
},
|
||||
authExt: AuthenticationExtensions{ExtensionAppID: "https://example.com"},
|
||||
credentialAttestationFormat: string(AttestationFormatFIDOUniversalSecondFactor),
|
||||
expectedAppID: "",
|
||||
},
|
||||
{
|
||||
name: "ShouldFailWhenSessionAppIDMissing",
|
||||
ppkc: ParsedPublicKeyCredential{
|
||||
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
|
||||
ExtensionAppID: true,
|
||||
},
|
||||
},
|
||||
authExt: AuthenticationExtensions{},
|
||||
credentialAttestationFormat: string(AttestationFormatFIDOUniversalSecondFactor),
|
||||
err: "Session Data does not have an appid but Client Output indicates it should be set",
|
||||
},
|
||||
{
|
||||
name: "ShouldFailWhenSessionAppIDNotString",
|
||||
ppkc: ParsedPublicKeyCredential{
|
||||
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
|
||||
ExtensionAppID: true,
|
||||
},
|
||||
},
|
||||
authExt: AuthenticationExtensions{ExtensionAppID: 123},
|
||||
credentialAttestationFormat: string(AttestationFormatFIDOUniversalSecondFactor),
|
||||
err: "Session Data appid did not have the expected type",
|
||||
},
|
||||
{
|
||||
name: "ShouldReturnAppID",
|
||||
ppkc: ParsedPublicKeyCredential{
|
||||
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
|
||||
ExtensionAppID: true,
|
||||
},
|
||||
},
|
||||
authExt: AuthenticationExtensions{ExtensionAppID: "https://example.com"},
|
||||
credentialAttestationFormat: string(AttestationFormatFIDOUniversalSecondFactor),
|
||||
expectedAppID: "https://example.com",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
appID, err := tc.ppkc.GetAppID(tc.authExt, tc.credentialAttestationFormat)
|
||||
if tc.err != "" {
|
||||
assert.EqualError(t, err, tc.err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedAppID, appID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var testCredentialRequestResponses = map[string]string{
|
||||
`success`: `
|
||||
{
|
||||
"id":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
"rawId":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
"type":"public-key",
|
||||
"authenticatorAttachment":"platform",
|
||||
"clientExtensionResults":{
|
||||
"appid":true
|
||||
},
|
||||
"response":{
|
||||
"attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw",
|
||||
"clientDataJSON":"eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ",
|
||||
"transports":["usb","nfc","fake"]
|
||||
}
|
||||
}
|
||||
`,
|
||||
`trailingData`: `
|
||||
{
|
||||
"id":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
"rawId":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
"type":"public-key",
|
||||
"authenticatorAttachment":"platform",
|
||||
"clientExtensionResults":{
|
||||
"appid":true
|
||||
},
|
||||
"response":{
|
||||
"attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw",
|
||||
"clientDataJSON":"eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ",
|
||||
"transports":["usb","nfc","fake"]
|
||||
}
|
||||
}
|
||||
|
||||
trailing
|
||||
`,
|
||||
`successDeprecatedTransports`: `
|
||||
{
|
||||
"id":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
"rawId":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
"type":"public-key",
|
||||
"authenticatorAttachment":"not-valid",
|
||||
"transports":["usb","nfc","fake"],
|
||||
"clientExtensionResults":{
|
||||
"appid":true
|
||||
},
|
||||
"response":{
|
||||
"attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw",
|
||||
"clientDataJSON":"eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ"
|
||||
}
|
||||
}
|
||||
`,
|
||||
`successDeprecatedTransportsAndNew`: `
|
||||
{
|
||||
"id":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
"rawId":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
|
||||
"type":"public-key",
|
||||
"authenticatorAttachment":"cross-platform",
|
||||
"transports":["usb","nfc","fake"],
|
||||
"clientExtensionResults":{
|
||||
"appid":true
|
||||
},
|
||||
"response":{
|
||||
"attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw",
|
||||
"clientDataJSON":"eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ",
|
||||
"transports":["usb","nfc"]
|
||||
}
|
||||
}
|
||||
`,
|
||||
}
|
||||
Reference in New Issue
Block a user