diff --git a/compose/compose_strategy.go b/compose/compose_strategy.go index 21550ab9..f48ab9e0 100644 --- a/compose/compose_strategy.go +++ b/compose/compose_strategy.go @@ -6,7 +6,6 @@ package compose import ( "context" - "github.com/coocood/freecache" "github.com/ory/fosite" "github.com/ory/fosite/handler/oauth2" "github.com/ory/fosite/handler/openid" @@ -55,8 +54,7 @@ func NewOpenIDConnectStrategy(keyGetter func(context.Context) (interface{}, erro // Create a new device strategy func NewDeviceStrategy(config fosite.Configurator) *rfc8628.DefaultDeviceStrategy { return &rfc8628.DefaultDeviceStrategy{ - Enigma: &hmac.HMACStrategy{Config: config}, - RateLimiterCache: freecache.NewCache(1024 * 1024), - Config: config, + Enigma: &hmac.HMACStrategy{Config: config}, + Config: config, } } diff --git a/go.mod b/go.mod index 5de2f315..b368ff95 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ replace github.com/gorilla/sessions => github.com/gorilla/sessions v1.2.1 require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 - github.com/coocood/freecache v1.2.4 github.com/cristalhq/jwt/v4 v4.0.2 github.com/dgraph-io/ristretto v0.1.1 github.com/go-jose/go-jose/v3 v3.0.3 diff --git a/go.sum b/go.sum index 2fca2c19..fadb0a27 100644 --- a/go.sum +++ b/go.sum @@ -46,7 +46,6 @@ github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqy github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -57,8 +56,6 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coocood/freecache v1.2.4 h1:UdR6Yz/X1HW4fZOuH0Z94KwG851GWOSknua5VUbb/5M= -github.com/coocood/freecache v1.2.4/go.mod h1:RBUWa/Cy+OHdfTGFEhEuE1pMCMX51Ncizj7rthiQ3vk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -375,7 +372,6 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH 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/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= diff --git a/handler/openid/flow_device_auth_test.go b/handler/openid/flow_device_auth_test.go index 3de6aec8..34bb3bbf 100644 --- a/handler/openid/flow_device_auth_test.go +++ b/handler/openid/flow_device_auth_test.go @@ -15,8 +15,6 @@ import ( "github.com/stretchr/testify/require" - "github.com/coocood/freecache" - "github.com/ory/fosite" "github.com/ory/fosite/handler/rfc8628" "github.com/ory/fosite/token/hmac" @@ -42,9 +40,8 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) { h := OpenIDConnectDeviceHandler{ OpenIDConnectRequestStorage: store, DeviceCodeStrategy: &rfc8628.DefaultDeviceStrategy{ - Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobar")}}, - RateLimiterCache: freecache.NewCache(1024 * 1024), - Config: config, + Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobar")}}, + Config: config, }, Config: config, IDTokenHandleHelper: &IDTokenHandleHelper{ diff --git a/handler/openid/flow_device_token_test.go b/handler/openid/flow_device_token_test.go index 25442a74..dbd7c696 100644 --- a/handler/openid/flow_device_token_test.go +++ b/handler/openid/flow_device_token_test.go @@ -14,7 +14,6 @@ import ( "github.com/stretchr/testify/require" - "github.com/coocood/freecache" "github.com/ory/fosite/handler/rfc8628" "github.com/ory/fosite/internal" "github.com/ory/fosite/token/hmac" @@ -59,9 +58,8 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { h := OpenIDConnectDeviceHandler{ OpenIDConnectRequestStorage: store, DeviceCodeStrategy: &rfc8628.DefaultDeviceStrategy{ - Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobar")}}, - RateLimiterCache: freecache.NewCache(1024 * 1024), - Config: config, + Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobar")}}, + Config: config, }, Config: config, IDTokenHandleHelper: &IDTokenHandleHelper{ diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go index 81611670..9f604096 100644 --- a/handler/rfc8628/strategy_hmacsha.go +++ b/handler/rfc8628/strategy_hmacsha.go @@ -5,11 +5,9 @@ package rfc8628 import ( "context" - "encoding/json" "strings" "time" - "github.com/coocood/freecache" "github.com/mohae/deepcopy" "github.com/ory/x/errorsx" @@ -101,9 +99,8 @@ func (s *DefaultDeviceFlowSession) SetBrowserFlowCompleted(flag bool) { // DefaultDeviceStrategy implements the default device strategy type DefaultDeviceStrategy struct { - Enigma *enigma.HMACStrategy - RateLimiterCache *freecache.Cache - Config interface { + Enigma *enigma.HMACStrategy + Config interface { fosite.DeviceProvider fosite.DeviceAndUserCodeLifespanProvider } @@ -173,70 +170,5 @@ func (h *DefaultDeviceStrategy) ValidateDeviceCode(ctx context.Context, r fosite // ShouldRateLimit is used to decide whether a request should be rate-limited func (h *DefaultDeviceStrategy) ShouldRateLimit(context context.Context, code string) (bool, error) { - key := code + "_limiter" - - keyBytes := []byte(key) - object, err := h.RateLimiterCache.Get(keyBytes) - // This code is not in the cache, so we just add it - if err != nil { - timer := new(expirationTimer) - timer.Counter = 1 - timer.NotUntil = h.getNotUntil(context, 1) - exp, err := h.serializeExpiration(timer) - if err != nil { - return false, errorsx.WithStack(fosite.ErrServerError.WithHintf("Failed to serialize expiration struct %s", err)) - } - // Set the expiration time as value, and use the lifespan of the device code as TTL. - h.RateLimiterCache.Set(keyBytes, exp, int(h.Config.GetDeviceAndUserCodeLifespan(context).Seconds())) - return false, nil - } - - expiration, err := h.deserializeExpiration(object) - if err != nil { - return false, errorsx.WithStack(fosite.ErrServerError.WithHintf("Failed to store to rate limit cache: %s", err)) - } - - // The code is valid and enough time has passed since the last call. - if time.Now().After(expiration.NotUntil) { - expiration.NotUntil = h.getNotUntil(context, expiration.Counter) - exp, err := h.serializeExpiration(expiration) - if err != nil { - return false, errorsx.WithStack(fosite.ErrServerError.WithHintf("Failed to serialize expiration struct %s", err)) - } - h.RateLimiterCache.Set(keyBytes, exp, int(h.Config.GetDeviceAndUserCodeLifespan(context).Seconds())) - return false, nil - } - - // The token calls were made too fast, we need to double the interval period - expiration.NotUntil = h.getNotUntil(context, expiration.Counter+1) - expiration.Counter += 1 - exp, err := h.serializeExpiration(expiration) - if err != nil { - return false, errorsx.WithStack(fosite.ErrServerError.WithHintf("Failed to serialize expiration struct %s", err)) - } - h.RateLimiterCache.Set(keyBytes, exp, int(h.Config.GetDeviceAndUserCodeLifespan(context).Seconds())) - - return true, nil -} - -func (h *DefaultDeviceStrategy) getNotUntil(context context.Context, multiplier int) time.Time { - duration := h.Config.GetDeviceAuthTokenPollingInterval(context) - expiration := time.Now().Add(duration * time.Duration(multiplier)).Add(-POLLING_RATE_LIMITING_LEEWAY) - return expiration -} - -type expirationTimer struct { - NotUntil time.Time - Counter int -} - -func (h *DefaultDeviceStrategy) serializeExpiration(exp *expirationTimer) ([]byte, error) { - b, err := json.Marshal(exp) - return b, err -} - -func (h *DefaultDeviceStrategy) deserializeExpiration(b []byte) (*expirationTimer, error) { - timer := new(expirationTimer) - err := json.Unmarshal(b, timer) - return timer, err + return false, nil } diff --git a/handler/rfc8628/strategy_hmacsha_test.go b/handler/rfc8628/strategy_hmacsha_test.go index 40554cab..666a4725 100644 --- a/handler/rfc8628/strategy_hmacsha_test.go +++ b/handler/rfc8628/strategy_hmacsha_test.go @@ -11,7 +11,6 @@ import ( "testing" "time" - "github.com/coocood/freecache" "github.com/stretchr/testify/assert" "github.com/ory/fosite" @@ -20,8 +19,7 @@ import ( ) var hmacshaStrategy = DefaultDeviceStrategy{ - Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, - RateLimiterCache: freecache.NewCache(16384 * 64), + Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, Config: &fosite.Config{ AccessTokenLifespan: time.Minute * 24, AuthorizeCodeLifespan: time.Minute * 24, @@ -110,33 +108,3 @@ func TestHMACDeviceCode(t *testing.T) { }) } } - -func TestRateLimit(t *testing.T) { - t.Run("ratelimit no-wait", func(t *testing.T) { - hmacshaStrategy.RateLimiterCache.Clear() - b, err := hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA") - assert.NoError(t, err) - assert.False(t, b) - b, err = hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA") - assert.NoError(t, err) - assert.True(t, b) - }) - - t.Run("ratelimit wait", func(t *testing.T) { - hmacshaStrategy.RateLimiterCache.Clear() - b, err := hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA") - assert.NoError(t, err) - assert.False(t, b) - time.Sleep(500 * time.Millisecond) - b, err = hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA") - assert.NoError(t, err) - assert.False(t, b) - time.Sleep(500 * time.Millisecond) - b, err = hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA") - assert.NoError(t, err) - assert.False(t, b) - b, err = hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA") - assert.NoError(t, err) - assert.True(t, b) - }) -} diff --git a/handler/rfc8628/token_handler.go b/handler/rfc8628/token_handler.go index 08803ed6..fe4d54a6 100644 --- a/handler/rfc8628/token_handler.go +++ b/handler/rfc8628/token_handler.go @@ -247,7 +247,7 @@ func (c DeviceCodeTokenEndpointHandler) validateCode(ctx context.Context, reques return err } if shouldRateLimit { - return errorsx.WithStack(fosite.ErrPollingRateLimited) + return errorsx.WithStack(fosite.ErrSlowDown) } return nil } diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index b0e7ede8..c8a71d55 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -10,7 +10,6 @@ import ( "testing" "time" - "github.com/coocood/freecache" "github.com/pkg/errors" "github.com/ory/fosite/internal" @@ -34,8 +33,7 @@ var hmacshaStrategy = oauth2.NewHMACSHAStrategy( ) var RFC8628HMACSHAStrategy = DefaultDeviceStrategy{ - Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, - RateLimiterCache: freecache.NewCache(1024 * 1024), + Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, Config: &fosite.Config{ DeviceAndUserCodeLifespan: time.Minute * 30, }, @@ -350,7 +348,7 @@ func TestDeviceUserCode_HandleTokenEndpointRequest_RateLimiting(t *testing.T) { err = h.HandleTokenEndpointRequest(context.Background(), areq) require.NoError(t, err, "%+v", err) err = h.HandleTokenEndpointRequest(context.Background(), areq) - require.Error(t, fosite.ErrPollingRateLimited, err) + require.Error(t, fosite.ErrSlowDown, err) time.Sleep(10 * time.Second) err = h.HandleTokenEndpointRequest(context.Background(), areq) require.NoError(t, err, "%+v", err)