From 028b6d8646707bba3240baa97eed780d7ff13fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Sat, 9 Sep 2023 18:38:19 +0200 Subject: [PATCH 1/5] Add caching support to IDPMetadata() Caching the metadata document will avoid an additional round-trip to the IDP for every connection. The Metadata for the OASIS Security Assertion Markup Language says regarding caching: 4.3 Post-Processing of Metadata The following sections describe the post-processing of metadata. 4.3.1 Metadata Instance Caching [E94] Document caching MUST be based on the duration indicated by the cacheDuration attribute of the subject element(s). If metadata elements have parent elements which contain caching policies, the parent element takes precedence. To properly process the cacheDuration attribute, consumers must retain the date and time when an instance was obtained. Note that cache expiration does not imply a lack of validity in the absence of a validUntil attribute or other information; failure to update a cached instance (e.g., due to network failure) need not render metadata invalid, although implementations may offer such controls to deployers. When a document or element has expired, the consumer MUST retrieve a fresh copy, which may require a refresh of the document location(s). Consumers SHOULD process document cache processing according to [RFC2616] Section 13, and MAY request the Last-Modified date and time from the HTTP server. Publishers SHOULD ensure acceptable cache processing as described in [RFC2616] (Section 10.3.5 304 Not Modified). 4.3.2 [E94] Metadata Instance Validity Metadata MUST be considered invalid upon reaching the time specified in a validUntil attribute of the subject element(s). The effective expiration may be adjusted downward by parent element(s) with earlier expirations. Invalid metadata MUST NOT be used. This contrasts with "stale" metadata that may be beyond its optimum cache duration but is not explicitly invalid. Such metadata remains valid and MAY be used at the discretion of the implementation. With this change the cached metadata is used until it expires. This behavior can be disabled using WithCache(). Using a stale document when refreshing it fails is disabled by default and users can opt-in using WithStale(). --- saml/authn_request.go | 2 + saml/models/metadata/duration.go | 128 +++++++++++++++++++ saml/models/metadata/duration_test.go | 84 +++++++++++++ saml/models/metadata/entity_descriptor.go | 6 +- saml/sp.go | 104 +++++++++++++++- saml/sp_test.go | 144 ++++++++++++++++++++++ 6 files changed, 462 insertions(+), 6 deletions(-) create mode 100644 saml/models/metadata/duration.go create mode 100644 saml/models/metadata/duration_test.go diff --git a/saml/authn_request.go b/saml/authn_request.go index 3668387..d7fb6f9 100644 --- a/saml/authn_request.go +++ b/saml/authn_request.go @@ -118,6 +118,8 @@ func WithClock(clock clockwork.Clock) Option { opts.clock = clock case *parseResponseOptions: opts.clock = clock + case *idpMetadataOptions: + opts.clock = clock } } } diff --git a/saml/models/metadata/duration.go b/saml/models/metadata/duration.go new file mode 100644 index 0000000..51b4147 --- /dev/null +++ b/saml/models/metadata/duration.go @@ -0,0 +1,128 @@ +package metadata + +import ( + "fmt" + "regexp" + "strconv" + "strings" + "time" +) + +// Duration is a time.Duration that uses the xsd:duration format for text +// marshalling and unmarshalling. +type Duration time.Duration + +// MarshalText implements the encoding.TextMarshaler interface. +func (d Duration) MarshalText() ([]byte, error) { + if d == 0 { + return nil, nil + } + + out := "PT" + if d < 0 { + d *= -1 + out = "-" + out + } + + h := time.Duration(d) / time.Hour + m := time.Duration(d) % time.Hour / time.Minute + s := time.Duration(d) % time.Minute / time.Second + ns := time.Duration(d) % time.Second + if h > 0 { + out += fmt.Sprintf("%dH", h) + } + if m > 0 { + out += fmt.Sprintf("%dM", m) + } + if s > 0 || ns > 0 { + out += fmt.Sprintf("%d", s) + if ns > 0 { + out += strings.TrimRight(fmt.Sprintf(".%09d", ns), "0") + } + out += "S" + } + + return []byte(out), nil +} + +const ( + day = 24 * time.Hour + month = 30 * day // Assumed to be 30 days. + year = 365 * day // Assumed to be non-leap year. +) + +var ( + durationRegexp = regexp.MustCompile(`^(-?)P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(.+))?$`) + durationTimeRegexp = regexp.MustCompile(`^(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?$`) +) + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (d *Duration) UnmarshalText(text []byte) error { + if text == nil { + *d = 0 + return nil + } + + var ( + out time.Duration + sign time.Duration = 1 + ) + match := durationRegexp.FindStringSubmatch(string(text)) + if match == nil || strings.Join(match[2:6], "") == "" { + return fmt.Errorf("invalid duration (%s)", text) + } + if match[1] == "-" { + sign = -1 + } + if match[2] != "" { + y, err := strconv.Atoi(match[2]) + if err != nil { + return fmt.Errorf("invalid duration years (%s): %s", text, err) + } + out += time.Duration(y) * year + } + if match[3] != "" { + m, err := strconv.Atoi(match[3]) + if err != nil { + return fmt.Errorf("invalid duration months (%s): %s", text, err) + } + out += time.Duration(m) * month + } + if match[4] != "" { + d, err := strconv.Atoi(match[4]) + if err != nil { + return fmt.Errorf("invalid duration days (%s): %s", text, err) + } + out += time.Duration(d) * day + } + if match[5] != "" { + match := durationTimeRegexp.FindStringSubmatch(match[5]) + if match == nil { + return fmt.Errorf("invalid duration (%s)", text) + } + if match[1] != "" { + h, err := strconv.Atoi(match[1]) + if err != nil { + return fmt.Errorf("invalid duration hours (%s): %s", text, err) + } + out += time.Duration(h) * time.Hour + } + if match[2] != "" { + m, err := strconv.Atoi(match[2]) + if err != nil { + return fmt.Errorf("invalid duration minutes (%s): %s", text, err) + } + out += time.Duration(m) * time.Minute + } + if match[3] != "" { + s, err := strconv.ParseFloat(match[3], 64) + if err != nil { + return fmt.Errorf("invalid duration seconds (%s): %s", text, err) + } + out += time.Duration(s * float64(time.Second)) + } + } + + *d = Duration(sign * out) + return nil +} diff --git a/saml/models/metadata/duration_test.go b/saml/models/metadata/duration_test.go new file mode 100644 index 0000000..ca60b3c --- /dev/null +++ b/saml/models/metadata/duration_test.go @@ -0,0 +1,84 @@ +package metadata + +import ( + "errors" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +var durationMarshalTests = []struct { + in time.Duration + expected []byte +}{ + {0, nil}, + {time.Nanosecond, []byte("PT0.000000001S")}, + {time.Millisecond, []byte("PT0.001S")}, + {time.Second, []byte("PT1S")}, + {time.Minute, []byte("PT1M")}, + {time.Hour, []byte("PT1H")}, + {-time.Hour, []byte("-PT1H")}, + {2*time.Hour + 3*time.Minute + 4*time.Second + 5*time.Nanosecond, []byte("PT2H3M4.000000005S")}, +} + +func TestDuration(t *testing.T) { + for i, testCase := range durationMarshalTests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + actual, err := Duration(testCase.in).MarshalText() + require.NoError(t, err) + require.Equal(t, testCase.expected, actual) + }) + } +} + +var durationUnmarshalTests = []struct { + in []byte + expected time.Duration + err error +}{ + {nil, 0, nil}, + {[]byte("PT0.0000000001S"), 0, nil}, + {[]byte("PT0.000000001S"), time.Nanosecond, nil}, + {[]byte("PT0.001S"), time.Millisecond, nil}, + {[]byte("PT1S"), time.Second, nil}, + {[]byte("PT1M"), time.Minute, nil}, + {[]byte("PT1H"), time.Hour, nil}, + {[]byte("-PT1H"), -time.Hour, nil}, + {[]byte("P1D"), 24 * time.Hour, nil}, + {[]byte("P1M"), 720 * time.Hour, nil}, + {[]byte("P1Y"), 8760 * time.Hour, nil}, + {[]byte("P2Y3M4DT5H6M7.000000008S"), 19781*time.Hour + 6*time.Minute + 7*time.Second + 8*time.Nanosecond, nil}, + {[]byte("P0Y0M0DT0H0M0S"), 0, nil}, + {[]byte("PT0001.0000S"), time.Second, nil}, + {[]byte(""), 0, errors.New("invalid duration ()")}, + {[]byte("12345"), 0, errors.New("invalid duration (12345)")}, + {[]byte("P1D1M1Y"), 0, errors.New("invalid duration (P1D1M1Y)")}, + {[]byte("P1H1M1S"), 0, errors.New("invalid duration (P1H1M1S)")}, + {[]byte("PT1S1M1H"), 0, errors.New("invalid duration (PT1S1M1H)")}, + {[]byte(" P1Y "), 0, errors.New("invalid duration ( P1Y )")}, + {[]byte("P"), 0, errors.New("invalid duration (P)")}, + {[]byte("-P"), 0, errors.New("invalid duration (-P)")}, + {[]byte("PT"), 0, errors.New("invalid duration (PT)")}, + {[]byte("P1YMD"), 0, errors.New("invalid duration (P1YMD)")}, + {[]byte("P1YT"), 0, errors.New("invalid duration (P1YT)")}, + {[]byte("P-1Y"), 0, errors.New("invalid duration (P-1Y)")}, + {[]byte("P1.5Y"), 0, errors.New("invalid duration (P1.5Y)")}, + {[]byte("PT1.S"), 0, errors.New("invalid duration (PT1.S)")}, +} + +func TestDurationUnmarshal(t *testing.T) { + for i, testCase := range durationUnmarshalTests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + var actual Duration + err := actual.UnmarshalText(testCase.in) + if testCase.err == nil { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, testCase.err.Error()) + } + require.Equal(t, Duration(testCase.expected), actual) + }) + } +} diff --git a/saml/models/metadata/entity_descriptor.go b/saml/models/metadata/entity_descriptor.go index 0efb1ad..365ad71 100644 --- a/saml/models/metadata/entity_descriptor.go +++ b/saml/models/metadata/entity_descriptor.go @@ -37,9 +37,9 @@ const ( // DescriptorCommon defines common fields used in Entity- and EntitiesDescriptor. type DescriptorCommon struct { - ID string `xml:",attr,omitempty"` - ValidUntil *time.Time `xml:"validUntil,attr,omitempty"` - CacheDuration time.Duration `xml:"cacheDuration,attr,omitempty"` + ID string `xml:",attr,omitempty"` + ValidUntil *time.Time `xml:"validUntil,attr,omitempty"` + CacheDuration *Duration `xml:"cacheDuration,attr,omitempty"` Signature *dsig.Signature } diff --git a/saml/sp.go b/saml/sp.go index 6002463..8350944 100644 --- a/saml/sp.go +++ b/saml/sp.go @@ -8,9 +8,12 @@ import ( "io" "net/http" "net/url" + "sync" + "time" "github.com/hashicorp/cap/saml/models/core" "github.com/hashicorp/cap/saml/models/metadata" + "github.com/jonboulle/clockwork" dsig "github.com/russellhaering/goxmldsig/types" ) @@ -82,6 +85,10 @@ func WithAdditionalACSEndpoint(b core.ServiceBinding, location *url.URL) Option type ServiceProvider struct { cfg *Config + + metadata *metadata.EntityDescriptorIDPSSO + metadataCachedUntil *time.Time + metadataLock sync.Mutex } // NewServiceProvider creates a new ServiceProvider. @@ -157,21 +164,101 @@ func (sp *ServiceProvider) CreateMetadata(opt ...Option) *metadata.EntityDescrip return &spsso } +type idpMetadataOptions struct { + cache bool + useStale bool + clock clockwork.Clock +} + +func idpMetadataOptionsDefault() idpMetadataOptions { + return idpMetadataOptions{ + cache: true, + useStale: false, + clock: clockwork.NewRealClock(), + } +} + +func getIDPMetadataOptions(opt ...Option) idpMetadataOptions { + opts := idpMetadataOptionsDefault() + ApplyOpts(&opts, opt...) + return opts +} + +// WithCache control whether we should cache IDP Metadata. +func WithCache(cache bool) Option { + return func(o interface{}) { + if o, ok := o.(*idpMetadataOptions); ok { + o.cache = cache + } + } +} + +// WithStale control whether we should use a stale IDP Metadata document if +// refreshing it fails. +func WithStale(stale bool) Option { + return func(o interface{}) { + if o, ok := o.(*idpMetadataOptions); ok { + o.useStale = stale + } + } +} + // IDPMetadata fetches the metadata XML document from the configured identity provider. -func (sp *ServiceProvider) IDPMetadata() (*metadata.EntityDescriptorIDPSSO, error) { +// Options: +// - WithClock +// - WithCache +// - WithStale +func (sp *ServiceProvider) IDPMetadata(opt ...Option) (*metadata.EntityDescriptorIDPSSO, error) { const op = "saml.ServiceProvider.FetchIDPMetadata" + opts := getIDPMetadataOptions(opt...) + var err error var ed *metadata.EntityDescriptorIDPSSO + isValid := func(md *metadata.EntityDescriptorIDPSSO) bool { + if md == nil { + return false + } + if md.ValidUntil == nil { + return true + } + return opts.clock.Now().Before(*md.ValidUntil) + } + + isAlive := func(md *metadata.EntityDescriptorIDPSSO, expireAt *time.Time) bool { + if md == nil || !opts.cache || expireAt == nil { + return false + } + + return opts.clock.Now().Before(*expireAt) + } + + if opts.cache { + // We only take the lock when caching is enabled so that requests can be + // done concurrently when it is not + sp.metadataLock.Lock() + defer sp.metadataLock.Unlock() + + if !isValid(sp.metadata) { + sp.metadata = nil + sp.metadataCachedUntil = nil + } else if isAlive(sp.metadata, sp.metadataCachedUntil) { + return sp.metadata, nil + } + } + // Order of switch case determines IDP metadata config precedence switch { case sp.cfg.MetadataURL != "": ed, err = fetchIDPMetadata(sp.cfg.MetadataURL) - if err != nil { + if err != nil && opts.useStale && isValid(sp.metadata) { + // An error occured but we have a cached metadata document that + // we can use + return sp.metadata, nil + } else if err != nil { return nil, fmt.Errorf("%s: %w", op, err) } - return ed, nil case sp.cfg.MetadataXML != "": ed, err = parseIDPMetadata([]byte(sp.cfg.MetadataXML)) @@ -189,6 +276,17 @@ func (sp *ServiceProvider) IDPMetadata() (*metadata.EntityDescriptorIDPSSO, erro return nil, fmt.Errorf("%s: no IDP metadata configuration set: %w", op, ErrInvalidParameter) } + if !isValid(ed) { + return nil, fmt.Errorf("the IDP configuration was only valid until %s", ed.ValidUntil.Format(time.RFC3339)) + } + + sp.metadata = ed + sp.metadataCachedUntil = nil + if sp.metadata.CacheDuration != nil { + cachedUntil := opts.clock.Now().Add(time.Duration(*sp.metadata.CacheDuration)) + sp.metadataCachedUntil = &cachedUntil + } + return ed, err } diff --git a/saml/sp_test.go b/saml/sp_test.go index 30ea97f..5e1237d 100644 --- a/saml/sp_test.go +++ b/saml/sp_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" "github.com/hashicorp/cap/saml" @@ -116,6 +117,119 @@ func Test_ServiceProvider_FetchMetadata_ErrorCases(t *testing.T) { } } +func Test_ServiceProvider_FetchMetadata_Cache(t *testing.T) { + type testServer struct { + fail bool + failOnRefresh bool + } + + newTestServer := func(t *testing.T, failOnRefresh bool) string { + t.Helper() + + ts := &testServer{false, failOnRefresh} + + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + if !ts.fail { + w.Write([]byte(exampleIDPSSODescriptorX)) + } + ts.fail = ts.fail || ts.failOnRefresh + })) + t.Cleanup(s.Close) + + return s.URL + } + + cases := []struct { + name string + newTime string + shoudBeCached bool + opts []saml.Option + failOnRefresh bool + expectErrorOnRefresh bool + }{ + { + name: "is cached", + shoudBeCached: true, + }, + { + name: "cache is disabled", + opts: []saml.Option{saml.WithCache(false)}, + shoudBeCached: false, + }, + { + name: "stale cached document should not be used", + newTime: "2017-07-26", + shoudBeCached: false, + }, + { + name: "is not cached once validUntil is reached", + newTime: "2018-07-25", + expectErrorOnRefresh: true, + }, + { + name: "a stale document should not be used if refreshing fails", + newTime: "2017-07-26", + failOnRefresh: true, + expectErrorOnRefresh: true, + }, + { + name: "use stale document", + opts: []saml.Option{saml.WithStale(true)}, + newTime: "2017-07-26", + failOnRefresh: true, + shoudBeCached: true, + }, + } + + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + r := require.New(t) + + url := newTestServer(t, tt.failOnRefresh) + metaURL := fmt.Sprintf("%s/saml/metadata", url) + cfg, err := saml.NewConfig( + metaURL, + metaURL, + metaURL, + ) + r.NoError(err) + + provider, err := saml.NewServiceProvider(cfg) + r.NoError(err) + + newTime, err := time.Parse("2006-01-02", "2017-07-25") + r.NoError(err) + + opts := append([]saml.Option{saml.WithClock(clockwork.NewFakeClockAt(newTime))}, tt.opts...) + + got1, err := provider.IDPMetadata(opts...) + r.NoError(err) + r.NotNil(got1) + + if tt.newTime != "" { + newTime, err = time.Parse("2006-01-02", tt.newTime) + r.NoError(err) + opts = append(opts, saml.WithClock(clockwork.NewFakeClockAt(newTime))) + } + + got2, err := provider.IDPMetadata(opts...) + if tt.expectErrorOnRefresh { + r.Error(err) + return + } else { + r.NoError(err) + } + r.NotNil(got2) + + if tt.shoudBeCached { + r.True(got1 == got2) + } else { + r.False(got1 == got2) + } + }) + } +} + func Test_ServiceProvider_CreateMetadata(t *testing.T) { r := require.New(t) @@ -133,6 +247,7 @@ func Test_ServiceProvider_CreateMetadata(t *testing.T) { acs, meta, ) + r.NoError(err) cfg.ValidUntil = validUntil @@ -281,3 +396,32 @@ func Test_CreateMetadata_Options(t *testing.T) { ) }) } + +var exampleIDPSSODescriptorX = ` + + + + + + + https://registrar.example.net/category/self-certified + + + + + + ... + ... + https://www.example.info/ + + + SAML Technical Support + mailto:technical-support@example.info + + +` From 36f61ae1ac57c8f67eb6888727c453bf4fab994b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Mon, 11 Sep 2023 09:45:33 +0200 Subject: [PATCH 2/5] Address code review comments --- saml/go.mod | 1 + saml/go.sum | 26 ++++++ saml/models/metadata/duration.go | 116 ++------------------------ saml/models/metadata/duration_test.go | 28 ------- saml/sp.go | 12 +-- saml/sp_test.go | 30 +++---- 6 files changed, 54 insertions(+), 159 deletions(-) diff --git a/saml/go.mod b/saml/go.mod index 2e7469c..a91d5ef 100644 --- a/saml/go.mod +++ b/saml/go.mod @@ -16,6 +16,7 @@ require ( require ( github.com/coreos/go-oidc/v3 v3.6.0 // indirect github.com/crewjam/errset v0.0.0-20160219153700-f78d65de925c // indirect + github.com/crewjam/saml v0.4.13 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.15.0 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect diff --git a/saml/go.sum b/saml/go.sum index 1d009f1..79d7094 100644 --- a/saml/go.sum +++ b/saml/go.sum @@ -8,14 +8,19 @@ github.com/crewjam/errset v0.0.0-20160219153700-f78d65de925c h1:dCJ9oZ0VgnzJHR5B github.com/crewjam/errset v0.0.0-20160219153700-f78d65de925c/go.mod h1:XhiWL7J86xoqJ8+x2OA+AM2l9skQP2DZ0UOXQYVg7uI= github.com/crewjam/go-xmlsec v0.0.0-20200414151428-d2b1a58f7262 h1:3V8RSsB1mxeAfxMb7lGSd0HlCHhc/ElJj1peaJMAkyk= github.com/crewjam/go-xmlsec v0.0.0-20200414151428-d2b1a58f7262/go.mod h1:M9eHnKpImgRwzOFdlFQnbgJRqFwW/eX1cKAVobv03uE= +github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4= +github.com/crewjam/saml v0.4.13 h1:TYHggH/hwP7eArqiXSJUvtOPNzQDyQ7vwmwEqlFWhMc= +github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -23,6 +28,7 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/cap v0.3.1 h1:JwX2vg3KIl2+ka4VIPB0yWB9PoPvHL3ACmVrLJLCHDQ= github.com/hashicorp/cap v0.3.1/go.mod h1:dHTmyMIVbzT981XxRoci5G//dfWmd/HhuNiCH6J5+IA= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= @@ -39,6 +45,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -57,6 +64,7 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/moov-io/signedxml v1.1.1 h1:TQ2fK4DRCYv7agH+z6RjtnBTmEyYMAztFzuHIPtUJpg= github.com/moov-io/signedxml v1.1.1/go.mod h1:p+b4f/Wo/qKyew8fHW8VZOgsILWylyvvjdE68egzbwc= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -64,22 +72,33 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russellhaering/gosaml2 v0.9.1 h1:H/whrl8NuSoxyW46Ww5lKPskm+5K+qYLw9afqJ/Zef0= github.com/russellhaering/gosaml2 v0.9.1/go.mod h1:ja+qgbayxm+0mxBRLMSUuX3COqy+sb0RRhIGun/W2kc= +github.com/russellhaering/goxmldsig v1.2.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/russellhaering/goxmldsig v1.3.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys= github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs= @@ -88,6 +107,9 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -95,8 +117,10 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -112,7 +136,9 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= diff --git a/saml/models/metadata/duration.go b/saml/models/metadata/duration.go index 51b4147..f28aa35 100644 --- a/saml/models/metadata/duration.go +++ b/saml/models/metadata/duration.go @@ -1,11 +1,9 @@ package metadata import ( - "fmt" - "regexp" - "strconv" - "strings" "time" + + crewjamSaml "github.com/crewjam/saml" ) // Duration is a time.Duration that uses the xsd:duration format for text @@ -14,115 +12,11 @@ type Duration time.Duration // MarshalText implements the encoding.TextMarshaler interface. func (d Duration) MarshalText() ([]byte, error) { - if d == 0 { - return nil, nil - } - - out := "PT" - if d < 0 { - d *= -1 - out = "-" + out - } - - h := time.Duration(d) / time.Hour - m := time.Duration(d) % time.Hour / time.Minute - s := time.Duration(d) % time.Minute / time.Second - ns := time.Duration(d) % time.Second - if h > 0 { - out += fmt.Sprintf("%dH", h) - } - if m > 0 { - out += fmt.Sprintf("%dM", m) - } - if s > 0 || ns > 0 { - out += fmt.Sprintf("%d", s) - if ns > 0 { - out += strings.TrimRight(fmt.Sprintf(".%09d", ns), "0") - } - out += "S" - } - - return []byte(out), nil + return crewjamSaml.Duration(d).MarshalText() } -const ( - day = 24 * time.Hour - month = 30 * day // Assumed to be 30 days. - year = 365 * day // Assumed to be non-leap year. -) - -var ( - durationRegexp = regexp.MustCompile(`^(-?)P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(.+))?$`) - durationTimeRegexp = regexp.MustCompile(`^(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?$`) -) - // UnmarshalText implements the encoding.TextUnmarshaler interface. func (d *Duration) UnmarshalText(text []byte) error { - if text == nil { - *d = 0 - return nil - } - - var ( - out time.Duration - sign time.Duration = 1 - ) - match := durationRegexp.FindStringSubmatch(string(text)) - if match == nil || strings.Join(match[2:6], "") == "" { - return fmt.Errorf("invalid duration (%s)", text) - } - if match[1] == "-" { - sign = -1 - } - if match[2] != "" { - y, err := strconv.Atoi(match[2]) - if err != nil { - return fmt.Errorf("invalid duration years (%s): %s", text, err) - } - out += time.Duration(y) * year - } - if match[3] != "" { - m, err := strconv.Atoi(match[3]) - if err != nil { - return fmt.Errorf("invalid duration months (%s): %s", text, err) - } - out += time.Duration(m) * month - } - if match[4] != "" { - d, err := strconv.Atoi(match[4]) - if err != nil { - return fmt.Errorf("invalid duration days (%s): %s", text, err) - } - out += time.Duration(d) * day - } - if match[5] != "" { - match := durationTimeRegexp.FindStringSubmatch(match[5]) - if match == nil { - return fmt.Errorf("invalid duration (%s)", text) - } - if match[1] != "" { - h, err := strconv.Atoi(match[1]) - if err != nil { - return fmt.Errorf("invalid duration hours (%s): %s", text, err) - } - out += time.Duration(h) * time.Hour - } - if match[2] != "" { - m, err := strconv.Atoi(match[2]) - if err != nil { - return fmt.Errorf("invalid duration minutes (%s): %s", text, err) - } - out += time.Duration(m) * time.Minute - } - if match[3] != "" { - s, err := strconv.ParseFloat(match[3], 64) - if err != nil { - return fmt.Errorf("invalid duration seconds (%s): %s", text, err) - } - out += time.Duration(s * float64(time.Second)) - } - } - - *d = Duration(sign * out) - return nil + cp := (*crewjamSaml.Duration)(d) + return cp.UnmarshalText(text) } diff --git a/saml/models/metadata/duration_test.go b/saml/models/metadata/duration_test.go index ca60b3c..9ae0853 100644 --- a/saml/models/metadata/duration_test.go +++ b/saml/models/metadata/duration_test.go @@ -14,13 +14,8 @@ var durationMarshalTests = []struct { expected []byte }{ {0, nil}, - {time.Nanosecond, []byte("PT0.000000001S")}, - {time.Millisecond, []byte("PT0.001S")}, - {time.Second, []byte("PT1S")}, - {time.Minute, []byte("PT1M")}, {time.Hour, []byte("PT1H")}, {-time.Hour, []byte("-PT1H")}, - {2*time.Hour + 3*time.Minute + 4*time.Second + 5*time.Nanosecond, []byte("PT2H3M4.000000005S")}, } func TestDuration(t *testing.T) { @@ -39,32 +34,9 @@ var durationUnmarshalTests = []struct { err error }{ {nil, 0, nil}, - {[]byte("PT0.0000000001S"), 0, nil}, - {[]byte("PT0.000000001S"), time.Nanosecond, nil}, - {[]byte("PT0.001S"), time.Millisecond, nil}, - {[]byte("PT1S"), time.Second, nil}, - {[]byte("PT1M"), time.Minute, nil}, - {[]byte("PT1H"), time.Hour, nil}, {[]byte("-PT1H"), -time.Hour, nil}, {[]byte("P1D"), 24 * time.Hour, nil}, {[]byte("P1M"), 720 * time.Hour, nil}, - {[]byte("P1Y"), 8760 * time.Hour, nil}, - {[]byte("P2Y3M4DT5H6M7.000000008S"), 19781*time.Hour + 6*time.Minute + 7*time.Second + 8*time.Nanosecond, nil}, - {[]byte("P0Y0M0DT0H0M0S"), 0, nil}, - {[]byte("PT0001.0000S"), time.Second, nil}, - {[]byte(""), 0, errors.New("invalid duration ()")}, - {[]byte("12345"), 0, errors.New("invalid duration (12345)")}, - {[]byte("P1D1M1Y"), 0, errors.New("invalid duration (P1D1M1Y)")}, - {[]byte("P1H1M1S"), 0, errors.New("invalid duration (P1H1M1S)")}, - {[]byte("PT1S1M1H"), 0, errors.New("invalid duration (PT1S1M1H)")}, - {[]byte(" P1Y "), 0, errors.New("invalid duration ( P1Y )")}, - {[]byte("P"), 0, errors.New("invalid duration (P)")}, - {[]byte("-P"), 0, errors.New("invalid duration (-P)")}, - {[]byte("PT"), 0, errors.New("invalid duration (PT)")}, - {[]byte("P1YMD"), 0, errors.New("invalid duration (P1YMD)")}, - {[]byte("P1YT"), 0, errors.New("invalid duration (P1YT)")}, - {[]byte("P-1Y"), 0, errors.New("invalid duration (P-1Y)")}, - {[]byte("P1.5Y"), 0, errors.New("invalid duration (P1.5Y)")}, {[]byte("PT1.S"), 0, errors.New("invalid duration (PT1.S)")}, } diff --git a/saml/sp.go b/saml/sp.go index 8350944..d488303 100644 --- a/saml/sp.go +++ b/saml/sp.go @@ -240,10 +240,11 @@ func (sp *ServiceProvider) IDPMetadata(opt ...Option) (*metadata.EntityDescripto sp.metadataLock.Lock() defer sp.metadataLock.Unlock() - if !isValid(sp.metadata) { + switch { + case !isValid(sp.metadata): sp.metadata = nil sp.metadataCachedUntil = nil - } else if isAlive(sp.metadata, sp.metadataCachedUntil) { + case isValid(sp.metadata) && isAlive(sp.metadata, sp.metadataCachedUntil): return sp.metadata, nil } } @@ -252,11 +253,12 @@ func (sp *ServiceProvider) IDPMetadata(opt ...Option) (*metadata.EntityDescripto switch { case sp.cfg.MetadataURL != "": ed, err = fetchIDPMetadata(sp.cfg.MetadataURL) - if err != nil && opts.useStale && isValid(sp.metadata) { - // An error occured but we have a cached metadata document that + switch { + case err != nil && opts.useStale && isValid(sp.metadata): + // An error occurred but we have a cached metadata document that // we can use return sp.metadata, nil - } else if err != nil { + case err != nil: return nil, fmt.Errorf("%s: %w", op, err) } diff --git a/saml/sp_test.go b/saml/sp_test.go index 5e1237d..cea4957 100644 --- a/saml/sp_test.go +++ b/saml/sp_test.go @@ -142,24 +142,24 @@ func Test_ServiceProvider_FetchMetadata_Cache(t *testing.T) { cases := []struct { name string newTime string - shoudBeCached bool + shouldBeCached bool opts []saml.Option failOnRefresh bool expectErrorOnRefresh bool }{ { - name: "is cached", - shoudBeCached: true, + name: "is cached", + shouldBeCached: true, }, { - name: "cache is disabled", - opts: []saml.Option{saml.WithCache(false)}, - shoudBeCached: false, + name: "cache is disabled", + opts: []saml.Option{saml.WithCache(false)}, + shouldBeCached: false, }, { - name: "stale cached document should not be used", - newTime: "2017-07-26", - shoudBeCached: false, + name: "stale cached document should not be used", + newTime: "2017-07-26", + shouldBeCached: false, }, { name: "is not cached once validUntil is reached", @@ -173,11 +173,11 @@ func Test_ServiceProvider_FetchMetadata_Cache(t *testing.T) { expectErrorOnRefresh: true, }, { - name: "use stale document", - opts: []saml.Option{saml.WithStale(true)}, - newTime: "2017-07-26", - failOnRefresh: true, - shoudBeCached: true, + name: "use stale document", + opts: []saml.Option{saml.WithStale(true)}, + newTime: "2017-07-26", + failOnRefresh: true, + shouldBeCached: true, }, } @@ -221,7 +221,7 @@ func Test_ServiceProvider_FetchMetadata_Cache(t *testing.T) { } r.NotNil(got2) - if tt.shoudBeCached { + if tt.shouldBeCached { r.True(got1 == got2) } else { r.False(got1 == got2) From 4999c8efd0f39e737c7f4b686daeeefbd9ccf3ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Mon, 11 Sep 2023 09:46:05 +0200 Subject: [PATCH 3/5] Run go mod tidy --- saml/go.mod | 2 +- saml/go.sum | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/saml/go.mod b/saml/go.mod index a91d5ef..54df577 100644 --- a/saml/go.mod +++ b/saml/go.mod @@ -5,6 +5,7 @@ go 1.19 require ( github.com/beevik/etree v1.2.0 github.com/crewjam/go-xmlsec v0.0.0-20200414151428-d2b1a58f7262 + github.com/crewjam/saml v0.4.13 github.com/hashicorp/cap v0.3.1 github.com/hashicorp/go-uuid v1.0.3 github.com/jonboulle/clockwork v0.4.0 @@ -16,7 +17,6 @@ require ( require ( github.com/coreos/go-oidc/v3 v3.6.0 // indirect github.com/crewjam/errset v0.0.0-20160219153700-f78d65de925c // indirect - github.com/crewjam/saml v0.4.13 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.15.0 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect diff --git a/saml/go.sum b/saml/go.sum index 79d7094..6304e4a 100644 --- a/saml/go.sum +++ b/saml/go.sum @@ -20,6 +20,7 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU= github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -27,7 +28,7 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/cap v0.3.1 h1:JwX2vg3KIl2+ka4VIPB0yWB9PoPvHL3ACmVrLJLCHDQ= github.com/hashicorp/cap v0.3.1/go.mod h1:dHTmyMIVbzT981XxRoci5G//dfWmd/HhuNiCH6J5+IA= @@ -43,8 +44,8 @@ github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -70,8 +71,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russellhaering/gosaml2 v0.9.1 h1:H/whrl8NuSoxyW46Ww5lKPskm+5K+qYLw9afqJ/Zef0= github.com/russellhaering/gosaml2 v0.9.1/go.mod h1:ja+qgbayxm+0mxBRLMSUuX3COqy+sb0RRhIGun/W2kc= @@ -141,4 +142,5 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= From 0379538d6f24b02e6362dea7470c04706ce362c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Mon, 11 Sep 2023 09:48:37 +0200 Subject: [PATCH 4/5] Run go mod tidy --- saml/go.sum | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) diff --git a/saml/go.sum b/saml/go.sum index 5d7b541..003b56e 100644 --- a/saml/go.sum +++ b/saml/go.sum @@ -13,25 +13,10 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= -github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU= github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= @@ -73,56 +58,21 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs= -golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= From b2cfbd604a08f7d07c96a41577ddbf68b17e22e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Mon, 11 Sep 2023 15:18:00 +0200 Subject: [PATCH 5/5] Update saml/sp_test.go Co-authored-by: Jim --- saml/sp_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/saml/sp_test.go b/saml/sp_test.go index b4b4516..9c74bba 100644 --- a/saml/sp_test.go +++ b/saml/sp_test.go @@ -218,9 +218,8 @@ func Test_ServiceProvider_FetchMetadata_Cache(t *testing.T) { if tt.expectErrorOnRefresh { r.Error(err) return - } else { - r.NoError(err) - } + } + r.NoError(err) r.NotNil(got2) if tt.shouldBeCached {