Skip to content

Commit

Permalink
Add RateLimit to Device Polling endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
supercairos committed Jan 4, 2024
1 parent 5bc8783 commit e8b1654
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 133 deletions.
4 changes: 2 additions & 2 deletions compose/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ func Compose(config *fosite.Config, storage interface{}, strategy interface{}, f
if dh, ok := res.(fosite.DeviceEndpointHandler); ok {
config.DeviceEndpointHandlers.Append(dh)
}
if dah, ok := res.(fosite.DeviceUserEndpointHandler); ok {
config.DeviceUserEndpointHandlers.Append(dah)
if duh, ok := res.(fosite.DeviceUserEndpointHandler); ok {
config.DeviceUserEndpointHandlers.Append(duh)
}
}

Expand Down
9 changes: 5 additions & 4 deletions compose/compose_rfc8628.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ func RFC8628DeviceFactory(config fosite.Configurator, storage interface{}, strat
}
}

// OAuth2DeviceCodeFactory creates an OAuth2 device authorization grant ("device authorization flow") handler and registers
// RFC8628DeviceAuthorizationTokenFactory creates an OAuth2 device authorization grant ("Device Authorization Grant") handler and registers
// an access token, refresh token and authorize code validator.
func RFC8628DeviceAuthorizationTokenFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} {
return &rfc8628.DeviceCodeTokenEndpointHandler{
GenericCodeTokenEndpointHandler: oauth2.GenericCodeTokenEndpointHandler{
CodeTokenEndpointHandler: &rfc8628.DeviceUserHandler{
DeviceStrategy: strategy.(rfc8628.DeviceCodeStrategy),
DeviceStorage: storage.(rfc8628.DeviceCodeStorage),
CodeTokenEndpointHandler: &rfc8628.DeviceHandler{
DeviceRateLimitStrategy: strategy.(rfc8628.DeviceRateLimitStrategy),
DeviceStrategy: strategy.(rfc8628.DeviceCodeStrategy),
DeviceStorage: storage.(rfc8628.DeviceCodeStorage),
},
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
Expand Down
5 changes: 5 additions & 0 deletions compose/compose_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/ory/fosite/handler/rfc8628"
"github.com/ory/fosite/token/hmac"
"github.com/ory/fosite/token/jwt"
"github.com/patrickmn/go-cache"
)

type CommonStrategy struct {
Expand Down Expand Up @@ -57,6 +58,10 @@ func NewOpenIDConnectStrategy(keyGetter func(context.Context) (interface{}, erro
func NewDeviceStrategy(config fosite.Configurator) *rfc8628.DefaultDeviceStrategy {
return &rfc8628.DefaultDeviceStrategy{
Enigma: &hmac.HMACStrategy{Config: config},
RateLimiterCache: cache.New(
config.GetDeviceAndUserCodeLifespan(context.TODO()),
config.GetDeviceAndUserCodeLifespan(context.TODO())*2,
),
Config: config,
}
}
6 changes: 3 additions & 3 deletions device_user_response_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import (
"context"
)

func (f *Fosite) NewDeviceUserResponse(ctx context.Context, dar DeviceUserRequester, session Session) (DeviceUserResponder, error) {
func (f *Fosite) NewDeviceUserResponse(ctx context.Context, dur DeviceUserRequester, session Session) (DeviceUserResponder, error) {
var resp = &DeviceUserResponse{}

dar.SetSession(session)
dur.SetSession(session)
for _, h := range f.Config.GetDeviceUserEndpointHandlers(ctx) {
if err := h.HandleDeviceUserEndpointRequest(ctx, dar, resp); err != nil {
if err := h.HandleDeviceUserEndpointRequest(ctx, dur, resp); err != nil {
return nil, err
}
}
Expand Down
7 changes: 7 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,12 @@ var (
ErrorField: errAuthorizationPending,
CodeField: http.StatusBadRequest,
}
ErrPollingRateLimited = &RFC6749Error{
DescriptionField: "The authorization request was rate-limited to prevent system overload.",
HintField: "Ensure that you don't call the token endpoint sooner than the polling interval",
ErrorField: errPollingIntervalRateLimited,
CodeField: http.StatusTooManyRequests,
}
ErrDeviceExpiredToken = &RFC6749Error{
DescriptionField: "The device_code has expired, and the device authorization session has concluded.",
ErrorField: errDeviceExpiredToken,
Expand Down Expand Up @@ -254,6 +260,7 @@ const (
errRegistrationNotSupportedName = "registration_not_supported"
errJTIKnownName = "jti_known"
errAuthorizationPending = "authorization_pending"
errPollingIntervalRateLimited = "polling_interval_rate_limited"
errDeviceExpiredToken = "expired_token"
)

Expand Down
69 changes: 36 additions & 33 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ replace github.com/gobuffalo/packr => github.com/gobuffalo/packr v1.30.1

replace github.com/gorilla/sessions => github.com/gorilla/sessions v1.2.1

replace github.com/ory/x => ../x

require (
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
github.com/cristalhq/jwt/v4 v4.0.2
github.com/dgraph-io/ristretto v0.1.1
github.com/ecordell/optgen v0.0.9
github.com/go-jose/go-jose/v3 v3.0.0
github.com/golang/mock v1.6.0
github.com/google/uuid v1.3.0
github.com/google/uuid v1.3.1
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.5.0
github.com/hashicorp/go-retryablehttp v0.7.4
Expand All @@ -23,16 +25,18 @@ require (
github.com/oleiade/reflections v1.0.1
github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe
github.com/ory/go-convenience v0.1.0
github.com/ory/x v0.0.575
github.com/ory/x v0.0.0-00010101000000-000000000000
github.com/parnurzeal/gorequest v0.2.15
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.8.4
github.com/tidwall/gjson v1.14.3
go.opentelemetry.io/otel/trace v1.16.0
golang.org/x/crypto v0.11.0
golang.org/x/net v0.13.0
golang.org/x/oauth2 v0.10.0
golang.org/x/text v0.11.0
go.opentelemetry.io/otel/trace v1.19.0
golang.org/x/crypto v0.15.0
golang.org/x/net v0.18.0
golang.org/x/oauth2 v0.14.0
golang.org/x/text v0.14.0
golang.org/x/time v0.4.0
)

require (
Expand All @@ -44,21 +48,21 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gobuffalo/pop/v6 v6.0.8 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.1.1 // indirect
github.com/golang/glog v1.1.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/openzipkin/zipkin-go v0.4.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 // indirect
Expand All @@ -73,28 +77,27 @@ require (
github.com/subosito/gotenv v1.4.2 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.42.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect
go.opentelemetry.io/contrib/propagators/b3 v1.17.0 // indirect
go.opentelemetry.io/contrib/propagators/jaeger v1.17.0 // indirect
go.opentelemetry.io/contrib/samplers/jaegerremote v0.11.0 // indirect
go.opentelemetry.io/otel v1.16.0 // indirect
go.opentelemetry.io/otel/exporters/jaeger v1.16.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 // indirect
go.opentelemetry.io/otel/exporters/zipkin v1.16.0 // indirect
go.opentelemetry.io/otel/metric v1.16.0 // indirect
go.opentelemetry.io/otel/sdk v1.16.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
go.opentelemetry.io/contrib/propagators/b3 v1.20.0 // indirect
go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 // indirect
go.opentelemetry.io/contrib/samplers/jaegerremote v0.14.0 // indirect
go.opentelemetry.io/otel v1.19.0 // indirect
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect
go.opentelemetry.io/otel/exporters/zipkin v1.19.0 // indirect
go.opentelemetry.io/otel/metric v1.19.0 // indirect
go.opentelemetry.io/otel/sdk v1.19.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/tools v0.11.1 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230731193218-e0aa005b6bdf // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230731193218-e0aa005b6bdf // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230731193218-e0aa005b6bdf // indirect
google.golang.org/grpc v1.57.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/tools v0.15.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
Loading

0 comments on commit e8b1654

Please sign in to comment.