From b4b9ad988c954433c1094387ea317d7f4f7398ca Mon Sep 17 00:00:00 2001 From: Sakshyam Shah Date: Wed, 25 Sep 2024 07:15:27 -0700 Subject: [PATCH] move acs_url input validation to rpc create and update methods (#46847) --- lib/auth/auth_with_roles.go | 18 ++ lib/auth/auth_with_roles_test.go | 162 +++++++++++++++ .../local/saml_idp_service_provider.go | 36 ++-- .../local/saml_idp_service_provider_test.go | 190 +----------------- lib/services/saml_idp_service_provider.go | 57 +++++- .../saml_idp_service_provider_test.go | 8 +- 6 files changed, 254 insertions(+), 217 deletions(-) diff --git a/lib/auth/auth_with_roles.go b/lib/auth/auth_with_roles.go index c18ecd71cc0eb..f08947ad7c9de 100644 --- a/lib/auth/auth_with_roles.go +++ b/lib/auth/auth_with_roles.go @@ -6686,6 +6686,16 @@ func (a *ServerWithRoles) CreateSAMLIdPServiceProvider(ctx context.Context, sp t log.WithError(trace.NewAggregate(emitErr, err)).Warn("Failed to emit SAML IdP service provider created event.") } + if err := services.ValidateAssertionConsumerServicesEndpoint(sp.GetACSURL()); err != nil { + return trace.Wrap(err) + } + + if sp.GetEntityDescriptor() != "" { + if err := services.ValidateAndFilterEntityDescriptor(sp, services.SAMLACSInputStrictFilter); err != nil { + return trace.Wrap(err) + } + } + return trace.Wrap(err) } @@ -6717,6 +6727,14 @@ func (a *ServerWithRoles) UpdateSAMLIdPServiceProvider(ctx context.Context, sp t log.WithError(trace.NewAggregate(emitErr, err)).Warn("Failed to emit SAML IdP service provider updated event.") } + if err := services.ValidateAssertionConsumerServicesEndpoint(sp.GetACSURL()); err != nil { + return trace.Wrap(err) + } + + if err := services.ValidateAndFilterEntityDescriptor(sp, services.SAMLACSInputStrictFilter); err != nil { + return trace.Wrap(err) + } + return trace.Wrap(err) } diff --git a/lib/auth/auth_with_roles_test.go b/lib/auth/auth_with_roles_test.go index 36ec4240d2464..d97f64aa3d759 100644 --- a/lib/auth/auth_with_roles_test.go +++ b/lib/auth/auth_with_roles_test.go @@ -5701,6 +5701,168 @@ func TestUpdateSAMLIdPServiceProvider(t *testing.T) { } } +func TestCreateSAMLIdPServiceProviderInvalidInputs(t *testing.T) { + ctx := context.Background() + srv := newTestTLSServer(t) + user, _ := createSAMLIdPTestUsers(t, srv.Auth()) + client, err := srv.NewClient(TestUser(user)) + require.NoError(t, err) + + tests := []struct { + name string + entityDescriptor string + entityID string + acsURL string + errAssertion require.ErrorAssertionFunc + }{ + { + name: "missing url scheme in acs input", + entityID: "sp", + acsURL: "sp", + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "invalid scheme") + }, + }, + { + name: "missing url scheme for acs in ed", + entityDescriptor: services.NewSAMLTestSPMetadata("sp", "sp"), + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "invalid url scheme") + }, + }, + { + name: "http url scheme in acs", + entityID: "sp", + acsURL: "http://sp", + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "invalid scheme") + }, + }, + { + name: "http url scheme for acs in ed", + entityDescriptor: services.NewSAMLTestSPMetadata("sp", "http://sp"), + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "unsupported ACS bindings") + }, + }, + { + name: "unsupported scheme in acs", + entityID: "sp", + acsURL: "gopher://sp", + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "invalid scheme") + }, + }, + { + name: "unsupported scheme for acs in ed", + entityDescriptor: services.NewSAMLTestSPMetadata("sp", "gopher://sp"), + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "invalid url scheme") + }, + }, + { + name: "invalid character in acs", + entityID: "sp", + acsURL: "https://sp>", + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "unsupported character") + }, + }, + { + name: "invalid character in acs in ed", + entityDescriptor: services.NewSAMLTestSPMetadata("sp", "https://sp>"), + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "unsupported ACS bindings") + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + sp, err := types.NewSAMLIdPServiceProvider(types.Metadata{ + Name: "test", + }, types.SAMLIdPServiceProviderSpecV1{ + EntityDescriptor: test.entityDescriptor, + EntityID: test.entityID, + ACSURL: test.acsURL, + }) + require.NoError(t, err) + + err = client.CreateSAMLIdPServiceProvider(ctx, sp) + test.errAssertion(t, err) + }) + } +} + +func TestUpdateSAMLIdPServiceProviderInvalidInputs(t *testing.T) { + ctx := context.Background() + srv := newTestTLSServer(t) + user, _ := createSAMLIdPTestUsers(t, srv.Auth()) + client, err := srv.NewClient(TestUser(user)) + require.NoError(t, err) + + sp, err := types.NewSAMLIdPServiceProvider(types.Metadata{ + Name: "sp", + }, types.SAMLIdPServiceProviderSpecV1{ + EntityDescriptor: services.NewSAMLTestSPMetadata("https://sp", "https://sp"), + }) + require.NoError(t, err) + + err = client.CreateSAMLIdPServiceProvider(ctx, sp) + require.NoError(t, err) + + tests := []struct { + name string + entityDescriptor string + entityID string + acsURL string + errAssertion require.ErrorAssertionFunc + }{ + { + name: "missing url scheme for acs in ed", + entityDescriptor: services.NewSAMLTestSPMetadata("https://sp", "sp"), + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "invalid url scheme") + }, + }, + { + name: "http url scheme for acs in ed", + entityDescriptor: services.NewSAMLTestSPMetadata("https://sp", "http://sp"), + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "unsupported ACS bindings") + }, + }, + { + name: "unsupported scheme for acs in ed", + entityDescriptor: services.NewSAMLTestSPMetadata("https://sp", "gopher://sp"), + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "invalid url scheme") + }, + }, + { + name: "invalid character in acs in ed", + entityDescriptor: services.NewSAMLTestSPMetadata("https://sp", "https://sp>"), + errAssertion: func(t require.TestingT, err error, i ...interface{}) { + require.ErrorContains(t, err, "unsupported ACS bindings") + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + sp, err := types.NewSAMLIdPServiceProvider(types.Metadata{ + Name: "sp", + }, types.SAMLIdPServiceProviderSpecV1{ + EntityDescriptor: test.entityDescriptor, + }) + require.NoError(t, err) + + err = client.UpdateSAMLIdPServiceProvider(ctx, sp) + test.errAssertion(t, err) + }) + } +} + func TestDeleteSAMLIdPServiceProvider(t *testing.T) { ctx := context.Background() srv := newTestTLSServer(t) diff --git a/lib/services/local/saml_idp_service_provider.go b/lib/services/local/saml_idp_service_provider.go index 91af4e5312945..adeb0f9cecb1e 100644 --- a/lib/services/local/saml_idp_service_provider.go +++ b/lib/services/local/saml_idp_service_provider.go @@ -110,9 +110,10 @@ func (s *SAMLIdPServiceProviderService) GetSAMLIdPServiceProvider(ctx context.Co // CreateSAMLIdPServiceProvider creates a new SAML IdP service provider resource. func (s *SAMLIdPServiceProviderService) CreateSAMLIdPServiceProvider(ctx context.Context, sp types.SAMLIdPServiceProvider) error { if err := services.ValidateAssertionConsumerServicesEndpoint(sp.GetACSURL()); err != nil { - return trace.Wrap(err) + // logging instead of returning an error cause we do not want to break cache writes on a cluster + // that already has a service provider with unsupported characters/scheme in the acs_url. + s.log.Warn(err) } - if sp.GetEntityDescriptor() == "" { // fetchAndSetEntityDescriptor is expected to return error if it fails // to fetch a valid entity descriptor. @@ -126,7 +127,9 @@ func (s *SAMLIdPServiceProviderService) CreateSAMLIdPServiceProvider(ctx context } } - if err := s.validateEntityDescriptor(sp); err != nil { + // we only verify if the entity ID field in the spec matches with the entity descriptor. + // filtering is done only for logging purpose. + if err := services.ValidateAndFilterEntityDescriptor(sp, services.SAMLACSInputPermissiveFilter); err != nil { return trace.Wrap(err) } @@ -157,10 +160,14 @@ func (s *SAMLIdPServiceProviderService) CreateSAMLIdPServiceProvider(ctx context // UpdateSAMLIdPServiceProvider updates an existing SAML IdP service provider resource. func (s *SAMLIdPServiceProviderService) UpdateSAMLIdPServiceProvider(ctx context.Context, sp types.SAMLIdPServiceProvider) error { if err := services.ValidateAssertionConsumerServicesEndpoint(sp.GetACSURL()); err != nil { - return trace.Wrap(err) + // logging instead of returning an error cause we do not want to break cache writes on a cluster + // that already has a service provider with unsupported characters/scheme in the acs_url. + s.log.Warn(err) } - if err := s.validateEntityDescriptor(sp); err != nil { + // we only verify if the entity ID field in the spec matches with the entity descriptor. + // filtering is done only for logging purpose. + if err := services.ValidateAndFilterEntityDescriptor(sp, services.SAMLACSInputPermissiveFilter); err != nil { return trace.Wrap(err) } @@ -327,25 +334,6 @@ func (s *SAMLIdPServiceProviderService) embedAttributeMapping(sp types.SAMLIdPSe return nil } -// validateEntityDescriptor validates entity descriptor XML, entity ID and logs unsupported ACS bindings. -func (s *SAMLIdPServiceProviderService) validateEntityDescriptor(sp types.SAMLIdPServiceProvider) error { - ed, err := samlsp.ParseMetadata([]byte(sp.GetEntityDescriptor())) - if err != nil { - return trace.BadParameter("invalid entity descriptor for SAML IdP Service Provider %q: %v", sp.GetEntityID(), err) - } - - if ed.EntityID != sp.GetEntityID() { - return trace.BadParameter("entity ID parsed from the entity descriptor does not match the entity ID in the SAML IdP service provider object") - } - - // ensure any filtering related issues get logged - if err := services.FilterSAMLEntityDescriptor(ed, false /* quiet */); err != nil { - return trace.BadParameter("Entity descriptor for SAML IdP Service Provider %q contains unsupported ACS bindings: %v", sp.GetEntityID(), err) - } - - return nil -} - // GetTeleportSPSSODescriptor returns Teleport embedded SPSSODescriptor and its index from a // list of SPSSODescriptors. The correct SPSSODescriptor is determined by searching for // AttributeConsumingService element with ServiceNames named teleport_saml_idp_service. diff --git a/lib/services/local/saml_idp_service_provider_test.go b/lib/services/local/saml_idp_service_provider_test.go index 127349500478d..169f6c610d485 100644 --- a/lib/services/local/saml_idp_service_provider_test.go +++ b/lib/services/local/saml_idp_service_provider_test.go @@ -34,6 +34,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/backend/memory" + "github.com/gravitational/teleport/lib/services" ) // TestSAMLIdPServiceProviderCRUD tests backend operations with SAML IdP service provider resources. @@ -206,19 +207,6 @@ const testEntityDescriptor = ` ` -func newSAMLSPMetadata(entityID, acsURL string) string { - return fmt.Sprintf(samlSPMetadata, entityID, acsURL) -} - -// samlSPMetadata mimics metadata generated by saml.ServiceProvider.Metadata() -const samlSPMetadata = ` - - urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified - - - -` - func TestCreateSAMLIdPServiceProvider_fetchOrGenerateEntityDescriptor(t *testing.T) { ctx := context.Background() backend, err := memory.New(memory.Config{ @@ -301,7 +289,7 @@ func TestCreateSAMLIdPServiceProvider_fetchOrGenerateEntityDescriptor(t *testing sp2FromBackend, err := service2.GetSAMLIdPServiceProvider(ctx, sp2.GetName()) require.NoError(t, err) - metadataTemplate := newSAMLSPMetadata(notFoundURL, testSPServer.URL) + metadataTemplate := services.NewSAMLTestSPMetadata(notFoundURL, testSPServer.URL) expected, err := samlsp.ParseMetadata([]byte(metadataTemplate)) require.NoError(t, err) @@ -327,7 +315,7 @@ func TestCreateSAMLIdPServiceProvider_fetchAndSetEntityDescriptor(t *testing.T) fmt.Fprintln(w, "test") default: location := fmt.Sprintf("https://%s", r.Host) - metadata := newSAMLSPMetadata(location, location) + metadata := services.NewSAMLTestSPMetadata(location, location) w.WriteHeader(http.StatusOK) fmt.Fprintln(w, metadata) } @@ -599,175 +587,3 @@ func TestCreateSAMLIdPServiceProvider_GetTeleportSPSSODescriptor(t *testing.T) { index, _ := GetTeleportSPSSODescriptor(ed.SPSSODescriptors) require.Equal(t, 3, index) } - -func TestCreateSAMLIdPServiceProviderInvalidInputs(t *testing.T) { - ctx := context.Background() - - backend, err := memory.New(memory.Config{ - Context: ctx, - Clock: clockwork.NewFakeClock(), - }) - require.NoError(t, err) - - service, err := NewSAMLIdPServiceProviderService(backend) - require.NoError(t, err) - - tests := []struct { - name string - entityDescriptor string - entityID string - acsURL string - errAssertion require.ErrorAssertionFunc - }{ - { - name: "missing url scheme in acs input", - entityID: "sp", - acsURL: "sp", - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "invalid scheme") - }, - }, - { - name: "missing url scheme for acs in ed", - entityDescriptor: newSAMLSPMetadata("sp", "sp"), - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "invalid url scheme") - }, - }, - { - name: "http url scheme in acs", - entityID: "sp", - acsURL: "http://sp", - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "invalid scheme") - }, - }, - { - name: "http url scheme for acs in ed", - entityDescriptor: newSAMLSPMetadata("sp", "http://sp"), - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "unsupported ACS bindings") - }, - }, - { - name: "unsupported scheme in acs", - entityID: "sp", - acsURL: "gopher://sp", - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "invalid scheme") - }, - }, - { - name: "unsupported scheme for acs in ed", - entityDescriptor: newSAMLSPMetadata("sp", "gopher://sp"), - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "invalid url scheme") - }, - }, - { - name: "invalid character in acs", - entityID: "sp", - acsURL: "https://sp>", - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "unsupported character") - }, - }, - { - name: "invalid character in acs in ed", - entityDescriptor: newSAMLSPMetadata("sp", "https://sp>"), - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "unsupported ACS bindings") - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - sp, err := types.NewSAMLIdPServiceProvider(types.Metadata{ - Name: "test", - }, types.SAMLIdPServiceProviderSpecV1{ - EntityDescriptor: test.entityDescriptor, - EntityID: test.entityID, - ACSURL: test.acsURL, - }) - require.NoError(t, err) - - err = service.CreateSAMLIdPServiceProvider(ctx, sp) - test.errAssertion(t, err) - }) - } -} - -func TestUpdateSAMLIdPServiceProviderInvalidInputs(t *testing.T) { - ctx := context.Background() - - backend, err := memory.New(memory.Config{ - Context: ctx, - Clock: clockwork.NewFakeClock(), - }) - require.NoError(t, err) - - service, err := NewSAMLIdPServiceProviderService(backend) - require.NoError(t, err) - - sp, err := types.NewSAMLIdPServiceProvider(types.Metadata{ - Name: "sp", - }, types.SAMLIdPServiceProviderSpecV1{ - EntityDescriptor: newSAMLSPMetadata("https://sp", "https://sp"), - }) - require.NoError(t, err) - - err = service.CreateSAMLIdPServiceProvider(ctx, sp) - require.NoError(t, err) - - tests := []struct { - name string - entityDescriptor string - entityID string - acsURL string - errAssertion require.ErrorAssertionFunc - }{ - { - name: "missing url scheme for acs in ed", - entityDescriptor: newSAMLSPMetadata("https://sp", "sp"), - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "invalid url scheme") - }, - }, - { - name: "http url scheme for acs in ed", - entityDescriptor: newSAMLSPMetadata("https://sp", "http://sp"), - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "unsupported ACS bindings") - }, - }, - { - name: "unsupported scheme for acs in ed", - entityDescriptor: newSAMLSPMetadata("https://sp", "gopher://sp"), - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "invalid url scheme") - }, - }, - { - name: "invalid character in acs in ed", - entityDescriptor: newSAMLSPMetadata("https://sp", "https://sp>"), - errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorContains(t, err, "unsupported ACS bindings") - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - sp, err := types.NewSAMLIdPServiceProvider(types.Metadata{ - Name: "sp", - }, types.SAMLIdPServiceProviderSpecV1{ - EntityDescriptor: test.entityDescriptor, - }) - require.NoError(t, err) - - err = service.UpdateSAMLIdPServiceProvider(ctx, sp) - test.errAssertion(t, err) - }) - } -} diff --git a/lib/services/saml_idp_service_provider.go b/lib/services/saml_idp_service_provider.go index 4d86980065578..5e1e6333dcbca 100644 --- a/lib/services/saml_idp_service_provider.go +++ b/lib/services/saml_idp_service_provider.go @@ -18,11 +18,13 @@ package services import ( "context" + "fmt" "net/url" "slices" "strings" "github.com/crewjam/saml" + "github.com/crewjam/saml/samlsp" "github.com/gravitational/trace" log "github.com/sirupsen/logrus" @@ -158,8 +160,8 @@ func FilterSAMLEntityDescriptor(ed *saml.EntityDescriptor, quiet bool) error { ed.SPSSODescriptors[i].AssertionConsumerServices = filtered } - if filteredCount == 0 && originalCount != 0 { - return trace.BadParameter("no AssertionConsumerService bindings for entity %q passed validation", ed.EntityID) + if filteredCount != originalCount { + return trace.BadParameter("Entity descriptor for entity %q contains unsupported AssertionConsumerService binding or location", ed.EntityID) } return nil @@ -170,6 +172,43 @@ func FilterSAMLEntityDescriptor(ed *saml.EntityDescriptor, quiet bool) error { // meant to increase the ost of xss payload. const invalidSAMLIdPACSURLChars = `<>"!;` +// SAMLACSInputFilteringThreshold defines level of strictness for entity descriptor filtering. +type SAMLACSInputFilteringThreshold string + +const ( + // SAMLACSInputStrictFilter indicates ValidateAndFilterEntityDescriptor to return an error on + // any instance of unsupported ACS value. + SAMLACSInputStrictFilter SAMLACSInputFilteringThreshold = "SAMLACSInputStrictFilter" + // SAMLACSInputPermissiveFilter indicates ValidateAndFilterEntityDescriptor to ignore an error on + // any instance of unsupported ACS value. + SAMLACSInputPermissiveFilter SAMLACSInputFilteringThreshold = "SAMLACSInputPermissiveFilter" +) + +// ValidateAndFilterEntityDescriptor validates entity id and ACS value. It specifically: +// - checks for a valid entity descriptor XML format. +// - checks for a matching entity ID field in both the entity_id field and entity ID contained in the value of +// entity_descriptor field. +// - performs filtering on the Assertion Consumer service (ACS) binding format or its location URL endpoint. +// filterThreshold dictates if ValidateAndFilterEntityDescriptor should return or ignore error on filtering result. +func ValidateAndFilterEntityDescriptor(sp types.SAMLIdPServiceProvider, filterThreshold SAMLACSInputFilteringThreshold) error { + edOriginal, err := samlsp.ParseMetadata([]byte(sp.GetEntityDescriptor())) + if err != nil { + return trace.BadParameter("invalid entity descriptor for SAML IdP Service Provider %q: %v", sp.GetEntityID(), err) + } + + if edOriginal.EntityID != sp.GetEntityID() { + return trace.BadParameter("entity ID parsed from the entity descriptor does not match the entity ID in the SAML IdP service provider object") + } + + if err := FilterSAMLEntityDescriptor(edOriginal, false /* quiet */); err != nil { + if filterThreshold == SAMLACSInputStrictFilter { + return trace.BadParameter("Entity descriptor for SAML IdP Service Provider %q contains unsupported ACS bindings: %v", sp.GetEntityID(), err) + } + } + + return nil +} + // ValidateAssertionConsumerServicesEndpoint ensures that the Assertion Consumer Service location // is a valid HTTPS endpoint. func ValidateAssertionConsumerServicesEndpoint(acs string) error { @@ -189,3 +228,17 @@ func ValidateAssertionConsumerServicesEndpoint(acs string) error { } return nil } + +// NewSAMLTestSPMetadata creates a new entity descriptor for tests. +func NewSAMLTestSPMetadata(entityID, acsURL string) string { + return fmt.Sprintf(samlTestSPMetadata, entityID, acsURL) +} + +// samlTestSPMetadata mimics metadata format generated by saml.ServiceProvider.Metadata() +const samlTestSPMetadata = ` + + urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified + + + + ` diff --git a/lib/services/saml_idp_service_provider_test.go b/lib/services/saml_idp_service_provider_test.go index 1e0c481853c0d..4fb377710c6b2 100644 --- a/lib/services/saml_idp_service_provider_test.go +++ b/lib/services/saml_idp_service_provider_test.go @@ -87,7 +87,7 @@ func TestFilterSAMLEntityDescriptor(t *testing.T) { ACS(saml.HTTPPostBinding, "https://example.com/acs"). ACS(saml.HTTPPostBinding, "http://example.com/acs"). Done(), - ok: true, + ok: false, before: 2, after: 1, name: "scheme filtering", @@ -98,7 +98,7 @@ func TestFilterSAMLEntityDescriptor(t *testing.T) { ACS("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign", "https://example.com/POST-SimpleSign"). ACS(saml.HTTPPostBinding, "https://example.com/acs"). Done(), - ok: true, + ok: false, before: 3, after: 1, name: "binding filtering", @@ -125,9 +125,9 @@ func TestFilterSAMLEntityDescriptor(t *testing.T) { err = FilterSAMLEntityDescriptor(ed, false /* quiet */) if !tt.ok { require.Error(t, err) - return + } else { + require.NoError(t, err) } - require.NoError(t, err) require.Equal(t, tt.after, getACSCount(ed)) })