diff --git a/metadata/decode.go b/metadata/decode.go index db03a09..f290012 100644 --- a/metadata/decode.go +++ b/metadata/decode.go @@ -46,9 +46,9 @@ type Decoder struct { } // Parse handles parsing of the raw JSON values of the metadata blob. Should be used after using Decode or DecodeBytes. -func (d *Decoder) Parse(payload *MetadataBLOBPayloadJSON) (metadata *Metadata, err error) { +func (d *Decoder) Parse(payload *PayloadJSON) (metadata *Metadata, err error) { metadata = &Metadata{ - Parsed: MetadataBLOBPayload{ + Parsed: Parsed{ LegalHeader: payload.LegalHeader, Number: payload.Number, }, @@ -58,13 +58,13 @@ func (d *Decoder) Parse(payload *MetadataBLOBPayloadJSON) (metadata *Metadata, e return nil, fmt.Errorf("error occurred parsing next update value '%s': %w", payload.NextUpdate, err) } - var parsed MetadataBLOBPayloadEntry + var parsed Entry for _, entry := range payload.Entries { if parsed, err = entry.Parse(); err != nil { - metadata.Unparsed = append(metadata.Unparsed, MetadataBLOBPayloadEntryError{ - Error: err, - MetadataBLOBPayloadEntryJSON: entry, + metadata.Unparsed = append(metadata.Unparsed, EntryError{ + Error: err, + EntryJSON: entry, }) continue @@ -81,7 +81,7 @@ func (d *Decoder) Parse(payload *MetadataBLOBPayloadJSON) (metadata *Metadata, e } // Decode the blob from an io.ReadCloser. This function will close the io.ReadCloser after completing. -func (d *Decoder) Decode(r io.ReadCloser) (payload *MetadataBLOBPayloadJSON, err error) { +func (d *Decoder) Decode(r io.ReadCloser) (payload *PayloadJSON, err error) { defer r.Close() bytes, err := io.ReadAll(r) @@ -93,8 +93,8 @@ func (d *Decoder) Decode(r io.ReadCloser) (payload *MetadataBLOBPayloadJSON, err } // DecodeBytes handles decoding raw bytes. If you have a read closer it's suggested to use Decode. -func (d *Decoder) DecodeBytes(bytes []byte) (payload *MetadataBLOBPayloadJSON, err error) { - payload = &MetadataBLOBPayloadJSON{} +func (d *Decoder) DecodeBytes(bytes []byte) (payload *PayloadJSON, err error) { + payload = &PayloadJSON{} var token *jwt.Token diff --git a/metadata/metadata.go b/metadata/metadata.go index 2f6b1f4..58dfb4b 100644 --- a/metadata/metadata.go +++ b/metadata/metadata.go @@ -17,7 +17,7 @@ import ( func Fetch() (metadata *Metadata, err error) { var ( decoder *Decoder - payload *MetadataBLOBPayloadJSON + payload *PayloadJSON res *http.Response ) @@ -39,12 +39,12 @@ func Fetch() (metadata *Metadata, err error) { } type Metadata struct { - Parsed MetadataBLOBPayload - Unparsed []MetadataBLOBPayloadEntryError + Parsed Parsed + Unparsed []EntryError } -func (m *Metadata) ToMap() (metadata map[uuid.UUID]*MetadataBLOBPayloadEntry) { - metadata = make(map[uuid.UUID]*MetadataBLOBPayloadEntry) +func (m *Metadata) ToMap() (metadata map[uuid.UUID]*Entry) { + metadata = make(map[uuid.UUID]*Entry) for _, entry := range m.Parsed.Entries { if entry.AaGUID != uuid.Nil { @@ -55,15 +55,10 @@ func (m *Metadata) ToMap() (metadata map[uuid.UUID]*MetadataBLOBPayloadEntry) { return metadata } -type MetadataBLOBPayloadEntryError struct { - Error error - MetadataBLOBPayloadEntryJSON -} - -// MetadataBLOBPayload is a structure representing the MetadataBLOBPayload MDS3 dictionary. +// Parsed is a structure representing the Parsed MDS3 dictionary. // // See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html#metadata-blob-payload-entry-dictionary -type MetadataBLOBPayload struct { +type Parsed struct { // The legalHeader, if present, contains a legal guide for accessing and using metadata, which itself MAY contain URL(s) pointing to further information, such as a full Terms and Conditions statement. LegalHeader string @@ -74,19 +69,19 @@ type MetadataBLOBPayload struct { NextUpdate time.Time // List of zero or more MetadataTOCPayloadEntry objects. - Entries []MetadataBLOBPayloadEntry + Entries []Entry } -// MetadataBLOBPayloadJSON is an intermediary JSON/JWT representation of the MetadataBLOBPayload. -type MetadataBLOBPayloadJSON struct { +// PayloadJSON is an intermediary JSON/JWT representation of the Parsed. +type PayloadJSON struct { LegalHeader string `json:"legalHeader"` Number int `json:"no"` NextUpdate string `json:"nextUpdate"` - Entries []MetadataBLOBPayloadEntryJSON `json:"entries"` + Entries []EntryJSON `json:"entries"` } -func (j MetadataBLOBPayloadJSON) Parse() (payload MetadataBLOBPayload, err error) { +func (j PayloadJSON) Parse() (payload Parsed, err error) { var update time.Time if update, err = time.Parse(time.DateOnly, j.NextUpdate); err != nil { @@ -95,7 +90,7 @@ func (j MetadataBLOBPayloadJSON) Parse() (payload MetadataBLOBPayload, err error n := len(j.Entries) - entries := make([]MetadataBLOBPayloadEntry, n) + entries := make([]Entry, n) for i := 0; i < n; i++ { if entries[i], err = j.Entries[i].Parse(); err != nil { @@ -103,7 +98,7 @@ func (j MetadataBLOBPayloadJSON) Parse() (payload MetadataBLOBPayload, err error } } - return MetadataBLOBPayload{ + return Parsed{ LegalHeader: j.LegalHeader, Number: j.Number, NextUpdate: update, @@ -111,10 +106,10 @@ func (j MetadataBLOBPayloadJSON) Parse() (payload MetadataBLOBPayload, err error }, nil } -// MetadataBLOBPayloadEntry is a structure representing the MetadataBLOBPayloadEntry MDS3 dictionary. +// Entry is a structure representing the Entry MDS3 dictionary. // // See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html#metadata-blob-payload-entry-dictionary -type MetadataBLOBPayloadEntry struct { +type Entry struct { // The Authenticator Attestation ID. Aaid string `json:"aaid"` @@ -125,7 +120,7 @@ type MetadataBLOBPayloadEntry struct { AttestationCertificateKeyIdentifiers []string `json:"attestationCertificateKeyIdentifiers"` // The metadataStatement JSON object as defined in FIDOMetadataStatement. - MetadataStatement MetadataStatement `json:"metadataStatement"` + MetadataStatement Statement `json:"metadataStatement"` // Status of the FIDO Biometric Certification of one or more biometric components of the Authenticator BiometricStatusReports []BiometricStatusReport `json:"biometricStatusReports"` @@ -143,15 +138,15 @@ type MetadataBLOBPayloadEntry struct { RogueListHash string } -// MetadataBLOBPayloadEntryJSON is an intermediary JSON/JWT structure representing the MetadataBLOBPayloadEntry MDS3 dictionary. +// EntryJSON is an intermediary JSON/JWT structure representing the Entry MDS3 dictionary. // // See: https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html#metadata-blob-payload-entry-dictionary -type MetadataBLOBPayloadEntryJSON struct { +type EntryJSON struct { Aaid string `json:"aaid"` AaGUID string `json:"aaguid"` AttestationCertificateKeyIdentifiers []string `json:"attestationCertificateKeyIdentifiers"` - MetadataStatement MetadataStatementJSON `json:"metadataStatement"` + MetadataStatement StatementJSON `json:"metadataStatement"` BiometricStatusReports []BiometricStatusReportJSON `json:"biometricStatusReports"` StatusReports []StatusReportJSON `json:"statusReports"` @@ -160,7 +155,7 @@ type MetadataBLOBPayloadEntryJSON struct { RogueListHash string `json:"rogueListHash"` } -func (j MetadataBLOBPayloadEntryJSON) Parse() (entry MetadataBLOBPayloadEntry, err error) { +func (j EntryJSON) Parse() (entry Entry, err error) { var aaguid uuid.UUID if len(j.AaGUID) != 0 { @@ -169,7 +164,7 @@ func (j MetadataBLOBPayloadEntryJSON) Parse() (entry MetadataBLOBPayloadEntry, e } } - var statement MetadataStatement + var statement Statement if statement, err = j.MetadataStatement.Parse(); err != nil { return entry, fmt.Errorf("error occurred parsing metadata entry with AAGUID '%s': %w", j.AaGUID, err) @@ -215,7 +210,7 @@ func (j MetadataBLOBPayloadEntryJSON) Parse() (entry MetadataBLOBPayloadEntry, e } } - return MetadataBLOBPayloadEntry{ + return Entry{ Aaid: j.Aaid, AaGUID: aaguid, AttestationCertificateKeyIdentifiers: j.AttestationCertificateKeyIdentifiers, @@ -228,12 +223,12 @@ func (j MetadataBLOBPayloadEntryJSON) Parse() (entry MetadataBLOBPayloadEntry, e }, nil } -// MetadataStatement is a structure representing the MetadataStatement MDS3 dictionary. +// Statement is a structure representing the Statement MDS3 dictionary. // Authenticator metadata statements are used directly by the FIDO server at a relying party, but the information // contained in the authoritative statement is used in several other places. // // See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.0-ps-20210518.html#metadata-keys -type MetadataStatement struct { +type Statement struct { // The legalHeader, if present, contains a legal guide for accessing and using metadata, which itself MAY contain URL(s) pointing to further information, such as a full Terms and Conditions statement. LegalHeader string @@ -321,7 +316,7 @@ type MetadataStatement struct { AuthenticatorGetInfo AuthenticatorGetInfo } -func (s *MetadataStatement) Verifier() (opts x509.VerifyOptions) { +func (s *Statement) Verifier() (opts x509.VerifyOptions) { roots := x509.NewCertPool() for _, root := range s.AttestationRootCertificates { @@ -333,12 +328,12 @@ func (s *MetadataStatement) Verifier() (opts x509.VerifyOptions) { } } -// MetadataStatementJSON is an intermediary JSON/JWT structure representing the MetadataStatement MDS3 dictionary. +// StatementJSON is an intermediary JSON/JWT structure representing the Statement MDS3 dictionary. // Authenticator metadata statements are used directly by the FIDO server at a relying party, but the information // contained in the authoritative statement is used in several other places. // // See: https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.0-ps-20210518.html#metadata-keys -type MetadataStatementJSON struct { +type StatementJSON struct { LegalHeader string `json:"legalHeader"` Aaid string `json:"aaid"` AaGUID string `json:"aaguid"` @@ -368,7 +363,7 @@ type MetadataStatementJSON struct { AuthenticatorGetInfo AuthenticatorGetInfoJSON `json:"authenticatorGetInfo"` } -func (j MetadataStatementJSON) Parse() (statement MetadataStatement, err error) { +func (j StatementJSON) Parse() (statement Statement, err error) { var aaguid uuid.UUID if len(j.AaGUID) != 0 { @@ -401,7 +396,7 @@ func (j MetadataStatementJSON) Parse() (statement MetadataStatement, err error) return statement, fmt.Errorf("error occurred parsing statement with description '%s': error occurred parsing authenticator get info value: %w", j.Description, err) } - return MetadataStatement{ + return Statement{ LegalHeader: j.LegalHeader, Aaid: j.Aaid, AaGUID: aaguid, @@ -914,3 +909,8 @@ func DefaultUndesiredAuthenticatorStatuses() []AuthenticatorStatus { return undesired } + +type EntryError struct { + Error error + EntryJSON +} diff --git a/metadata/metadata_test.go b/metadata/metadata_test.go index cadecb3..eeca71a 100644 --- a/metadata/metadata_test.go +++ b/metadata/metadata_test.go @@ -81,11 +81,11 @@ func TestConformanceMetadataTOCParsing(t *testing.T) { require.NoError(t, err) - metadata := make(map[uuid.UUID]MetadataBLOBPayloadEntryJSON) + metadata := make(map[uuid.UUID]EntryJSON) var ( res *http.Response - blob *MetadataBLOBPayloadJSON + blob *PayloadJSON me *MetadataError ) @@ -317,8 +317,8 @@ func getEndpoints(c *http.Client) ([]string, error) { return resp.Result, err } -func getTestMetadata(s string, c *http.Client) (MetadataStatementJSON, error) { - var statement MetadataStatementJSON +func getTestMetadata(s string, c *http.Client) (StatementJSON, error) { + var statement StatementJSON // MDSGetEndpointsRequest is the request sent to the conformance metadata getEndpoints endpoint. type MDSGetTestMetadata struct { @@ -345,8 +345,8 @@ func getTestMetadata(s string, c *http.Client) (MetadataStatementJSON, error) { } type ConformanceResponse struct { - Status string `json:"status"` - Result MetadataStatementJSON `json:"result"` + Status string `json:"status"` + Result StatementJSON `json:"result"` } var resp ConformanceResponse diff --git a/metadata/providers/cached/provider.go b/metadata/providers/cached/provider.go index ad38938..d8a0dd1 100644 --- a/metadata/providers/cached/provider.go +++ b/metadata/providers/cached/provider.go @@ -114,7 +114,7 @@ func (p *Provider) init() (err error) { } func (p *Provider) parse(rc io.ReadCloser) (data *metadata.Metadata, err error) { - var payload *metadata.MetadataBLOBPayloadJSON + var payload *metadata.PayloadJSON if payload, err = p.decoder.Decode(rc); err != nil { return nil, err diff --git a/metadata/providers/memory/options.go b/metadata/providers/memory/options.go index 1281e2f..7089bed 100644 --- a/metadata/providers/memory/options.go +++ b/metadata/providers/memory/options.go @@ -10,7 +10,7 @@ import ( type Option func(provider *Provider) (err error) // WithMetadata provides the required metadata for the memory provider. -func WithMetadata(mds map[uuid.UUID]*metadata.MetadataBLOBPayloadEntry) Option { +func WithMetadata(mds map[uuid.UUID]*metadata.Entry) Option { return func(provider *Provider) (err error) { provider.mds = mds diff --git a/metadata/providers/memory/provider.go b/metadata/providers/memory/provider.go index f935c0a..052b7e9 100644 --- a/metadata/providers/memory/provider.go +++ b/metadata/providers/memory/provider.go @@ -31,7 +31,7 @@ func New(opts ...Option) (provider metadata.Provider, err error) { // a simple one-shot that doesn't perform any locking, provide dynamic functionality, or download the metadata at any // stage (it expects it's provided via one of the Option's). type Provider struct { - mds map[uuid.UUID]*metadata.MetadataBLOBPayloadEntry + mds map[uuid.UUID]*metadata.Entry desired []metadata.AuthenticatorStatus undesired []metadata.AuthenticatorStatus entry bool @@ -40,7 +40,7 @@ type Provider struct { status bool } -func (p *Provider) GetEntry(ctx context.Context, aaguid uuid.UUID) (entry *metadata.MetadataBLOBPayloadEntry, err error) { +func (p *Provider) GetEntry(ctx context.Context, aaguid uuid.UUID) (entry *metadata.Entry, err error) { if p.mds == nil { return nil, metadata.ErrNotInitialized } diff --git a/metadata/types.go b/metadata/types.go index 72cb84a..daf5f1a 100644 --- a/metadata/types.go +++ b/metadata/types.go @@ -13,7 +13,7 @@ import ( type Provider interface { // GetEntry returns a MDS3 payload entry given a AAGUID. This - GetEntry(ctx context.Context, aaguid uuid.UUID) (entry *MetadataBLOBPayloadEntry, err error) + GetEntry(ctx context.Context, aaguid uuid.UUID) (entry *Entry, err error) // GetValidateEntry returns true if this provider requires an entry to exist with a AAGUID matching the attestation // statement during registration. diff --git a/protocol/attestation.go b/protocol/attestation.go index 90979e3..fc8f0f2 100644 --- a/protocol/attestation.go +++ b/protocol/attestation.go @@ -173,7 +173,7 @@ func (a *AttestationObject) VerifyAttestation(clientDataHash []byte, mds metadat var ( aaguid uuid.UUID - entry *metadata.MetadataBLOBPayloadEntry + entry *metadata.Entry ) if len(a.AuthData.AttData.AAGUID) != 0 { diff --git a/protocol/metadata.go b/protocol/metadata.go new file mode 100644 index 0000000..a7e6651 --- /dev/null +++ b/protocol/metadata.go @@ -0,0 +1,44 @@ +package protocol + +import ( + "context" + "fmt" + + "github.com/google/uuid" + + "github.com/go-webauthn/webauthn/metadata" +) + +func ValidateMetadata(ctx context.Context, aaguid uuid.UUID, mds metadata.Provider) (err error) { + if mds == nil { + return nil + } + + var ( + entry *metadata.Entry + ) + + if entry, err = mds.GetEntry(ctx, aaguid); err != nil { + return err + } + + if entry == nil { + if aaguid == uuid.Nil && mds.GetValidateEntryPermitZeroAAGUID(ctx) { + return nil + } + + if mds.GetValidateEntry(ctx) { + return fmt.Errorf("error occurred performing authenticator entry validation: AAGUID entry has not been registered with the metadata service") + } + + return nil + } + + if mds.GetValidateStatus(ctx) { + if err = mds.ValidateStatusReports(ctx, entry.StatusReports); err != nil { + return fmt.Errorf("error occurred performing authenticator status validation: %w", err) + } + } + + return nil +} diff --git a/webauthn/login.go b/webauthn/login.go index bbff80d..d5a01b3 100644 --- a/webauthn/login.go +++ b/webauthn/login.go @@ -2,11 +2,14 @@ package webauthn import ( "bytes" + "context" "fmt" "net/http" "net/url" "time" + "github.com/google/uuid" + "github.com/go-webauthn/webauthn/protocol" ) @@ -222,16 +225,19 @@ func (webauthn *WebAuthn) validateLogin(user User, session SessionData, parsedRe // allowCredentials. // NON-NORMATIVE Prior Step: Verify that the allowCredentials for the session are owned by the user provided. - userCredentials := user.WebAuthnCredentials() + credentials := user.WebAuthnCredentials() - var credentialFound bool + var ( + found bool + credential Credential + ) if len(session.AllowedCredentialIDs) > 0 { var credentialsOwned bool for _, allowedCredentialID := range session.AllowedCredentialIDs { - for _, userCredential := range userCredentials { - if bytes.Equal(userCredential.ID, allowedCredentialID) { + for _, credential = range credentials { + if bytes.Equal(credential.ID, allowedCredentialID) { credentialsOwned = true break @@ -247,13 +253,13 @@ func (webauthn *WebAuthn) validateLogin(user User, session SessionData, parsedRe for _, allowedCredentialID := range session.AllowedCredentialIDs { if bytes.Equal(parsedResponse.RawID, allowedCredentialID) { - credentialFound = true + found = true break } } - if !credentialFound { + if !found { return nil, protocol.ErrBadRequest.WithDetails("User does not own the credential returned") } } @@ -272,44 +278,57 @@ func (webauthn *WebAuthn) validateLogin(user User, session SessionData, parsedRe // Step 3. Using credential’s id attribute (or the corresponding rawId, if base64url encoding is inappropriate // for your use case), look up the corresponding credential public key. - var loginCredential Credential - - for _, cred := range userCredentials { - if bytes.Equal(cred.ID, parsedResponse.RawID) { - loginCredential = cred - credentialFound = true + for _, credential = range credentials { + if bytes.Equal(credential.ID, parsedResponse.RawID) { + found = true break } - credentialFound = false + found = false } - if !credentialFound { + if !found { return nil, protocol.ErrBadRequest.WithDetails("Unable to find the credential for the returned credential ID") } + var ( + appID string + err error + ) + + // Ensure authenticators with a bad status is not used. + if webauthn.Config.MDS != nil { + var aaguid uuid.UUID + + if aaguid, err = uuid.FromBytes(credential.Authenticator.AAGUID); err != nil { + return nil, protocol.ErrBadRequest.WithDetails("Failed to decode AAGUID").WithInfo(fmt.Sprintf("Error occurred decoding AAGUID from the credential record: %s", err)) + } + + if err = protocol.ValidateMetadata(context.Background(), aaguid, webauthn.Config.MDS); err != nil { + return nil, protocol.ErrBadRequest.WithDetails("Failed to validate credential record metadata").WithInfo(fmt.Sprintf("Error occurred validating authenticator metadata from the credential record: %s", err)) + } + } + shouldVerifyUser := session.UserVerification == protocol.VerificationRequired rpID := webauthn.Config.RPID rpOrigins := webauthn.Config.RPOrigins rpTopOrigins := webauthn.Config.RPTopOrigins - appID, err := parsedResponse.GetAppID(session.Extensions, loginCredential.AttestationType) - if err != nil { + if appID, err = parsedResponse.GetAppID(session.Extensions, credential.AttestationType); err != nil { return nil, err } // Handle steps 4 through 16. - validError := parsedResponse.Verify(session.Challenge, rpID, rpOrigins, rpTopOrigins, webauthn.Config.RPTopOriginVerificationMode, appID, shouldVerifyUser, loginCredential.PublicKey) - if validError != nil { - return nil, validError + if err = parsedResponse.Verify(session.Challenge, rpID, rpOrigins, rpTopOrigins, webauthn.Config.RPTopOriginVerificationMode, appID, shouldVerifyUser, credential.PublicKey); err != nil { + return nil, err } // Handle step 17. - loginCredential.Authenticator.UpdateCounter(parsedResponse.Response.AuthenticatorData.Counter) + credential.Authenticator.UpdateCounter(parsedResponse.Response.AuthenticatorData.Counter) // Check if the BackupEligible flag has changed. - if loginCredential.Flags.BackupEligible != parsedResponse.Response.AuthenticatorData.Flags.HasBackupEligible() { + if credential.Flags.BackupEligible != parsedResponse.Response.AuthenticatorData.Flags.HasBackupEligible() { return nil, protocol.ErrBadRequest.WithDetails("BackupEligible flag inconsistency detected during login validation") } @@ -319,10 +338,10 @@ func (webauthn *WebAuthn) validateLogin(user User, session SessionData, parsedRe } // Update flags from response data. - loginCredential.Flags.UserPresent = parsedResponse.Response.AuthenticatorData.Flags.HasUserPresent() - loginCredential.Flags.UserVerified = parsedResponse.Response.AuthenticatorData.Flags.HasUserVerified() - loginCredential.Flags.BackupEligible = parsedResponse.Response.AuthenticatorData.Flags.HasBackupEligible() - loginCredential.Flags.BackupState = parsedResponse.Response.AuthenticatorData.Flags.HasBackupState() + credential.Flags.UserPresent = parsedResponse.Response.AuthenticatorData.Flags.HasUserPresent() + credential.Flags.UserVerified = parsedResponse.Response.AuthenticatorData.Flags.HasUserVerified() + credential.Flags.BackupEligible = parsedResponse.Response.AuthenticatorData.Flags.HasBackupEligible() + credential.Flags.BackupState = parsedResponse.Response.AuthenticatorData.Flags.HasBackupState() - return &loginCredential, nil + return &credential, nil } diff --git a/webauthn/registration.go b/webauthn/registration.go index 3352eb2..79590da 100644 --- a/webauthn/registration.go +++ b/webauthn/registration.go @@ -227,7 +227,7 @@ func (webauthn *WebAuthn) CreateCredential(user User, session SessionData, parse var clientDataHash []byte - if clientDataHash, err = parsedResponse.Verify(session.Challenge, shouldVerifyUser, webauthn.Config.RPID, webauthn.Config.RPOrigins, webauthn.Config.RPTopOrigins, webauthn.Config.RPTopOriginVerificationMode, webauthn.Config.MetaData); err != nil { + if clientDataHash, err = parsedResponse.Verify(session.Challenge, shouldVerifyUser, webauthn.Config.RPID, webauthn.Config.RPOrigins, webauthn.Config.RPTopOrigins, webauthn.Config.RPTopOriginVerificationMode, webauthn.Config.MDS); err != nil { return nil, err } diff --git a/webauthn/types.go b/webauthn/types.go index 199d76f..2ec1f2d 100644 --- a/webauthn/types.go +++ b/webauthn/types.go @@ -63,7 +63,8 @@ type Config struct { // Timeouts configures various timeouts. Timeouts TimeoutsConfig - MetaData metadata.Provider + // MDS is a metadata.Provider and enables various metadata validations if configured. + MDS metadata.Provider validated bool } @@ -164,7 +165,7 @@ func (c *Config) GetTopOriginVerificationMode() protocol.TopOriginVerificationMo } func (c *Config) GetMetaDataProvider() metadata.Provider { - return c.MetaData + return c.MDS } type ConfigProvider interface {