From da9b16b19bc57ccd24e2016fe414f386d7bb8413 Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 15 Oct 2024 13:09:26 +0300 Subject: [PATCH 01/36] fix: fix tests --- handler/rfc7523/handler_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/handler/rfc7523/handler_test.go b/handler/rfc7523/handler_test.go index aeb2811ba..c2897793b 100644 --- a/handler/rfc7523/handler_test.go +++ b/handler/rfc7523/handler_test.go @@ -773,9 +773,9 @@ func (s *AuthorizeJWTGrantRequestHandlerTestSuite) createStandardClaim() jwt.Cla Issuer: "trusted_issuer", Subject: "some_ro", Audience: jwt.Audience{"https://www.example.com/token", "leela", "fry"}, - Expiry: jwt.NewNumericDate(time.Now().AddDate(0, 0, 23)), + Expiry: jwt.NewNumericDate(time.Now().UTC().AddDate(0, 0, 23)), NotBefore: nil, - IssuedAt: jwt.NewNumericDate(time.Now().AddDate(0, 0, -7)), + IssuedAt: jwt.NewNumericDate(time.Now().UTC().AddDate(0, 0, -7)), ID: "my_token", } } From a2f56111dbdb45e85b2c4a571990475e4a7fb327 Mon Sep 17 00:00:00 2001 From: Nikos Date: Mon, 5 Feb 2024 16:07:56 +0200 Subject: [PATCH 02/36] fix: Use Requester param in WriteAccessError The WriteAccessError is used to construct error responses as described in Section 5.2 of [RFC6749]. It is not limited to access token responses. Perhaps we should rename the function to Rfc6749TokenError. --- access_error.go | 5 +++-- oauth2.go | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/access_error.go b/access_error.go index 5364072a5..d4c59850e 100644 --- a/access_error.go +++ b/access_error.go @@ -10,11 +10,12 @@ import ( "net/http" ) -func (f *Fosite) WriteAccessError(ctx context.Context, rw http.ResponseWriter, req AccessRequester, err error) { +// Convert an error to an http response as per RFC6749 +func (f *Fosite) WriteAccessError(ctx context.Context, rw http.ResponseWriter, req Requester, err error) { f.writeJsonError(ctx, rw, req, err) } -func (f *Fosite) writeJsonError(ctx context.Context, rw http.ResponseWriter, requester AccessRequester, err error) { +func (f *Fosite) writeJsonError(ctx context.Context, rw http.ResponseWriter, requester Requester, err error) { rw.Header().Set("Content-Type", "application/json;charset=UTF-8") rw.Header().Set("Cache-Control", "no-store") rw.Header().Set("Pragma", "no-cache") diff --git a/oauth2.go b/oauth2.go index 0827b8ed6..0e4700d5f 100644 --- a/oauth2.go +++ b/oauth2.go @@ -120,7 +120,7 @@ type OAuth2Provider interface { // // The following specs must be considered in any implementation of this method: // * https://tools.ietf.org/html/rfc6749#section-5.2 (everything) - WriteAccessError(ctx context.Context, rw http.ResponseWriter, requester AccessRequester, err error) + WriteAccessError(ctx context.Context, rw http.ResponseWriter, requester Requester, err error) // WriteAccessResponse writes the access response. // From 55b085d721b0dd2526c3e635b5c93cf9d0015298 Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 6 Feb 2024 10:53:18 +0200 Subject: [PATCH 03/36] fix: generalize validateAuthorizeAudience method --- audience_strategy.go | 6 +++--- authorize_request_handler.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/audience_strategy.go b/audience_strategy.go index 75d4bbf8c..bcef40bbe 100644 --- a/audience_strategy.go +++ b/audience_strategy.go @@ -92,10 +92,10 @@ func GetAudiences(form url.Values) []string { } } -func (f *Fosite) validateAuthorizeAudience(ctx context.Context, r *http.Request, request *AuthorizeRequest) error { - audience := GetAudiences(request.Form) +func (f *Fosite) validateAudience(ctx context.Context, r *http.Request, request Requester) error { + audience := GetAudiences(request.GetRequestForm()) - if err := f.Config.GetAudienceStrategy(ctx)(request.Client.GetAudience(), audience); err != nil { + if err := f.Config.GetAudienceStrategy(ctx)(request.GetClient().GetAudience(), audience); err != nil { return err } diff --git a/authorize_request_handler.go b/authorize_request_handler.go index 675983fc6..9ec9bae45 100644 --- a/authorize_request_handler.go +++ b/authorize_request_handler.go @@ -390,7 +390,7 @@ func (f *Fosite) newAuthorizeRequest(ctx context.Context, r *http.Request, isPAR return request, err } - if err = f.validateAuthorizeAudience(ctx, r, request); err != nil { + if err = f.validateAudience(ctx, r, request); err != nil { return request, err } From 27fc5e14224f0a62ce5f5620e2eceaeb3d184dab Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 6 Feb 2024 14:45:11 +0200 Subject: [PATCH 04/36] feat: add device flow base logic --- device_request.go | 15 +++ device_request_handler.go | 87 ++++++++++++++ device_request_handler_test.go | 214 +++++++++++++++++++++++++++++++++ device_request_test.go | 18 +++ device_response.go | 87 ++++++++++++++ device_response_test.go | 26 ++++ device_response_writer.go | 21 ++++ device_write.go | 43 +++++++ device_write_test.go | 61 ++++++++++ 9 files changed, 572 insertions(+) create mode 100644 device_request.go create mode 100644 device_request_handler.go create mode 100644 device_request_handler_test.go create mode 100644 device_request_test.go create mode 100644 device_response.go create mode 100644 device_response_test.go create mode 100644 device_response_writer.go create mode 100644 device_write.go create mode 100644 device_write_test.go diff --git a/device_request.go b/device_request.go new file mode 100644 index 000000000..3c2df0636 --- /dev/null +++ b/device_request.go @@ -0,0 +1,15 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package fosite + +// DeviceRequest is an implementation of DeviceRequester +type DeviceRequest struct { + Request +} + +func NewDeviceRequest() *DeviceRequest { + return &DeviceRequest{ + Request: *NewRequest(), + } +} diff --git a/device_request_handler.go b/device_request_handler.go new file mode 100644 index 000000000..20d3b1e26 --- /dev/null +++ b/device_request_handler.go @@ -0,0 +1,87 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +/* + * Copyright © 2015-2021 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2021 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + "net/http" + "strings" + + "github.com/ory/fosite/i18n" + "github.com/ory/x/errorsx" + "github.com/ory/x/otelx" + "go.opentelemetry.io/otel/trace" +) + +func (f *Fosite) NewDeviceRequest(ctx context.Context, r *http.Request) (_ DeviceRequester, err error) { + ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("github.com/ory/fosite").Start(ctx, "Fosite.NewAccessRequest") + defer otelx.End(span, &err) + + request := NewDeviceRequest() + request.Lang = i18n.GetLangFromRequest(f.Config.GetMessageCatalog(ctx), r) + + if r.Method != "POST" { + return request, errorsx.WithStack(ErrInvalidRequest.WithHintf("HTTP method is '%s', expected 'POST'.", r.Method)) + } else if err := r.ParseForm(); err != nil { + return nil, errorsx.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithWrap(err).WithDebug(err.Error())) + } else if len(r.PostForm) == 0 { + return request, errorsx.WithStack(ErrInvalidRequest.WithHint("The POST body can not be empty.")) + } + request.Form = r.PostForm + + client, clientErr := f.AuthenticateClient(ctx, r, r.PostForm) + if clientErr != nil { + return request, clientErr + } + if client.GetID() != request.Form.Get("client_id") { + return request, errorsx.WithStack(ErrInvalidRequest.WithHint("Provided client_id mismatch.")) + } + request.Client = client + + if !client.GetGrantTypes().Has(string(GrantTypeDeviceCode)) { + return nil, errorsx.WithStack(ErrInvalidGrant.WithHint("The requested OAuth 2.0 Client does not have the 'urn:ietf:params:oauth:grant-type:device_code' grant.")) + } + + if err := f.validateDeviceScope(ctx, r, request); err != nil { + return nil, err + } + + if err := f.validateAudience(ctx, r, request); err != nil { + return request, err + } + + return request, nil +} + +func (f *Fosite) validateDeviceScope(ctx context.Context, r *http.Request, request *DeviceRequest) error { + scope := RemoveEmpty(strings.Split(request.Form.Get("scope"), " ")) + for _, permission := range scope { + if !f.Config.GetScopeStrategy(ctx)(request.Client.GetScopes(), permission) { + return errorsx.WithStack(ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope '%s'.", permission)) + } + } + request.SetRequestedScopes(scope) + return nil +} diff --git a/device_request_handler_test.go b/device_request_handler_test.go new file mode 100644 index 000000000..d6dceeffa --- /dev/null +++ b/device_request_handler_test.go @@ -0,0 +1,214 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package fosite_test + +import ( + "context" + "fmt" + "net/http" + "net/url" + "testing" + + "github.com/golang/mock/gomock" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + . "github.com/ory/fosite" + "github.com/ory/fosite/internal" +) + +func TestNewDeviceRequestWithPublicClient(t *testing.T) { + ctrl := gomock.NewController(t) + store := internal.NewMockStorage(ctrl) + client := &DefaultClient{ID: "client_id"} + defer ctrl.Finish() + config := &Config{ScopeStrategy: ExactScopeStrategy, AudienceMatchingStrategy: DefaultAudienceMatchingStrategy} + fosite := &Fosite{Store: store, Config: config} + for k, c := range []struct { + header http.Header + form url.Values + method string + expectedError error + mock func() + expect DeviceRequester + }{ + /* invalid Method */ + { + expectedError: ErrInvalidRequest, + method: "GET", + mock: func() {}, + }, + /* empty request */ + { + expectedError: ErrInvalidRequest, + method: "POST", + mock: func() {}, + }, + /* invalid client */ + { + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"foo bar"}, + }, + expectedError: ErrInvalidClient, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(nil, errors.New("")) + }, + }, + /* fails because scope not allowed */ + { + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"17 42 foo"}, + }, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) + client.Public = true + client.Scopes = []string{"17", "42"} + client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + }, + expectedError: ErrInvalidScope, + }, + /* fails because scope not allowed */ + { + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"17 42"}, + "audience": {"aud"}, + }, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) + client.Public = true + client.Scopes = []string{"17", "42"} + client.Audience = []string{"aud2"} + client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + }, + expectedError: ErrInvalidRequest, + }, + /* should fail because doesn't have proper grant */ + { + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"17 42"}, + }, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) + client.Public = true + client.Scopes = []string{"17", "42"} + client.GrantTypes = []string{"authorization_code"} + }, + expectedError: ErrInvalidGrant, + }, + /* success case */ + { + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"17 42"}, + }, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) + client.Public = true + client.Scopes = []string{"17", "42"} + client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + }, + }, + } { + t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + c.mock() + r := &http.Request{ + Header: c.header, + PostForm: c.form, + Form: c.form, + Method: c.method, + } + + ar, err := fosite.NewDeviceRequest(context.Background(), r) + if c.expectedError != nil { + assert.EqualError(t, err, c.expectedError.Error()) + } else { + require.NoError(t, err) + assert.NotNil(t, ar.GetRequestedAt()) + } + }) + } +} + +func TestNewDeviceRequestWithClientAuthn(t *testing.T) { + ctrl := gomock.NewController(t) + store := internal.NewMockStorage(ctrl) + hasher := internal.NewMockHasher(ctrl) + client := &DefaultClient{ID: "client_id"} + defer ctrl.Finish() + config := &Config{ClientSecretsHasher: hasher, ScopeStrategy: ExactScopeStrategy, AudienceMatchingStrategy: DefaultAudienceMatchingStrategy} + fosite := &Fosite{Store: store, Config: config} + for k, c := range []struct { + header http.Header + form url.Values + method string + expectedError error + mock func() + expect DeviceRequester + }{ + // No client authn provided + { + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"foo bar"}, + }, + expectedError: ErrInvalidClient, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) + client.Public = false + client.Secret = []byte("client_secret") + client.Scopes = []string{"foo", "bar"} + client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + hasher.EXPECT().Compare(gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("")) + }, + }, + // success + { + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"foo bar"}, + }, + header: http.Header{ + "Authorization": {basicAuth("client_id", "client_secret")}, + }, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) + client.Public = false + client.Secret = []byte("client_secret") + client.Scopes = []string{"foo", "bar"} + client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + hasher.EXPECT().Compare(gomock.Any(), gomock.Eq([]byte("client_secret")), gomock.Eq([]byte("client_secret"))).Return(nil) + }, + }, + } { + t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + c.mock() + r := &http.Request{ + Header: c.header, + PostForm: c.form, + Form: c.form, + Method: c.method, + } + + req, err := fosite.NewDeviceRequest(context.Background(), r) + if c.expectedError != nil { + assert.EqualError(t, err, c.expectedError.Error()) + } else { + require.NoError(t, err) + assert.NotNil(t, req.GetRequestedAt()) + } + }) + } +} diff --git a/device_request_test.go b/device_request_test.go new file mode 100644 index 000000000..571e83ba8 --- /dev/null +++ b/device_request_test.go @@ -0,0 +1,18 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package fosite + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDeviceRequest(t *testing.T) { + r := NewDeviceRequest() + r.Client = &DefaultClient{} + r.SetRequestedScopes([]string{"17", "42"}) + assert.True(t, r.GetRequestedScopes().Has("17", "42")) + assert.Equal(t, r.Client, r.GetClient()) +} diff --git a/device_response.go b/device_response.go new file mode 100644 index 000000000..a70ee25fe --- /dev/null +++ b/device_response.go @@ -0,0 +1,87 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package fosite + +import ( + "net/http" +) + +type deviceResponse struct { + Header http.Header + DeviceCode string `json:"device_code"` + UserCode string `json:"user_code"` + VerificationURI string `json:"verification_uri"` + VerificationURIComplete string `json:"verification_uri_complete,omitempty"` + ExpiresIn int64 `json:"expires_in"` + Interval int `json:"interval,omitempty"` +} + +type DeviceResponse struct { + deviceResponse +} + +func NewDeviceResponse() *DeviceResponse { + return &DeviceResponse{} +} + +func (d *DeviceResponse) GetDeviceCode() string { + return d.deviceResponse.DeviceCode +} + +// SetDeviceCode returns the response's user code +func (d *DeviceResponse) SetDeviceCode(code string) { + d.deviceResponse.DeviceCode = code +} + +func (d *DeviceResponse) GetUserCode() string { + return d.deviceResponse.UserCode +} + +func (d *DeviceResponse) SetUserCode(code string) { + d.deviceResponse.UserCode = code +} + +// GetVerificationURI returns the response's verification uri +func (d *DeviceResponse) GetVerificationURI() string { + return d.deviceResponse.VerificationURI +} + +func (d *DeviceResponse) SetVerificationURI(uri string) { + d.deviceResponse.VerificationURI = uri +} + +// GetVerificationURIComplete returns the response's complete verification uri if set +func (d *DeviceResponse) GetVerificationURIComplete() string { + return d.deviceResponse.VerificationURIComplete +} + +func (d *DeviceResponse) SetVerificationURIComplete(uri string) { + d.deviceResponse.VerificationURIComplete = uri +} + +// GetExpiresIn returns the response's device code and user code lifetime in seconds if set +func (d *DeviceResponse) GetExpiresIn() int64 { + return d.deviceResponse.ExpiresIn +} + +func (d *DeviceResponse) SetExpiresIn(seconds int64) { + d.deviceResponse.ExpiresIn = seconds +} + +// GetInterval returns the response's polling interval if set +func (d *DeviceResponse) GetInterval() int { + return d.deviceResponse.Interval +} + +func (d *DeviceResponse) SetInterval(seconds int) { + d.deviceResponse.Interval = seconds +} + +func (a *DeviceResponse) GetHeader() http.Header { + return a.deviceResponse.Header +} + +func (a *DeviceResponse) AddHeader(key, value string) { + a.deviceResponse.Header.Add(key, value) +} diff --git a/device_response_test.go b/device_response_test.go new file mode 100644 index 000000000..366899a1b --- /dev/null +++ b/device_response_test.go @@ -0,0 +1,26 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package fosite + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDeviceResponse(t *testing.T) { + r := NewDeviceResponse() + r.SetDeviceCode("device_code") + r.SetUserCode("user_code") + r.SetExpiresIn(5) + r.SetVerificationURI("https://www.example.com") + r.SetVerificationURIComplete("https://www.example.com?code=user_code") + r.SetInterval(5) + assert.Equal(t, "device_code", r.GetDeviceCode()) + assert.Equal(t, "user_code", r.GetUserCode()) + assert.Equal(t, int64(5), r.GetExpiresIn()) + assert.Equal(t, "https://www.example.com", r.GetVerificationURI()) + assert.Equal(t, "https://www.example.com?code=user_code", r.GetVerificationURIComplete()) + assert.Equal(t, 5, r.GetInterval()) +} diff --git a/device_response_writer.go b/device_response_writer.go new file mode 100644 index 000000000..82c5d7c93 --- /dev/null +++ b/device_response_writer.go @@ -0,0 +1,21 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package fosite + +import ( + "context" +) + +func (f *Fosite) NewDeviceResponse(ctx context.Context, r DeviceRequester, session Session) (DeviceResponder, error) { + var resp = &DeviceResponse{} + + r.SetSession(session) + for _, h := range f.Config.GetDeviceEndpointHandlers(ctx) { + if err := h.HandleDeviceEndpointRequest(ctx, r, resp); err != nil { + return nil, err + } + } + + return resp, nil +} diff --git a/device_write.go b/device_write.go new file mode 100644 index 000000000..f21184dbe --- /dev/null +++ b/device_write.go @@ -0,0 +1,43 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package fosite + +import ( + "context" + "encoding/json" + "net/http" +) + +// TODO: Do documentation + +func (f *Fosite) WriteDeviceResponse(ctx context.Context, rw http.ResponseWriter, requester DeviceRequester, responder DeviceResponder) { + // Set custom headers, e.g. "X-MySuperCoolCustomHeader" or "X-DONT-CACHE-ME"... + wh := rw.Header() + rh := responder.GetHeader() + for k := range rh { + wh.Set(k, rh.Get(k)) + } + + rw.Header().Set("Content-Type", "application/json;charset=UTF-8") + rw.Header().Set("Cache-Control", "no-store") + rw.Header().Set("Pragma", "no-cache") + + deviceResponse := &DeviceResponse{ + deviceResponse{ + DeviceCode: responder.GetDeviceCode(), + UserCode: responder.GetUserCode(), + VerificationURI: responder.GetVerificationURI(), + VerificationURIComplete: responder.GetVerificationURIComplete(), + ExpiresIn: responder.GetExpiresIn(), + Interval: responder.GetInterval(), + }, + } + + r, err := json.Marshal(deviceResponse) + rw.Write(r) + if err != nil { + http.Error(rw, ErrServerError.WithWrap(err).WithDebug(err.Error()).Error(), http.StatusInternalServerError) + return + } +} diff --git a/device_write_test.go b/device_write_test.go new file mode 100644 index 000000000..961d516c7 --- /dev/null +++ b/device_write_test.go @@ -0,0 +1,61 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package fosite_test + +import ( + "context" + "encoding/json" + "io" + "net/http/httptest" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + . "github.com/ory/fosite" +) + +func TestWriteDeviceUserResponse(t *testing.T) { + oauth2 := &Fosite{Config: &Config{ + DeviceAndUserCodeLifespan: time.Minute, + DeviceAuthTokenPollingInterval: time.Minute, + DeviceVerificationURL: "http://ory.sh", + }} + ctx := context.Background() + + rw := httptest.NewRecorder() + ar := &Request{} + resp := &DeviceResponse{} + resp.SetUserCode("AAAA") + resp.SetDeviceCode("BBBB") + resp.SetInterval(int( + oauth2.Config.GetDeviceAuthTokenPollingInterval(ctx).Round(time.Second).Seconds(), + )) + resp.SetExpiresIn(int64( + oauth2.Config.GetDeviceAndUserCodeLifespan(ctx), + )) + resp.SetVerificationURI(oauth2.Config.GetDeviceVerificationURL(ctx)) + resp.SetVerificationURIComplete( + oauth2.Config.GetDeviceVerificationURL(ctx) + "?user_code=" + resp.GetUserCode(), + ) + + oauth2.WriteDeviceResponse(context.Background(), rw, ar, resp) + + assert.Equal(t, 200, rw.Code) + + body, err := io.ReadAll(rw.Body) + require.NoError(t, err) + + wroteDeviceResponse := DeviceResponse{} + err = json.Unmarshal(body, &wroteDeviceResponse) + require.NoError(t, err) + + assert.Equal(t, resp.GetUserCode(), wroteDeviceResponse.UserCode) + assert.Equal(t, resp.GetDeviceCode(), wroteDeviceResponse.DeviceCode) + assert.Equal(t, resp.GetVerificationURI(), wroteDeviceResponse.VerificationURI) + assert.Equal(t, resp.GetVerificationURIComplete(), wroteDeviceResponse.VerificationURIComplete) + assert.Equal(t, resp.GetInterval(), wroteDeviceResponse.Interval) + assert.Equal(t, resp.GetExpiresIn(), wroteDeviceResponse.ExpiresIn) +} From 95c216d337ae5b2c10603b184cb7bfe370cc4a69 Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 6 Feb 2024 14:46:01 +0200 Subject: [PATCH 05/36] fix: add handler for device authorization req --- handler/rfc8628/auth_handler.go | 55 ++++++++++ handler/rfc8628/auth_handler_test.go | 79 ++++++++++++++ handler/rfc8628/storage.go | 52 +++++++++ handler/rfc8628/strategy.go | 32 ++++++ handler/rfc8628/strategy_hmacsha.go | 84 +++++++++++++++ handler/rfc8628/strategy_hmacsha_test.go | 129 +++++++++++++++++++++++ 6 files changed, 431 insertions(+) create mode 100644 handler/rfc8628/auth_handler.go create mode 100644 handler/rfc8628/auth_handler_test.go create mode 100644 handler/rfc8628/storage.go create mode 100644 handler/rfc8628/strategy.go create mode 100644 handler/rfc8628/strategy_hmacsha.go create mode 100644 handler/rfc8628/strategy_hmacsha_test.go diff --git a/handler/rfc8628/auth_handler.go b/handler/rfc8628/auth_handler.go new file mode 100644 index 000000000..9072cbe46 --- /dev/null +++ b/handler/rfc8628/auth_handler.go @@ -0,0 +1,55 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package rfc8628 + +import ( + "context" + "time" + + "github.com/ory/fosite" + "github.com/ory/x/errorsx" +) + +type DeviceAuthHandler struct { + Storage RFC8628CoreStorage + Strategy RFC8628CodeStrategy + Config interface { + fosite.DeviceProvider + fosite.DeviceAndUserCodeLifespanProvider + } +} + +// DeviceAuthorizationHandler is a response handler for the Device Authorisation Grant as +// defined in https://tools.ietf.org/html/rfc8628#section-3.1 +func (d *DeviceAuthHandler) HandleDeviceEndpointRequest(ctx context.Context, dar fosite.DeviceRequester, resp fosite.DeviceResponder) error { + deviceCode, deviceCodeSignature, err := d.Strategy.GenerateDeviceCode(ctx) + if err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + userCode, userCodeSignature, err := d.Strategy.GenerateUserCode(ctx) + if err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + // Store the User Code session (this has no real data other that the user and device code), can be converted into a 'full' session after user auth + dar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx))) + if err := d.Storage.CreateDeviceCodeSession(ctx, deviceCodeSignature, dar.Sanitize(nil)); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + dar.GetSession().SetExpiresAt(fosite.UserCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx)).Round(time.Second)) + if err := d.Storage.CreateUserCodeSession(ctx, userCodeSignature, dar.Sanitize(nil)); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + // Populate the response fields + resp.SetDeviceCode(deviceCode) + resp.SetUserCode(userCode) + resp.SetVerificationURI(d.Config.GetDeviceVerificationURL(ctx)) + resp.SetVerificationURIComplete(d.Config.GetDeviceVerificationURL(ctx) + "?user_code=" + userCode) + resp.SetExpiresIn(int64(time.Until(dar.GetSession().GetExpiresAt(fosite.UserCode)).Seconds())) + resp.SetInterval(int(d.Config.GetDeviceAuthTokenPollingInterval(ctx).Seconds())) + return nil +} diff --git a/handler/rfc8628/auth_handler_test.go b/handler/rfc8628/auth_handler_test.go new file mode 100644 index 000000000..c29112bf6 --- /dev/null +++ b/handler/rfc8628/auth_handler_test.go @@ -0,0 +1,79 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package rfc8628_test + +import ( + "context" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/ory/fosite" + . "github.com/ory/fosite/handler/rfc8628" + "github.com/ory/fosite/storage" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_HandleDeviceEndpointRequest(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + store := storage.NewMemoryStore() + handler := DeviceAuthHandler{ + Storage: store, + Strategy: &hmacshaStrategy, + Config: &fosite.Config{ + DeviceAndUserCodeLifespan: time.Minute * 10, + DeviceAuthTokenPollingInterval: time.Second * 5, + DeviceVerificationURL: "www.test.com", + AccessTokenLifespan: time.Hour, + RefreshTokenLifespan: time.Hour, + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + RefreshTokenScopes: []string{"offline"}, + }, + } + + for _, c := range []struct { + handler DeviceAuthHandler + req *fosite.DeviceRequest + description string + expectErr error + expect func(t *testing.T, req *fosite.DeviceRequest, resp *fosite.DeviceResponse) + }{ + { + handler: handler, + req: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + Audience: []string{"https://www.ory.sh/api"}, + }, + Session: &fosite.DefaultSession{}, + }, + }, + expect: func(t *testing.T, req *fosite.DeviceRequest, resp *fosite.DeviceResponse) { + assert.NotEmpty(t, resp.GetDeviceCode()) + assert.NotEmpty(t, resp.GetUserCode()) + assert.Equal(t, len(resp.GetUserCode()), 8) + assert.Contains(t, resp.GetDeviceCode(), "ory_dc_") + assert.Contains(t, resp.GetDeviceCode(), ".") + assert.Equal(t, resp.GetVerificationURI(), "www.test.com") + }, + }, + } { + t.Run("case="+c.description, func(t *testing.T) { + resp := fosite.NewDeviceResponse() + err := c.handler.HandleDeviceEndpointRequest(context.Background(), c.req, resp) + if c.expectErr != nil { + require.EqualError(t, err, c.expectErr.Error()) + } else { + require.NoError(t, err) + } + + if c.expect != nil { + c.expect(t, c.req, resp) + } + }) + } +} diff --git a/handler/rfc8628/storage.go b/handler/rfc8628/storage.go new file mode 100644 index 000000000..f356c6aaa --- /dev/null +++ b/handler/rfc8628/storage.go @@ -0,0 +1,52 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package rfc8628 + +import ( + "context" + + "github.com/ory/fosite" + "github.com/ory/fosite/handler/oauth2" +) + +type RFC8628CoreStorage interface { + DeviceCodeStorage + UserCodeStorage + oauth2.AccessTokenStorage + oauth2.RefreshTokenStorage +} + +type DeviceCodeStorage interface { + // CreateDeviceCodeSession stores the device request for a given device code. + CreateDeviceCodeSession(ctx context.Context, signature string, request fosite.Requester) (err error) + + // GetDeviceCodeSession hydrates the session based on the given device code and returns the device request. + // If the device code has been invalidated with `InvalidateDeviceCodeSession`, this + // method should return the ErrInvalidatedDeviceCode error. + // + // Make sure to also return the fosite.Requester value when returning the fosite.ErrInvalidatedDeviceCode error! + GetDeviceCodeSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) + + // InvalidateDeviceCodeSession is called when an device code is being used. The state of the user + // code should be set to invalid and consecutive requests to GetDeviceCodeSession should return the + // ErrInvalidatedDeviceCode error. + InvalidateDeviceCodeSession(ctx context.Context, signature string) (err error) +} + +type UserCodeStorage interface { + // CreateUserCodeSession stores the device request for a given user code. + CreateUserCodeSession(ctx context.Context, signature string, request fosite.Requester) (err error) + + // GetUserCodeSession hydrates the session based on the given user code and returns the device request. + // If the user code has been invalidated with `InvalidateUserCodeSession`, this + // method should return the ErrInvalidatedUserCode error. + // + // Make sure to also return the fosite.Requester value when returning the fosite.ErrInvalidatedUserCode error! + GetUserCodeSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) + + // InvalidateUserCodeSession is called when an user code is being used. The state of the user + // code should be set to invalid and consecutive requests to GetUserCodeSession should return the + // ErrInvalidatedUserCode error. + InvalidateUserCodeSession(ctx context.Context, signature string) (err error) +} diff --git a/handler/rfc8628/strategy.go b/handler/rfc8628/strategy.go new file mode 100644 index 000000000..3b0df7a71 --- /dev/null +++ b/handler/rfc8628/strategy.go @@ -0,0 +1,32 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package rfc8628 + +import ( + "context" + + "github.com/ory/fosite" +) + +type RFC8628CodeStrategy interface { + DeviceRateLimitStrategy + DeviceCodeStrategy + UserCodeStrategy +} + +type DeviceRateLimitStrategy interface { + ShouldRateLimit(ctx context.Context, code string) bool +} + +type DeviceCodeStrategy interface { + DeviceCodeSignature(ctx context.Context, code string) (signature string, err error) + GenerateDeviceCode(ctx context.Context) (code string, signature string, err error) + ValidateDeviceCode(ctx context.Context, r fosite.Requester, code string) (err error) +} + +type UserCodeStrategy interface { + UserCodeSignature(ctx context.Context, code string) (signature string, err error) + GenerateUserCode(ctx context.Context) (code string, signature string, err error) + ValidateUserCode(ctx context.Context, r fosite.Requester, code string) (err error) +} diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go new file mode 100644 index 000000000..a43fb82d5 --- /dev/null +++ b/handler/rfc8628/strategy_hmacsha.go @@ -0,0 +1,84 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package rfc8628 + +import ( + "context" + + "github.com/ory/x/randx" + "github.com/patrickmn/go-cache" + "golang.org/x/time/rate" + + "github.com/ory/fosite" + enigma "github.com/ory/fosite/token/hmac" +) + +type DefaultDeviceStrategy struct { + Enigma *enigma.HMACStrategy + RateLimiterCache *cache.Cache + Config interface { + fosite.DeviceProvider + fosite.DeviceAndUserCodeLifespanProvider + } +} + +var _ RFC8628CodeStrategy = (*DefaultDeviceStrategy)(nil) + +func (h *DefaultDeviceStrategy) GenerateUserCode(ctx context.Context) (token string, signature string, err error) { + seq, err := randx.RuneSequence(8, []rune(randx.AlphaUpper)) + if err != nil { + return "", "", err + } + userCode := string(seq) + signUserCode, signErr := h.UserCodeSignature(ctx, userCode) + if signErr != nil { + return "", "", err + } + return userCode, signUserCode, nil +} + +func (h *DefaultDeviceStrategy) UserCodeSignature(ctx context.Context, token string) (signature string, err error) { + return h.Enigma.Signature(token), nil +} + +func (h *DefaultDeviceStrategy) ValidateUserCode(ctx context.Context, r fosite.Requester, code string) (err error) { + // TODO + return nil +} + +func (h *DefaultDeviceStrategy) GenerateDeviceCode(ctx context.Context) (token string, signature string, err error) { + token, sig, err := h.Enigma.Generate(ctx) + if err != nil { + return "", "", err + } + + return "ory_dc_" + token, sig, nil +} + +func (h *DefaultDeviceStrategy) DeviceCodeSignature(ctx context.Context, token string) (signature string, err error) { + return h.Enigma.Signature(token), nil +} + +func (h *DefaultDeviceStrategy) ValidateDeviceCode(ctx context.Context, r fosite.Requester, code string) (err error) { + // TODO + return nil +} + +func (t *DefaultDeviceStrategy) ShouldRateLimit(context context.Context, code string) bool { + key := code + "_limiter" + + if x, found := t.RateLimiterCache.Get(key); found { + return !x.(*rate.Limiter).Allow() + } + + rateLimiter := rate.NewLimiter( + rate.Every( + t.Config.GetDeviceAuthTokenPollingInterval(context), + ), + 1, + ) + + t.RateLimiterCache.Set(key, rateLimiter, cache.DefaultExpiration) + return false +} diff --git a/handler/rfc8628/strategy_hmacsha_test.go b/handler/rfc8628/strategy_hmacsha_test.go new file mode 100644 index 000000000..f2835ea51 --- /dev/null +++ b/handler/rfc8628/strategy_hmacsha_test.go @@ -0,0 +1,129 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package rfc8628_test + +import ( + "context" + "fmt" + "regexp" + "strings" + "testing" + "time" + + "github.com/patrickmn/go-cache" + "github.com/stretchr/testify/assert" + + "github.com/ory/fosite" + . "github.com/ory/fosite/handler/rfc8628" + "github.com/ory/fosite/token/hmac" +) + +var hmacshaStrategy = DefaultDeviceStrategy{ + Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, + RateLimiterCache: cache.New(24*time.Minute, 2*24*time.Minute), + Config: &fosite.Config{ + AccessTokenLifespan: time.Minute * 24, + AuthorizeCodeLifespan: time.Minute * 24, + DeviceAndUserCodeLifespan: time.Minute * 24, + DeviceAuthTokenPollingInterval: 400 * time.Millisecond, + }, +} + +var hmacValidCase = fosite.Request{ + Client: &fosite.DefaultClient{ + Secret: []byte("foobarfoobarfoobarfoobar"), + }, + Session: &fosite.DefaultSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.UserCode: time.Now().UTC().Add(time.Hour), + fosite.DeviceCode: time.Now().UTC().Add(time.Hour), + }, + }, +} + +func TestHMACUserCode(t *testing.T) { + for k, c := range []struct { + r fosite.Request + pass bool + }{ + { + r: hmacValidCase, + pass: true, + }, + } { + t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + userCode, signature, err := hmacshaStrategy.GenerateUserCode(context.TODO()) + assert.NoError(t, err) + regex := regexp.MustCompile("[ABCDEFGHIJKLMNOPQRSTUVWXYZ]{8}") + assert.Equal(t, len(regex.FindString(userCode)), len(userCode)) + + err = hmacshaStrategy.ValidateUserCode(context.TODO(), &c.r, userCode) + if c.pass { + assert.NoError(t, err) + validate, _ := hmacshaStrategy.Enigma.GenerateHMACForString(context.TODO(), userCode) + assert.Equal(t, signature, validate) + testSign, err := hmacshaStrategy.UserCodeSignature(context.TODO(), userCode) + assert.NoError(t, err) + assert.Equal(t, testSign, signature) + } else { + assert.Error(t, err) + } + }) + } +} + +func TestHMACDeviceCode(t *testing.T) { + for k, c := range []struct { + r fosite.Request + pass bool + }{ + { + r: hmacValidCase, + pass: true, + }, + } { + t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + token, signature, err := hmacshaStrategy.GenerateDeviceCode(context.TODO()) + assert.NoError(t, err) + assert.Equal(t, strings.Split(token, ".")[1], signature) + assert.Contains(t, token, "ory_dc_") + + for k, token := range []string{ + token, + strings.TrimPrefix(token, "ory_dc_"), + } { + t.Run(fmt.Sprintf("prefix=%v", k == 0), func(t *testing.T) { + err = hmacshaStrategy.ValidateDeviceCode(context.TODO(), &c.r, token) + if c.pass { + assert.NoError(t, err) + validate := hmacshaStrategy.Enigma.Signature(token) + assert.Equal(t, signature, validate) + testSign, err := hmacshaStrategy.DeviceCodeSignature(context.TODO(), token) + assert.NoError(t, err) + assert.Equal(t, testSign, signature) + } else { + assert.Error(t, err) + } + }) + } + }) + } +} + +func TestRateLimit(t *testing.T) { + t.Run("ratelimit no-wait", func(t *testing.T) { + hmacshaStrategy.RateLimiterCache.Flush() + assert.False(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) + assert.False(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) + assert.True(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) + }) + + t.Run("ratelimit wait", func(t *testing.T) { + hmacshaStrategy.RateLimiterCache.Flush() + assert.False(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) + assert.False(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) + time.Sleep(500 * time.Millisecond) + assert.False(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) + }) +} From 9dc12f86ad110d36f8c2d3d1586df91e79e1cbf4 Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 6 Feb 2024 14:46:34 +0200 Subject: [PATCH 06/36] fix: add device flow handlers to compose --- compose/compose.go | 6 +++ compose/compose_rfc8628.go | 19 +++++++++ compose/compose_strategy.go | 15 +++++++ config.go | 15 +++++++ config_default.go | 34 ++++++++++++++++ fosite.go | 17 ++++++++ go.mod | 2 + go.sum | 4 ++ handler.go | 10 +++++ handler/rfc8628/strategy_hmacsha.go | 2 +- oauth2.go | 63 ++++++++++++++++++++++++++++- token/hmac/hmacsha.go | 20 +++++++++ token/hmac/hmacsha_test.go | 30 ++++++++++++++ 13 files changed, 235 insertions(+), 2 deletions(-) create mode 100644 compose/compose_rfc8628.go diff --git a/compose/compose.go b/compose/compose.go index c47b08d1e..94c7349ff 100644 --- a/compose/compose.go +++ b/compose/compose.go @@ -53,6 +53,9 @@ func Compose(config *fosite.Config, storage interface{}, strategy interface{}, f if ph, ok := res.(fosite.PushedAuthorizeEndpointHandler); ok { config.PushedAuthorizeEndpointHandlers.Append(ph) } + if dh, ok := res.(fosite.DeviceEndpointHandler); ok { + config.DeviceEndpointHandlers.Append(dh) + } } return f @@ -68,6 +71,7 @@ func ComposeAllEnabled(config *fosite.Config, storage interface{}, key interface storage, &CommonStrategy{ CoreStrategy: NewOAuth2HMACStrategy(config), + RFC8628CodeStrategy: NewDeviceStrategy(config), OpenIDConnectTokenStrategy: NewOpenIDConnectStrategy(keyGetter, config), Signer: &jwt.DefaultSigner{GetPrivateKey: keyGetter}, }, @@ -86,6 +90,8 @@ func ComposeAllEnabled(config *fosite.Config, storage interface{}, key interface OAuth2TokenIntrospectionFactory, OAuth2TokenRevocationFactory, + RFC8628DeviceFactory, + OAuth2PKCEFactory, PushedAuthorizeHandlerFactory, ) diff --git a/compose/compose_rfc8628.go b/compose/compose_rfc8628.go new file mode 100644 index 000000000..fb377606b --- /dev/null +++ b/compose/compose_rfc8628.go @@ -0,0 +1,19 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package compose + +import ( + "github.com/ory/fosite" + "github.com/ory/fosite/handler/rfc8628" +) + +// RFC8628DeviceFactory creates an OAuth2 device code grant ("Device Authorization Grant") handler and registers +// an user code, device code, access token and a refresh token validator. +func RFC8628DeviceFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} { + return &rfc8628.DeviceAuthHandler{ + Strategy: strategy.(rfc8628.RFC8628CodeStrategy), + Storage: storage.(rfc8628.RFC8628CoreStorage), + Config: config, + } +} diff --git a/compose/compose_strategy.go b/compose/compose_strategy.go index eb7d1ba16..af44f6bf6 100644 --- a/compose/compose_strategy.go +++ b/compose/compose_strategy.go @@ -9,12 +9,15 @@ import ( "github.com/ory/fosite" "github.com/ory/fosite/handler/oauth2" "github.com/ory/fosite/handler/openid" + "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 { oauth2.CoreStrategy + rfc8628.RFC8628CodeStrategy openid.OpenIDConnectTokenStrategy jwt.Signer } @@ -27,6 +30,7 @@ type HMACSHAStrategyConfigurator interface { fosite.GlobalSecretProvider fosite.RotatedGlobalSecretsProvider fosite.HMACHashingProvider + fosite.DeviceAndUserCodeLifespanProvider } func NewOAuth2HMACStrategy(config HMACSHAStrategyConfigurator) *oauth2.HMACSHAStrategy { @@ -47,3 +51,14 @@ func NewOpenIDConnectStrategy(keyGetter func(context.Context) (interface{}, erro Config: config, } } + +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, + } +} diff --git a/config.go b/config.go index 7b7f6c0d3..36351712b 100644 --- a/config.go +++ b/config.go @@ -46,6 +46,10 @@ type IDTokenLifespanProvider interface { GetIDTokenLifespan(ctx context.Context) time.Duration } +type DeviceAndUserCodeLifespanProvider interface { + GetDeviceAndUserCodeLifespan(ctx context.Context) time.Duration +} + // ScopeStrategyProvider returns the provider for configuring the scope strategy. type ScopeStrategyProvider interface { // GetScopeStrategy returns the scope strategy. @@ -76,6 +80,11 @@ type DisableRefreshTokenValidationProvider interface { GetDisableRefreshTokenValidation(ctx context.Context) bool } +type DeviceProvider interface { + GetDeviceVerificationURL(ctx context.Context) string + GetDeviceAuthTokenPollingInterval(ctx context.Context) time.Duration +} + // BCryptCostProvider returns the provider for configuring the BCrypt hash cost. type BCryptCostProvider interface { // GetBCryptCost returns the BCrypt hash cost. @@ -306,3 +315,9 @@ type PushedAuthorizeRequestConfigProvider interface { // must contain the PAR request_uri. EnforcePushedAuthorize(ctx context.Context) bool } + +// DeviceEndpointHandlersProvider returns the provider for setting up the Device handlers. +type DeviceEndpointHandlersProvider interface { + // GetDeviceEndpointHandlers returns the handlers. + GetDeviceEndpointHandlers(ctx context.Context) DeviceEndpointHandlers +} diff --git a/config_default.go b/config_default.go index 2c348a3a7..e08c9939b 100644 --- a/config_default.go +++ b/config_default.go @@ -84,6 +84,15 @@ type Config struct { // IDTokenIssuer sets the default issuer of the ID Token. IDTokenIssuer string + // Sets how long a device user/device code pair is valid for + DeviceAndUserCodeLifespan time.Duration + + // DeviceAuthTokenPollingInterval sets the interval that clients should check for device code grants + DeviceAuthTokenPollingInterval time.Duration + + // DeviceVerificationURL is the URL of the device verification endpoint, this is is included with the device code request responses + DeviceVerificationURL string + // HashCost sets the cost of the password hashing cost. Defaults to 12. HashCost int @@ -213,6 +222,9 @@ type Config struct { // PushedAuthorizeContextLifespan is the lifespan of the PAR context PushedAuthorizeContextLifespan time.Duration + // DeviceEndpointHandlers is a list of handlers that are called before the device endpoint is served. + DeviceEndpointHandlers DeviceEndpointHandlers + // IsPushedAuthorizeEnforced enforces pushed authorization request for /authorize IsPushedAuthorizeEnforced bool } @@ -245,6 +257,10 @@ func (c *Config) GetTokenIntrospectionHandlers(ctx context.Context) TokenIntrosp return c.TokenIntrospectionHandlers } +func (c *Config) GetDeviceEndpointHandlers(ctx context.Context) DeviceEndpointHandlers { + return c.DeviceEndpointHandlers +} + func (c *Config) GetRevocationHandlers(ctx context.Context) RevocationHandlers { return c.RevocationHandlers } @@ -396,6 +412,13 @@ func (c *Config) GetRefreshTokenLifespan(_ context.Context) time.Duration { return c.RefreshTokenLifespan } +func (c *Config) GetDeviceAndUserCodeLifespan(_ context.Context) time.Duration { + if c.DeviceAndUserCodeLifespan == 0 { + return time.Minute * 10 + } + return c.DeviceAndUserCodeLifespan +} + // GetBCryptCost returns the bcrypt cost factor. Defaults to 12. func (c *Config) GetBCryptCost(_ context.Context) int { if c.HashCost == 0 { @@ -499,3 +522,14 @@ func (c *Config) GetPushedAuthorizeContextLifespan(ctx context.Context) time.Dur func (c *Config) EnforcePushedAuthorize(ctx context.Context) bool { return c.IsPushedAuthorizeEnforced } + +func (c *Config) GetDeviceVerificationURL(ctx context.Context) string { + return c.DeviceVerificationURL +} + +func (c *Config) GetDeviceAuthTokenPollingInterval(ctx context.Context) time.Duration { + if c.DeviceAuthTokenPollingInterval == 0 { + return time.Second * 5 + } + return c.DeviceAuthTokenPollingInterval +} diff --git a/fosite.go b/fosite.go index 79620ad0e..d5610129f 100644 --- a/fosite.go +++ b/fosite.go @@ -82,6 +82,20 @@ func (a *PushedAuthorizeEndpointHandlers) Append(h PushedAuthorizeEndpointHandle *a = append(*a, h) } +// DeviceEndpointHandlers is a list of DeviceEndpointHandler +type DeviceEndpointHandlers []DeviceEndpointHandler + +// Append adds an DeviceEndpointHandlers to this list. Ignores duplicates based on reflect.TypeOf. +func (a *DeviceEndpointHandlers) Append(h DeviceEndpointHandler) { + for _, this := range *a { + if reflect.TypeOf(this) == reflect.TypeOf(h) { + return + } + } + + *a = append(*a, h) +} + var _ OAuth2Provider = (*Fosite)(nil) type Configurator interface { @@ -108,6 +122,7 @@ type Configurator interface { RefreshTokenLifespanProvider VerifiableCredentialsNonceLifespanProvider AuthorizeCodeLifespanProvider + DeviceAndUserCodeLifespanProvider TokenEntropyProvider RotatedGlobalSecretsProvider GlobalSecretProvider @@ -132,6 +147,8 @@ type Configurator interface { TokenIntrospectionHandlersProvider RevocationHandlersProvider UseLegacyErrorFormatProvider + DeviceEndpointHandlersProvider + DeviceProvider } func NewOAuth2Provider(s Storage, c Configurator) *Fosite { diff --git a/go.mod b/go.mod index 740836999..02f905274 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/ory/go-convenience v0.1.0 github.com/ory/x v0.0.677 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.9.0 github.com/tidwall/gjson v1.14.3 @@ -26,6 +27,7 @@ require ( golang.org/x/net v0.30.0 golang.org/x/oauth2 v0.23.0 golang.org/x/text v0.21.0 + golang.org/x/time v0.4.0 ) require ( diff --git a/go.sum b/go.sum index 0f0bd1cad..7dbcf5d11 100644 --- a/go.sum +++ b/go.sum @@ -334,6 +334,8 @@ github.com/ory/x v0.0.677 h1:ZulzE4EBhNBXNotWmGSmGsVNbgbZpIr4snMURRkski0= github.com/ory/x v0.0.677/go.mod h1:zJmnDtKje2FCP4EeFvRsKk94XXiqKCSGJMZcirAfhUs= github.com/parnurzeal/gorequest v0.2.15 h1:oPjDCsF5IkD4gUk6vIgsxYNaSgvAnIh1EJeROn3HdJU= github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -671,6 +673,8 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= diff --git a/handler.go b/handler.go index dd66a4de3..0d97a70e2 100644 --- a/handler.go +++ b/handler.go @@ -66,3 +66,13 @@ type PushedAuthorizeEndpointHandler interface { // the pushed authorize request, he must return nil and NOT modify session nor responder neither requester. HandlePushedAuthorizeEndpointRequest(ctx context.Context, requester AuthorizeRequester, responder PushedAuthorizeResponder) error } + +type DeviceEndpointHandler interface { + // HandleDeviceEndpointRequest handles a device authorize endpoint request. To extend the handler's capabilities, the http request + // is passed along, if further information retrieval is required. If the handler feels that he is not responsible for + // the device authorize request, he must return nil and NOT modify session nor responder neither requester. + // + // The following spec is a good example of what HandleDeviceUserRequest should do. + // * https://tools.ietf.org/html/rfc8628#section-3.2 + HandleDeviceEndpointRequest(ctx context.Context, requester DeviceRequester, responder DeviceResponder) error +} diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go index a43fb82d5..3e600a164 100644 --- a/handler/rfc8628/strategy_hmacsha.go +++ b/handler/rfc8628/strategy_hmacsha.go @@ -39,7 +39,7 @@ func (h *DefaultDeviceStrategy) GenerateUserCode(ctx context.Context) (token str } func (h *DefaultDeviceStrategy) UserCodeSignature(ctx context.Context, token string) (signature string, err error) { - return h.Enigma.Signature(token), nil + return h.Enigma.GenerateHMACForString(ctx, token) } func (h *DefaultDeviceStrategy) ValidateUserCode(ctx context.Context, r fosite.Requester, code string) (err error) { diff --git a/oauth2.go b/oauth2.go index 0e4700d5f..90d5f4f9a 100644 --- a/oauth2.go +++ b/oauth2.go @@ -23,6 +23,8 @@ const ( RefreshToken TokenType = "refresh_token" AuthorizeCode TokenType = "authorize_code" IDToken TokenType = "id_token" + UserCode TokenType = "user_code" + DeviceCode TokenType = "device_code" // PushedAuthorizeRequestContext represents the PAR context object PushedAuthorizeRequestContext TokenType = "par_context" @@ -31,7 +33,8 @@ const ( GrantTypeAuthorizationCode GrantType = "authorization_code" GrantTypePassword GrantType = "password" GrantTypeClientCredentials GrantType = "client_credentials" - GrantTypeJWTBearer GrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer" //nolint:gosec // this is not a hardcoded credential + GrantTypeJWTBearer GrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer" //nolint:gosec // this is not a hardcoded credential + GrantTypeDeviceCode GrantType = "urn:ietf:params:oauth:grant-type:device_code" //nolint:gosec // this is not a hardcoded credential BearerAccessToken string = "bearer" ) @@ -128,6 +131,34 @@ type OAuth2Provider interface { // https://tools.ietf.org/html/rfc6749#section-5.1 WriteAccessResponse(ctx context.Context, rw http.ResponseWriter, requester AccessRequester, responder AccessResponder) + // NewDeviceRequest validate the OAuth 2.0 Device Authorization Flow Request + // + // The following specs must be considered in any implementation of this method: + // * https://www.rfc-editor.org/rfc/rfc8628#section-3.1 (everything MUST be implemented) + // Parameters sent without a value MUST be treated as if they were + // omitted from the request. The authorization server MUST ignore + // unrecognized request parameters. Request and response parameters + // MUST NOT be included more than once. + NewDeviceRequest(ctx context.Context, req *http.Request) (DeviceRequester, error) + + // NewDeviceResponse persists the DeviceCodeSession and UserCodeSession in the store + // + // The following specs must be considered in any implementation of this method: + // * https://www.rfc-editor.org/rfc/rfc8628#section-3.2 (everything MUST be implemented) + // In response, the authorization server generates a unique device + // verification code and an end-user code that are valid for a limited + // time + NewDeviceResponse(ctx context.Context, requester DeviceRequester, session Session) (DeviceResponder, error) + + // WriteDeviceResponse return to the user both codes and + // some configuration informations in a JSON formated manner + // + // The following specs must be considered in any implementation of this method: + // * https://www.rfc-editor.org/rfc/rfc8628#section-3.2 (everything MUST be implemented) + // Response is a HTTP response body using the + // "application/json" format [RFC8259] with a 200 (OK) status code. + WriteDeviceResponse(ctx context.Context, rw http.ResponseWriter, requester DeviceRequester, responder DeviceResponder) + // NewRevocationRequest handles incoming token revocation requests and validates various parameters. // // The following specs must be considered in any implementation of this method: @@ -253,6 +284,11 @@ type AccessRequester interface { Requester } +// DeviceRequester is an device endpoint's request context. +type DeviceRequester interface { + Requester +} + // AuthorizeRequester is an authorize endpoint's request context. type AuthorizeRequester interface { // GetResponseTypes returns the requested response types @@ -365,3 +401,28 @@ type G11NContext interface { // GetLang returns the current language in the context GetLang() language.Tag } + +type DeviceResponder interface { + GetDeviceCode() string + SetDeviceCode(code string) + + GetUserCode() string + SetUserCode(code string) + + GetVerificationURI() string + SetVerificationURI(uri string) + + GetVerificationURIComplete() string + SetVerificationURIComplete(uri string) + + GetExpiresIn() int64 + SetExpiresIn(seconds int64) + + GetInterval() int + SetInterval(seconds int) + + // GetHeader returns the response's header + GetHeader() (header http.Header) + // AddHeader adds an header key value pair to the response + AddHeader(key, value string) +} diff --git a/token/hmac/hmacsha.go b/token/hmac/hmacsha.go index 695cff283..31237bd56 100644 --- a/token/hmac/hmacsha.go +++ b/token/hmac/hmacsha.go @@ -165,6 +165,26 @@ func (*HMACStrategy) Signature(token string) string { return split[1] } +func (c *HMACStrategy) GenerateHMACForString(ctx context.Context, text string) (string, error) { + var signingKey [32]byte + + secrets, err := c.Config.GetGlobalSecret(ctx) + if err != nil { + return "", err + } + + if len(secrets) < minimumSecretLength { + return "", errors.Errorf("secret for signing HMAC-SHA512/256 is expected to be 32 byte long, got %d byte", len(secrets)) + } + copy(signingKey[:], secrets) + + bytes := []byte(text) + hashBytes := c.generateHMAC(ctx, bytes, &signingKey) + + b64 := base64.RawURLEncoding.EncodeToString(hashBytes) + return b64, nil +} + func (c *HMACStrategy) generateHMAC(ctx context.Context, data []byte, key *[32]byte) []byte { hasher := c.Config.GetHMACHasher(ctx) if hasher == nil { diff --git a/token/hmac/hmacsha_test.go b/token/hmac/hmacsha_test.go index 0295fec98..c9d464df9 100644 --- a/token/hmac/hmacsha_test.go +++ b/token/hmac/hmacsha_test.go @@ -146,3 +146,33 @@ func TestCustomHMAC(t *testing.T) { require.NoError(t, sha512Hasher.Validate(ctx, token512)) require.ErrorIs(t, defaultHasher.Validate(ctx, token512), fosite.ErrTokenSignatureMismatch) } + +func TestGenerateFromString(t *testing.T) { + cg := HMACStrategy{Config: &fosite.Config{ + GlobalSecret: []byte("1234567890123456789012345678901234567890")}, + } + for _, c := range []struct { + text string + hash string + }{ + { + text: "", + hash: "-n7EqD-bXkY3yYMH-ctEAGV8XLkU7Y6Bo6pbyT1agGA", + }, + { + text: " ", + hash: "zXJvonHTNSOOGj_QKl4RpIX_zXgD2YfXUfwuDKaTTIg", + }, + { + text: "Test", + hash: "TMeEaHS-cDC2nijiesCNtsOyBqHHtzWqAcWvceQT50g", + }, + { + text: "AnotherTest1234", + hash: "zHYDOZGjzhVjx5r8RlBhpnJemX5JxEEBUjVT01n3IFM", + }, + } { + hash, _ := cg.GenerateHMACForString(context.Background(), c.text) + assert.Equal(t, c.hash, hash) + } +} From d7b70dd22ecaeb83b0a51d5dc7da71f4677b6da8 Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 6 Feb 2024 16:28:49 +0200 Subject: [PATCH 07/36] fix: update memory storage --- storage/memory.go | 96 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/storage/memory.go b/storage/memory.go index 82fc28c85..16afbf2de 100644 --- a/storage/memory.go +++ b/storage/memory.go @@ -42,12 +42,16 @@ type MemoryStore struct { IDSessions map[string]fosite.Requester AccessTokens map[string]fosite.Requester RefreshTokens map[string]StoreRefreshToken + DeviceCodes map[string]fosite.Requester + UserCodes map[string]fosite.Requester PKCES map[string]fosite.Requester Users map[string]MemoryUserRelation BlacklistedJTIs map[string]time.Time // In-memory request ID to token signatures AccessTokenRequestIDs map[string]string RefreshTokenRequestIDs map[string]string + DeviceCodesRequestIDs map[string]string + UserCodesRequestIDs map[string]string // Public keys to check signature in auth grant jwt assertion. IssuerPublicKeys map[string]IssuerPublicKeys PARSessions map[string]fosite.AuthorizeRequester @@ -57,11 +61,15 @@ type MemoryStore struct { idSessionsMutex sync.RWMutex accessTokensMutex sync.RWMutex refreshTokensMutex sync.RWMutex + userCodesMutex sync.RWMutex + deviceCodesMutex sync.RWMutex pkcesMutex sync.RWMutex usersMutex sync.RWMutex blacklistedJTIsMutex sync.RWMutex accessTokenRequestIDsMutex sync.RWMutex refreshTokenRequestIDsMutex sync.RWMutex + userCodesRequestIDsMutex sync.RWMutex + deviceCodesRequestIDsMutex sync.RWMutex issuerPublicKeysMutex sync.RWMutex parSessionsMutex sync.RWMutex } @@ -73,10 +81,14 @@ func NewMemoryStore() *MemoryStore { IDSessions: make(map[string]fosite.Requester), AccessTokens: make(map[string]fosite.Requester), RefreshTokens: make(map[string]StoreRefreshToken), + DeviceCodes: make(map[string]fosite.Requester), + UserCodes: make(map[string]fosite.Requester), PKCES: make(map[string]fosite.Requester), Users: make(map[string]MemoryUserRelation), AccessTokenRequestIDs: make(map[string]string), RefreshTokenRequestIDs: make(map[string]string), + DeviceCodesRequestIDs: make(map[string]string), + UserCodesRequestIDs: make(map[string]string), BlacklistedJTIs: make(map[string]time.Time), IssuerPublicKeys: make(map[string]IssuerPublicKeys), PARSessions: make(map[string]fosite.AuthorizeRequester), @@ -141,8 +153,12 @@ func NewExampleStore() *MemoryStore { AccessTokens: map[string]fosite.Requester{}, RefreshTokens: map[string]StoreRefreshToken{}, PKCES: map[string]fosite.Requester{}, + DeviceCodes: make(map[string]fosite.Requester), + UserCodes: make(map[string]fosite.Requester), AccessTokenRequestIDs: map[string]string{}, RefreshTokenRequestIDs: map[string]string{}, + DeviceCodesRequestIDs: make(map[string]string), + UserCodesRequestIDs: make(map[string]string), IssuerPublicKeys: map[string]IssuerPublicKeys{}, PARSessions: map[string]fosite.AuthorizeRequester{}, } @@ -502,3 +518,83 @@ func (s *MemoryStore) RotateRefreshToken(ctx context.Context, requestID string, } return s.RevokeAccessToken(ctx, requestID) } + +func (s *MemoryStore) CreateDeviceCodeSession(_ context.Context, signature string, req fosite.Requester) error { + // We first lock accessTokenRequestIDsMutex and then accessTokensMutex because this is the same order + // locking happens in RevokeAccessToken and using the same order prevents deadlocks. + s.deviceCodesRequestIDsMutex.Lock() + defer s.deviceCodesRequestIDsMutex.Unlock() + s.deviceCodesMutex.Lock() + defer s.deviceCodesMutex.Unlock() + + s.DeviceCodes[signature] = req + s.DeviceCodesRequestIDs[req.GetID()] = signature + return nil +} + +func (s *MemoryStore) UpdateDeviceCodeSession(_ context.Context, signature string, req fosite.Requester) error { + s.deviceCodesRequestIDsMutex.Lock() + defer s.deviceCodesRequestIDsMutex.Unlock() + s.deviceCodesMutex.Lock() + defer s.deviceCodesMutex.Unlock() + + // Only update if exist + if _, exists := s.DeviceCodes[signature]; exists { + s.DeviceCodes[signature] = req + s.DeviceCodesRequestIDs[req.GetID()] = signature + } + return nil +} + +func (s *MemoryStore) GetDeviceCodeSession(_ context.Context, signature string, _ fosite.Session) (fosite.Requester, error) { + s.deviceCodesMutex.RLock() + defer s.deviceCodesMutex.RUnlock() + + rel, ok := s.DeviceCodes[signature] + if !ok { + return nil, fosite.ErrNotFound + } + return rel, nil +} + +func (s *MemoryStore) InvalidateDeviceCodeSession(_ context.Context, code string) error { + s.deviceCodesRequestIDsMutex.Lock() + defer s.deviceCodesRequestIDsMutex.Unlock() + s.deviceCodesMutex.Lock() + defer s.deviceCodesMutex.Unlock() + + delete(s.DeviceCodes, code) + return nil +} + +func (s *MemoryStore) CreateUserCodeSession(_ context.Context, signature string, req fosite.Requester) error { + s.userCodesRequestIDsMutex.Lock() + defer s.userCodesRequestIDsMutex.Unlock() + s.userCodesMutex.Lock() + defer s.userCodesMutex.Unlock() + + s.UserCodes[signature] = req + s.UserCodesRequestIDs[req.GetID()] = signature + return nil +} + +func (s *MemoryStore) GetUserCodeSession(_ context.Context, signature string, _ fosite.Session) (fosite.Requester, error) { + s.userCodesMutex.RLock() + defer s.userCodesMutex.RUnlock() + + rel, ok := s.UserCodes[signature] + if !ok { + return nil, fosite.ErrNotFound + } + return rel, nil +} + +func (s *MemoryStore) InvalidateUserCodeSession(_ context.Context, code string) error { + s.userCodesRequestIDsMutex.Lock() + defer s.userCodesRequestIDsMutex.Unlock() + s.userCodesMutex.Lock() + defer s.userCodesMutex.Unlock() + + delete(s.UserCodes, code) + return nil +} From 09a8abed73e4892f708386f9c76187176ed9be19 Mon Sep 17 00:00:00 2001 From: Nikos Date: Wed, 7 Feb 2024 17:42:54 +0200 Subject: [PATCH 08/36] chore: update integration tests --- .../authorize_device_grant_request_test.go | 141 ++++++++++++++++++ integration/helper_endpoints_test.go | 40 +++++ integration/helper_setup_test.go | 9 +- 3 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 integration/authorize_device_grant_request_test.go diff --git a/integration/authorize_device_grant_request_test.go b/integration/authorize_device_grant_request_test.go new file mode 100644 index 000000000..2f548f147 --- /dev/null +++ b/integration/authorize_device_grant_request_test.go @@ -0,0 +1,141 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package integration_test + +import ( + "context" + "fmt" + "net/url" + "testing" + + "github.com/ory/fosite" + "github.com/ory/fosite/compose" + "github.com/ory/fosite/handler/oauth2" + "github.com/ory/fosite/handler/openid" + "github.com/ory/fosite/internal/gen" + "github.com/ory/fosite/token/jwt" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + goauth "golang.org/x/oauth2" +) + +func TestDeviceFlow(t *testing.T) { + for _, strategy := range []oauth2.AccessTokenStrategy{ + hmacStrategy, + } { + runDeviceFlowTest(t, strategy) + } +} + +func runDeviceFlowTest(t *testing.T, strategy interface{}) { + session := &defaultSession{ + DefaultSession: &openid.DefaultSession{ + Claims: &jwt.IDTokenClaims{ + Subject: "peter", + }, + Headers: &jwt.Headers{}, + Subject: "peter", + Username: "peteru", + }, + } + fc := new(fosite.Config) + fc.DeviceVerificationURL = "https://example.com/" + fc.RefreshTokenLifespan = -1 + fc.GlobalSecret = []byte("some-secret-thats-random-some-secret-thats-random-") + f := compose.ComposeAllEnabled(fc, fositeStore, gen.MustRSAKey()) + ts := mockServer(t, f, session) + defer ts.Close() + + oauthClient := &goauth.Config{ + ClientID: "device-client", + ClientSecret: "foobar", + Endpoint: goauth.Endpoint{ + TokenURL: ts.URL + tokenRelativePath, + DeviceAuthURL: ts.URL + deviceAuthRelativePath, + }, + } + for k, c := range []struct { + description string + setup func() + err bool + client fosite.Client + check func(t *testing.T, token *goauth.DeviceAuthResponse, err error) + params url.Values + }{ + { + description: "should fail with invalid_grant", + setup: func() { + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"authorization_code"} + }, + err: true, + check: func(t *testing.T, token *goauth.DeviceAuthResponse, err error) { + assert.ErrorContains(t, err, "invalid_grant") + }, + }, + { + description: "should fail with invalid_scope", + setup: func() { + oauthClient.Scopes = []string{"openid"} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).Scopes = []string{"profile"} + }, + err: true, + check: func(t *testing.T, token *goauth.DeviceAuthResponse, err error) { + assert.ErrorContains(t, err, "invalid_scope") + }, + }, + { + description: "should fail with invalid_client", + setup: func() { + oauthClient.ClientID = "123" + }, + err: true, + check: func(t *testing.T, token *goauth.DeviceAuthResponse, err error) { + assert.ErrorContains(t, err, "invalid_client") + }, + }, + { + description: "should pass", + setup: func() {}, + err: false, + }, + } { + t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + // Restore client + fositeStore.Clients["device-client"] = &fosite.DefaultClient{ + ID: "device-client", + Secret: []byte(`$2a$10$IxMdI6d.LIRZPpSfEwNoeu4rY3FhDREsxFJXikcgdRRAStxUlsuEO`), // = "foobar" + GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, + Scopes: []string{"fosite", "offline", "openid"}, + Audience: []string{tokenURL}, + Public: true, + } + oauthClient = &goauth.Config{ + ClientID: "device-client", + ClientSecret: "foobar", + Endpoint: goauth.Endpoint{ + TokenURL: ts.URL + tokenRelativePath, + DeviceAuthURL: ts.URL + deviceAuthRelativePath, + }, + } + + c.setup() + + resp, err := oauthClient.DeviceAuth(context.Background()) + require.Equal(t, c.err, err != nil, "(%d) %s\n%s\n%s", k, c.description, c.err, err) + if !c.err { + assert.NotEmpty(t, resp.DeviceCode) + assert.NotEmpty(t, resp.UserCode) + assert.NotEmpty(t, resp.Interval) + assert.NotEmpty(t, resp.VerificationURI) + assert.NotEmpty(t, resp.VerificationURIComplete) + } + + if c.check != nil { + c.check(t, resp, err) + } + + t.Logf("Passed test case %d", k) + }) + } +} diff --git a/integration/helper_endpoints_test.go b/integration/helper_endpoints_test.go index 09e3ea2b2..4f6ef0f56 100644 --- a/integration/helper_endpoints_test.go +++ b/integration/helper_endpoints_test.go @@ -175,3 +175,43 @@ func pushedAuthorizeRequestHandler(t *testing.T, oauth2 fosite.OAuth2Provider, s oauth2.WritePushedAuthorizeResponse(ctx, rw, ar, response) } } + +func deviceAuthorizationEndpointHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session fosite.Session) func(rw http.ResponseWriter, req *http.Request) { + return func(rw http.ResponseWriter, req *http.Request) { + ctx := fosite.NewContext() + + r, err := oauth2.NewDeviceRequest(ctx, req) + if err != nil { + t.Logf("Device auth request failed because: %+v", err) + t.Logf("Request: %+v", r) + oauth2.WriteAccessError(ctx, rw, r, err) + return + } + + if r.GetRequestedScopes().Has("fosite") { + r.GrantScope("fosite") + } + + if r.GetRequestedScopes().Has("offline") { + r.GrantScope("offline") + } + + if r.GetRequestedScopes().Has("openid") { + r.GrantScope("openid") + } + + for _, a := range r.GetRequestedAudience() { + r.GrantAudience(a) + } + + response, err := oauth2.NewDeviceResponse(ctx, r, session) + if err != nil { + t.Logf("Device auth response failed because: %+v", err) + t.Logf("Request: %+v", r) + oauth2.WriteAccessError(ctx, rw, r, err) + return + } + + oauth2.WriteDeviceResponse(ctx, rw, r, response) + } +} diff --git a/integration/helper_setup_test.go b/integration/helper_setup_test.go index 22e9627d0..0c6c0c971 100644 --- a/integration/helper_setup_test.go +++ b/integration/helper_setup_test.go @@ -41,6 +41,8 @@ const ( tokenURL = "https://www.ory.sh/api" tokenRelativePath = "/token" + + deviceAuthRelativePath = "/device/auth" ) var ( @@ -55,7 +57,7 @@ var fositeStore = &storage.MemoryStore{ Secret: []byte(`$2a$10$IxMdI6d.LIRZPpSfEwNoeu4rY3FhDREsxFJXikcgdRRAStxUlsuEO`), // = "foobar" RedirectURIs: []string{"http://localhost:3846/callback"}, ResponseTypes: []string{"id_token", "code", "token", "token code", "id_token code", "token id_token", "token code id_token"}, - GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, + GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials", "urn:ietf:params:oauth:grant-type:device_code"}, Scopes: []string{"fosite", "offline", "openid"}, Audience: []string{tokenURL}, }, @@ -113,6 +115,10 @@ var fositeStore = &storage.MemoryStore{ AccessTokenRequestIDs: map[string]string{}, RefreshTokenRequestIDs: map[string]string{}, PARSessions: map[string]fosite.AuthorizeRequester{}, + DeviceCodes: map[string]fosite.Requester{}, + UserCodes: map[string]fosite.Requester{}, + DeviceCodesRequestIDs: map[string]string{}, + UserCodesRequestIDs: map[string]string{}, } type defaultSession struct { @@ -204,6 +210,7 @@ func mockServer(t *testing.T, f fosite.OAuth2Provider, session fosite.Session) * router.HandleFunc("/introspect", tokenIntrospectionHandler(t, f, session)) router.HandleFunc("/revoke", tokenRevocationHandler(t, f, session)) router.HandleFunc("/par", pushedAuthorizeRequestHandler(t, f, session)) + router.HandleFunc(deviceAuthRelativePath, deviceAuthorizationEndpointHandler(t, f, session)) ts := httptest.NewServer(router) return ts From 9618c06c7fa84498e66f29e2b83b419be0a5fa99 Mon Sep 17 00:00:00 2001 From: Nikos Date: Fri, 9 Feb 2024 14:31:09 +0200 Subject: [PATCH 09/36] fix: review comments --- compose/compose_rfc8628.go | 4 +- compose/compose_strategy.go | 1 + config.go | 2 + config_default.go | 15 +- device_request.go | 3 +- device_request_handler.go | 35 +--- device_request_handler_test.go | 157 +++++++++--------- device_request_test.go | 2 +- device_response.go | 53 +++--- device_response_test.go | 2 +- device_response_writer.go | 3 +- device_write.go | 19 +-- device_write_test.go | 2 +- handler.go | 1 + handler/rfc8628/auth_handler.go | 10 +- handler/rfc8628/auth_handler_test.go | 62 +++---- handler/rfc8628/storage.go | 5 +- handler/rfc8628/strategy.go | 6 +- handler/rfc8628/strategy_hmacsha.go | 22 ++- handler/rfc8628/strategy_hmacsha_test.go | 2 +- .../authorize_device_grant_request_test.go | 4 +- oauth2.go | 13 ++ storage/memory.go | 7 + token/hmac/hmacsha.go | 1 + 24 files changed, 221 insertions(+), 210 deletions(-) diff --git a/compose/compose_rfc8628.go b/compose/compose_rfc8628.go index fb377606b..5217aeb7f 100644 --- a/compose/compose_rfc8628.go +++ b/compose/compose_rfc8628.go @@ -1,6 +1,8 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 +// Package compose provides various objects which can be used to +// instantiate OAuth2Providers with different functionality. package compose import ( diff --git a/compose/compose_strategy.go b/compose/compose_strategy.go index af44f6bf6..e0d700e5b 100644 --- a/compose/compose_strategy.go +++ b/compose/compose_strategy.go @@ -52,6 +52,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}, diff --git a/config.go b/config.go index 36351712b..24c4151c4 100644 --- a/config.go +++ b/config.go @@ -46,6 +46,7 @@ type IDTokenLifespanProvider interface { GetIDTokenLifespan(ctx context.Context) time.Duration } +// DeviceAndUserCodeLifespanProvider returns the provider for configuring the device and user code lifespan type DeviceAndUserCodeLifespanProvider interface { GetDeviceAndUserCodeLifespan(ctx context.Context) time.Duration } @@ -80,6 +81,7 @@ type DisableRefreshTokenValidationProvider interface { GetDisableRefreshTokenValidation(ctx context.Context) bool } +// DeviceProvider returns the provider for configuring the device flow type DeviceProvider interface { GetDeviceVerificationURL(ctx context.Context) string GetDeviceAuthTokenPollingInterval(ctx context.Context) time.Duration diff --git a/config_default.go b/config_default.go index e08c9939b..a73154f08 100644 --- a/config_default.go +++ b/config_default.go @@ -18,8 +18,10 @@ import ( ) const ( - defaultPARPrefix = "urn:ietf:params:oauth:request_uri:" - defaultPARContextLifetime = 5 * time.Minute + defaultPARPrefix = "urn:ietf:params:oauth:request_uri:" + defaultPARContextLifetime = 5 * time.Minute + defaultDeviceAndUserCodeLifespan = 10 * time.Minute + defaultAuthTokenPollingInterval = 5 * time.Second ) var ( @@ -257,6 +259,7 @@ func (c *Config) GetTokenIntrospectionHandlers(ctx context.Context) TokenIntrosp return c.TokenIntrospectionHandlers } +// GetDeviceEndpointHandlers return the Device Endpoint Handlers func (c *Config) GetDeviceEndpointHandlers(ctx context.Context) DeviceEndpointHandlers { return c.DeviceEndpointHandlers } @@ -412,9 +415,11 @@ func (c *Config) GetRefreshTokenLifespan(_ context.Context) time.Duration { return c.RefreshTokenLifespan } +// GetDeviceAndUserCodeLifespan returns how long the device and user codes should be valid. +// Defaults to 10 minutes func (c *Config) GetDeviceAndUserCodeLifespan(_ context.Context) time.Duration { if c.DeviceAndUserCodeLifespan == 0 { - return time.Minute * 10 + return defaultDeviceAndUserCodeLifespan } return c.DeviceAndUserCodeLifespan } @@ -523,13 +528,15 @@ func (c *Config) EnforcePushedAuthorize(ctx context.Context) bool { return c.IsPushedAuthorizeEnforced } +// GetDeviceVerificationURL returns the device verification URL func (c *Config) GetDeviceVerificationURL(ctx context.Context) string { return c.DeviceVerificationURL } +// GetDeviceAuthTokenPollingInterval returns configured device token endpoint polling interval func (c *Config) GetDeviceAuthTokenPollingInterval(ctx context.Context) time.Duration { if c.DeviceAuthTokenPollingInterval == 0 { - return time.Second * 5 + return defaultAuthTokenPollingInterval } return c.DeviceAuthTokenPollingInterval } diff --git a/device_request.go b/device_request.go index 3c2df0636..0b243b015 100644 --- a/device_request.go +++ b/device_request.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite @@ -8,6 +8,7 @@ type DeviceRequest struct { Request } +// NewDeviceRequest returns a new device request func NewDeviceRequest() *DeviceRequest { return &DeviceRequest{ Request: *NewRequest(), diff --git a/device_request_handler.go b/device_request_handler.go index 20d3b1e26..30d548257 100644 --- a/device_request_handler.go +++ b/device_request_handler.go @@ -1,27 +1,6 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 -/* - * Copyright © 2015-2021 Aeneas Rekkas - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * @author Aeneas Rekkas - * @copyright 2015-2021 Aeneas Rekkas - * @license Apache-2.0 - * - */ - package fosite import ( @@ -29,12 +8,14 @@ import ( "net/http" "strings" - "github.com/ory/fosite/i18n" "github.com/ory/x/errorsx" "github.com/ory/x/otelx" "go.opentelemetry.io/otel/trace" + + "github.com/ory/fosite/i18n" ) +// NewDeviceRequest parses an http Request returns a Device request func (f *Fosite) NewDeviceRequest(ctx context.Context, r *http.Request) (_ DeviceRequester, err error) { ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("github.com/ory/fosite").Start(ctx, "Fosite.NewAccessRequest") defer otelx.End(span, &err) @@ -42,11 +23,13 @@ func (f *Fosite) NewDeviceRequest(ctx context.Context, r *http.Request) (_ Devic request := NewDeviceRequest() request.Lang = i18n.GetLangFromRequest(f.Config.GetMessageCatalog(ctx), r) - if r.Method != "POST" { + if r.Method != http.MethodPost { return request, errorsx.WithStack(ErrInvalidRequest.WithHintf("HTTP method is '%s', expected 'POST'.", r.Method)) - } else if err := r.ParseForm(); err != nil { + } + if err := r.ParseForm(); err != nil { return nil, errorsx.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithWrap(err).WithDebug(err.Error())) - } else if len(r.PostForm) == 0 { + } + if len(r.PostForm) == 0 { return request, errorsx.WithStack(ErrInvalidRequest.WithHint("The POST body can not be empty.")) } request.Form = r.PostForm diff --git a/device_request_handler_test.go b/device_request_handler_test.go index d6dceeffa..0b5b38e6d 100644 --- a/device_request_handler_test.go +++ b/device_request_handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test @@ -33,94 +33,87 @@ func TestNewDeviceRequestWithPublicClient(t *testing.T) { expectedError error mock func() expect DeviceRequester - }{ - /* invalid Method */ - { - expectedError: ErrInvalidRequest, - method: "GET", - mock: func() {}, + description string + }{{ + description: "invalid method", + expectedError: ErrInvalidRequest, + method: "GET", + mock: func() {}, + }, { + description: "empty request", + expectedError: ErrInvalidRequest, + method: "POST", + mock: func() {}, + }, { + description: "invalid client", + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"foo bar"}, }, - /* empty request */ - { - expectedError: ErrInvalidRequest, - method: "POST", - mock: func() {}, + expectedError: ErrInvalidClient, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(nil, errors.New("")) }, - /* invalid client */ - { - form: url.Values{ - "client_id": {"client_id"}, - "scope": {"foo bar"}, - }, - expectedError: ErrInvalidClient, - method: "POST", - mock: func() { - store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(nil, errors.New("")) - }, + }, { + description: "fails because scope not allowed", + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"17 42 foo"}, }, - /* fails because scope not allowed */ - { - form: url.Values{ - "client_id": {"client_id"}, - "scope": {"17 42 foo"}, - }, - method: "POST", - mock: func() { - store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) - client.Public = true - client.Scopes = []string{"17", "42"} - client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} - }, - expectedError: ErrInvalidScope, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) + client.Public = true + client.Scopes = []string{"17", "42"} + client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} }, - /* fails because scope not allowed */ - { - form: url.Values{ - "client_id": {"client_id"}, - "scope": {"17 42"}, - "audience": {"aud"}, - }, - method: "POST", - mock: func() { - store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) - client.Public = true - client.Scopes = []string{"17", "42"} - client.Audience = []string{"aud2"} - client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} - }, - expectedError: ErrInvalidRequest, + expectedError: ErrInvalidScope, + }, { + description: "fails because audience not allowed", + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"17 42"}, + "audience": {"aud"}, }, - /* should fail because doesn't have proper grant */ - { - form: url.Values{ - "client_id": {"client_id"}, - "scope": {"17 42"}, - }, - method: "POST", - mock: func() { - store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) - client.Public = true - client.Scopes = []string{"17", "42"} - client.GrantTypes = []string{"authorization_code"} - }, - expectedError: ErrInvalidGrant, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) + client.Public = true + client.Scopes = []string{"17", "42"} + client.Audience = []string{"aud2"} + client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} }, - /* success case */ - { - form: url.Values{ - "client_id": {"client_id"}, - "scope": {"17 42"}, - }, - method: "POST", - mock: func() { - store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) - client.Public = true - client.Scopes = []string{"17", "42"} - client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} - }, + expectedError: ErrInvalidRequest, + }, { + description: "fails because it doesn't have the proper grant", + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"17 42"}, }, - } { - t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) + client.Public = true + client.Scopes = []string{"17", "42"} + client.GrantTypes = []string{"authorization_code"} + }, + expectedError: ErrInvalidGrant, + }, { + description: "success", + form: url.Values{ + "client_id": {"client_id"}, + "scope": {"17 42"}, + }, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) + client.Public = true + client.Scopes = []string{"17", "42"} + client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + }, + }} { + t.Run(fmt.Sprintf("case=%d description=%s", k, c.description), func(t *testing.T) { c.mock() r := &http.Request{ Header: c.header, diff --git a/device_request_test.go b/device_request_test.go index 571e83ba8..7e67c0529 100644 --- a/device_request_test.go +++ b/device_request_test.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/device_response.go b/device_response.go index a70ee25fe..5f8c95ff8 100644 --- a/device_response.go +++ b/device_response.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite @@ -7,7 +7,8 @@ import ( "net/http" ) -type deviceResponse struct { +// DeviceResponse represents the device authorization response +type DeviceResponse struct { Header http.Header DeviceCode string `json:"device_code"` UserCode string `json:"user_code"` @@ -17,71 +18,77 @@ type deviceResponse struct { Interval int `json:"interval,omitempty"` } -type DeviceResponse struct { - deviceResponse -} - +// NewDeviceResponse returns a new DeviceResponse func NewDeviceResponse() *DeviceResponse { return &DeviceResponse{} } +// GetDeviceCode returns the response's device_code func (d *DeviceResponse) GetDeviceCode() string { - return d.deviceResponse.DeviceCode + return d.DeviceCode } -// SetDeviceCode returns the response's user code +// SetDeviceCode sets the response's device_code func (d *DeviceResponse) SetDeviceCode(code string) { - d.deviceResponse.DeviceCode = code + d.DeviceCode = code } +// GetUserCode returns the response's user_code func (d *DeviceResponse) GetUserCode() string { - return d.deviceResponse.UserCode + return d.UserCode } +// SetUserCode sets the response's user_code func (d *DeviceResponse) SetUserCode(code string) { - d.deviceResponse.UserCode = code + d.UserCode = code } // GetVerificationURI returns the response's verification uri func (d *DeviceResponse) GetVerificationURI() string { - return d.deviceResponse.VerificationURI + return d.VerificationURI } +// SetVerificationURI sets the response's verification uri func (d *DeviceResponse) SetVerificationURI(uri string) { - d.deviceResponse.VerificationURI = uri + d.VerificationURI = uri } // GetVerificationURIComplete returns the response's complete verification uri if set func (d *DeviceResponse) GetVerificationURIComplete() string { - return d.deviceResponse.VerificationURIComplete + return d.VerificationURIComplete } +// SetVerificationURIComplete sets the response's complete verification uri func (d *DeviceResponse) SetVerificationURIComplete(uri string) { - d.deviceResponse.VerificationURIComplete = uri + d.VerificationURIComplete = uri } // GetExpiresIn returns the response's device code and user code lifetime in seconds if set func (d *DeviceResponse) GetExpiresIn() int64 { - return d.deviceResponse.ExpiresIn + return d.ExpiresIn } +// SetExpiresIn sets the response's device code and user code lifetime in seconds func (d *DeviceResponse) SetExpiresIn(seconds int64) { - d.deviceResponse.ExpiresIn = seconds + d.ExpiresIn = seconds } // GetInterval returns the response's polling interval if set func (d *DeviceResponse) GetInterval() int { - return d.deviceResponse.Interval + return d.Interval } +// SetInterval sets the response's polling interval func (d *DeviceResponse) SetInterval(seconds int) { - d.deviceResponse.Interval = seconds + d.Interval = seconds } -func (a *DeviceResponse) GetHeader() http.Header { - return a.deviceResponse.Header +// GetHeader returns the response's headers +func (d *DeviceResponse) GetHeader() http.Header { + return d.Header } -func (a *DeviceResponse) AddHeader(key, value string) { - a.deviceResponse.Header.Add(key, value) +// AddHeader adds a header to the response +func (d *DeviceResponse) AddHeader(key, value string) { + d.Header.Add(key, value) } diff --git a/device_response_test.go b/device_response_test.go index 366899a1b..a4e95e168 100644 --- a/device_response_test.go +++ b/device_response_test.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/device_response_writer.go b/device_response_writer.go index 82c5d7c93..2cc17d096 100644 --- a/device_response_writer.go +++ b/device_response_writer.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite @@ -7,6 +7,7 @@ import ( "context" ) +// NewDeviceResponse returns a new DeviceResponder func (f *Fosite) NewDeviceResponse(ctx context.Context, r DeviceRequester, session Session) (DeviceResponder, error) { var resp = &DeviceResponse{} diff --git a/device_write.go b/device_write.go index f21184dbe..d3337ab29 100644 --- a/device_write.go +++ b/device_write.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite @@ -9,8 +9,7 @@ import ( "net/http" ) -// TODO: Do documentation - +// WriteDeviceResponse writes the device response func (f *Fosite) WriteDeviceResponse(ctx context.Context, rw http.ResponseWriter, requester DeviceRequester, responder DeviceResponder) { // Set custom headers, e.g. "X-MySuperCoolCustomHeader" or "X-DONT-CACHE-ME"... wh := rw.Header() @@ -24,14 +23,12 @@ func (f *Fosite) WriteDeviceResponse(ctx context.Context, rw http.ResponseWriter rw.Header().Set("Pragma", "no-cache") deviceResponse := &DeviceResponse{ - deviceResponse{ - DeviceCode: responder.GetDeviceCode(), - UserCode: responder.GetUserCode(), - VerificationURI: responder.GetVerificationURI(), - VerificationURIComplete: responder.GetVerificationURIComplete(), - ExpiresIn: responder.GetExpiresIn(), - Interval: responder.GetInterval(), - }, + DeviceCode: responder.GetDeviceCode(), + UserCode: responder.GetUserCode(), + VerificationURI: responder.GetVerificationURI(), + VerificationURIComplete: responder.GetVerificationURIComplete(), + ExpiresIn: responder.GetExpiresIn(), + Interval: responder.GetInterval(), } r, err := json.Marshal(deviceResponse) diff --git a/device_write_test.go b/device_write_test.go index 961d516c7..fc8ade099 100644 --- a/device_write_test.go +++ b/device_write_test.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/handler.go b/handler.go index 0d97a70e2..163f4af6f 100644 --- a/handler.go +++ b/handler.go @@ -67,6 +67,7 @@ type PushedAuthorizeEndpointHandler interface { HandlePushedAuthorizeEndpointRequest(ctx context.Context, requester AuthorizeRequester, responder PushedAuthorizeResponder) error } +// DeviceEndpointHandler is the interface that handles https://tools.ietf.org/html/rfc8628 type DeviceEndpointHandler interface { // HandleDeviceEndpointRequest handles a device authorize endpoint request. To extend the handler's capabilities, the http request // is passed along, if further information retrieval is required. If the handler feels that he is not responsible for diff --git a/handler/rfc8628/auth_handler.go b/handler/rfc8628/auth_handler.go index 9072cbe46..6d97da3aa 100644 --- a/handler/rfc8628/auth_handler.go +++ b/handler/rfc8628/auth_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628 @@ -7,10 +7,13 @@ import ( "context" "time" - "github.com/ory/fosite" "github.com/ory/x/errorsx" + + "github.com/ory/fosite" ) +// DeviceAuthHandler is a response handler for the Device Authorisation Grant as +// defined in https://tools.ietf.org/html/rfc8628#section-3.1 type DeviceAuthHandler struct { Storage RFC8628CoreStorage Strategy RFC8628CodeStrategy @@ -20,8 +23,7 @@ type DeviceAuthHandler struct { } } -// DeviceAuthorizationHandler is a response handler for the Device Authorisation Grant as -// defined in https://tools.ietf.org/html/rfc8628#section-3.1 +// HandleDeviceEndpointRequest implements https://tools.ietf.org/html/rfc8628#section-3.1 func (d *DeviceAuthHandler) HandleDeviceEndpointRequest(ctx context.Context, dar fosite.DeviceRequester, resp fosite.DeviceResponder) error { deviceCode, deviceCodeSignature, err := d.Strategy.GenerateDeviceCode(ctx) if err != nil { diff --git a/handler/rfc8628/auth_handler_test.go b/handler/rfc8628/auth_handler_test.go index c29112bf6..220a03475 100644 --- a/handler/rfc8628/auth_handler_test.go +++ b/handler/rfc8628/auth_handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628_test @@ -9,18 +9,19 @@ import ( "time" "github.com/golang/mock/gomock" - "github.com/ory/fosite" - . "github.com/ory/fosite/handler/rfc8628" "github.com/ory/fosite/storage" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/ory/fosite" + "github.com/ory/fosite/handler/rfc8628" ) func Test_HandleDeviceEndpointRequest(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() store := storage.NewMemoryStore() - handler := DeviceAuthHandler{ + handler := rfc8628.DeviceAuthHandler{ Storage: store, Strategy: &hmacshaStrategy, Config: &fosite.Config{ @@ -35,45 +36,22 @@ func Test_HandleDeviceEndpointRequest(t *testing.T) { }, } - for _, c := range []struct { - handler DeviceAuthHandler - req *fosite.DeviceRequest - description string - expectErr error - expect func(t *testing.T, req *fosite.DeviceRequest, resp *fosite.DeviceResponse) - }{ - { - handler: handler, - req: &fosite.DeviceRequest{ - Request: fosite.Request{ - Client: &fosite.DefaultClient{ - Audience: []string{"https://www.ory.sh/api"}, - }, - Session: &fosite.DefaultSession{}, - }, - }, - expect: func(t *testing.T, req *fosite.DeviceRequest, resp *fosite.DeviceResponse) { - assert.NotEmpty(t, resp.GetDeviceCode()) - assert.NotEmpty(t, resp.GetUserCode()) - assert.Equal(t, len(resp.GetUserCode()), 8) - assert.Contains(t, resp.GetDeviceCode(), "ory_dc_") - assert.Contains(t, resp.GetDeviceCode(), ".") - assert.Equal(t, resp.GetVerificationURI(), "www.test.com") + req := &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + Audience: []string{"https://www.ory.sh/api"}, }, + Session: &fosite.DefaultSession{}, }, - } { - t.Run("case="+c.description, func(t *testing.T) { - resp := fosite.NewDeviceResponse() - err := c.handler.HandleDeviceEndpointRequest(context.Background(), c.req, resp) - if c.expectErr != nil { - require.EqualError(t, err, c.expectErr.Error()) - } else { - require.NoError(t, err) - } - - if c.expect != nil { - c.expect(t, c.req, resp) - } - }) } + resp := fosite.NewDeviceResponse() + err := handler.HandleDeviceEndpointRequest(context.Background(), req, resp) + + require.NoError(t, err) + assert.NotEmpty(t, resp.GetDeviceCode()) + assert.NotEmpty(t, resp.GetUserCode()) + assert.Equal(t, len(resp.GetUserCode()), 8) + assert.Contains(t, resp.GetDeviceCode(), "ory_dc_") + assert.Contains(t, resp.GetDeviceCode(), ".") + assert.Equal(t, resp.GetVerificationURI(), "www.test.com") } diff --git a/handler/rfc8628/storage.go b/handler/rfc8628/storage.go index f356c6aaa..17571ab18 100644 --- a/handler/rfc8628/storage.go +++ b/handler/rfc8628/storage.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628 @@ -10,6 +10,7 @@ import ( "github.com/ory/fosite/handler/oauth2" ) +// RFC8628CoreStorage is the storage needed for the DeviceAuthHandler type RFC8628CoreStorage interface { DeviceCodeStorage UserCodeStorage @@ -17,6 +18,7 @@ type RFC8628CoreStorage interface { oauth2.RefreshTokenStorage } +// DeviceCodeStorage handles the device_code storage type DeviceCodeStorage interface { // CreateDeviceCodeSession stores the device request for a given device code. CreateDeviceCodeSession(ctx context.Context, signature string, request fosite.Requester) (err error) @@ -34,6 +36,7 @@ type DeviceCodeStorage interface { InvalidateDeviceCodeSession(ctx context.Context, signature string) (err error) } +// UserCodeStorage handles the user_code storage type UserCodeStorage interface { // CreateUserCodeSession stores the device request for a given user code. CreateUserCodeSession(ctx context.Context, signature string, request fosite.Requester) (err error) diff --git a/handler/rfc8628/strategy.go b/handler/rfc8628/strategy.go index 3b0df7a71..33900a20c 100644 --- a/handler/rfc8628/strategy.go +++ b/handler/rfc8628/strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628 @@ -9,22 +9,26 @@ import ( "github.com/ory/fosite" ) +// RFC8628CodeStrategy is the code strategy needed for the DeviceAuthHandler type RFC8628CodeStrategy interface { DeviceRateLimitStrategy DeviceCodeStrategy UserCodeStrategy } +// DeviceRateLimitStrategy handles the rate limiting strategy type DeviceRateLimitStrategy interface { ShouldRateLimit(ctx context.Context, code string) bool } +// DeviceCodeStrategy handles the device_code strategy type DeviceCodeStrategy interface { DeviceCodeSignature(ctx context.Context, code string) (signature string, err error) GenerateDeviceCode(ctx context.Context) (code string, signature string, err error) ValidateDeviceCode(ctx context.Context, r fosite.Requester, code string) (err error) } +// UserCodeStrategy handles the user_code strategy type UserCodeStrategy interface { UserCodeSignature(ctx context.Context, code string) (signature string, err error) GenerateUserCode(ctx context.Context) (code string, signature string, err error) diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go index 3e600a164..6f8068c1e 100644 --- a/handler/rfc8628/strategy_hmacsha.go +++ b/handler/rfc8628/strategy_hmacsha.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628 @@ -14,6 +14,7 @@ import ( enigma "github.com/ory/fosite/token/hmac" ) +// DefaultDeviceStrategy implements the default device strategy type DefaultDeviceStrategy struct { Enigma *enigma.HMACStrategy RateLimiterCache *cache.Cache @@ -25,7 +26,8 @@ type DefaultDeviceStrategy struct { var _ RFC8628CodeStrategy = (*DefaultDeviceStrategy)(nil) -func (h *DefaultDeviceStrategy) GenerateUserCode(ctx context.Context) (token string, signature string, err error) { +// GenerateUserCode generates a user_code +func (h *DefaultDeviceStrategy) GenerateUserCode(ctx context.Context) (string, string, error) { seq, err := randx.RuneSequence(8, []rune(randx.AlphaUpper)) if err != nil { return "", "", err @@ -38,16 +40,19 @@ func (h *DefaultDeviceStrategy) GenerateUserCode(ctx context.Context) (token str return userCode, signUserCode, nil } -func (h *DefaultDeviceStrategy) UserCodeSignature(ctx context.Context, token string) (signature string, err error) { +// UserCodeSignature generates a user_code signature +func (h *DefaultDeviceStrategy) UserCodeSignature(ctx context.Context, token string) (string, error) { return h.Enigma.GenerateHMACForString(ctx, token) } -func (h *DefaultDeviceStrategy) ValidateUserCode(ctx context.Context, r fosite.Requester, code string) (err error) { +// ValidateUserCode validates a user_code +func (h *DefaultDeviceStrategy) ValidateUserCode(ctx context.Context, r fosite.Requester, code string) error { // TODO return nil } -func (h *DefaultDeviceStrategy) GenerateDeviceCode(ctx context.Context) (token string, signature string, err error) { +// GenerateDeviceCode generates a device_code +func (h *DefaultDeviceStrategy) GenerateDeviceCode(ctx context.Context) (string, string, error) { token, sig, err := h.Enigma.Generate(ctx) if err != nil { return "", "", err @@ -56,15 +61,18 @@ func (h *DefaultDeviceStrategy) GenerateDeviceCode(ctx context.Context) (token s return "ory_dc_" + token, sig, nil } -func (h *DefaultDeviceStrategy) DeviceCodeSignature(ctx context.Context, token string) (signature string, err error) { +// DeviceCodeSignature generates a device_code signature +func (h *DefaultDeviceStrategy) DeviceCodeSignature(ctx context.Context, token string) (string, error) { return h.Enigma.Signature(token), nil } -func (h *DefaultDeviceStrategy) ValidateDeviceCode(ctx context.Context, r fosite.Requester, code string) (err error) { +// ValidateDeviceCode validates a device_code +func (h *DefaultDeviceStrategy) ValidateDeviceCode(ctx context.Context, r fosite.Requester, code string) error { // TODO return nil } +// ShouldRateLimit is used to decide whether a request should be rate-limites func (t *DefaultDeviceStrategy) ShouldRateLimit(context context.Context, code string) bool { key := code + "_limiter" diff --git a/handler/rfc8628/strategy_hmacsha_test.go b/handler/rfc8628/strategy_hmacsha_test.go index f2835ea51..1673ea4c4 100644 --- a/handler/rfc8628/strategy_hmacsha_test.go +++ b/handler/rfc8628/strategy_hmacsha_test.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628_test diff --git a/integration/authorize_device_grant_request_test.go b/integration/authorize_device_grant_request_test.go index 2f548f147..2deb30678 100644 --- a/integration/authorize_device_grant_request_test.go +++ b/integration/authorize_device_grant_request_test.go @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test @@ -100,7 +100,7 @@ func runDeviceFlowTest(t *testing.T, strategy interface{}) { err: false, }, } { - t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + t.Run(fmt.Sprintf("case=%d description=%s", k, c.description), func(t *testing.T) { // Restore client fositeStore.Clients["device-client"] = &fosite.DefaultClient{ ID: "device-client", diff --git a/oauth2.go b/oauth2.go index 90d5f4f9a..1b4cb3d03 100644 --- a/oauth2.go +++ b/oauth2.go @@ -402,23 +402,36 @@ type G11NContext interface { GetLang() language.Tag } +// DeviceResponder is the device authorization endpoint's response type DeviceResponder interface { + // GetDeviceCode returns the device_code GetDeviceCode() string + // SetDeviceCode sets the device_code SetDeviceCode(code string) + // GetUserCode returns the user_code GetUserCode() string + // SetUserCode sets the user_code SetUserCode(code string) + // GetVerificationURI returns the verification_uri GetVerificationURI() string + // SetVerificationURI sets the verification_uri SetVerificationURI(uri string) + // GetVerificationURIComplete returns the verification_uri_complete GetVerificationURIComplete() string + // SetVerificationURIComplete sets the verification_uri_complete SetVerificationURIComplete(uri string) + // GetExpiresIn returns the expires_in GetExpiresIn() int64 + // SetExpiresIn sets the expires_in SetExpiresIn(seconds int64) + // GetInterval returns the interval GetInterval() int + // SetInterval sets the interval SetInterval(seconds int) // GetHeader returns the response's header diff --git a/storage/memory.go b/storage/memory.go index 16afbf2de..dab15a373 100644 --- a/storage/memory.go +++ b/storage/memory.go @@ -519,6 +519,7 @@ func (s *MemoryStore) RotateRefreshToken(ctx context.Context, requestID string, return s.RevokeAccessToken(ctx, requestID) } +// CreateDeviceCodeSession stores the device code session func (s *MemoryStore) CreateDeviceCodeSession(_ context.Context, signature string, req fosite.Requester) error { // We first lock accessTokenRequestIDsMutex and then accessTokensMutex because this is the same order // locking happens in RevokeAccessToken and using the same order prevents deadlocks. @@ -532,6 +533,7 @@ func (s *MemoryStore) CreateDeviceCodeSession(_ context.Context, signature strin return nil } +// UpdateDeviceCodeSession updates the device code session func (s *MemoryStore) UpdateDeviceCodeSession(_ context.Context, signature string, req fosite.Requester) error { s.deviceCodesRequestIDsMutex.Lock() defer s.deviceCodesRequestIDsMutex.Unlock() @@ -546,6 +548,7 @@ func (s *MemoryStore) UpdateDeviceCodeSession(_ context.Context, signature strin return nil } +// GetDeviceCodeSession gets the device code session func (s *MemoryStore) GetDeviceCodeSession(_ context.Context, signature string, _ fosite.Session) (fosite.Requester, error) { s.deviceCodesMutex.RLock() defer s.deviceCodesMutex.RUnlock() @@ -557,6 +560,7 @@ func (s *MemoryStore) GetDeviceCodeSession(_ context.Context, signature string, return rel, nil } +// InvalidateDeviceCodeSession invalidates the device code session func (s *MemoryStore) InvalidateDeviceCodeSession(_ context.Context, code string) error { s.deviceCodesRequestIDsMutex.Lock() defer s.deviceCodesRequestIDsMutex.Unlock() @@ -567,6 +571,7 @@ func (s *MemoryStore) InvalidateDeviceCodeSession(_ context.Context, code string return nil } +// CreateUserCodeSession stores the user code session func (s *MemoryStore) CreateUserCodeSession(_ context.Context, signature string, req fosite.Requester) error { s.userCodesRequestIDsMutex.Lock() defer s.userCodesRequestIDsMutex.Unlock() @@ -578,6 +583,7 @@ func (s *MemoryStore) CreateUserCodeSession(_ context.Context, signature string, return nil } +// GetUserCodeSession gets the user code session func (s *MemoryStore) GetUserCodeSession(_ context.Context, signature string, _ fosite.Session) (fosite.Requester, error) { s.userCodesMutex.RLock() defer s.userCodesMutex.RUnlock() @@ -589,6 +595,7 @@ func (s *MemoryStore) GetUserCodeSession(_ context.Context, signature string, _ return rel, nil } +// GetUserCodeSession invalidates the user code session func (s *MemoryStore) InvalidateUserCodeSession(_ context.Context, code string) error { s.userCodesRequestIDsMutex.Lock() defer s.userCodesRequestIDsMutex.Unlock() diff --git a/token/hmac/hmacsha.go b/token/hmac/hmacsha.go index 31237bd56..eaeb51d51 100644 --- a/token/hmac/hmacsha.go +++ b/token/hmac/hmacsha.go @@ -165,6 +165,7 @@ func (*HMACStrategy) Signature(token string) string { return split[1] } +// GenerateHMACForString returns an HMAC for a string func (c *HMACStrategy) GenerateHMACForString(ctx context.Context, text string) (string, error) { var signingKey [32]byte From 282633a79829826a75f61802b924cef039ac59e1 Mon Sep 17 00:00:00 2001 From: Shu Date: Fri, 15 Mar 2024 15:42:25 -0600 Subject: [PATCH 10/36] feat: implement the access token handling for device authorization flow feat: add the access token endpoint handling for device authorization flow --- compose/compose.go | 4 +- compose/compose_oauth2.go | 37 +- compose/compose_openid.go | 6 +- compose/compose_rfc8628.go | 26 +- device_response_writer.go | 2 +- errors.go | 21 + fosite_test.go | 10 +- generate-mocks.sh | 4 +- generate.go | 2 + handler.go | 2 +- handler/oauth2/flow_authorize_code_auth.go | 37 +- .../oauth2/flow_authorize_code_auth_test.go | 10 +- handler/oauth2/flow_authorize_code_token.go | 144 ++-- .../oauth2/flow_authorize_code_token_test.go | 105 ++- handler/oauth2/flow_generic_code_token.go | 254 +++++++ handler/oauth2/storage.go | 3 +- handler/openid/flow_hybrid.go | 8 +- handler/openid/flow_hybrid_test.go | 10 +- handler/rfc8628/storage.go | 4 +- handler/rfc8628/strategy_hmacsha.go | 39 +- handler/rfc8628/token_handler.go | 100 +++ handler/rfc8628/token_handler_test.go | 694 ++++++++++++++++++ ...rize_code_grant_public_client_pkce_test.go | 2 +- ...authorize_code_grant_public_client_test.go | 2 +- integration/authorize_code_grant_test.go | 4 +- .../authorize_device_grant_request_test.go | 160 +++- integration/helper_setup_test.go | 28 +- .../pushed_authorize_code_grant_test.go | 2 +- internal/device_code_rate_limit_strategy.go | 52 ++ internal/device_code_storage.go | 82 +++ oauth2.go | 22 +- storage/memory.go | 1 + 32 files changed, 1632 insertions(+), 245 deletions(-) create mode 100644 handler/oauth2/flow_generic_code_token.go create mode 100644 handler/rfc8628/token_handler.go create mode 100644 handler/rfc8628/token_handler_test.go create mode 100644 internal/device_code_rate_limit_strategy.go create mode 100644 internal/device_code_storage.go diff --git a/compose/compose.go b/compose/compose.go index 94c7349ff..91dd4e6e6 100644 --- a/compose/compose.go +++ b/compose/compose.go @@ -75,7 +75,8 @@ func ComposeAllEnabled(config *fosite.Config, storage interface{}, key interface OpenIDConnectTokenStrategy: NewOpenIDConnectStrategy(keyGetter, config), Signer: &jwt.DefaultSigner{GetPrivateKey: keyGetter}, }, - OAuth2AuthorizeExplicitFactory, + OAuth2AuthorizeExplicitAuthFactory, + Oauth2AuthorizeExplicitTokenFactory, OAuth2AuthorizeImplicitFactory, OAuth2ClientCredentialsGrantFactory, OAuth2RefreshTokenGrantFactory, @@ -91,6 +92,7 @@ func ComposeAllEnabled(config *fosite.Config, storage interface{}, key interface OAuth2TokenRevocationFactory, RFC8628DeviceFactory, + RFC8628DeviceAuthorizationTokenFactory, OAuth2PKCEFactory, PushedAuthorizeHandlerFactory, diff --git a/compose/compose_oauth2.go b/compose/compose_oauth2.go index c3f01073e..e1afc7533 100644 --- a/compose/compose_oauth2.go +++ b/compose/compose_oauth2.go @@ -9,16 +9,35 @@ import ( "github.com/ory/fosite/token/jwt" ) -// OAuth2AuthorizeExplicitFactory creates an OAuth2 authorize code grant ("authorize explicit flow") handler and registers +// OAuth2AuthorizeExplicitAuthFactory creates an OAuth2 authorize code grant ("authorize explicit flow") handler and registers // an access token, refresh token and authorize code validator. -func OAuth2AuthorizeExplicitFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} { - return &oauth2.AuthorizeExplicitGrantHandler{ - AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), - RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), - AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy), - CoreStorage: storage.(oauth2.CoreStorage), - TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage), - Config: config, +func OAuth2AuthorizeExplicitAuthFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} { + return &oauth2.AuthorizeExplicitGrantAuthHandler{ + AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy), + AuthorizeCodeStorage: storage.(oauth2.AuthorizeCodeStorage), + Config: config, + } +} + +// Oauth2AuthorizeExplicitTokenFactory creates an OAuth2 authorize code grant ("authorize explicit flow") token handler and registers +// an access token, refresh token and authorize code validator. +func Oauth2AuthorizeExplicitTokenFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} { + return &oauth2.AuthorizeExplicitTokenEndpointHandler{ + GenericCodeTokenEndpointHandler: oauth2.GenericCodeTokenEndpointHandler{ + AccessRequestValidator: &oauth2.AuthorizeExplicitGrantAccessRequestValidator{}, + CodeHandler: &oauth2.AuthorizeCodeHandler{ + AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy), + }, + SessionHandler: &oauth2.AuthorizeExplicitGrantSessionHandler{ + AuthorizeCodeStorage: storage.(oauth2.AuthorizeCodeStorage), + }, + + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), + CoreStorage: storage.(oauth2.CoreStorage), + TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage), + Config: config, + }, } } diff --git a/compose/compose_openid.go b/compose/compose_openid.go index 29b1d3a73..68178ddc7 100644 --- a/compose/compose_openid.go +++ b/compose/compose_openid.go @@ -59,11 +59,9 @@ func OpenIDConnectImplicitFactory(config fosite.Configurator, storage interface{ // **Important note:** You must add this handler *after* you have added an OAuth2 authorize code handler! func OpenIDConnectHybridFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} { return &openid.OpenIDConnectHybridHandler{ - AuthorizeExplicitGrantHandler: &oauth2.AuthorizeExplicitGrantHandler{ - AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), - RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), + AuthorizeExplicitGrantAuthHandler: &oauth2.AuthorizeExplicitGrantAuthHandler{ AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy), - CoreStorage: storage.(oauth2.CoreStorage), + AuthorizeCodeStorage: storage.(oauth2.AuthorizeCodeStorage), Config: config, }, Config: config, diff --git a/compose/compose_rfc8628.go b/compose/compose_rfc8628.go index 5217aeb7f..64ccc1e4c 100644 --- a/compose/compose_rfc8628.go +++ b/compose/compose_rfc8628.go @@ -7,11 +7,12 @@ package compose import ( "github.com/ory/fosite" + "github.com/ory/fosite/handler/oauth2" "github.com/ory/fosite/handler/rfc8628" ) // RFC8628DeviceFactory creates an OAuth2 device code grant ("Device Authorization Grant") handler and registers -// an user code, device code, access token and a refresh token validator. +// a user code, device code, access token and a refresh token validator. func RFC8628DeviceFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} { return &rfc8628.DeviceAuthHandler{ Strategy: strategy.(rfc8628.RFC8628CodeStrategy), @@ -19,3 +20,26 @@ func RFC8628DeviceFactory(config fosite.Configurator, storage interface{}, strat Config: config, } } + +// 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{ + AccessRequestValidator: &rfc8628.DeviceAccessRequestValidator{}, + CodeHandler: &rfc8628.DeviceCodeHandler{ + DeviceRateLimitStrategy: strategy.(rfc8628.DeviceRateLimitStrategy), + DeviceCodeStrategy: strategy.(rfc8628.DeviceCodeStrategy), + }, + SessionHandler: &rfc8628.DeviceSessionHandler{ + DeviceCodeStorage: storage.(rfc8628.DeviceCodeStorage), + }, + + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), + CoreStorage: storage.(oauth2.CoreStorage), + TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage), + Config: config, + }, + } +} diff --git a/device_response_writer.go b/device_response_writer.go index 2cc17d096..a093ea878 100644 --- a/device_response_writer.go +++ b/device_response_writer.go @@ -9,7 +9,7 @@ import ( // NewDeviceResponse returns a new DeviceResponder func (f *Fosite) NewDeviceResponse(ctx context.Context, r DeviceRequester, session Session) (DeviceResponder, error) { - var resp = &DeviceResponse{} + resp := &DeviceResponse{} r.SetSession(session) for _, h := range f.Config.GetDeviceEndpointHandlers(ctx) { diff --git a/errors.go b/errors.go index 332dbec2d..90b5c55e0 100644 --- a/errors.go +++ b/errors.go @@ -23,6 +23,8 @@ var ( // ErrInvalidatedAuthorizeCode is an error indicating that an authorization code has been // used previously. ErrInvalidatedAuthorizeCode = stderr.New("Authorization code has ben invalidated") + // ErrInvalidatedDeviceCode is an error indicating that a device code has benn used previously. + ErrInvalidatedDeviceCode = stderr.New("Device code has been invalidated") // ErrSerializationFailure is an error indicating that the transactional capable storage could not guarantee // consistency of Update & Delete operations on the same rows between multiple sessions. ErrSerializationFailure = &RFC6749Error{ @@ -206,6 +208,22 @@ var ( ErrorField: errJTIKnownName, CodeField: http.StatusBadRequest, } + ErrAuthorizationPending = &RFC6749Error{ + DescriptionField: "The authorization request is still pending as the end user hasn't yet completed the user-interaction steps.", + 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, + CodeField: http.StatusBadRequest, + } ) const ( @@ -243,6 +261,9 @@ const ( errRequestURINotSupportedName = "request_uri_not_supported" errRegistrationNotSupportedName = "registration_not_supported" errJTIKnownName = "jti_known" + errAuthorizationPending = "authorization_pending" + errPollingIntervalRateLimited = "polling_interval_rate_limited" + errDeviceExpiredToken = "expired_token" ) type ( diff --git a/fosite_test.go b/fosite_test.go index 2c86b498a..ded80b2c1 100644 --- a/fosite_test.go +++ b/fosite_test.go @@ -16,23 +16,23 @@ import ( ) func TestAuthorizeEndpointHandlers(t *testing.T) { - h := &oauth2.AuthorizeExplicitGrantHandler{} + h := &oauth2.AuthorizeExplicitGrantAuthHandler{} hs := AuthorizeEndpointHandlers{} hs.Append(h) hs.Append(h) - hs.Append(&oauth2.AuthorizeExplicitGrantHandler{}) + hs.Append(&oauth2.AuthorizeExplicitGrantAuthHandler{}) assert.Len(t, hs, 1) assert.Equal(t, hs[0], h) } func TestTokenEndpointHandlers(t *testing.T) { - h := &oauth2.AuthorizeExplicitGrantHandler{} + h := &oauth2.GenericCodeTokenEndpointHandler{} hs := TokenEndpointHandlers{} hs.Append(h) hs.Append(h) // do some crazy type things and make sure dupe detection works - var f interface{} = &oauth2.AuthorizeExplicitGrantHandler{} - hs.Append(&oauth2.AuthorizeExplicitGrantHandler{}) + var f interface{} = &oauth2.GenericCodeTokenEndpointHandler{} + hs.Append(&oauth2.GenericCodeTokenEndpointHandler{}) hs.Append(f.(TokenEndpointHandler)) require.Len(t, hs, 1) assert.Equal(t, hs[0], h) diff --git a/generate-mocks.sh b/generate-mocks.sh index d4dded4ea..2ed96b708 100755 --- a/generate-mocks.sh +++ b/generate-mocks.sh @@ -6,6 +6,7 @@ mockgen -package internal -destination internal/transactional.go github.com/ory/ mockgen -package internal -destination internal/oauth2_storage.go github.com/ory/fosite/handler/oauth2 CoreStorage mockgen -package internal -destination internal/oauth2_strategy.go github.com/ory/fosite/handler/oauth2 CoreStrategy mockgen -package internal -destination internal/authorize_code_storage.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStorage +mockgen -package internal -destination internal/device_code_storage.go github.com/ory/fosite/handler/rfc8628 DeviceCodeStorage mockgen -package internal -destination internal/oauth2_auth_jwt_storage.go github.com/ory/fosite/handler/rfc7523 RFC7523KeyStorage mockgen -package internal -destination internal/access_token_storage.go github.com/ory/fosite/handler/oauth2 AccessTokenStorage mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStorage @@ -16,6 +17,7 @@ mockgen -package internal -destination internal/openid_id_token_storage.go githu mockgen -package internal -destination internal/access_token_strategy.go github.com/ory/fosite/handler/oauth2 AccessTokenStrategy mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStrategy mockgen -package internal -destination internal/authorize_code_strategy.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStrategy +mockgen -package internal -destination internal/device_code_rate_limit_strategy.go github.com/ory/fosite/handler/rfc8628 DeviceRateLimitStrategy mockgen -package internal -destination internal/id_token_strategy.go github.com/ory/fosite/handler/openid OpenIDConnectTokenStrategy mockgen -package internal -destination internal/pkce_storage_strategy.go github.com/ory/fosite/handler/pkce PKCERequestStorage mockgen -package internal -destination internal/authorize_handler.go github.com/ory/fosite AuthorizeEndpointHandler @@ -29,4 +31,4 @@ mockgen -package internal -destination internal/access_response.go github.com/or mockgen -package internal -destination internal/authorize_request.go github.com/ory/fosite AuthorizeRequester mockgen -package internal -destination internal/authorize_response.go github.com/ory/fosite AuthorizeResponder -goimports -w internal/ \ No newline at end of file +goimports -w internal/ diff --git a/generate.go b/generate.go index fe382602b..0b3efaf63 100644 --- a/generate.go +++ b/generate.go @@ -9,6 +9,7 @@ package fosite //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_storage.go github.com/ory/fosite/handler/oauth2 CoreStorage //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_strategy.go github.com/ory/fosite/handler/oauth2 CoreStrategy //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/authorize_code_storage.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStorage +//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/device_code_storage.go github.com/ory/fosite/handler/rfc8628 DeviceCodeStorage //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_auth_jwt_storage.go github.com/ory/fosite/handler/rfc7523 RFC7523KeyStorage //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/access_token_storage.go github.com/ory/fosite/handler/oauth2 AccessTokenStorage //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStorage @@ -19,6 +20,7 @@ package fosite //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/access_token_strategy.go github.com/ory/fosite/handler/oauth2 AccessTokenStrategy //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStrategy //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/authorize_code_strategy.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStrategy +//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/device_code_rate_limit_strategy.go github.com/ory/fosite/handler/rfc8628 DeviceRateLimitStrategy //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/id_token_strategy.go github.com/ory/fosite/handler/openid OpenIDConnectTokenStrategy //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/pkce_storage_strategy.go github.com/ory/fosite/handler/pkce PKCERequestStorage //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/authorize_handler.go github.com/ory/fosite AuthorizeEndpointHandler diff --git a/handler.go b/handler.go index 163f4af6f..6a389b9fc 100644 --- a/handler.go +++ b/handler.go @@ -73,7 +73,7 @@ type DeviceEndpointHandler interface { // is passed along, if further information retrieval is required. If the handler feels that he is not responsible for // the device authorize request, he must return nil and NOT modify session nor responder neither requester. // - // The following spec is a good example of what HandleDeviceUserRequest should do. + // The following spec is a good example of what HandleDeviceEndpointRequest should do. // * https://tools.ietf.org/html/rfc8628#section-3.2 HandleDeviceEndpointRequest(ctx context.Context, requester DeviceRequester, responder DeviceResponder) error } diff --git a/handler/oauth2/flow_authorize_code_auth.go b/handler/oauth2/flow_authorize_code_auth.go index 0b03c8a78..ac70e883b 100644 --- a/handler/oauth2/flow_authorize_code_auth.go +++ b/handler/oauth2/flow_authorize_code_auth.go @@ -14,50 +14,39 @@ import ( "github.com/ory/fosite" ) -var _ fosite.AuthorizeEndpointHandler = (*AuthorizeExplicitGrantHandler)(nil) -var _ fosite.TokenEndpointHandler = (*AuthorizeExplicitGrantHandler)(nil) +var _ fosite.AuthorizeEndpointHandler = (*AuthorizeExplicitGrantAuthHandler)(nil) -// AuthorizeExplicitGrantHandler is a response handler for the Authorize Code grant using the explicit grant type +// AuthorizeExplicitGrantAuthHandler is a response handler for the Authorize Code grant using the explicit grant type // as defined in https://tools.ietf.org/html/rfc6749#section-4.1 -type AuthorizeExplicitGrantHandler struct { - AccessTokenStrategy AccessTokenStrategy - RefreshTokenStrategy RefreshTokenStrategy - AuthorizeCodeStrategy AuthorizeCodeStrategy - CoreStorage CoreStorage - TokenRevocationStorage TokenRevocationStorage - Config interface { +type AuthorizeExplicitGrantAuthHandler struct { + AuthorizeCodeStrategy AuthorizeCodeStrategy + AuthorizeCodeStorage AuthorizeCodeStorage + + Config interface { fosite.AuthorizeCodeLifespanProvider - fosite.AccessTokenLifespanProvider - fosite.RefreshTokenLifespanProvider fosite.ScopeStrategyProvider fosite.AudienceStrategyProvider fosite.RedirectSecureCheckerProvider - fosite.RefreshTokenScopesProvider fosite.OmitRedirectScopeParamProvider fosite.SanitationAllowedProvider } } -func (c *AuthorizeExplicitGrantHandler) secureChecker(ctx context.Context) func(context.Context, *url.URL) bool { +func (c *AuthorizeExplicitGrantAuthHandler) secureChecker(ctx context.Context) func(context.Context, *url.URL) bool { if c.Config.GetRedirectSecureChecker(ctx) == nil { return fosite.IsRedirectURISecure } return c.Config.GetRedirectSecureChecker(ctx) } -func (c *AuthorizeExplicitGrantHandler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { - // This let's us define multiple response types, for example open id connect's id_token +func (c *AuthorizeExplicitGrantAuthHandler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { + // This allows to define multiple response types, for example OpenID Connect `id_token` if !ar.GetResponseTypes().ExactOne("code") { return nil } ar.SetDefaultResponseMode(fosite.ResponseModeQuery) - // Disabled because this is already handled at the authorize_request_handler - // if !ar.GetClient().GetResponseTypes().Has("code") { - // return errorsx.WithStack(fosite.ErrInvalidGrant) - // } - if !c.secureChecker(ctx)(ctx, ar.GetRedirectURI()) { return errorsx.WithStack(fosite.ErrInvalidRequest.WithHint("Redirect URL is using an insecure protocol, http is only allowed for hosts with suffix 'localhost', for example: http://myapp.localhost/.")) } @@ -76,14 +65,14 @@ func (c *AuthorizeExplicitGrantHandler) HandleAuthorizeEndpointRequest(ctx conte return c.IssueAuthorizeCode(ctx, ar, resp) } -func (c *AuthorizeExplicitGrantHandler) IssueAuthorizeCode(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { +func (c *AuthorizeExplicitGrantAuthHandler) IssueAuthorizeCode(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { code, signature, err := c.AuthorizeCodeStrategy.GenerateAuthorizeCode(ctx, ar) if err != nil { return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } ar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().UTC().Add(c.Config.GetAuthorizeCodeLifespan(ctx))) - if err := c.CoreStorage.CreateAuthorizeCodeSession(ctx, signature, ar.Sanitize(c.GetSanitationWhiteList(ctx))); err != nil { + if err = c.AuthorizeCodeStorage.CreateAuthorizeCodeSession(ctx, signature, ar.Sanitize(c.GetSanitationWhiteList(ctx))); err != nil { return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } @@ -97,7 +86,7 @@ func (c *AuthorizeExplicitGrantHandler) IssueAuthorizeCode(ctx context.Context, return nil } -func (c *AuthorizeExplicitGrantHandler) GetSanitationWhiteList(ctx context.Context) []string { +func (c *AuthorizeExplicitGrantAuthHandler) GetSanitationWhiteList(ctx context.Context) []string { if allowedList := c.Config.GetSanitationWhiteList(ctx); len(allowedList) > 0 { return allowedList } diff --git a/handler/oauth2/flow_authorize_code_auth_test.go b/handler/oauth2/flow_authorize_code_auth_test.go index f915fefbd..027aa4e41 100644 --- a/handler/oauth2/flow_authorize_code_auth_test.go +++ b/handler/oauth2/flow_authorize_code_auth_test.go @@ -28,16 +28,16 @@ func TestAuthorizeCode_HandleAuthorizeEndpointRequest(t *testing.T) { } { t.Run("strategy="+k, func(t *testing.T) { store := storage.NewMemoryStore() - handler := AuthorizeExplicitGrantHandler{ - CoreStorage: store, + handler := AuthorizeExplicitGrantAuthHandler{ AuthorizeCodeStrategy: strategy, + AuthorizeCodeStorage: store, Config: &fosite.Config{ AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, ScopeStrategy: fosite.HierarchicScopeStrategy, }, } for _, c := range []struct { - handler AuthorizeExplicitGrantHandler + handler AuthorizeExplicitGrantAuthHandler areq *fosite.AuthorizeRequest description string expectErr error @@ -122,9 +122,9 @@ func TestAuthorizeCode_HandleAuthorizeEndpointRequest(t *testing.T) { }, }, { - handler: AuthorizeExplicitGrantHandler{ - CoreStorage: store, + handler: AuthorizeExplicitGrantAuthHandler{ AuthorizeCodeStrategy: strategy, + AuthorizeCodeStorage: store, Config: &fosite.Config{ ScopeStrategy: fosite.HierarchicScopeStrategy, AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, diff --git a/handler/oauth2/flow_authorize_code_token.go b/handler/oauth2/flow_authorize_code_token.go index 3b808aabc..e5a6b5534 100644 --- a/handler/oauth2/flow_authorize_code_token.go +++ b/handler/oauth2/flow_authorize_code_token.go @@ -7,113 +7,86 @@ import ( "context" "time" - "github.com/ory/x/errorsx" + "github.com/pkg/errors" "github.com/ory/fosite/storage" - - "github.com/pkg/errors" + "github.com/ory/x/errorsx" "github.com/ory/fosite" ) -// HandleTokenEndpointRequest implements -// * https://tools.ietf.org/html/rfc6749#section-4.1.3 (everything) -func (c *AuthorizeExplicitGrantHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error { - if !c.CanHandleTokenEndpointRequest(ctx, request) { - return errorsx.WithStack(errorsx.WithStack(fosite.ErrUnknownRequest)) - } - - if !request.GetClient().GetGrantTypes().Has("authorization_code") { - return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"authorization_code\".")) - } +type AuthorizeCodeHandler struct { + AuthorizeCodeStrategy AuthorizeCodeStrategy +} - code := request.GetRequestForm().Get("code") +func (c AuthorizeCodeHandler) Code(ctx context.Context, requester fosite.AccessRequester) (string, string, error) { + code := requester.GetRequestForm().Get("code") signature := c.AuthorizeCodeStrategy.AuthorizeCodeSignature(ctx, code) - authorizeRequest, err := c.CoreStorage.GetAuthorizeCodeSession(ctx, signature, request.GetSession()) - if errors.Is(err, fosite.ErrInvalidatedAuthorizeCode) { - if authorizeRequest == nil { - return fosite.ErrServerError. - WithHint("Misconfigured code lead to an error that prohibited the OAuth 2.0 Framework from processing this request."). - WithDebug("GetAuthorizeCodeSession must return a value for \"fosite.Requester\" when returning \"ErrInvalidatedAuthorizeCode\".") - } + return code, signature, nil +} - // If an authorize code is used twice, we revoke all refresh and access tokens associated with this request. - reqID := authorizeRequest.GetID() - hint := "The authorization code has already been used." - debug := "" - if revErr := c.TokenRevocationStorage.RevokeAccessToken(ctx, reqID); revErr != nil { - hint += " Additionally, an error occurred during processing the access token revocation." - debug += "Revocation of access_token lead to error " + revErr.Error() + "." - } - if revErr := c.TokenRevocationStorage.RevokeRefreshToken(ctx, reqID); revErr != nil { - hint += " Additionally, an error occurred during processing the refresh token revocation." - debug += "Revocation of refresh_token lead to error " + revErr.Error() + "." - } - return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint(hint).WithDebug(debug)) - } else if err != nil && errors.Is(err, fosite.ErrNotFound) { - return errorsx.WithStack(fosite.ErrInvalidGrant.WithWrap(err).WithDebug(err.Error())) - } else if err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } +func (c AuthorizeCodeHandler) ValidateCode(ctx context.Context, requester fosite.AccessRequester, code string) error { + return c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, requester, code) +} - // The authorization server MUST verify that the authorization code is valid - // This needs to happen after store retrieval for the session to be hydrated properly - if err := c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, request, code); err != nil { - return errorsx.WithStack(fosite.ErrInvalidGrant.WithWrap(err).WithDebug(err.Error())) - } +type AuthorizeExplicitGrantSessionHandler struct { + AuthorizeCodeStorage AuthorizeCodeStorage +} - // Override scopes - request.SetRequestedScopes(authorizeRequest.GetRequestedScopes()) +func (s AuthorizeExplicitGrantSessionHandler) Session(ctx context.Context, requester fosite.AccessRequester, codeSignature string) (fosite.Requester, error) { + req, err := s.AuthorizeCodeStorage.GetAuthorizeCodeSession(ctx, codeSignature, requester.GetSession()) - // Override audiences - request.SetRequestedAudience(authorizeRequest.GetRequestedAudience()) + if err != nil && errors.Is(err, fosite.ErrInvalidatedAuthorizeCode) { + if req != nil { + return req, err + } - // The authorization server MUST ensure that the authorization code was issued to the authenticated - // confidential client, or if the client is public, ensure that the - // code was issued to "client_id" in the request, - if authorizeRequest.GetClient().GetID() != request.GetClient().GetID() { - return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the one from the authorize request.")) + return req, fosite.ErrServerError. + WithHint("Misconfigured code lead to an error that prohibited the OAuth 2.0 Framework from processing this request."). + WithDebug("\"GetAuthorizeCodeSession\" must return a value for \"fosite.Requester\" when returning \"ErrInvalidatedAuthorizeCode\".") } - // ensure that the "redirect_uri" parameter is present if the - // "redirect_uri" parameter was included in the initial authorization - // request as described in Section 4.1.1, and if included ensure that - // their values are identical. - forcedRedirectURI := authorizeRequest.GetRequestForm().Get("redirect_uri") - if forcedRedirectURI != "" && forcedRedirectURI != request.GetRequestForm().Get("redirect_uri") { - return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The \"redirect_uri\" from this request does not match the one from the authorize request.")) + if err != nil && errors.Is(err, fosite.ErrNotFound) { + return nil, errorsx.WithStack(fosite.ErrInvalidGrant.WithWrap(err).WithDebug(err.Error())) + } + + if err != nil { + return nil, errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } - // Checking of POST client_id skipped, because: - // If the client type is confidential or the client was issued client - // credentials (or assigned other authentication requirements), the - // client MUST authenticate with the authorization server as described - // in Section 3.2.1. - request.SetSession(authorizeRequest.GetSession()) - request.SetID(authorizeRequest.GetID()) + return req, err +} + +func (s AuthorizeExplicitGrantSessionHandler) InvalidateSession(ctx context.Context, codeSignature string) error { + return s.AuthorizeCodeStorage.InvalidateAuthorizeCodeSession(ctx, codeSignature) +} - atLifespan := fosite.GetEffectiveLifespan(request.GetClient(), fosite.GrantTypeAuthorizationCode, fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) - request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(atLifespan).Round(time.Second)) +type AuthorizeExplicitGrantAccessRequestValidator struct{} + +func (v AuthorizeExplicitGrantAccessRequestValidator) CanHandleRequest(requester fosite.AccessRequester) bool { + return requester.GetGrantTypes().ExactOne("authorization_code") +} - rtLifespan := fosite.GetEffectiveLifespan(request.GetClient(), fosite.GrantTypeAuthorizationCode, fosite.RefreshToken, c.Config.GetRefreshTokenLifespan(ctx)) - if rtLifespan > -1 { - request.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(rtLifespan).Round(time.Second)) +func (v AuthorizeExplicitGrantAccessRequestValidator) ValidateGrantTypes(requester fosite.AccessRequester) error { + if !requester.GetClient().GetGrantTypes().Has("authorization_code") { + return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"authorization_code\".")) } return nil } -func canIssueRefreshToken(ctx context.Context, c *AuthorizeExplicitGrantHandler, request fosite.Requester) bool { - scope := c.Config.GetRefreshTokenScopes(ctx) - // Require one of the refresh token scopes, if set. - if len(scope) > 0 && !request.GetGrantedScopes().HasOneOf(scope...) { - return false - } - // Do not issue a refresh token to clients that cannot use the refresh token grant type. - if !request.GetClient().GetGrantTypes().Has("refresh_token") { - return false +func (v AuthorizeExplicitGrantAccessRequestValidator) ValidateRedirectURI(accessRequester fosite.AccessRequester, authorizeRequester fosite.Requester) error { + forcedRedirectURI := authorizeRequester.GetRequestForm().Get("redirect_uri") + requestedRedirectURI := accessRequester.GetRequestForm().Get("redirect_uri") + if forcedRedirectURI != "" && forcedRedirectURI != requestedRedirectURI { + return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The \"redirect_uri\" from this request does not match the one from the authorize request.")) } - return true + + return nil +} + +type AuthorizeExplicitTokenEndpointHandler struct { + GenericCodeTokenEndpointHandler } func (c *AuthorizeExplicitGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) (err error) { @@ -199,3 +172,10 @@ func (c *AuthorizeExplicitGrantHandler) CanHandleTokenEndpointRequest(ctx contex // Value MUST be set to "authorization_code" return requester.GetGrantTypes().ExactOne("authorization_code") } + +var ( + _ AccessRequestValidator = (*AuthorizeExplicitGrantAccessRequestValidator)(nil) + _ CodeHandler = (*AuthorizeCodeHandler)(nil) + _ SessionHandler = (*AuthorizeExplicitGrantSessionHandler)(nil) + _ fosite.TokenEndpointHandler = (*AuthorizeExplicitTokenEndpointHandler)(nil) +) diff --git a/handler/oauth2/flow_authorize_code_token_test.go b/handler/oauth2/flow_authorize_code_token_test.go index 94587111b..cbf07c072 100644 --- a/handler/oauth2/flow_authorize_code_token_test.go +++ b/handler/oauth2/flow_authorize_code_token_test.go @@ -7,16 +7,14 @@ import ( "context" "fmt" "net/url" - "testing" //"time" - - //"github.com/golang/mock/gomock" + "testing" "time" "github.com/golang/mock/gomock" "github.com/ory/fosite/internal" - "github.com/ory/fosite" //"github.com/ory/fosite/internal" + "github.com/ory/fosite" "github.com/ory/fosite/storage" "github.com/pkg/errors" "github.com/stretchr/testify/assert" @@ -30,7 +28,7 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { t.Run("strategy="+k, func(t *testing.T) { store := storage.NewMemoryStore() - var h AuthorizeExplicitGrantHandler + var h GenericCodeTokenEndpointHandler for _, c := range []struct { areq *fosite.AccessRequest description string @@ -209,12 +207,18 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { AccessTokenLifespan: time.Minute, RefreshTokenScopes: []string{"offline"}, } - h = AuthorizeExplicitGrantHandler{ - CoreStorage: store, - AuthorizeCodeStrategy: strategy, - AccessTokenStrategy: strategy, - RefreshTokenStrategy: strategy, - Config: config, + h = GenericCodeTokenEndpointHandler{ + AccessRequestValidator: &AuthorizeExplicitGrantAccessRequestValidator{}, + CodeHandler: &AuthorizeCodeHandler{ + AuthorizeCodeStrategy: strategy, + }, + SessionHandler: &AuthorizeExplicitGrantSessionHandler{ + AuthorizeCodeStorage: store, + }, + AccessTokenStrategy: strategy, + RefreshTokenStrategy: strategy, + CoreStorage: store, + Config: config, } if c.setup != nil { @@ -245,16 +249,22 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { } { t.Run("strategy="+k, func(t *testing.T) { store := storage.NewMemoryStore() - - h := AuthorizeExplicitGrantHandler{ + config := &fosite.Config{ + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + AuthorizeCodeLifespan: time.Minute, + } + h := GenericCodeTokenEndpointHandler{ + AccessRequestValidator: &AuthorizeExplicitGrantAccessRequestValidator{}, CoreStorage: store, - AuthorizeCodeStrategy: hmacshaStrategy, - TokenRevocationStorage: store, - Config: &fosite.Config{ - ScopeStrategy: fosite.HierarchicScopeStrategy, - AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, - AuthorizeCodeLifespan: time.Minute, + CodeHandler: &AuthorizeCodeHandler{ + AuthorizeCodeStrategy: hmacshaStrategy, + }, + SessionHandler: &AuthorizeExplicitGrantSessionHandler{ + AuthorizeCodeStorage: store, }, + TokenRevocationStorage: store, + Config: config, } for i, c := range []struct { areq *fosite.AccessRequest @@ -445,6 +455,7 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { var mockTransactional *internal.MockTransactional var mockCoreStore *internal.MockCoreStorage + var mockAuthorizeStore *internal.MockAuthorizeCodeStorage strategy := hmacshaStrategy request := &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, @@ -469,6 +480,11 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { CoreStorage } + type authorizeTransactionalStore struct { + storage.Transactional + AuthorizeCodeStorage + } + for _, testCase := range []struct { description string setup func() @@ -477,7 +493,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "transaction should be committed successfully if no errors occur", setup: func() { - mockCoreStore. + mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(request, nil). @@ -486,7 +502,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockCoreStore. + mockAuthorizeStore. EXPECT(). InvalidateAuthorizeCodeSession(gomock.Any(), gomock.Any()). Return(nil). @@ -511,7 +527,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "transaction should be rolled back if `InvalidateAuthorizeCodeSession` returns an error", setup: func() { - mockCoreStore. + mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(request, nil). @@ -520,7 +536,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockCoreStore. + mockAuthorizeStore. EXPECT(). InvalidateAuthorizeCodeSession(gomock.Any(), gomock.Any()). Return(errors.New("Whoops, a nasty database error occurred!")). @@ -536,7 +552,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "transaction should be rolled back if `CreateAccessTokenSession` returns an error", setup: func() { - mockCoreStore. + mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(request, nil). @@ -545,7 +561,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockCoreStore. + mockAuthorizeStore. EXPECT(). InvalidateAuthorizeCodeSession(gomock.Any(), gomock.Any()). Return(nil). @@ -566,7 +582,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "should result in a server error if transaction cannot be created", setup: func() { - mockCoreStore. + mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(request, nil). @@ -581,7 +597,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "should result in a server error if transaction cannot be rolled back", setup: func() { - mockCoreStore. + mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(request, nil). @@ -590,7 +606,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockCoreStore. + mockAuthorizeStore. EXPECT(). InvalidateAuthorizeCodeSession(gomock.Any(), gomock.Any()). Return(errors.New("Whoops, a nasty database error occurred!")). @@ -606,7 +622,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "should result in a server error if transaction cannot be committed", setup: func() { - mockCoreStore. + mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(request, nil). @@ -615,7 +631,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockCoreStore. + mockAuthorizeStore. EXPECT(). InvalidateAuthorizeCodeSession(gomock.Any(), gomock.Any()). Return(nil). @@ -650,21 +666,32 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockTransactional = internal.NewMockTransactional(ctrl) mockCoreStore = internal.NewMockCoreStorage(ctrl) + mockAuthorizeStore = internal.NewMockAuthorizeCodeStorage(ctrl) testCase.setup() - handler := AuthorizeExplicitGrantHandler{ + config := &fosite.Config{ + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + AuthorizeCodeLifespan: time.Minute, + } + handler := GenericCodeTokenEndpointHandler{ + AccessRequestValidator: &AuthorizeExplicitGrantAccessRequestValidator{}, + CodeHandler: &AuthorizeCodeHandler{ + AuthorizeCodeStrategy: strategy, + }, + SessionHandler: &AuthorizeExplicitGrantSessionHandler{ + AuthorizeCodeStorage: authorizeTransactionalStore{ + mockTransactional, + mockAuthorizeStore, + }, + }, CoreStorage: transactionalStore{ mockTransactional, mockCoreStore, }, - AccessTokenStrategy: strategy, - RefreshTokenStrategy: strategy, - AuthorizeCodeStrategy: strategy, - Config: &fosite.Config{ - ScopeStrategy: fosite.HierarchicScopeStrategy, - AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, - AuthorizeCodeLifespan: time.Minute, - }, + AccessTokenStrategy: strategy, + RefreshTokenStrategy: strategy, + Config: config, } if err := handler.PopulateTokenEndpointResponse(propagatedContext, request, response); testCase.expectError != nil { diff --git a/handler/oauth2/flow_generic_code_token.go b/handler/oauth2/flow_generic_code_token.go new file mode 100644 index 000000000..39c40422c --- /dev/null +++ b/handler/oauth2/flow_generic_code_token.go @@ -0,0 +1,254 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package oauth2 + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/pkg/errors" + + "github.com/ory/fosite/storage" + + "github.com/ory/x/errorsx" + + "github.com/ory/fosite" +) + +// AccessRequestValidator handles various validations in the access request handling. +type AccessRequestValidator interface { + // CanHandleRequest validates if the access request should be handled. + CanHandleRequest(requester fosite.AccessRequester) bool + + // ValidateGrantTypes validates the grant types in the access request. + ValidateGrantTypes(requester fosite.AccessRequester) error + + // ValidateRedirectURI validates the redirect uri in the access request. + ValidateRedirectURI(accessRequester fosite.AccessRequester, authorizeRequester fosite.Requester) error +} + +// CodeHandler handles authorization/device code related operations. +type CodeHandler interface { + // Code fetches the code and code signature. + Code(ctx context.Context, requester fosite.AccessRequester) (code string, signature string, err error) + + // ValidateCode validates the code. + ValidateCode(ctx context.Context, requester fosite.AccessRequester, code string) error +} + +// SessionHandler handles session-related operations. +type SessionHandler interface { + // Session fetches the authorized request. + Session(ctx context.Context, requester fosite.AccessRequester, codeSignature string) (fosite.Requester, error) + + // InvalidateSession invalidates the code and session. + InvalidateSession(ctx context.Context, codeSignature string) error +} + +// GenericCodeTokenEndpointHandler is a token response handler for +// - the Authorize Code grant using the explicit grant type as defined in https://tools.ietf.org/html/rfc6749#section-4.1 +// - the Device Authorization Grant as defined in https://www.rfc-editor.org/rfc/rfc8628 +type GenericCodeTokenEndpointHandler struct { + AccessRequestValidator + CodeHandler + SessionHandler + + AccessTokenStrategy AccessTokenStrategy + RefreshTokenStrategy RefreshTokenStrategy + CoreStorage CoreStorage + TokenRevocationStorage TokenRevocationStorage + Config interface { + fosite.AccessTokenLifespanProvider + fosite.RefreshTokenLifespanProvider + fosite.RefreshTokenScopesProvider + } +} + +func (c *GenericCodeTokenEndpointHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { + if !c.CanHandleTokenEndpointRequest(ctx, requester) { + return errorsx.WithStack(fosite.ErrUnknownRequest) + } + + var code, signature string + var err error + if code, signature, err = c.Code(ctx, requester); err != nil { + return err + } + + var ar fosite.Requester + if ar, err = c.Session(ctx, requester, signature); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + if err = c.ValidateCode(ctx, requester, code); err != nil { + return errorsx.WithStack(fosite.ErrInvalidRequest.WithWrap(err).WithDebug(err.Error())) + } + + for _, scope := range ar.GetRequestedScopes() { + requester.GrantScope(scope) + } + + for _, audience := range ar.GetGrantedAudience() { + requester.GrantAudience(audience) + } + + var accessToken, accessTokenSignature string + accessToken, accessTokenSignature, err = c.AccessTokenStrategy.GenerateAccessToken(ctx, requester) + if err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + var refreshToken, refreshTokenSignature string + if c.canIssueRefreshToken(ctx, ar) { + refreshToken, refreshTokenSignature, err = c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester) + if err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + } + + ctx, err = storage.MaybeBeginTx(ctx, c.CoreStorage) + if err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + defer func() { + if err != nil { + if rollBackTxnErr := storage.MaybeRollbackTx(ctx, c.CoreStorage); rollBackTxnErr != nil { + err = errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebugf("error: %s; rollback error: %s", err, rollBackTxnErr)) + } + } + }() + + if err = c.InvalidateSession(ctx, signature); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + if err = c.CoreStorage.CreateAccessTokenSession(ctx, accessTokenSignature, requester.Sanitize([]string{})); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + if refreshTokenSignature != "" { + if err = c.CoreStorage.CreateRefreshTokenSession(ctx, refreshTokenSignature, requester.Sanitize([]string{})); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + } + + lifeSpan := fosite.GetEffectiveLifespan(requester.GetClient(), fosite.GrantTypeAuthorizationCode, fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) + responder.SetAccessToken(accessToken) + responder.SetTokenType("bearer") + responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, lifeSpan, time.Now().UTC())) + responder.SetScopes(requester.GetGrantedScopes()) + if refreshToken != "" { + responder.SetExtra("refresh_token", refreshToken) + } + + if err = storage.MaybeCommitTx(ctx, c.CoreStorage); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + return nil +} + +func (c *GenericCodeTokenEndpointHandler) HandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) error { + if !c.CanHandleTokenEndpointRequest(ctx, requester) { + return errorsx.WithStack(errorsx.WithStack(fosite.ErrUnknownRequest)) + } + + var err error + if err = c.ValidateGrantTypes(requester); err != nil { + return err + } + + var code, signature string + if code, signature, err = c.Code(ctx, requester); err != nil { + return err + } + + var ar fosite.Requester + if ar, err = c.Session(ctx, requester, signature); err != nil { + if ar != nil && (errors.Is(err, fosite.ErrInvalidatedAuthorizeCode) || errors.Is(err, fosite.ErrInvalidatedDeviceCode)) { + return c.revokeTokens(ctx, requester.GetID()) + } + + return err + } + + if err = c.ValidateCode(ctx, requester, code); err != nil { + return errorsx.WithStack(err) + } + + // Override scopes + requester.SetRequestedScopes(ar.GetRequestedScopes()) + + // Override audiences + requester.SetRequestedAudience(ar.GetRequestedAudience()) + + // The authorization server MUST ensure that + // the authorization code was issued to the authenticated confidential client, + // or if the client is public, ensure that the code was issued to "client_id" in the request + if ar.GetClient().GetID() != requester.GetClient().GetID() { + return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the one from the authorize request.")) + } + + if err = c.ValidateRedirectURI(requester, ar); err != nil { + return err + } + + // Checking of POST client_id skipped, because + // if the client type is confidential or the client was issued client credentials (or assigned other authentication requirements), + // the client MUST authenticate with the authorization server as described in Section 3.2.1. + requester.SetSession(ar.GetSession()) + requester.SetID(ar.GetID()) + + atLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), fosite.GrantTypeAuthorizationCode, fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) + requester.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(atLifespan).Round(time.Second)) + + rtLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), fosite.GrantTypeAuthorizationCode, fosite.RefreshToken, c.Config.GetRefreshTokenLifespan(ctx)) + if rtLifespan > -1 { + requester.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(rtLifespan).Round(time.Second)) + } + + return nil +} + +func (c *GenericCodeTokenEndpointHandler) CanSkipClientAuth(ctx context.Context, requester fosite.AccessRequester) bool { + return false +} + +func (c *GenericCodeTokenEndpointHandler) CanHandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) bool { + return c.CanHandleRequest(requester) +} + +func (c *GenericCodeTokenEndpointHandler) canIssueRefreshToken(ctx context.Context, requester fosite.Requester) bool { + scope := c.Config.GetRefreshTokenScopes(ctx) + if len(scope) > 0 && !requester.GetGrantedScopes().HasOneOf(scope...) { + return false + } + + if !requester.GetClient().GetGrantTypes().Has("refresh_token") { + return false + } + + return true +} + +func (c *GenericCodeTokenEndpointHandler) revokeTokens(ctx context.Context, reqId string) error { + hint := "The authorization code has already been used." + var debug strings.Builder + + revokeAndAppendErr := func(tokenType string, revokeFunc func(context.Context, string) error) { + if err := revokeFunc(ctx, reqId); err != nil { + hint += fmt.Sprintf(" Additionally, an error occurred during processing the %s token revocation.", tokenType) + debug.WriteString(fmt.Sprintf("Revocation of %s token lead to error %s.", tokenType, err.Error())) + } + } + + revokeAndAppendErr("access", c.TokenRevocationStorage.RevokeAccessToken) + revokeAndAppendErr("refresh", c.TokenRevocationStorage.RevokeRefreshToken) + + return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint(hint).WithDebug(debug.String())) +} + +var _ fosite.TokenEndpointHandler = (*GenericCodeTokenEndpointHandler)(nil) diff --git a/handler/oauth2/storage.go b/handler/oauth2/storage.go index fd9306624..58a581057 100644 --- a/handler/oauth2/storage.go +++ b/handler/oauth2/storage.go @@ -10,14 +10,13 @@ import ( ) type CoreStorage interface { - AuthorizeCodeStorage AccessTokenStorage RefreshTokenStorage } // AuthorizeCodeStorage handles storage requests related to authorization codes. type AuthorizeCodeStorage interface { - // GetAuthorizeCodeSession stores the authorization request for a given authorization code. + // CreateAuthorizeCodeSession stores the authorization request for a given authorization code. CreateAuthorizeCodeSession(ctx context.Context, code string, request fosite.Requester) (err error) // GetAuthorizeCodeSession hydrates the session based on the given code and returns the authorization request. diff --git a/handler/openid/flow_hybrid.go b/handler/openid/flow_hybrid.go index c1dc6c645..5bca57682 100644 --- a/handler/openid/flow_hybrid.go +++ b/handler/openid/flow_hybrid.go @@ -16,7 +16,7 @@ import ( type OpenIDConnectHybridHandler struct { AuthorizeImplicitGrantTypeHandler *oauth2.AuthorizeImplicitGrantTypeHandler - AuthorizeExplicitGrantHandler *oauth2.AuthorizeExplicitGrantHandler + AuthorizeExplicitGrantAuthHandler *oauth2.AuthorizeExplicitGrantAuthHandler IDTokenHandleHelper *IDTokenHandleHelper OpenIDConnectRequestValidator *OpenIDConnectRequestValidator OpenIDConnectRequestStorage OpenIDConnectRequestStorage @@ -97,7 +97,7 @@ func (c *OpenIDConnectHybridHandler) HandleAuthorizeEndpointRequest(ctx context. return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant 'authorization_code'.")) } - code, signature, err := c.AuthorizeExplicitGrantHandler.AuthorizeCodeStrategy.GenerateAuthorizeCode(ctx, ar) + code, signature, err := c.AuthorizeExplicitGrantAuthHandler.AuthorizeCodeStrategy.GenerateAuthorizeCode(ctx, ar) if err != nil { return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } @@ -110,8 +110,8 @@ func (c *OpenIDConnectHybridHandler) HandleAuthorizeEndpointRequest(ctx context. // } // This is required because we must limit the authorize code lifespan. - ar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().UTC().Add(c.AuthorizeExplicitGrantHandler.Config.GetAuthorizeCodeLifespan(ctx)).Round(time.Second)) - if err := c.AuthorizeExplicitGrantHandler.CoreStorage.CreateAuthorizeCodeSession(ctx, signature, ar.Sanitize(c.AuthorizeExplicitGrantHandler.GetSanitationWhiteList(ctx))); err != nil { + ar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().UTC().Add(c.AuthorizeExplicitGrantAuthHandler.Config.GetAuthorizeCodeLifespan(ctx)).Round(time.Second)) + if err := c.AuthorizeExplicitGrantAuthHandler.AuthorizeCodeStorage.CreateAuthorizeCodeSession(ctx, signature, ar.Sanitize(c.AuthorizeExplicitGrantAuthHandler.GetSanitationWhiteList(ctx))); err != nil { return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } diff --git a/handler/openid/flow_hybrid_test.go b/handler/openid/flow_hybrid_test.go index afe4bbe38..e0214ab3a 100644 --- a/handler/openid/flow_hybrid_test.go +++ b/handler/openid/flow_hybrid_test.go @@ -32,7 +32,7 @@ var hmacStrategy = oauth2.NewHMACSHAStrategy( ) func makeOpenIDConnectHybridHandler(minParameterEntropy int) OpenIDConnectHybridHandler { - var idStrategy = &DefaultStrategy{ + idStrategy := &DefaultStrategy{ Signer: &jwt.DefaultSigner{ GetPrivateKey: func(_ context.Context) (interface{}, error) { return gen.MustRSAKey(), nil @@ -43,7 +43,7 @@ func makeOpenIDConnectHybridHandler(minParameterEntropy int) OpenIDConnectHybrid }, } - var j = &DefaultStrategy{ + j := &DefaultStrategy{ Signer: &jwt.DefaultSigner{ GetPrivateKey: func(_ context.Context) (interface{}, error) { return key, nil @@ -61,11 +61,11 @@ func makeOpenIDConnectHybridHandler(minParameterEntropy int) OpenIDConnectHybrid AuthorizeCodeLifespan: time.Hour, RefreshTokenLifespan: time.Hour, } + store := storage.NewMemoryStore() return OpenIDConnectHybridHandler{ - AuthorizeExplicitGrantHandler: &oauth2.AuthorizeExplicitGrantHandler{ + AuthorizeExplicitGrantAuthHandler: &oauth2.AuthorizeExplicitGrantAuthHandler{ AuthorizeCodeStrategy: hmacStrategy, - AccessTokenStrategy: hmacStrategy, - CoreStorage: storage.NewMemoryStore(), + AuthorizeCodeStorage: store, Config: config, }, AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{ diff --git a/handler/rfc8628/storage.go b/handler/rfc8628/storage.go index 17571ab18..8ae1b35eb 100644 --- a/handler/rfc8628/storage.go +++ b/handler/rfc8628/storage.go @@ -30,7 +30,7 @@ type DeviceCodeStorage interface { // Make sure to also return the fosite.Requester value when returning the fosite.ErrInvalidatedDeviceCode error! GetDeviceCodeSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) - // InvalidateDeviceCodeSession is called when an device code is being used. The state of the user + // InvalidateDeviceCodeSession is called when a device code is being used. The state of the user // code should be set to invalid and consecutive requests to GetDeviceCodeSession should return the // ErrInvalidatedDeviceCode error. InvalidateDeviceCodeSession(ctx context.Context, signature string) (err error) @@ -48,7 +48,7 @@ type UserCodeStorage interface { // Make sure to also return the fosite.Requester value when returning the fosite.ErrInvalidatedUserCode error! GetUserCodeSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) - // InvalidateUserCodeSession is called when an user code is being used. The state of the user + // InvalidateUserCodeSession is called when a user code is being used. The state of the user // code should be set to invalid and consecutive requests to GetUserCodeSession should return the // ErrInvalidatedUserCode error. InvalidateUserCodeSession(ctx context.Context, signature string) (err error) diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go index 6f8068c1e..9c173f97a 100644 --- a/handler/rfc8628/strategy_hmacsha.go +++ b/handler/rfc8628/strategy_hmacsha.go @@ -5,6 +5,10 @@ package rfc8628 import ( "context" + "strings" + "time" + + "github.com/ory/x/errorsx" "github.com/ory/x/randx" "github.com/patrickmn/go-cache" @@ -46,8 +50,17 @@ func (h *DefaultDeviceStrategy) UserCodeSignature(ctx context.Context, token str } // ValidateUserCode validates a user_code -func (h *DefaultDeviceStrategy) ValidateUserCode(ctx context.Context, r fosite.Requester, code string) error { - // TODO +// This function only checks if the device request session is active as we cannot verify the authenticity of the token. +// Unlike other tokens, the user_code is of limited length, which means that we cannot include the HMAC signature in the token itself. +// The only way to check the validity of the user_code is to check if its signature is stored in storage. +func (h *DefaultDeviceStrategy) ValidateUserCode(ctx context.Context, r fosite.DeviceRequester, code string) error { + exp := r.GetSession().GetExpiresAt(fosite.UserCode) + if exp.IsZero() && r.GetRequestedAt().Add(h.Config.GetDeviceAndUserCodeLifespan(ctx)).Before(time.Now().UTC()) { + return errorsx.WithStack(fosite.ErrDeviceExpiredToken.WithHintf("User code expired at '%s'.", r.GetRequestedAt().Add(h.Config.GetDeviceAndUserCodeLifespan(ctx)))) + } + if !exp.IsZero() && exp.Before(time.Now().UTC()) { + return errorsx.WithStack(fosite.ErrDeviceExpiredToken.WithHintf("User code expired at '%s'.", exp)) + } return nil } @@ -68,25 +81,33 @@ func (h *DefaultDeviceStrategy) DeviceCodeSignature(ctx context.Context, token s // ValidateDeviceCode validates a device_code func (h *DefaultDeviceStrategy) ValidateDeviceCode(ctx context.Context, r fosite.Requester, code string) error { - // TODO - return nil + exp := r.GetSession().GetExpiresAt(fosite.DeviceCode) + if exp.IsZero() && r.GetRequestedAt().Add(h.Config.GetDeviceAndUserCodeLifespan(ctx)).Before(time.Now().UTC()) { + return errorsx.WithStack(fosite.ErrDeviceExpiredToken.WithHintf("Device code expired at '%s'.", r.GetRequestedAt().Add(h.Config.GetDeviceAndUserCodeLifespan(ctx)))) + } + + if !exp.IsZero() && exp.Before(time.Now().UTC()) { + return errorsx.WithStack(fosite.ErrDeviceExpiredToken.WithHintf("Device code expired at '%s'.", exp)) + } + + return h.Enigma.Validate(ctx, strings.TrimPrefix(code, "ory_dc_")) } -// ShouldRateLimit is used to decide whether a request should be rate-limites -func (t *DefaultDeviceStrategy) ShouldRateLimit(context context.Context, code string) bool { +// ShouldRateLimit is used to decide whether a request should be rate-limited +func (h *DefaultDeviceStrategy) ShouldRateLimit(context context.Context, code string) bool { key := code + "_limiter" - if x, found := t.RateLimiterCache.Get(key); found { + if x, found := h.RateLimiterCache.Get(key); found { return !x.(*rate.Limiter).Allow() } rateLimiter := rate.NewLimiter( rate.Every( - t.Config.GetDeviceAuthTokenPollingInterval(context), + h.Config.GetDeviceAuthTokenPollingInterval(context), ), 1, ) - t.RateLimiterCache.Set(key, rateLimiter, cache.DefaultExpiration) + h.RateLimiterCache.Set(key, rateLimiter, cache.DefaultExpiration) return false } diff --git a/handler/rfc8628/token_handler.go b/handler/rfc8628/token_handler.go new file mode 100644 index 000000000..3e0c3c7d8 --- /dev/null +++ b/handler/rfc8628/token_handler.go @@ -0,0 +1,100 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package rfc8628 + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/ory/x/errorsx" + + "github.com/ory/fosite" + "github.com/ory/fosite/handler/oauth2" +) + +type DeviceCodeHandler struct { + DeviceRateLimitStrategy DeviceRateLimitStrategy + DeviceCodeStrategy DeviceCodeStrategy +} + +func (c DeviceCodeHandler) Code(ctx context.Context, requester fosite.AccessRequester) (code string, signature string, err error) { + code = requester.GetRequestForm().Get("device_code") + + if c.DeviceRateLimitStrategy.ShouldRateLimit(ctx, code) { + return "", "", errorsx.WithStack(fosite.ErrPollingRateLimited) + } + + signature, err = c.DeviceCodeStrategy.DeviceCodeSignature(ctx, code) + if err != nil { + return "", "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + return +} + +func (c DeviceCodeHandler) ValidateCode(ctx context.Context, requester fosite.AccessRequester, code string) error { + return c.DeviceCodeStrategy.ValidateDeviceCode(ctx, requester, code) +} + +type DeviceSessionHandler struct { + DeviceCodeStorage DeviceCodeStorage +} + +func (s DeviceSessionHandler) Session(ctx context.Context, requester fosite.AccessRequester, codeSignature string) (fosite.Requester, error) { + req, err := s.DeviceCodeStorage.GetDeviceCodeSession(ctx, codeSignature, requester.GetSession()) + + if err != nil && errors.Is(err, fosite.ErrInvalidatedDeviceCode) { + if req != nil { + return req, err + } + + return req, fosite.ErrServerError. + WithHint("Misconfigured code lead to an error that prohibited the OAuth 2.0 Framework from processing this request."). + WithDebug("\"GetDeviceCodeSession\" must return a value for \"fosite.Requester\" when returning \"ErrInvalidatedDeviceCode\".") + } + + if err != nil && errors.Is(err, fosite.ErrNotFound) { + return nil, errorsx.WithStack(fosite.ErrInvalidGrant.WithWrap(err).WithDebug(err.Error())) + } + + if err != nil { + return nil, errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + return req, err +} + +func (s DeviceSessionHandler) InvalidateSession(ctx context.Context, codeSignature string) error { + return s.DeviceCodeStorage.InvalidateDeviceCodeSession(ctx, codeSignature) +} + +type DeviceAccessRequestValidator struct{} + +func (v DeviceAccessRequestValidator) CanHandleRequest(requester fosite.AccessRequester) bool { + return requester.GetGrantTypes().ExactOne(string(fosite.GrantTypeDeviceCode)) +} + +func (v DeviceAccessRequestValidator) ValidateGrantTypes(requester fosite.AccessRequester) error { + if !requester.GetClient().GetGrantTypes().Has(string(fosite.GrantTypeDeviceCode)) { + return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"urn:ietf:params:oauth:grant-type:device_code\".")) + } + + return nil +} + +func (v DeviceAccessRequestValidator) ValidateRedirectURI(accessRequester fosite.AccessRequester, authorizeRequester fosite.Requester) error { + return nil +} + +type DeviceCodeTokenEndpointHandler struct { + oauth2.GenericCodeTokenEndpointHandler +} + +var ( + _ oauth2.AccessRequestValidator = (*DeviceAccessRequestValidator)(nil) + _ oauth2.CodeHandler = (*DeviceCodeHandler)(nil) + _ oauth2.SessionHandler = (*DeviceSessionHandler)(nil) + _ fosite.TokenEndpointHandler = (*DeviceCodeTokenEndpointHandler)(nil) +) diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go new file mode 100644 index 000000000..d3d76096a --- /dev/null +++ b/handler/rfc8628/token_handler_test.go @@ -0,0 +1,694 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package rfc8628 + +import ( + "context" + "fmt" + "net/url" + "testing" + "time" + + "github.com/pkg/errors" + + "github.com/golang/mock/gomock" + "github.com/ory/fosite/internal" + + "github.com/patrickmn/go-cache" + + "github.com/ory/fosite/handler/oauth2" + "github.com/ory/fosite/token/hmac" + + "github.com/ory/fosite" + "github.com/ory/fosite/storage" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var hmacshaStrategy = oauth2.NewHMACSHAStrategy( + &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, + &fosite.Config{ + AccessTokenLifespan: time.Hour * 24, + AuthorizeCodeLifespan: time.Hour * 24, + }, +) + +var RFC8628HMACSHAStrategy = DefaultDeviceStrategy{ + Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, + RateLimiterCache: cache.New( + time.Hour*12, + time.Hour*24, + ), + Config: &fosite.Config{ + DeviceAndUserCodeLifespan: time.Hour * 24, + }, +} + +func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { + for k, strategy := range map[string]struct { + oauth2.CoreStrategy + RFC8628CodeStrategy + }{ + "hmac": {hmacshaStrategy, &RFC8628HMACSHAStrategy}, + } { + t.Run("strategy="+k, func(t *testing.T) { + store := storage.NewMemoryStore() + + var h oauth2.GenericCodeTokenEndpointHandler + for _, c := range []struct { + areq *fosite.AccessRequest + description string + setup func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) + check func(t *testing.T, aresp *fosite.AccessResponse) + expectErr error + }{ + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"123"}, + }, + description: "should fail because not responsible", + expectErr: fosite.ErrUnknownRequest, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Form: url.Values{}, + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + }, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + description: "should fail because device code not found", + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + code, _, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + areq.Form.Set("device_code", code) + }, + expectErr: fosite.ErrServerError, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Form: url.Values{}, + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, + }, + GrantedScope: fosite.Arguments{"foo", "offline"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + code, sig, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + areq.Form.Add("device_code", code) + + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), sig, areq)) + }, + description: "should pass with offline scope and refresh token", + check: func(t *testing.T, aresp *fosite.AccessResponse) { + assert.NotEmpty(t, aresp.AccessToken) + assert.Equal(t, "bearer", aresp.TokenType) + assert.NotEmpty(t, aresp.GetExtra("refresh_token")) + assert.NotEmpty(t, aresp.GetExtra("expires_in")) + assert.Equal(t, "foo offline", aresp.GetExtra("scope")) + }, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Form: url.Values{}, + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, + }, + GrantedScope: fosite.Arguments{"foo"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + config.RefreshTokenScopes = []string{} + code, sig, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + areq.Form.Add("device_code", code) + + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), sig, areq)) + }, + description: "should pass with refresh token always provided", + check: func(t *testing.T, aresp *fosite.AccessResponse) { + assert.NotEmpty(t, aresp.AccessToken) + assert.Equal(t, "bearer", aresp.TokenType) + assert.NotEmpty(t, aresp.GetExtra("refresh_token")) + assert.NotEmpty(t, aresp.GetExtra("expires_in")) + assert.Equal(t, "foo", aresp.GetExtra("scope")) + }, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Form: url.Values{}, + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + }, + GrantedScope: fosite.Arguments{}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + config.RefreshTokenScopes = []string{} + code, sig, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + areq.Form.Add("device_code", code) + + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), sig, areq)) + }, + description: "should pass with no refresh token", + check: func(t *testing.T, aresp *fosite.AccessResponse) { + assert.NotEmpty(t, aresp.AccessToken) + assert.Equal(t, "bearer", aresp.TokenType) + assert.Empty(t, aresp.GetExtra("refresh_token")) + assert.NotEmpty(t, aresp.GetExtra("expires_in")) + assert.Empty(t, aresp.GetExtra("scope")) + }, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Form: url.Values{}, + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + }, + GrantedScope: fosite.Arguments{"foo"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + code, sig, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + areq.Form.Add("device_code", code) + + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), sig, areq)) + }, + description: "should not have refresh token", + check: func(t *testing.T, aresp *fosite.AccessResponse) { + assert.NotEmpty(t, aresp.AccessToken) + assert.Equal(t, "bearer", aresp.TokenType) + assert.Empty(t, aresp.GetExtra("refresh_token")) + assert.NotEmpty(t, aresp.GetExtra("expires_in")) + assert.Equal(t, "foo", aresp.GetExtra("scope")) + }, + }, + } { + t.Run("case="+c.description, func(t *testing.T) { + config := &fosite.Config{ + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + AccessTokenLifespan: time.Minute, + RefreshTokenScopes: []string{"offline"}, + } + h = oauth2.GenericCodeTokenEndpointHandler{ + AccessRequestValidator: &DeviceAccessRequestValidator{}, + CodeHandler: &DeviceCodeHandler{ + DeviceRateLimitStrategy: strategy, + DeviceCodeStrategy: strategy, + }, + SessionHandler: &DeviceSessionHandler{ + DeviceCodeStorage: store, + }, + AccessTokenStrategy: strategy.CoreStrategy, + RefreshTokenStrategy: strategy.CoreStrategy, + Config: config, + CoreStorage: store, + TokenRevocationStorage: store, + } + + if c.setup != nil { + c.setup(t, c.areq, config) + } + + aresp := fosite.NewAccessResponse() + err := h.PopulateTokenEndpointResponse(context.TODO(), c.areq, aresp) + + if c.expectErr != nil { + require.EqualError(t, err, c.expectErr.Error(), "%+v", err) + } else { + require.NoError(t, err, "%+v", err) + } + + if c.check != nil { + c.check(t, aresp) + } + }) + } + }) + } +} + +func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { + for k, strategy := range map[string]struct { + oauth2.CoreStrategy + RFC8628CodeStrategy + }{ + "hmac": {hmacshaStrategy, &RFC8628HMACSHAStrategy}, + } { + t.Run("strategy="+k, func(t *testing.T) { + store := storage.NewMemoryStore() + + h := oauth2.GenericCodeTokenEndpointHandler{ + AccessRequestValidator: &DeviceAccessRequestValidator{}, + CodeHandler: &DeviceCodeHandler{ + DeviceRateLimitStrategy: strategy, + DeviceCodeStrategy: strategy, + }, + SessionHandler: &DeviceSessionHandler{ + DeviceCodeStorage: store, + }, + CoreStorage: store, + AccessTokenStrategy: strategy.CoreStrategy, + RefreshTokenStrategy: strategy.CoreStrategy, + Config: &fosite.Config{ + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + AuthorizeCodeLifespan: time.Minute, + }, + } + for i, c := range []struct { + areq *fosite.AccessRequest + authreq *fosite.DeviceRequest + description string + setup func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) + check func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) + expectErr error + }{ + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"12345678"}, + }, + description: "should fail because not responsible", + expectErr: fosite.ErrUnknownRequest, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{""}}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + description: "should fail because client is not granted this grant type", + expectErr: fosite.ErrUnauthorizedClient, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Client: &fosite.DefaultClient{GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + description: "should fail because device code could not be retrieved", + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + deviceCode, _, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + areq.Form = url.Values{"device_code": {deviceCode}} + }, + expectErr: fosite.ErrInvalidGrant, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Form: url.Values{"device_code": {"AAAA"}}, + Client: &fosite.DefaultClient{GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + description: "should fail because device code validation failed", + expectErr: fosite.ErrInvalidGrant, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "bar"}, + RequestedScope: fosite.Arguments{"a", "b"}, + }, + }, + description: "should fail because client mismatch", + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + token, signature, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + areq.Form = url.Values{"device_code": {token}} + + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + }, + expectErr: fosite.ErrInvalidGrant, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + Session: &fosite.DefaultSession{}, + RequestedScope: fosite.Arguments{"a", "b"}, + RequestedAt: time.Now().UTC(), + }, + }, + description: "should pass", + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + token, signature, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + + areq.Form = url.Values{"device_code": {token}} + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + }, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Form: url.Values{}, + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + }, + GrantedScope: fosite.Arguments{"foo", "offline"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + check: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + assert.Equal(t, time.Now().Add(time.Minute).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.AccessToken)) + assert.Equal(t, time.Now().Add(time.Minute).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.RefreshToken)) + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + code, sig, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + areq.Form.Add("device_code", code) + areq.GetSession().SetExpiresAt(fosite.DeviceCode, time.Now().Add(-time.Hour).UTC().Round(time.Second)) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), sig, areq)) + }, + description: "should fail because device code has expired", + expectErr: fosite.ErrDeviceExpiredToken, + }, + } { + t.Run(fmt.Sprintf("case=%d/description=%s", i, c.description), func(t *testing.T) { + if c.setup != nil { + c.setup(t, c.areq, c.authreq) + } + + t.Logf("Processing %+v", c.areq.Client) + + err := h.HandleTokenEndpointRequest(context.Background(), c.areq) + if c.expectErr != nil { + require.EqualError(t, err, c.expectErr.Error(), "%+v", err) + } else { + require.NoError(t, err, "%+v", err) + if c.check != nil { + c.check(t, c.areq, c.authreq) + } + } + }) + } + }) + } +} + +func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { + var mockTransactional *internal.MockTransactional + var mockCoreStore *internal.MockCoreStorage + var mockDeviceCodeStore *internal.MockDeviceCodeStorage + var mockDeviceRateLimitStrategy *internal.MockDeviceRateLimitStrategy + strategy := hmacshaStrategy + deviceStrategy := RFC8628HMACSHAStrategy + request := &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, + }, + GrantedScope: fosite.Arguments{"offline"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + } + token, _, err := deviceStrategy.GenerateDeviceCode(context.Background()) + require.NoError(t, err) + request.Form = url.Values{"device_code": {token}} + response := fosite.NewAccessResponse() + propagatedContext := context.Background() + + // some storage implementation that has support for transactions, notice the embedded type `storage.Transactional` + type coreTransactionalStore struct { + storage.Transactional + oauth2.CoreStorage + } + + type deviceTransactionalStore struct { + storage.Transactional + DeviceCodeStorage + } + + for _, testCase := range []struct { + description string + setup func() + expectError error + }{ + { + description: "transaction should be committed successfully if no errors occur", + setup: func() { + mockDeviceCodeStore. + EXPECT(). + GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). + Return(request, nil). + Times(1) + mockTransactional. + EXPECT(). + BeginTX(propagatedContext). + Return(propagatedContext, nil) + mockDeviceCodeStore. + EXPECT(). + InvalidateDeviceCodeSession(gomock.Any(), gomock.Any()). + Return(nil). + Times(1) + mockCoreStore. + EXPECT(). + CreateAccessTokenSession(propagatedContext, gomock.Any(), gomock.Any()). + Return(nil). + Times(1) + mockCoreStore. + EXPECT(). + CreateRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any(), gomock.Any()). + Return(nil). + Times(1) + mockTransactional. + EXPECT(). + Commit(propagatedContext). + Return(nil). + Times(1) + }, + }, + { + description: "transaction should be rolled back if `InvalidateDeviceCodeSession` returns an error", + setup: func() { + mockDeviceCodeStore. + EXPECT(). + GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). + Return(request, nil). + Times(1) + mockTransactional. + EXPECT(). + BeginTX(propagatedContext). + Return(propagatedContext, nil) + mockDeviceCodeStore. + EXPECT(). + InvalidateDeviceCodeSession(gomock.Any(), gomock.Any()). + Return(errors.New("Whoops, a nasty database error occurred!")). + Times(1) + mockTransactional. + EXPECT(). + Rollback(propagatedContext). + Return(nil). + Times(1) + }, + expectError: fosite.ErrServerError, + }, + { + description: "transaction should be rolled back if `CreateAccessTokenSession` returns an error", + setup: func() { + mockDeviceCodeStore. + EXPECT(). + GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). + Return(request, nil). + Times(1) + mockTransactional. + EXPECT(). + BeginTX(propagatedContext). + Return(propagatedContext, nil) + mockDeviceCodeStore. + EXPECT(). + InvalidateDeviceCodeSession(gomock.Any(), gomock.Any()). + Return(nil). + Times(1) + mockCoreStore. + EXPECT(). + CreateAccessTokenSession(propagatedContext, gomock.Any(), gomock.Any()). + Return(errors.New("Whoops, a nasty database error occurred!")). + Times(1) + mockTransactional. + EXPECT(). + Rollback(propagatedContext). + Return(nil). + Times(1) + }, + expectError: fosite.ErrServerError, + }, + { + description: "should result in a server error if transaction cannot be created", + setup: func() { + mockDeviceCodeStore. + EXPECT(). + GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). + Return(request, nil). + Times(1) + mockTransactional. + EXPECT(). + BeginTX(propagatedContext). + Return(nil, errors.New("Whoops, unable to create transaction!")) + }, + expectError: fosite.ErrServerError, + }, + { + description: "should result in a server error if transaction cannot be rolled back", + setup: func() { + mockDeviceCodeStore. + EXPECT(). + GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). + Return(request, nil). + Times(1) + mockTransactional. + EXPECT(). + BeginTX(propagatedContext). + Return(propagatedContext, nil) + mockDeviceCodeStore. + EXPECT(). + InvalidateDeviceCodeSession(gomock.Any(), gomock.Any()). + Return(errors.New("Whoops, a nasty database error occurred!")). + Times(1) + mockTransactional. + EXPECT(). + Rollback(propagatedContext). + Return(errors.New("Whoops, unable to rollback transaction!")). + Times(1) + }, + expectError: fosite.ErrServerError, + }, + { + description: "should result in a server error if transaction cannot be committed", + setup: func() { + mockDeviceCodeStore. + EXPECT(). + GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). + Return(request, nil). + Times(1) + mockTransactional. + EXPECT(). + BeginTX(propagatedContext). + Return(propagatedContext, nil) + mockDeviceCodeStore. + EXPECT(). + InvalidateDeviceCodeSession(gomock.Any(), gomock.Any()). + Return(nil). + Times(1) + mockCoreStore. + EXPECT(). + CreateAccessTokenSession(propagatedContext, gomock.Any(), gomock.Any()). + Return(nil). + Times(1) + mockCoreStore. + EXPECT(). + CreateRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any(), gomock.Any()). + Return(nil). + Times(1) + mockTransactional. + EXPECT(). + Commit(propagatedContext). + Return(errors.New("Whoops, unable to commit transaction!")). + Times(1) + mockTransactional. + EXPECT(). + Rollback(propagatedContext). + Return(nil). + Times(1) + }, + expectError: fosite.ErrServerError, + }, + } { + t.Run(fmt.Sprintf("scenario=%s", testCase.description), func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockTransactional = internal.NewMockTransactional(ctrl) + mockCoreStore = internal.NewMockCoreStorage(ctrl) + mockDeviceCodeStore = internal.NewMockDeviceCodeStorage(ctrl) + mockDeviceRateLimitStrategy = internal.NewMockDeviceRateLimitStrategy(ctrl) + mockDeviceRateLimitStrategy.EXPECT().ShouldRateLimit(gomock.Any(), gomock.Any()).Return(false).Times(1) + testCase.setup() + + handler := oauth2.GenericCodeTokenEndpointHandler{ + AccessRequestValidator: &DeviceAccessRequestValidator{}, + CodeHandler: &DeviceCodeHandler{ + DeviceRateLimitStrategy: mockDeviceRateLimitStrategy, + DeviceCodeStrategy: &deviceStrategy, + }, + SessionHandler: &DeviceSessionHandler{ + DeviceCodeStorage: deviceTransactionalStore{ + mockTransactional, + mockDeviceCodeStore, + }, + }, + CoreStorage: coreTransactionalStore{ + mockTransactional, + mockCoreStore, + }, + AccessTokenStrategy: strategy, + RefreshTokenStrategy: strategy, + Config: &fosite.Config{ + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + DeviceAndUserCodeLifespan: time.Minute, + }, + } + + if err = handler.PopulateTokenEndpointResponse(propagatedContext, request, response); testCase.expectError != nil { + assert.EqualError(t, err, testCase.expectError.Error()) + } + }) + } +} diff --git a/integration/authorize_code_grant_public_client_pkce_test.go b/integration/authorize_code_grant_public_client_pkce_test.go index 74426daed..14d852547 100644 --- a/integration/authorize_code_grant_public_client_pkce_test.go +++ b/integration/authorize_code_grant_public_client_pkce_test.go @@ -32,7 +32,7 @@ func runAuthorizeCodeGrantWithPublicClientAndPKCETest(t *testing.T, strategy int c := new(fosite.Config) c.EnforcePKCE = true c.EnablePKCEPlainChallengeMethod = true - f := compose.Compose(c, fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2PKCEFactory, compose.OAuth2TokenIntrospectionFactory) + f := compose.Compose(c, fositeStore, strategy, compose.OAuth2AuthorizeExplicitAuthFactory, compose.Oauth2AuthorizeExplicitTokenFactory, compose.OAuth2PKCEFactory, compose.OAuth2TokenIntrospectionFactory) ts := mockServer(t, f, &fosite.DefaultSession{}) defer ts.Close() diff --git a/integration/authorize_code_grant_public_client_test.go b/integration/authorize_code_grant_public_client_test.go index 24d8d64bd..6a517365c 100644 --- a/integration/authorize_code_grant_public_client_test.go +++ b/integration/authorize_code_grant_public_client_test.go @@ -27,7 +27,7 @@ func TestAuthorizeCodeFlowWithPublicClient(t *testing.T) { } func runAuthorizeCodeGrantWithPublicClientTest(t *testing.T, strategy interface{}) { - f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2TokenIntrospectionFactory) + f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitAuthFactory, compose.Oauth2AuthorizeExplicitTokenFactory, compose.OAuth2TokenIntrospectionFactory) ts := mockServer(t, f, &fosite.DefaultSession{Subject: "foo-sub"}) defer ts.Close() diff --git a/integration/authorize_code_grant_test.go b/integration/authorize_code_grant_test.go index 13a663c7a..9ddb02cc8 100644 --- a/integration/authorize_code_grant_test.go +++ b/integration/authorize_code_grant_test.go @@ -38,7 +38,7 @@ func TestAuthorizeCodeFlowDupeCode(t *testing.T) { } func runAuthorizeCodeGrantTest(t *testing.T, strategy interface{}) { - f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2TokenIntrospectionFactory) + f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitAuthFactory, compose.Oauth2AuthorizeExplicitTokenFactory, compose.OAuth2TokenIntrospectionFactory) ts := mockServer(t, f, &openid.DefaultSession{Subject: "foo-sub"}) defer ts.Close() @@ -148,7 +148,7 @@ func runAuthorizeCodeGrantTest(t *testing.T, strategy interface{}) { } func runAuthorizeCodeGrantDupeCodeTest(t *testing.T, strategy interface{}) { - f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2TokenIntrospectionFactory) + f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitAuthFactory, compose.Oauth2AuthorizeExplicitTokenFactory, compose.OAuth2TokenIntrospectionFactory) ts := mockServer(t, f, &fosite.DefaultSession{}) defer ts.Close() diff --git a/integration/authorize_device_grant_request_test.go b/integration/authorize_device_grant_request_test.go index 2deb30678..14b1d134f 100644 --- a/integration/authorize_device_grant_request_test.go +++ b/integration/authorize_device_grant_request_test.go @@ -6,7 +6,6 @@ package integration_test import ( "context" "fmt" - "net/url" "testing" "github.com/ory/fosite" @@ -25,6 +24,7 @@ func TestDeviceFlow(t *testing.T) { hmacStrategy, } { runDeviceFlowTest(t, strategy) + runDeviceFlowAccessTokenTest(t, strategy) } } @@ -39,10 +39,12 @@ func runDeviceFlowTest(t *testing.T, strategy interface{}) { Username: "peteru", }, } - fc := new(fosite.Config) - fc.DeviceVerificationURL = "https://example.com/" - fc.RefreshTokenLifespan = -1 - fc.GlobalSecret = []byte("some-secret-thats-random-some-secret-thats-random-") + + fc := &fosite.Config{ + DeviceVerificationURL: "https://example.com/", + RefreshTokenLifespan: -1, + GlobalSecret: []byte("some-secret-thats-random-some-secret-thats-random-"), + } f := compose.ComposeAllEnabled(fc, fositeStore, gen.MustRSAKey()) ts := mockServer(t, f, session) defer ts.Close() @@ -59,9 +61,8 @@ func runDeviceFlowTest(t *testing.T, strategy interface{}) { description string setup func() err bool - client fosite.Client check func(t *testing.T, token *goauth.DeviceAuthResponse, err error) - params url.Values + cleanUp func() }{ { description: "should fail with invalid_grant", @@ -72,6 +73,9 @@ func runDeviceFlowTest(t *testing.T, strategy interface{}) { check: func(t *testing.T, token *goauth.DeviceAuthResponse, err error) { assert.ErrorContains(t, err, "invalid_grant") }, + cleanUp: func() { + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + }, }, { description: "should fail with invalid_scope", @@ -83,6 +87,10 @@ func runDeviceFlowTest(t *testing.T, strategy interface{}) { check: func(t *testing.T, token *goauth.DeviceAuthResponse, err error) { assert.ErrorContains(t, err, "invalid_scope") }, + cleanUp: func() { + oauthClient.Scopes = []string{} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).Scopes = []string{"fosite", "offline", "openid"} + }, }, { description: "should fail with invalid_client", @@ -93,6 +101,9 @@ func runDeviceFlowTest(t *testing.T, strategy interface{}) { check: func(t *testing.T, token *goauth.DeviceAuthResponse, err error) { assert.ErrorContains(t, err, "invalid_client") }, + cleanUp: func() { + oauthClient.ClientID = "device-client" + }, }, { description: "should pass", @@ -101,24 +112,6 @@ func runDeviceFlowTest(t *testing.T, strategy interface{}) { }, } { t.Run(fmt.Sprintf("case=%d description=%s", k, c.description), func(t *testing.T) { - // Restore client - fositeStore.Clients["device-client"] = &fosite.DefaultClient{ - ID: "device-client", - Secret: []byte(`$2a$10$IxMdI6d.LIRZPpSfEwNoeu4rY3FhDREsxFJXikcgdRRAStxUlsuEO`), // = "foobar" - GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, - Scopes: []string{"fosite", "offline", "openid"}, - Audience: []string{tokenURL}, - Public: true, - } - oauthClient = &goauth.Config{ - ClientID: "device-client", - ClientSecret: "foobar", - Endpoint: goauth.Endpoint{ - TokenURL: ts.URL + tokenRelativePath, - DeviceAuthURL: ts.URL + deviceAuthRelativePath, - }, - } - c.setup() resp, err := oauthClient.DeviceAuth(context.Background()) @@ -135,6 +128,123 @@ func runDeviceFlowTest(t *testing.T, strategy interface{}) { c.check(t, resp, err) } + if c.cleanUp != nil { + c.cleanUp() + } + + t.Logf("Passed test case %d", k) + }) + } +} + +func runDeviceFlowAccessTokenTest(t *testing.T, strategy interface{}) { + session := &defaultSession{ + DefaultSession: &openid.DefaultSession{ + Claims: &jwt.IDTokenClaims{ + Subject: "peter", + }, + Headers: &jwt.Headers{}, + Subject: "peter", + Username: "peteru", + }, + } + + fc := &fosite.Config{ + DeviceVerificationURL: "https://example.com/", + RefreshTokenLifespan: -1, + GlobalSecret: []byte("some-secret-thats-random-some-secret-thats-random-"), + DeviceAuthTokenPollingInterval: -1, + } + f := compose.ComposeAllEnabled(fc, fositeStore, gen.MustRSAKey()) + ts := mockServer(t, f, session) + defer ts.Close() + + oauthClient := &goauth.Config{ + ClientID: "device-client", + ClientSecret: "foobar", + Endpoint: goauth.Endpoint{ + TokenURL: ts.URL + tokenRelativePath, + DeviceAuthURL: ts.URL + deviceAuthRelativePath, + }, + } + resp, _ := oauthClient.DeviceAuth(context.Background()) + + for k, c := range []struct { + description string + setup func() + params []goauth.AuthCodeOption + err bool + check func(t *testing.T, token *goauth.Token, err error) + cleanUp func() + }{ + { + description: "should fail with invalid grant type", + setup: func() { + }, + params: []goauth.AuthCodeOption{goauth.SetAuthURLParam("grant_type", "invalid_grant_type")}, + err: true, + check: func(t *testing.T, token *goauth.Token, err error) { + assert.ErrorContains(t, err, "invalid_request") + }, + }, + { + description: "should fail with unauthorized client", + setup: func() { + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"authorization_code"} + }, + params: []goauth.AuthCodeOption{}, + err: true, + check: func(t *testing.T, token *goauth.Token, err error) { + assert.ErrorContains(t, err, "unauthorized_client") + }, + cleanUp: func() { + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + }, + }, + { + description: "should fail with invalid device code", + setup: func() {}, + params: []goauth.AuthCodeOption{goauth.SetAuthURLParam("device_code", "invalid_device_code")}, + err: true, + check: func(t *testing.T, token *goauth.Token, err error) { + assert.ErrorContains(t, err, "invalid_grant") + }, + }, + { + description: "should fail with invalid client id", + setup: func() { + oauthClient.ClientID = "invalid_client_id" + }, + err: true, + check: func(t *testing.T, token *goauth.Token, err error) { + assert.ErrorContains(t, err, "invalid_client") + }, + cleanUp: func() { + oauthClient.ClientID = "device-client" + }, + }, + { + description: "should pass", + setup: func() {}, + err: false, + }, + } { + t.Run(fmt.Sprintf("case=%d description=%s", k, c.description), func(t *testing.T) { + c.setup() + + token, err := oauthClient.DeviceAccessToken(context.Background(), resp, c.params...) + if !c.err { + assert.NotEmpty(t, token.AccessToken) + } + + if c.check != nil { + c.check(t, token, err) + } + + if c.cleanUp != nil { + c.cleanUp() + } + t.Logf("Passed test case %d", k) }) } diff --git a/integration/helper_setup_test.go b/integration/helper_setup_test.go index 0c6c0c971..432fe58ea 100644 --- a/integration/helper_setup_test.go +++ b/integration/helper_setup_test.go @@ -83,6 +83,14 @@ var fositeStore = &storage.MemoryStore{ Scopes: []string{"fosite", "offline", "openid"}, Audience: []string{tokenURL}, }, + "device-client": &fosite.DefaultClient{ + ID: "device-client", + Secret: []byte(`$2a$10$IxMdI6d.LIRZPpSfEwNoeu4rY3FhDREsxFJXikcgdRRAStxUlsuEO`), // = "foobar" + GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, + Scopes: []string{"fosite", "offline", "openid"}, + Audience: []string{tokenURL}, + Public: true, + }, }, Users: map[string]storage.MemoryUserRelation{ "peter": { @@ -190,16 +198,18 @@ var hmacStrategy = oauth2.NewHMACSHAStrategy( }, ) -var defaultRSAKey = gen.MustRSAKey() -var jwtStrategy = &oauth2.DefaultJWTStrategy{ - Signer: &jwt.DefaultSigner{ - GetPrivateKey: func(ctx context.Context) (interface{}, error) { - return defaultRSAKey, nil +var ( + defaultRSAKey = gen.MustRSAKey() + jwtStrategy = &oauth2.DefaultJWTStrategy{ + Signer: &jwt.DefaultSigner{ + GetPrivateKey: func(ctx context.Context) (interface{}, error) { + return defaultRSAKey, nil + }, }, - }, - Config: &fosite.Config{}, - HMACSHAStrategy: hmacStrategy, -} + Config: &fosite.Config{}, + HMACSHAStrategy: hmacStrategy, + } +) func mockServer(t *testing.T, f fosite.OAuth2Provider, session fosite.Session) *httptest.Server { router := mux.NewRouter() diff --git a/integration/pushed_authorize_code_grant_test.go b/integration/pushed_authorize_code_grant_test.go index 0d9a710d1..2aa9714a6 100644 --- a/integration/pushed_authorize_code_grant_test.go +++ b/integration/pushed_authorize_code_grant_test.go @@ -30,7 +30,7 @@ func TestPushedAuthorizeCodeFlow(t *testing.T) { } func runPushedAuthorizeCodeGrantTest(t *testing.T, strategy interface{}) { - f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2TokenIntrospectionFactory, compose.PushedAuthorizeHandlerFactory) + f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitAuthFactory, compose.Oauth2AuthorizeExplicitTokenFactory, compose.OAuth2TokenIntrospectionFactory, compose.PushedAuthorizeHandlerFactory) ts := mockServer(t, f, &fosite.DefaultSession{Subject: "foo-sub"}) defer ts.Close() diff --git a/internal/device_code_rate_limit_strategy.go b/internal/device_code_rate_limit_strategy.go new file mode 100644 index 000000000..3a3b49511 --- /dev/null +++ b/internal/device_code_rate_limit_strategy.go @@ -0,0 +1,52 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ory/fosite/handler/rfc8628 (interfaces: DeviceRateLimitStrategy) + +// Package internal is a generated GoMock package. +package internal + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockDeviceRateLimitStrategy is a mock of DeviceRateLimitStrategy interface. +type MockDeviceRateLimitStrategy struct { + ctrl *gomock.Controller + recorder *MockDeviceRateLimitStrategyMockRecorder +} + +// MockDeviceRateLimitStrategyMockRecorder is the mock recorder for MockDeviceRateLimitStrategy. +type MockDeviceRateLimitStrategyMockRecorder struct { + mock *MockDeviceRateLimitStrategy +} + +// NewMockDeviceRateLimitStrategy creates a new mock instance. +func NewMockDeviceRateLimitStrategy(ctrl *gomock.Controller) *MockDeviceRateLimitStrategy { + mock := &MockDeviceRateLimitStrategy{ctrl: ctrl} + mock.recorder = &MockDeviceRateLimitStrategyMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDeviceRateLimitStrategy) EXPECT() *MockDeviceRateLimitStrategyMockRecorder { + return m.recorder +} + +// ShouldRateLimit mocks base method. +func (m *MockDeviceRateLimitStrategy) ShouldRateLimit(arg0 context.Context, arg1 string) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ShouldRateLimit", arg0, arg1) + ret0, _ := ret[0].(bool) + return ret0 +} + +// ShouldRateLimit indicates an expected call of ShouldRateLimit. +func (mr *MockDeviceRateLimitStrategyMockRecorder) ShouldRateLimit(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldRateLimit", reflect.TypeOf((*MockDeviceRateLimitStrategy)(nil).ShouldRateLimit), arg0, arg1) +} diff --git a/internal/device_code_storage.go b/internal/device_code_storage.go new file mode 100644 index 000000000..c4eee24d9 --- /dev/null +++ b/internal/device_code_storage.go @@ -0,0 +1,82 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ory/fosite/handler/rfc8628 (interfaces: DeviceCodeStorage) + +// Package internal is a generated GoMock package. +package internal + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + fosite "github.com/ory/fosite" +) + +// MockDeviceCodeStorage is a mock of DeviceCodeStorage interface. +type MockDeviceCodeStorage struct { + ctrl *gomock.Controller + recorder *MockDeviceCodeStorageMockRecorder +} + +// MockDeviceCodeStorageMockRecorder is the mock recorder for MockDeviceCodeStorage. +type MockDeviceCodeStorageMockRecorder struct { + mock *MockDeviceCodeStorage +} + +// NewMockDeviceCodeStorage creates a new mock instance. +func NewMockDeviceCodeStorage(ctrl *gomock.Controller) *MockDeviceCodeStorage { + mock := &MockDeviceCodeStorage{ctrl: ctrl} + mock.recorder = &MockDeviceCodeStorageMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDeviceCodeStorage) EXPECT() *MockDeviceCodeStorageMockRecorder { + return m.recorder +} + +// CreateDeviceCodeSession mocks base method. +func (m *MockDeviceCodeStorage) CreateDeviceCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateDeviceCodeSession", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateDeviceCodeSession indicates an expected call of CreateDeviceCodeSession. +func (mr *MockDeviceCodeStorageMockRecorder) CreateDeviceCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDeviceCodeSession", reflect.TypeOf((*MockDeviceCodeStorage)(nil).CreateDeviceCodeSession), arg0, arg1, arg2) +} + +// GetDeviceCodeSession mocks base method. +func (m *MockDeviceCodeStorage) GetDeviceCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDeviceCodeSession", arg0, arg1, arg2) + ret0, _ := ret[0].(fosite.Requester) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDeviceCodeSession indicates an expected call of GetDeviceCodeSession. +func (mr *MockDeviceCodeStorageMockRecorder) GetDeviceCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeviceCodeSession", reflect.TypeOf((*MockDeviceCodeStorage)(nil).GetDeviceCodeSession), arg0, arg1, arg2) +} + +// InvalidateDeviceCodeSession mocks base method. +func (m *MockDeviceCodeStorage) InvalidateDeviceCodeSession(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InvalidateDeviceCodeSession", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// InvalidateDeviceCodeSession indicates an expected call of InvalidateDeviceCodeSession. +func (mr *MockDeviceCodeStorageMockRecorder) InvalidateDeviceCodeSession(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateDeviceCodeSession", reflect.TypeOf((*MockDeviceCodeStorage)(nil).InvalidateDeviceCodeSession), arg0, arg1) +} diff --git a/oauth2.go b/oauth2.go index 1b4cb3d03..9fc689cd0 100644 --- a/oauth2.go +++ b/oauth2.go @@ -61,7 +61,7 @@ type OAuth2Provider interface { NewAuthorizeRequest(ctx context.Context, req *http.Request) (AuthorizeRequester, error) // NewAuthorizeResponse iterates through all response type handlers and returns their result or - // ErrUnsupportedResponseType if none of the handler's were able to handle it. + // ErrUnsupportedResponseType if none of the handlers were able to handle it. // // The following specs must be considered in any implementation of this method: // * https://tools.ietf.org/html/rfc6749#section-3.1.1 @@ -151,11 +151,11 @@ type OAuth2Provider interface { NewDeviceResponse(ctx context.Context, requester DeviceRequester, session Session) (DeviceResponder, error) // WriteDeviceResponse return to the user both codes and - // some configuration informations in a JSON formated manner + // some configuration information in a JSON formatted manner // // The following specs must be considered in any implementation of this method: // * https://www.rfc-editor.org/rfc/rfc8628#section-3.2 (everything MUST be implemented) - // Response is a HTTP response body using the + // Response is an HTTP response body using the // "application/json" format [RFC8259] with a 200 (OK) status code. WriteDeviceResponse(ctx context.Context, rw http.ResponseWriter, requester DeviceRequester, responder DeviceResponder) @@ -207,14 +207,14 @@ type IntrospectionResponder interface { // IsActive returns true if the introspected token is active and false otherwise. IsActive() bool - // AccessRequester returns nil when IsActive() is false and the original access request object otherwise. + // GetAccessRequester returns nil when IsActive() is false and the original access request object otherwise. GetAccessRequester() AccessRequester // GetTokenUse optionally returns the type of the token that was introspected. This could be "access_token", "refresh_token", // or if the type can not be determined an empty string. GetTokenUse() TokenUse - //GetAccessTokenType optionally returns the type of the access token that was introspected. This could be "bearer", "mac", + // GetAccessTokenType optionally returns the type of the access token that was introspected. This could be "bearer", "mac", // or empty string if the type of the token is refresh token. GetAccessTokenType() string } @@ -248,7 +248,7 @@ type Requester interface { // AppendRequestedScope appends a scope to the request. AppendRequestedScope(scope string) - // GetGrantScopes returns all granted scopes. + // GetGrantedScopes returns all granted scopes. GetGrantedScopes() (grantedScopes Arguments) // GetGrantedAudience returns all granted audiences. @@ -278,7 +278,7 @@ type Requester interface { // AccessRequester is a token endpoint's request context. type AccessRequester interface { - // GetGrantType returns the requests grant type. + // GetGrantTypes returns the requests grant type. GetGrantTypes() (grantTypes Arguments) Requester @@ -341,7 +341,7 @@ type AccessResponder interface { // SetTokenType set's the responses mandatory token type SetTokenType(tokenType string) - // SetAccessToken returns the responses access token. + // GetAccessToken returns the responses access token. GetAccessToken() (token string) // GetTokenType returns the responses token type. @@ -359,7 +359,7 @@ type AuthorizeResponder interface { // GetHeader returns the response's header GetHeader() (header http.Header) - // AddHeader adds an header key value pair to the response + // AddHeader adds a header key value pair to the response AddHeader(key, value string) // GetParameters returns the response's parameters @@ -383,7 +383,7 @@ type PushedAuthorizeResponder interface { // GetHeader returns the response's header GetHeader() (header http.Header) - // AddHeader adds an header key value pair to the response + // AddHeader adds a header key value pair to the response AddHeader(key, value string) // SetExtra sets a key value pair for the response. @@ -436,6 +436,6 @@ type DeviceResponder interface { // GetHeader returns the response's header GetHeader() (header http.Header) - // AddHeader adds an header key value pair to the response + // AddHeader adds a header key value pair to the response AddHeader(key, value string) } diff --git a/storage/memory.go b/storage/memory.go index dab15a373..e6a06b5cd 100644 --- a/storage/memory.go +++ b/storage/memory.go @@ -428,6 +428,7 @@ func (s *MemoryStore) GetPublicKey(ctx context.Context, issuer string, subject s return nil, fosite.ErrNotFound } + func (s *MemoryStore) GetPublicKeys(ctx context.Context, issuer string, subject string) (*jose.JSONWebKeySet, error) { s.issuerPublicKeysMutex.RLock() defer s.issuerPublicKeysMutex.RUnlock() From 044f494d47aba8bfafe6eae11af320a92efd6c78 Mon Sep 17 00:00:00 2001 From: dushu Date: Sat, 16 Mar 2024 21:12:30 -0600 Subject: [PATCH 11/36] fix: passing the correct authorization request when validating if the auth/device code is expired --- handler/oauth2/flow_authorize_code_token.go | 2 +- .../oauth2/flow_authorize_code_token_test.go | 157 +++++++++--------- handler/oauth2/flow_generic_code_token.go | 4 +- handler/rfc8628/token_handler.go | 2 +- handler/rfc8628/token_handler_test.go | 148 +++++++---------- 5 files changed, 140 insertions(+), 173 deletions(-) diff --git a/handler/oauth2/flow_authorize_code_token.go b/handler/oauth2/flow_authorize_code_token.go index e5a6b5534..d9c745578 100644 --- a/handler/oauth2/flow_authorize_code_token.go +++ b/handler/oauth2/flow_authorize_code_token.go @@ -25,7 +25,7 @@ func (c AuthorizeCodeHandler) Code(ctx context.Context, requester fosite.AccessR return code, signature, nil } -func (c AuthorizeCodeHandler) ValidateCode(ctx context.Context, requester fosite.AccessRequester, code string) error { +func (c AuthorizeCodeHandler) ValidateCode(ctx context.Context, requester fosite.Requester, code string) error { return c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, requester, code) } diff --git a/handler/oauth2/flow_authorize_code_token_test.go b/handler/oauth2/flow_authorize_code_token_test.go index cbf07c072..c39f5f85a 100644 --- a/handler/oauth2/flow_authorize_code_token_test.go +++ b/handler/oauth2/flow_authorize_code_token_test.go @@ -37,13 +37,14 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { expectErr error }{ { + description: "should fail because not responsible", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"123"}, }, - description: "should fail because not responsible", - expectErr: fosite.ErrUnknownRequest, + expectErr: fosite.ErrUnknownRequest, }, { + description: "should fail because authorization code cannot be retrieved", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ @@ -55,7 +56,6 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { RequestedAt: time.Now().UTC(), }, }, - description: "should fail because authcode not found", setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { code, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) @@ -64,6 +64,7 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { expectErr: fosite.ErrServerError, }, { + description: "should fail because authorization code is expired", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ @@ -71,17 +72,21 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { Client: &fosite.DefaultClient{ GrantTypes: fosite.Arguments{"authorization_code"}, }, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Session: &fosite.DefaultSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.AuthorizeCode: time.Now().Add(-time.Hour).UTC(), + }, + }, + RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), }, }, - description: "should fail because validation failed", setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), "bar", areq)) }, expectErr: fosite.ErrInvalidRequest, }, { + description: "should pass with offline scope and refresh token", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ @@ -95,13 +100,12 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { - code, sig, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) areq.Form.Add("code", code) - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, areq)) + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, areq)) }, - description: "should pass with offline scope and refresh token", check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) assert.Equal(t, "bearer", aresp.TokenType) @@ -111,6 +115,7 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { }, }, { + description: "should pass with refresh token always provided", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ @@ -125,13 +130,12 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { }, setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { config.RefreshTokenScopes = []string{} - code, sig, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) areq.Form.Add("code", code) - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, areq)) + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, areq)) }, - description: "should pass with refresh token always provided", check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) assert.Equal(t, "bearer", aresp.TokenType) @@ -141,36 +145,7 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { }, }, { - areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"authorization_code"}, - Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"authorization_code"}, - }, - GrantedScope: fosite.Arguments{}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), - }, - }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { - config.RefreshTokenScopes = []string{} - code, sig, err := strategy.GenerateAuthorizeCode(context.Background(), nil) - require.NoError(t, err) - areq.Form.Add("code", code) - - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, areq)) - }, - description: "should pass with no refresh token", - check: func(t *testing.T, aresp *fosite.AccessResponse) { - assert.NotEmpty(t, aresp.AccessToken) - assert.Equal(t, "bearer", aresp.TokenType) - assert.Empty(t, aresp.GetExtra("refresh_token")) - assert.NotEmpty(t, aresp.GetExtra("expires_in")) - assert.Empty(t, aresp.GetExtra("scope")) - }, - }, - { + description: "pass and response should not have refresh token", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ @@ -190,7 +165,6 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, areq)) }, - description: "should not have refresh token", check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) assert.Equal(t, "bearer", aresp.TokenType) @@ -267,21 +241,22 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { Config: config, } for i, c := range []struct { + description string areq *fosite.AccessRequest authreq *fosite.AuthorizeRequest - description string setup func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) check func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) expectErr error }{ { + description: "should fail because not responsible", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"12345678"}, }, - description: "should fail because not responsible", - expectErr: fosite.ErrUnknownRequest, + expectErr: fosite.ErrUnknownRequest, }, { + description: "should fail because client is not granted the correct grant type", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ @@ -290,10 +265,10 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { RequestedAt: time.Now().UTC(), }, }, - description: "should fail because client is not granted this grant type", - expectErr: fosite.ErrUnauthorizedClient, + expectErr: fosite.ErrUnauthorizedClient, }, { + description: "should fail because authorization code cannot be retrieved", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ @@ -302,7 +277,6 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { RequestedAt: time.Now().UTC(), }, }, - description: "should fail because authcode could not be retrieved (1)", setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { token, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) @@ -311,19 +285,38 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { expectErr: fosite.ErrInvalidGrant, }, { + description: "should fail because authorization code is expired", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ Form: url.Values{"code": {"foo.bar"}}, - Client: &fosite.DefaultClient{GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, - description: "should fail because authcode validation failed", - expectErr: fosite.ErrInvalidGrant, + authreq: &fosite.AuthorizeRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo"}, + Session: &fosite.DefaultSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.AuthorizeCode: time.Now().Add(-time.Hour).UTC(), + }, + }, + RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { + token, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + require.NoError(t, err) + areq.Form = url.Values{"code": {token}} + + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) + }, + expectErr: fosite.ErrTokenExpired, }, { + description: "should fail because client mismatch", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ @@ -334,11 +327,14 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "bar"}, - RequestedScope: fosite.Arguments{"a", "b"}, + Client: &fosite.DefaultClient{ID: "bar"}, + Session: &fosite.DefaultSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.AuthorizeCode: time.Now().Add(time.Hour).UTC(), + }, + }, }, }, - description: "should fail because client mismatch", setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { token, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) @@ -349,6 +345,7 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { expectErr: fosite.ErrInvalidGrant, }, { + description: "should fail because redirect uri was set during /authorize call, but not in /token call", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ @@ -359,12 +356,15 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, - Form: url.Values{"redirect_uri": []string{"request-redir"}}, - Session: &fosite.DefaultSession{}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, + Session: &fosite.DefaultSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.AuthorizeCode: time.Now().Add(time.Hour).UTC(), + }, + }, }, }, - description: "should fail because redirect uri was set during /authorize call, but not in /token call", setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { token, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) @@ -375,6 +375,7 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { expectErr: fosite.ErrInvalidGrant, }, { + description: "should pass", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ @@ -386,13 +387,11 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, - Session: &fosite.DefaultSession{}, - RequestedScope: fosite.Arguments{"a", "b"}, - RequestedAt: time.Now().UTC(), + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, - description: "should pass", setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { token, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) @@ -402,32 +401,32 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, }, { + description: "should fail because code has been used already", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"authorization_code"}, - }, - GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Form: url.Values{}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: fosite.Arguments{"authorization_code"}}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, - check: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - assert.Equal(t, time.Now().Add(time.Minute).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.AccessToken)) - assert.Equal(t, time.Now().Add(time.Minute).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.RefreshToken)) + authreq: &fosite.AuthorizeRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - code, sig, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) areq.Form.Add("code", code) - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, areq)) - require.NoError(t, store.InvalidateAuthorizeCodeSession(context.Background(), sig)) + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) + require.NoError(t, store.InvalidateAuthorizeCodeSession(context.Background(), signature)) }, - description: "should fail because code has been used already", - expectErr: fosite.ErrInvalidGrant, + expectErr: fosite.ErrInvalidGrant, }, } { t.Run(fmt.Sprintf("case=%d/description=%s", i, c.description), func(t *testing.T) { diff --git a/handler/oauth2/flow_generic_code_token.go b/handler/oauth2/flow_generic_code_token.go index 39c40422c..756507c2b 100644 --- a/handler/oauth2/flow_generic_code_token.go +++ b/handler/oauth2/flow_generic_code_token.go @@ -36,7 +36,7 @@ type CodeHandler interface { Code(ctx context.Context, requester fosite.AccessRequester) (code string, signature string, err error) // ValidateCode validates the code. - ValidateCode(ctx context.Context, requester fosite.AccessRequester, code string) error + ValidateCode(ctx context.Context, requester fosite.Requester, code string) error } // SessionHandler handles session-related operations. @@ -175,7 +175,7 @@ func (c *GenericCodeTokenEndpointHandler) HandleTokenEndpointRequest(ctx context return err } - if err = c.ValidateCode(ctx, requester, code); err != nil { + if err = c.ValidateCode(ctx, ar, code); err != nil { return errorsx.WithStack(err) } diff --git a/handler/rfc8628/token_handler.go b/handler/rfc8628/token_handler.go index 3e0c3c7d8..9279a3809 100644 --- a/handler/rfc8628/token_handler.go +++ b/handler/rfc8628/token_handler.go @@ -34,7 +34,7 @@ func (c DeviceCodeHandler) Code(ctx context.Context, requester fosite.AccessRequ return } -func (c DeviceCodeHandler) ValidateCode(ctx context.Context, requester fosite.AccessRequester, code string) error { +func (c DeviceCodeHandler) ValidateCode(ctx context.Context, requester fosite.Requester, code string) error { return c.DeviceCodeStrategy.ValidateDeviceCode(ctx, requester, code) } diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index d3d76096a..2bbbe4955 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -64,13 +64,14 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { expectErr error }{ { + description: "should fail because not responsible", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"123"}, }, - description: "should fail because not responsible", - expectErr: fosite.ErrUnknownRequest, + expectErr: fosite.ErrUnknownRequest, }, { + description: "should fail because device code cannot be retrieved", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ @@ -82,7 +83,6 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { RequestedAt: time.Now().UTC(), }, }, - description: "should fail because device code not found", setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { code, _, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) @@ -91,6 +91,7 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { expectErr: fosite.ErrServerError, }, { + description: "should pass with offline scope and refresh token", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ @@ -104,13 +105,12 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { - code, sig, err := strategy.GenerateDeviceCode(context.TODO()) + code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), sig, areq)) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) }, - description: "should pass with offline scope and refresh token", check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) assert.Equal(t, "bearer", aresp.TokenType) @@ -120,6 +120,7 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { }, }, { + description: "should pass with refresh token always provided", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ @@ -134,13 +135,12 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { }, setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { config.RefreshTokenScopes = []string{} - code, sig, err := strategy.GenerateDeviceCode(context.TODO()) + code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), sig, areq)) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) }, - description: "should pass with refresh token always provided", check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) assert.Equal(t, "bearer", aresp.TokenType) @@ -150,36 +150,7 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { }, }, { - areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, - Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, - }, - GrantedScope: fosite.Arguments{}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), - }, - }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { - config.RefreshTokenScopes = []string{} - code, sig, err := strategy.GenerateDeviceCode(context.TODO()) - require.NoError(t, err) - areq.Form.Add("device_code", code) - - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), sig, areq)) - }, - description: "should pass with no refresh token", - check: func(t *testing.T, aresp *fosite.AccessResponse) { - assert.NotEmpty(t, aresp.AccessToken) - assert.Equal(t, "bearer", aresp.TokenType) - assert.Empty(t, aresp.GetExtra("refresh_token")) - assert.NotEmpty(t, aresp.GetExtra("expires_in")) - assert.Empty(t, aresp.GetExtra("scope")) - }, - }, - { + description: "pass and response should not have refresh token", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ @@ -199,7 +170,6 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), sig, areq)) }, - description: "should not have refresh token", check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) assert.Equal(t, "bearer", aresp.TokenType) @@ -277,27 +247,28 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { AccessTokenStrategy: strategy.CoreStrategy, RefreshTokenStrategy: strategy.CoreStrategy, Config: &fosite.Config{ - ScopeStrategy: fosite.HierarchicScopeStrategy, - AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, - AuthorizeCodeLifespan: time.Minute, + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + DeviceAndUserCodeLifespan: time.Minute, }, } for i, c := range []struct { + description string areq *fosite.AccessRequest authreq *fosite.DeviceRequest - description string setup func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) check func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) expectErr error }{ { + description: "should fail because not responsible", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"12345678"}, }, - description: "should fail because not responsible", - expectErr: fosite.ErrUnknownRequest, + expectErr: fosite.ErrUnknownRequest, }, { + description: "should fail because client is not granted the correct grant type", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ @@ -306,10 +277,10 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { RequestedAt: time.Now().UTC(), }, }, - description: "should fail because client is not granted this grant type", - expectErr: fosite.ErrUnauthorizedClient, + expectErr: fosite.ErrUnauthorizedClient, }, { + description: "should fail because device code could not be retrieved", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ @@ -318,7 +289,6 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { RequestedAt: time.Now().UTC(), }, }, - description: "should fail because device code could not be retrieved", setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { deviceCode, _, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) @@ -327,19 +297,42 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { expectErr: fosite.ErrInvalidGrant, }, { + description: "should fail because device code has expired", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ - Form: url.Values{"device_code": {"AAAA"}}, - Client: &fosite.DefaultClient{GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Form: url.Values{}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + }, + GrantedScope: fosite.Arguments{"foo", "offline"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + Session: &fosite.DefaultSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), + }, + }, + RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), }, }, - description: "should fail because device code validation failed", - expectErr: fosite.ErrInvalidGrant, + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + code, signature, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + areq.Form.Add("device_code", code) + + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + }, + expectErr: fosite.ErrDeviceExpiredToken, }, { + description: "should fail because client mismatch", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ @@ -350,11 +343,14 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { }, authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "bar"}, - RequestedScope: fosite.Arguments{"a", "b"}, + Client: &fosite.DefaultClient{ID: "bar"}, + Session: &fosite.DefaultSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.DeviceCode: time.Now().Add(time.Hour).UTC(), + }, + }, }, }, - description: "should fail because client mismatch", setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { token, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) @@ -365,6 +361,7 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { expectErr: fosite.ErrInvalidGrant, }, { + description: "should pass", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ @@ -375,13 +372,11 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { }, authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, - Session: &fosite.DefaultSession{}, - RequestedScope: fosite.Arguments{"a", "b"}, - RequestedAt: time.Now().UTC(), + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, - description: "should pass", setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { token, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) @@ -390,33 +385,6 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) }, }, - { - areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, - Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, - }, - GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), - }, - }, - check: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { - assert.Equal(t, time.Now().Add(time.Minute).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.AccessToken)) - assert.Equal(t, time.Now().Add(time.Minute).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.RefreshToken)) - }, - setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { - code, sig, err := strategy.GenerateDeviceCode(context.TODO()) - require.NoError(t, err) - areq.Form.Add("device_code", code) - areq.GetSession().SetExpiresAt(fosite.DeviceCode, time.Now().Add(-time.Hour).UTC().Round(time.Second)) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), sig, areq)) - }, - description: "should fail because device code has expired", - expectErr: fosite.ErrDeviceExpiredToken, - }, } { t.Run(fmt.Sprintf("case=%d/description=%s", i, c.description), func(t *testing.T) { if c.setup != nil { From 027ada770d05070fe4c5abf9ff03d3f86d61cd4b Mon Sep 17 00:00:00 2001 From: dushu Date: Sun, 17 Mar 2024 18:31:06 -0600 Subject: [PATCH 12/36] feat: error handling for authorization pending in device flow --- handler/rfc8628/auth_handler.go | 2 +- handler/rfc8628/strategy_hmacsha.go | 79 +++++++++ handler/rfc8628/token_handler.go | 13 ++ handler/rfc8628/token_handler_test.go | 151 +++++++++++++----- .../authorize_device_grant_request_test.go | 47 ++---- 5 files changed, 217 insertions(+), 75 deletions(-) diff --git a/handler/rfc8628/auth_handler.go b/handler/rfc8628/auth_handler.go index 6d97da3aa..aa31ff520 100644 --- a/handler/rfc8628/auth_handler.go +++ b/handler/rfc8628/auth_handler.go @@ -36,7 +36,7 @@ func (d *DeviceAuthHandler) HandleDeviceEndpointRequest(ctx context.Context, dar } // Store the User Code session (this has no real data other that the user and device code), can be converted into a 'full' session after user auth - dar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx))) + dar.GetSession().SetExpiresAt(fosite.DeviceCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx))) if err := d.Storage.CreateDeviceCodeSession(ctx, deviceCodeSignature, dar.Sanitize(nil)); err != nil { return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go index 9c173f97a..d5f58d0c8 100644 --- a/handler/rfc8628/strategy_hmacsha.go +++ b/handler/rfc8628/strategy_hmacsha.go @@ -8,6 +8,8 @@ import ( "strings" "time" + "github.com/mohae/deepcopy" + "github.com/ory/x/errorsx" "github.com/ory/x/randx" @@ -18,6 +20,83 @@ import ( enigma "github.com/ory/fosite/token/hmac" ) +// DeviceFlowSession is a fosite.Session container specific for the device flow. +type DeviceFlowSession interface { + // BrowserFlowCompleted returns the flag indicating whether user has completed the browser flow or not. + BrowserFlowCompleted() bool + + // SetBrowserFlowCompleted allows client to mark user has completed the browser flow. + SetBrowserFlowCompleted(flag bool) + + fosite.Session +} + +// DefaultDeviceFlowSession is a DeviceFlowSession implementation for the device flow. +type DefaultDeviceFlowSession struct { + ExpiresAt map[fosite.TokenType]time.Time `json:"expires_at"` + Username string `json:"username"` + Subject string `json:"subject"` + Extra map[string]interface{} `json:"extra"` + BrowserFlowCompleted bool `json:"browser_flow_completed"` +} + +func (s *DefaultDeviceFlowSession) SetExpiresAt(key fosite.TokenType, exp time.Time) { + if s.ExpiresAt == nil { + s.ExpiresAt = make(map[fosite.TokenType]time.Time) + } + s.ExpiresAt[key] = exp +} + +func (s *DefaultDeviceFlowSession) GetExpiresAt(key fosite.TokenType) time.Time { + if s.ExpiresAt == nil { + s.ExpiresAt = make(map[fosite.TokenType]time.Time) + } + + if _, ok := s.ExpiresAt[key]; !ok { + return time.Time{} + } + return s.ExpiresAt[key] +} + +func (s *DefaultDeviceFlowSession) GetUsername() string { + if s == nil { + return "" + } + return s.Username +} + +func (s *DefaultDeviceFlowSession) SetSubject(subject string) { + s.Subject = subject +} + +func (s *DefaultDeviceFlowSession) GetSubject() string { + if s == nil { + return "" + } + + return s.Subject +} + +func (s *DefaultDeviceFlowSession) Clone() fosite.Session { + if s == nil { + return nil + } + + return deepcopy.Copy(s).(fosite.Session) +} + +func (s *DefaultDeviceFlowSession) GetBrowserFlowCompleted() bool { + if s == nil { + return false + } + + return s.BrowserFlowCompleted +} + +func (s *DefaultDeviceFlowSession) SetBrowserFlowCompleted(flag bool) { + s.BrowserFlowCompleted = flag +} + // DefaultDeviceStrategy implements the default device strategy type DefaultDeviceStrategy struct { Enigma *enigma.HMACStrategy diff --git a/handler/rfc8628/token_handler.go b/handler/rfc8628/token_handler.go index 9279a3809..dd71a7e83 100644 --- a/handler/rfc8628/token_handler.go +++ b/handler/rfc8628/token_handler.go @@ -55,6 +55,10 @@ func (s DeviceSessionHandler) Session(ctx context.Context, requester fosite.Acce WithDebug("\"GetDeviceCodeSession\" must return a value for \"fosite.Requester\" when returning \"ErrInvalidatedDeviceCode\".") } + if err != nil && errors.Is(err, fosite.ErrAuthorizationPending) { + return nil, err + } + if err != nil && errors.Is(err, fosite.ErrNotFound) { return nil, errorsx.WithStack(fosite.ErrInvalidGrant.WithWrap(err).WithDebug(err.Error())) } @@ -63,6 +67,15 @@ func (s DeviceSessionHandler) Session(ctx context.Context, requester fosite.Acce return nil, errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } + session, ok := req.GetSession().(*DefaultDeviceFlowSession) + if !ok { + return nil, fosite.ErrServerError.WithHint("Wrong authorization request session.") + } + + if !session.GetBrowserFlowCompleted() { + return nil, fosite.ErrAuthorizationPending + } + return req, err } diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index 2bbbe4955..a6e1f7321 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -73,13 +73,13 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { { description: "should fail because device code cannot be retrieved", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, }, - Session: &fosite.DefaultSession{}, + Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, @@ -90,18 +90,47 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { }, expectErr: fosite.ErrServerError, }, + { + description: "should fail because device code is expired", + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + Request: fosite.Request{ + Form: url.Values{}, + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + }, + Session: &DefaultDeviceFlowSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), + }, + BrowserFlowCompleted: true, + }, + RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + code, signature, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + areq.Form.Add("device_code", code) + + require.NoError(t, store.CreateDeviceCodeSession(context.Background(), signature, areq)) + }, + expectErr: fosite.ErrInvalidRequest, + }, { description: "should pass with offline scope and refresh token", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode), string(fosite.GrantTypeRefreshToken)}, }, GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, + }, + RequestedAt: time.Now().UTC(), }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { @@ -122,15 +151,17 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { { description: "should pass with refresh token always provided", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode), string(fosite.GrantTypeRefreshToken)}, }, GrantedScope: fosite.Arguments{"foo"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, + }, + RequestedAt: time.Now().UTC(), }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { @@ -152,23 +183,25 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { { description: "pass and response should not have refresh token", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, }, GrantedScope: fosite.Arguments{"foo"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, + }, + RequestedAt: time.Now().UTC(), }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { - code, sig, err := strategy.GenerateDeviceCode(context.TODO()) + code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), sig, areq)) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) }, check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) @@ -270,10 +303,10 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because client is not granted the correct grant type", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{""}}, - Session: &fosite.DefaultSession{}, + Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, @@ -282,10 +315,10 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because device code could not be retrieved", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ - Client: &fosite.DefaultClient{GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, - Session: &fosite.DefaultSession{}, + Client: &fosite.DefaultClient{GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, @@ -296,28 +329,61 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { }, expectErr: fosite.ErrInvalidGrant, }, + { + description: "should fail because user has not completed the browser flow", + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + Request: fosite.Request{ + Form: url.Values{}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), + }, + BrowserFlowCompleted: false, + }, + RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + code, signature, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + areq.Form.Add("device_code", code) + + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + }, + expectErr: fosite.ErrAuthorizationPending, + }, { description: "should fail because device code has expired", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ ID: "foo", - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, }, GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &fosite.DefaultSession{}, + Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, - Session: &fosite.DefaultSession{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), }, + BrowserFlowCompleted: true, }, RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), }, @@ -334,20 +400,21 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because client mismatch", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, - Session: &fosite.DefaultSession{}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ Request: fosite.Request{ Client: &fosite.DefaultClient{ID: "bar"}, - Session: &fosite.DefaultSession{ + Session: &DefaultDeviceFlowSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.DeviceCode: time.Now().Add(time.Hour).UTC(), }, + BrowserFlowCompleted: true, }, }, }, @@ -363,17 +430,19 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should pass", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, - Session: &fosite.DefaultSession{}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, - Session: &fosite.DefaultSession{}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, + }, RequestedAt: time.Now().UTC(), }, }, @@ -416,14 +485,16 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { strategy := hmacshaStrategy deviceStrategy := RFC8628HMACSHAStrategy request := &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode), string(fosite.GrantTypeRefreshToken)}, }, GrantedScope: fosite.Arguments{"offline"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, + }, + RequestedAt: time.Now().UTC(), }, } token, _, err := deviceStrategy.GenerateDeviceCode(context.Background()) diff --git a/integration/authorize_device_grant_request_test.go b/integration/authorize_device_grant_request_test.go index 14b1d134f..170c906fa 100644 --- a/integration/authorize_device_grant_request_test.go +++ b/integration/authorize_device_grant_request_test.go @@ -8,37 +8,23 @@ import ( "fmt" "testing" + "github.com/ory/fosite/handler/rfc8628" + "github.com/ory/fosite" "github.com/ory/fosite/compose" - "github.com/ory/fosite/handler/oauth2" - "github.com/ory/fosite/handler/openid" "github.com/ory/fosite/internal/gen" - "github.com/ory/fosite/token/jwt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" goauth "golang.org/x/oauth2" ) func TestDeviceFlow(t *testing.T) { - for _, strategy := range []oauth2.AccessTokenStrategy{ - hmacStrategy, - } { - runDeviceFlowTest(t, strategy) - runDeviceFlowAccessTokenTest(t, strategy) - } + runDeviceFlowTest(t) + runDeviceFlowAccessTokenTest(t) } -func runDeviceFlowTest(t *testing.T, strategy interface{}) { - session := &defaultSession{ - DefaultSession: &openid.DefaultSession{ - Claims: &jwt.IDTokenClaims{ - Subject: "peter", - }, - Headers: &jwt.Headers{}, - Subject: "peter", - Username: "peteru", - }, - } +func runDeviceFlowTest(t *testing.T) { + session := &rfc8628.DefaultDeviceFlowSession{} fc := &fosite.Config{ DeviceVerificationURL: "https://example.com/", @@ -67,14 +53,14 @@ func runDeviceFlowTest(t *testing.T, strategy interface{}) { { description: "should fail with invalid_grant", setup: func() { - fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"authorization_code"} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{string(fosite.GrantTypeAuthorizationCode)} }, err: true, check: func(t *testing.T, token *goauth.DeviceAuthResponse, err error) { assert.ErrorContains(t, err, "invalid_grant") }, cleanUp: func() { - fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{string(fosite.GrantTypeDeviceCode)} }, }, { @@ -137,16 +123,9 @@ func runDeviceFlowTest(t *testing.T, strategy interface{}) { } } -func runDeviceFlowAccessTokenTest(t *testing.T, strategy interface{}) { - session := &defaultSession{ - DefaultSession: &openid.DefaultSession{ - Claims: &jwt.IDTokenClaims{ - Subject: "peter", - }, - Headers: &jwt.Headers{}, - Subject: "peter", - Username: "peteru", - }, +func runDeviceFlowAccessTokenTest(t *testing.T) { + session := &rfc8628.DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, } fc := &fosite.Config{ @@ -190,7 +169,7 @@ func runDeviceFlowAccessTokenTest(t *testing.T, strategy interface{}) { { description: "should fail with unauthorized client", setup: func() { - fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"authorization_code"} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{string(fosite.GrantTypeAuthorizationCode)} }, params: []goauth.AuthCodeOption{}, err: true, @@ -198,7 +177,7 @@ func runDeviceFlowAccessTokenTest(t *testing.T, strategy interface{}) { assert.ErrorContains(t, err, "unauthorized_client") }, cleanUp: func() { - fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{string(fosite.GrantTypeDeviceCode)} }, }, { From 88d7ee4b2e273d68a916c6671543659adc8ca866 Mon Sep 17 00:00:00 2001 From: dushu Date: Mon, 18 Mar 2024 09:32:39 -0600 Subject: [PATCH 13/36] test: reorganize the testcases --- .../oauth2/flow_authorize_code_token_test.go | 67 ++++++++++--------- handler/rfc8628/token_handler_test.go | 31 +++++---- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/handler/oauth2/flow_authorize_code_token_test.go b/handler/oauth2/flow_authorize_code_token_test.go index c39f5f85a..dd0f2a676 100644 --- a/handler/oauth2/flow_authorize_code_token_test.go +++ b/handler/oauth2/flow_authorize_code_token_test.go @@ -240,7 +240,8 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { TokenRevocationStorage: store, Config: config, } - for i, c := range []struct { + + testCases := []struct { description string areq *fosite.AccessRequest authreq *fosite.AuthorizeRequest @@ -258,7 +259,7 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because client is not granted the correct grant type", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"authorization_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, Request: fosite.Request{ Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{""}}, Session: &fosite.DefaultSession{}, @@ -270,9 +271,9 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because authorization code cannot be retrieved", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"authorization_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, Request: fosite.Request{ - Client: &fosite.DefaultClient{GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, @@ -287,10 +288,10 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because authorization code is expired", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"authorization_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, Request: fosite.Request{ Form: url.Values{"code": {"foo.bar"}}, - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, @@ -318,9 +319,9 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because client mismatch", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"authorization_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, @@ -347,16 +348,16 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because redirect uri was set during /authorize call, but not in /token call", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"authorization_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, Form: url.Values{"redirect_uri": []string{"request-redir"}}, Session: &fosite.DefaultSession{ ExpiresAt: map[fosite.TokenType]time.Time{ @@ -377,9 +378,9 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should pass", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"authorization_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, Form: url.Values{"redirect_uri": []string{"request-redir"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), @@ -387,7 +388,7 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, @@ -403,17 +404,17 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because code has been used already", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"authorization_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, Request: fosite.Request{ Form: url.Values{}, - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: fosite.Arguments{"authorization_code"}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, @@ -428,21 +429,23 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, expectErr: fosite.ErrInvalidGrant, }, - } { - t.Run(fmt.Sprintf("case=%d/description=%s", i, c.description), func(t *testing.T) { - if c.setup != nil { - c.setup(t, c.areq, c.authreq) + } + + for i, testCase := range testCases { + t.Run(fmt.Sprintf("case=%d/description=%s", i, testCase.description), func(t *testing.T) { + if testCase.setup != nil { + testCase.setup(t, testCase.areq, testCase.authreq) } - t.Logf("Processing %+v", c.areq.Client) + t.Logf("Processing %+v", testCase.areq.Client) - err := h.HandleTokenEndpointRequest(context.Background(), c.areq) - if c.expectErr != nil { - require.EqualError(t, err, c.expectErr.Error(), "%+v", err) + err := h.HandleTokenEndpointRequest(context.Background(), testCase.areq) + if testCase.expectErr != nil { + require.EqualError(t, err, testCase.expectErr.Error(), "%+v", err) } else { require.NoError(t, err, "%+v", err) - if c.check != nil { - c.check(t, c.areq, c.authreq) + if testCase.check != nil { + testCase.check(t, testCase.areq, testCase.authreq) } } }) @@ -457,10 +460,10 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { var mockAuthorizeStore *internal.MockAuthorizeCodeStorage strategy := hmacshaStrategy request := &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"authorization_code"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, Request: fosite.Request{ Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"authorization_code", "refresh_token"}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode), string(fosite.GrantTypeRefreshToken)}, }, GrantedScope: fosite.Arguments{"offline"}, Session: &fosite.DefaultSession{}, @@ -484,7 +487,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { AuthorizeCodeStorage } - for _, testCase := range []struct { + testCases := []struct { description string setup func() expectError error @@ -658,7 +661,9 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { }, expectError: fosite.ErrServerError, }, - } { + } + + for _, testCase := range testCases { t.Run(fmt.Sprintf("scenario=%s", testCase.description), func(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index a6e1f7321..903c758f7 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -285,7 +285,8 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { DeviceAndUserCodeLifespan: time.Minute, }, } - for i, c := range []struct { + + testCases := []struct { description string areq *fosite.AccessRequest authreq *fosite.DeviceRequest @@ -454,21 +455,23 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) }, }, - } { - t.Run(fmt.Sprintf("case=%d/description=%s", i, c.description), func(t *testing.T) { - if c.setup != nil { - c.setup(t, c.areq, c.authreq) + } + + for i, testCase := range testCases { + t.Run(fmt.Sprintf("case=%d/description=%s", i, testCase.description), func(t *testing.T) { + if testCase.setup != nil { + testCase.setup(t, testCase.areq, testCase.authreq) } - t.Logf("Processing %+v", c.areq.Client) + t.Logf("Processing %+v", testCase.areq.Client) - err := h.HandleTokenEndpointRequest(context.Background(), c.areq) - if c.expectErr != nil { - require.EqualError(t, err, c.expectErr.Error(), "%+v", err) + err := h.HandleTokenEndpointRequest(context.Background(), testCase.areq) + if testCase.expectErr != nil { + require.EqualError(t, err, testCase.expectErr.Error(), "%+v", err) } else { require.NoError(t, err, "%+v", err) - if c.check != nil { - c.check(t, c.areq, c.authreq) + if testCase.check != nil { + testCase.check(t, testCase.areq, testCase.authreq) } } }) @@ -514,7 +517,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { DeviceCodeStorage } - for _, testCase := range []struct { + testCases := []struct { description string setup func() expectError error @@ -688,7 +691,9 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { }, expectError: fosite.ErrServerError, }, - } { + } + + for _, testCase := range testCases { t.Run(fmt.Sprintf("scenario=%s", testCase.description), func(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() From 8ff61e7ad9b3813690c50c45b533f58b0e1fbe9d Mon Sep 17 00:00:00 2001 From: dushu Date: Tue, 19 Mar 2024 11:50:42 -0600 Subject: [PATCH 14/36] chore: resolve comments --- .../oauth2/flow_authorize_code_token_test.go | 62 ++++++++++--------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/handler/oauth2/flow_authorize_code_token_test.go b/handler/oauth2/flow_authorize_code_token_test.go index dd0f2a676..3ff30dd7f 100644 --- a/handler/oauth2/flow_authorize_code_token_test.go +++ b/handler/oauth2/flow_authorize_code_token_test.go @@ -29,7 +29,8 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { store := storage.NewMemoryStore() var h GenericCodeTokenEndpointHandler - for _, c := range []struct { + + testCases := []struct { areq *fosite.AccessRequest description string setup func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) @@ -173,8 +174,10 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { assert.Equal(t, "foo", aresp.GetExtra("scope")) }, }, - } { - t.Run("case="+c.description, func(t *testing.T) { + } + + for _, testCase := range testCases { + t.Run("case="+testCase.description, func(t *testing.T) { config := &fosite.Config{ ScopeStrategy: fosite.HierarchicScopeStrategy, AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, @@ -195,21 +198,21 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { Config: config, } - if c.setup != nil { - c.setup(t, c.areq, config) + if testCase.setup != nil { + testCase.setup(t, testCase.areq, config) } aresp := fosite.NewAccessResponse() - err := h.PopulateTokenEndpointResponse(context.Background(), c.areq, aresp) + err := h.PopulateTokenEndpointResponse(context.Background(), testCase.areq, aresp) - if c.expectErr != nil { - require.EqualError(t, err, c.expectErr.Error(), "%+v", err) + if testCase.expectErr != nil { + require.EqualError(t, err, testCase.expectErr.Error(), "%+v", err) } else { require.NoError(t, err, "%+v", err) } - if c.check != nil { - c.check(t, aresp) + if testCase.check != nil { + testCase.check(t, aresp) } }) } @@ -230,9 +233,8 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { } h := GenericCodeTokenEndpointHandler{ AccessRequestValidator: &AuthorizeExplicitGrantAccessRequestValidator{}, - CoreStorage: store, CodeHandler: &AuthorizeCodeHandler{ - AuthorizeCodeStrategy: hmacshaStrategy, + AuthorizeCodeStrategy: strategy, }, SessionHandler: &AuthorizeExplicitGrantSessionHandler{ AuthorizeCodeStorage: store, @@ -259,7 +261,7 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because client is not granted the correct grant type", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, + GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{""}}, Session: &fosite.DefaultSession{}, @@ -271,9 +273,9 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because authorization code cannot be retrieved", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, + GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, + Client: &fosite.DefaultClient{GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, @@ -288,10 +290,10 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because authorization code is expired", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, + GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ Form: url.Values{"code": {"foo.bar"}}, - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, @@ -319,9 +321,9 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because client mismatch", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, + GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, @@ -348,16 +350,16 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because redirect uri was set during /authorize call, but not in /token call", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, + GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Form: url.Values{"redirect_uri": []string{"request-redir"}}, Session: &fosite.DefaultSession{ ExpiresAt: map[fosite.TokenType]time.Time{ @@ -378,9 +380,9 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should pass", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, + GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Form: url.Values{"redirect_uri": []string{"request-redir"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), @@ -388,7 +390,7 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, @@ -404,17 +406,17 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because code has been used already", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, + GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ Form: url.Values{}, - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: fosite.Arguments{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, @@ -460,10 +462,10 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { var mockAuthorizeStore *internal.MockAuthorizeCodeStorage strategy := hmacshaStrategy request := &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, + GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode), string(fosite.GrantTypeRefreshToken)}, + GrantTypes: fosite.Arguments{"authorization_code", "refresh_token"}, }, GrantedScope: fosite.Arguments{"offline"}, Session: &fosite.DefaultSession{}, From f1a3568fd31a9b6ee04faf230a449c59719f6d6a Mon Sep 17 00:00:00 2001 From: dushu Date: Sat, 23 Mar 2024 18:09:11 -0600 Subject: [PATCH 15/36] fix: fix oauth2 core storage interface and device flow session type assertion --- handler/oauth2/flow_authorize_code_token_test.go | 2 +- handler/oauth2/storage.go | 1 + handler/rfc8628/strategy_hmacsha.go | 4 ++-- handler/rfc8628/token_handler.go | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/handler/oauth2/flow_authorize_code_token_test.go b/handler/oauth2/flow_authorize_code_token_test.go index 3ff30dd7f..c4c423b5b 100644 --- a/handler/oauth2/flow_authorize_code_token_test.go +++ b/handler/oauth2/flow_authorize_code_token_test.go @@ -31,8 +31,8 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { var h GenericCodeTokenEndpointHandler testCases := []struct { - areq *fosite.AccessRequest description string + areq *fosite.AccessRequest setup func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) check func(t *testing.T, aresp *fosite.AccessResponse) expectErr error diff --git a/handler/oauth2/storage.go b/handler/oauth2/storage.go index 58a581057..52c4c3b91 100644 --- a/handler/oauth2/storage.go +++ b/handler/oauth2/storage.go @@ -10,6 +10,7 @@ import ( ) type CoreStorage interface { + AuthorizeCodeStorage AccessTokenStorage RefreshTokenStorage } diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go index d5f58d0c8..d5064c99e 100644 --- a/handler/rfc8628/strategy_hmacsha.go +++ b/handler/rfc8628/strategy_hmacsha.go @@ -22,8 +22,8 @@ import ( // DeviceFlowSession is a fosite.Session container specific for the device flow. type DeviceFlowSession interface { - // BrowserFlowCompleted returns the flag indicating whether user has completed the browser flow or not. - BrowserFlowCompleted() bool + // GetBrowserFlowCompleted returns the flag indicating whether user has completed the browser flow or not. + GetBrowserFlowCompleted() bool // SetBrowserFlowCompleted allows client to mark user has completed the browser flow. SetBrowserFlowCompleted(flag bool) diff --git a/handler/rfc8628/token_handler.go b/handler/rfc8628/token_handler.go index dd71a7e83..4cb318834 100644 --- a/handler/rfc8628/token_handler.go +++ b/handler/rfc8628/token_handler.go @@ -67,7 +67,7 @@ func (s DeviceSessionHandler) Session(ctx context.Context, requester fosite.Acce return nil, errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } - session, ok := req.GetSession().(*DefaultDeviceFlowSession) + session, ok := req.GetSession().(DeviceFlowSession) if !ok { return nil, fosite.ErrServerError.WithHint("Wrong authorization request session.") } From 8a3cdd84d4a9d4ab59e978a280af4e9f0d4c0d1e Mon Sep 17 00:00:00 2001 From: Nikos Date: Thu, 28 Mar 2024 13:47:50 +0200 Subject: [PATCH 16/36] fix: implement rate limiting --- compose/compose_strategy.go | 11 +- errors.go | 8 +- go.mod | 3 +- go.sum | 7 +- handler/rfc8628/strategy.go | 2 +- handler/rfc8628/strategy_hmacsha.go | 81 +++- handler/rfc8628/strategy_hmacsha_test.go | 33 +- handler/rfc8628/token_handler.go | 7 +- handler/rfc8628/token_handler_test.go | 480 +++++++++++++---------- 9 files changed, 382 insertions(+), 250 deletions(-) diff --git a/compose/compose_strategy.go b/compose/compose_strategy.go index e0d700e5b..21550ab91 100644 --- a/compose/compose_strategy.go +++ b/compose/compose_strategy.go @@ -6,13 +6,13 @@ package compose import ( "context" + "github.com/coocood/freecache" "github.com/ory/fosite" "github.com/ory/fosite/handler/oauth2" "github.com/ory/fosite/handler/openid" "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 { @@ -55,11 +55,8 @@ 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: cache.New( - config.GetDeviceAndUserCodeLifespan(context.TODO()), - config.GetDeviceAndUserCodeLifespan(context.TODO())*2, - ), - Config: config, + Enigma: &hmac.HMACStrategy{Config: config}, + RateLimiterCache: freecache.NewCache(1024 * 1024), + Config: config, } } diff --git a/errors.go b/errors.go index 90b5c55e0..5e324fc55 100644 --- a/errors.go +++ b/errors.go @@ -213,11 +213,11 @@ var ( ErrorField: errAuthorizationPending, CodeField: http.StatusBadRequest, } - ErrPollingRateLimited = &RFC6749Error{ + ErrSlowDown = &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, + ErrorField: errSlowDown, + CodeField: http.StatusBadRequest, } ErrDeviceExpiredToken = &RFC6749Error{ DescriptionField: "The device_code has expired, and the device authorization session has concluded.", @@ -262,7 +262,7 @@ const ( errRegistrationNotSupportedName = "registration_not_supported" errJTIKnownName = "jti_known" errAuthorizationPending = "authorization_pending" - errPollingIntervalRateLimited = "polling_interval_rate_limited" + errSlowDown = "slow_down" errDeviceExpiredToken = "expired_token" ) diff --git a/go.mod b/go.mod index 02f905274..29edf5382 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,7 @@ module github.com/ory/fosite 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 v1.0.0 github.com/go-jose/go-jose/v3 v3.0.3 @@ -18,7 +19,6 @@ require ( github.com/ory/go-convenience v0.1.0 github.com/ory/x v0.0.677 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.9.0 github.com/tidwall/gjson v1.14.3 @@ -27,7 +27,6 @@ require ( golang.org/x/net v0.30.0 golang.org/x/oauth2 v0.23.0 golang.org/x/text v0.21.0 - golang.org/x/time v0.4.0 ) require ( diff --git a/go.sum b/go.sum index 7dbcf5d11..ccadcd0b0 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,7 @@ github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd3 github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/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.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -55,6 +56,8 @@ 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= @@ -334,8 +337,6 @@ github.com/ory/x v0.0.677 h1:ZulzE4EBhNBXNotWmGSmGsVNbgbZpIr4snMURRkski0= github.com/ory/x v0.0.677/go.mod h1:zJmnDtKje2FCP4EeFvRsKk94XXiqKCSGJMZcirAfhUs= github.com/parnurzeal/gorequest v0.2.15 h1:oPjDCsF5IkD4gUk6vIgsxYNaSgvAnIh1EJeROn3HdJU= github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE= -github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= -github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -673,8 +674,6 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= -golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= diff --git a/handler/rfc8628/strategy.go b/handler/rfc8628/strategy.go index 33900a20c..67ca28084 100644 --- a/handler/rfc8628/strategy.go +++ b/handler/rfc8628/strategy.go @@ -18,7 +18,7 @@ type RFC8628CodeStrategy interface { // DeviceRateLimitStrategy handles the rate limiting strategy type DeviceRateLimitStrategy interface { - ShouldRateLimit(ctx context.Context, code string) bool + ShouldRateLimit(ctx context.Context, code string) (bool, error) } // DeviceCodeStrategy handles the device_code strategy diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go index d5064c99e..bf8ae2a41 100644 --- a/handler/rfc8628/strategy_hmacsha.go +++ b/handler/rfc8628/strategy_hmacsha.go @@ -5,21 +5,23 @@ package rfc8628 import ( "context" + "encoding/json" "strings" "time" + "github.com/coocood/freecache" "github.com/mohae/deepcopy" "github.com/ory/x/errorsx" "github.com/ory/x/randx" - "github.com/patrickmn/go-cache" - "golang.org/x/time/rate" "github.com/ory/fosite" enigma "github.com/ory/fosite/token/hmac" ) +const POLLING_RATE_LIMITING_LEEWAY = 200 * time.Millisecond + // DeviceFlowSession is a fosite.Session container specific for the device flow. type DeviceFlowSession interface { // GetBrowserFlowCompleted returns the flag indicating whether user has completed the browser flow or not. @@ -100,7 +102,7 @@ func (s *DefaultDeviceFlowSession) SetBrowserFlowCompleted(flag bool) { // DefaultDeviceStrategy implements the default device strategy type DefaultDeviceStrategy struct { Enigma *enigma.HMACStrategy - RateLimiterCache *cache.Cache + RateLimiterCache *freecache.Cache Config interface { fosite.DeviceProvider fosite.DeviceAndUserCodeLifespanProvider @@ -173,20 +175,71 @@ 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 { +func (h *DefaultDeviceStrategy) ShouldRateLimit(context context.Context, code string) (bool, error) { key := code + "_limiter" - if x, found := h.RateLimiterCache.Get(key); found { - return !x.(*rate.Limiter).Allow() + 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())) - rateLimiter := rate.NewLimiter( - rate.Every( - h.Config.GetDeviceAuthTokenPollingInterval(context), - ), - 1, - ) + 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 +} - h.RateLimiterCache.Set(key, rateLimiter, cache.DefaultExpiration) - return false +func (h *DefaultDeviceStrategy) deserializeExpiration(b []byte) (*expirationTimer, error) { + timer := new(expirationTimer) + err := json.Unmarshal(b, timer) + return timer, err } diff --git a/handler/rfc8628/strategy_hmacsha_test.go b/handler/rfc8628/strategy_hmacsha_test.go index 1673ea4c4..40554cabd 100644 --- a/handler/rfc8628/strategy_hmacsha_test.go +++ b/handler/rfc8628/strategy_hmacsha_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "github.com/patrickmn/go-cache" + "github.com/coocood/freecache" "github.com/stretchr/testify/assert" "github.com/ory/fosite" @@ -21,7 +21,7 @@ import ( var hmacshaStrategy = DefaultDeviceStrategy{ Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, - RateLimiterCache: cache.New(24*time.Minute, 2*24*time.Minute), + RateLimiterCache: freecache.NewCache(16384 * 64), Config: &fosite.Config{ AccessTokenLifespan: time.Minute * 24, AuthorizeCodeLifespan: time.Minute * 24, @@ -113,17 +113,30 @@ func TestHMACDeviceCode(t *testing.T) { func TestRateLimit(t *testing.T) { t.Run("ratelimit no-wait", func(t *testing.T) { - hmacshaStrategy.RateLimiterCache.Flush() - assert.False(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) - assert.False(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) - assert.True(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) + 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.Flush() - assert.False(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) - assert.False(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) + hmacshaStrategy.RateLimiterCache.Clear() + b, err := hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA") + assert.NoError(t, err) + assert.False(t, b) time.Sleep(500 * time.Millisecond) - assert.False(t, hmacshaStrategy.ShouldRateLimit(context.TODO(), "AAA")) + 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 4cb318834..a8d0f8bbc 100644 --- a/handler/rfc8628/token_handler.go +++ b/handler/rfc8628/token_handler.go @@ -22,7 +22,12 @@ type DeviceCodeHandler struct { func (c DeviceCodeHandler) Code(ctx context.Context, requester fosite.AccessRequester) (code string, signature string, err error) { code = requester.GetRequestForm().Get("device_code") - if c.DeviceRateLimitStrategy.ShouldRateLimit(ctx, code) { + shouldRateLimit, err := c.DeviceRateLimitStrategy.ShouldRateLimit(ctx, code) + // TODO(nsklikas) : should we error out or just silently log it? + if err != nil { + return "", "", err + } + if shouldRateLimit { return "", "", errorsx.WithStack(fosite.ErrPollingRateLimited) } diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index 903c758f7..bf8169dc4 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -10,13 +10,12 @@ import ( "testing" "time" + "github.com/coocood/freecache" "github.com/pkg/errors" "github.com/golang/mock/gomock" "github.com/ory/fosite/internal" - "github.com/patrickmn/go-cache" - "github.com/ory/fosite/handler/oauth2" "github.com/ory/fosite/token/hmac" @@ -35,17 +34,14 @@ var hmacshaStrategy = oauth2.NewHMACSHAStrategy( ) var RFC8628HMACSHAStrategy = DefaultDeviceStrategy{ - Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, - RateLimiterCache: cache.New( - time.Hour*12, - time.Hour*24, - ), + Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, + RateLimiterCache: freecache.NewCache(16384 * 64), Config: &fosite.Config{ DeviceAndUserCodeLifespan: time.Hour * 24, }, } -func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { +func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { for k, strategy := range map[string]struct { oauth2.CoreStrategy RFC8628CodeStrategy @@ -55,201 +51,212 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { t.Run("strategy="+k, func(t *testing.T) { store := storage.NewMemoryStore() - var h oauth2.GenericCodeTokenEndpointHandler - for _, c := range []struct { - areq *fosite.AccessRequest + h := oauth2.GenericCodeTokenEndpointHandler{ + AccessRequestValidator: &DeviceAccessRequestValidator{}, + CodeHandler: &DeviceCodeHandler{ + DeviceRateLimitStrategy: strategy, + DeviceCodeStrategy: strategy, + }, + SessionHandler: &DeviceSessionHandler{ + DeviceCodeStorage: store, + }, + CoreStorage: store, + AccessTokenStrategy: strategy.CoreStrategy, + RefreshTokenStrategy: strategy.CoreStrategy, + Config: &fosite.Config{ + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + DeviceAndUserCodeLifespan: time.Minute, + }, + } + + testCases := []struct { description string - setup func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) - check func(t *testing.T, aresp *fosite.AccessResponse) + areq *fosite.AccessRequest + authreq *fosite.DeviceRequest + setup func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) + check func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) expectErr error }{ { description: "should fail because not responsible", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"123"}, + GrantTypes: fosite.Arguments{"12345678"}, }, expectErr: fosite.ErrUnknownRequest, }, { - description: "should fail because device code cannot be retrieved", + description: "should fail because client is not granted the correct grant type", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, - }, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{""}}, Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { - code, _, err := strategy.GenerateDeviceCode(context.TODO()) + expectErr: fosite.ErrUnauthorizedClient, + }, + { + description: "should fail because device code could not be retrieved", + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + Request: fosite.Request{ + Client: &fosite.DefaultClient{GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + deviceCode, _, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) - areq.Form.Set("device_code", code) + areq.Form = url.Values{"device_code": {deviceCode}} }, - expectErr: fosite.ErrServerError, + expectErr: fosite.ErrInvalidGrant, }, { - description: "should fail because device code is expired", + description: "should fail because user has not completed the browser flow", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, - }, + Form: url.Values{}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, Session: &DefaultDeviceFlowSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), }, - BrowserFlowCompleted: true, + BrowserFlowCompleted: false, }, RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.Background(), signature, areq)) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) }, - expectErr: fosite.ErrInvalidRequest, + expectErr: fosite.ErrAuthorizationPending, }, { - description: "should pass with offline scope and refresh token", + description: "should fail because device code has expired", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode), string(fosite.GrantTypeRefreshToken)}, + ID: "foo", + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, }, GrantedScope: fosite.Arguments{"foo", "offline"}, + Session: &DefaultDeviceFlowSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, Session: &DefaultDeviceFlowSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), + }, BrowserFlowCompleted: true, }, - RequestedAt: time.Now().UTC(), + RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) - }, - check: func(t *testing.T, aresp *fosite.AccessResponse) { - assert.NotEmpty(t, aresp.AccessToken) - assert.Equal(t, "bearer", aresp.TokenType) - assert.NotEmpty(t, aresp.GetExtra("refresh_token")) - assert.NotEmpty(t, aresp.GetExtra("expires_in")) - assert.Equal(t, "foo offline", aresp.GetExtra("scope")) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) }, + expectErr: fosite.ErrDeviceExpiredToken, }, { - description: "should pass with refresh token always provided", + description: "should fail because client mismatch", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode), string(fosite.GrantTypeRefreshToken)}, - }, - GrantedScope: fosite.Arguments{"foo"}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "bar"}, Session: &DefaultDeviceFlowSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.DeviceCode: time.Now().Add(time.Hour).UTC(), + }, BrowserFlowCompleted: true, }, - RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { - config.RefreshTokenScopes = []string{} - code, signature, err := strategy.GenerateDeviceCode(context.TODO()) + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + token, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) - areq.Form.Add("device_code", code) + areq.Form = url.Values{"device_code": {token}} - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) - }, - check: func(t *testing.T, aresp *fosite.AccessResponse) { - assert.NotEmpty(t, aresp.AccessToken) - assert.Equal(t, "bearer", aresp.TokenType) - assert.NotEmpty(t, aresp.GetExtra("refresh_token")) - assert.NotEmpty(t, aresp.GetExtra("expires_in")) - assert.Equal(t, "foo", aresp.GetExtra("scope")) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) }, + expectErr: fosite.ErrInvalidGrant, }, { - description: "pass and response should not have refresh token", + description: "should pass", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, - }, - GrantedScope: fosite.Arguments{"foo"}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, Session: &DefaultDeviceFlowSession{ BrowserFlowCompleted: true, }, RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { - code, signature, err := strategy.GenerateDeviceCode(context.TODO()) + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + token, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) - areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) - }, - check: func(t *testing.T, aresp *fosite.AccessResponse) { - assert.NotEmpty(t, aresp.AccessToken) - assert.Equal(t, "bearer", aresp.TokenType) - assert.Empty(t, aresp.GetExtra("refresh_token")) - assert.NotEmpty(t, aresp.GetExtra("expires_in")) - assert.Equal(t, "foo", aresp.GetExtra("scope")) + areq.Form = url.Values{"device_code": {token}} + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) }, }, - } { - t.Run("case="+c.description, func(t *testing.T) { - config := &fosite.Config{ - ScopeStrategy: fosite.HierarchicScopeStrategy, - AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, - AccessTokenLifespan: time.Minute, - RefreshTokenScopes: []string{"offline"}, - } - h = oauth2.GenericCodeTokenEndpointHandler{ - AccessRequestValidator: &DeviceAccessRequestValidator{}, - CodeHandler: &DeviceCodeHandler{ - DeviceRateLimitStrategy: strategy, - DeviceCodeStrategy: strategy, - }, - SessionHandler: &DeviceSessionHandler{ - DeviceCodeStorage: store, - }, - AccessTokenStrategy: strategy.CoreStrategy, - RefreshTokenStrategy: strategy.CoreStrategy, - Config: config, - CoreStorage: store, - TokenRevocationStorage: store, - } + } - if c.setup != nil { - c.setup(t, c.areq, config) + for i, testCase := range testCases { + t.Run(fmt.Sprintf("case=%d/description=%s", i, testCase.description), func(t *testing.T) { + if testCase.setup != nil { + testCase.setup(t, testCase.areq, testCase.authreq) } - aresp := fosite.NewAccessResponse() - err := h.PopulateTokenEndpointResponse(context.TODO(), c.areq, aresp) + t.Logf("Processing %+v", testCase.areq.Client) - if c.expectErr != nil { - require.EqualError(t, err, c.expectErr.Error(), "%+v", err) + err := h.HandleTokenEndpointRequest(context.Background(), testCase.areq) + if testCase.expectErr != nil { + require.EqualError(t, err, testCase.expectErr.Error(), "%+v", err) } else { require.NoError(t, err, "%+v", err) - } - - if c.check != nil { - c.check(t, aresp) + if testCase.check != nil { + testCase.check(t, testCase.areq, testCase.authreq) + } } }) } @@ -257,7 +264,7 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { } } -func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { +func TestDeviceUserCode_HandleTokenEndpointRequest_Ratelimitting(t *testing.T) { for k, strategy := range map[string]struct { oauth2.CoreStrategy RFC8628CodeStrategy @@ -285,194 +292,253 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { DeviceAndUserCodeLifespan: time.Minute, }, } + areq := &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + Request: fosite.Request{ + Form: url.Values{}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + }, + GrantedScope: fosite.Arguments{"foo", "offline"}, + Session: &DefaultDeviceFlowSession{}, + RequestedAt: time.Now().UTC(), + }, + } + authreq := &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, + }, + RequestedAt: time.Now().UTC(), + }, + } + + token, signature, err := strategy.GenerateDeviceCode(context.TODO()) + require.NoError(t, err) + + areq.Form = url.Values{"device_code": {token}} + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + err = h.HandleTokenEndpointRequest(context.Background(), areq) + require.NoError(t, err, "%+v", err) + err = h.HandleTokenEndpointRequest(context.Background(), areq) + require.Error(t, fosite.ErrPollingRateLimited, err) + time.Sleep(10 * time.Second) + err = h.HandleTokenEndpointRequest(context.Background(), areq) + require.NoError(t, err, "%+v", err) + }) + } +} + +func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { + for k, strategy := range map[string]struct { + oauth2.CoreStrategy + RFC8628CodeStrategy + }{ + "hmac": {hmacshaStrategy, &RFC8628HMACSHAStrategy}, + } { + t.Run("strategy="+k, func(t *testing.T) { + store := storage.NewMemoryStore() + + var h oauth2.GenericCodeTokenEndpointHandler testCases := []struct { - description string areq *fosite.AccessRequest - authreq *fosite.DeviceRequest - setup func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) - check func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) + description string + setup func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) + check func(t *testing.T, aresp *fosite.AccessResponse) expectErr error }{ { description: "should fail because not responsible", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"12345678"}, + GrantTypes: fosite.Arguments{"123"}, }, expectErr: fosite.ErrUnknownRequest, }, { - description: "should fail because client is not granted the correct grant type", - areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, - Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{""}}, - Session: &DefaultDeviceFlowSession{}, - RequestedAt: time.Now().UTC(), - }, - }, - expectErr: fosite.ErrUnauthorizedClient, - }, - { - description: "should fail because device code could not be retrieved", + description: "should fail because device code cannot be retrieved", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ - Client: &fosite.DefaultClient{GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Form: url.Values{}, + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + }, Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { - deviceCode, _, err := strategy.GenerateDeviceCode(context.TODO()) + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + code, _, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) - areq.Form = url.Values{"device_code": {deviceCode}} + areq.Form.Set("device_code", code) }, - expectErr: fosite.ErrInvalidGrant, + expectErr: fosite.ErrServerError, }, { - description: "should fail because user has not completed the browser flow", + description: "should fail because device code is expired", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, - Session: &DefaultDeviceFlowSession{}, - RequestedAt: time.Now().UTC(), - }, - }, - authreq: &fosite.DeviceRequest{ - Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Form: url.Values{}, + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + }, Session: &DefaultDeviceFlowSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), }, - BrowserFlowCompleted: false, + BrowserFlowCompleted: true, }, RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceCodeSession(context.Background(), signature, areq)) }, - expectErr: fosite.ErrAuthorizationPending, + expectErr: fosite.ErrInvalidRequest, }, { - description: "should fail because device code has expired", + description: "should pass with offline scope and refresh token", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode), string(fosite.GrantTypeRefreshToken)}, }, GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &DefaultDeviceFlowSession{}, - RequestedAt: time.Now().UTC(), - }, - }, - authreq: &fosite.DeviceRequest{ - Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, Session: &DefaultDeviceFlowSession{ - ExpiresAt: map[fosite.TokenType]time.Time{ - fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), - }, BrowserFlowCompleted: true, }, - RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), + RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) + }, + check: func(t *testing.T, aresp *fosite.AccessResponse) { + assert.NotEmpty(t, aresp.AccessToken) + assert.Equal(t, "bearer", aresp.TokenType) + assert.NotEmpty(t, aresp.GetExtra("refresh_token")) + assert.NotEmpty(t, aresp.GetExtra("expires_in")) + assert.Equal(t, "foo offline", aresp.GetExtra("scope")) }, - expectErr: fosite.ErrDeviceExpiredToken, }, { - description: "should fail because client mismatch", + description: "should pass with refresh token always provided", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, - Session: &DefaultDeviceFlowSession{}, - RequestedAt: time.Now().UTC(), - }, - }, - authreq: &fosite.DeviceRequest{ - Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "bar"}, + Form: url.Values{}, + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode), string(fosite.GrantTypeRefreshToken)}, + }, + GrantedScope: fosite.Arguments{"foo"}, Session: &DefaultDeviceFlowSession{ - ExpiresAt: map[fosite.TokenType]time.Time{ - fosite.DeviceCode: time.Now().Add(time.Hour).UTC(), - }, BrowserFlowCompleted: true, }, + RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { - token, signature, err := strategy.GenerateDeviceCode(context.TODO()) + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + config.RefreshTokenScopes = []string{} + code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) - areq.Form = url.Values{"device_code": {token}} + areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) + }, + check: func(t *testing.T, aresp *fosite.AccessResponse) { + assert.NotEmpty(t, aresp.AccessToken) + assert.Equal(t, "bearer", aresp.TokenType) + assert.NotEmpty(t, aresp.GetExtra("refresh_token")) + assert.NotEmpty(t, aresp.GetExtra("expires_in")) + assert.Equal(t, "foo", aresp.GetExtra("scope")) }, - expectErr: fosite.ErrInvalidGrant, }, { - description: "should pass", + description: "pass and response should not have refresh token", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, - Session: &DefaultDeviceFlowSession{}, - RequestedAt: time.Now().UTC(), - }, - }, - authreq: &fosite.DeviceRequest{ - Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Form: url.Values{}, + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + }, + GrantedScope: fosite.Arguments{"foo"}, Session: &DefaultDeviceFlowSession{ BrowserFlowCompleted: true, }, RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { - token, signature, err := strategy.GenerateDeviceCode(context.TODO()) + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) + areq.Form.Add("device_code", code) - areq.Form = url.Values{"device_code": {token}} - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) + }, + check: func(t *testing.T, aresp *fosite.AccessResponse) { + assert.NotEmpty(t, aresp.AccessToken) + assert.Equal(t, "bearer", aresp.TokenType) + assert.Empty(t, aresp.GetExtra("refresh_token")) + assert.NotEmpty(t, aresp.GetExtra("expires_in")) + assert.Equal(t, "foo", aresp.GetExtra("scope")) }, }, } - for i, testCase := range testCases { - t.Run(fmt.Sprintf("case=%d/description=%s", i, testCase.description), func(t *testing.T) { + for _, testCase := range testCases { + t.Run("case="+testCase.description, func(t *testing.T) { + config := &fosite.Config{ + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + AccessTokenLifespan: time.Minute, + RefreshTokenScopes: []string{"offline"}, + } + h = oauth2.GenericCodeTokenEndpointHandler{ + AccessRequestValidator: &DeviceAccessRequestValidator{}, + CodeHandler: &DeviceCodeHandler{ + DeviceRateLimitStrategy: strategy, + DeviceCodeStrategy: strategy, + }, + SessionHandler: &DeviceSessionHandler{ + DeviceCodeStorage: store, + }, + AccessTokenStrategy: strategy.CoreStrategy, + RefreshTokenStrategy: strategy.CoreStrategy, + Config: config, + CoreStorage: store, + TokenRevocationStorage: store, + } + if testCase.setup != nil { - testCase.setup(t, testCase.areq, testCase.authreq) + testCase.setup(t, testCase.areq, config) } - t.Logf("Processing %+v", testCase.areq.Client) + aresp := fosite.NewAccessResponse() + err := h.PopulateTokenEndpointResponse(context.TODO(), testCase.areq, aresp) - err := h.HandleTokenEndpointRequest(context.Background(), testCase.areq) if testCase.expectErr != nil { require.EqualError(t, err, testCase.expectErr.Error(), "%+v", err) } else { require.NoError(t, err, "%+v", err) - if testCase.check != nil { - testCase.check(t, testCase.areq, testCase.authreq) - } + } + + if testCase.check != nil { + testCase.check(t, aresp) } }) } @@ -702,7 +768,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockCoreStore = internal.NewMockCoreStorage(ctrl) mockDeviceCodeStore = internal.NewMockDeviceCodeStorage(ctrl) mockDeviceRateLimitStrategy = internal.NewMockDeviceRateLimitStrategy(ctrl) - mockDeviceRateLimitStrategy.EXPECT().ShouldRateLimit(gomock.Any(), gomock.Any()).Return(false).Times(1) + mockDeviceRateLimitStrategy.EXPECT().ShouldRateLimit(gomock.Any(), gomock.Any()).Return(false, nil).Times(1) testCase.setup() handler := oauth2.GenericCodeTokenEndpointHandler{ From 21d172666554688f3b20c695eab39367d24fae14 Mon Sep 17 00:00:00 2001 From: Nikos Date: Thu, 28 Mar 2024 18:19:40 +0200 Subject: [PATCH 17/36] fix: do not validate request when creating response --- handler/oauth2/flow_authorize_code_token.go | 4 +++ .../oauth2/flow_authorize_code_token_test.go | 22 --------------- handler/oauth2/flow_generic_code_token.go | 15 +++++++--- handler/rfc8628/token_handler.go | 20 +++++++------ handler/rfc8628/token_handler_test.go | 28 ------------------- 5 files changed, 26 insertions(+), 63 deletions(-) diff --git a/handler/oauth2/flow_authorize_code_token.go b/handler/oauth2/flow_authorize_code_token.go index d9c745578..7073ecf6e 100644 --- a/handler/oauth2/flow_authorize_code_token.go +++ b/handler/oauth2/flow_authorize_code_token.go @@ -26,6 +26,10 @@ func (c AuthorizeCodeHandler) Code(ctx context.Context, requester fosite.AccessR } func (c AuthorizeCodeHandler) ValidateCode(ctx context.Context, requester fosite.Requester, code string) error { + return nil +} + +func (c AuthorizeCodeHandler) ValidateCodeSession(ctx context.Context, requester fosite.Requester, code string) error { return c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, requester, code) } diff --git a/handler/oauth2/flow_authorize_code_token_test.go b/handler/oauth2/flow_authorize_code_token_test.go index c4c423b5b..e46b2cf1a 100644 --- a/handler/oauth2/flow_authorize_code_token_test.go +++ b/handler/oauth2/flow_authorize_code_token_test.go @@ -64,28 +64,6 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { }, expectErr: fosite.ErrServerError, }, - { - description: "should fail because authorization code is expired", - areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"authorization_code"}, - Request: fosite.Request{ - Form: url.Values{"code": []string{"foo.bar"}}, - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"authorization_code"}, - }, - Session: &fosite.DefaultSession{ - ExpiresAt: map[fosite.TokenType]time.Time{ - fosite.AuthorizeCode: time.Now().Add(-time.Hour).UTC(), - }, - }, - RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), - }, - }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), "bar", areq)) - }, - expectErr: fosite.ErrInvalidRequest, - }, { description: "should pass with offline scope and refresh token", areq: &fosite.AccessRequest{ diff --git a/handler/oauth2/flow_generic_code_token.go b/handler/oauth2/flow_generic_code_token.go index 756507c2b..e469e5585 100644 --- a/handler/oauth2/flow_generic_code_token.go +++ b/handler/oauth2/flow_generic_code_token.go @@ -35,8 +35,11 @@ type CodeHandler interface { // Code fetches the code and code signature. Code(ctx context.Context, requester fosite.AccessRequester) (code string, signature string, err error) - // ValidateCode validates the code. + // ValidateCode validates the code. Can be used for checks that need to run before we fetch the session from the database. ValidateCode(ctx context.Context, requester fosite.Requester, code string) error + + // ValidateCodeSession validates the code session. + ValidateCodeSession(ctx context.Context, requester fosite.Requester, code string) error } // SessionHandler handles session-related operations. @@ -83,8 +86,8 @@ func (c *GenericCodeTokenEndpointHandler) PopulateTokenEndpointResponse(ctx cont return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } - if err = c.ValidateCode(ctx, requester, code); err != nil { - return errorsx.WithStack(fosite.ErrInvalidRequest.WithWrap(err).WithDebug(err.Error())) + if err = c.ValidateCodeSession(ctx, ar, code); err != nil { + return errorsx.WithStack(err) } for _, scope := range ar.GetRequestedScopes() { @@ -166,6 +169,10 @@ func (c *GenericCodeTokenEndpointHandler) HandleTokenEndpointRequest(ctx context return err } + if err = c.ValidateCode(ctx, requester, code); err != nil { + return errorsx.WithStack(err) + } + var ar fosite.Requester if ar, err = c.Session(ctx, requester, signature); err != nil { if ar != nil && (errors.Is(err, fosite.ErrInvalidatedAuthorizeCode) || errors.Is(err, fosite.ErrInvalidatedDeviceCode)) { @@ -175,7 +182,7 @@ func (c *GenericCodeTokenEndpointHandler) HandleTokenEndpointRequest(ctx context return err } - if err = c.ValidateCode(ctx, ar, code); err != nil { + if err = c.ValidateCodeSession(ctx, ar, code); err != nil { return errorsx.WithStack(err) } diff --git a/handler/rfc8628/token_handler.go b/handler/rfc8628/token_handler.go index a8d0f8bbc..29fb8fc7b 100644 --- a/handler/rfc8628/token_handler.go +++ b/handler/rfc8628/token_handler.go @@ -22,15 +22,6 @@ type DeviceCodeHandler struct { func (c DeviceCodeHandler) Code(ctx context.Context, requester fosite.AccessRequester) (code string, signature string, err error) { code = requester.GetRequestForm().Get("device_code") - shouldRateLimit, err := c.DeviceRateLimitStrategy.ShouldRateLimit(ctx, code) - // TODO(nsklikas) : should we error out or just silently log it? - if err != nil { - return "", "", err - } - if shouldRateLimit { - return "", "", errorsx.WithStack(fosite.ErrPollingRateLimited) - } - signature, err = c.DeviceCodeStrategy.DeviceCodeSignature(ctx, code) if err != nil { return "", "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) @@ -40,6 +31,17 @@ func (c DeviceCodeHandler) Code(ctx context.Context, requester fosite.AccessRequ } func (c DeviceCodeHandler) ValidateCode(ctx context.Context, requester fosite.Requester, code string) error { + shouldRateLimit, err := c.DeviceRateLimitStrategy.ShouldRateLimit(ctx, code) + if err != nil { + return err + } + if shouldRateLimit { + return errorsx.WithStack(fosite.ErrPollingRateLimited) + } + return nil +} + +func (c DeviceCodeHandler) ValidateCodeSession(ctx context.Context, requester fosite.Requester, code string) error { return c.DeviceCodeStrategy.ValidateDeviceCode(ctx, requester, code) } diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index bf8169dc4..eefae4005 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -377,33 +377,6 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { }, expectErr: fosite.ErrServerError, }, - { - description: "should fail because device code is expired", - areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, - Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, - }, - Session: &DefaultDeviceFlowSession{ - ExpiresAt: map[fosite.TokenType]time.Time{ - fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), - }, - BrowserFlowCompleted: true, - }, - RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), - }, - }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { - code, signature, err := strategy.GenerateDeviceCode(context.TODO()) - require.NoError(t, err) - areq.Form.Add("device_code", code) - - require.NoError(t, store.CreateDeviceCodeSession(context.Background(), signature, areq)) - }, - expectErr: fosite.ErrInvalidRequest, - }, { description: "should pass with offline scope and refresh token", areq: &fosite.AccessRequest{ @@ -768,7 +741,6 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockCoreStore = internal.NewMockCoreStorage(ctrl) mockDeviceCodeStore = internal.NewMockDeviceCodeStorage(ctrl) mockDeviceRateLimitStrategy = internal.NewMockDeviceRateLimitStrategy(ctrl) - mockDeviceRateLimitStrategy.EXPECT().ShouldRateLimit(gomock.Any(), gomock.Any()).Return(false, nil).Times(1) testCase.setup() handler := oauth2.GenericCodeTokenEndpointHandler{ From cb518cc95e6d8cee75b5d55e5bb14de0a74676e2 Mon Sep 17 00:00:00 2001 From: Shu Date: Fri, 5 Apr 2024 09:41:19 -0600 Subject: [PATCH 18/36] fix: add the OIDC handler for device flow (#13) fix: add the OIDC handler for device flow --- compose/compose.go | 6 +- compose/compose_openid.go | 15 ++ device_request_handler.go | 2 +- handler/openid/flow_device_auth.go | 50 ++++ handler/openid/flow_device_auth_test.go | 162 +++++++++++++ handler/openid/flow_device_token.go | 64 ++++++ handler/openid/flow_device_token_test.go | 277 +++++++++++++++++++++++ handler/openid/validator.go | 5 +- handler/openid/validator_test.go | 7 +- handler/rfc8628/auth_handler_test.go | 3 - handler/rfc8628/token_handler_test.go | 2 +- 11 files changed, 580 insertions(+), 13 deletions(-) create mode 100644 handler/openid/flow_device_auth.go create mode 100644 handler/openid/flow_device_auth_test.go create mode 100644 handler/openid/flow_device_token.go create mode 100644 handler/openid/flow_device_token_test.go diff --git a/compose/compose.go b/compose/compose.go index 91dd4e6e6..632186ee2 100644 --- a/compose/compose.go +++ b/compose/compose.go @@ -82,18 +82,18 @@ func ComposeAllEnabled(config *fosite.Config, storage interface{}, key interface OAuth2RefreshTokenGrantFactory, OAuth2ResourceOwnerPasswordCredentialsFactory, RFC7523AssertionGrantFactory, + RFC8628DeviceFactory, + RFC8628DeviceAuthorizationTokenFactory, OpenIDConnectExplicitFactory, OpenIDConnectImplicitFactory, OpenIDConnectHybridFactory, OpenIDConnectRefreshFactory, + OpenIDConnectDeviceFactory, OAuth2TokenIntrospectionFactory, OAuth2TokenRevocationFactory, - RFC8628DeviceFactory, - RFC8628DeviceAuthorizationTokenFactory, - OAuth2PKCEFactory, PushedAuthorizeHandlerFactory, ) diff --git a/compose/compose_openid.go b/compose/compose_openid.go index 68178ddc7..4e05a6c73 100644 --- a/compose/compose_openid.go +++ b/compose/compose_openid.go @@ -7,6 +7,7 @@ import ( "github.com/ory/fosite" "github.com/ory/fosite/handler/oauth2" "github.com/ory/fosite/handler/openid" + "github.com/ory/fosite/handler/rfc8628" "github.com/ory/fosite/token/jwt" ) @@ -77,3 +78,17 @@ func OpenIDConnectHybridFactory(config fosite.Configurator, storage interface{}, OpenIDConnectRequestValidator: openid.NewOpenIDConnectRequestValidator(strategy.(jwt.Signer), config), } } + +// OpenIDConnectDeviceFactory creates an OpenID Connect device ("device code flow") grant handler. +// +// **Important note:** You must add this handler *after* you have added an OAuth2 device authorization handler! +func OpenIDConnectDeviceFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} { + return &openid.OpenIDConnectDeviceHandler{ + OpenIDConnectRequestStorage: storage.(openid.OpenIDConnectRequestStorage), + IDTokenHandleHelper: &openid.IDTokenHandleHelper{ + IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy), + }, + DeviceCodeStrategy: strategy.(rfc8628.DeviceCodeStrategy), + Config: config, + } +} diff --git a/device_request_handler.go b/device_request_handler.go index 30d548257..2f3510839 100644 --- a/device_request_handler.go +++ b/device_request_handler.go @@ -17,7 +17,7 @@ import ( // NewDeviceRequest parses an http Request returns a Device request func (f *Fosite) NewDeviceRequest(ctx context.Context, r *http.Request) (_ DeviceRequester, err error) { - ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("github.com/ory/fosite").Start(ctx, "Fosite.NewAccessRequest") + ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("github.com/ory/fosite").Start(ctx, "Fosite.NewDeviceRequest") defer otelx.End(span, &err) request := NewDeviceRequest() diff --git a/handler/openid/flow_device_auth.go b/handler/openid/flow_device_auth.go new file mode 100644 index 000000000..3a54b4948 --- /dev/null +++ b/handler/openid/flow_device_auth.go @@ -0,0 +1,50 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package openid + +import ( + "context" + + "github.com/ory/fosite/handler/rfc8628" + + "github.com/ory/fosite" + "github.com/ory/x/errorsx" +) + +// OpenIDConnectDeviceHandler a response handler for the Device Authorization Grant with OpenID Connect identity layer +type OpenIDConnectDeviceHandler struct { + OpenIDConnectRequestStorage OpenIDConnectRequestStorage + DeviceCodeStrategy rfc8628.DeviceCodeStrategy + + Config interface { + fosite.IDTokenLifespanProvider + } + + *IDTokenHandleHelper +} + +func (c *OpenIDConnectDeviceHandler) HandleDeviceEndpointRequest(ctx context.Context, dar fosite.DeviceRequester, resp fosite.DeviceResponder) error { + if !(dar.GetGrantedScopes().Has("openid")) { + return nil + } + + if !dar.GetClient().GetGrantTypes().Has(string(fosite.GrantTypeDeviceCode)) { + return nil + } + + if len(resp.GetDeviceCode()) == 0 { + return errorsx.WithStack(fosite.ErrMisconfiguration.WithDebug("The device code has not been issued yet, indicating a broken code configuration.")) + } + + signature, err := c.DeviceCodeStrategy.DeviceCodeSignature(ctx, resp.GetDeviceCode()) + if err != nil { + return err + } + + if err := c.OpenIDConnectRequestStorage.CreateOpenIDConnectSession(ctx, signature, dar.Sanitize(oidcParameters)); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + return nil +} diff --git a/handler/openid/flow_device_auth_test.go b/handler/openid/flow_device_auth_test.go new file mode 100644 index 000000000..a84e1e44d --- /dev/null +++ b/handler/openid/flow_device_auth_test.go @@ -0,0 +1,162 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package openid + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/ory/fosite/internal" + "github.com/pkg/errors" + + "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" + "github.com/ory/fosite/token/jwt" +) + +func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + store := internal.NewMockOpenIDConnectRequestStorage(ctrl) + + config := &fosite.Config{ + MinParameterEntropy: fosite.MinParameterEntropy, + DeviceAndUserCodeLifespan: time.Hour * 24, + } + + signer := &jwt.DefaultSigner{ + GetPrivateKey: func(ctx context.Context) (interface{}, error) { + return key, nil + }, + } + + h := OpenIDConnectDeviceHandler{ + OpenIDConnectRequestStorage: store, + DeviceCodeStrategy: &rfc8628.DefaultDeviceStrategy{ + Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobar")}}, + RateLimiterCache: freecache.NewCache(1024 * 1024), + Config: config, + }, + Config: config, + IDTokenHandleHelper: &IDTokenHandleHelper{ + IDTokenStrategy: &DefaultStrategy{ + Signer: signer, + Config: config, + }, + }, + } + + session := &DefaultSession{ + Claims: &jwt.IDTokenClaims{ + Subject: "foo", + }, + Headers: &jwt.Headers{}, + } + + client := &fosite.DefaultClient{ + ID: "foo", + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + } + + testCases := []struct { + description string + authreq *fosite.DeviceRequest + authresp *fosite.DeviceResponse + setup func(authreq *fosite.DeviceRequest) + expectErr error + }{ + { + description: "should ignore because scope openid is not set", + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + GrantedScope: fosite.Arguments{"email"}, + }, + }, + }, + { + description: "should ignore because client grant type is invalid", + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + GrantedScope: fosite.Arguments{"openid", "email"}, + Client: &fosite.DefaultClient{ + GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}, + }, + }, + }, + }, + { + description: "should fail because device code is not issued", + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + GrantedScope: fosite.Arguments{"openid", "email"}, + Client: client, + }, + }, + authresp: &fosite.DeviceResponse{}, + expectErr: fosite.ErrMisconfiguration, + }, + { + description: "should fail because cannot create session", + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + GrantedScope: fosite.Arguments{"openid", "email"}, + Client: client, + Session: session, + }, + }, + authresp: &fosite.DeviceResponse{ + DeviceCode: "device_code", + }, + setup: func(authreq *fosite.DeviceRequest) { + store. + EXPECT(). + CreateOpenIDConnectSession(gomock.Any(), gomock.Any(), gomock.Eq(authreq.Sanitize(oidcParameters))). + Return(errors.New("")) + }, + expectErr: fosite.ErrServerError, + }, + { + description: "should pass", + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + GrantedScope: fosite.Arguments{"openid", "email"}, + Client: client, + Session: session, + }, + }, + authresp: &fosite.DeviceResponse{ + DeviceCode: "device_code", + }, + setup: func(authreq *fosite.DeviceRequest) { + store. + EXPECT(). + CreateOpenIDConnectSession(gomock.Any(), gomock.Any(), gomock.Eq(authreq.Sanitize(oidcParameters))). + Return(nil) + }, + }, + } + + for i, testCase := range testCases { + t.Run(fmt.Sprintf("case=%d/description=%s", i, testCase.description), func(t *testing.T) { + if testCase.setup != nil { + testCase.setup(testCase.authreq) + } + + err := h.HandleDeviceEndpointRequest(context.Background(), testCase.authreq, testCase.authresp) + if testCase.expectErr != nil { + require.EqualError(t, err, testCase.expectErr.Error(), "%+v", err) + } else { + require.NoError(t, err, "%+v", err) + } + }) + } +} diff --git a/handler/openid/flow_device_token.go b/handler/openid/flow_device_token.go new file mode 100644 index 000000000..5456b0b4c --- /dev/null +++ b/handler/openid/flow_device_token.go @@ -0,0 +1,64 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package openid + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/ory/fosite" + "github.com/ory/x/errorsx" +) + +func (c *OpenIDConnectDeviceHandler) HandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) error { + return errorsx.WithStack(fosite.ErrUnknownRequest) +} + +func (c *OpenIDConnectDeviceHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { + if !c.CanHandleTokenEndpointRequest(ctx, requester) { + return errorsx.WithStack(fosite.ErrUnknownRequest) + } + + deviceCode := requester.GetRequestForm().Get("device_code") + signature, err := c.DeviceCodeStrategy.DeviceCodeSignature(ctx, deviceCode) + ar, err := c.OpenIDConnectRequestStorage.GetOpenIDConnectSession(ctx, signature, requester) + if errors.Is(err, ErrNoSessionFound) { + return errorsx.WithStack(fosite.ErrUnknownRequest.WithWrap(err).WithDebug(err.Error())) + } + if err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + if !ar.GetGrantedScopes().Has("openid") { + return errorsx.WithStack(fosite.ErrMisconfiguration.WithDebug("An OpenID Connect session was found but the openid scope is missing, probably due to a broken code configuration.")) + } + + if !requester.GetClient().GetGrantTypes().Has(string(fosite.GrantTypeDeviceCode)) { + return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"urn:ietf:params:oauth:grant-type:device_code\".")) + } + + session, ok := ar.GetSession().(Session) + if !ok { + return errorsx.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because session must be of type fosite/handler/openid.Session.")) + } + + claims := session.IDTokenClaims() + if claims.Subject == "" { + return errorsx.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because subject is an empty string.")) + } + + claims.AccessTokenHash = c.GetAccessTokenHash(ctx, requester, responder) + + idTokenLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), fosite.GrantTypeDeviceCode, fosite.IDToken, c.Config.GetIDTokenLifespan(ctx)) + return c.IssueExplicitIDToken(ctx, idTokenLifespan, ar, responder) +} + +func (c *OpenIDConnectDeviceHandler) CanSkipClientAuth(ctx context.Context, requester fosite.AccessRequester) bool { + return false +} + +func (c *OpenIDConnectDeviceHandler) CanHandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) bool { + return requester.GetGrantTypes().ExactOne(string(fosite.GrantTypeDeviceCode)) +} diff --git a/handler/openid/flow_device_token_test.go b/handler/openid/flow_device_token_test.go new file mode 100644 index 000000000..54f9686ec --- /dev/null +++ b/handler/openid/flow_device_token_test.go @@ -0,0 +1,277 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package openid + +import ( + "context" + "fmt" + "net/url" + "testing" + "time" + + "github.com/pkg/errors" + + "github.com/stretchr/testify/require" + + "github.com/coocood/freecache" + "github.com/golang/mock/gomock" + "github.com/ory/fosite/handler/rfc8628" + "github.com/ory/fosite/internal" + "github.com/ory/fosite/token/hmac" + "github.com/ory/fosite/token/jwt" + + "github.com/stretchr/testify/assert" + + "github.com/ory/fosite" +) + +func TestDeviceToken_HandleTokenEndpointRequest(t *testing.T) { + h := OpenIDConnectDeviceHandler{ + Config: &fosite.Config{}, + } + areq := fosite.NewAccessRequest(nil) + areq.Client = &fosite.DefaultClient{ + ResponseTypes: fosite.Arguments{"code"}, + } + + err := h.HandleTokenEndpointRequest(context.Background(), areq) + assert.EqualError(t, err, fosite.ErrUnknownRequest.Error()) +} + +func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + store := internal.NewMockOpenIDConnectRequestStorage(ctrl) + + config := &fosite.Config{ + MinParameterEntropy: fosite.MinParameterEntropy, + DeviceAndUserCodeLifespan: time.Hour * 24, + IDTokenLifespan: time.Hour * 24, + } + + signer := &jwt.DefaultSigner{ + GetPrivateKey: func(ctx context.Context) (interface{}, error) { + return key, nil + }, + } + + h := OpenIDConnectDeviceHandler{ + OpenIDConnectRequestStorage: store, + DeviceCodeStrategy: &rfc8628.DefaultDeviceStrategy{ + Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobar")}}, + RateLimiterCache: freecache.NewCache(1024 * 1024), + Config: config, + }, + Config: config, + IDTokenHandleHelper: &IDTokenHandleHelper{ + IDTokenStrategy: &DefaultStrategy{ + Signer: signer, + Config: config, + }, + }, + } + + session := &DefaultSession{ + Claims: &jwt.IDTokenClaims{ + Subject: "foo", + }, + Headers: &jwt.Headers{}, + } + + client := &fosite.DefaultClient{ + ID: "foo", + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + } + + testCases := []struct { + description string + areq *fosite.AccessRequest + aresp *fosite.AccessResponse + setup func(areq *fosite.AccessRequest) + check func(t *testing.T, aresp *fosite.AccessResponse) + expectErr error + }{ + { + description: "should fail because the grant type is invalid", + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, + Request: fosite.Request{ + Form: url.Values{"device_code": []string{"device_code"}}, + Session: session, + }, + }, + aresp: fosite.NewAccessResponse(), + expectErr: fosite.ErrUnknownRequest, + }, + { + description: "should fail because session not found", + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + Request: fosite.Request{ + Form: url.Values{"device_code": []string{"device_code"}}, + Session: session, + }, + }, + aresp: fosite.NewAccessResponse(), + setup: func(areq *fosite.AccessRequest) { + store.EXPECT().GetOpenIDConnectSession(gomock.Any(), gomock.Any(), areq).Return(nil, ErrNoSessionFound) + }, + expectErr: fosite.ErrUnknownRequest, + }, + { + description: "should fail because session lookup fails", + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + Request: fosite.Request{ + Form: url.Values{"device_code": []string{"device_code"}}, + Session: session, + }, + }, + setup: func(areq *fosite.AccessRequest) { + store.EXPECT().GetOpenIDConnectSession(gomock.Any(), gomock.Any(), areq).Return(nil, errors.New("")) + }, + expectErr: fosite.ErrServerError, + }, + { + description: "should fail because auth request grant scope is invalid", + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + Request: fosite.Request{ + Form: url.Values{"device_code": []string{"device_code"}}, + Session: session, + }, + }, + setup: func(areq *fosite.AccessRequest) { + authreq := &fosite.DeviceRequest{ + Request: fosite.Request{ + GrantedScope: fosite.Arguments{"email"}, + Session: session, + }, + } + store.EXPECT().GetOpenIDConnectSession(gomock.Any(), gomock.Any(), areq).Return(authreq, nil) + }, + expectErr: fosite.ErrMisconfiguration, + }, + { + description: "should fail because auth request's client grant type is invalid", + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, + }, + Form: url.Values{"device_code": []string{"device_code"}}, + Session: session, + }, + }, + setup: func(areq *fosite.AccessRequest) { + authreq := &fosite.DeviceRequest{ + Request: fosite.Request{ + GrantedScope: fosite.Arguments{"openid", "email"}, + Session: session, + }, + } + store.EXPECT().GetOpenIDConnectSession(gomock.Any(), gomock.Any(), areq).Return(authreq, nil) + }, + expectErr: fosite.ErrUnauthorizedClient, + }, + { + description: "should fail because auth request is missing session", + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + Request: fosite.Request{ + Client: client, + Form: url.Values{"device_code": []string{"device_code"}}, + Session: session, + }, + }, + setup: func(areq *fosite.AccessRequest) { + authreq := &fosite.DeviceRequest{ + Request: fosite.Request{ + GrantedScope: fosite.Arguments{"openid", "email"}, + }, + } + store.EXPECT().GetOpenIDConnectSession(gomock.Any(), gomock.Any(), areq).Return(authreq, nil) + }, + expectErr: fosite.ErrServerError, + }, + { + description: "should fail because auth request session is missing subject claims", + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + Request: fosite.Request{ + Client: client, + Form: url.Values{"device_code": []string{"device_code"}}, + Session: session, + }, + }, + setup: func(areq *fosite.AccessRequest) { + authreq := &fosite.DeviceRequest{ + Request: fosite.Request{ + GrantedScope: fosite.Arguments{"openid", "email"}, + Session: NewDefaultSession(), + }, + } + store.EXPECT().GetOpenIDConnectSession(gomock.Any(), gomock.Any(), areq).Return(authreq, nil) + }, + expectErr: fosite.ErrServerError, + }, + { + description: "should pass", + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + Request: fosite.Request{ + Client: client, + Form: url.Values{"device_code": []string{"device_code"}}, + Session: session, + }, + }, + setup: func(areq *fosite.AccessRequest) { + authreq := &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: client, + GrantedScope: fosite.Arguments{"openid", "email"}, + Session: session, + }, + } + store.EXPECT().GetOpenIDConnectSession(gomock.Any(), gomock.Any(), areq).Return(authreq, nil) + }, + check: func(t *testing.T, aresp *fosite.AccessResponse) { + assert.NotEmpty(t, aresp.GetExtra("id_token")) + + idToken, _ := aresp.GetExtra("id_token").(string) + decodedIdToken, err := jwt.Parse(idToken, func(token *jwt.Token) (interface{}, error) { + return key.PublicKey, nil + }) + require.NoError(t, err) + + claims := decodedIdToken.Claims + assert.NotEmpty(t, claims["at_hash"]) + + idTokenExp := internal.ExtractJwtExpClaim(t, idToken) + internal.RequireEqualTime(t, time.Now().Add(time.Hour*24), *idTokenExp, time.Minute) + }, + }, + } + + for i, testCase := range testCases { + t.Run(fmt.Sprintf("case=%d/description=%s", i, testCase.description), func(t *testing.T) { + if testCase.setup != nil { + testCase.setup(testCase.areq) + } + + aresp := fosite.NewAccessResponse() + err := h.PopulateTokenEndpointResponse(context.Background(), testCase.areq, aresp) + if testCase.expectErr != nil { + require.EqualError(t, err, testCase.expectErr.Error(), "%+v", err) + } else { + require.NoError(t, err, "%+v", err) + } + + if testCase.check != nil { + testCase.check(t, aresp) + } + }) + } +} diff --git a/handler/openid/validator.go b/handler/openid/validator.go index f25314943..4a8f3060c 100644 --- a/handler/openid/validator.go +++ b/handler/openid/validator.go @@ -60,9 +60,10 @@ func (v *OpenIDConnectRequestValidator) ValidatePrompt(ctx context.Context, req // unless the identity of the client can be proven, the request SHOULD // be processed as if no previous request had been approved. - checker := v.Config.GetRedirectSecureChecker(ctx) if stringslice.Has(requiredPrompt, "none") { - if !checker(ctx, req.GetRedirectURI()) { + redirectURI := req.GetRedirectURI() + checker := v.Config.GetRedirectSecureChecker(ctx) + if !checker(ctx, redirectURI) { return errorsx.WithStack(fosite.ErrConsentRequired.WithHint("OAuth 2.0 Client is marked public and redirect uri is not considered secure (https missing), but \"prompt=none\" was requested.")) } } diff --git a/handler/openid/validator_test.go b/handler/openid/validator_test.go index d22bb33ef..f9b5d254b 100644 --- a/handler/openid/validator_test.go +++ b/handler/openid/validator_test.go @@ -21,11 +21,12 @@ func TestValidatePrompt(t *testing.T) { config := &fosite.Config{ MinParameterEntropy: fosite.MinParameterEntropy, } - var j = &DefaultStrategy{ + j := &DefaultStrategy{ Signer: &jwt.DefaultSigner{ GetPrivateKey: func(_ context.Context) (interface{}, error) { return key, nil - }}, + }, + }, Config: &fosite.Config{ MinParameterEntropy: fosite.MinParameterEntropy, }, @@ -33,7 +34,7 @@ func TestValidatePrompt(t *testing.T) { v := NewOpenIDConnectRequestValidator(j, config) - var genIDToken = func(c jwt.IDTokenClaims) string { + genIDToken := func(c jwt.IDTokenClaims) string { s, _, err := j.Generate(context.TODO(), c.ToMapClaims(), jwt.NewHeaders()) require.NoError(t, err) return s diff --git a/handler/rfc8628/auth_handler_test.go b/handler/rfc8628/auth_handler_test.go index 220a03475..74f010506 100644 --- a/handler/rfc8628/auth_handler_test.go +++ b/handler/rfc8628/auth_handler_test.go @@ -8,7 +8,6 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" "github.com/ory/fosite/storage" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -18,8 +17,6 @@ import ( ) func Test_HandleDeviceEndpointRequest(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() store := storage.NewMemoryStore() handler := rfc8628.DeviceAuthHandler{ Storage: store, diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index eefae4005..f30475140 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -35,7 +35,7 @@ var hmacshaStrategy = oauth2.NewHMACSHAStrategy( var RFC8628HMACSHAStrategy = DefaultDeviceStrategy{ Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, - RateLimiterCache: freecache.NewCache(16384 * 64), + RateLimiterCache: freecache.NewCache(1024 * 1024), Config: &fosite.Config{ DeviceAndUserCodeLifespan: time.Hour * 24, }, From 426d5ab52b265159dd6bdc750fb1b4ae0fe877cb Mon Sep 17 00:00:00 2001 From: Shu Date: Fri, 12 Apr 2024 11:03:32 -0600 Subject: [PATCH 19/36] fix: fix the refresh token issue (#14) * fix: fix the refresh token issue * fix: fix the OIDC token missing issue --- .../oauth2/flow_authorize_code_token_test.go | 274 +++++++++++++----- handler/oauth2/flow_generic_code_token.go | 11 +- handler/openid/flow_device_auth.go | 4 +- handler/openid/flow_device_auth_test.go | 24 +- handler/openid/flow_device_token.go | 8 +- handler/openid/flow_device_token_test.go | 46 +-- handler/rfc8628/token_handler_test.go | 234 ++++++++++----- .../authorize_device_grant_request_test.go | 26 +- 8 files changed, 411 insertions(+), 216 deletions(-) diff --git a/handler/oauth2/flow_authorize_code_token_test.go b/handler/oauth2/flow_authorize_code_token_test.go index e46b2cf1a..e06468065 100644 --- a/handler/oauth2/flow_authorize_code_token_test.go +++ b/handler/oauth2/flow_authorize_code_token_test.go @@ -28,19 +28,25 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { t.Run("strategy="+k, func(t *testing.T) { store := storage.NewMemoryStore() - var h GenericCodeTokenEndpointHandler - testCases := []struct { description string areq *fosite.AccessRequest - setup func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) + authreq *fosite.AuthorizeRequest + setup func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest, config *fosite.Config) check func(t *testing.T, aresp *fosite.AccessResponse) expectErr error }{ { - description: "should fail because not responsible", + description: "should fail because not responsible for handling the request", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"123"}, + GrantTypes: fosite.Arguments{"implicit"}, + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{"authorization_code"}, + }, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, }, expectErr: fosite.ErrUnknownRequest, }, @@ -57,7 +63,7 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + setup: func(t *testing.T, areq *fosite.AccessRequest, _ *fosite.AuthorizeRequest, _ *fosite.Config) { code, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) areq.Form.Set("code", code) @@ -65,25 +71,37 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { expectErr: fosite.ErrServerError, }, { - description: "should pass with offline scope and refresh token", + description: "should pass with offline scope and refresh token grant type", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ + ID: "foo", GrantTypes: fosite.Arguments{"authorization_code", "refresh_token"}, }, - GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + authreq: &fosite.AuthorizeRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + RequestedScope: fosite.Arguments{"foo", "bar", "offline"}, + GrantedScope: fosite.Arguments{"foo", "offline"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest, _ *fosite.Config) { code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Add("code", code) + areq.Form.Set("code", code) - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, areq)) + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) }, check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) @@ -94,26 +112,38 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { }, }, { - description: "should pass with refresh token always provided", + description: "should pass with refresh token grant type", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ + ID: "foo", GrantTypes: fosite.Arguments{"authorization_code", "refresh_token"}, }, - GrantedScope: fosite.Arguments{"foo"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + authreq: &fosite.AuthorizeRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + RequestedScope: fosite.Arguments{"foo", "bar"}, + GrantedScope: fosite.Arguments{"foo"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest, config *fosite.Config) { config.RefreshTokenScopes = []string{} code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Add("code", code) + areq.Form.Set("code", code) - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, areq)) + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) }, check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) @@ -130,19 +160,31 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ + ID: "foo", GrantTypes: fosite.Arguments{"authorization_code"}, }, - GrantedScope: fosite.Arguments{"foo"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + authreq: &fosite.AuthorizeRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + RequestedScope: fosite.Arguments{"foo", "bar"}, + GrantedScope: fosite.Arguments{"foo"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest, _ *fosite.Config) { code, sig, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Add("code", code) + areq.Form.Set("code", code) - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, areq)) + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, authreq)) }, check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) @@ -162,7 +204,7 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { AccessTokenLifespan: time.Minute, RefreshTokenScopes: []string{"offline"}, } - h = GenericCodeTokenEndpointHandler{ + h := GenericCodeTokenEndpointHandler{ AccessRequestValidator: &AuthorizeExplicitGrantAccessRequestValidator{}, CodeHandler: &AuthorizeCodeHandler{ AuthorizeCodeStrategy: strategy, @@ -177,7 +219,7 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { } if testCase.setup != nil { - testCase.setup(t, testCase.areq, config) + testCase.setup(t, testCase.areq, testCase.authreq, config) } aresp := fosite.NewAccessResponse() @@ -230,9 +272,18 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { expectErr error }{ { - description: "should fail because not responsible", + description: "should fail because not responsible for handling the request", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"12345678"}, + GrantTypes: fosite.Arguments{"implicit"}, + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, }, expectErr: fosite.ErrUnknownRequest, }, @@ -241,7 +292,11 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{""}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{""}, + }, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, @@ -253,15 +308,19 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - token, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + code, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form = url.Values{"code": {token}} + areq.Form.Set("code", code) }, expectErr: fosite.ErrInvalidGrant, }, @@ -270,15 +329,27 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Form: url.Values{"code": {"foo.bar"}}, - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Form: url.Values{ + "code": {"foo.bar"}, + "redirect_uri": []string{"request-redir"}, + }, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo"}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, + RequestedScope: fosite.Arguments{"foo"}, + GrantedScope: fosite.Arguments{"foo"}, Session: &fosite.DefaultSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.AuthorizeCode: time.Now().Add(-time.Hour).UTC(), @@ -288,9 +359,9 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - token, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form = url.Values{"code": {token}} + areq.Form.Set("code", code) require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) }, @@ -301,14 +372,24 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "bar"}, + Client: &fosite.DefaultClient{ + ID: "bar", + GrantTypes: []string{"authorization_code"}, + }, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, + RequestedScope: fosite.Arguments{"foo"}, + GrantedScope: fosite.Arguments{"foo"}, Session: &fosite.DefaultSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.AuthorizeCode: time.Now().Add(time.Hour).UTC(), @@ -317,9 +398,9 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - token, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form = url.Values{"code": {token}} + areq.Form.Set("code", code) require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) }, @@ -330,15 +411,24 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + Form: url.Values{}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, - Form: url.Values{"redirect_uri": []string{"request-redir"}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, + RequestedScope: fosite.Arguments{"foo"}, + GrantedScope: fosite.Arguments{"foo"}, Session: &fosite.DefaultSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.AuthorizeCode: time.Now().Add(time.Hour).UTC(), @@ -347,9 +437,9 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - token, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form = url.Values{"code": {token}} + areq.Form.Set("code", code) require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) }, @@ -360,7 +450,10 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, Form: url.Values{"redirect_uri": []string{"request-redir"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), @@ -368,16 +461,22 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, + RequestedScope: fosite.Arguments{"foo"}, + GrantedScope: fosite.Arguments{"foo"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - token, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) + areq.Form.Set("code", code) - areq.Form = url.Values{"code": {token}} require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) }, }, @@ -386,23 +485,32 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: fosite.Arguments{"authorization_code"}}, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: fosite.Arguments{"authorization_code"}, + }, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, + RequestedScope: fosite.Arguments{"foo"}, + GrantedScope: fosite.Arguments{"foo"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Add("code", code) + areq.Form.Set("code", code) require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) require.NoError(t, store.InvalidateAuthorizeCodeSession(context.Background(), signature)) @@ -439,23 +547,37 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { var mockCoreStore *internal.MockCoreStorage var mockAuthorizeStore *internal.MockAuthorizeCodeStorage strategy := hmacshaStrategy - request := &fosite.AccessRequest{ + + authreq := &fosite.AuthorizeRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"authorization_code"}, + }, + RequestedScope: fosite.Arguments{"foo", "offline"}, + GrantedScope: fosite.Arguments{"foo", "offline"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), + }, + } + + areq := &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ Client: &fosite.DefaultClient{ GrantTypes: fosite.Arguments{"authorization_code", "refresh_token"}, }, - GrantedScope: fosite.Arguments{"offline"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, } - token, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) - require.NoError(t, err) - request.Form = url.Values{"code": {token}} - response := fosite.NewAccessResponse() + aresp := fosite.NewAccessResponse() propagatedContext := context.Background() + code, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + require.NoError(t, err) + areq.Form = url.Values{"code": {code}} + // some storage implementation that has support for transactions, notice the embedded type `storage.Transactional` type transactionalStore struct { storage.Transactional @@ -478,7 +600,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -512,7 +634,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -537,7 +659,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -567,7 +689,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -582,7 +704,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -607,7 +729,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockAuthorizeStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -658,7 +780,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, AuthorizeCodeLifespan: time.Minute, } - handler := GenericCodeTokenEndpointHandler{ + h := GenericCodeTokenEndpointHandler{ AccessRequestValidator: &AuthorizeExplicitGrantAccessRequestValidator{}, CodeHandler: &AuthorizeCodeHandler{ AuthorizeCodeStrategy: strategy, @@ -678,7 +800,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { Config: config, } - if err := handler.PopulateTokenEndpointResponse(propagatedContext, request, response); testCase.expectError != nil { + if err := h.PopulateTokenEndpointResponse(propagatedContext, areq, aresp); testCase.expectError != nil { assert.EqualError(t, err, testCase.expectError.Error()) } }) diff --git a/handler/oauth2/flow_generic_code_token.go b/handler/oauth2/flow_generic_code_token.go index e469e5585..031ec84e5 100644 --- a/handler/oauth2/flow_generic_code_token.go +++ b/handler/oauth2/flow_generic_code_token.go @@ -90,7 +90,7 @@ func (c *GenericCodeTokenEndpointHandler) PopulateTokenEndpointResponse(ctx cont return errorsx.WithStack(err) } - for _, scope := range ar.GetRequestedScopes() { + for _, scope := range ar.GetGrantedScopes() { requester.GrantScope(scope) } @@ -105,7 +105,7 @@ func (c *GenericCodeTokenEndpointHandler) PopulateTokenEndpointResponse(ctx cont } var refreshToken, refreshTokenSignature string - if c.canIssueRefreshToken(ctx, ar) { + if c.canIssueRefreshToken(ctx, requester) { refreshToken, refreshTokenSignature, err = c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester) if err != nil { return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) @@ -229,11 +229,14 @@ func (c *GenericCodeTokenEndpointHandler) CanHandleTokenEndpointRequest(ctx cont } func (c *GenericCodeTokenEndpointHandler) canIssueRefreshToken(ctx context.Context, requester fosite.Requester) bool { - scope := c.Config.GetRefreshTokenScopes(ctx) - if len(scope) > 0 && !requester.GetGrantedScopes().HasOneOf(scope...) { + scopes := c.Config.GetRefreshTokenScopes(ctx) + + // Require one of the refresh token scopes, if set. + if len(scopes) > 0 && !requester.GetGrantedScopes().HasOneOf(scopes...) { return false } + // Do not issue a refresh token to clients that cannot use the refresh token grant type. if !requester.GetClient().GetGrantTypes().Has("refresh_token") { return false } diff --git a/handler/openid/flow_device_auth.go b/handler/openid/flow_device_auth.go index 3a54b4948..efeb2115e 100644 --- a/handler/openid/flow_device_auth.go +++ b/handler/openid/flow_device_auth.go @@ -25,7 +25,7 @@ type OpenIDConnectDeviceHandler struct { } func (c *OpenIDConnectDeviceHandler) HandleDeviceEndpointRequest(ctx context.Context, dar fosite.DeviceRequester, resp fosite.DeviceResponder) error { - if !(dar.GetGrantedScopes().Has("openid")) { + if !(dar.GetRequestedScopes().Has("openid")) { return nil } @@ -33,7 +33,7 @@ func (c *OpenIDConnectDeviceHandler) HandleDeviceEndpointRequest(ctx context.Con return nil } - if len(resp.GetDeviceCode()) == 0 { + if resp.GetDeviceCode() == "" { return errorsx.WithStack(fosite.ErrMisconfiguration.WithDebug("The device code has not been issued yet, indicating a broken code configuration.")) } diff --git a/handler/openid/flow_device_auth_test.go b/handler/openid/flow_device_auth_test.go index a84e1e44d..a345660f1 100644 --- a/handler/openid/flow_device_auth_test.go +++ b/handler/openid/flow_device_auth_test.go @@ -64,7 +64,7 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) { client := &fosite.DefaultClient{ ID: "foo", - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, } testCases := []struct { @@ -78,7 +78,7 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) { description: "should ignore because scope openid is not set", authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - GrantedScope: fosite.Arguments{"email"}, + RequestedScope: fosite.Arguments{"email"}, }, }, }, @@ -86,9 +86,9 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) { description: "should ignore because client grant type is invalid", authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - GrantedScope: fosite.Arguments{"openid", "email"}, + RequestedScope: fosite.Arguments{"openid", "email"}, Client: &fosite.DefaultClient{ - GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)}, + GrantTypes: []string{"authorization_code"}, }, }, }, @@ -97,8 +97,8 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) { description: "should fail because device code is not issued", authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - GrantedScope: fosite.Arguments{"openid", "email"}, - Client: client, + RequestedScope: fosite.Arguments{"openid", "email"}, + Client: client, }, }, authresp: &fosite.DeviceResponse{}, @@ -108,9 +108,9 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) { description: "should fail because cannot create session", authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - GrantedScope: fosite.Arguments{"openid", "email"}, - Client: client, - Session: session, + RequestedScope: fosite.Arguments{"openid", "email"}, + Client: client, + Session: session, }, }, authresp: &fosite.DeviceResponse{ @@ -128,9 +128,9 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) { description: "should pass", authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - GrantedScope: fosite.Arguments{"openid", "email"}, - Client: client, - Session: session, + RequestedScope: fosite.Arguments{"openid", "email"}, + Client: client, + Session: session, }, }, authresp: &fosite.DeviceResponse{ diff --git a/handler/openid/flow_device_token.go b/handler/openid/flow_device_token.go index 5456b0b4c..c0e2660eb 100644 --- a/handler/openid/flow_device_token.go +++ b/handler/openid/flow_device_token.go @@ -21,6 +21,10 @@ func (c *OpenIDConnectDeviceHandler) PopulateTokenEndpointResponse(ctx context.C return errorsx.WithStack(fosite.ErrUnknownRequest) } + if !requester.GetClient().GetGrantTypes().Has(string(fosite.GrantTypeDeviceCode)) { + return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"urn:ietf:params:oauth:grant-type:device_code\".")) + } + deviceCode := requester.GetRequestForm().Get("device_code") signature, err := c.DeviceCodeStrategy.DeviceCodeSignature(ctx, deviceCode) ar, err := c.OpenIDConnectRequestStorage.GetOpenIDConnectSession(ctx, signature, requester) @@ -35,10 +39,6 @@ func (c *OpenIDConnectDeviceHandler) PopulateTokenEndpointResponse(ctx context.C return errorsx.WithStack(fosite.ErrMisconfiguration.WithDebug("An OpenID Connect session was found but the openid scope is missing, probably due to a broken code configuration.")) } - if !requester.GetClient().GetGrantTypes().Has(string(fosite.GrantTypeDeviceCode)) { - return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"urn:ietf:params:oauth:grant-type:device_code\".")) - } - session, ok := ar.GetSession().(Session) if !ok { return errorsx.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because session must be of type fosite/handler/openid.Session.")) diff --git a/handler/openid/flow_device_token_test.go b/handler/openid/flow_device_token_test.go index 54f9686ec..03a51cd64 100644 --- a/handler/openid/flow_device_token_test.go +++ b/handler/openid/flow_device_token_test.go @@ -81,7 +81,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { client := &fosite.DefaultClient{ ID: "foo", - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, } testCases := []struct { @@ -95,8 +95,9 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { { description: "should fail because the grant type is invalid", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, + GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ + Client: client, Form: url.Values{"device_code": []string{"device_code"}}, Session: session, }, @@ -107,8 +108,9 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { { description: "should fail because session not found", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ + Client: client, Form: url.Values{"device_code": []string{"device_code"}}, Session: session, }, @@ -122,8 +124,9 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { { description: "should fail because session lookup fails", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ + Client: client, Form: url.Values{"device_code": []string{"device_code"}}, Session: session, }, @@ -136,8 +139,9 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { { description: "should fail because auth request grant scope is invalid", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ + Client: client, Form: url.Values{"device_code": []string{"device_code"}}, Session: session, }, @@ -145,6 +149,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { setup: func(areq *fosite.AccessRequest) { authreq := &fosite.DeviceRequest{ Request: fosite.Request{ + Client: client, GrantedScope: fosite.Arguments{"email"}, Session: session, }, @@ -153,33 +158,10 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { }, expectErr: fosite.ErrMisconfiguration, }, - { - description: "should fail because auth request's client grant type is invalid", - areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, - Request: fosite.Request{ - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)}, - }, - Form: url.Values{"device_code": []string{"device_code"}}, - Session: session, - }, - }, - setup: func(areq *fosite.AccessRequest) { - authreq := &fosite.DeviceRequest{ - Request: fosite.Request{ - GrantedScope: fosite.Arguments{"openid", "email"}, - Session: session, - }, - } - store.EXPECT().GetOpenIDConnectSession(gomock.Any(), gomock.Any(), areq).Return(authreq, nil) - }, - expectErr: fosite.ErrUnauthorizedClient, - }, { description: "should fail because auth request is missing session", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ Client: client, Form: url.Values{"device_code": []string{"device_code"}}, @@ -189,6 +171,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { setup: func(areq *fosite.AccessRequest) { authreq := &fosite.DeviceRequest{ Request: fosite.Request{ + Client: client, GrantedScope: fosite.Arguments{"openid", "email"}, }, } @@ -199,7 +182,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { { description: "should fail because auth request session is missing subject claims", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ Client: client, Form: url.Values{"device_code": []string{"device_code"}}, @@ -209,6 +192,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { setup: func(areq *fosite.AccessRequest) { authreq := &fosite.DeviceRequest{ Request: fosite.Request{ + Client: client, GrantedScope: fosite.Arguments{"openid", "email"}, Session: NewDefaultSession(), }, @@ -220,7 +204,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { { description: "should pass", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ Client: client, Form: url.Values{"device_code": []string{"device_code"}}, diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index f30475140..dbec5fce9 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -79,18 +79,28 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { expectErr error }{ { - description: "should fail because not responsible", + description: "should fail because not responsible for handling the request", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"12345678"}, + GrantTypes: fosite.Arguments{"authorization_code"}, + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + }, + Session: &DefaultDeviceFlowSession{}, + RequestedAt: time.Now().UTC(), + }, }, expectErr: fosite.ErrUnknownRequest, }, { description: "should fail because client is not granted the correct grant type", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{""}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{""}, + }, Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, @@ -100,14 +110,17 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because device code could not be retrieved", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, + }, Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { + setup: func(t *testing.T, areq *fosite.AccessRequest, _ *fosite.DeviceRequest) { deviceCode, _, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form = url.Values{"device_code": {deviceCode}} @@ -117,17 +130,25 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because user has not completed the browser flow", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ - Form: url.Values{}, - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Form: url.Values{}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, + }, Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, + }, + RequestedScope: fosite.Arguments{"foo"}, + GrantedScope: fosite.Arguments{"foo"}, Session: &DefaultDeviceFlowSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), @@ -149,12 +170,12 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because device code has expired", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ ID: "foo", - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, }, GrantedScope: fosite.Arguments{"foo", "offline"}, Session: &DefaultDeviceFlowSession{}, @@ -163,7 +184,9 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { }, authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + RequestedScope: fosite.Arguments{"foo"}, + GrantedScope: fosite.Arguments{"foo"}, Session: &DefaultDeviceFlowSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), @@ -185,16 +208,21 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should fail because client mismatch", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, + }, Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "bar"}, + Client: &fosite.DefaultClient{ID: "bar"}, + RequestedScope: fosite.Arguments{"foo"}, + GrantedScope: fosite.Arguments{"foo"}, Session: &DefaultDeviceFlowSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.DeviceCode: time.Now().Add(time.Hour).UTC(), @@ -215,16 +243,24 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { { description: "should pass", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, + }, Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Client: &fosite.DefaultClient{ + ID: "foo", + GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, + }, + RequestedScope: fosite.Arguments{"foo"}, + GrantedScope: fosite.Arguments{"foo"}, Session: &DefaultDeviceFlowSession{ BrowserFlowCompleted: true, }, @@ -264,7 +300,7 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { } } -func TestDeviceUserCode_HandleTokenEndpointRequest_Ratelimitting(t *testing.T) { +func TestDeviceUserCode_HandleTokenEndpointRequest_RateLimiting(t *testing.T) { for k, strategy := range map[string]struct { oauth2.CoreStrategy RFC8628CodeStrategy @@ -293,21 +329,22 @@ func TestDeviceUserCode_HandleTokenEndpointRequest_Ratelimitting(t *testing.T) { }, } areq := &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ ID: "foo", - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, }, - GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &DefaultDeviceFlowSession{}, - RequestedAt: time.Now().UTC(), + Session: &DefaultDeviceFlowSession{}, + RequestedAt: time.Now().UTC(), }, } authreq := &fosite.DeviceRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{string(fosite.GrantTypeDeviceCode)}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + RequestedScope: fosite.Arguments{"foo"}, + GrantedScope: fosite.Arguments{"foo"}, Session: &DefaultDeviceFlowSession{ BrowserFlowCompleted: true, }, @@ -341,36 +378,46 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { t.Run("strategy="+k, func(t *testing.T) { store := storage.NewMemoryStore() - var h oauth2.GenericCodeTokenEndpointHandler - testCases := []struct { - areq *fosite.AccessRequest description string - setup func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) + areq *fosite.AccessRequest + authreq *fosite.DeviceRequest + setup func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest, config *fosite.Config) check func(t *testing.T, aresp *fosite.AccessResponse) expectErr error }{ { - description: "should fail because not responsible", + description: "should fail because not responsible for handling the request", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"123"}, + GrantTypes: fosite.Arguments{"authorization_code"}, + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + }, + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, + }, + RequestedAt: time.Now().UTC(), + }, }, expectErr: fosite.ErrUnknownRequest, }, { description: "should fail because device code cannot be retrieved", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, + }, + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, }, - Session: &DefaultDeviceFlowSession{}, RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + setup: func(t *testing.T, areq *fosite.AccessRequest, _ *fosite.DeviceRequest, _ *fosite.Config) { code, _, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form.Set("device_code", code) @@ -378,27 +425,37 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { expectErr: fosite.ErrServerError, }, { - description: "should pass with offline scope and refresh token", + description: "should pass with offline scope and refresh token grant type", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode), string(fosite.GrantTypeRefreshToken)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, }, - GrantedScope: fosite.Arguments{"foo", "offline"}, Session: &DefaultDeviceFlowSession{ BrowserFlowCompleted: true, }, RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + RequestedScope: fosite.Arguments{"foo", "bar", "offline"}, + GrantedScope: fosite.Arguments{"foo", "offline"}, + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, + }, + RequestedAt: time.Now().UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest, _ *fosite.Config) { code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) }, check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) @@ -409,28 +466,38 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { }, }, { - description: "should pass with refresh token always provided", + description: "should pass with refresh token grant type", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode), string(fosite.GrantTypeRefreshToken)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, }, - GrantedScope: fosite.Arguments{"foo"}, Session: &DefaultDeviceFlowSession{ BrowserFlowCompleted: true, }, RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + RequestedScope: fosite.Arguments{"foo", "bar"}, + GrantedScope: fosite.Arguments{"foo"}, + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, + }, + RequestedAt: time.Now().UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest, config *fosite.Config) { config.RefreshTokenScopes = []string{} code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) }, check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) @@ -443,25 +510,35 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { { description: "pass and response should not have refresh token", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, }, - GrantedScope: fosite.Arguments{"foo"}, Session: &DefaultDeviceFlowSession{ BrowserFlowCompleted: true, }, RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + authreq: &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + RequestedScope: fosite.Arguments{"foo", "bar"}, + GrantedScope: fosite.Arguments{"foo"}, + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, + }, + RequestedAt: time.Now().UTC(), + }, + }, + setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest, config *fosite.Config) { code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, areq)) + require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) }, check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) @@ -481,7 +558,7 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { AccessTokenLifespan: time.Minute, RefreshTokenScopes: []string{"offline"}, } - h = oauth2.GenericCodeTokenEndpointHandler{ + h := oauth2.GenericCodeTokenEndpointHandler{ AccessRequestValidator: &DeviceAccessRequestValidator{}, CodeHandler: &DeviceCodeHandler{ DeviceRateLimitStrategy: strategy, @@ -498,7 +575,7 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { } if testCase.setup != nil { - testCase.setup(t, testCase.areq, config) + testCase.setup(t, testCase.areq, testCase.authreq, config) } aresp := fosite.NewAccessResponse() @@ -526,25 +603,38 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { var mockDeviceRateLimitStrategy *internal.MockDeviceRateLimitStrategy strategy := hmacshaStrategy deviceStrategy := RFC8628HMACSHAStrategy - request := &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)}, + + authreq := &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, + RequestedScope: fosite.Arguments{"foo", "offline"}, + GrantedScope: fosite.Arguments{"foo", "offline"}, + Session: &DefaultDeviceFlowSession{ + BrowserFlowCompleted: true, + }, + RequestedAt: time.Now().UTC(), + }, + } + + areq := &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, Request: fosite.Request{ Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode), string(fosite.GrantTypeRefreshToken)}, + GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, }, - GrantedScope: fosite.Arguments{"offline"}, Session: &DefaultDeviceFlowSession{ BrowserFlowCompleted: true, }, RequestedAt: time.Now().UTC(), }, } - token, _, err := deviceStrategy.GenerateDeviceCode(context.Background()) - require.NoError(t, err) - request.Form = url.Values{"device_code": {token}} - response := fosite.NewAccessResponse() + aresp := fosite.NewAccessResponse() propagatedContext := context.Background() + code, _, err := deviceStrategy.GenerateDeviceCode(context.Background()) + require.NoError(t, err) + areq.Form = url.Values{"device_code": {code}} + // some storage implementation that has support for transactions, notice the embedded type `storage.Transactional` type coreTransactionalStore struct { storage.Transactional @@ -567,7 +657,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockDeviceCodeStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -601,7 +691,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockDeviceCodeStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -626,7 +716,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockDeviceCodeStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -656,7 +746,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockDeviceCodeStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -671,7 +761,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockDeviceCodeStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -696,7 +786,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockDeviceCodeStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(request, nil). + Return(authreq, nil). Times(1) mockTransactional. EXPECT(). @@ -743,7 +833,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { mockDeviceRateLimitStrategy = internal.NewMockDeviceRateLimitStrategy(ctrl) testCase.setup() - handler := oauth2.GenericCodeTokenEndpointHandler{ + h := oauth2.GenericCodeTokenEndpointHandler{ AccessRequestValidator: &DeviceAccessRequestValidator{}, CodeHandler: &DeviceCodeHandler{ DeviceRateLimitStrategy: mockDeviceRateLimitStrategy, @@ -768,7 +858,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { }, } - if err = handler.PopulateTokenEndpointResponse(propagatedContext, request, response); testCase.expectError != nil { + if err = h.PopulateTokenEndpointResponse(propagatedContext, areq, aresp); testCase.expectError != nil { assert.EqualError(t, err, testCase.expectError.Error()) } }) diff --git a/integration/authorize_device_grant_request_test.go b/integration/authorize_device_grant_request_test.go index 170c906fa..9eb2460ae 100644 --- a/integration/authorize_device_grant_request_test.go +++ b/integration/authorize_device_grant_request_test.go @@ -53,14 +53,14 @@ func runDeviceFlowTest(t *testing.T) { { description: "should fail with invalid_grant", setup: func() { - fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{string(fosite.GrantTypeAuthorizationCode)} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"authorization_code"} }, err: true, check: func(t *testing.T, token *goauth.DeviceAuthResponse, err error) { assert.ErrorContains(t, err, "invalid_grant") }, cleanUp: func() { - fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{string(fosite.GrantTypeDeviceCode)} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} }, }, { @@ -152,7 +152,6 @@ func runDeviceFlowAccessTokenTest(t *testing.T) { description string setup func() params []goauth.AuthCodeOption - err bool check func(t *testing.T, token *goauth.Token, err error) cleanUp func() }{ @@ -161,7 +160,6 @@ func runDeviceFlowAccessTokenTest(t *testing.T) { setup: func() { }, params: []goauth.AuthCodeOption{goauth.SetAuthURLParam("grant_type", "invalid_grant_type")}, - err: true, check: func(t *testing.T, token *goauth.Token, err error) { assert.ErrorContains(t, err, "invalid_request") }, @@ -169,22 +167,20 @@ func runDeviceFlowAccessTokenTest(t *testing.T) { { description: "should fail with unauthorized client", setup: func() { - fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{string(fosite.GrantTypeAuthorizationCode)} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"authorization_code"} }, params: []goauth.AuthCodeOption{}, - err: true, check: func(t *testing.T, token *goauth.Token, err error) { assert.ErrorContains(t, err, "unauthorized_client") }, cleanUp: func() { - fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{string(fosite.GrantTypeDeviceCode)} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} }, }, { description: "should fail with invalid device code", setup: func() {}, params: []goauth.AuthCodeOption{goauth.SetAuthURLParam("device_code", "invalid_device_code")}, - err: true, check: func(t *testing.T, token *goauth.Token, err error) { assert.ErrorContains(t, err, "invalid_grant") }, @@ -194,7 +190,6 @@ func runDeviceFlowAccessTokenTest(t *testing.T) { setup: func() { oauthClient.ClientID = "invalid_client_id" }, - err: true, check: func(t *testing.T, token *goauth.Token, err error) { assert.ErrorContains(t, err, "invalid_client") }, @@ -204,17 +199,18 @@ func runDeviceFlowAccessTokenTest(t *testing.T) { }, { description: "should pass", - setup: func() {}, - err: false, + check: func(t *testing.T, token *goauth.Token, err error) { + assert.Equal(t, "bearer", token.TokenType) + assert.NotEmpty(t, token.AccessToken) + }, }, } { t.Run(fmt.Sprintf("case=%d description=%s", k, c.description), func(t *testing.T) { - c.setup() + if c.setup != nil { + c.setup() + } token, err := oauthClient.DeviceAccessToken(context.Background(), resp, c.params...) - if !c.err { - assert.NotEmpty(t, token.AccessToken) - } if c.check != nil { c.check(t, token, err) From 8951431794d949781f65dc0224680a47991eba44 Mon Sep 17 00:00:00 2001 From: Nikos Date: Mon, 29 Apr 2024 11:09:30 +0300 Subject: [PATCH 20/36] fix: use correct grant lifespan to issue tokens --- handler/oauth2/flow_authorize_code_token.go | 4 ++++ handler/oauth2/flow_generic_code_token.go | 9 ++++++--- handler/rfc8628/token_handler.go | 4 ++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/handler/oauth2/flow_authorize_code_token.go b/handler/oauth2/flow_authorize_code_token.go index 7073ecf6e..abecc0e3b 100644 --- a/handler/oauth2/flow_authorize_code_token.go +++ b/handler/oauth2/flow_authorize_code_token.go @@ -79,6 +79,10 @@ func (v AuthorizeExplicitGrantAccessRequestValidator) ValidateGrantTypes(request return nil } +func (v AuthorizeExplicitGrantAccessRequestValidator) GetGrantType(requester fosite.AccessRequester) fosite.GrantType { + return fosite.GrantTypeAuthorizationCode +} + func (v AuthorizeExplicitGrantAccessRequestValidator) ValidateRedirectURI(accessRequester fosite.AccessRequester, authorizeRequester fosite.Requester) error { forcedRedirectURI := authorizeRequester.GetRequestForm().Get("redirect_uri") requestedRedirectURI := accessRequester.GetRequestForm().Get("redirect_uri") diff --git a/handler/oauth2/flow_generic_code_token.go b/handler/oauth2/flow_generic_code_token.go index 031ec84e5..407d6b1ac 100644 --- a/handler/oauth2/flow_generic_code_token.go +++ b/handler/oauth2/flow_generic_code_token.go @@ -28,6 +28,9 @@ type AccessRequestValidator interface { // ValidateRedirectURI validates the redirect uri in the access request. ValidateRedirectURI(accessRequester fosite.AccessRequester, authorizeRequester fosite.Requester) error + + // GetGrantType retrieves the grant type from the request. + GetGrantType(requester fosite.AccessRequester) fosite.GrantType } // CodeHandler handles authorization/device code related operations. @@ -138,7 +141,7 @@ func (c *GenericCodeTokenEndpointHandler) PopulateTokenEndpointResponse(ctx cont } } - lifeSpan := fosite.GetEffectiveLifespan(requester.GetClient(), fosite.GrantTypeAuthorizationCode, fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) + lifeSpan := fosite.GetEffectiveLifespan(requester.GetClient(), c.GetGrantType(requester), fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) responder.SetAccessToken(accessToken) responder.SetTokenType("bearer") responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, lifeSpan, time.Now().UTC())) @@ -209,10 +212,10 @@ func (c *GenericCodeTokenEndpointHandler) HandleTokenEndpointRequest(ctx context requester.SetSession(ar.GetSession()) requester.SetID(ar.GetID()) - atLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), fosite.GrantTypeAuthorizationCode, fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) + atLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), c.GetGrantType(requester), fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) requester.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(atLifespan).Round(time.Second)) - rtLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), fosite.GrantTypeAuthorizationCode, fosite.RefreshToken, c.Config.GetRefreshTokenLifespan(ctx)) + rtLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), c.GetGrantType(requester), fosite.RefreshToken, c.Config.GetRefreshTokenLifespan(ctx)) if rtLifespan > -1 { requester.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(rtLifespan).Round(time.Second)) } diff --git a/handler/rfc8628/token_handler.go b/handler/rfc8628/token_handler.go index 29fb8fc7b..5313af9f4 100644 --- a/handler/rfc8628/token_handler.go +++ b/handler/rfc8628/token_handler.go @@ -108,6 +108,10 @@ func (v DeviceAccessRequestValidator) ValidateRedirectURI(accessRequester fosite return nil } +func (v DeviceAccessRequestValidator) GetGrantType(requester fosite.AccessRequester) fosite.GrantType { + return fosite.GrantTypeDeviceCode +} + type DeviceCodeTokenEndpointHandler struct { oauth2.GenericCodeTokenEndpointHandler } From 040eb7c33c12e742c21343838bac6e5d3f8fbcde Mon Sep 17 00:00:00 2001 From: dushu Date: Mon, 29 Apr 2024 19:21:12 -0400 Subject: [PATCH 21/36] fix: handle the user code generation duplication --- generate-mocks.sh | 3 +- generate.go | 3 +- handler/rfc8628/auth_handler.go | 69 ++++++--- handler/rfc8628/auth_handler_test.go | 163 ++++++++++++++++++++- internal/rfc8628_code_strategy.go | 144 ++++++++++++++++++ internal/rfc8628_core_storage.go | 211 +++++++++++++++++++++++++++ 6 files changed, 571 insertions(+), 22 deletions(-) create mode 100644 internal/rfc8628_code_strategy.go create mode 100644 internal/rfc8628_core_storage.go diff --git a/generate-mocks.sh b/generate-mocks.sh index 2ed96b708..5637f2c8c 100755 --- a/generate-mocks.sh +++ b/generate-mocks.sh @@ -6,7 +6,7 @@ mockgen -package internal -destination internal/transactional.go github.com/ory/ mockgen -package internal -destination internal/oauth2_storage.go github.com/ory/fosite/handler/oauth2 CoreStorage mockgen -package internal -destination internal/oauth2_strategy.go github.com/ory/fosite/handler/oauth2 CoreStrategy mockgen -package internal -destination internal/authorize_code_storage.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStorage -mockgen -package internal -destination internal/device_code_storage.go github.com/ory/fosite/handler/rfc8628 DeviceCodeStorage +mockgen -package internal -destination internal/rfc8628_core_storage.go github.com/ory/fosite/handler/rfc8628 RFC8628CoreStorage mockgen -package internal -destination internal/oauth2_auth_jwt_storage.go github.com/ory/fosite/handler/rfc7523 RFC7523KeyStorage mockgen -package internal -destination internal/access_token_storage.go github.com/ory/fosite/handler/oauth2 AccessTokenStorage mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStorage @@ -17,6 +17,7 @@ mockgen -package internal -destination internal/openid_id_token_storage.go githu mockgen -package internal -destination internal/access_token_strategy.go github.com/ory/fosite/handler/oauth2 AccessTokenStrategy mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStrategy mockgen -package internal -destination internal/authorize_code_strategy.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStrategy +mockgen -package internal -destination internal/rfc8628_code_strategy.go github.com/ory/fosite/handler/rfc8628 RFC8628CodeStrategy mockgen -package internal -destination internal/device_code_rate_limit_strategy.go github.com/ory/fosite/handler/rfc8628 DeviceRateLimitStrategy mockgen -package internal -destination internal/id_token_strategy.go github.com/ory/fosite/handler/openid OpenIDConnectTokenStrategy mockgen -package internal -destination internal/pkce_storage_strategy.go github.com/ory/fosite/handler/pkce PKCERequestStorage diff --git a/generate.go b/generate.go index 0b3efaf63..891dc8381 100644 --- a/generate.go +++ b/generate.go @@ -9,7 +9,7 @@ package fosite //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_storage.go github.com/ory/fosite/handler/oauth2 CoreStorage //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_strategy.go github.com/ory/fosite/handler/oauth2 CoreStrategy //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/authorize_code_storage.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/device_code_storage.go github.com/ory/fosite/handler/rfc8628 DeviceCodeStorage +//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/rfc8628_core_storage.go github.com/ory/fosite/handler/rfc8628 RFC8628CoreStorage //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_auth_jwt_storage.go github.com/ory/fosite/handler/rfc7523 RFC7523KeyStorage //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/access_token_storage.go github.com/ory/fosite/handler/oauth2 AccessTokenStorage //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStorage @@ -21,6 +21,7 @@ package fosite //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStrategy //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/authorize_code_strategy.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStrategy //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/device_code_rate_limit_strategy.go github.com/ory/fosite/handler/rfc8628 DeviceRateLimitStrategy +//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/rfc8628_code_strategy.go github.com/ory/fosite/handler/rfc8628 RFC8628CodeStrategy //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/id_token_strategy.go github.com/ory/fosite/handler/openid OpenIDConnectTokenStrategy //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/pkce_storage_strategy.go github.com/ory/fosite/handler/pkce PKCERequestStorage //go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/authorize_handler.go github.com/ory/fosite AuthorizeEndpointHandler diff --git a/handler/rfc8628/auth_handler.go b/handler/rfc8628/auth_handler.go index aa31ff520..70a6af8a4 100644 --- a/handler/rfc8628/auth_handler.go +++ b/handler/rfc8628/auth_handler.go @@ -5,13 +5,16 @@ package rfc8628 import ( "context" + "fmt" "time" - "github.com/ory/x/errorsx" - "github.com/ory/fosite" + "github.com/ory/x/errorsx" ) +// MaxAttempts for retrying the generation of user codes. +const MaxAttempts = 3 + // DeviceAuthHandler is a response handler for the Device Authorisation Grant as // defined in https://tools.ietf.org/html/rfc8628#section-3.1 type DeviceAuthHandler struct { @@ -25,25 +28,18 @@ type DeviceAuthHandler struct { // HandleDeviceEndpointRequest implements https://tools.ietf.org/html/rfc8628#section-3.1 func (d *DeviceAuthHandler) HandleDeviceEndpointRequest(ctx context.Context, dar fosite.DeviceRequester, resp fosite.DeviceResponder) error { - deviceCode, deviceCodeSignature, err := d.Strategy.GenerateDeviceCode(ctx) - if err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } + var err error - userCode, userCodeSignature, err := d.Strategy.GenerateUserCode(ctx) + var deviceCode string + deviceCode, err = d.handleDeviceCode(ctx, dar) if err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + return err } - // Store the User Code session (this has no real data other that the user and device code), can be converted into a 'full' session after user auth - dar.GetSession().SetExpiresAt(fosite.DeviceCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx))) - if err := d.Storage.CreateDeviceCodeSession(ctx, deviceCodeSignature, dar.Sanitize(nil)); err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } - - dar.GetSession().SetExpiresAt(fosite.UserCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx)).Round(time.Second)) - if err := d.Storage.CreateUserCodeSession(ctx, userCodeSignature, dar.Sanitize(nil)); err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + var userCode string + userCode, err = d.handleUserCode(ctx, dar) + if err != nil { + return err } // Populate the response fields @@ -55,3 +51,42 @@ func (d *DeviceAuthHandler) HandleDeviceEndpointRequest(ctx context.Context, dar resp.SetInterval(int(d.Config.GetDeviceAuthTokenPollingInterval(ctx).Seconds())) return nil } + +func (d *DeviceAuthHandler) handleDeviceCode(ctx context.Context, dar fosite.DeviceRequester) (string, error) { + code, signature, err := d.Strategy.GenerateDeviceCode(ctx) + if err != nil { + return "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + dar.GetSession().SetExpiresAt(fosite.DeviceCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx))) + if err = d.Storage.CreateDeviceCodeSession(ctx, signature, dar.Sanitize(nil)); err != nil { + return "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + return code, nil +} + +func (d *DeviceAuthHandler) handleUserCode(ctx context.Context, dar fosite.DeviceRequester) (string, error) { + var err error + var userCode, signature string + // Note: the retries are added here because we need to ensure uniqueness of user codes. + // The chances of duplicates should however be diminishing, because they are the same + // chance an attacker will be able to hit a valid code with few guesses. However, as + // used codes will probably still be around for some time before they get cleaned, + // the chances of hitting a duplicate here can be higher. + // Three retries should be plenty, as otherwise the entropy is definitely off. + for i := 0; i < MaxAttempts; i++ { + userCode, signature, err = d.Strategy.GenerateUserCode(ctx) + if err != nil { + return "", err + } + + dar.GetSession().SetExpiresAt(fosite.UserCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx)).Round(time.Second)) + if err = d.Storage.CreateUserCodeSession(ctx, signature, dar.Sanitize(nil)); err == nil { + return userCode, nil + } + } + + errMsg := fmt.Sprintf("Exceeded user-code generation max attempts %v: %s", MaxAttempts, err.Error()) + return "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(errMsg)) +} diff --git a/handler/rfc8628/auth_handler_test.go b/handler/rfc8628/auth_handler_test.go index 74f010506..ec20b8527 100644 --- a/handler/rfc8628/auth_handler_test.go +++ b/handler/rfc8628/auth_handler_test.go @@ -5,15 +5,20 @@ package rfc8628_test import ( "context" + "errors" + "fmt" "testing" "time" - "github.com/ory/fosite/storage" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/golang/mock/gomock" + + "github.com/ory/fosite/internal" "github.com/ory/fosite" "github.com/ory/fosite/handler/rfc8628" + "github.com/ory/fosite/storage" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func Test_HandleDeviceEndpointRequest(t *testing.T) { @@ -52,3 +57,155 @@ func Test_HandleDeviceEndpointRequest(t *testing.T) { assert.Contains(t, resp.GetDeviceCode(), ".") assert.Equal(t, resp.GetVerificationURI(), "www.test.com") } + +func Test_HandleDeviceEndpointRequestWithRetry(t *testing.T) { + var mockRFC8628CoreStorage *internal.MockRFC8628CoreStorage + var mockRFC8628CodeStrategy *internal.MockRFC8628CodeStrategy + + ctx := context.Background() + req := &fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + Audience: []string{"https://www.ory.sh/api"}, + }, + Session: &fosite.DefaultSession{}, + }, + } + + testCases := []struct { + description string + setup func() + check func(t *testing.T, resp *fosite.DeviceResponse) + expectError error + }{ + { + description: "should pass when generating a unique user code at the first attempt", + setup: func() { + mockRFC8628CodeStrategy. + EXPECT(). + GenerateDeviceCode(ctx). + Return("deviceCode", "signature", nil) + mockRFC8628CoreStorage. + EXPECT(). + CreateDeviceCodeSession(ctx, "signature", gomock.Any()). + Return(nil) + mockRFC8628CodeStrategy. + EXPECT(). + GenerateUserCode(ctx). + Return("userCode", "signature", nil). + Times(1) + mockRFC8628CoreStorage. + EXPECT(). + CreateUserCodeSession(ctx, "signature", gomock.Any()). + Return(nil). + Times(1) + }, + check: func(t *testing.T, resp *fosite.DeviceResponse) { + assert.Equal(t, "userCode", resp.GetUserCode()) + }, + }, + { + description: "should pass when generating a unique user code within allowed attempts", + setup: func() { + mockRFC8628CodeStrategy. + EXPECT(). + GenerateDeviceCode(ctx). + Return("deviceCode", "signature", nil) + mockRFC8628CoreStorage. + EXPECT(). + CreateDeviceCodeSession(ctx, "signature", gomock.Any()). + Return(nil) + gomock.InOrder( + mockRFC8628CodeStrategy. + EXPECT(). + GenerateUserCode(ctx). + Return("duplicatedUserCode", "duplicatedSignature", nil), + mockRFC8628CoreStorage. + EXPECT(). + CreateUserCodeSession(ctx, "duplicatedSignature", gomock.Any()). + Return(errors.New("unique constraint violation")), + mockRFC8628CodeStrategy. + EXPECT(). + GenerateUserCode(ctx). + Return("uniqueUserCode", "uniqueSignature", nil), + mockRFC8628CoreStorage. + EXPECT(). + CreateUserCodeSession(ctx, "uniqueSignature", gomock.Any()). + Return(nil), + ) + }, + check: func(t *testing.T, resp *fosite.DeviceResponse) { + assert.Equal(t, "uniqueUserCode", resp.GetUserCode()) + }, + }, + { + description: "should fail after maximum retries to generate a unique user code", + setup: func() { + mockRFC8628CodeStrategy. + EXPECT(). + GenerateDeviceCode(ctx). + Return("deviceCode", "signature", nil) + mockRFC8628CoreStorage. + EXPECT(). + CreateDeviceCodeSession(ctx, "signature", gomock.Any()). + Return(nil) + mockRFC8628CodeStrategy. + EXPECT(). + GenerateUserCode(ctx). + Return("duplicatedUserCode", "duplicatedSignature", nil). + Times(rfc8628.MaxAttempts) + mockRFC8628CoreStorage. + EXPECT(). + CreateUserCodeSession(ctx, "duplicatedSignature", gomock.Any()). + Return(errors.New("unique constraint violation")). + Times(rfc8628.MaxAttempts) + }, + check: func(t *testing.T, resp *fosite.DeviceResponse) { + assert.Empty(t, resp.GetUserCode()) + }, + expectError: fosite.ErrServerError, + }, + } + + for _, testCase := range testCases { + t.Run(fmt.Sprintf("scenario=%s", testCase.description), func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockRFC8628CoreStorage = internal.NewMockRFC8628CoreStorage(ctrl) + mockRFC8628CodeStrategy = internal.NewMockRFC8628CodeStrategy(ctrl) + + h := rfc8628.DeviceAuthHandler{ + Storage: mockRFC8628CoreStorage, + Strategy: mockRFC8628CodeStrategy, + Config: &fosite.Config{ + DeviceAndUserCodeLifespan: time.Minute * 10, + DeviceAuthTokenPollingInterval: time.Second * 5, + DeviceVerificationURL: "www.test.com", + AccessTokenLifespan: time.Hour, + RefreshTokenLifespan: time.Hour, + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + RefreshTokenScopes: []string{"offline"}, + }, + } + + if testCase.setup != nil { + testCase.setup() + } + + resp := fosite.NewDeviceResponse() + err := h.HandleDeviceEndpointRequest(ctx, req, resp) + + if testCase.expectError != nil { + require.EqualError(t, err, testCase.expectError.Error(), "%+v", err) + } else { + require.NoError(t, err, "%+v", err) + } + + if testCase.check != nil { + testCase.check(t, resp) + } + }) + } +} diff --git a/internal/rfc8628_code_strategy.go b/internal/rfc8628_code_strategy.go new file mode 100644 index 000000000..a328ac1fa --- /dev/null +++ b/internal/rfc8628_code_strategy.go @@ -0,0 +1,144 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ory/fosite/handler/rfc8628 (interfaces: RFC8628CodeStrategy) + +// Package internal is a generated GoMock package. +package internal + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + fosite "github.com/ory/fosite" +) + +// MockRFC8628CodeStrategy is a mock of RFC8628CodeStrategy interface. +type MockRFC8628CodeStrategy struct { + ctrl *gomock.Controller + recorder *MockRFC8628CodeStrategyMockRecorder +} + +// MockRFC8628CodeStrategyMockRecorder is the mock recorder for MockRFC8628CodeStrategy. +type MockRFC8628CodeStrategyMockRecorder struct { + mock *MockRFC8628CodeStrategy +} + +// NewMockRFC8628CodeStrategy creates a new mock instance. +func NewMockRFC8628CodeStrategy(ctrl *gomock.Controller) *MockRFC8628CodeStrategy { + mock := &MockRFC8628CodeStrategy{ctrl: ctrl} + mock.recorder = &MockRFC8628CodeStrategyMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRFC8628CodeStrategy) EXPECT() *MockRFC8628CodeStrategyMockRecorder { + return m.recorder +} + +// DeviceCodeSignature mocks base method. +func (m *MockRFC8628CodeStrategy) DeviceCodeSignature(arg0 context.Context, arg1 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeviceCodeSignature", arg0, arg1) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeviceCodeSignature indicates an expected call of DeviceCodeSignature. +func (mr *MockRFC8628CodeStrategyMockRecorder) DeviceCodeSignature(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeviceCodeSignature", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).DeviceCodeSignature), arg0, arg1) +} + +// GenerateDeviceCode mocks base method. +func (m *MockRFC8628CodeStrategy) GenerateDeviceCode(arg0 context.Context) (string, string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GenerateDeviceCode", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(string) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GenerateDeviceCode indicates an expected call of GenerateDeviceCode. +func (mr *MockRFC8628CodeStrategyMockRecorder) GenerateDeviceCode(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateDeviceCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).GenerateDeviceCode), arg0) +} + +// GenerateUserCode mocks base method. +func (m *MockRFC8628CodeStrategy) GenerateUserCode(arg0 context.Context) (string, string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GenerateUserCode", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(string) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GenerateUserCode indicates an expected call of GenerateUserCode. +func (mr *MockRFC8628CodeStrategyMockRecorder) GenerateUserCode(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateUserCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).GenerateUserCode), arg0) +} + +// ShouldRateLimit mocks base method. +func (m *MockRFC8628CodeStrategy) ShouldRateLimit(arg0 context.Context, arg1 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ShouldRateLimit", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ShouldRateLimit indicates an expected call of ShouldRateLimit. +func (mr *MockRFC8628CodeStrategyMockRecorder) ShouldRateLimit(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldRateLimit", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).ShouldRateLimit), arg0, arg1) +} + +// UserCodeSignature mocks base method. +func (m *MockRFC8628CodeStrategy) UserCodeSignature(arg0 context.Context, arg1 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UserCodeSignature", arg0, arg1) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UserCodeSignature indicates an expected call of UserCodeSignature. +func (mr *MockRFC8628CodeStrategyMockRecorder) UserCodeSignature(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserCodeSignature", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).UserCodeSignature), arg0, arg1) +} + +// ValidateDeviceCode mocks base method. +func (m *MockRFC8628CodeStrategy) ValidateDeviceCode(arg0 context.Context, arg1 fosite.Requester, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateDeviceCode", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidateDeviceCode indicates an expected call of ValidateDeviceCode. +func (mr *MockRFC8628CodeStrategyMockRecorder) ValidateDeviceCode(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateDeviceCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).ValidateDeviceCode), arg0, arg1, arg2) +} + +// ValidateUserCode mocks base method. +func (m *MockRFC8628CodeStrategy) ValidateUserCode(arg0 context.Context, arg1 fosite.Requester, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateUserCode", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidateUserCode indicates an expected call of ValidateUserCode. +func (mr *MockRFC8628CodeStrategyMockRecorder) ValidateUserCode(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateUserCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).ValidateUserCode), arg0, arg1, arg2) +} diff --git a/internal/rfc8628_core_storage.go b/internal/rfc8628_core_storage.go new file mode 100644 index 000000000..93340de2d --- /dev/null +++ b/internal/rfc8628_core_storage.go @@ -0,0 +1,211 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ory/fosite/handler/rfc8628 (interfaces: RFC8628CoreStorage) + +// Package internal is a generated GoMock package. +package internal + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + fosite "github.com/ory/fosite" +) + +// MockRFC8628CoreStorage is a mock of RFC8628CoreStorage interface. +type MockRFC8628CoreStorage struct { + ctrl *gomock.Controller + recorder *MockRFC8628CoreStorageMockRecorder +} + +// MockRFC8628CoreStorageMockRecorder is the mock recorder for MockRFC8628CoreStorage. +type MockRFC8628CoreStorageMockRecorder struct { + mock *MockRFC8628CoreStorage +} + +// NewMockRFC8628CoreStorage creates a new mock instance. +func NewMockRFC8628CoreStorage(ctrl *gomock.Controller) *MockRFC8628CoreStorage { + mock := &MockRFC8628CoreStorage{ctrl: ctrl} + mock.recorder = &MockRFC8628CoreStorageMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRFC8628CoreStorage) EXPECT() *MockRFC8628CoreStorageMockRecorder { + return m.recorder +} + +// CreateAccessTokenSession mocks base method. +func (m *MockRFC8628CoreStorage) CreateAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateAccessTokenSession", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateAccessTokenSession indicates an expected call of CreateAccessTokenSession. +func (mr *MockRFC8628CoreStorageMockRecorder) CreateAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateAccessTokenSession), arg0, arg1, arg2) +} + +// CreateDeviceCodeSession mocks base method. +func (m *MockRFC8628CoreStorage) CreateDeviceCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateDeviceCodeSession", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateDeviceCodeSession indicates an expected call of CreateDeviceCodeSession. +func (mr *MockRFC8628CoreStorageMockRecorder) CreateDeviceCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDeviceCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateDeviceCodeSession), arg0, arg1, arg2) +} + +// CreateRefreshTokenSession mocks base method. +func (m *MockRFC8628CoreStorage) CreateRefreshTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateRefreshTokenSession", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateRefreshTokenSession indicates an expected call of CreateRefreshTokenSession. +func (mr *MockRFC8628CoreStorageMockRecorder) CreateRefreshTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRefreshTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateRefreshTokenSession), arg0, arg1, arg2) +} + +// CreateUserCodeSession mocks base method. +func (m *MockRFC8628CoreStorage) CreateUserCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateUserCodeSession", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateUserCodeSession indicates an expected call of CreateUserCodeSession. +func (mr *MockRFC8628CoreStorageMockRecorder) CreateUserCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUserCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateUserCodeSession), arg0, arg1, arg2) +} + +// DeleteAccessTokenSession mocks base method. +func (m *MockRFC8628CoreStorage) DeleteAccessTokenSession(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteAccessTokenSession", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteAccessTokenSession indicates an expected call of DeleteAccessTokenSession. +func (mr *MockRFC8628CoreStorageMockRecorder) DeleteAccessTokenSession(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).DeleteAccessTokenSession), arg0, arg1) +} + +// DeleteRefreshTokenSession mocks base method. +func (m *MockRFC8628CoreStorage) DeleteRefreshTokenSession(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteRefreshTokenSession", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteRefreshTokenSession indicates an expected call of DeleteRefreshTokenSession. +func (mr *MockRFC8628CoreStorageMockRecorder) DeleteRefreshTokenSession(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRefreshTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).DeleteRefreshTokenSession), arg0, arg1) +} + +// GetAccessTokenSession mocks base method. +func (m *MockRFC8628CoreStorage) GetAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAccessTokenSession", arg0, arg1, arg2) + ret0, _ := ret[0].(fosite.Requester) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAccessTokenSession indicates an expected call of GetAccessTokenSession. +func (mr *MockRFC8628CoreStorageMockRecorder) GetAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetAccessTokenSession), arg0, arg1, arg2) +} + +// GetDeviceCodeSession mocks base method. +func (m *MockRFC8628CoreStorage) GetDeviceCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDeviceCodeSession", arg0, arg1, arg2) + ret0, _ := ret[0].(fosite.Requester) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDeviceCodeSession indicates an expected call of GetDeviceCodeSession. +func (mr *MockRFC8628CoreStorageMockRecorder) GetDeviceCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeviceCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetDeviceCodeSession), arg0, arg1, arg2) +} + +// GetRefreshTokenSession mocks base method. +func (m *MockRFC8628CoreStorage) GetRefreshTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRefreshTokenSession", arg0, arg1, arg2) + ret0, _ := ret[0].(fosite.Requester) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRefreshTokenSession indicates an expected call of GetRefreshTokenSession. +func (mr *MockRFC8628CoreStorageMockRecorder) GetRefreshTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRefreshTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetRefreshTokenSession), arg0, arg1, arg2) +} + +// GetUserCodeSession mocks base method. +func (m *MockRFC8628CoreStorage) GetUserCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserCodeSession", arg0, arg1, arg2) + ret0, _ := ret[0].(fosite.Requester) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserCodeSession indicates an expected call of GetUserCodeSession. +func (mr *MockRFC8628CoreStorageMockRecorder) GetUserCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetUserCodeSession), arg0, arg1, arg2) +} + +// InvalidateDeviceCodeSession mocks base method. +func (m *MockRFC8628CoreStorage) InvalidateDeviceCodeSession(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InvalidateDeviceCodeSession", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// InvalidateDeviceCodeSession indicates an expected call of InvalidateDeviceCodeSession. +func (mr *MockRFC8628CoreStorageMockRecorder) InvalidateDeviceCodeSession(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateDeviceCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).InvalidateDeviceCodeSession), arg0, arg1) +} + +// InvalidateUserCodeSession mocks base method. +func (m *MockRFC8628CoreStorage) InvalidateUserCodeSession(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InvalidateUserCodeSession", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// InvalidateUserCodeSession indicates an expected call of InvalidateUserCodeSession. +func (mr *MockRFC8628CoreStorageMockRecorder) InvalidateUserCodeSession(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateUserCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).InvalidateUserCodeSession), arg0, arg1) +} From bc45749eb93cc0c6294b00c80310d99369d41c65 Mon Sep 17 00:00:00 2001 From: Nikos Date: Thu, 12 Sep 2024 14:35:55 +0300 Subject: [PATCH 22/36] chore: migrate to uber/gomock --- Makefile | 2 +- access_error_test.go | 2 +- access_request_handler_test.go | 2 +- access_response_writer_test.go | 2 +- access_write_test.go | 2 +- authorize_error_test.go | 2 +- authorize_request_handler_test.go | 2 +- authorize_response_writer_test.go | 2 +- authorize_write_test.go | 2 +- device_request_handler_test.go | 2 +- generate.go | 62 +++++----- go.mod | 2 + go.sum | 2 + .../oauth2/flow_authorize_code_token_test.go | 2 +- .../oauth2/flow_authorize_implicit_test.go | 2 +- .../oauth2/flow_client_credentials_test.go | 2 +- handler/oauth2/flow_refresh_test.go | 2 +- handler/oauth2/flow_resource_owner_test.go | 2 +- handler/oauth2/helper_test.go | 2 +- handler/oauth2/introspector_test.go | 2 +- handler/oauth2/revocation_test.go | 2 +- handler/openid/flow_device_auth_test.go | 2 +- handler/openid/flow_device_token_test.go | 2 +- handler/openid/flow_explicit_auth_test.go | 2 +- handler/openid/flow_explicit_token_test.go | 2 +- handler/openid/flow_hybrid_test.go | 2 +- handler/openid/flow_implicit_test.go | 2 +- handler/openid/helper_test.go | 2 +- handler/rfc7523/handler_test.go | 2 +- handler/rfc8628/auth_handler_test.go | 2 +- handler/rfc8628/token_handler_test.go | 2 +- handler/verifiable/handler_test.go | 2 +- internal/access_request.go | 80 +++++++------ internal/access_response.go | 56 ++++----- internal/access_token_storage.go | 32 +++--- internal/access_token_strategy.go | 32 +++--- internal/authorize_code_storage.go | 32 +++--- internal/authorize_code_strategy.go | 32 +++--- internal/authorize_handler.go | 16 ++- internal/authorize_request.go | 96 ++++++++-------- internal/authorize_response.go | 24 ++-- internal/client.go | 8 +- internal/device_code_rate_limit_strategy.go | 19 +++- internal/device_code_storage.go | 14 ++- internal/hash.go | 24 ++-- internal/id_token_strategy.go | 16 ++- internal/introspector.go | 16 ++- internal/oauth2_auth_jwt_storage.go | 48 ++++---- internal/oauth2_client_storage.go | 32 +++--- internal/oauth2_explicit_storage.go | 2 +- internal/oauth2_owner_storage.go | 72 ++++++------ internal/oauth2_refresh_storage.go | 2 +- internal/oauth2_revoke_storage.go | 80 +++++++------ internal/oauth2_storage.go | 88 ++++++++------- internal/oauth2_strategy.go | 80 +++++++------ internal/openid_id_token_storage.go | 32 +++--- internal/pkce_storage_strategy.go | 32 +++--- internal/pushed_authorize_handler.go | 2 +- internal/refresh_token_strategy.go | 32 +++--- internal/request.go | 80 +++++++------ internal/revoke_handler.go | 16 ++- internal/rfc8628_code_strategy.go | 64 ++++++----- internal/rfc8628_core_storage.go | 106 +++++++++++------- internal/rw.go | 2 +- internal/storage.go | 32 +++--- internal/token_handler.go | 40 ++++--- internal/transactional.go | 32 +++--- introspect_test.go | 2 +- introspection_request_handler_test.go | 2 +- introspection_response_writer_test.go | 2 +- pushed_authorize_request_handler_test.go | 2 +- pushed_authorize_response_writer_test.go | 2 +- revoke_handler_test.go | 2 +- tools.go | 2 +- 74 files changed, 856 insertions(+), 653 deletions(-) diff --git a/Makefile b/Makefile index dbbc657ab..9308cd288 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ test: # runs all tests curl https://raw.githubusercontent.com/ory/ci/master/licenses/install | sh .bin/mockgen: - go build -o .bin/mockgen github.com/golang/mock/mockgen + go build -o .bin/mockgen go.uber.org/mock/mockgen .bin/ory: Makefile curl https://raw.githubusercontent.com/ory/meta/master/install.sh | bash -s -- -b .bin ory v0.1.48 diff --git a/access_error_test.go b/access_error_test.go index e1d4ef566..b6cbb19de 100644 --- a/access_error_test.go +++ b/access_error_test.go @@ -11,9 +11,9 @@ import ( "net/http/httptest" "testing" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" . "github.com/ory/fosite/internal" diff --git a/access_request_handler_test.go b/access_request_handler_test.go index 01f5a6920..a5d63729c 100644 --- a/access_request_handler_test.go +++ b/access_request_handler_test.go @@ -10,10 +10,10 @@ import ( "net/url" "testing" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/access_response_writer_test.go b/access_response_writer_test.go index 39e62ed64..45f6089bf 100644 --- a/access_response_writer_test.go +++ b/access_response_writer_test.go @@ -8,9 +8,9 @@ import ( "fmt" "testing" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/access_write_test.go b/access_write_test.go index a392aba90..4229185b9 100644 --- a/access_write_test.go +++ b/access_write_test.go @@ -8,8 +8,8 @@ import ( "net/http" "testing" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" . "github.com/ory/fosite/internal" diff --git a/authorize_error_test.go b/authorize_error_test.go index 0db1771fc..a7f4d81fb 100644 --- a/authorize_error_test.go +++ b/authorize_error_test.go @@ -10,8 +10,8 @@ import ( "net/url" "testing" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" . "github.com/ory/fosite/internal" diff --git a/authorize_request_handler_test.go b/authorize_request_handler_test.go index ce835243e..e5c301fd1 100644 --- a/authorize_request_handler_test.go +++ b/authorize_request_handler_test.go @@ -10,10 +10,10 @@ import ( "net/url" "testing" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" . "github.com/ory/fosite/internal" diff --git a/authorize_response_writer_test.go b/authorize_response_writer_test.go index 59f892a56..0ff2c05d9 100644 --- a/authorize_response_writer_test.go +++ b/authorize_response_writer_test.go @@ -7,9 +7,9 @@ import ( "context" "testing" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" . "github.com/ory/fosite" diff --git a/authorize_write_test.go b/authorize_write_test.go index 38f01ea83..36630e4c4 100644 --- a/authorize_write_test.go +++ b/authorize_write_test.go @@ -9,8 +9,8 @@ import ( "net/url" "testing" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" . "github.com/ory/fosite/internal" diff --git a/device_request_handler_test.go b/device_request_handler_test.go index 0b5b38e6d..38cb336f4 100644 --- a/device_request_handler_test.go +++ b/device_request_handler_test.go @@ -10,10 +10,10 @@ import ( "net/url" "testing" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/generate.go b/generate.go index 891dc8381..d7a60d50c 100644 --- a/generate.go +++ b/generate.go @@ -3,34 +3,34 @@ package fosite -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/hash.go github.com/ory/fosite Hasher -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/storage.go github.com/ory/fosite Storage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/transactional.go github.com/ory/fosite/storage Transactional -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_storage.go github.com/ory/fosite/handler/oauth2 CoreStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_strategy.go github.com/ory/fosite/handler/oauth2 CoreStrategy -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/authorize_code_storage.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/rfc8628_core_storage.go github.com/ory/fosite/handler/rfc8628 RFC8628CoreStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_auth_jwt_storage.go github.com/ory/fosite/handler/rfc7523 RFC7523KeyStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/access_token_storage.go github.com/ory/fosite/handler/oauth2 AccessTokenStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_client_storage.go github.com/ory/fosite/handler/oauth2 ClientCredentialsGrantStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_owner_storage.go github.com/ory/fosite/handler/oauth2 ResourceOwnerPasswordCredentialsGrantStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/oauth2_revoke_storage.go github.com/ory/fosite/handler/oauth2 TokenRevocationStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/openid_id_token_storage.go github.com/ory/fosite/handler/openid OpenIDConnectRequestStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/access_token_strategy.go github.com/ory/fosite/handler/oauth2 AccessTokenStrategy -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStrategy -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/authorize_code_strategy.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStrategy -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/device_code_rate_limit_strategy.go github.com/ory/fosite/handler/rfc8628 DeviceRateLimitStrategy -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/rfc8628_code_strategy.go github.com/ory/fosite/handler/rfc8628 RFC8628CodeStrategy -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/id_token_strategy.go github.com/ory/fosite/handler/openid OpenIDConnectTokenStrategy -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/pkce_storage_strategy.go github.com/ory/fosite/handler/pkce PKCERequestStorage -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/authorize_handler.go github.com/ory/fosite AuthorizeEndpointHandler -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/revoke_handler.go github.com/ory/fosite RevocationHandler -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/token_handler.go github.com/ory/fosite TokenEndpointHandler -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/introspector.go github.com/ory/fosite TokenIntrospector -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/client.go github.com/ory/fosite Client -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/request.go github.com/ory/fosite Requester -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/access_request.go github.com/ory/fosite AccessRequester -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/access_response.go github.com/ory/fosite AccessResponder -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/authorize_request.go github.com/ory/fosite AuthorizeRequester -//go:generate go run github.com/golang/mock/mockgen -package internal -destination internal/authorize_response.go github.com/ory/fosite AuthorizeResponder +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/hash.go github.com/ory/fosite Hasher +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/storage.go github.com/ory/fosite Storage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/transactional.go github.com/ory/fosite/storage Transactional +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/oauth2_storage.go github.com/ory/fosite/handler/oauth2 CoreStorage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/oauth2_strategy.go github.com/ory/fosite/handler/oauth2 CoreStrategy +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/authorize_code_storage.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStorage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/rfc8628_core_storage.go github.com/ory/fosite/handler/rfc8628 RFC8628CoreStorage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/oauth2_auth_jwt_storage.go github.com/ory/fosite/handler/rfc7523 RFC7523KeyStorage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/access_token_storage.go github.com/ory/fosite/handler/oauth2 AccessTokenStorage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStorage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/oauth2_client_storage.go github.com/ory/fosite/handler/oauth2 ClientCredentialsGrantStorage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/oauth2_owner_storage.go github.com/ory/fosite/handler/oauth2 ResourceOwnerPasswordCredentialsGrantStorage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/oauth2_revoke_storage.go github.com/ory/fosite/handler/oauth2 TokenRevocationStorage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/openid_id_token_storage.go github.com/ory/fosite/handler/openid OpenIDConnectRequestStorage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/access_token_strategy.go github.com/ory/fosite/handler/oauth2 AccessTokenStrategy +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStrategy +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/authorize_code_strategy.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStrategy +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/device_code_rate_limit_strategy.go github.com/ory/fosite/handler/rfc8628 DeviceRateLimitStrategy +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/rfc8628_code_strategy.go github.com/ory/fosite/handler/rfc8628 RFC8628CodeStrategy +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/id_token_strategy.go github.com/ory/fosite/handler/openid OpenIDConnectTokenStrategy +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/pkce_storage_strategy.go github.com/ory/fosite/handler/pkce PKCERequestStorage +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/authorize_handler.go github.com/ory/fosite AuthorizeEndpointHandler +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/revoke_handler.go github.com/ory/fosite RevocationHandler +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/token_handler.go github.com/ory/fosite TokenEndpointHandler +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/introspector.go github.com/ory/fosite TokenIntrospector +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/client.go github.com/ory/fosite Client +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/request.go github.com/ory/fosite Requester +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/access_request.go github.com/ory/fosite AccessRequester +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/access_response.go github.com/ory/fosite AccessResponder +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/authorize_request.go github.com/ory/fosite AuthorizeRequester +//go:generate go run go.uber.org/mock/mockgen -package internal -destination internal/authorize_response.go github.com/ory/fosite AuthorizeResponder diff --git a/go.mod b/go.mod index 29edf5382..ba0423901 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.14.3 go.opentelemetry.io/otel/trace v1.32.0 + go.uber.org/mock v0.5.0 golang.org/x/crypto v0.31.0 golang.org/x/net v0.30.0 golang.org/x/oauth2 v0.23.0 @@ -76,6 +77,7 @@ require ( go.opentelemetry.io/otel/sdk v1.32.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/mod v0.18.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/tools v0.22.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect diff --git a/go.sum b/go.sum index ccadcd0b0..735d4a191 100644 --- a/go.sum +++ b/go.sum @@ -463,6 +463,8 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= diff --git a/handler/oauth2/flow_authorize_code_token_test.go b/handler/oauth2/flow_authorize_code_token_test.go index e06468065..c7ee35e21 100644 --- a/handler/oauth2/flow_authorize_code_token_test.go +++ b/handler/oauth2/flow_authorize_code_token_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite/internal" diff --git a/handler/oauth2/flow_authorize_implicit_test.go b/handler/oauth2/flow_authorize_implicit_test.go index 6bff9e89e..3cac0db34 100644 --- a/handler/oauth2/flow_authorize_implicit_test.go +++ b/handler/oauth2/flow_authorize_implicit_test.go @@ -11,9 +11,9 @@ import ( "github.com/stretchr/testify/assert" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/handler/oauth2/flow_client_credentials_test.go b/handler/oauth2/flow_client_credentials_test.go index ed16ab180..8d9c906ca 100644 --- a/handler/oauth2/flow_client_credentials_test.go +++ b/handler/oauth2/flow_client_credentials_test.go @@ -10,8 +10,8 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/handler/oauth2/flow_refresh_test.go b/handler/oauth2/flow_refresh_test.go index 6abf80398..4f2bc57c2 100644 --- a/handler/oauth2/flow_refresh_test.go +++ b/handler/oauth2/flow_refresh_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite/internal" diff --git a/handler/oauth2/flow_resource_owner_test.go b/handler/oauth2/flow_resource_owner_test.go index 0bf201ed6..c03d219d6 100644 --- a/handler/oauth2/flow_resource_owner_test.go +++ b/handler/oauth2/flow_resource_owner_test.go @@ -10,10 +10,10 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/handler/oauth2/helper_test.go b/handler/oauth2/helper_test.go index fbce3ac20..395000d9c 100644 --- a/handler/oauth2/helper_test.go +++ b/handler/oauth2/helper_test.go @@ -8,10 +8,10 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/handler/oauth2/introspector_test.go b/handler/oauth2/introspector_test.go index f1960d166..20834ab72 100644 --- a/handler/oauth2/introspector_test.go +++ b/handler/oauth2/introspector_test.go @@ -11,10 +11,10 @@ import ( "github.com/ory/x/errorsx" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/handler/oauth2/revocation_test.go b/handler/oauth2/revocation_test.go index b657bed3c..ad95d8e76 100644 --- a/handler/oauth2/revocation_test.go +++ b/handler/oauth2/revocation_test.go @@ -8,8 +8,8 @@ import ( "fmt" "testing" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/handler/openid/flow_device_auth_test.go b/handler/openid/flow_device_auth_test.go index a345660f1..3de6aec8a 100644 --- a/handler/openid/flow_device_auth_test.go +++ b/handler/openid/flow_device_auth_test.go @@ -9,9 +9,9 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" "github.com/ory/fosite/internal" "github.com/pkg/errors" + gomock "go.uber.org/mock/gomock" "github.com/stretchr/testify/require" diff --git a/handler/openid/flow_device_token_test.go b/handler/openid/flow_device_token_test.go index 03a51cd64..25442a74c 100644 --- a/handler/openid/flow_device_token_test.go +++ b/handler/openid/flow_device_token_test.go @@ -15,11 +15,11 @@ import ( "github.com/stretchr/testify/require" "github.com/coocood/freecache" - "github.com/golang/mock/gomock" "github.com/ory/fosite/handler/rfc8628" "github.com/ory/fosite/internal" "github.com/ory/fosite/token/hmac" "github.com/ory/fosite/token/jwt" + gomock "go.uber.org/mock/gomock" "github.com/stretchr/testify/assert" diff --git a/handler/openid/flow_explicit_auth_test.go b/handler/openid/flow_explicit_auth_test.go index 756f3d82f..db00bc232 100644 --- a/handler/openid/flow_explicit_auth_test.go +++ b/handler/openid/flow_explicit_auth_test.go @@ -11,9 +11,9 @@ import ( "github.com/ory/fosite/internal/gen" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/handler/openid/flow_explicit_token_test.go b/handler/openid/flow_explicit_token_test.go index dadc6a8f8..eeddedd2c 100644 --- a/handler/openid/flow_explicit_token_test.go +++ b/handler/openid/flow_explicit_token_test.go @@ -9,10 +9,10 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/handler/openid/flow_hybrid_test.go b/handler/openid/flow_hybrid_test.go index e0214ab3a..3885de298 100644 --- a/handler/openid/flow_hybrid_test.go +++ b/handler/openid/flow_hybrid_test.go @@ -15,9 +15,9 @@ import ( "github.com/ory/fosite/internal/gen" cristaljwt "github.com/cristalhq/jwt/v4" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/handler/oauth2" diff --git a/handler/openid/flow_implicit_test.go b/handler/openid/flow_implicit_test.go index a833e51b1..46cab8f74 100644 --- a/handler/openid/flow_implicit_test.go +++ b/handler/openid/flow_implicit_test.go @@ -13,8 +13,8 @@ import ( "github.com/ory/fosite/internal" "github.com/ory/fosite/internal/gen" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/handler/oauth2" diff --git a/handler/openid/helper_test.go b/handler/openid/helper_test.go index 7ca85678a..dc488225d 100644 --- a/handler/openid/helper_test.go +++ b/handler/openid/helper_test.go @@ -11,9 +11,9 @@ import ( "github.com/ory/fosite/internal/gen" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/handler/rfc7523/handler_test.go b/handler/rfc7523/handler_test.go index c2897793b..45d8044e9 100644 --- a/handler/rfc7523/handler_test.go +++ b/handler/rfc7523/handler_test.go @@ -20,8 +20,8 @@ import ( "github.com/go-jose/go-jose/v3" "github.com/go-jose/go-jose/v3/jwt" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/handler/rfc8628/auth_handler_test.go b/handler/rfc8628/auth_handler_test.go index ec20b8527..bbe2d525b 100644 --- a/handler/rfc8628/auth_handler_test.go +++ b/handler/rfc8628/auth_handler_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite/internal" diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index dbec5fce9..3aab203b3 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -13,8 +13,8 @@ import ( "github.com/coocood/freecache" "github.com/pkg/errors" - "github.com/golang/mock/gomock" "github.com/ory/fosite/internal" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite/handler/oauth2" "github.com/ory/fosite/token/hmac" diff --git a/handler/verifiable/handler_test.go b/handler/verifiable/handler_test.go index 2b5f91b16..930e49c9e 100644 --- a/handler/verifiable/handler_test.go +++ b/handler/verifiable/handler_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/internal/access_request.go b/internal/access_request.go index d2f42e326..a37d0de3c 100644 --- a/internal/access_request.go +++ b/internal/access_request.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: AccessRequester) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/access_request.go github.com/ory/fosite AccessRequester +// // Package internal is a generated GoMock package. package internal @@ -12,14 +17,15 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockAccessRequester is a mock of AccessRequester interface. type MockAccessRequester struct { ctrl *gomock.Controller recorder *MockAccessRequesterMockRecorder + isgomock struct{} } // MockAccessRequesterMockRecorder is the mock recorder for MockAccessRequester. @@ -40,15 +46,15 @@ func (m *MockAccessRequester) EXPECT() *MockAccessRequesterMockRecorder { } // AppendRequestedScope mocks base method. -func (m *MockAccessRequester) AppendRequestedScope(arg0 string) { +func (m *MockAccessRequester) AppendRequestedScope(scope string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "AppendRequestedScope", arg0) + m.ctrl.Call(m, "AppendRequestedScope", scope) } // AppendRequestedScope indicates an expected call of AppendRequestedScope. -func (mr *MockAccessRequesterMockRecorder) AppendRequestedScope(arg0 interface{}) *gomock.Call { +func (mr *MockAccessRequesterMockRecorder) AppendRequestedScope(scope any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppendRequestedScope", reflect.TypeOf((*MockAccessRequester)(nil).AppendRequestedScope), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppendRequestedScope", reflect.TypeOf((*MockAccessRequester)(nil).AppendRequestedScope), scope) } // GetClient mocks base method. @@ -192,99 +198,99 @@ func (mr *MockAccessRequesterMockRecorder) GetSession() *gomock.Call { } // GrantAudience mocks base method. -func (m *MockAccessRequester) GrantAudience(arg0 string) { +func (m *MockAccessRequester) GrantAudience(audience string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "GrantAudience", arg0) + m.ctrl.Call(m, "GrantAudience", audience) } // GrantAudience indicates an expected call of GrantAudience. -func (mr *MockAccessRequesterMockRecorder) GrantAudience(arg0 interface{}) *gomock.Call { +func (mr *MockAccessRequesterMockRecorder) GrantAudience(audience any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantAudience", reflect.TypeOf((*MockAccessRequester)(nil).GrantAudience), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantAudience", reflect.TypeOf((*MockAccessRequester)(nil).GrantAudience), audience) } // GrantScope mocks base method. -func (m *MockAccessRequester) GrantScope(arg0 string) { +func (m *MockAccessRequester) GrantScope(scope string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "GrantScope", arg0) + m.ctrl.Call(m, "GrantScope", scope) } // GrantScope indicates an expected call of GrantScope. -func (mr *MockAccessRequesterMockRecorder) GrantScope(arg0 interface{}) *gomock.Call { +func (mr *MockAccessRequesterMockRecorder) GrantScope(scope any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantScope", reflect.TypeOf((*MockAccessRequester)(nil).GrantScope), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantScope", reflect.TypeOf((*MockAccessRequester)(nil).GrantScope), scope) } // Merge mocks base method. -func (m *MockAccessRequester) Merge(arg0 fosite.Requester) { +func (m *MockAccessRequester) Merge(requester fosite.Requester) { m.ctrl.T.Helper() - m.ctrl.Call(m, "Merge", arg0) + m.ctrl.Call(m, "Merge", requester) } // Merge indicates an expected call of Merge. -func (mr *MockAccessRequesterMockRecorder) Merge(arg0 interface{}) *gomock.Call { +func (mr *MockAccessRequesterMockRecorder) Merge(requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Merge", reflect.TypeOf((*MockAccessRequester)(nil).Merge), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Merge", reflect.TypeOf((*MockAccessRequester)(nil).Merge), requester) } // Sanitize mocks base method. -func (m *MockAccessRequester) Sanitize(arg0 []string) fosite.Requester { +func (m *MockAccessRequester) Sanitize(allowedParameters []string) fosite.Requester { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Sanitize", arg0) + ret := m.ctrl.Call(m, "Sanitize", allowedParameters) ret0, _ := ret[0].(fosite.Requester) return ret0 } // Sanitize indicates an expected call of Sanitize. -func (mr *MockAccessRequesterMockRecorder) Sanitize(arg0 interface{}) *gomock.Call { +func (mr *MockAccessRequesterMockRecorder) Sanitize(allowedParameters any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sanitize", reflect.TypeOf((*MockAccessRequester)(nil).Sanitize), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sanitize", reflect.TypeOf((*MockAccessRequester)(nil).Sanitize), allowedParameters) } // SetID mocks base method. -func (m *MockAccessRequester) SetID(arg0 string) { +func (m *MockAccessRequester) SetID(id string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetID", arg0) + m.ctrl.Call(m, "SetID", id) } // SetID indicates an expected call of SetID. -func (mr *MockAccessRequesterMockRecorder) SetID(arg0 interface{}) *gomock.Call { +func (mr *MockAccessRequesterMockRecorder) SetID(id any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetID", reflect.TypeOf((*MockAccessRequester)(nil).SetID), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetID", reflect.TypeOf((*MockAccessRequester)(nil).SetID), id) } // SetRequestedAudience mocks base method. -func (m *MockAccessRequester) SetRequestedAudience(arg0 fosite.Arguments) { +func (m *MockAccessRequester) SetRequestedAudience(audience fosite.Arguments) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetRequestedAudience", arg0) + m.ctrl.Call(m, "SetRequestedAudience", audience) } // SetRequestedAudience indicates an expected call of SetRequestedAudience. -func (mr *MockAccessRequesterMockRecorder) SetRequestedAudience(arg0 interface{}) *gomock.Call { +func (mr *MockAccessRequesterMockRecorder) SetRequestedAudience(audience any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedAudience", reflect.TypeOf((*MockAccessRequester)(nil).SetRequestedAudience), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedAudience", reflect.TypeOf((*MockAccessRequester)(nil).SetRequestedAudience), audience) } // SetRequestedScopes mocks base method. -func (m *MockAccessRequester) SetRequestedScopes(arg0 fosite.Arguments) { +func (m *MockAccessRequester) SetRequestedScopes(scopes fosite.Arguments) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetRequestedScopes", arg0) + m.ctrl.Call(m, "SetRequestedScopes", scopes) } // SetRequestedScopes indicates an expected call of SetRequestedScopes. -func (mr *MockAccessRequesterMockRecorder) SetRequestedScopes(arg0 interface{}) *gomock.Call { +func (mr *MockAccessRequesterMockRecorder) SetRequestedScopes(scopes any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedScopes", reflect.TypeOf((*MockAccessRequester)(nil).SetRequestedScopes), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedScopes", reflect.TypeOf((*MockAccessRequester)(nil).SetRequestedScopes), scopes) } // SetSession mocks base method. -func (m *MockAccessRequester) SetSession(arg0 fosite.Session) { +func (m *MockAccessRequester) SetSession(session fosite.Session) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSession", arg0) + m.ctrl.Call(m, "SetSession", session) } // SetSession indicates an expected call of SetSession. -func (mr *MockAccessRequesterMockRecorder) SetSession(arg0 interface{}) *gomock.Call { +func (mr *MockAccessRequesterMockRecorder) SetSession(session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSession", reflect.TypeOf((*MockAccessRequester)(nil).SetSession), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSession", reflect.TypeOf((*MockAccessRequester)(nil).SetSession), session) } diff --git a/internal/access_response.go b/internal/access_response.go index 5b3f42f4c..fd0b55e7f 100644 --- a/internal/access_response.go +++ b/internal/access_response.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: AccessResponder) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/access_response.go github.com/ory/fosite AccessResponder +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockAccessResponder is a mock of AccessResponder interface. type MockAccessResponder struct { ctrl *gomock.Controller recorder *MockAccessResponderMockRecorder + isgomock struct{} } // MockAccessResponderMockRecorder is the mock recorder for MockAccessResponder. @@ -53,17 +59,17 @@ func (mr *MockAccessResponderMockRecorder) GetAccessToken() *gomock.Call { } // GetExtra mocks base method. -func (m *MockAccessResponder) GetExtra(arg0 string) interface{} { +func (m *MockAccessResponder) GetExtra(key string) any { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetExtra", arg0) - ret0, _ := ret[0].(interface{}) + ret := m.ctrl.Call(m, "GetExtra", key) + ret0, _ := ret[0].(any) return ret0 } // GetExtra indicates an expected call of GetExtra. -func (mr *MockAccessResponderMockRecorder) GetExtra(arg0 interface{}) *gomock.Call { +func (mr *MockAccessResponderMockRecorder) GetExtra(key any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExtra", reflect.TypeOf((*MockAccessResponder)(nil).GetExtra), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExtra", reflect.TypeOf((*MockAccessResponder)(nil).GetExtra), key) } // GetTokenType mocks base method. @@ -81,15 +87,15 @@ func (mr *MockAccessResponderMockRecorder) GetTokenType() *gomock.Call { } // SetAccessToken mocks base method. -func (m *MockAccessResponder) SetAccessToken(arg0 string) { +func (m *MockAccessResponder) SetAccessToken(token string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetAccessToken", arg0) + m.ctrl.Call(m, "SetAccessToken", token) } // SetAccessToken indicates an expected call of SetAccessToken. -func (mr *MockAccessResponderMockRecorder) SetAccessToken(arg0 interface{}) *gomock.Call { +func (mr *MockAccessResponderMockRecorder) SetAccessToken(token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAccessToken", reflect.TypeOf((*MockAccessResponder)(nil).SetAccessToken), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAccessToken", reflect.TypeOf((*MockAccessResponder)(nil).SetAccessToken), token) } // SetExpiresIn mocks base method. @@ -99,52 +105,52 @@ func (m *MockAccessResponder) SetExpiresIn(arg0 time.Duration) { } // SetExpiresIn indicates an expected call of SetExpiresIn. -func (mr *MockAccessResponderMockRecorder) SetExpiresIn(arg0 interface{}) *gomock.Call { +func (mr *MockAccessResponderMockRecorder) SetExpiresIn(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExpiresIn", reflect.TypeOf((*MockAccessResponder)(nil).SetExpiresIn), arg0) } // SetExtra mocks base method. -func (m *MockAccessResponder) SetExtra(arg0 string, arg1 interface{}) { +func (m *MockAccessResponder) SetExtra(key string, value any) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetExtra", arg0, arg1) + m.ctrl.Call(m, "SetExtra", key, value) } // SetExtra indicates an expected call of SetExtra. -func (mr *MockAccessResponderMockRecorder) SetExtra(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAccessResponderMockRecorder) SetExtra(key, value any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExtra", reflect.TypeOf((*MockAccessResponder)(nil).SetExtra), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExtra", reflect.TypeOf((*MockAccessResponder)(nil).SetExtra), key, value) } // SetScopes mocks base method. -func (m *MockAccessResponder) SetScopes(arg0 fosite.Arguments) { +func (m *MockAccessResponder) SetScopes(scopes fosite.Arguments) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetScopes", arg0) + m.ctrl.Call(m, "SetScopes", scopes) } // SetScopes indicates an expected call of SetScopes. -func (mr *MockAccessResponderMockRecorder) SetScopes(arg0 interface{}) *gomock.Call { +func (mr *MockAccessResponderMockRecorder) SetScopes(scopes any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetScopes", reflect.TypeOf((*MockAccessResponder)(nil).SetScopes), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetScopes", reflect.TypeOf((*MockAccessResponder)(nil).SetScopes), scopes) } // SetTokenType mocks base method. -func (m *MockAccessResponder) SetTokenType(arg0 string) { +func (m *MockAccessResponder) SetTokenType(tokenType string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetTokenType", arg0) + m.ctrl.Call(m, "SetTokenType", tokenType) } // SetTokenType indicates an expected call of SetTokenType. -func (mr *MockAccessResponderMockRecorder) SetTokenType(arg0 interface{}) *gomock.Call { +func (mr *MockAccessResponderMockRecorder) SetTokenType(tokenType any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTokenType", reflect.TypeOf((*MockAccessResponder)(nil).SetTokenType), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTokenType", reflect.TypeOf((*MockAccessResponder)(nil).SetTokenType), tokenType) } // ToMap mocks base method. -func (m *MockAccessResponder) ToMap() map[string]interface{} { +func (m *MockAccessResponder) ToMap() map[string]any { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ToMap") - ret0, _ := ret[0].(map[string]interface{}) + ret0, _ := ret[0].(map[string]any) return ret0 } diff --git a/internal/access_token_storage.go b/internal/access_token_storage.go index 6d0a00512..937ee5cc7 100644 --- a/internal/access_token_storage.go +++ b/internal/access_token_storage.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/oauth2 (interfaces: AccessTokenStorage) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/access_token_storage.go github.com/ory/fosite/handler/oauth2 AccessTokenStorage +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockAccessTokenStorage is a mock of AccessTokenStorage interface. type MockAccessTokenStorage struct { ctrl *gomock.Controller recorder *MockAccessTokenStorageMockRecorder + isgomock struct{} } // MockAccessTokenStorageMockRecorder is the mock recorder for MockAccessTokenStorage. @@ -39,44 +45,44 @@ func (m *MockAccessTokenStorage) EXPECT() *MockAccessTokenStorageMockRecorder { } // CreateAccessTokenSession mocks base method. -func (m *MockAccessTokenStorage) CreateAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +func (m *MockAccessTokenStorage) CreateAccessTokenSession(ctx context.Context, signature string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateAccessTokenSession", ctx, signature, request) ret0, _ := ret[0].(error) return ret0 } // CreateAccessTokenSession indicates an expected call of CreateAccessTokenSession. -func (mr *MockAccessTokenStorageMockRecorder) CreateAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockAccessTokenStorageMockRecorder) CreateAccessTokenSession(ctx, signature, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockAccessTokenStorage)(nil).CreateAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockAccessTokenStorage)(nil).CreateAccessTokenSession), ctx, signature, request) } // DeleteAccessTokenSession mocks base method. -func (m *MockAccessTokenStorage) DeleteAccessTokenSession(arg0 context.Context, arg1 string) error { +func (m *MockAccessTokenStorage) DeleteAccessTokenSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteAccessTokenSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteAccessTokenSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // DeleteAccessTokenSession indicates an expected call of DeleteAccessTokenSession. -func (mr *MockAccessTokenStorageMockRecorder) DeleteAccessTokenSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAccessTokenStorageMockRecorder) DeleteAccessTokenSession(ctx, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockAccessTokenStorage)(nil).DeleteAccessTokenSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockAccessTokenStorage)(nil).DeleteAccessTokenSession), ctx, signature) } // GetAccessTokenSession mocks base method. -func (m *MockAccessTokenStorage) GetAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockAccessTokenStorage) GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetAccessTokenSession", ctx, signature, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetAccessTokenSession indicates an expected call of GetAccessTokenSession. -func (mr *MockAccessTokenStorageMockRecorder) GetAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockAccessTokenStorageMockRecorder) GetAccessTokenSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockAccessTokenStorage)(nil).GetAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockAccessTokenStorage)(nil).GetAccessTokenSession), ctx, signature, session) } diff --git a/internal/access_token_strategy.go b/internal/access_token_strategy.go index 24e95187e..d9d7545e5 100644 --- a/internal/access_token_strategy.go +++ b/internal/access_token_strategy.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/oauth2 (interfaces: AccessTokenStrategy) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/access_token_strategy.go github.com/ory/fosite/handler/oauth2 AccessTokenStrategy +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockAccessTokenStrategy is a mock of AccessTokenStrategy interface. type MockAccessTokenStrategy struct { ctrl *gomock.Controller recorder *MockAccessTokenStrategyMockRecorder + isgomock struct{} } // MockAccessTokenStrategyMockRecorder is the mock recorder for MockAccessTokenStrategy. @@ -39,23 +45,23 @@ func (m *MockAccessTokenStrategy) EXPECT() *MockAccessTokenStrategyMockRecorder } // AccessTokenSignature mocks base method. -func (m *MockAccessTokenStrategy) AccessTokenSignature(arg0 context.Context, arg1 string) string { +func (m *MockAccessTokenStrategy) AccessTokenSignature(ctx context.Context, token string) string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AccessTokenSignature", arg0, arg1) + ret := m.ctrl.Call(m, "AccessTokenSignature", ctx, token) ret0, _ := ret[0].(string) return ret0 } // AccessTokenSignature indicates an expected call of AccessTokenSignature. -func (mr *MockAccessTokenStrategyMockRecorder) AccessTokenSignature(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAccessTokenStrategyMockRecorder) AccessTokenSignature(ctx, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccessTokenSignature", reflect.TypeOf((*MockAccessTokenStrategy)(nil).AccessTokenSignature), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccessTokenSignature", reflect.TypeOf((*MockAccessTokenStrategy)(nil).AccessTokenSignature), ctx, token) } // GenerateAccessToken mocks base method. -func (m *MockAccessTokenStrategy) GenerateAccessToken(arg0 context.Context, arg1 fosite.Requester) (string, string, error) { +func (m *MockAccessTokenStrategy) GenerateAccessToken(ctx context.Context, requester fosite.Requester) (string, string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GenerateAccessToken", arg0, arg1) + ret := m.ctrl.Call(m, "GenerateAccessToken", ctx, requester) ret0, _ := ret[0].(string) ret1, _ := ret[1].(string) ret2, _ := ret[2].(error) @@ -63,21 +69,21 @@ func (m *MockAccessTokenStrategy) GenerateAccessToken(arg0 context.Context, arg1 } // GenerateAccessToken indicates an expected call of GenerateAccessToken. -func (mr *MockAccessTokenStrategyMockRecorder) GenerateAccessToken(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAccessTokenStrategyMockRecorder) GenerateAccessToken(ctx, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateAccessToken", reflect.TypeOf((*MockAccessTokenStrategy)(nil).GenerateAccessToken), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateAccessToken", reflect.TypeOf((*MockAccessTokenStrategy)(nil).GenerateAccessToken), ctx, requester) } // ValidateAccessToken mocks base method. -func (m *MockAccessTokenStrategy) ValidateAccessToken(arg0 context.Context, arg1 fosite.Requester, arg2 string) error { +func (m *MockAccessTokenStrategy) ValidateAccessToken(ctx context.Context, requester fosite.Requester, token string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateAccessToken", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ValidateAccessToken", ctx, requester, token) ret0, _ := ret[0].(error) return ret0 } // ValidateAccessToken indicates an expected call of ValidateAccessToken. -func (mr *MockAccessTokenStrategyMockRecorder) ValidateAccessToken(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockAccessTokenStrategyMockRecorder) ValidateAccessToken(ctx, requester, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAccessToken", reflect.TypeOf((*MockAccessTokenStrategy)(nil).ValidateAccessToken), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAccessToken", reflect.TypeOf((*MockAccessTokenStrategy)(nil).ValidateAccessToken), ctx, requester, token) } diff --git a/internal/authorize_code_storage.go b/internal/authorize_code_storage.go index 4c80e3117..f0fef08b6 100644 --- a/internal/authorize_code_storage.go +++ b/internal/authorize_code_storage.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/oauth2 (interfaces: AuthorizeCodeStorage) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/authorize_code_storage.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStorage +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockAuthorizeCodeStorage is a mock of AuthorizeCodeStorage interface. type MockAuthorizeCodeStorage struct { ctrl *gomock.Controller recorder *MockAuthorizeCodeStorageMockRecorder + isgomock struct{} } // MockAuthorizeCodeStorageMockRecorder is the mock recorder for MockAuthorizeCodeStorage. @@ -39,44 +45,44 @@ func (m *MockAuthorizeCodeStorage) EXPECT() *MockAuthorizeCodeStorageMockRecorde } // CreateAuthorizeCodeSession mocks base method. -func (m *MockAuthorizeCodeStorage) CreateAuthorizeCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +func (m *MockAuthorizeCodeStorage) CreateAuthorizeCodeSession(ctx context.Context, code string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateAuthorizeCodeSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateAuthorizeCodeSession", ctx, code, request) ret0, _ := ret[0].(error) return ret0 } // CreateAuthorizeCodeSession indicates an expected call of CreateAuthorizeCodeSession. -func (mr *MockAuthorizeCodeStorageMockRecorder) CreateAuthorizeCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockAuthorizeCodeStorageMockRecorder) CreateAuthorizeCodeSession(ctx, code, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAuthorizeCodeSession", reflect.TypeOf((*MockAuthorizeCodeStorage)(nil).CreateAuthorizeCodeSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAuthorizeCodeSession", reflect.TypeOf((*MockAuthorizeCodeStorage)(nil).CreateAuthorizeCodeSession), ctx, code, request) } // GetAuthorizeCodeSession mocks base method. -func (m *MockAuthorizeCodeStorage) GetAuthorizeCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockAuthorizeCodeStorage) GetAuthorizeCodeSession(ctx context.Context, code string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAuthorizeCodeSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetAuthorizeCodeSession", ctx, code, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetAuthorizeCodeSession indicates an expected call of GetAuthorizeCodeSession. -func (mr *MockAuthorizeCodeStorageMockRecorder) GetAuthorizeCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockAuthorizeCodeStorageMockRecorder) GetAuthorizeCodeSession(ctx, code, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizeCodeSession", reflect.TypeOf((*MockAuthorizeCodeStorage)(nil).GetAuthorizeCodeSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizeCodeSession", reflect.TypeOf((*MockAuthorizeCodeStorage)(nil).GetAuthorizeCodeSession), ctx, code, session) } // InvalidateAuthorizeCodeSession mocks base method. -func (m *MockAuthorizeCodeStorage) InvalidateAuthorizeCodeSession(arg0 context.Context, arg1 string) error { +func (m *MockAuthorizeCodeStorage) InvalidateAuthorizeCodeSession(ctx context.Context, code string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InvalidateAuthorizeCodeSession", arg0, arg1) + ret := m.ctrl.Call(m, "InvalidateAuthorizeCodeSession", ctx, code) ret0, _ := ret[0].(error) return ret0 } // InvalidateAuthorizeCodeSession indicates an expected call of InvalidateAuthorizeCodeSession. -func (mr *MockAuthorizeCodeStorageMockRecorder) InvalidateAuthorizeCodeSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAuthorizeCodeStorageMockRecorder) InvalidateAuthorizeCodeSession(ctx, code any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateAuthorizeCodeSession", reflect.TypeOf((*MockAuthorizeCodeStorage)(nil).InvalidateAuthorizeCodeSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateAuthorizeCodeSession", reflect.TypeOf((*MockAuthorizeCodeStorage)(nil).InvalidateAuthorizeCodeSession), ctx, code) } diff --git a/internal/authorize_code_strategy.go b/internal/authorize_code_strategy.go index cc0250a7a..67ec01220 100644 --- a/internal/authorize_code_strategy.go +++ b/internal/authorize_code_strategy.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/oauth2 (interfaces: AuthorizeCodeStrategy) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/authorize_code_strategy.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStrategy +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockAuthorizeCodeStrategy is a mock of AuthorizeCodeStrategy interface. type MockAuthorizeCodeStrategy struct { ctrl *gomock.Controller recorder *MockAuthorizeCodeStrategyMockRecorder + isgomock struct{} } // MockAuthorizeCodeStrategyMockRecorder is the mock recorder for MockAuthorizeCodeStrategy. @@ -39,23 +45,23 @@ func (m *MockAuthorizeCodeStrategy) EXPECT() *MockAuthorizeCodeStrategyMockRecor } // AuthorizeCodeSignature mocks base method. -func (m *MockAuthorizeCodeStrategy) AuthorizeCodeSignature(arg0 context.Context, arg1 string) string { +func (m *MockAuthorizeCodeStrategy) AuthorizeCodeSignature(ctx context.Context, token string) string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AuthorizeCodeSignature", arg0, arg1) + ret := m.ctrl.Call(m, "AuthorizeCodeSignature", ctx, token) ret0, _ := ret[0].(string) return ret0 } // AuthorizeCodeSignature indicates an expected call of AuthorizeCodeSignature. -func (mr *MockAuthorizeCodeStrategyMockRecorder) AuthorizeCodeSignature(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAuthorizeCodeStrategyMockRecorder) AuthorizeCodeSignature(ctx, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthorizeCodeSignature", reflect.TypeOf((*MockAuthorizeCodeStrategy)(nil).AuthorizeCodeSignature), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthorizeCodeSignature", reflect.TypeOf((*MockAuthorizeCodeStrategy)(nil).AuthorizeCodeSignature), ctx, token) } // GenerateAuthorizeCode mocks base method. -func (m *MockAuthorizeCodeStrategy) GenerateAuthorizeCode(arg0 context.Context, arg1 fosite.Requester) (string, string, error) { +func (m *MockAuthorizeCodeStrategy) GenerateAuthorizeCode(ctx context.Context, requester fosite.Requester) (string, string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GenerateAuthorizeCode", arg0, arg1) + ret := m.ctrl.Call(m, "GenerateAuthorizeCode", ctx, requester) ret0, _ := ret[0].(string) ret1, _ := ret[1].(string) ret2, _ := ret[2].(error) @@ -63,21 +69,21 @@ func (m *MockAuthorizeCodeStrategy) GenerateAuthorizeCode(arg0 context.Context, } // GenerateAuthorizeCode indicates an expected call of GenerateAuthorizeCode. -func (mr *MockAuthorizeCodeStrategyMockRecorder) GenerateAuthorizeCode(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAuthorizeCodeStrategyMockRecorder) GenerateAuthorizeCode(ctx, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateAuthorizeCode", reflect.TypeOf((*MockAuthorizeCodeStrategy)(nil).GenerateAuthorizeCode), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateAuthorizeCode", reflect.TypeOf((*MockAuthorizeCodeStrategy)(nil).GenerateAuthorizeCode), ctx, requester) } // ValidateAuthorizeCode mocks base method. -func (m *MockAuthorizeCodeStrategy) ValidateAuthorizeCode(arg0 context.Context, arg1 fosite.Requester, arg2 string) error { +func (m *MockAuthorizeCodeStrategy) ValidateAuthorizeCode(ctx context.Context, requester fosite.Requester, token string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateAuthorizeCode", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ValidateAuthorizeCode", ctx, requester, token) ret0, _ := ret[0].(error) return ret0 } // ValidateAuthorizeCode indicates an expected call of ValidateAuthorizeCode. -func (mr *MockAuthorizeCodeStrategyMockRecorder) ValidateAuthorizeCode(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockAuthorizeCodeStrategyMockRecorder) ValidateAuthorizeCode(ctx, requester, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAuthorizeCode", reflect.TypeOf((*MockAuthorizeCodeStrategy)(nil).ValidateAuthorizeCode), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAuthorizeCode", reflect.TypeOf((*MockAuthorizeCodeStrategy)(nil).ValidateAuthorizeCode), ctx, requester, token) } diff --git a/internal/authorize_handler.go b/internal/authorize_handler.go index bbc919d8e..80cf21a88 100644 --- a/internal/authorize_handler.go +++ b/internal/authorize_handler.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: AuthorizeEndpointHandler) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/authorize_handler.go github.com/ory/fosite AuthorizeEndpointHandler +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockAuthorizeEndpointHandler is a mock of AuthorizeEndpointHandler interface. type MockAuthorizeEndpointHandler struct { ctrl *gomock.Controller recorder *MockAuthorizeEndpointHandlerMockRecorder + isgomock struct{} } // MockAuthorizeEndpointHandlerMockRecorder is the mock recorder for MockAuthorizeEndpointHandler. @@ -39,15 +45,15 @@ func (m *MockAuthorizeEndpointHandler) EXPECT() *MockAuthorizeEndpointHandlerMoc } // HandleAuthorizeEndpointRequest mocks base method. -func (m *MockAuthorizeEndpointHandler) HandleAuthorizeEndpointRequest(arg0 context.Context, arg1 fosite.AuthorizeRequester, arg2 fosite.AuthorizeResponder) error { +func (m *MockAuthorizeEndpointHandler) HandleAuthorizeEndpointRequest(ctx context.Context, requester fosite.AuthorizeRequester, responder fosite.AuthorizeResponder) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HandleAuthorizeEndpointRequest", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "HandleAuthorizeEndpointRequest", ctx, requester, responder) ret0, _ := ret[0].(error) return ret0 } // HandleAuthorizeEndpointRequest indicates an expected call of HandleAuthorizeEndpointRequest. -func (mr *MockAuthorizeEndpointHandlerMockRecorder) HandleAuthorizeEndpointRequest(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockAuthorizeEndpointHandlerMockRecorder) HandleAuthorizeEndpointRequest(ctx, requester, responder any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleAuthorizeEndpointRequest", reflect.TypeOf((*MockAuthorizeEndpointHandler)(nil).HandleAuthorizeEndpointRequest), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleAuthorizeEndpointRequest", reflect.TypeOf((*MockAuthorizeEndpointHandler)(nil).HandleAuthorizeEndpointRequest), ctx, requester, responder) } diff --git a/internal/authorize_request.go b/internal/authorize_request.go index 7e85bb057..85666eab5 100644 --- a/internal/authorize_request.go +++ b/internal/authorize_request.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: AuthorizeRequester) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/authorize_request.go github.com/ory/fosite AuthorizeRequester +// // Package internal is a generated GoMock package. package internal @@ -12,14 +17,15 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockAuthorizeRequester is a mock of AuthorizeRequester interface. type MockAuthorizeRequester struct { ctrl *gomock.Controller recorder *MockAuthorizeRequesterMockRecorder + isgomock struct{} } // MockAuthorizeRequesterMockRecorder is the mock recorder for MockAuthorizeRequester. @@ -40,15 +46,15 @@ func (m *MockAuthorizeRequester) EXPECT() *MockAuthorizeRequesterMockRecorder { } // AppendRequestedScope mocks base method. -func (m *MockAuthorizeRequester) AppendRequestedScope(arg0 string) { +func (m *MockAuthorizeRequester) AppendRequestedScope(scope string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "AppendRequestedScope", arg0) + m.ctrl.Call(m, "AppendRequestedScope", scope) } // AppendRequestedScope indicates an expected call of AppendRequestedScope. -func (mr *MockAuthorizeRequesterMockRecorder) AppendRequestedScope(arg0 interface{}) *gomock.Call { +func (mr *MockAuthorizeRequesterMockRecorder) AppendRequestedScope(scope any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppendRequestedScope", reflect.TypeOf((*MockAuthorizeRequester)(nil).AppendRequestedScope), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppendRequestedScope", reflect.TypeOf((*MockAuthorizeRequester)(nil).AppendRequestedScope), scope) } // DidHandleAllResponseTypes mocks base method. @@ -262,27 +268,27 @@ func (mr *MockAuthorizeRequesterMockRecorder) GetState() *gomock.Call { } // GrantAudience mocks base method. -func (m *MockAuthorizeRequester) GrantAudience(arg0 string) { +func (m *MockAuthorizeRequester) GrantAudience(audience string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "GrantAudience", arg0) + m.ctrl.Call(m, "GrantAudience", audience) } // GrantAudience indicates an expected call of GrantAudience. -func (mr *MockAuthorizeRequesterMockRecorder) GrantAudience(arg0 interface{}) *gomock.Call { +func (mr *MockAuthorizeRequesterMockRecorder) GrantAudience(audience any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantAudience", reflect.TypeOf((*MockAuthorizeRequester)(nil).GrantAudience), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantAudience", reflect.TypeOf((*MockAuthorizeRequester)(nil).GrantAudience), audience) } // GrantScope mocks base method. -func (m *MockAuthorizeRequester) GrantScope(arg0 string) { +func (m *MockAuthorizeRequester) GrantScope(scope string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "GrantScope", arg0) + m.ctrl.Call(m, "GrantScope", scope) } // GrantScope indicates an expected call of GrantScope. -func (mr *MockAuthorizeRequesterMockRecorder) GrantScope(arg0 interface{}) *gomock.Call { +func (mr *MockAuthorizeRequesterMockRecorder) GrantScope(scope any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantScope", reflect.TypeOf((*MockAuthorizeRequester)(nil).GrantScope), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantScope", reflect.TypeOf((*MockAuthorizeRequester)(nil).GrantScope), scope) } // IsRedirectURIValid mocks base method. @@ -300,99 +306,99 @@ func (mr *MockAuthorizeRequesterMockRecorder) IsRedirectURIValid() *gomock.Call } // Merge mocks base method. -func (m *MockAuthorizeRequester) Merge(arg0 fosite.Requester) { +func (m *MockAuthorizeRequester) Merge(requester fosite.Requester) { m.ctrl.T.Helper() - m.ctrl.Call(m, "Merge", arg0) + m.ctrl.Call(m, "Merge", requester) } // Merge indicates an expected call of Merge. -func (mr *MockAuthorizeRequesterMockRecorder) Merge(arg0 interface{}) *gomock.Call { +func (mr *MockAuthorizeRequesterMockRecorder) Merge(requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Merge", reflect.TypeOf((*MockAuthorizeRequester)(nil).Merge), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Merge", reflect.TypeOf((*MockAuthorizeRequester)(nil).Merge), requester) } // Sanitize mocks base method. -func (m *MockAuthorizeRequester) Sanitize(arg0 []string) fosite.Requester { +func (m *MockAuthorizeRequester) Sanitize(allowedParameters []string) fosite.Requester { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Sanitize", arg0) + ret := m.ctrl.Call(m, "Sanitize", allowedParameters) ret0, _ := ret[0].(fosite.Requester) return ret0 } // Sanitize indicates an expected call of Sanitize. -func (mr *MockAuthorizeRequesterMockRecorder) Sanitize(arg0 interface{}) *gomock.Call { +func (mr *MockAuthorizeRequesterMockRecorder) Sanitize(allowedParameters any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sanitize", reflect.TypeOf((*MockAuthorizeRequester)(nil).Sanitize), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sanitize", reflect.TypeOf((*MockAuthorizeRequester)(nil).Sanitize), allowedParameters) } // SetDefaultResponseMode mocks base method. -func (m *MockAuthorizeRequester) SetDefaultResponseMode(arg0 fosite.ResponseModeType) { +func (m *MockAuthorizeRequester) SetDefaultResponseMode(responseMode fosite.ResponseModeType) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetDefaultResponseMode", arg0) + m.ctrl.Call(m, "SetDefaultResponseMode", responseMode) } // SetDefaultResponseMode indicates an expected call of SetDefaultResponseMode. -func (mr *MockAuthorizeRequesterMockRecorder) SetDefaultResponseMode(arg0 interface{}) *gomock.Call { +func (mr *MockAuthorizeRequesterMockRecorder) SetDefaultResponseMode(responseMode any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDefaultResponseMode", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetDefaultResponseMode), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDefaultResponseMode", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetDefaultResponseMode), responseMode) } // SetID mocks base method. -func (m *MockAuthorizeRequester) SetID(arg0 string) { +func (m *MockAuthorizeRequester) SetID(id string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetID", arg0) + m.ctrl.Call(m, "SetID", id) } // SetID indicates an expected call of SetID. -func (mr *MockAuthorizeRequesterMockRecorder) SetID(arg0 interface{}) *gomock.Call { +func (mr *MockAuthorizeRequesterMockRecorder) SetID(id any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetID", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetID), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetID", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetID), id) } // SetRequestedAudience mocks base method. -func (m *MockAuthorizeRequester) SetRequestedAudience(arg0 fosite.Arguments) { +func (m *MockAuthorizeRequester) SetRequestedAudience(audience fosite.Arguments) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetRequestedAudience", arg0) + m.ctrl.Call(m, "SetRequestedAudience", audience) } // SetRequestedAudience indicates an expected call of SetRequestedAudience. -func (mr *MockAuthorizeRequesterMockRecorder) SetRequestedAudience(arg0 interface{}) *gomock.Call { +func (mr *MockAuthorizeRequesterMockRecorder) SetRequestedAudience(audience any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedAudience", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetRequestedAudience), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedAudience", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetRequestedAudience), audience) } // SetRequestedScopes mocks base method. -func (m *MockAuthorizeRequester) SetRequestedScopes(arg0 fosite.Arguments) { +func (m *MockAuthorizeRequester) SetRequestedScopes(scopes fosite.Arguments) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetRequestedScopes", arg0) + m.ctrl.Call(m, "SetRequestedScopes", scopes) } // SetRequestedScopes indicates an expected call of SetRequestedScopes. -func (mr *MockAuthorizeRequesterMockRecorder) SetRequestedScopes(arg0 interface{}) *gomock.Call { +func (mr *MockAuthorizeRequesterMockRecorder) SetRequestedScopes(scopes any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedScopes", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetRequestedScopes), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedScopes", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetRequestedScopes), scopes) } // SetResponseTypeHandled mocks base method. -func (m *MockAuthorizeRequester) SetResponseTypeHandled(arg0 string) { +func (m *MockAuthorizeRequester) SetResponseTypeHandled(responseType string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetResponseTypeHandled", arg0) + m.ctrl.Call(m, "SetResponseTypeHandled", responseType) } // SetResponseTypeHandled indicates an expected call of SetResponseTypeHandled. -func (mr *MockAuthorizeRequesterMockRecorder) SetResponseTypeHandled(arg0 interface{}) *gomock.Call { +func (mr *MockAuthorizeRequesterMockRecorder) SetResponseTypeHandled(responseType any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetResponseTypeHandled", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetResponseTypeHandled), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetResponseTypeHandled", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetResponseTypeHandled), responseType) } // SetSession mocks base method. -func (m *MockAuthorizeRequester) SetSession(arg0 fosite.Session) { +func (m *MockAuthorizeRequester) SetSession(session fosite.Session) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSession", arg0) + m.ctrl.Call(m, "SetSession", session) } // SetSession indicates an expected call of SetSession. -func (mr *MockAuthorizeRequesterMockRecorder) SetSession(arg0 interface{}) *gomock.Call { +func (mr *MockAuthorizeRequesterMockRecorder) SetSession(session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSession", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetSession), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSession", reflect.TypeOf((*MockAuthorizeRequester)(nil).SetSession), session) } diff --git a/internal/authorize_response.go b/internal/authorize_response.go index 5526adf12..659bb1369 100644 --- a/internal/authorize_response.go +++ b/internal/authorize_response.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: AuthorizeResponder) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/authorize_response.go github.com/ory/fosite AuthorizeResponder +// // Package internal is a generated GoMock package. package internal @@ -12,13 +17,14 @@ import ( url "net/url" reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockAuthorizeResponder is a mock of AuthorizeResponder interface. type MockAuthorizeResponder struct { ctrl *gomock.Controller recorder *MockAuthorizeResponderMockRecorder + isgomock struct{} } // MockAuthorizeResponderMockRecorder is the mock recorder for MockAuthorizeResponder. @@ -39,27 +45,27 @@ func (m *MockAuthorizeResponder) EXPECT() *MockAuthorizeResponderMockRecorder { } // AddHeader mocks base method. -func (m *MockAuthorizeResponder) AddHeader(arg0, arg1 string) { +func (m *MockAuthorizeResponder) AddHeader(key, value string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "AddHeader", arg0, arg1) + m.ctrl.Call(m, "AddHeader", key, value) } // AddHeader indicates an expected call of AddHeader. -func (mr *MockAuthorizeResponderMockRecorder) AddHeader(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAuthorizeResponderMockRecorder) AddHeader(key, value any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddHeader", reflect.TypeOf((*MockAuthorizeResponder)(nil).AddHeader), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddHeader", reflect.TypeOf((*MockAuthorizeResponder)(nil).AddHeader), key, value) } // AddParameter mocks base method. -func (m *MockAuthorizeResponder) AddParameter(arg0, arg1 string) { +func (m *MockAuthorizeResponder) AddParameter(key, value string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "AddParameter", arg0, arg1) + m.ctrl.Call(m, "AddParameter", key, value) } // AddParameter indicates an expected call of AddParameter. -func (mr *MockAuthorizeResponderMockRecorder) AddParameter(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAuthorizeResponderMockRecorder) AddParameter(key, value any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddParameter", reflect.TypeOf((*MockAuthorizeResponder)(nil).AddParameter), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddParameter", reflect.TypeOf((*MockAuthorizeResponder)(nil).AddParameter), key, value) } // GetCode mocks base method. diff --git a/internal/client.go b/internal/client.go index e53cebf57..228ec8b81 100644 --- a/internal/client.go +++ b/internal/client.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: Client) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/client.go github.com/ory/fosite Client +// // Package internal is a generated GoMock package. package internal @@ -10,14 +15,15 @@ package internal import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockClient is a mock of Client interface. type MockClient struct { ctrl *gomock.Controller recorder *MockClientMockRecorder + isgomock struct{} } // MockClientMockRecorder is the mock recorder for MockClient. diff --git a/internal/device_code_rate_limit_strategy.go b/internal/device_code_rate_limit_strategy.go index 3a3b49511..1a3c037c5 100644 --- a/internal/device_code_rate_limit_strategy.go +++ b/internal/device_code_rate_limit_strategy.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/rfc8628 (interfaces: DeviceRateLimitStrategy) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/device_code_rate_limit_strategy.go github.com/ory/fosite/handler/rfc8628 DeviceRateLimitStrategy +// // Package internal is a generated GoMock package. package internal @@ -11,13 +16,14 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockDeviceRateLimitStrategy is a mock of DeviceRateLimitStrategy interface. type MockDeviceRateLimitStrategy struct { ctrl *gomock.Controller recorder *MockDeviceRateLimitStrategyMockRecorder + isgomock struct{} } // MockDeviceRateLimitStrategyMockRecorder is the mock recorder for MockDeviceRateLimitStrategy. @@ -38,15 +44,16 @@ func (m *MockDeviceRateLimitStrategy) EXPECT() *MockDeviceRateLimitStrategyMockR } // ShouldRateLimit mocks base method. -func (m *MockDeviceRateLimitStrategy) ShouldRateLimit(arg0 context.Context, arg1 string) bool { +func (m *MockDeviceRateLimitStrategy) ShouldRateLimit(ctx context.Context, code string) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ShouldRateLimit", arg0, arg1) + ret := m.ctrl.Call(m, "ShouldRateLimit", ctx, code) ret0, _ := ret[0].(bool) - return ret0 + ret1, _ := ret[1].(error) + return ret0, ret1 } // ShouldRateLimit indicates an expected call of ShouldRateLimit. -func (mr *MockDeviceRateLimitStrategyMockRecorder) ShouldRateLimit(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockDeviceRateLimitStrategyMockRecorder) ShouldRateLimit(ctx, code any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldRateLimit", reflect.TypeOf((*MockDeviceRateLimitStrategy)(nil).ShouldRateLimit), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldRateLimit", reflect.TypeOf((*MockDeviceRateLimitStrategy)(nil).ShouldRateLimit), ctx, code) } diff --git a/internal/device_code_storage.go b/internal/device_code_storage.go index c4eee24d9..d43630445 100644 --- a/internal/device_code_storage.go +++ b/internal/device_code_storage.go @@ -3,7 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/rfc8628 (interfaces: DeviceCodeStorage) - +// +// Generated by this command: +// +// mockgen -package internal -destination internal/device_code_storage.go github.com/ory/fosite/handler/rfc8628 DeviceCodeStorage +// // Package internal is a generated GoMock package. package internal @@ -11,8 +15,8 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockDeviceCodeStorage is a mock of DeviceCodeStorage interface. @@ -47,7 +51,7 @@ func (m *MockDeviceCodeStorage) CreateDeviceCodeSession(arg0 context.Context, ar } // CreateDeviceCodeSession indicates an expected call of CreateDeviceCodeSession. -func (mr *MockDeviceCodeStorageMockRecorder) CreateDeviceCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockDeviceCodeStorageMockRecorder) CreateDeviceCodeSession(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDeviceCodeSession", reflect.TypeOf((*MockDeviceCodeStorage)(nil).CreateDeviceCodeSession), arg0, arg1, arg2) } @@ -62,7 +66,7 @@ func (m *MockDeviceCodeStorage) GetDeviceCodeSession(arg0 context.Context, arg1 } // GetDeviceCodeSession indicates an expected call of GetDeviceCodeSession. -func (mr *MockDeviceCodeStorageMockRecorder) GetDeviceCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockDeviceCodeStorageMockRecorder) GetDeviceCodeSession(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeviceCodeSession", reflect.TypeOf((*MockDeviceCodeStorage)(nil).GetDeviceCodeSession), arg0, arg1, arg2) } @@ -76,7 +80,7 @@ func (m *MockDeviceCodeStorage) InvalidateDeviceCodeSession(arg0 context.Context } // InvalidateDeviceCodeSession indicates an expected call of InvalidateDeviceCodeSession. -func (mr *MockDeviceCodeStorageMockRecorder) InvalidateDeviceCodeSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockDeviceCodeStorageMockRecorder) InvalidateDeviceCodeSession(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateDeviceCodeSession", reflect.TypeOf((*MockDeviceCodeStorage)(nil).InvalidateDeviceCodeSession), arg0, arg1) } diff --git a/internal/hash.go b/internal/hash.go index 687984e76..786647a7f 100644 --- a/internal/hash.go +++ b/internal/hash.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: Hasher) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/hash.go github.com/ory/fosite Hasher +// // Package internal is a generated GoMock package. package internal @@ -11,13 +16,14 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockHasher is a mock of Hasher interface. type MockHasher struct { ctrl *gomock.Controller recorder *MockHasherMockRecorder + isgomock struct{} } // MockHasherMockRecorder is the mock recorder for MockHasher. @@ -38,30 +44,30 @@ func (m *MockHasher) EXPECT() *MockHasherMockRecorder { } // Compare mocks base method. -func (m *MockHasher) Compare(arg0 context.Context, arg1, arg2 []byte) error { +func (m *MockHasher) Compare(ctx context.Context, hash, data []byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Compare", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "Compare", ctx, hash, data) ret0, _ := ret[0].(error) return ret0 } // Compare indicates an expected call of Compare. -func (mr *MockHasherMockRecorder) Compare(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockHasherMockRecorder) Compare(ctx, hash, data any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Compare", reflect.TypeOf((*MockHasher)(nil).Compare), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Compare", reflect.TypeOf((*MockHasher)(nil).Compare), ctx, hash, data) } // Hash mocks base method. -func (m *MockHasher) Hash(arg0 context.Context, arg1 []byte) ([]byte, error) { +func (m *MockHasher) Hash(ctx context.Context, data []byte) ([]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Hash", arg0, arg1) + ret := m.ctrl.Call(m, "Hash", ctx, data) ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(error) return ret0, ret1 } // Hash indicates an expected call of Hash. -func (mr *MockHasherMockRecorder) Hash(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockHasherMockRecorder) Hash(ctx, data any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Hash", reflect.TypeOf((*MockHasher)(nil).Hash), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Hash", reflect.TypeOf((*MockHasher)(nil).Hash), ctx, data) } diff --git a/internal/id_token_strategy.go b/internal/id_token_strategy.go index d953d339b..01cade8fc 100644 --- a/internal/id_token_strategy.go +++ b/internal/id_token_strategy.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/openid (interfaces: OpenIDConnectTokenStrategy) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/id_token_strategy.go github.com/ory/fosite/handler/openid OpenIDConnectTokenStrategy +// // Package internal is a generated GoMock package. package internal @@ -12,14 +17,15 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockOpenIDConnectTokenStrategy is a mock of OpenIDConnectTokenStrategy interface. type MockOpenIDConnectTokenStrategy struct { ctrl *gomock.Controller recorder *MockOpenIDConnectTokenStrategyMockRecorder + isgomock struct{} } // MockOpenIDConnectTokenStrategyMockRecorder is the mock recorder for MockOpenIDConnectTokenStrategy. @@ -40,16 +46,16 @@ func (m *MockOpenIDConnectTokenStrategy) EXPECT() *MockOpenIDConnectTokenStrateg } // GenerateIDToken mocks base method. -func (m *MockOpenIDConnectTokenStrategy) GenerateIDToken(arg0 context.Context, arg1 time.Duration, arg2 fosite.Requester) (string, error) { +func (m *MockOpenIDConnectTokenStrategy) GenerateIDToken(ctx context.Context, lifespan time.Duration, requester fosite.Requester) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GenerateIDToken", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GenerateIDToken", ctx, lifespan, requester) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // GenerateIDToken indicates an expected call of GenerateIDToken. -func (mr *MockOpenIDConnectTokenStrategyMockRecorder) GenerateIDToken(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockOpenIDConnectTokenStrategyMockRecorder) GenerateIDToken(ctx, lifespan, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateIDToken", reflect.TypeOf((*MockOpenIDConnectTokenStrategy)(nil).GenerateIDToken), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateIDToken", reflect.TypeOf((*MockOpenIDConnectTokenStrategy)(nil).GenerateIDToken), ctx, lifespan, requester) } diff --git a/internal/introspector.go b/internal/introspector.go index 7122b93e2..585fd823b 100644 --- a/internal/introspector.go +++ b/internal/introspector.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: TokenIntrospector) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/introspector.go github.com/ory/fosite TokenIntrospector +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockTokenIntrospector is a mock of TokenIntrospector interface. type MockTokenIntrospector struct { ctrl *gomock.Controller recorder *MockTokenIntrospectorMockRecorder + isgomock struct{} } // MockTokenIntrospectorMockRecorder is the mock recorder for MockTokenIntrospector. @@ -39,16 +45,16 @@ func (m *MockTokenIntrospector) EXPECT() *MockTokenIntrospectorMockRecorder { } // IntrospectToken mocks base method. -func (m *MockTokenIntrospector) IntrospectToken(arg0 context.Context, arg1 string, arg2 fosite.TokenType, arg3 fosite.AccessRequester, arg4 []string) (fosite.TokenType, error) { +func (m *MockTokenIntrospector) IntrospectToken(ctx context.Context, token string, tokenUse fosite.TokenType, accessRequest fosite.AccessRequester, scopes []string) (fosite.TokenType, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IntrospectToken", arg0, arg1, arg2, arg3, arg4) + ret := m.ctrl.Call(m, "IntrospectToken", ctx, token, tokenUse, accessRequest, scopes) ret0, _ := ret[0].(fosite.TokenType) ret1, _ := ret[1].(error) return ret0, ret1 } // IntrospectToken indicates an expected call of IntrospectToken. -func (mr *MockTokenIntrospectorMockRecorder) IntrospectToken(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockTokenIntrospectorMockRecorder) IntrospectToken(ctx, token, tokenUse, accessRequest, scopes any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntrospectToken", reflect.TypeOf((*MockTokenIntrospector)(nil).IntrospectToken), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntrospectToken", reflect.TypeOf((*MockTokenIntrospector)(nil).IntrospectToken), ctx, token, tokenUse, accessRequest, scopes) } diff --git a/internal/oauth2_auth_jwt_storage.go b/internal/oauth2_auth_jwt_storage.go index 80c7278e5..5aa937b23 100644 --- a/internal/oauth2_auth_jwt_storage.go +++ b/internal/oauth2_auth_jwt_storage.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/rfc7523 (interfaces: RFC7523KeyStorage) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/oauth2_auth_jwt_storage.go github.com/ory/fosite/handler/rfc7523 RFC7523KeyStorage +// // Package internal is a generated GoMock package. package internal @@ -13,13 +18,14 @@ import ( time "time" jose "github.com/go-jose/go-jose/v3" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockRFC7523KeyStorage is a mock of RFC7523KeyStorage interface. type MockRFC7523KeyStorage struct { ctrl *gomock.Controller recorder *MockRFC7523KeyStorageMockRecorder + isgomock struct{} } // MockRFC7523KeyStorageMockRecorder is the mock recorder for MockRFC7523KeyStorage. @@ -40,75 +46,75 @@ func (m *MockRFC7523KeyStorage) EXPECT() *MockRFC7523KeyStorageMockRecorder { } // GetPublicKey mocks base method. -func (m *MockRFC7523KeyStorage) GetPublicKey(arg0 context.Context, arg1, arg2, arg3 string) (*jose.JSONWebKey, error) { +func (m *MockRFC7523KeyStorage) GetPublicKey(ctx context.Context, issuer, subject, keyId string) (*jose.JSONWebKey, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPublicKey", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "GetPublicKey", ctx, issuer, subject, keyId) ret0, _ := ret[0].(*jose.JSONWebKey) ret1, _ := ret[1].(error) return ret0, ret1 } // GetPublicKey indicates an expected call of GetPublicKey. -func (mr *MockRFC7523KeyStorageMockRecorder) GetPublicKey(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockRFC7523KeyStorageMockRecorder) GetPublicKey(ctx, issuer, subject, keyId any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublicKey", reflect.TypeOf((*MockRFC7523KeyStorage)(nil).GetPublicKey), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublicKey", reflect.TypeOf((*MockRFC7523KeyStorage)(nil).GetPublicKey), ctx, issuer, subject, keyId) } // GetPublicKeyScopes mocks base method. -func (m *MockRFC7523KeyStorage) GetPublicKeyScopes(arg0 context.Context, arg1, arg2, arg3 string) ([]string, error) { +func (m *MockRFC7523KeyStorage) GetPublicKeyScopes(ctx context.Context, issuer, subject, keyId string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPublicKeyScopes", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "GetPublicKeyScopes", ctx, issuer, subject, keyId) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // GetPublicKeyScopes indicates an expected call of GetPublicKeyScopes. -func (mr *MockRFC7523KeyStorageMockRecorder) GetPublicKeyScopes(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockRFC7523KeyStorageMockRecorder) GetPublicKeyScopes(ctx, issuer, subject, keyId any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublicKeyScopes", reflect.TypeOf((*MockRFC7523KeyStorage)(nil).GetPublicKeyScopes), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublicKeyScopes", reflect.TypeOf((*MockRFC7523KeyStorage)(nil).GetPublicKeyScopes), ctx, issuer, subject, keyId) } // GetPublicKeys mocks base method. -func (m *MockRFC7523KeyStorage) GetPublicKeys(arg0 context.Context, arg1, arg2 string) (*jose.JSONWebKeySet, error) { +func (m *MockRFC7523KeyStorage) GetPublicKeys(ctx context.Context, issuer, subject string) (*jose.JSONWebKeySet, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPublicKeys", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetPublicKeys", ctx, issuer, subject) ret0, _ := ret[0].(*jose.JSONWebKeySet) ret1, _ := ret[1].(error) return ret0, ret1 } // GetPublicKeys indicates an expected call of GetPublicKeys. -func (mr *MockRFC7523KeyStorageMockRecorder) GetPublicKeys(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRFC7523KeyStorageMockRecorder) GetPublicKeys(ctx, issuer, subject any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublicKeys", reflect.TypeOf((*MockRFC7523KeyStorage)(nil).GetPublicKeys), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublicKeys", reflect.TypeOf((*MockRFC7523KeyStorage)(nil).GetPublicKeys), ctx, issuer, subject) } // IsJWTUsed mocks base method. -func (m *MockRFC7523KeyStorage) IsJWTUsed(arg0 context.Context, arg1 string) (bool, error) { +func (m *MockRFC7523KeyStorage) IsJWTUsed(ctx context.Context, jti string) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsJWTUsed", arg0, arg1) + ret := m.ctrl.Call(m, "IsJWTUsed", ctx, jti) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } // IsJWTUsed indicates an expected call of IsJWTUsed. -func (mr *MockRFC7523KeyStorageMockRecorder) IsJWTUsed(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockRFC7523KeyStorageMockRecorder) IsJWTUsed(ctx, jti any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsJWTUsed", reflect.TypeOf((*MockRFC7523KeyStorage)(nil).IsJWTUsed), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsJWTUsed", reflect.TypeOf((*MockRFC7523KeyStorage)(nil).IsJWTUsed), ctx, jti) } // MarkJWTUsedForTime mocks base method. -func (m *MockRFC7523KeyStorage) MarkJWTUsedForTime(arg0 context.Context, arg1 string, arg2 time.Time) error { +func (m *MockRFC7523KeyStorage) MarkJWTUsedForTime(ctx context.Context, jti string, exp time.Time) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MarkJWTUsedForTime", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "MarkJWTUsedForTime", ctx, jti, exp) ret0, _ := ret[0].(error) return ret0 } // MarkJWTUsedForTime indicates an expected call of MarkJWTUsedForTime. -func (mr *MockRFC7523KeyStorageMockRecorder) MarkJWTUsedForTime(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRFC7523KeyStorageMockRecorder) MarkJWTUsedForTime(ctx, jti, exp any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MarkJWTUsedForTime", reflect.TypeOf((*MockRFC7523KeyStorage)(nil).MarkJWTUsedForTime), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MarkJWTUsedForTime", reflect.TypeOf((*MockRFC7523KeyStorage)(nil).MarkJWTUsedForTime), ctx, jti, exp) } diff --git a/internal/oauth2_client_storage.go b/internal/oauth2_client_storage.go index 96eb41711..892f3b69a 100644 --- a/internal/oauth2_client_storage.go +++ b/internal/oauth2_client_storage.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/oauth2 (interfaces: ClientCredentialsGrantStorage) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/oauth2_client_storage.go github.com/ory/fosite/handler/oauth2 ClientCredentialsGrantStorage +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockClientCredentialsGrantStorage is a mock of ClientCredentialsGrantStorage interface. type MockClientCredentialsGrantStorage struct { ctrl *gomock.Controller recorder *MockClientCredentialsGrantStorageMockRecorder + isgomock struct{} } // MockClientCredentialsGrantStorageMockRecorder is the mock recorder for MockClientCredentialsGrantStorage. @@ -39,44 +45,44 @@ func (m *MockClientCredentialsGrantStorage) EXPECT() *MockClientCredentialsGrant } // CreateAccessTokenSession mocks base method. -func (m *MockClientCredentialsGrantStorage) CreateAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +func (m *MockClientCredentialsGrantStorage) CreateAccessTokenSession(ctx context.Context, signature string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateAccessTokenSession", ctx, signature, request) ret0, _ := ret[0].(error) return ret0 } // CreateAccessTokenSession indicates an expected call of CreateAccessTokenSession. -func (mr *MockClientCredentialsGrantStorageMockRecorder) CreateAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockClientCredentialsGrantStorageMockRecorder) CreateAccessTokenSession(ctx, signature, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockClientCredentialsGrantStorage)(nil).CreateAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockClientCredentialsGrantStorage)(nil).CreateAccessTokenSession), ctx, signature, request) } // DeleteAccessTokenSession mocks base method. -func (m *MockClientCredentialsGrantStorage) DeleteAccessTokenSession(arg0 context.Context, arg1 string) error { +func (m *MockClientCredentialsGrantStorage) DeleteAccessTokenSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteAccessTokenSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteAccessTokenSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // DeleteAccessTokenSession indicates an expected call of DeleteAccessTokenSession. -func (mr *MockClientCredentialsGrantStorageMockRecorder) DeleteAccessTokenSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockClientCredentialsGrantStorageMockRecorder) DeleteAccessTokenSession(ctx, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockClientCredentialsGrantStorage)(nil).DeleteAccessTokenSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockClientCredentialsGrantStorage)(nil).DeleteAccessTokenSession), ctx, signature) } // GetAccessTokenSession mocks base method. -func (m *MockClientCredentialsGrantStorage) GetAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockClientCredentialsGrantStorage) GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetAccessTokenSession", ctx, signature, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetAccessTokenSession indicates an expected call of GetAccessTokenSession. -func (mr *MockClientCredentialsGrantStorageMockRecorder) GetAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockClientCredentialsGrantStorageMockRecorder) GetAccessTokenSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockClientCredentialsGrantStorage)(nil).GetAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockClientCredentialsGrantStorage)(nil).GetAccessTokenSession), ctx, signature, session) } diff --git a/internal/oauth2_explicit_storage.go b/internal/oauth2_explicit_storage.go index 1bcd39226..9e78dcdb2 100644 --- a/internal/oauth2_explicit_storage.go +++ b/internal/oauth2_explicit_storage.go @@ -9,7 +9,7 @@ package internal import ( "context" - "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" ) diff --git a/internal/oauth2_owner_storage.go b/internal/oauth2_owner_storage.go index fca78900b..68bdfa7ee 100644 --- a/internal/oauth2_owner_storage.go +++ b/internal/oauth2_owner_storage.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/oauth2 (interfaces: ResourceOwnerPasswordCredentialsGrantStorage) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/oauth2_owner_storage.go github.com/ory/fosite/handler/oauth2 ResourceOwnerPasswordCredentialsGrantStorage +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockResourceOwnerPasswordCredentialsGrantStorage is a mock of ResourceOwnerPasswordCredentialsGrantStorage interface. type MockResourceOwnerPasswordCredentialsGrantStorage struct { ctrl *gomock.Controller recorder *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder + isgomock struct{} } // MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder is the mock recorder for MockResourceOwnerPasswordCredentialsGrantStorage. @@ -39,116 +45,116 @@ func (m *MockResourceOwnerPasswordCredentialsGrantStorage) EXPECT() *MockResourc } // Authenticate mocks base method. -func (m *MockResourceOwnerPasswordCredentialsGrantStorage) Authenticate(arg0 context.Context, arg1, arg2 string) (string, error) { +func (m *MockResourceOwnerPasswordCredentialsGrantStorage) Authenticate(ctx context.Context, name, secret string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Authenticate", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "Authenticate", ctx, name, secret) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // Authenticate indicates an expected call of Authenticate. -func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) Authenticate(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) Authenticate(ctx, name, secret any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Authenticate", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).Authenticate), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Authenticate", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).Authenticate), ctx, name, secret) } // CreateAccessTokenSession mocks base method. -func (m *MockResourceOwnerPasswordCredentialsGrantStorage) CreateAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +func (m *MockResourceOwnerPasswordCredentialsGrantStorage) CreateAccessTokenSession(ctx context.Context, signature string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateAccessTokenSession", ctx, signature, request) ret0, _ := ret[0].(error) return ret0 } // CreateAccessTokenSession indicates an expected call of CreateAccessTokenSession. -func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) CreateAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) CreateAccessTokenSession(ctx, signature, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).CreateAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).CreateAccessTokenSession), ctx, signature, request) } // CreateRefreshTokenSession mocks base method. -func (m *MockResourceOwnerPasswordCredentialsGrantStorage) CreateRefreshTokenSession(arg0 context.Context, arg1, arg2 string, arg3 fosite.Requester) error { +func (m *MockResourceOwnerPasswordCredentialsGrantStorage) CreateRefreshTokenSession(ctx context.Context, signature, accessSignature string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateRefreshTokenSession", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "CreateRefreshTokenSession", ctx, signature, accessSignature, request) ret0, _ := ret[0].(error) return ret0 } // CreateRefreshTokenSession indicates an expected call of CreateRefreshTokenSession. -func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) CreateRefreshTokenSession(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) CreateRefreshTokenSession(ctx, signature, accessSignature, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRefreshTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).CreateRefreshTokenSession), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRefreshTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).CreateRefreshTokenSession), ctx, signature, accessSignature, request) } // DeleteAccessTokenSession mocks base method. -func (m *MockResourceOwnerPasswordCredentialsGrantStorage) DeleteAccessTokenSession(arg0 context.Context, arg1 string) error { +func (m *MockResourceOwnerPasswordCredentialsGrantStorage) DeleteAccessTokenSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteAccessTokenSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteAccessTokenSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // DeleteAccessTokenSession indicates an expected call of DeleteAccessTokenSession. -func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) DeleteAccessTokenSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) DeleteAccessTokenSession(ctx, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).DeleteAccessTokenSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).DeleteAccessTokenSession), ctx, signature) } // DeleteRefreshTokenSession mocks base method. -func (m *MockResourceOwnerPasswordCredentialsGrantStorage) DeleteRefreshTokenSession(arg0 context.Context, arg1 string) error { +func (m *MockResourceOwnerPasswordCredentialsGrantStorage) DeleteRefreshTokenSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteRefreshTokenSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteRefreshTokenSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // DeleteRefreshTokenSession indicates an expected call of DeleteRefreshTokenSession. -func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) DeleteRefreshTokenSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) DeleteRefreshTokenSession(ctx, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRefreshTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).DeleteRefreshTokenSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRefreshTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).DeleteRefreshTokenSession), ctx, signature) } // GetAccessTokenSession mocks base method. -func (m *MockResourceOwnerPasswordCredentialsGrantStorage) GetAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockResourceOwnerPasswordCredentialsGrantStorage) GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetAccessTokenSession", ctx, signature, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetAccessTokenSession indicates an expected call of GetAccessTokenSession. -func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) GetAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) GetAccessTokenSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).GetAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).GetAccessTokenSession), ctx, signature, session) } // GetRefreshTokenSession mocks base method. -func (m *MockResourceOwnerPasswordCredentialsGrantStorage) GetRefreshTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockResourceOwnerPasswordCredentialsGrantStorage) GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRefreshTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetRefreshTokenSession", ctx, signature, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetRefreshTokenSession indicates an expected call of GetRefreshTokenSession. -func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) GetRefreshTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) GetRefreshTokenSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRefreshTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).GetRefreshTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRefreshTokenSession", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).GetRefreshTokenSession), ctx, signature, session) } // RotateRefreshToken mocks base method. -func (m *MockResourceOwnerPasswordCredentialsGrantStorage) RotateRefreshToken(arg0 context.Context, arg1, arg2 string) error { +func (m *MockResourceOwnerPasswordCredentialsGrantStorage) RotateRefreshToken(ctx context.Context, requestID, refreshTokenSignature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RotateRefreshToken", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "RotateRefreshToken", ctx, requestID, refreshTokenSignature) ret0, _ := ret[0].(error) return ret0 } // RotateRefreshToken indicates an expected call of RotateRefreshToken. -func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) RotateRefreshToken(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockResourceOwnerPasswordCredentialsGrantStorageMockRecorder) RotateRefreshToken(ctx, requestID, refreshTokenSignature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RotateRefreshToken", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).RotateRefreshToken), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RotateRefreshToken", reflect.TypeOf((*MockResourceOwnerPasswordCredentialsGrantStorage)(nil).RotateRefreshToken), ctx, requestID, refreshTokenSignature) } diff --git a/internal/oauth2_refresh_storage.go b/internal/oauth2_refresh_storage.go index 73cfa8c29..8cf6eaa75 100644 --- a/internal/oauth2_refresh_storage.go +++ b/internal/oauth2_refresh_storage.go @@ -9,7 +9,7 @@ package internal import ( "context" - "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" ) diff --git a/internal/oauth2_revoke_storage.go b/internal/oauth2_revoke_storage.go index 9cdfad2fd..04e2dfae4 100644 --- a/internal/oauth2_revoke_storage.go +++ b/internal/oauth2_revoke_storage.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/oauth2 (interfaces: TokenRevocationStorage) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/oauth2_revoke_storage.go github.com/ory/fosite/handler/oauth2 TokenRevocationStorage +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockTokenRevocationStorage is a mock of TokenRevocationStorage interface. type MockTokenRevocationStorage struct { ctrl *gomock.Controller recorder *MockTokenRevocationStorageMockRecorder + isgomock struct{} } // MockTokenRevocationStorageMockRecorder is the mock recorder for MockTokenRevocationStorage. @@ -39,129 +45,129 @@ func (m *MockTokenRevocationStorage) EXPECT() *MockTokenRevocationStorageMockRec } // CreateAccessTokenSession mocks base method. -func (m *MockTokenRevocationStorage) CreateAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +func (m *MockTokenRevocationStorage) CreateAccessTokenSession(ctx context.Context, signature string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateAccessTokenSession", ctx, signature, request) ret0, _ := ret[0].(error) return ret0 } // CreateAccessTokenSession indicates an expected call of CreateAccessTokenSession. -func (mr *MockTokenRevocationStorageMockRecorder) CreateAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockTokenRevocationStorageMockRecorder) CreateAccessTokenSession(ctx, signature, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).CreateAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).CreateAccessTokenSession), ctx, signature, request) } // CreateRefreshTokenSession mocks base method. -func (m *MockTokenRevocationStorage) CreateRefreshTokenSession(arg0 context.Context, arg1, arg2 string, arg3 fosite.Requester) error { +func (m *MockTokenRevocationStorage) CreateRefreshTokenSession(ctx context.Context, signature, accessSignature string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateRefreshTokenSession", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "CreateRefreshTokenSession", ctx, signature, accessSignature, request) ret0, _ := ret[0].(error) return ret0 } // CreateRefreshTokenSession indicates an expected call of CreateRefreshTokenSession. -func (mr *MockTokenRevocationStorageMockRecorder) CreateRefreshTokenSession(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockTokenRevocationStorageMockRecorder) CreateRefreshTokenSession(ctx, signature, accessSignature, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRefreshTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).CreateRefreshTokenSession), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRefreshTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).CreateRefreshTokenSession), ctx, signature, accessSignature, request) } // DeleteAccessTokenSession mocks base method. -func (m *MockTokenRevocationStorage) DeleteAccessTokenSession(arg0 context.Context, arg1 string) error { +func (m *MockTokenRevocationStorage) DeleteAccessTokenSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteAccessTokenSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteAccessTokenSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // DeleteAccessTokenSession indicates an expected call of DeleteAccessTokenSession. -func (mr *MockTokenRevocationStorageMockRecorder) DeleteAccessTokenSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockTokenRevocationStorageMockRecorder) DeleteAccessTokenSession(ctx, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).DeleteAccessTokenSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).DeleteAccessTokenSession), ctx, signature) } // DeleteRefreshTokenSession mocks base method. -func (m *MockTokenRevocationStorage) DeleteRefreshTokenSession(arg0 context.Context, arg1 string) error { +func (m *MockTokenRevocationStorage) DeleteRefreshTokenSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteRefreshTokenSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteRefreshTokenSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // DeleteRefreshTokenSession indicates an expected call of DeleteRefreshTokenSession. -func (mr *MockTokenRevocationStorageMockRecorder) DeleteRefreshTokenSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockTokenRevocationStorageMockRecorder) DeleteRefreshTokenSession(ctx, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRefreshTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).DeleteRefreshTokenSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRefreshTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).DeleteRefreshTokenSession), ctx, signature) } // GetAccessTokenSession mocks base method. -func (m *MockTokenRevocationStorage) GetAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockTokenRevocationStorage) GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetAccessTokenSession", ctx, signature, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetAccessTokenSession indicates an expected call of GetAccessTokenSession. -func (mr *MockTokenRevocationStorageMockRecorder) GetAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockTokenRevocationStorageMockRecorder) GetAccessTokenSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).GetAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).GetAccessTokenSession), ctx, signature, session) } // GetRefreshTokenSession mocks base method. -func (m *MockTokenRevocationStorage) GetRefreshTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockTokenRevocationStorage) GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRefreshTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetRefreshTokenSession", ctx, signature, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetRefreshTokenSession indicates an expected call of GetRefreshTokenSession. -func (mr *MockTokenRevocationStorageMockRecorder) GetRefreshTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockTokenRevocationStorageMockRecorder) GetRefreshTokenSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRefreshTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).GetRefreshTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRefreshTokenSession", reflect.TypeOf((*MockTokenRevocationStorage)(nil).GetRefreshTokenSession), ctx, signature, session) } // RevokeAccessToken mocks base method. -func (m *MockTokenRevocationStorage) RevokeAccessToken(arg0 context.Context, arg1 string) error { +func (m *MockTokenRevocationStorage) RevokeAccessToken(ctx context.Context, requestID string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RevokeAccessToken", arg0, arg1) + ret := m.ctrl.Call(m, "RevokeAccessToken", ctx, requestID) ret0, _ := ret[0].(error) return ret0 } // RevokeAccessToken indicates an expected call of RevokeAccessToken. -func (mr *MockTokenRevocationStorageMockRecorder) RevokeAccessToken(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockTokenRevocationStorageMockRecorder) RevokeAccessToken(ctx, requestID any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevokeAccessToken", reflect.TypeOf((*MockTokenRevocationStorage)(nil).RevokeAccessToken), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevokeAccessToken", reflect.TypeOf((*MockTokenRevocationStorage)(nil).RevokeAccessToken), ctx, requestID) } // RevokeRefreshToken mocks base method. -func (m *MockTokenRevocationStorage) RevokeRefreshToken(arg0 context.Context, arg1 string) error { +func (m *MockTokenRevocationStorage) RevokeRefreshToken(ctx context.Context, requestID string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RevokeRefreshToken", arg0, arg1) + ret := m.ctrl.Call(m, "RevokeRefreshToken", ctx, requestID) ret0, _ := ret[0].(error) return ret0 } // RevokeRefreshToken indicates an expected call of RevokeRefreshToken. -func (mr *MockTokenRevocationStorageMockRecorder) RevokeRefreshToken(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockTokenRevocationStorageMockRecorder) RevokeRefreshToken(ctx, requestID any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevokeRefreshToken", reflect.TypeOf((*MockTokenRevocationStorage)(nil).RevokeRefreshToken), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevokeRefreshToken", reflect.TypeOf((*MockTokenRevocationStorage)(nil).RevokeRefreshToken), ctx, requestID) } // RotateRefreshToken mocks base method. -func (m *MockTokenRevocationStorage) RotateRefreshToken(arg0 context.Context, arg1, arg2 string) error { +func (m *MockTokenRevocationStorage) RotateRefreshToken(ctx context.Context, requestID, refreshTokenSignature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RotateRefreshToken", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "RotateRefreshToken", ctx, requestID, refreshTokenSignature) ret0, _ := ret[0].(error) return ret0 } // RotateRefreshToken indicates an expected call of RotateRefreshToken. -func (mr *MockTokenRevocationStorageMockRecorder) RotateRefreshToken(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockTokenRevocationStorageMockRecorder) RotateRefreshToken(ctx, requestID, refreshTokenSignature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RotateRefreshToken", reflect.TypeOf((*MockTokenRevocationStorage)(nil).RotateRefreshToken), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RotateRefreshToken", reflect.TypeOf((*MockTokenRevocationStorage)(nil).RotateRefreshToken), ctx, requestID, refreshTokenSignature) } diff --git a/internal/oauth2_storage.go b/internal/oauth2_storage.go index 5524c6c7e..772e39fd9 100644 --- a/internal/oauth2_storage.go +++ b/internal/oauth2_storage.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/oauth2 (interfaces: CoreStorage) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/oauth2_storage.go github.com/ory/fosite/handler/oauth2 CoreStorage +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockCoreStorage is a mock of CoreStorage interface. type MockCoreStorage struct { ctrl *gomock.Controller recorder *MockCoreStorageMockRecorder + isgomock struct{} } // MockCoreStorageMockRecorder is the mock recorder for MockCoreStorage. @@ -39,144 +45,144 @@ func (m *MockCoreStorage) EXPECT() *MockCoreStorageMockRecorder { } // CreateAccessTokenSession mocks base method. -func (m *MockCoreStorage) CreateAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +func (m *MockCoreStorage) CreateAccessTokenSession(ctx context.Context, signature string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateAccessTokenSession", ctx, signature, request) ret0, _ := ret[0].(error) return ret0 } // CreateAccessTokenSession indicates an expected call of CreateAccessTokenSession. -func (mr *MockCoreStorageMockRecorder) CreateAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockCoreStorageMockRecorder) CreateAccessTokenSession(ctx, signature, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).CreateAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).CreateAccessTokenSession), ctx, signature, request) } // CreateAuthorizeCodeSession mocks base method. -func (m *MockCoreStorage) CreateAuthorizeCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +func (m *MockCoreStorage) CreateAuthorizeCodeSession(ctx context.Context, code string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateAuthorizeCodeSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateAuthorizeCodeSession", ctx, code, request) ret0, _ := ret[0].(error) return ret0 } // CreateAuthorizeCodeSession indicates an expected call of CreateAuthorizeCodeSession. -func (mr *MockCoreStorageMockRecorder) CreateAuthorizeCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockCoreStorageMockRecorder) CreateAuthorizeCodeSession(ctx, code, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAuthorizeCodeSession", reflect.TypeOf((*MockCoreStorage)(nil).CreateAuthorizeCodeSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAuthorizeCodeSession", reflect.TypeOf((*MockCoreStorage)(nil).CreateAuthorizeCodeSession), ctx, code, request) } // CreateRefreshTokenSession mocks base method. -func (m *MockCoreStorage) CreateRefreshTokenSession(arg0 context.Context, arg1, arg2 string, arg3 fosite.Requester) error { +func (m *MockCoreStorage) CreateRefreshTokenSession(ctx context.Context, signature, accessSignature string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateRefreshTokenSession", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "CreateRefreshTokenSession", ctx, signature, accessSignature, request) ret0, _ := ret[0].(error) return ret0 } // CreateRefreshTokenSession indicates an expected call of CreateRefreshTokenSession. -func (mr *MockCoreStorageMockRecorder) CreateRefreshTokenSession(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockCoreStorageMockRecorder) CreateRefreshTokenSession(ctx, signature, accessSignature, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRefreshTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).CreateRefreshTokenSession), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRefreshTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).CreateRefreshTokenSession), ctx, signature, accessSignature, request) } // DeleteAccessTokenSession mocks base method. -func (m *MockCoreStorage) DeleteAccessTokenSession(arg0 context.Context, arg1 string) error { +func (m *MockCoreStorage) DeleteAccessTokenSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteAccessTokenSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteAccessTokenSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // DeleteAccessTokenSession indicates an expected call of DeleteAccessTokenSession. -func (mr *MockCoreStorageMockRecorder) DeleteAccessTokenSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockCoreStorageMockRecorder) DeleteAccessTokenSession(ctx, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).DeleteAccessTokenSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).DeleteAccessTokenSession), ctx, signature) } // DeleteRefreshTokenSession mocks base method. -func (m *MockCoreStorage) DeleteRefreshTokenSession(arg0 context.Context, arg1 string) error { +func (m *MockCoreStorage) DeleteRefreshTokenSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteRefreshTokenSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteRefreshTokenSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // DeleteRefreshTokenSession indicates an expected call of DeleteRefreshTokenSession. -func (mr *MockCoreStorageMockRecorder) DeleteRefreshTokenSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockCoreStorageMockRecorder) DeleteRefreshTokenSession(ctx, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRefreshTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).DeleteRefreshTokenSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRefreshTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).DeleteRefreshTokenSession), ctx, signature) } // GetAccessTokenSession mocks base method. -func (m *MockCoreStorage) GetAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockCoreStorage) GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetAccessTokenSession", ctx, signature, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetAccessTokenSession indicates an expected call of GetAccessTokenSession. -func (mr *MockCoreStorageMockRecorder) GetAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockCoreStorageMockRecorder) GetAccessTokenSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).GetAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).GetAccessTokenSession), ctx, signature, session) } // GetAuthorizeCodeSession mocks base method. -func (m *MockCoreStorage) GetAuthorizeCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockCoreStorage) GetAuthorizeCodeSession(ctx context.Context, code string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAuthorizeCodeSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetAuthorizeCodeSession", ctx, code, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetAuthorizeCodeSession indicates an expected call of GetAuthorizeCodeSession. -func (mr *MockCoreStorageMockRecorder) GetAuthorizeCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockCoreStorageMockRecorder) GetAuthorizeCodeSession(ctx, code, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizeCodeSession", reflect.TypeOf((*MockCoreStorage)(nil).GetAuthorizeCodeSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizeCodeSession", reflect.TypeOf((*MockCoreStorage)(nil).GetAuthorizeCodeSession), ctx, code, session) } // GetRefreshTokenSession mocks base method. -func (m *MockCoreStorage) GetRefreshTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockCoreStorage) GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRefreshTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetRefreshTokenSession", ctx, signature, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetRefreshTokenSession indicates an expected call of GetRefreshTokenSession. -func (mr *MockCoreStorageMockRecorder) GetRefreshTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockCoreStorageMockRecorder) GetRefreshTokenSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRefreshTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).GetRefreshTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRefreshTokenSession", reflect.TypeOf((*MockCoreStorage)(nil).GetRefreshTokenSession), ctx, signature, session) } // InvalidateAuthorizeCodeSession mocks base method. -func (m *MockCoreStorage) InvalidateAuthorizeCodeSession(arg0 context.Context, arg1 string) error { +func (m *MockCoreStorage) InvalidateAuthorizeCodeSession(ctx context.Context, code string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InvalidateAuthorizeCodeSession", arg0, arg1) + ret := m.ctrl.Call(m, "InvalidateAuthorizeCodeSession", ctx, code) ret0, _ := ret[0].(error) return ret0 } // InvalidateAuthorizeCodeSession indicates an expected call of InvalidateAuthorizeCodeSession. -func (mr *MockCoreStorageMockRecorder) InvalidateAuthorizeCodeSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockCoreStorageMockRecorder) InvalidateAuthorizeCodeSession(ctx, code any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateAuthorizeCodeSession", reflect.TypeOf((*MockCoreStorage)(nil).InvalidateAuthorizeCodeSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateAuthorizeCodeSession", reflect.TypeOf((*MockCoreStorage)(nil).InvalidateAuthorizeCodeSession), ctx, code) } // RotateRefreshToken mocks base method. -func (m *MockCoreStorage) RotateRefreshToken(arg0 context.Context, arg1, arg2 string) error { +func (m *MockCoreStorage) RotateRefreshToken(ctx context.Context, requestID, refreshTokenSignature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RotateRefreshToken", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "RotateRefreshToken", ctx, requestID, refreshTokenSignature) ret0, _ := ret[0].(error) return ret0 } // RotateRefreshToken indicates an expected call of RotateRefreshToken. -func (mr *MockCoreStorageMockRecorder) RotateRefreshToken(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockCoreStorageMockRecorder) RotateRefreshToken(ctx, requestID, refreshTokenSignature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RotateRefreshToken", reflect.TypeOf((*MockCoreStorage)(nil).RotateRefreshToken), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RotateRefreshToken", reflect.TypeOf((*MockCoreStorage)(nil).RotateRefreshToken), ctx, requestID, refreshTokenSignature) } diff --git a/internal/oauth2_strategy.go b/internal/oauth2_strategy.go index aeb473fe5..456ab2e20 100644 --- a/internal/oauth2_strategy.go +++ b/internal/oauth2_strategy.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/oauth2 (interfaces: CoreStrategy) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/oauth2_strategy.go github.com/ory/fosite/handler/oauth2 CoreStrategy +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockCoreStrategy is a mock of CoreStrategy interface. type MockCoreStrategy struct { ctrl *gomock.Controller recorder *MockCoreStrategyMockRecorder + isgomock struct{} } // MockCoreStrategyMockRecorder is the mock recorder for MockCoreStrategy. @@ -39,37 +45,37 @@ func (m *MockCoreStrategy) EXPECT() *MockCoreStrategyMockRecorder { } // AccessTokenSignature mocks base method. -func (m *MockCoreStrategy) AccessTokenSignature(arg0 context.Context, arg1 string) string { +func (m *MockCoreStrategy) AccessTokenSignature(ctx context.Context, token string) string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AccessTokenSignature", arg0, arg1) + ret := m.ctrl.Call(m, "AccessTokenSignature", ctx, token) ret0, _ := ret[0].(string) return ret0 } // AccessTokenSignature indicates an expected call of AccessTokenSignature. -func (mr *MockCoreStrategyMockRecorder) AccessTokenSignature(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockCoreStrategyMockRecorder) AccessTokenSignature(ctx, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccessTokenSignature", reflect.TypeOf((*MockCoreStrategy)(nil).AccessTokenSignature), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccessTokenSignature", reflect.TypeOf((*MockCoreStrategy)(nil).AccessTokenSignature), ctx, token) } // AuthorizeCodeSignature mocks base method. -func (m *MockCoreStrategy) AuthorizeCodeSignature(arg0 context.Context, arg1 string) string { +func (m *MockCoreStrategy) AuthorizeCodeSignature(ctx context.Context, token string) string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AuthorizeCodeSignature", arg0, arg1) + ret := m.ctrl.Call(m, "AuthorizeCodeSignature", ctx, token) ret0, _ := ret[0].(string) return ret0 } // AuthorizeCodeSignature indicates an expected call of AuthorizeCodeSignature. -func (mr *MockCoreStrategyMockRecorder) AuthorizeCodeSignature(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockCoreStrategyMockRecorder) AuthorizeCodeSignature(ctx, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthorizeCodeSignature", reflect.TypeOf((*MockCoreStrategy)(nil).AuthorizeCodeSignature), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthorizeCodeSignature", reflect.TypeOf((*MockCoreStrategy)(nil).AuthorizeCodeSignature), ctx, token) } // GenerateAccessToken mocks base method. -func (m *MockCoreStrategy) GenerateAccessToken(arg0 context.Context, arg1 fosite.Requester) (string, string, error) { +func (m *MockCoreStrategy) GenerateAccessToken(ctx context.Context, requester fosite.Requester) (string, string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GenerateAccessToken", arg0, arg1) + ret := m.ctrl.Call(m, "GenerateAccessToken", ctx, requester) ret0, _ := ret[0].(string) ret1, _ := ret[1].(string) ret2, _ := ret[2].(error) @@ -77,15 +83,15 @@ func (m *MockCoreStrategy) GenerateAccessToken(arg0 context.Context, arg1 fosite } // GenerateAccessToken indicates an expected call of GenerateAccessToken. -func (mr *MockCoreStrategyMockRecorder) GenerateAccessToken(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockCoreStrategyMockRecorder) GenerateAccessToken(ctx, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateAccessToken", reflect.TypeOf((*MockCoreStrategy)(nil).GenerateAccessToken), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateAccessToken", reflect.TypeOf((*MockCoreStrategy)(nil).GenerateAccessToken), ctx, requester) } // GenerateAuthorizeCode mocks base method. -func (m *MockCoreStrategy) GenerateAuthorizeCode(arg0 context.Context, arg1 fosite.Requester) (string, string, error) { +func (m *MockCoreStrategy) GenerateAuthorizeCode(ctx context.Context, requester fosite.Requester) (string, string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GenerateAuthorizeCode", arg0, arg1) + ret := m.ctrl.Call(m, "GenerateAuthorizeCode", ctx, requester) ret0, _ := ret[0].(string) ret1, _ := ret[1].(string) ret2, _ := ret[2].(error) @@ -93,15 +99,15 @@ func (m *MockCoreStrategy) GenerateAuthorizeCode(arg0 context.Context, arg1 fosi } // GenerateAuthorizeCode indicates an expected call of GenerateAuthorizeCode. -func (mr *MockCoreStrategyMockRecorder) GenerateAuthorizeCode(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockCoreStrategyMockRecorder) GenerateAuthorizeCode(ctx, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateAuthorizeCode", reflect.TypeOf((*MockCoreStrategy)(nil).GenerateAuthorizeCode), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateAuthorizeCode", reflect.TypeOf((*MockCoreStrategy)(nil).GenerateAuthorizeCode), ctx, requester) } // GenerateRefreshToken mocks base method. -func (m *MockCoreStrategy) GenerateRefreshToken(arg0 context.Context, arg1 fosite.Requester) (string, string, error) { +func (m *MockCoreStrategy) GenerateRefreshToken(ctx context.Context, requester fosite.Requester) (string, string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GenerateRefreshToken", arg0, arg1) + ret := m.ctrl.Call(m, "GenerateRefreshToken", ctx, requester) ret0, _ := ret[0].(string) ret1, _ := ret[1].(string) ret2, _ := ret[2].(error) @@ -109,63 +115,63 @@ func (m *MockCoreStrategy) GenerateRefreshToken(arg0 context.Context, arg1 fosit } // GenerateRefreshToken indicates an expected call of GenerateRefreshToken. -func (mr *MockCoreStrategyMockRecorder) GenerateRefreshToken(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockCoreStrategyMockRecorder) GenerateRefreshToken(ctx, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateRefreshToken", reflect.TypeOf((*MockCoreStrategy)(nil).GenerateRefreshToken), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateRefreshToken", reflect.TypeOf((*MockCoreStrategy)(nil).GenerateRefreshToken), ctx, requester) } // RefreshTokenSignature mocks base method. -func (m *MockCoreStrategy) RefreshTokenSignature(arg0 context.Context, arg1 string) string { +func (m *MockCoreStrategy) RefreshTokenSignature(ctx context.Context, token string) string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RefreshTokenSignature", arg0, arg1) + ret := m.ctrl.Call(m, "RefreshTokenSignature", ctx, token) ret0, _ := ret[0].(string) return ret0 } // RefreshTokenSignature indicates an expected call of RefreshTokenSignature. -func (mr *MockCoreStrategyMockRecorder) RefreshTokenSignature(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockCoreStrategyMockRecorder) RefreshTokenSignature(ctx, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RefreshTokenSignature", reflect.TypeOf((*MockCoreStrategy)(nil).RefreshTokenSignature), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RefreshTokenSignature", reflect.TypeOf((*MockCoreStrategy)(nil).RefreshTokenSignature), ctx, token) } // ValidateAccessToken mocks base method. -func (m *MockCoreStrategy) ValidateAccessToken(arg0 context.Context, arg1 fosite.Requester, arg2 string) error { +func (m *MockCoreStrategy) ValidateAccessToken(ctx context.Context, requester fosite.Requester, token string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateAccessToken", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ValidateAccessToken", ctx, requester, token) ret0, _ := ret[0].(error) return ret0 } // ValidateAccessToken indicates an expected call of ValidateAccessToken. -func (mr *MockCoreStrategyMockRecorder) ValidateAccessToken(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockCoreStrategyMockRecorder) ValidateAccessToken(ctx, requester, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAccessToken", reflect.TypeOf((*MockCoreStrategy)(nil).ValidateAccessToken), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAccessToken", reflect.TypeOf((*MockCoreStrategy)(nil).ValidateAccessToken), ctx, requester, token) } // ValidateAuthorizeCode mocks base method. -func (m *MockCoreStrategy) ValidateAuthorizeCode(arg0 context.Context, arg1 fosite.Requester, arg2 string) error { +func (m *MockCoreStrategy) ValidateAuthorizeCode(ctx context.Context, requester fosite.Requester, token string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateAuthorizeCode", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ValidateAuthorizeCode", ctx, requester, token) ret0, _ := ret[0].(error) return ret0 } // ValidateAuthorizeCode indicates an expected call of ValidateAuthorizeCode. -func (mr *MockCoreStrategyMockRecorder) ValidateAuthorizeCode(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockCoreStrategyMockRecorder) ValidateAuthorizeCode(ctx, requester, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAuthorizeCode", reflect.TypeOf((*MockCoreStrategy)(nil).ValidateAuthorizeCode), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAuthorizeCode", reflect.TypeOf((*MockCoreStrategy)(nil).ValidateAuthorizeCode), ctx, requester, token) } // ValidateRefreshToken mocks base method. -func (m *MockCoreStrategy) ValidateRefreshToken(arg0 context.Context, arg1 fosite.Requester, arg2 string) error { +func (m *MockCoreStrategy) ValidateRefreshToken(ctx context.Context, requester fosite.Requester, token string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateRefreshToken", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ValidateRefreshToken", ctx, requester, token) ret0, _ := ret[0].(error) return ret0 } // ValidateRefreshToken indicates an expected call of ValidateRefreshToken. -func (mr *MockCoreStrategyMockRecorder) ValidateRefreshToken(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockCoreStrategyMockRecorder) ValidateRefreshToken(ctx, requester, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateRefreshToken", reflect.TypeOf((*MockCoreStrategy)(nil).ValidateRefreshToken), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateRefreshToken", reflect.TypeOf((*MockCoreStrategy)(nil).ValidateRefreshToken), ctx, requester, token) } diff --git a/internal/openid_id_token_storage.go b/internal/openid_id_token_storage.go index 2aa736b7c..cc2a4d198 100644 --- a/internal/openid_id_token_storage.go +++ b/internal/openid_id_token_storage.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/openid (interfaces: OpenIDConnectRequestStorage) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/openid_id_token_storage.go github.com/ory/fosite/handler/openid OpenIDConnectRequestStorage +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockOpenIDConnectRequestStorage is a mock of OpenIDConnectRequestStorage interface. type MockOpenIDConnectRequestStorage struct { ctrl *gomock.Controller recorder *MockOpenIDConnectRequestStorageMockRecorder + isgomock struct{} } // MockOpenIDConnectRequestStorageMockRecorder is the mock recorder for MockOpenIDConnectRequestStorage. @@ -39,44 +45,44 @@ func (m *MockOpenIDConnectRequestStorage) EXPECT() *MockOpenIDConnectRequestStor } // CreateOpenIDConnectSession mocks base method. -func (m *MockOpenIDConnectRequestStorage) CreateOpenIDConnectSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +func (m *MockOpenIDConnectRequestStorage) CreateOpenIDConnectSession(ctx context.Context, authorizeCode string, requester fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateOpenIDConnectSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateOpenIDConnectSession", ctx, authorizeCode, requester) ret0, _ := ret[0].(error) return ret0 } // CreateOpenIDConnectSession indicates an expected call of CreateOpenIDConnectSession. -func (mr *MockOpenIDConnectRequestStorageMockRecorder) CreateOpenIDConnectSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockOpenIDConnectRequestStorageMockRecorder) CreateOpenIDConnectSession(ctx, authorizeCode, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOpenIDConnectSession", reflect.TypeOf((*MockOpenIDConnectRequestStorage)(nil).CreateOpenIDConnectSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOpenIDConnectSession", reflect.TypeOf((*MockOpenIDConnectRequestStorage)(nil).CreateOpenIDConnectSession), ctx, authorizeCode, requester) } // DeleteOpenIDConnectSession mocks base method. -func (m *MockOpenIDConnectRequestStorage) DeleteOpenIDConnectSession(arg0 context.Context, arg1 string) error { +func (m *MockOpenIDConnectRequestStorage) DeleteOpenIDConnectSession(ctx context.Context, authorizeCode string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteOpenIDConnectSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteOpenIDConnectSession", ctx, authorizeCode) ret0, _ := ret[0].(error) return ret0 } // DeleteOpenIDConnectSession indicates an expected call of DeleteOpenIDConnectSession. -func (mr *MockOpenIDConnectRequestStorageMockRecorder) DeleteOpenIDConnectSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockOpenIDConnectRequestStorageMockRecorder) DeleteOpenIDConnectSession(ctx, authorizeCode any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOpenIDConnectSession", reflect.TypeOf((*MockOpenIDConnectRequestStorage)(nil).DeleteOpenIDConnectSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOpenIDConnectSession", reflect.TypeOf((*MockOpenIDConnectRequestStorage)(nil).DeleteOpenIDConnectSession), ctx, authorizeCode) } // GetOpenIDConnectSession mocks base method. -func (m *MockOpenIDConnectRequestStorage) GetOpenIDConnectSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) (fosite.Requester, error) { +func (m *MockOpenIDConnectRequestStorage) GetOpenIDConnectSession(ctx context.Context, authorizeCode string, requester fosite.Requester) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetOpenIDConnectSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetOpenIDConnectSession", ctx, authorizeCode, requester) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetOpenIDConnectSession indicates an expected call of GetOpenIDConnectSession. -func (mr *MockOpenIDConnectRequestStorageMockRecorder) GetOpenIDConnectSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockOpenIDConnectRequestStorageMockRecorder) GetOpenIDConnectSession(ctx, authorizeCode, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOpenIDConnectSession", reflect.TypeOf((*MockOpenIDConnectRequestStorage)(nil).GetOpenIDConnectSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOpenIDConnectSession", reflect.TypeOf((*MockOpenIDConnectRequestStorage)(nil).GetOpenIDConnectSession), ctx, authorizeCode, requester) } diff --git a/internal/pkce_storage_strategy.go b/internal/pkce_storage_strategy.go index bdaf4c624..745add3a3 100644 --- a/internal/pkce_storage_strategy.go +++ b/internal/pkce_storage_strategy.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/pkce (interfaces: PKCERequestStorage) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/pkce_storage_strategy.go github.com/ory/fosite/handler/pkce PKCERequestStorage +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockPKCERequestStorage is a mock of PKCERequestStorage interface. type MockPKCERequestStorage struct { ctrl *gomock.Controller recorder *MockPKCERequestStorageMockRecorder + isgomock struct{} } // MockPKCERequestStorageMockRecorder is the mock recorder for MockPKCERequestStorage. @@ -39,44 +45,44 @@ func (m *MockPKCERequestStorage) EXPECT() *MockPKCERequestStorageMockRecorder { } // CreatePKCERequestSession mocks base method. -func (m *MockPKCERequestStorage) CreatePKCERequestSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +func (m *MockPKCERequestStorage) CreatePKCERequestSession(ctx context.Context, signature string, requester fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreatePKCERequestSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreatePKCERequestSession", ctx, signature, requester) ret0, _ := ret[0].(error) return ret0 } // CreatePKCERequestSession indicates an expected call of CreatePKCERequestSession. -func (mr *MockPKCERequestStorageMockRecorder) CreatePKCERequestSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockPKCERequestStorageMockRecorder) CreatePKCERequestSession(ctx, signature, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePKCERequestSession", reflect.TypeOf((*MockPKCERequestStorage)(nil).CreatePKCERequestSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePKCERequestSession", reflect.TypeOf((*MockPKCERequestStorage)(nil).CreatePKCERequestSession), ctx, signature, requester) } // DeletePKCERequestSession mocks base method. -func (m *MockPKCERequestStorage) DeletePKCERequestSession(arg0 context.Context, arg1 string) error { +func (m *MockPKCERequestStorage) DeletePKCERequestSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeletePKCERequestSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeletePKCERequestSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // DeletePKCERequestSession indicates an expected call of DeletePKCERequestSession. -func (mr *MockPKCERequestStorageMockRecorder) DeletePKCERequestSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockPKCERequestStorageMockRecorder) DeletePKCERequestSession(ctx, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePKCERequestSession", reflect.TypeOf((*MockPKCERequestStorage)(nil).DeletePKCERequestSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePKCERequestSession", reflect.TypeOf((*MockPKCERequestStorage)(nil).DeletePKCERequestSession), ctx, signature) } // GetPKCERequestSession mocks base method. -func (m *MockPKCERequestStorage) GetPKCERequestSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockPKCERequestStorage) GetPKCERequestSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPKCERequestSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetPKCERequestSession", ctx, signature, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetPKCERequestSession indicates an expected call of GetPKCERequestSession. -func (mr *MockPKCERequestStorageMockRecorder) GetPKCERequestSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockPKCERequestStorageMockRecorder) GetPKCERequestSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPKCERequestSession", reflect.TypeOf((*MockPKCERequestStorage)(nil).GetPKCERequestSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPKCERequestSession", reflect.TypeOf((*MockPKCERequestStorage)(nil).GetPKCERequestSession), ctx, signature, session) } diff --git a/internal/pushed_authorize_handler.go b/internal/pushed_authorize_handler.go index d871469de..a017f56d9 100644 --- a/internal/pushed_authorize_handler.go +++ b/internal/pushed_authorize_handler.go @@ -7,7 +7,7 @@ import ( "context" "reflect" - "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" ) diff --git a/internal/refresh_token_strategy.go b/internal/refresh_token_strategy.go index 2bafb3c90..d160397c9 100644 --- a/internal/refresh_token_strategy.go +++ b/internal/refresh_token_strategy.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/oauth2 (interfaces: RefreshTokenStrategy) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStrategy +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockRefreshTokenStrategy is a mock of RefreshTokenStrategy interface. type MockRefreshTokenStrategy struct { ctrl *gomock.Controller recorder *MockRefreshTokenStrategyMockRecorder + isgomock struct{} } // MockRefreshTokenStrategyMockRecorder is the mock recorder for MockRefreshTokenStrategy. @@ -39,9 +45,9 @@ func (m *MockRefreshTokenStrategy) EXPECT() *MockRefreshTokenStrategyMockRecorde } // GenerateRefreshToken mocks base method. -func (m *MockRefreshTokenStrategy) GenerateRefreshToken(arg0 context.Context, arg1 fosite.Requester) (string, string, error) { +func (m *MockRefreshTokenStrategy) GenerateRefreshToken(ctx context.Context, requester fosite.Requester) (string, string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GenerateRefreshToken", arg0, arg1) + ret := m.ctrl.Call(m, "GenerateRefreshToken", ctx, requester) ret0, _ := ret[0].(string) ret1, _ := ret[1].(string) ret2, _ := ret[2].(error) @@ -49,35 +55,35 @@ func (m *MockRefreshTokenStrategy) GenerateRefreshToken(arg0 context.Context, ar } // GenerateRefreshToken indicates an expected call of GenerateRefreshToken. -func (mr *MockRefreshTokenStrategyMockRecorder) GenerateRefreshToken(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockRefreshTokenStrategyMockRecorder) GenerateRefreshToken(ctx, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateRefreshToken", reflect.TypeOf((*MockRefreshTokenStrategy)(nil).GenerateRefreshToken), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateRefreshToken", reflect.TypeOf((*MockRefreshTokenStrategy)(nil).GenerateRefreshToken), ctx, requester) } // RefreshTokenSignature mocks base method. -func (m *MockRefreshTokenStrategy) RefreshTokenSignature(arg0 context.Context, arg1 string) string { +func (m *MockRefreshTokenStrategy) RefreshTokenSignature(ctx context.Context, token string) string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RefreshTokenSignature", arg0, arg1) + ret := m.ctrl.Call(m, "RefreshTokenSignature", ctx, token) ret0, _ := ret[0].(string) return ret0 } // RefreshTokenSignature indicates an expected call of RefreshTokenSignature. -func (mr *MockRefreshTokenStrategyMockRecorder) RefreshTokenSignature(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockRefreshTokenStrategyMockRecorder) RefreshTokenSignature(ctx, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RefreshTokenSignature", reflect.TypeOf((*MockRefreshTokenStrategy)(nil).RefreshTokenSignature), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RefreshTokenSignature", reflect.TypeOf((*MockRefreshTokenStrategy)(nil).RefreshTokenSignature), ctx, token) } // ValidateRefreshToken mocks base method. -func (m *MockRefreshTokenStrategy) ValidateRefreshToken(arg0 context.Context, arg1 fosite.Requester, arg2 string) error { +func (m *MockRefreshTokenStrategy) ValidateRefreshToken(ctx context.Context, requester fosite.Requester, token string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateRefreshToken", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ValidateRefreshToken", ctx, requester, token) ret0, _ := ret[0].(error) return ret0 } // ValidateRefreshToken indicates an expected call of ValidateRefreshToken. -func (mr *MockRefreshTokenStrategyMockRecorder) ValidateRefreshToken(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRefreshTokenStrategyMockRecorder) ValidateRefreshToken(ctx, requester, token any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateRefreshToken", reflect.TypeOf((*MockRefreshTokenStrategy)(nil).ValidateRefreshToken), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateRefreshToken", reflect.TypeOf((*MockRefreshTokenStrategy)(nil).ValidateRefreshToken), ctx, requester, token) } diff --git a/internal/request.go b/internal/request.go index 762a43b38..7135980c5 100644 --- a/internal/request.go +++ b/internal/request.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: Requester) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/request.go github.com/ory/fosite Requester +// // Package internal is a generated GoMock package. package internal @@ -12,14 +17,15 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockRequester is a mock of Requester interface. type MockRequester struct { ctrl *gomock.Controller recorder *MockRequesterMockRecorder + isgomock struct{} } // MockRequesterMockRecorder is the mock recorder for MockRequester. @@ -40,15 +46,15 @@ func (m *MockRequester) EXPECT() *MockRequesterMockRecorder { } // AppendRequestedScope mocks base method. -func (m *MockRequester) AppendRequestedScope(arg0 string) { +func (m *MockRequester) AppendRequestedScope(scope string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "AppendRequestedScope", arg0) + m.ctrl.Call(m, "AppendRequestedScope", scope) } // AppendRequestedScope indicates an expected call of AppendRequestedScope. -func (mr *MockRequesterMockRecorder) AppendRequestedScope(arg0 interface{}) *gomock.Call { +func (mr *MockRequesterMockRecorder) AppendRequestedScope(scope any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppendRequestedScope", reflect.TypeOf((*MockRequester)(nil).AppendRequestedScope), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppendRequestedScope", reflect.TypeOf((*MockRequester)(nil).AppendRequestedScope), scope) } // GetClient mocks base method. @@ -178,99 +184,99 @@ func (mr *MockRequesterMockRecorder) GetSession() *gomock.Call { } // GrantAudience mocks base method. -func (m *MockRequester) GrantAudience(arg0 string) { +func (m *MockRequester) GrantAudience(audience string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "GrantAudience", arg0) + m.ctrl.Call(m, "GrantAudience", audience) } // GrantAudience indicates an expected call of GrantAudience. -func (mr *MockRequesterMockRecorder) GrantAudience(arg0 interface{}) *gomock.Call { +func (mr *MockRequesterMockRecorder) GrantAudience(audience any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantAudience", reflect.TypeOf((*MockRequester)(nil).GrantAudience), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantAudience", reflect.TypeOf((*MockRequester)(nil).GrantAudience), audience) } // GrantScope mocks base method. -func (m *MockRequester) GrantScope(arg0 string) { +func (m *MockRequester) GrantScope(scope string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "GrantScope", arg0) + m.ctrl.Call(m, "GrantScope", scope) } // GrantScope indicates an expected call of GrantScope. -func (mr *MockRequesterMockRecorder) GrantScope(arg0 interface{}) *gomock.Call { +func (mr *MockRequesterMockRecorder) GrantScope(scope any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantScope", reflect.TypeOf((*MockRequester)(nil).GrantScope), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantScope", reflect.TypeOf((*MockRequester)(nil).GrantScope), scope) } // Merge mocks base method. -func (m *MockRequester) Merge(arg0 fosite.Requester) { +func (m *MockRequester) Merge(requester fosite.Requester) { m.ctrl.T.Helper() - m.ctrl.Call(m, "Merge", arg0) + m.ctrl.Call(m, "Merge", requester) } // Merge indicates an expected call of Merge. -func (mr *MockRequesterMockRecorder) Merge(arg0 interface{}) *gomock.Call { +func (mr *MockRequesterMockRecorder) Merge(requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Merge", reflect.TypeOf((*MockRequester)(nil).Merge), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Merge", reflect.TypeOf((*MockRequester)(nil).Merge), requester) } // Sanitize mocks base method. -func (m *MockRequester) Sanitize(arg0 []string) fosite.Requester { +func (m *MockRequester) Sanitize(allowedParameters []string) fosite.Requester { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Sanitize", arg0) + ret := m.ctrl.Call(m, "Sanitize", allowedParameters) ret0, _ := ret[0].(fosite.Requester) return ret0 } // Sanitize indicates an expected call of Sanitize. -func (mr *MockRequesterMockRecorder) Sanitize(arg0 interface{}) *gomock.Call { +func (mr *MockRequesterMockRecorder) Sanitize(allowedParameters any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sanitize", reflect.TypeOf((*MockRequester)(nil).Sanitize), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sanitize", reflect.TypeOf((*MockRequester)(nil).Sanitize), allowedParameters) } // SetID mocks base method. -func (m *MockRequester) SetID(arg0 string) { +func (m *MockRequester) SetID(id string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetID", arg0) + m.ctrl.Call(m, "SetID", id) } // SetID indicates an expected call of SetID. -func (mr *MockRequesterMockRecorder) SetID(arg0 interface{}) *gomock.Call { +func (mr *MockRequesterMockRecorder) SetID(id any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetID", reflect.TypeOf((*MockRequester)(nil).SetID), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetID", reflect.TypeOf((*MockRequester)(nil).SetID), id) } // SetRequestedAudience mocks base method. -func (m *MockRequester) SetRequestedAudience(arg0 fosite.Arguments) { +func (m *MockRequester) SetRequestedAudience(audience fosite.Arguments) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetRequestedAudience", arg0) + m.ctrl.Call(m, "SetRequestedAudience", audience) } // SetRequestedAudience indicates an expected call of SetRequestedAudience. -func (mr *MockRequesterMockRecorder) SetRequestedAudience(arg0 interface{}) *gomock.Call { +func (mr *MockRequesterMockRecorder) SetRequestedAudience(audience any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedAudience", reflect.TypeOf((*MockRequester)(nil).SetRequestedAudience), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedAudience", reflect.TypeOf((*MockRequester)(nil).SetRequestedAudience), audience) } // SetRequestedScopes mocks base method. -func (m *MockRequester) SetRequestedScopes(arg0 fosite.Arguments) { +func (m *MockRequester) SetRequestedScopes(scopes fosite.Arguments) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetRequestedScopes", arg0) + m.ctrl.Call(m, "SetRequestedScopes", scopes) } // SetRequestedScopes indicates an expected call of SetRequestedScopes. -func (mr *MockRequesterMockRecorder) SetRequestedScopes(arg0 interface{}) *gomock.Call { +func (mr *MockRequesterMockRecorder) SetRequestedScopes(scopes any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedScopes", reflect.TypeOf((*MockRequester)(nil).SetRequestedScopes), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestedScopes", reflect.TypeOf((*MockRequester)(nil).SetRequestedScopes), scopes) } // SetSession mocks base method. -func (m *MockRequester) SetSession(arg0 fosite.Session) { +func (m *MockRequester) SetSession(session fosite.Session) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSession", arg0) + m.ctrl.Call(m, "SetSession", session) } // SetSession indicates an expected call of SetSession. -func (mr *MockRequesterMockRecorder) SetSession(arg0 interface{}) *gomock.Call { +func (mr *MockRequesterMockRecorder) SetSession(session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSession", reflect.TypeOf((*MockRequester)(nil).SetSession), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSession", reflect.TypeOf((*MockRequester)(nil).SetSession), session) } diff --git a/internal/revoke_handler.go b/internal/revoke_handler.go index 0599be852..e77291086 100644 --- a/internal/revoke_handler.go +++ b/internal/revoke_handler.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: RevocationHandler) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/revoke_handler.go github.com/ory/fosite RevocationHandler +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockRevocationHandler is a mock of RevocationHandler interface. type MockRevocationHandler struct { ctrl *gomock.Controller recorder *MockRevocationHandlerMockRecorder + isgomock struct{} } // MockRevocationHandlerMockRecorder is the mock recorder for MockRevocationHandler. @@ -39,15 +45,15 @@ func (m *MockRevocationHandler) EXPECT() *MockRevocationHandlerMockRecorder { } // RevokeToken mocks base method. -func (m *MockRevocationHandler) RevokeToken(arg0 context.Context, arg1 string, arg2 fosite.TokenType, arg3 fosite.Client) error { +func (m *MockRevocationHandler) RevokeToken(ctx context.Context, token string, tokenType fosite.TokenType, client fosite.Client) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RevokeToken", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "RevokeToken", ctx, token, tokenType, client) ret0, _ := ret[0].(error) return ret0 } // RevokeToken indicates an expected call of RevokeToken. -func (mr *MockRevocationHandlerMockRecorder) RevokeToken(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockRevocationHandlerMockRecorder) RevokeToken(ctx, token, tokenType, client any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevokeToken", reflect.TypeOf((*MockRevocationHandler)(nil).RevokeToken), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevokeToken", reflect.TypeOf((*MockRevocationHandler)(nil).RevokeToken), ctx, token, tokenType, client) } diff --git a/internal/rfc8628_code_strategy.go b/internal/rfc8628_code_strategy.go index a328ac1fa..944a07b99 100644 --- a/internal/rfc8628_code_strategy.go +++ b/internal/rfc8628_code_strategy.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/rfc8628 (interfaces: RFC8628CodeStrategy) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/rfc8628_code_strategy.go github.com/ory/fosite/handler/rfc8628 RFC8628CodeStrategy +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockRFC8628CodeStrategy is a mock of RFC8628CodeStrategy interface. type MockRFC8628CodeStrategy struct { ctrl *gomock.Controller recorder *MockRFC8628CodeStrategyMockRecorder + isgomock struct{} } // MockRFC8628CodeStrategyMockRecorder is the mock recorder for MockRFC8628CodeStrategy. @@ -39,24 +45,24 @@ func (m *MockRFC8628CodeStrategy) EXPECT() *MockRFC8628CodeStrategyMockRecorder } // DeviceCodeSignature mocks base method. -func (m *MockRFC8628CodeStrategy) DeviceCodeSignature(arg0 context.Context, arg1 string) (string, error) { +func (m *MockRFC8628CodeStrategy) DeviceCodeSignature(ctx context.Context, code string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeviceCodeSignature", arg0, arg1) + ret := m.ctrl.Call(m, "DeviceCodeSignature", ctx, code) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // DeviceCodeSignature indicates an expected call of DeviceCodeSignature. -func (mr *MockRFC8628CodeStrategyMockRecorder) DeviceCodeSignature(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockRFC8628CodeStrategyMockRecorder) DeviceCodeSignature(ctx, code any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeviceCodeSignature", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).DeviceCodeSignature), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeviceCodeSignature", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).DeviceCodeSignature), ctx, code) } // GenerateDeviceCode mocks base method. -func (m *MockRFC8628CodeStrategy) GenerateDeviceCode(arg0 context.Context) (string, string, error) { +func (m *MockRFC8628CodeStrategy) GenerateDeviceCode(ctx context.Context) (string, string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GenerateDeviceCode", arg0) + ret := m.ctrl.Call(m, "GenerateDeviceCode", ctx) ret0, _ := ret[0].(string) ret1, _ := ret[1].(string) ret2, _ := ret[2].(error) @@ -64,15 +70,15 @@ func (m *MockRFC8628CodeStrategy) GenerateDeviceCode(arg0 context.Context) (stri } // GenerateDeviceCode indicates an expected call of GenerateDeviceCode. -func (mr *MockRFC8628CodeStrategyMockRecorder) GenerateDeviceCode(arg0 interface{}) *gomock.Call { +func (mr *MockRFC8628CodeStrategyMockRecorder) GenerateDeviceCode(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateDeviceCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).GenerateDeviceCode), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateDeviceCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).GenerateDeviceCode), ctx) } // GenerateUserCode mocks base method. -func (m *MockRFC8628CodeStrategy) GenerateUserCode(arg0 context.Context) (string, string, error) { +func (m *MockRFC8628CodeStrategy) GenerateUserCode(ctx context.Context) (string, string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GenerateUserCode", arg0) + ret := m.ctrl.Call(m, "GenerateUserCode", ctx) ret0, _ := ret[0].(string) ret1, _ := ret[1].(string) ret2, _ := ret[2].(error) @@ -80,65 +86,65 @@ func (m *MockRFC8628CodeStrategy) GenerateUserCode(arg0 context.Context) (string } // GenerateUserCode indicates an expected call of GenerateUserCode. -func (mr *MockRFC8628CodeStrategyMockRecorder) GenerateUserCode(arg0 interface{}) *gomock.Call { +func (mr *MockRFC8628CodeStrategyMockRecorder) GenerateUserCode(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateUserCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).GenerateUserCode), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateUserCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).GenerateUserCode), ctx) } // ShouldRateLimit mocks base method. -func (m *MockRFC8628CodeStrategy) ShouldRateLimit(arg0 context.Context, arg1 string) (bool, error) { +func (m *MockRFC8628CodeStrategy) ShouldRateLimit(ctx context.Context, code string) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ShouldRateLimit", arg0, arg1) + ret := m.ctrl.Call(m, "ShouldRateLimit", ctx, code) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } // ShouldRateLimit indicates an expected call of ShouldRateLimit. -func (mr *MockRFC8628CodeStrategyMockRecorder) ShouldRateLimit(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockRFC8628CodeStrategyMockRecorder) ShouldRateLimit(ctx, code any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldRateLimit", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).ShouldRateLimit), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldRateLimit", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).ShouldRateLimit), ctx, code) } // UserCodeSignature mocks base method. -func (m *MockRFC8628CodeStrategy) UserCodeSignature(arg0 context.Context, arg1 string) (string, error) { +func (m *MockRFC8628CodeStrategy) UserCodeSignature(ctx context.Context, code string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UserCodeSignature", arg0, arg1) + ret := m.ctrl.Call(m, "UserCodeSignature", ctx, code) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // UserCodeSignature indicates an expected call of UserCodeSignature. -func (mr *MockRFC8628CodeStrategyMockRecorder) UserCodeSignature(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockRFC8628CodeStrategyMockRecorder) UserCodeSignature(ctx, code any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserCodeSignature", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).UserCodeSignature), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserCodeSignature", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).UserCodeSignature), ctx, code) } // ValidateDeviceCode mocks base method. -func (m *MockRFC8628CodeStrategy) ValidateDeviceCode(arg0 context.Context, arg1 fosite.Requester, arg2 string) error { +func (m *MockRFC8628CodeStrategy) ValidateDeviceCode(ctx context.Context, r fosite.DeviceRequester, code string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateDeviceCode", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ValidateDeviceCode", ctx, r, code) ret0, _ := ret[0].(error) return ret0 } // ValidateDeviceCode indicates an expected call of ValidateDeviceCode. -func (mr *MockRFC8628CodeStrategyMockRecorder) ValidateDeviceCode(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRFC8628CodeStrategyMockRecorder) ValidateDeviceCode(ctx, r, code any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateDeviceCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).ValidateDeviceCode), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateDeviceCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).ValidateDeviceCode), ctx, r, code) } // ValidateUserCode mocks base method. -func (m *MockRFC8628CodeStrategy) ValidateUserCode(arg0 context.Context, arg1 fosite.Requester, arg2 string) error { +func (m *MockRFC8628CodeStrategy) ValidateUserCode(ctx context.Context, r fosite.DeviceRequester, code string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateUserCode", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ValidateUserCode", ctx, r, code) ret0, _ := ret[0].(error) return ret0 } // ValidateUserCode indicates an expected call of ValidateUserCode. -func (mr *MockRFC8628CodeStrategyMockRecorder) ValidateUserCode(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRFC8628CodeStrategyMockRecorder) ValidateUserCode(ctx, r, code any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateUserCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).ValidateUserCode), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateUserCode", reflect.TypeOf((*MockRFC8628CodeStrategy)(nil).ValidateUserCode), ctx, r, code) } diff --git a/internal/rfc8628_core_storage.go b/internal/rfc8628_core_storage.go index 93340de2d..ab021b950 100644 --- a/internal/rfc8628_core_storage.go +++ b/internal/rfc8628_core_storage.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/handler/rfc8628 (interfaces: RFC8628CoreStorage) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/rfc8628_core_storage.go github.com/ory/fosite/handler/rfc8628 RFC8628CoreStorage +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockRFC8628CoreStorage is a mock of RFC8628CoreStorage interface. type MockRFC8628CoreStorage struct { ctrl *gomock.Controller recorder *MockRFC8628CoreStorageMockRecorder + isgomock struct{} } // MockRFC8628CoreStorageMockRecorder is the mock recorder for MockRFC8628CoreStorage. @@ -39,45 +45,45 @@ func (m *MockRFC8628CoreStorage) EXPECT() *MockRFC8628CoreStorageMockRecorder { } // CreateAccessTokenSession mocks base method. -func (m *MockRFC8628CoreStorage) CreateAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +func (m *MockRFC8628CoreStorage) CreateAccessTokenSession(ctx context.Context, signature string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateAccessTokenSession", ctx, signature, request) ret0, _ := ret[0].(error) return ret0 } // CreateAccessTokenSession indicates an expected call of CreateAccessTokenSession. -func (mr *MockRFC8628CoreStorageMockRecorder) CreateAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRFC8628CoreStorageMockRecorder) CreateAccessTokenSession(ctx, signature, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateAccessTokenSession), ctx, signature, request) } -// CreateDeviceCodeSession mocks base method. -func (m *MockRFC8628CoreStorage) CreateDeviceCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +// CreateDeviceAuthSession mocks base method. +func (m *MockRFC8628CoreStorage) CreateDeviceAuthSession(ctx context.Context, deviceCodeSignature, userCodeSignature string, request fosite.DeviceRequester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateDeviceCodeSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateDeviceAuthSession", ctx, deviceCodeSignature, userCodeSignature, request) ret0, _ := ret[0].(error) return ret0 } -// CreateDeviceCodeSession indicates an expected call of CreateDeviceCodeSession. -func (mr *MockRFC8628CoreStorageMockRecorder) CreateDeviceCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { +// CreateDeviceAuthSession indicates an expected call of CreateDeviceAuthSession. +func (mr *MockRFC8628CoreStorageMockRecorder) CreateDeviceAuthSession(ctx, deviceCodeSignature, userCodeSignature, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDeviceCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateDeviceCodeSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDeviceAuthSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateDeviceAuthSession), ctx, deviceCodeSignature, userCodeSignature, request) } // CreateRefreshTokenSession mocks base method. -func (m *MockRFC8628CoreStorage) CreateRefreshTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { +func (m *MockRFC8628CoreStorage) CreateRefreshTokenSession(ctx context.Context, signature, accessSignature string, request fosite.Requester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateRefreshTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateRefreshTokenSession", ctx, signature, accessSignature, request) ret0, _ := ret[0].(error) return ret0 } // CreateRefreshTokenSession indicates an expected call of CreateRefreshTokenSession. -func (mr *MockRFC8628CoreStorageMockRecorder) CreateRefreshTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRFC8628CoreStorageMockRecorder) CreateRefreshTokenSession(ctx, signature, accessSignature, request any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRefreshTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateRefreshTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRefreshTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateRefreshTokenSession), ctx, signature, accessSignature, request) } // CreateUserCodeSession mocks base method. @@ -89,82 +95,82 @@ func (m *MockRFC8628CoreStorage) CreateUserCodeSession(arg0 context.Context, arg } // CreateUserCodeSession indicates an expected call of CreateUserCodeSession. -func (mr *MockRFC8628CoreStorageMockRecorder) CreateUserCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRFC8628CoreStorageMockRecorder) CreateUserCodeSession(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUserCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateUserCodeSession), arg0, arg1, arg2) } // DeleteAccessTokenSession mocks base method. -func (m *MockRFC8628CoreStorage) DeleteAccessTokenSession(arg0 context.Context, arg1 string) error { +func (m *MockRFC8628CoreStorage) DeleteAccessTokenSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteAccessTokenSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteAccessTokenSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // DeleteAccessTokenSession indicates an expected call of DeleteAccessTokenSession. -func (mr *MockRFC8628CoreStorageMockRecorder) DeleteAccessTokenSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockRFC8628CoreStorageMockRecorder) DeleteAccessTokenSession(ctx, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).DeleteAccessTokenSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).DeleteAccessTokenSession), ctx, signature) } // DeleteRefreshTokenSession mocks base method. -func (m *MockRFC8628CoreStorage) DeleteRefreshTokenSession(arg0 context.Context, arg1 string) error { +func (m *MockRFC8628CoreStorage) DeleteRefreshTokenSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteRefreshTokenSession", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteRefreshTokenSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // DeleteRefreshTokenSession indicates an expected call of DeleteRefreshTokenSession. -func (mr *MockRFC8628CoreStorageMockRecorder) DeleteRefreshTokenSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockRFC8628CoreStorageMockRecorder) DeleteRefreshTokenSession(ctx, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRefreshTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).DeleteRefreshTokenSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRefreshTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).DeleteRefreshTokenSession), ctx, signature) } // GetAccessTokenSession mocks base method. -func (m *MockRFC8628CoreStorage) GetAccessTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockRFC8628CoreStorage) GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAccessTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetAccessTokenSession", ctx, signature, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetAccessTokenSession indicates an expected call of GetAccessTokenSession. -func (mr *MockRFC8628CoreStorageMockRecorder) GetAccessTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRFC8628CoreStorageMockRecorder) GetAccessTokenSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetAccessTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccessTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetAccessTokenSession), ctx, signature, session) } // GetDeviceCodeSession mocks base method. -func (m *MockRFC8628CoreStorage) GetDeviceCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockRFC8628CoreStorage) GetDeviceCodeSession(ctx context.Context, signature string, session fosite.Session) (fosite.DeviceRequester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDeviceCodeSession", arg0, arg1, arg2) - ret0, _ := ret[0].(fosite.Requester) + ret := m.ctrl.Call(m, "GetDeviceCodeSession", ctx, signature, session) + ret0, _ := ret[0].(fosite.DeviceRequester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetDeviceCodeSession indicates an expected call of GetDeviceCodeSession. -func (mr *MockRFC8628CoreStorageMockRecorder) GetDeviceCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRFC8628CoreStorageMockRecorder) GetDeviceCodeSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeviceCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetDeviceCodeSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeviceCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetDeviceCodeSession), ctx, signature, session) } // GetRefreshTokenSession mocks base method. -func (m *MockRFC8628CoreStorage) GetRefreshTokenSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { +func (m *MockRFC8628CoreStorage) GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRefreshTokenSession", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetRefreshTokenSession", ctx, signature, session) ret0, _ := ret[0].(fosite.Requester) ret1, _ := ret[1].(error) return ret0, ret1 } // GetRefreshTokenSession indicates an expected call of GetRefreshTokenSession. -func (mr *MockRFC8628CoreStorageMockRecorder) GetRefreshTokenSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRFC8628CoreStorageMockRecorder) GetRefreshTokenSession(ctx, signature, session any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRefreshTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetRefreshTokenSession), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRefreshTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetRefreshTokenSession), ctx, signature, session) } // GetUserCodeSession mocks base method. @@ -177,23 +183,37 @@ func (m *MockRFC8628CoreStorage) GetUserCodeSession(arg0 context.Context, arg1 s } // GetUserCodeSession indicates an expected call of GetUserCodeSession. -func (mr *MockRFC8628CoreStorageMockRecorder) GetUserCodeSession(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockRFC8628CoreStorageMockRecorder) GetUserCodeSession(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetUserCodeSession), arg0, arg1, arg2) } // InvalidateDeviceCodeSession mocks base method. -func (m *MockRFC8628CoreStorage) InvalidateDeviceCodeSession(arg0 context.Context, arg1 string) error { +func (m *MockRFC8628CoreStorage) InvalidateDeviceCodeSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InvalidateDeviceCodeSession", arg0, arg1) + ret := m.ctrl.Call(m, "InvalidateDeviceCodeSession", ctx, signature) ret0, _ := ret[0].(error) return ret0 } // InvalidateDeviceCodeSession indicates an expected call of InvalidateDeviceCodeSession. -func (mr *MockRFC8628CoreStorageMockRecorder) InvalidateDeviceCodeSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockRFC8628CoreStorageMockRecorder) InvalidateDeviceCodeSession(ctx, signature any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateDeviceCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).InvalidateDeviceCodeSession), ctx, signature) +} + +// RotateRefreshToken mocks base method. +func (m *MockRFC8628CoreStorage) RotateRefreshToken(ctx context.Context, requestID, refreshTokenSignature string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RotateRefreshToken", ctx, requestID, refreshTokenSignature) + ret0, _ := ret[0].(error) + return ret0 +} + +// RotateRefreshToken indicates an expected call of RotateRefreshToken. +func (mr *MockRFC8628CoreStorageMockRecorder) RotateRefreshToken(ctx, requestID, refreshTokenSignature any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateDeviceCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).InvalidateDeviceCodeSession), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RotateRefreshToken", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).RotateRefreshToken), ctx, requestID, refreshTokenSignature) } // InvalidateUserCodeSession mocks base method. @@ -205,7 +225,7 @@ func (m *MockRFC8628CoreStorage) InvalidateUserCodeSession(arg0 context.Context, } // InvalidateUserCodeSession indicates an expected call of InvalidateUserCodeSession. -func (mr *MockRFC8628CoreStorageMockRecorder) InvalidateUserCodeSession(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockRFC8628CoreStorageMockRecorder) InvalidateUserCodeSession(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateUserCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).InvalidateUserCodeSession), arg0, arg1) } diff --git a/internal/rw.go b/internal/rw.go index 3d9545521..674d323d2 100644 --- a/internal/rw.go +++ b/internal/rw.go @@ -9,7 +9,7 @@ package internal import ( "net/http" - "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // Mock of ResponseWriter interface diff --git a/internal/storage.go b/internal/storage.go index 44b199ac5..8a2cf9ce8 100644 --- a/internal/storage.go +++ b/internal/storage.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: Storage) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/storage.go github.com/ory/fosite Storage +// // Package internal is a generated GoMock package. package internal @@ -12,14 +17,15 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockStorage is a mock of Storage interface. type MockStorage struct { ctrl *gomock.Controller recorder *MockStorageMockRecorder + isgomock struct{} } // MockStorageMockRecorder is the mock recorder for MockStorage. @@ -40,44 +46,44 @@ func (m *MockStorage) EXPECT() *MockStorageMockRecorder { } // ClientAssertionJWTValid mocks base method. -func (m *MockStorage) ClientAssertionJWTValid(arg0 context.Context, arg1 string) error { +func (m *MockStorage) ClientAssertionJWTValid(ctx context.Context, jti string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ClientAssertionJWTValid", arg0, arg1) + ret := m.ctrl.Call(m, "ClientAssertionJWTValid", ctx, jti) ret0, _ := ret[0].(error) return ret0 } // ClientAssertionJWTValid indicates an expected call of ClientAssertionJWTValid. -func (mr *MockStorageMockRecorder) ClientAssertionJWTValid(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockStorageMockRecorder) ClientAssertionJWTValid(ctx, jti any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientAssertionJWTValid", reflect.TypeOf((*MockStorage)(nil).ClientAssertionJWTValid), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientAssertionJWTValid", reflect.TypeOf((*MockStorage)(nil).ClientAssertionJWTValid), ctx, jti) } // GetClient mocks base method. -func (m *MockStorage) GetClient(arg0 context.Context, arg1 string) (fosite.Client, error) { +func (m *MockStorage) GetClient(ctx context.Context, id string) (fosite.Client, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetClient", arg0, arg1) + ret := m.ctrl.Call(m, "GetClient", ctx, id) ret0, _ := ret[0].(fosite.Client) ret1, _ := ret[1].(error) return ret0, ret1 } // GetClient indicates an expected call of GetClient. -func (mr *MockStorageMockRecorder) GetClient(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockStorageMockRecorder) GetClient(ctx, id any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClient", reflect.TypeOf((*MockStorage)(nil).GetClient), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClient", reflect.TypeOf((*MockStorage)(nil).GetClient), ctx, id) } // SetClientAssertionJWT mocks base method. -func (m *MockStorage) SetClientAssertionJWT(arg0 context.Context, arg1 string, arg2 time.Time) error { +func (m *MockStorage) SetClientAssertionJWT(ctx context.Context, jti string, exp time.Time) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetClientAssertionJWT", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "SetClientAssertionJWT", ctx, jti, exp) ret0, _ := ret[0].(error) return ret0 } // SetClientAssertionJWT indicates an expected call of SetClientAssertionJWT. -func (mr *MockStorageMockRecorder) SetClientAssertionJWT(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockStorageMockRecorder) SetClientAssertionJWT(ctx, jti, exp any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetClientAssertionJWT", reflect.TypeOf((*MockStorage)(nil).SetClientAssertionJWT), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetClientAssertionJWT", reflect.TypeOf((*MockStorage)(nil).SetClientAssertionJWT), ctx, jti, exp) } diff --git a/internal/token_handler.go b/internal/token_handler.go index 519afa8aa..be25ceb9c 100644 --- a/internal/token_handler.go +++ b/internal/token_handler.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite (interfaces: TokenEndpointHandler) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/token_handler.go github.com/ory/fosite TokenEndpointHandler +// // Package internal is a generated GoMock package. package internal @@ -11,14 +16,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" fosite "github.com/ory/fosite" + gomock "go.uber.org/mock/gomock" ) // MockTokenEndpointHandler is a mock of TokenEndpointHandler interface. type MockTokenEndpointHandler struct { ctrl *gomock.Controller recorder *MockTokenEndpointHandlerMockRecorder + isgomock struct{} } // MockTokenEndpointHandlerMockRecorder is the mock recorder for MockTokenEndpointHandler. @@ -39,57 +45,57 @@ func (m *MockTokenEndpointHandler) EXPECT() *MockTokenEndpointHandlerMockRecorde } // CanHandleTokenEndpointRequest mocks base method. -func (m *MockTokenEndpointHandler) CanHandleTokenEndpointRequest(arg0 context.Context, arg1 fosite.AccessRequester) bool { +func (m *MockTokenEndpointHandler) CanHandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) bool { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CanHandleTokenEndpointRequest", arg0, arg1) + ret := m.ctrl.Call(m, "CanHandleTokenEndpointRequest", ctx, requester) ret0, _ := ret[0].(bool) return ret0 } // CanHandleTokenEndpointRequest indicates an expected call of CanHandleTokenEndpointRequest. -func (mr *MockTokenEndpointHandlerMockRecorder) CanHandleTokenEndpointRequest(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockTokenEndpointHandlerMockRecorder) CanHandleTokenEndpointRequest(ctx, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanHandleTokenEndpointRequest", reflect.TypeOf((*MockTokenEndpointHandler)(nil).CanHandleTokenEndpointRequest), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanHandleTokenEndpointRequest", reflect.TypeOf((*MockTokenEndpointHandler)(nil).CanHandleTokenEndpointRequest), ctx, requester) } // CanSkipClientAuth mocks base method. -func (m *MockTokenEndpointHandler) CanSkipClientAuth(arg0 context.Context, arg1 fosite.AccessRequester) bool { +func (m *MockTokenEndpointHandler) CanSkipClientAuth(ctx context.Context, requester fosite.AccessRequester) bool { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CanSkipClientAuth", arg0, arg1) + ret := m.ctrl.Call(m, "CanSkipClientAuth", ctx, requester) ret0, _ := ret[0].(bool) return ret0 } // CanSkipClientAuth indicates an expected call of CanSkipClientAuth. -func (mr *MockTokenEndpointHandlerMockRecorder) CanSkipClientAuth(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockTokenEndpointHandlerMockRecorder) CanSkipClientAuth(ctx, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanSkipClientAuth", reflect.TypeOf((*MockTokenEndpointHandler)(nil).CanSkipClientAuth), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanSkipClientAuth", reflect.TypeOf((*MockTokenEndpointHandler)(nil).CanSkipClientAuth), ctx, requester) } // HandleTokenEndpointRequest mocks base method. -func (m *MockTokenEndpointHandler) HandleTokenEndpointRequest(arg0 context.Context, arg1 fosite.AccessRequester) error { +func (m *MockTokenEndpointHandler) HandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HandleTokenEndpointRequest", arg0, arg1) + ret := m.ctrl.Call(m, "HandleTokenEndpointRequest", ctx, requester) ret0, _ := ret[0].(error) return ret0 } // HandleTokenEndpointRequest indicates an expected call of HandleTokenEndpointRequest. -func (mr *MockTokenEndpointHandlerMockRecorder) HandleTokenEndpointRequest(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockTokenEndpointHandlerMockRecorder) HandleTokenEndpointRequest(ctx, requester any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleTokenEndpointRequest", reflect.TypeOf((*MockTokenEndpointHandler)(nil).HandleTokenEndpointRequest), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleTokenEndpointRequest", reflect.TypeOf((*MockTokenEndpointHandler)(nil).HandleTokenEndpointRequest), ctx, requester) } // PopulateTokenEndpointResponse mocks base method. -func (m *MockTokenEndpointHandler) PopulateTokenEndpointResponse(arg0 context.Context, arg1 fosite.AccessRequester, arg2 fosite.AccessResponder) error { +func (m *MockTokenEndpointHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PopulateTokenEndpointResponse", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "PopulateTokenEndpointResponse", ctx, requester, responder) ret0, _ := ret[0].(error) return ret0 } // PopulateTokenEndpointResponse indicates an expected call of PopulateTokenEndpointResponse. -func (mr *MockTokenEndpointHandlerMockRecorder) PopulateTokenEndpointResponse(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockTokenEndpointHandlerMockRecorder) PopulateTokenEndpointResponse(ctx, requester, responder any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PopulateTokenEndpointResponse", reflect.TypeOf((*MockTokenEndpointHandler)(nil).PopulateTokenEndpointResponse), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PopulateTokenEndpointResponse", reflect.TypeOf((*MockTokenEndpointHandler)(nil).PopulateTokenEndpointResponse), ctx, requester, responder) } diff --git a/internal/transactional.go b/internal/transactional.go index d98d63ab7..4bcf74991 100644 --- a/internal/transactional.go +++ b/internal/transactional.go @@ -3,6 +3,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ory/fosite/storage (interfaces: Transactional) +// +// Generated by this command: +// +// mockgen -package internal -destination internal/transactional.go github.com/ory/fosite/storage Transactional +// // Package internal is a generated GoMock package. package internal @@ -11,13 +16,14 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockTransactional is a mock of Transactional interface. type MockTransactional struct { ctrl *gomock.Controller recorder *MockTransactionalMockRecorder + isgomock struct{} } // MockTransactionalMockRecorder is the mock recorder for MockTransactional. @@ -38,44 +44,44 @@ func (m *MockTransactional) EXPECT() *MockTransactionalMockRecorder { } // BeginTX mocks base method. -func (m *MockTransactional) BeginTX(arg0 context.Context) (context.Context, error) { +func (m *MockTransactional) BeginTX(ctx context.Context) (context.Context, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BeginTX", arg0) + ret := m.ctrl.Call(m, "BeginTX", ctx) ret0, _ := ret[0].(context.Context) ret1, _ := ret[1].(error) return ret0, ret1 } // BeginTX indicates an expected call of BeginTX. -func (mr *MockTransactionalMockRecorder) BeginTX(arg0 interface{}) *gomock.Call { +func (mr *MockTransactionalMockRecorder) BeginTX(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginTX", reflect.TypeOf((*MockTransactional)(nil).BeginTX), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginTX", reflect.TypeOf((*MockTransactional)(nil).BeginTX), ctx) } // Commit mocks base method. -func (m *MockTransactional) Commit(arg0 context.Context) error { +func (m *MockTransactional) Commit(ctx context.Context) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Commit", arg0) + ret := m.ctrl.Call(m, "Commit", ctx) ret0, _ := ret[0].(error) return ret0 } // Commit indicates an expected call of Commit. -func (mr *MockTransactionalMockRecorder) Commit(arg0 interface{}) *gomock.Call { +func (mr *MockTransactionalMockRecorder) Commit(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Commit", reflect.TypeOf((*MockTransactional)(nil).Commit), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Commit", reflect.TypeOf((*MockTransactional)(nil).Commit), ctx) } // Rollback mocks base method. -func (m *MockTransactional) Rollback(arg0 context.Context) error { +func (m *MockTransactional) Rollback(ctx context.Context) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Rollback", arg0) + ret := m.ctrl.Call(m, "Rollback", ctx) ret0, _ := ret[0].(error) return ret0 } // Rollback indicates an expected call of Rollback. -func (mr *MockTransactionalMockRecorder) Rollback(arg0 interface{}) *gomock.Call { +func (mr *MockTransactionalMockRecorder) Rollback(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rollback", reflect.TypeOf((*MockTransactional)(nil).Rollback), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rollback", reflect.TypeOf((*MockTransactional)(nil).Rollback), ctx) } diff --git a/introspect_test.go b/introspect_test.go index a6b9787fe..f2a4669ef 100644 --- a/introspect_test.go +++ b/introspect_test.go @@ -9,9 +9,9 @@ import ( "net/http" "testing" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" "github.com/ory/fosite/compose" diff --git a/introspection_request_handler_test.go b/introspection_request_handler_test.go index d589b61e0..3ab6fc8b6 100644 --- a/introspection_request_handler_test.go +++ b/introspection_request_handler_test.go @@ -10,10 +10,10 @@ import ( "net/url" "testing" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" "github.com/ory/fosite" . "github.com/ory/fosite" diff --git a/introspection_response_writer_test.go b/introspection_response_writer_test.go index a7754486f..d512a54b9 100644 --- a/introspection_response_writer_test.go +++ b/introspection_response_writer_test.go @@ -13,10 +13,10 @@ import ( "github.com/ory/x/errorsx" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/pushed_authorize_request_handler_test.go b/pushed_authorize_request_handler_test.go index 41dd0b263..7898cb4f1 100644 --- a/pushed_authorize_request_handler_test.go +++ b/pushed_authorize_request_handler_test.go @@ -10,9 +10,9 @@ import ( "runtime/debug" "testing" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/pushed_authorize_response_writer_test.go b/pushed_authorize_response_writer_test.go index 00c9d8fb6..e7a9269f3 100644 --- a/pushed_authorize_response_writer_test.go +++ b/pushed_authorize_response_writer_test.go @@ -7,9 +7,9 @@ import ( "context" "testing" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" . "github.com/ory/fosite/internal" diff --git a/revoke_handler_test.go b/revoke_handler_test.go index 42a8269fd..97f9063ce 100644 --- a/revoke_handler_test.go +++ b/revoke_handler_test.go @@ -11,9 +11,9 @@ import ( "net/url" "testing" - "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" + gomock "go.uber.org/mock/gomock" . "github.com/ory/fosite" "github.com/ory/fosite/internal" diff --git a/tools.go b/tools.go index 8d529f085..12c3ef948 100644 --- a/tools.go +++ b/tools.go @@ -7,8 +7,8 @@ package fosite import ( - _ "github.com/golang/mock/mockgen" _ "github.com/mattn/goveralls" + _ "go.uber.org/mock/mockgen" _ "github.com/ory/go-acc" ) From 57bd5455d968eddfd629e797b2350f5c5c86bd7f Mon Sep 17 00:00:00 2001 From: Nikos Date: Wed, 16 Oct 2024 12:38:48 +0300 Subject: [PATCH 23/36] refactor: revert oauth handler changes --- compose/compose.go | 3 +- compose/compose_oauth2.go | 37 +- compose/compose_openid.go | 6 +- compose/compose_rfc8628.go | 24 +- fosite_test.go | 10 +- handler/oauth2/flow_authorize_code_auth.go | 37 +- .../oauth2/flow_authorize_code_auth_test.go | 10 +- handler/oauth2/flow_authorize_code_token.go | 150 ++--- .../oauth2/flow_authorize_code_token_test.go | 518 +++++++----------- handler/oauth2/flow_generic_code_token.go | 267 --------- handler/openid/flow_hybrid.go | 8 +- handler/openid/flow_hybrid_test.go | 10 +- handler/openid/validator.go | 5 +- handler/openid/validator_test.go | 7 +- handler/rfc8628/token_handler.go | 263 +++++++-- handler/rfc8628/token_handler_test.go | 115 ++-- ...rize_code_grant_public_client_pkce_test.go | 2 +- ...authorize_code_grant_public_client_test.go | 2 +- integration/authorize_code_grant_test.go | 4 +- .../pushed_authorize_code_grant_test.go | 2 +- 20 files changed, 615 insertions(+), 865 deletions(-) delete mode 100644 handler/oauth2/flow_generic_code_token.go diff --git a/compose/compose.go b/compose/compose.go index 632186ee2..9467d054c 100644 --- a/compose/compose.go +++ b/compose/compose.go @@ -75,8 +75,7 @@ func ComposeAllEnabled(config *fosite.Config, storage interface{}, key interface OpenIDConnectTokenStrategy: NewOpenIDConnectStrategy(keyGetter, config), Signer: &jwt.DefaultSigner{GetPrivateKey: keyGetter}, }, - OAuth2AuthorizeExplicitAuthFactory, - Oauth2AuthorizeExplicitTokenFactory, + OAuth2AuthorizeExplicitFactory, OAuth2AuthorizeImplicitFactory, OAuth2ClientCredentialsGrantFactory, OAuth2RefreshTokenGrantFactory, diff --git a/compose/compose_oauth2.go b/compose/compose_oauth2.go index e1afc7533..c3f01073e 100644 --- a/compose/compose_oauth2.go +++ b/compose/compose_oauth2.go @@ -9,35 +9,16 @@ import ( "github.com/ory/fosite/token/jwt" ) -// OAuth2AuthorizeExplicitAuthFactory creates an OAuth2 authorize code grant ("authorize explicit flow") handler and registers +// OAuth2AuthorizeExplicitFactory creates an OAuth2 authorize code grant ("authorize explicit flow") handler and registers // an access token, refresh token and authorize code validator. -func OAuth2AuthorizeExplicitAuthFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} { - return &oauth2.AuthorizeExplicitGrantAuthHandler{ - AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy), - AuthorizeCodeStorage: storage.(oauth2.AuthorizeCodeStorage), - Config: config, - } -} - -// Oauth2AuthorizeExplicitTokenFactory creates an OAuth2 authorize code grant ("authorize explicit flow") token handler and registers -// an access token, refresh token and authorize code validator. -func Oauth2AuthorizeExplicitTokenFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} { - return &oauth2.AuthorizeExplicitTokenEndpointHandler{ - GenericCodeTokenEndpointHandler: oauth2.GenericCodeTokenEndpointHandler{ - AccessRequestValidator: &oauth2.AuthorizeExplicitGrantAccessRequestValidator{}, - CodeHandler: &oauth2.AuthorizeCodeHandler{ - AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy), - }, - SessionHandler: &oauth2.AuthorizeExplicitGrantSessionHandler{ - AuthorizeCodeStorage: storage.(oauth2.AuthorizeCodeStorage), - }, - - AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), - RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), - CoreStorage: storage.(oauth2.CoreStorage), - TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage), - Config: config, - }, +func OAuth2AuthorizeExplicitFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} { + return &oauth2.AuthorizeExplicitGrantHandler{ + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), + AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy), + CoreStorage: storage.(oauth2.CoreStorage), + TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage), + Config: config, } } diff --git a/compose/compose_openid.go b/compose/compose_openid.go index 4e05a6c73..d7bc0ca79 100644 --- a/compose/compose_openid.go +++ b/compose/compose_openid.go @@ -60,9 +60,11 @@ func OpenIDConnectImplicitFactory(config fosite.Configurator, storage interface{ // **Important note:** You must add this handler *after* you have added an OAuth2 authorize code handler! func OpenIDConnectHybridFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} { return &openid.OpenIDConnectHybridHandler{ - AuthorizeExplicitGrantAuthHandler: &oauth2.AuthorizeExplicitGrantAuthHandler{ + AuthorizeExplicitGrantHandler: &oauth2.AuthorizeExplicitGrantHandler{ + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy), - AuthorizeCodeStorage: storage.(oauth2.AuthorizeCodeStorage), + CoreStorage: storage.(oauth2.CoreStorage), Config: config, }, Config: config, diff --git a/compose/compose_rfc8628.go b/compose/compose_rfc8628.go index 64ccc1e4c..428ad3a6f 100644 --- a/compose/compose_rfc8628.go +++ b/compose/compose_rfc8628.go @@ -25,21 +25,13 @@ func RFC8628DeviceFactory(config fosite.Configurator, storage interface{}, strat // 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{ - AccessRequestValidator: &rfc8628.DeviceAccessRequestValidator{}, - CodeHandler: &rfc8628.DeviceCodeHandler{ - DeviceRateLimitStrategy: strategy.(rfc8628.DeviceRateLimitStrategy), - DeviceCodeStrategy: strategy.(rfc8628.DeviceCodeStrategy), - }, - SessionHandler: &rfc8628.DeviceSessionHandler{ - DeviceCodeStorage: storage.(rfc8628.DeviceCodeStorage), - }, - - AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), - RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), - CoreStorage: storage.(oauth2.CoreStorage), - TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage), - Config: config, - }, + DeviceRateLimitStrategy: strategy.(rfc8628.DeviceRateLimitStrategy), + DeviceCodeStrategy: strategy.(rfc8628.DeviceCodeStrategy), + UserCodeStrategy: strategy.(rfc8628.UserCodeStrategy), + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), + CoreStorage: storage.(rfc8628.RFC8628CoreStorage), + TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage), + Config: config, } } diff --git a/fosite_test.go b/fosite_test.go index ded80b2c1..2c86b498a 100644 --- a/fosite_test.go +++ b/fosite_test.go @@ -16,23 +16,23 @@ import ( ) func TestAuthorizeEndpointHandlers(t *testing.T) { - h := &oauth2.AuthorizeExplicitGrantAuthHandler{} + h := &oauth2.AuthorizeExplicitGrantHandler{} hs := AuthorizeEndpointHandlers{} hs.Append(h) hs.Append(h) - hs.Append(&oauth2.AuthorizeExplicitGrantAuthHandler{}) + hs.Append(&oauth2.AuthorizeExplicitGrantHandler{}) assert.Len(t, hs, 1) assert.Equal(t, hs[0], h) } func TestTokenEndpointHandlers(t *testing.T) { - h := &oauth2.GenericCodeTokenEndpointHandler{} + h := &oauth2.AuthorizeExplicitGrantHandler{} hs := TokenEndpointHandlers{} hs.Append(h) hs.Append(h) // do some crazy type things and make sure dupe detection works - var f interface{} = &oauth2.GenericCodeTokenEndpointHandler{} - hs.Append(&oauth2.GenericCodeTokenEndpointHandler{}) + var f interface{} = &oauth2.AuthorizeExplicitGrantHandler{} + hs.Append(&oauth2.AuthorizeExplicitGrantHandler{}) hs.Append(f.(TokenEndpointHandler)) require.Len(t, hs, 1) assert.Equal(t, hs[0], h) diff --git a/handler/oauth2/flow_authorize_code_auth.go b/handler/oauth2/flow_authorize_code_auth.go index ac70e883b..0b03c8a78 100644 --- a/handler/oauth2/flow_authorize_code_auth.go +++ b/handler/oauth2/flow_authorize_code_auth.go @@ -14,39 +14,50 @@ import ( "github.com/ory/fosite" ) -var _ fosite.AuthorizeEndpointHandler = (*AuthorizeExplicitGrantAuthHandler)(nil) +var _ fosite.AuthorizeEndpointHandler = (*AuthorizeExplicitGrantHandler)(nil) +var _ fosite.TokenEndpointHandler = (*AuthorizeExplicitGrantHandler)(nil) -// AuthorizeExplicitGrantAuthHandler is a response handler for the Authorize Code grant using the explicit grant type +// AuthorizeExplicitGrantHandler is a response handler for the Authorize Code grant using the explicit grant type // as defined in https://tools.ietf.org/html/rfc6749#section-4.1 -type AuthorizeExplicitGrantAuthHandler struct { - AuthorizeCodeStrategy AuthorizeCodeStrategy - AuthorizeCodeStorage AuthorizeCodeStorage - - Config interface { +type AuthorizeExplicitGrantHandler struct { + AccessTokenStrategy AccessTokenStrategy + RefreshTokenStrategy RefreshTokenStrategy + AuthorizeCodeStrategy AuthorizeCodeStrategy + CoreStorage CoreStorage + TokenRevocationStorage TokenRevocationStorage + Config interface { fosite.AuthorizeCodeLifespanProvider + fosite.AccessTokenLifespanProvider + fosite.RefreshTokenLifespanProvider fosite.ScopeStrategyProvider fosite.AudienceStrategyProvider fosite.RedirectSecureCheckerProvider + fosite.RefreshTokenScopesProvider fosite.OmitRedirectScopeParamProvider fosite.SanitationAllowedProvider } } -func (c *AuthorizeExplicitGrantAuthHandler) secureChecker(ctx context.Context) func(context.Context, *url.URL) bool { +func (c *AuthorizeExplicitGrantHandler) secureChecker(ctx context.Context) func(context.Context, *url.URL) bool { if c.Config.GetRedirectSecureChecker(ctx) == nil { return fosite.IsRedirectURISecure } return c.Config.GetRedirectSecureChecker(ctx) } -func (c *AuthorizeExplicitGrantAuthHandler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { - // This allows to define multiple response types, for example OpenID Connect `id_token` +func (c *AuthorizeExplicitGrantHandler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { + // This let's us define multiple response types, for example open id connect's id_token if !ar.GetResponseTypes().ExactOne("code") { return nil } ar.SetDefaultResponseMode(fosite.ResponseModeQuery) + // Disabled because this is already handled at the authorize_request_handler + // if !ar.GetClient().GetResponseTypes().Has("code") { + // return errorsx.WithStack(fosite.ErrInvalidGrant) + // } + if !c.secureChecker(ctx)(ctx, ar.GetRedirectURI()) { return errorsx.WithStack(fosite.ErrInvalidRequest.WithHint("Redirect URL is using an insecure protocol, http is only allowed for hosts with suffix 'localhost', for example: http://myapp.localhost/.")) } @@ -65,14 +76,14 @@ func (c *AuthorizeExplicitGrantAuthHandler) HandleAuthorizeEndpointRequest(ctx c return c.IssueAuthorizeCode(ctx, ar, resp) } -func (c *AuthorizeExplicitGrantAuthHandler) IssueAuthorizeCode(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { +func (c *AuthorizeExplicitGrantHandler) IssueAuthorizeCode(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { code, signature, err := c.AuthorizeCodeStrategy.GenerateAuthorizeCode(ctx, ar) if err != nil { return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } ar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().UTC().Add(c.Config.GetAuthorizeCodeLifespan(ctx))) - if err = c.AuthorizeCodeStorage.CreateAuthorizeCodeSession(ctx, signature, ar.Sanitize(c.GetSanitationWhiteList(ctx))); err != nil { + if err := c.CoreStorage.CreateAuthorizeCodeSession(ctx, signature, ar.Sanitize(c.GetSanitationWhiteList(ctx))); err != nil { return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } @@ -86,7 +97,7 @@ func (c *AuthorizeExplicitGrantAuthHandler) IssueAuthorizeCode(ctx context.Conte return nil } -func (c *AuthorizeExplicitGrantAuthHandler) GetSanitationWhiteList(ctx context.Context) []string { +func (c *AuthorizeExplicitGrantHandler) GetSanitationWhiteList(ctx context.Context) []string { if allowedList := c.Config.GetSanitationWhiteList(ctx); len(allowedList) > 0 { return allowedList } diff --git a/handler/oauth2/flow_authorize_code_auth_test.go b/handler/oauth2/flow_authorize_code_auth_test.go index 027aa4e41..f915fefbd 100644 --- a/handler/oauth2/flow_authorize_code_auth_test.go +++ b/handler/oauth2/flow_authorize_code_auth_test.go @@ -28,16 +28,16 @@ func TestAuthorizeCode_HandleAuthorizeEndpointRequest(t *testing.T) { } { t.Run("strategy="+k, func(t *testing.T) { store := storage.NewMemoryStore() - handler := AuthorizeExplicitGrantAuthHandler{ + handler := AuthorizeExplicitGrantHandler{ + CoreStorage: store, AuthorizeCodeStrategy: strategy, - AuthorizeCodeStorage: store, Config: &fosite.Config{ AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, ScopeStrategy: fosite.HierarchicScopeStrategy, }, } for _, c := range []struct { - handler AuthorizeExplicitGrantAuthHandler + handler AuthorizeExplicitGrantHandler areq *fosite.AuthorizeRequest description string expectErr error @@ -122,9 +122,9 @@ func TestAuthorizeCode_HandleAuthorizeEndpointRequest(t *testing.T) { }, }, { - handler: AuthorizeExplicitGrantAuthHandler{ + handler: AuthorizeExplicitGrantHandler{ + CoreStorage: store, AuthorizeCodeStrategy: strategy, - AuthorizeCodeStorage: store, Config: &fosite.Config{ ScopeStrategy: fosite.HierarchicScopeStrategy, AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, diff --git a/handler/oauth2/flow_authorize_code_token.go b/handler/oauth2/flow_authorize_code_token.go index abecc0e3b..3b808aabc 100644 --- a/handler/oauth2/flow_authorize_code_token.go +++ b/handler/oauth2/flow_authorize_code_token.go @@ -7,94 +7,113 @@ import ( "context" "time" - "github.com/pkg/errors" + "github.com/ory/x/errorsx" "github.com/ory/fosite/storage" - "github.com/ory/x/errorsx" + + "github.com/pkg/errors" "github.com/ory/fosite" ) -type AuthorizeCodeHandler struct { - AuthorizeCodeStrategy AuthorizeCodeStrategy -} - -func (c AuthorizeCodeHandler) Code(ctx context.Context, requester fosite.AccessRequester) (string, string, error) { - code := requester.GetRequestForm().Get("code") - signature := c.AuthorizeCodeStrategy.AuthorizeCodeSignature(ctx, code) - return code, signature, nil -} - -func (c AuthorizeCodeHandler) ValidateCode(ctx context.Context, requester fosite.Requester, code string) error { - return nil -} - -func (c AuthorizeCodeHandler) ValidateCodeSession(ctx context.Context, requester fosite.Requester, code string) error { - return c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, requester, code) -} - -type AuthorizeExplicitGrantSessionHandler struct { - AuthorizeCodeStorage AuthorizeCodeStorage -} +// HandleTokenEndpointRequest implements +// * https://tools.ietf.org/html/rfc6749#section-4.1.3 (everything) +func (c *AuthorizeExplicitGrantHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error { + if !c.CanHandleTokenEndpointRequest(ctx, request) { + return errorsx.WithStack(errorsx.WithStack(fosite.ErrUnknownRequest)) + } -func (s AuthorizeExplicitGrantSessionHandler) Session(ctx context.Context, requester fosite.AccessRequester, codeSignature string) (fosite.Requester, error) { - req, err := s.AuthorizeCodeStorage.GetAuthorizeCodeSession(ctx, codeSignature, requester.GetSession()) + if !request.GetClient().GetGrantTypes().Has("authorization_code") { + return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"authorization_code\".")) + } - if err != nil && errors.Is(err, fosite.ErrInvalidatedAuthorizeCode) { - if req != nil { - return req, err + code := request.GetRequestForm().Get("code") + signature := c.AuthorizeCodeStrategy.AuthorizeCodeSignature(ctx, code) + authorizeRequest, err := c.CoreStorage.GetAuthorizeCodeSession(ctx, signature, request.GetSession()) + if errors.Is(err, fosite.ErrInvalidatedAuthorizeCode) { + if authorizeRequest == nil { + return fosite.ErrServerError. + WithHint("Misconfigured code lead to an error that prohibited the OAuth 2.0 Framework from processing this request."). + WithDebug("GetAuthorizeCodeSession must return a value for \"fosite.Requester\" when returning \"ErrInvalidatedAuthorizeCode\".") } - return req, fosite.ErrServerError. - WithHint("Misconfigured code lead to an error that prohibited the OAuth 2.0 Framework from processing this request."). - WithDebug("\"GetAuthorizeCodeSession\" must return a value for \"fosite.Requester\" when returning \"ErrInvalidatedAuthorizeCode\".") - } - - if err != nil && errors.Is(err, fosite.ErrNotFound) { - return nil, errorsx.WithStack(fosite.ErrInvalidGrant.WithWrap(err).WithDebug(err.Error())) + // If an authorize code is used twice, we revoke all refresh and access tokens associated with this request. + reqID := authorizeRequest.GetID() + hint := "The authorization code has already been used." + debug := "" + if revErr := c.TokenRevocationStorage.RevokeAccessToken(ctx, reqID); revErr != nil { + hint += " Additionally, an error occurred during processing the access token revocation." + debug += "Revocation of access_token lead to error " + revErr.Error() + "." + } + if revErr := c.TokenRevocationStorage.RevokeRefreshToken(ctx, reqID); revErr != nil { + hint += " Additionally, an error occurred during processing the refresh token revocation." + debug += "Revocation of refresh_token lead to error " + revErr.Error() + "." + } + return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint(hint).WithDebug(debug)) + } else if err != nil && errors.Is(err, fosite.ErrNotFound) { + return errorsx.WithStack(fosite.ErrInvalidGrant.WithWrap(err).WithDebug(err.Error())) + } else if err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } - if err != nil { - return nil, errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + // The authorization server MUST verify that the authorization code is valid + // This needs to happen after store retrieval for the session to be hydrated properly + if err := c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, request, code); err != nil { + return errorsx.WithStack(fosite.ErrInvalidGrant.WithWrap(err).WithDebug(err.Error())) } - return req, err -} + // Override scopes + request.SetRequestedScopes(authorizeRequest.GetRequestedScopes()) -func (s AuthorizeExplicitGrantSessionHandler) InvalidateSession(ctx context.Context, codeSignature string) error { - return s.AuthorizeCodeStorage.InvalidateAuthorizeCodeSession(ctx, codeSignature) -} - -type AuthorizeExplicitGrantAccessRequestValidator struct{} + // Override audiences + request.SetRequestedAudience(authorizeRequest.GetRequestedAudience()) -func (v AuthorizeExplicitGrantAccessRequestValidator) CanHandleRequest(requester fosite.AccessRequester) bool { - return requester.GetGrantTypes().ExactOne("authorization_code") -} + // The authorization server MUST ensure that the authorization code was issued to the authenticated + // confidential client, or if the client is public, ensure that the + // code was issued to "client_id" in the request, + if authorizeRequest.GetClient().GetID() != request.GetClient().GetID() { + return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the one from the authorize request.")) + } -func (v AuthorizeExplicitGrantAccessRequestValidator) ValidateGrantTypes(requester fosite.AccessRequester) error { - if !requester.GetClient().GetGrantTypes().Has("authorization_code") { - return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"authorization_code\".")) + // ensure that the "redirect_uri" parameter is present if the + // "redirect_uri" parameter was included in the initial authorization + // request as described in Section 4.1.1, and if included ensure that + // their values are identical. + forcedRedirectURI := authorizeRequest.GetRequestForm().Get("redirect_uri") + if forcedRedirectURI != "" && forcedRedirectURI != request.GetRequestForm().Get("redirect_uri") { + return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The \"redirect_uri\" from this request does not match the one from the authorize request.")) } - return nil -} + // Checking of POST client_id skipped, because: + // If the client type is confidential or the client was issued client + // credentials (or assigned other authentication requirements), the + // client MUST authenticate with the authorization server as described + // in Section 3.2.1. + request.SetSession(authorizeRequest.GetSession()) + request.SetID(authorizeRequest.GetID()) -func (v AuthorizeExplicitGrantAccessRequestValidator) GetGrantType(requester fosite.AccessRequester) fosite.GrantType { - return fosite.GrantTypeAuthorizationCode -} + atLifespan := fosite.GetEffectiveLifespan(request.GetClient(), fosite.GrantTypeAuthorizationCode, fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) + request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(atLifespan).Round(time.Second)) -func (v AuthorizeExplicitGrantAccessRequestValidator) ValidateRedirectURI(accessRequester fosite.AccessRequester, authorizeRequester fosite.Requester) error { - forcedRedirectURI := authorizeRequester.GetRequestForm().Get("redirect_uri") - requestedRedirectURI := accessRequester.GetRequestForm().Get("redirect_uri") - if forcedRedirectURI != "" && forcedRedirectURI != requestedRedirectURI { - return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The \"redirect_uri\" from this request does not match the one from the authorize request.")) + rtLifespan := fosite.GetEffectiveLifespan(request.GetClient(), fosite.GrantTypeAuthorizationCode, fosite.RefreshToken, c.Config.GetRefreshTokenLifespan(ctx)) + if rtLifespan > -1 { + request.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(rtLifespan).Round(time.Second)) } return nil } -type AuthorizeExplicitTokenEndpointHandler struct { - GenericCodeTokenEndpointHandler +func canIssueRefreshToken(ctx context.Context, c *AuthorizeExplicitGrantHandler, request fosite.Requester) bool { + scope := c.Config.GetRefreshTokenScopes(ctx) + // Require one of the refresh token scopes, if set. + if len(scope) > 0 && !request.GetGrantedScopes().HasOneOf(scope...) { + return false + } + // Do not issue a refresh token to clients that cannot use the refresh token grant type. + if !request.GetClient().GetGrantTypes().Has("refresh_token") { + return false + } + return true } func (c *AuthorizeExplicitGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) (err error) { @@ -180,10 +199,3 @@ func (c *AuthorizeExplicitGrantHandler) CanHandleTokenEndpointRequest(ctx contex // Value MUST be set to "authorization_code" return requester.GetGrantTypes().ExactOne("authorization_code") } - -var ( - _ AccessRequestValidator = (*AuthorizeExplicitGrantAccessRequestValidator)(nil) - _ CodeHandler = (*AuthorizeCodeHandler)(nil) - _ SessionHandler = (*AuthorizeExplicitGrantSessionHandler)(nil) - _ fosite.TokenEndpointHandler = (*AuthorizeExplicitTokenEndpointHandler)(nil) -) diff --git a/handler/oauth2/flow_authorize_code_token_test.go b/handler/oauth2/flow_authorize_code_token_test.go index c7ee35e21..34e88830c 100644 --- a/handler/oauth2/flow_authorize_code_token_test.go +++ b/handler/oauth2/flow_authorize_code_token_test.go @@ -7,14 +7,15 @@ import ( "context" "fmt" "net/url" - "testing" + "testing" //"time" + "time" gomock "go.uber.org/mock/gomock" "github.com/ory/fosite/internal" - "github.com/ory/fosite" + "github.com/ory/fosite" //"github.com/ory/fosite/internal" "github.com/ory/fosite/storage" "github.com/pkg/errors" "github.com/stretchr/testify/assert" @@ -28,30 +29,22 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { t.Run("strategy="+k, func(t *testing.T) { store := storage.NewMemoryStore() - testCases := []struct { - description string + var h AuthorizeExplicitGrantHandler + for _, c := range []struct { areq *fosite.AccessRequest - authreq *fosite.AuthorizeRequest - setup func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest, config *fosite.Config) + description string + setup func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) check func(t *testing.T, aresp *fosite.AccessResponse) expectErr error }{ { - description: "should fail because not responsible for handling the request", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"implicit"}, - Request: fosite.Request{ - Client: &fosite.DefaultClient{ - GrantTypes: fosite.Arguments{"authorization_code"}, - }, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), - }, + GrantTypes: fosite.Arguments{"123"}, }, - expectErr: fosite.ErrUnknownRequest, + description: "should fail because not responsible", + expectErr: fosite.ErrUnknownRequest, }, { - description: "should fail because authorization code cannot be retrieved", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ @@ -63,7 +56,8 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, _ *fosite.AuthorizeRequest, _ *fosite.Config) { + description: "should fail because authcode not found", + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { code, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) areq.Form.Set("code", code) @@ -71,38 +65,44 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { expectErr: fosite.ErrServerError, }, { - description: "should pass with offline scope and refresh token grant type", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Form: url.Values{}, + Form: url.Values{"code": []string{"foo.bar"}}, Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: fosite.Arguments{"authorization_code", "refresh_token"}, + GrantTypes: fosite.Arguments{"authorization_code"}, }, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, - authreq: &fosite.AuthorizeRequest{ + description: "should fail because validation failed", + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), "bar", areq)) + }, + expectErr: fosite.ErrInvalidRequest, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ + Form: url.Values{}, Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, + GrantTypes: fosite.Arguments{"authorization_code", "refresh_token"}, }, - RequestedScope: fosite.Arguments{"foo", "bar", "offline"}, - GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + GrantedScope: fosite.Arguments{"foo", "offline"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest, _ *fosite.Config) { - code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + code, sig, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Set("code", code) + areq.Form.Add("code", code) - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, areq)) }, + description: "should pass with offline scope and refresh token", check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) assert.Equal(t, "bearer", aresp.TokenType) @@ -112,39 +112,27 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { }, }, { - description: "should pass with refresh token grant type", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - ID: "foo", GrantTypes: fosite.Arguments{"authorization_code", "refresh_token"}, }, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), - }, - }, - authreq: &fosite.AuthorizeRequest{ - Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, - RequestedScope: fosite.Arguments{"foo", "bar"}, - GrantedScope: fosite.Arguments{"foo"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + GrantedScope: fosite.Arguments{"foo"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest, config *fosite.Config) { + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { config.RefreshTokenScopes = []string{} - code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + code, sig, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Set("code", code) + areq.Form.Add("code", code) - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, areq)) }, + description: "should pass with refresh token always provided", check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) assert.Equal(t, "bearer", aresp.TokenType) @@ -154,38 +142,56 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { }, }, { - description: "pass and response should not have refresh token", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ Form: url.Values{}, Client: &fosite.DefaultClient{ - ID: "foo", GrantTypes: fosite.Arguments{"authorization_code"}, }, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + GrantedScope: fosite.Arguments{}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, - authreq: &fosite.AuthorizeRequest{ + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { + config.RefreshTokenScopes = []string{} + code, sig, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + require.NoError(t, err) + areq.Form.Add("code", code) + + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, areq)) + }, + description: "should pass with no refresh token", + check: func(t *testing.T, aresp *fosite.AccessResponse) { + assert.NotEmpty(t, aresp.AccessToken) + assert.Equal(t, "bearer", aresp.TokenType) + assert.Empty(t, aresp.GetExtra("refresh_token")) + assert.NotEmpty(t, aresp.GetExtra("expires_in")) + assert.Empty(t, aresp.GetExtra("scope")) + }, + }, + { + areq: &fosite.AccessRequest{ + GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ + Form: url.Values{}, Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, + GrantTypes: fosite.Arguments{"authorization_code"}, }, - RequestedScope: fosite.Arguments{"foo", "bar"}, - GrantedScope: fosite.Arguments{"foo"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + GrantedScope: fosite.Arguments{"foo"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, - setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest, _ *fosite.Config) { + setup: func(t *testing.T, areq *fosite.AccessRequest, config *fosite.Config) { code, sig, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Set("code", code) + areq.Form.Add("code", code) - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, authreq)) + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, areq)) }, + description: "should not have refresh token", check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) assert.Equal(t, "bearer", aresp.TokenType) @@ -194,45 +200,37 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) { assert.Equal(t, "foo", aresp.GetExtra("scope")) }, }, - } - - for _, testCase := range testCases { - t.Run("case="+testCase.description, func(t *testing.T) { + } { + t.Run("case="+c.description, func(t *testing.T) { config := &fosite.Config{ ScopeStrategy: fosite.HierarchicScopeStrategy, AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, AccessTokenLifespan: time.Minute, RefreshTokenScopes: []string{"offline"}, } - h := GenericCodeTokenEndpointHandler{ - AccessRequestValidator: &AuthorizeExplicitGrantAccessRequestValidator{}, - CodeHandler: &AuthorizeCodeHandler{ - AuthorizeCodeStrategy: strategy, - }, - SessionHandler: &AuthorizeExplicitGrantSessionHandler{ - AuthorizeCodeStorage: store, - }, - AccessTokenStrategy: strategy, - RefreshTokenStrategy: strategy, - CoreStorage: store, - Config: config, + h = AuthorizeExplicitGrantHandler{ + CoreStorage: store, + AuthorizeCodeStrategy: strategy, + AccessTokenStrategy: strategy, + RefreshTokenStrategy: strategy, + Config: config, } - if testCase.setup != nil { - testCase.setup(t, testCase.areq, testCase.authreq, config) + if c.setup != nil { + c.setup(t, c.areq, config) } aresp := fosite.NewAccessResponse() - err := h.PopulateTokenEndpointResponse(context.Background(), testCase.areq, aresp) + err := h.PopulateTokenEndpointResponse(context.Background(), c.areq, aresp) - if testCase.expectErr != nil { - require.EqualError(t, err, testCase.expectErr.Error(), "%+v", err) + if c.expectErr != nil { + require.EqualError(t, err, c.expectErr.Error(), "%+v", err) } else { require.NoError(t, err, "%+v", err) } - if testCase.check != nil { - testCase.check(t, aresp) + if c.check != nil { + c.check(t, aresp) } }) } @@ -246,214 +244,130 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { } { t.Run("strategy="+k, func(t *testing.T) { store := storage.NewMemoryStore() - config := &fosite.Config{ - ScopeStrategy: fosite.HierarchicScopeStrategy, - AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, - AuthorizeCodeLifespan: time.Minute, - } - h := GenericCodeTokenEndpointHandler{ - AccessRequestValidator: &AuthorizeExplicitGrantAccessRequestValidator{}, - CodeHandler: &AuthorizeCodeHandler{ - AuthorizeCodeStrategy: strategy, - }, - SessionHandler: &AuthorizeExplicitGrantSessionHandler{ - AuthorizeCodeStorage: store, - }, + + h := AuthorizeExplicitGrantHandler{ + CoreStorage: store, + AuthorizeCodeStrategy: hmacshaStrategy, TokenRevocationStorage: store, - Config: config, + Config: &fosite.Config{ + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + AuthorizeCodeLifespan: time.Minute, + }, } - - testCases := []struct { - description string + for i, c := range []struct { areq *fosite.AccessRequest authreq *fosite.AuthorizeRequest + description string setup func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) check func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) expectErr error }{ { - description: "should fail because not responsible for handling the request", areq: &fosite.AccessRequest{ - GrantTypes: fosite.Arguments{"implicit"}, - Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, - Form: url.Values{"redirect_uri": []string{"request-redir"}}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), - }, + GrantTypes: fosite.Arguments{"12345678"}, }, - expectErr: fosite.ErrUnknownRequest, + description: "should fail because not responsible", + expectErr: fosite.ErrUnknownRequest, }, { - description: "should fail because client is not granted the correct grant type", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{""}, - }, - Form: url.Values{"redirect_uri": []string{"request-redir"}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{""}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, - expectErr: fosite.ErrUnauthorizedClient, + description: "should fail because client is not granted this grant type", + expectErr: fosite.ErrUnauthorizedClient, }, { - description: "should fail because authorization code cannot be retrieved", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, - Form: url.Values{"redirect_uri": []string{"request-redir"}}, + Client: &fosite.DefaultClient{GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, + description: "should fail because authcode could not be retrieved (1)", setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - code, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + token, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Set("code", code) + areq.Form = url.Values{"code": {token}} }, expectErr: fosite.ErrInvalidGrant, }, { - description: "should fail because authorization code is expired", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Form: url.Values{ - "code": {"foo.bar"}, - "redirect_uri": []string{"request-redir"}, - }, - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, + Form: url.Values{"code": {"foo.bar"}}, + Client: &fosite.DefaultClient{GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, - authreq: &fosite.AuthorizeRequest{ - Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, - Form: url.Values{"redirect_uri": []string{"request-redir"}}, - RequestedScope: fosite.Arguments{"foo"}, - GrantedScope: fosite.Arguments{"foo"}, - Session: &fosite.DefaultSession{ - ExpiresAt: map[fosite.TokenType]time.Time{ - fosite.AuthorizeCode: time.Now().Add(-time.Hour).UTC(), - }, - }, - RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), - }, - }, - setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) - require.NoError(t, err) - areq.Form.Set("code", code) - - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) - }, - expectErr: fosite.ErrTokenExpired, + description: "should fail because authcode validation failed", + expectErr: fosite.ErrInvalidGrant, }, { - description: "should fail because client mismatch", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, - Form: url.Values{"redirect_uri": []string{"request-redir"}}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "bar", - GrantTypes: []string{"authorization_code"}, - }, - Form: url.Values{"redirect_uri": []string{"request-redir"}}, - RequestedScope: fosite.Arguments{"foo"}, - GrantedScope: fosite.Arguments{"foo"}, - Session: &fosite.DefaultSession{ - ExpiresAt: map[fosite.TokenType]time.Time{ - fosite.AuthorizeCode: time.Now().Add(time.Hour).UTC(), - }, - }, + Client: &fosite.DefaultClient{ID: "bar"}, + RequestedScope: fosite.Arguments{"a", "b"}, }, }, + description: "should fail because client mismatch", setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + token, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Set("code", code) + areq.Form = url.Values{"code": {token}} require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) }, expectErr: fosite.ErrInvalidGrant, }, { - description: "should fail because redirect uri was set during /authorize call, but not in /token call", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, - Form: url.Values{}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, - Form: url.Values{"redirect_uri": []string{"request-redir"}}, - RequestedScope: fosite.Arguments{"foo"}, - GrantedScope: fosite.Arguments{"foo"}, - Session: &fosite.DefaultSession{ - ExpiresAt: map[fosite.TokenType]time.Time{ - fosite.AuthorizeCode: time.Now().Add(time.Hour).UTC(), - }, - }, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, + Form: url.Values{"redirect_uri": []string{"request-redir"}}, + Session: &fosite.DefaultSession{}, }, }, + description: "should fail because redirect uri was set during /authorize call, but not in /token call", setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + token, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Set("code", code) + areq.Form = url.Values{"code": {token}} require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) }, expectErr: fosite.ErrInvalidGrant, }, { - description: "should pass", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Form: url.Values{"redirect_uri": []string{"request-redir"}}, Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), @@ -461,79 +375,64 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { }, authreq: &fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, - Form: url.Values{"redirect_uri": []string{"request-redir"}}, - RequestedScope: fosite.Arguments{"foo"}, - GrantedScope: fosite.Arguments{"foo"}, + Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"authorization_code"}}, Session: &fosite.DefaultSession{}, + RequestedScope: fosite.Arguments{"a", "b"}, RequestedAt: time.Now().UTC(), }, }, + description: "should pass", setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + token, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Set("code", code) + areq.Form = url.Values{"code": {token}} require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) }, }, { - description: "should fail because code has been used already", areq: &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ - Form: url.Values{"redirect_uri": []string{"request-redir"}}, + Form: url.Values{}, Client: &fosite.DefaultClient{ - ID: "foo", GrantTypes: fosite.Arguments{"authorization_code"}, }, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + GrantedScope: fosite.Arguments{"foo", "offline"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, - authreq: &fosite.AuthorizeRequest{ - Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, - Form: url.Values{"redirect_uri": []string{"request-redir"}}, - RequestedScope: fosite.Arguments{"foo"}, - GrantedScope: fosite.Arguments{"foo"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), - }, + check: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { + assert.Equal(t, time.Now().Add(time.Minute).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.AccessToken)) + assert.Equal(t, time.Now().Add(time.Minute).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.RefreshToken)) }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.AuthorizeRequest) { - code, signature, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + code, sig, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form.Set("code", code) + areq.Form.Add("code", code) - require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), signature, authreq)) - require.NoError(t, store.InvalidateAuthorizeCodeSession(context.Background(), signature)) + require.NoError(t, store.CreateAuthorizeCodeSession(context.Background(), sig, areq)) + require.NoError(t, store.InvalidateAuthorizeCodeSession(context.Background(), sig)) }, - expectErr: fosite.ErrInvalidGrant, + description: "should fail because code has been used already", + expectErr: fosite.ErrInvalidGrant, }, - } - - for i, testCase := range testCases { - t.Run(fmt.Sprintf("case=%d/description=%s", i, testCase.description), func(t *testing.T) { - if testCase.setup != nil { - testCase.setup(t, testCase.areq, testCase.authreq) + } { + t.Run(fmt.Sprintf("case=%d/description=%s", i, c.description), func(t *testing.T) { + if c.setup != nil { + c.setup(t, c.areq, c.authreq) } - t.Logf("Processing %+v", testCase.areq.Client) + t.Logf("Processing %+v", c.areq.Client) - err := h.HandleTokenEndpointRequest(context.Background(), testCase.areq) - if testCase.expectErr != nil { - require.EqualError(t, err, testCase.expectErr.Error(), "%+v", err) + err := h.HandleTokenEndpointRequest(context.Background(), c.areq) + if c.expectErr != nil { + require.EqualError(t, err, c.expectErr.Error(), "%+v", err) } else { require.NoError(t, err, "%+v", err) - if testCase.check != nil { - testCase.check(t, testCase.areq, testCase.authreq) + if c.check != nil { + c.check(t, c.areq, c.authreq) } } }) @@ -545,38 +444,23 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) { func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { var mockTransactional *internal.MockTransactional var mockCoreStore *internal.MockCoreStorage - var mockAuthorizeStore *internal.MockAuthorizeCodeStorage strategy := hmacshaStrategy - - authreq := &fosite.AuthorizeRequest{ - Request: fosite.Request{ - Client: &fosite.DefaultClient{ - ID: "foo", - GrantTypes: []string{"authorization_code"}, - }, - RequestedScope: fosite.Arguments{"foo", "offline"}, - GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), - }, - } - - areq := &fosite.AccessRequest{ + request := &fosite.AccessRequest{ GrantTypes: fosite.Arguments{"authorization_code"}, Request: fosite.Request{ Client: &fosite.DefaultClient{ GrantTypes: fosite.Arguments{"authorization_code", "refresh_token"}, }, - Session: &fosite.DefaultSession{}, - RequestedAt: time.Now().UTC(), + GrantedScope: fosite.Arguments{"offline"}, + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, } - aresp := fosite.NewAccessResponse() - propagatedContext := context.Background() - - code, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) + token, _, err := strategy.GenerateAuthorizeCode(context.Background(), nil) require.NoError(t, err) - areq.Form = url.Values{"code": {code}} + request.Form = url.Values{"code": {token}} + response := fosite.NewAccessResponse() + propagatedContext := context.Background() // some storage implementation that has support for transactions, notice the embedded type `storage.Transactional` type transactionalStore struct { @@ -584,12 +468,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { CoreStorage } - type authorizeTransactionalStore struct { - storage.Transactional - AuthorizeCodeStorage - } - - testCases := []struct { + for _, testCase := range []struct { description string setup func() expectError error @@ -597,16 +476,16 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "transaction should be committed successfully if no errors occur", setup: func() { - mockAuthorizeStore. + mockCoreStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(authreq, nil). + Return(request, nil). Times(1) mockTransactional. EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockAuthorizeStore. + mockCoreStore. EXPECT(). InvalidateAuthorizeCodeSession(gomock.Any(), gomock.Any()). Return(nil). @@ -631,16 +510,16 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "transaction should be rolled back if `InvalidateAuthorizeCodeSession` returns an error", setup: func() { - mockAuthorizeStore. + mockCoreStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(authreq, nil). + Return(request, nil). Times(1) mockTransactional. EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockAuthorizeStore. + mockCoreStore. EXPECT(). InvalidateAuthorizeCodeSession(gomock.Any(), gomock.Any()). Return(errors.New("Whoops, a nasty database error occurred!")). @@ -656,16 +535,16 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "transaction should be rolled back if `CreateAccessTokenSession` returns an error", setup: func() { - mockAuthorizeStore. + mockCoreStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(authreq, nil). + Return(request, nil). Times(1) mockTransactional. EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockAuthorizeStore. + mockCoreStore. EXPECT(). InvalidateAuthorizeCodeSession(gomock.Any(), gomock.Any()). Return(nil). @@ -686,10 +565,10 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "should result in a server error if transaction cannot be created", setup: func() { - mockAuthorizeStore. + mockCoreStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(authreq, nil). + Return(request, nil). Times(1) mockTransactional. EXPECT(). @@ -701,16 +580,16 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "should result in a server error if transaction cannot be rolled back", setup: func() { - mockAuthorizeStore. + mockCoreStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(authreq, nil). + Return(request, nil). Times(1) mockTransactional. EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockAuthorizeStore. + mockCoreStore. EXPECT(). InvalidateAuthorizeCodeSession(gomock.Any(), gomock.Any()). Return(errors.New("Whoops, a nasty database error occurred!")). @@ -726,16 +605,16 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "should result in a server error if transaction cannot be committed", setup: func() { - mockAuthorizeStore. + mockCoreStore. EXPECT(). GetAuthorizeCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). - Return(authreq, nil). + Return(request, nil). Times(1) mockTransactional. EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockAuthorizeStore. + mockCoreStore. EXPECT(). InvalidateAuthorizeCodeSession(gomock.Any(), gomock.Any()). Return(nil). @@ -763,44 +642,31 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { }, expectError: fosite.ErrServerError, }, - } - - for _, testCase := range testCases { + } { t.Run(fmt.Sprintf("scenario=%s", testCase.description), func(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockTransactional = internal.NewMockTransactional(ctrl) mockCoreStore = internal.NewMockCoreStorage(ctrl) - mockAuthorizeStore = internal.NewMockAuthorizeCodeStorage(ctrl) testCase.setup() - config := &fosite.Config{ - ScopeStrategy: fosite.HierarchicScopeStrategy, - AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, - AuthorizeCodeLifespan: time.Minute, - } - h := GenericCodeTokenEndpointHandler{ - AccessRequestValidator: &AuthorizeExplicitGrantAccessRequestValidator{}, - CodeHandler: &AuthorizeCodeHandler{ - AuthorizeCodeStrategy: strategy, - }, - SessionHandler: &AuthorizeExplicitGrantSessionHandler{ - AuthorizeCodeStorage: authorizeTransactionalStore{ - mockTransactional, - mockAuthorizeStore, - }, - }, + handler := AuthorizeExplicitGrantHandler{ CoreStorage: transactionalStore{ mockTransactional, mockCoreStore, }, - AccessTokenStrategy: strategy, - RefreshTokenStrategy: strategy, - Config: config, + AccessTokenStrategy: strategy, + RefreshTokenStrategy: strategy, + AuthorizeCodeStrategy: strategy, + Config: &fosite.Config{ + ScopeStrategy: fosite.HierarchicScopeStrategy, + AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, + AuthorizeCodeLifespan: time.Minute, + }, } - if err := h.PopulateTokenEndpointResponse(propagatedContext, areq, aresp); testCase.expectError != nil { + if err := handler.PopulateTokenEndpointResponse(propagatedContext, request, response); testCase.expectError != nil { assert.EqualError(t, err, testCase.expectError.Error()) } }) diff --git a/handler/oauth2/flow_generic_code_token.go b/handler/oauth2/flow_generic_code_token.go deleted file mode 100644 index 407d6b1ac..000000000 --- a/handler/oauth2/flow_generic_code_token.go +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright © 2024 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package oauth2 - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/pkg/errors" - - "github.com/ory/fosite/storage" - - "github.com/ory/x/errorsx" - - "github.com/ory/fosite" -) - -// AccessRequestValidator handles various validations in the access request handling. -type AccessRequestValidator interface { - // CanHandleRequest validates if the access request should be handled. - CanHandleRequest(requester fosite.AccessRequester) bool - - // ValidateGrantTypes validates the grant types in the access request. - ValidateGrantTypes(requester fosite.AccessRequester) error - - // ValidateRedirectURI validates the redirect uri in the access request. - ValidateRedirectURI(accessRequester fosite.AccessRequester, authorizeRequester fosite.Requester) error - - // GetGrantType retrieves the grant type from the request. - GetGrantType(requester fosite.AccessRequester) fosite.GrantType -} - -// CodeHandler handles authorization/device code related operations. -type CodeHandler interface { - // Code fetches the code and code signature. - Code(ctx context.Context, requester fosite.AccessRequester) (code string, signature string, err error) - - // ValidateCode validates the code. Can be used for checks that need to run before we fetch the session from the database. - ValidateCode(ctx context.Context, requester fosite.Requester, code string) error - - // ValidateCodeSession validates the code session. - ValidateCodeSession(ctx context.Context, requester fosite.Requester, code string) error -} - -// SessionHandler handles session-related operations. -type SessionHandler interface { - // Session fetches the authorized request. - Session(ctx context.Context, requester fosite.AccessRequester, codeSignature string) (fosite.Requester, error) - - // InvalidateSession invalidates the code and session. - InvalidateSession(ctx context.Context, codeSignature string) error -} - -// GenericCodeTokenEndpointHandler is a token response handler for -// - the Authorize Code grant using the explicit grant type as defined in https://tools.ietf.org/html/rfc6749#section-4.1 -// - the Device Authorization Grant as defined in https://www.rfc-editor.org/rfc/rfc8628 -type GenericCodeTokenEndpointHandler struct { - AccessRequestValidator - CodeHandler - SessionHandler - - AccessTokenStrategy AccessTokenStrategy - RefreshTokenStrategy RefreshTokenStrategy - CoreStorage CoreStorage - TokenRevocationStorage TokenRevocationStorage - Config interface { - fosite.AccessTokenLifespanProvider - fosite.RefreshTokenLifespanProvider - fosite.RefreshTokenScopesProvider - } -} - -func (c *GenericCodeTokenEndpointHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { - if !c.CanHandleTokenEndpointRequest(ctx, requester) { - return errorsx.WithStack(fosite.ErrUnknownRequest) - } - - var code, signature string - var err error - if code, signature, err = c.Code(ctx, requester); err != nil { - return err - } - - var ar fosite.Requester - if ar, err = c.Session(ctx, requester, signature); err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } - - if err = c.ValidateCodeSession(ctx, ar, code); err != nil { - return errorsx.WithStack(err) - } - - for _, scope := range ar.GetGrantedScopes() { - requester.GrantScope(scope) - } - - for _, audience := range ar.GetGrantedAudience() { - requester.GrantAudience(audience) - } - - var accessToken, accessTokenSignature string - accessToken, accessTokenSignature, err = c.AccessTokenStrategy.GenerateAccessToken(ctx, requester) - if err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } - - var refreshToken, refreshTokenSignature string - if c.canIssueRefreshToken(ctx, requester) { - refreshToken, refreshTokenSignature, err = c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester) - if err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } - } - - ctx, err = storage.MaybeBeginTx(ctx, c.CoreStorage) - if err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } - defer func() { - if err != nil { - if rollBackTxnErr := storage.MaybeRollbackTx(ctx, c.CoreStorage); rollBackTxnErr != nil { - err = errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebugf("error: %s; rollback error: %s", err, rollBackTxnErr)) - } - } - }() - - if err = c.InvalidateSession(ctx, signature); err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } - - if err = c.CoreStorage.CreateAccessTokenSession(ctx, accessTokenSignature, requester.Sanitize([]string{})); err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } - - if refreshTokenSignature != "" { - if err = c.CoreStorage.CreateRefreshTokenSession(ctx, refreshTokenSignature, requester.Sanitize([]string{})); err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } - } - - lifeSpan := fosite.GetEffectiveLifespan(requester.GetClient(), c.GetGrantType(requester), fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) - responder.SetAccessToken(accessToken) - responder.SetTokenType("bearer") - responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, lifeSpan, time.Now().UTC())) - responder.SetScopes(requester.GetGrantedScopes()) - if refreshToken != "" { - responder.SetExtra("refresh_token", refreshToken) - } - - if err = storage.MaybeCommitTx(ctx, c.CoreStorage); err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } - - return nil -} - -func (c *GenericCodeTokenEndpointHandler) HandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) error { - if !c.CanHandleTokenEndpointRequest(ctx, requester) { - return errorsx.WithStack(errorsx.WithStack(fosite.ErrUnknownRequest)) - } - - var err error - if err = c.ValidateGrantTypes(requester); err != nil { - return err - } - - var code, signature string - if code, signature, err = c.Code(ctx, requester); err != nil { - return err - } - - if err = c.ValidateCode(ctx, requester, code); err != nil { - return errorsx.WithStack(err) - } - - var ar fosite.Requester - if ar, err = c.Session(ctx, requester, signature); err != nil { - if ar != nil && (errors.Is(err, fosite.ErrInvalidatedAuthorizeCode) || errors.Is(err, fosite.ErrInvalidatedDeviceCode)) { - return c.revokeTokens(ctx, requester.GetID()) - } - - return err - } - - if err = c.ValidateCodeSession(ctx, ar, code); err != nil { - return errorsx.WithStack(err) - } - - // Override scopes - requester.SetRequestedScopes(ar.GetRequestedScopes()) - - // Override audiences - requester.SetRequestedAudience(ar.GetRequestedAudience()) - - // The authorization server MUST ensure that - // the authorization code was issued to the authenticated confidential client, - // or if the client is public, ensure that the code was issued to "client_id" in the request - if ar.GetClient().GetID() != requester.GetClient().GetID() { - return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the one from the authorize request.")) - } - - if err = c.ValidateRedirectURI(requester, ar); err != nil { - return err - } - - // Checking of POST client_id skipped, because - // if the client type is confidential or the client was issued client credentials (or assigned other authentication requirements), - // the client MUST authenticate with the authorization server as described in Section 3.2.1. - requester.SetSession(ar.GetSession()) - requester.SetID(ar.GetID()) - - atLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), c.GetGrantType(requester), fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) - requester.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(atLifespan).Round(time.Second)) - - rtLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), c.GetGrantType(requester), fosite.RefreshToken, c.Config.GetRefreshTokenLifespan(ctx)) - if rtLifespan > -1 { - requester.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(rtLifespan).Round(time.Second)) - } - - return nil -} - -func (c *GenericCodeTokenEndpointHandler) CanSkipClientAuth(ctx context.Context, requester fosite.AccessRequester) bool { - return false -} - -func (c *GenericCodeTokenEndpointHandler) CanHandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) bool { - return c.CanHandleRequest(requester) -} - -func (c *GenericCodeTokenEndpointHandler) canIssueRefreshToken(ctx context.Context, requester fosite.Requester) bool { - scopes := c.Config.GetRefreshTokenScopes(ctx) - - // Require one of the refresh token scopes, if set. - if len(scopes) > 0 && !requester.GetGrantedScopes().HasOneOf(scopes...) { - return false - } - - // Do not issue a refresh token to clients that cannot use the refresh token grant type. - if !requester.GetClient().GetGrantTypes().Has("refresh_token") { - return false - } - - return true -} - -func (c *GenericCodeTokenEndpointHandler) revokeTokens(ctx context.Context, reqId string) error { - hint := "The authorization code has already been used." - var debug strings.Builder - - revokeAndAppendErr := func(tokenType string, revokeFunc func(context.Context, string) error) { - if err := revokeFunc(ctx, reqId); err != nil { - hint += fmt.Sprintf(" Additionally, an error occurred during processing the %s token revocation.", tokenType) - debug.WriteString(fmt.Sprintf("Revocation of %s token lead to error %s.", tokenType, err.Error())) - } - } - - revokeAndAppendErr("access", c.TokenRevocationStorage.RevokeAccessToken) - revokeAndAppendErr("refresh", c.TokenRevocationStorage.RevokeRefreshToken) - - return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint(hint).WithDebug(debug.String())) -} - -var _ fosite.TokenEndpointHandler = (*GenericCodeTokenEndpointHandler)(nil) diff --git a/handler/openid/flow_hybrid.go b/handler/openid/flow_hybrid.go index 5bca57682..c1dc6c645 100644 --- a/handler/openid/flow_hybrid.go +++ b/handler/openid/flow_hybrid.go @@ -16,7 +16,7 @@ import ( type OpenIDConnectHybridHandler struct { AuthorizeImplicitGrantTypeHandler *oauth2.AuthorizeImplicitGrantTypeHandler - AuthorizeExplicitGrantAuthHandler *oauth2.AuthorizeExplicitGrantAuthHandler + AuthorizeExplicitGrantHandler *oauth2.AuthorizeExplicitGrantHandler IDTokenHandleHelper *IDTokenHandleHelper OpenIDConnectRequestValidator *OpenIDConnectRequestValidator OpenIDConnectRequestStorage OpenIDConnectRequestStorage @@ -97,7 +97,7 @@ func (c *OpenIDConnectHybridHandler) HandleAuthorizeEndpointRequest(ctx context. return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant 'authorization_code'.")) } - code, signature, err := c.AuthorizeExplicitGrantAuthHandler.AuthorizeCodeStrategy.GenerateAuthorizeCode(ctx, ar) + code, signature, err := c.AuthorizeExplicitGrantHandler.AuthorizeCodeStrategy.GenerateAuthorizeCode(ctx, ar) if err != nil { return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } @@ -110,8 +110,8 @@ func (c *OpenIDConnectHybridHandler) HandleAuthorizeEndpointRequest(ctx context. // } // This is required because we must limit the authorize code lifespan. - ar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().UTC().Add(c.AuthorizeExplicitGrantAuthHandler.Config.GetAuthorizeCodeLifespan(ctx)).Round(time.Second)) - if err := c.AuthorizeExplicitGrantAuthHandler.AuthorizeCodeStorage.CreateAuthorizeCodeSession(ctx, signature, ar.Sanitize(c.AuthorizeExplicitGrantAuthHandler.GetSanitationWhiteList(ctx))); err != nil { + ar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().UTC().Add(c.AuthorizeExplicitGrantHandler.Config.GetAuthorizeCodeLifespan(ctx)).Round(time.Second)) + if err := c.AuthorizeExplicitGrantHandler.CoreStorage.CreateAuthorizeCodeSession(ctx, signature, ar.Sanitize(c.AuthorizeExplicitGrantHandler.GetSanitationWhiteList(ctx))); err != nil { return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } diff --git a/handler/openid/flow_hybrid_test.go b/handler/openid/flow_hybrid_test.go index 3885de298..c6baac949 100644 --- a/handler/openid/flow_hybrid_test.go +++ b/handler/openid/flow_hybrid_test.go @@ -32,7 +32,7 @@ var hmacStrategy = oauth2.NewHMACSHAStrategy( ) func makeOpenIDConnectHybridHandler(minParameterEntropy int) OpenIDConnectHybridHandler { - idStrategy := &DefaultStrategy{ + var idStrategy = &DefaultStrategy{ Signer: &jwt.DefaultSigner{ GetPrivateKey: func(_ context.Context) (interface{}, error) { return gen.MustRSAKey(), nil @@ -43,7 +43,7 @@ func makeOpenIDConnectHybridHandler(minParameterEntropy int) OpenIDConnectHybrid }, } - j := &DefaultStrategy{ + var j = &DefaultStrategy{ Signer: &jwt.DefaultSigner{ GetPrivateKey: func(_ context.Context) (interface{}, error) { return key, nil @@ -61,11 +61,11 @@ func makeOpenIDConnectHybridHandler(minParameterEntropy int) OpenIDConnectHybrid AuthorizeCodeLifespan: time.Hour, RefreshTokenLifespan: time.Hour, } - store := storage.NewMemoryStore() return OpenIDConnectHybridHandler{ - AuthorizeExplicitGrantAuthHandler: &oauth2.AuthorizeExplicitGrantAuthHandler{ + AuthorizeExplicitGrantHandler: &oauth2.AuthorizeExplicitGrantHandler{ AuthorizeCodeStrategy: hmacStrategy, - AuthorizeCodeStorage: store, + AccessTokenStrategy: hmacStrategy, + CoreStorage: storage.NewMemoryStore(), Config: config, }, AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{ diff --git a/handler/openid/validator.go b/handler/openid/validator.go index 4a8f3060c..f25314943 100644 --- a/handler/openid/validator.go +++ b/handler/openid/validator.go @@ -60,10 +60,9 @@ func (v *OpenIDConnectRequestValidator) ValidatePrompt(ctx context.Context, req // unless the identity of the client can be proven, the request SHOULD // be processed as if no previous request had been approved. + checker := v.Config.GetRedirectSecureChecker(ctx) if stringslice.Has(requiredPrompt, "none") { - redirectURI := req.GetRedirectURI() - checker := v.Config.GetRedirectSecureChecker(ctx) - if !checker(ctx, redirectURI) { + if !checker(ctx, req.GetRedirectURI()) { return errorsx.WithStack(fosite.ErrConsentRequired.WithHint("OAuth 2.0 Client is marked public and redirect uri is not considered secure (https missing), but \"prompt=none\" was requested.")) } } diff --git a/handler/openid/validator_test.go b/handler/openid/validator_test.go index f9b5d254b..d22bb33ef 100644 --- a/handler/openid/validator_test.go +++ b/handler/openid/validator_test.go @@ -21,12 +21,11 @@ func TestValidatePrompt(t *testing.T) { config := &fosite.Config{ MinParameterEntropy: fosite.MinParameterEntropy, } - j := &DefaultStrategy{ + var j = &DefaultStrategy{ Signer: &jwt.DefaultSigner{ GetPrivateKey: func(_ context.Context) (interface{}, error) { return key, nil - }, - }, + }}, Config: &fosite.Config{ MinParameterEntropy: fosite.MinParameterEntropy, }, @@ -34,7 +33,7 @@ func TestValidatePrompt(t *testing.T) { v := NewOpenIDConnectRequestValidator(j, config) - genIDToken := func(c jwt.IDTokenClaims) string { + var genIDToken = func(c jwt.IDTokenClaims) string { s, _, err := j.Generate(context.TODO(), c.ToMapClaims(), jwt.NewHeaders()) require.NoError(t, err) return s diff --git a/handler/rfc8628/token_handler.go b/handler/rfc8628/token_handler.go index 5313af9f4..bc20f5307 100644 --- a/handler/rfc8628/token_handler.go +++ b/handler/rfc8628/token_handler.go @@ -5,21 +5,232 @@ package rfc8628 import ( "context" + "fmt" + "strings" + "time" "github.com/pkg/errors" + "github.com/ory/fosite/handler/oauth2" + "github.com/ory/fosite/storage" "github.com/ory/x/errorsx" "github.com/ory/fosite" - "github.com/ory/fosite/handler/oauth2" ) -type DeviceCodeHandler struct { +var _ fosite.TokenEndpointHandler = (*DeviceCodeTokenEndpointHandler)(nil) + +// DeviceCodeTokenEndpointHandler is a token response handler for +// - the Authorize code grant using the explicit grant type as defined in https://tools.ietf.org/html/rfc6749#section-4.1 +// - the Device Authorization Grant as defined in https://www.rfc-editor.org/rfc/rfc8628 +type DeviceCodeTokenEndpointHandler struct { DeviceRateLimitStrategy DeviceRateLimitStrategy DeviceCodeStrategy DeviceCodeStrategy + UserCodeStrategy UserCodeStrategy + CoreStorage RFC8628CoreStorage + + AccessTokenStrategy oauth2.AccessTokenStrategy + RefreshTokenStrategy oauth2.RefreshTokenStrategy + TokenRevocationStorage oauth2.TokenRevocationStorage + Config interface { + fosite.AccessTokenLifespanProvider + fosite.RefreshTokenLifespanProvider + fosite.RefreshTokenScopesProvider + } +} + +func (c *DeviceCodeTokenEndpointHandler) CanSkipClientAuth(ctx context.Context, requester fosite.AccessRequester) bool { + return false +} + +func (c *DeviceCodeTokenEndpointHandler) CanHandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) bool { + return requester.GetGrantTypes().ExactOne(string(fosite.GrantTypeDeviceCode)) +} + +func (v DeviceCodeTokenEndpointHandler) CanHandleRequest(requester fosite.AccessRequester) bool { + return requester.GetGrantTypes().ExactOne(string(fosite.GrantTypeDeviceCode)) +} + +func (c *DeviceCodeTokenEndpointHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { + if !c.CanHandleTokenEndpointRequest(ctx, requester) { + return errorsx.WithStack(fosite.ErrUnknownRequest) + } + + var code, signature string + var err error + if code, signature, err = c.deviceCode(ctx, requester); err != nil { + return err + } + + var ar fosite.Requester + if ar, err = c.session(ctx, requester, signature); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + if err = c.DeviceCodeStrategy.ValidateDeviceCode(ctx, requester, code); err != nil { + return errorsx.WithStack(err) + } + + for _, scope := range ar.GetGrantedScopes() { + requester.GrantScope(scope) + } + + for _, audience := range ar.GetGrantedAudience() { + requester.GrantAudience(audience) + } + + var accessToken, accessTokenSignature string + accessToken, accessTokenSignature, err = c.AccessTokenStrategy.GenerateAccessToken(ctx, requester) + if err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + var refreshToken, refreshTokenSignature string + if c.canIssueRefreshToken(ctx, requester) { + refreshToken, refreshTokenSignature, err = c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester) + if err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + } + + ctx, err = storage.MaybeBeginTx(ctx, c.CoreStorage) + if err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + defer func() { + if err != nil { + if rollBackTxnErr := storage.MaybeRollbackTx(ctx, c.CoreStorage); rollBackTxnErr != nil { + err = errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebugf("error: %s; rollback error: %s", err, rollBackTxnErr)) + } + } + }() + + if err = c.CoreStorage.InvalidateDeviceCodeSession(ctx, signature); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + if err = c.CoreStorage.CreateAccessTokenSession(ctx, accessTokenSignature, requester.Sanitize([]string{})); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + if refreshTokenSignature != "" { + if err = c.CoreStorage.CreateRefreshTokenSession(ctx, refreshTokenSignature, accessTokenSignature, requester.Sanitize([]string{})); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + } + + lifeSpan := fosite.GetEffectiveLifespan(requester.GetClient(), c.getGrantType(requester), fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) + responder.SetAccessToken(accessToken) + responder.SetTokenType("bearer") + responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, lifeSpan, time.Now().UTC())) + responder.SetScopes(requester.GetGrantedScopes()) + if refreshToken != "" { + responder.SetExtra("refresh_token", refreshToken) + } + + if err = storage.MaybeCommitTx(ctx, c.CoreStorage); err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + + return nil +} + +func (c *DeviceCodeTokenEndpointHandler) HandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) error { + if !c.CanHandleTokenEndpointRequest(ctx, requester) { + return errorsx.WithStack(errorsx.WithStack(fosite.ErrUnknownRequest)) + } + + var err error + if err = c.validateGrantTypes(requester); err != nil { + return err + } + + var code, signature string + if code, signature, err = c.deviceCode(ctx, requester); err != nil { + return err + } + + if err = c.validateCode(ctx, requester, code); err != nil { + return errorsx.WithStack(err) + } + + var ar fosite.Requester + if ar, err = c.session(ctx, requester, signature); err != nil { + if ar != nil && (errors.Is(err, fosite.ErrInvalidatedAuthorizeCode) || errors.Is(err, fosite.ErrInvalidatedDeviceCode)) { + return c.revokeTokens(ctx, requester.GetID()) + } + + return err + } + + if err = c.DeviceCodeStrategy.ValidateDeviceCode(ctx, ar, code); err != nil { + return errorsx.WithStack(err) + } + + // Override scopes + requester.SetRequestedScopes(ar.GetRequestedScopes()) + + // Override audiences + requester.SetRequestedAudience(ar.GetRequestedAudience()) + + // The authorization server MUST ensure that + // the authorization code was issued to the authenticated confidential client, + // or if the client is public, ensure that the code was issued to "client_id" in the request + if ar.GetClient().GetID() != requester.GetClient().GetID() { + return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the one from the authorize request.")) + } + + // Checking of POST client_id skipped, because + // if the client type is confidential or the client was issued client credentials (or assigned other authentication requirements), + // the client MUST authenticate with the authorization server as described in Section 3.2.1. + requester.SetSession(ar.GetSession()) + requester.SetID(ar.GetID()) + + atLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), c.getGrantType(requester), fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx)) + requester.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(atLifespan).Round(time.Second)) + + rtLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), c.getGrantType(requester), fosite.RefreshToken, c.Config.GetRefreshTokenLifespan(ctx)) + if rtLifespan > -1 { + requester.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(rtLifespan).Round(time.Second)) + } + + return nil } -func (c DeviceCodeHandler) Code(ctx context.Context, requester fosite.AccessRequester) (code string, signature string, err error) { +func (c *DeviceCodeTokenEndpointHandler) canIssueRefreshToken(ctx context.Context, requester fosite.Requester) bool { + scopes := c.Config.GetRefreshTokenScopes(ctx) + + // Require one of the refresh token scopes, if set. + if len(scopes) > 0 && !requester.GetGrantedScopes().HasOneOf(scopes...) { + return false + } + + // Do not issue a refresh token to clients that cannot use the refresh token grant type. + if !requester.GetClient().GetGrantTypes().Has("refresh_token") { + return false + } + + return true +} + +func (c *DeviceCodeTokenEndpointHandler) revokeTokens(ctx context.Context, reqId string) error { + hint := "The authorization code has already been used." + var debug strings.Builder + + revokeAndAppendErr := func(tokenType string, revokeFunc func(context.Context, string) error) { + if err := revokeFunc(ctx, reqId); err != nil { + hint += fmt.Sprintf(" Additionally, an error occurred during processing the %s token revocation.", tokenType) + debug.WriteString(fmt.Sprintf("Revocation of %s token lead to error %s.", tokenType, err.Error())) + } + } + + revokeAndAppendErr("access", c.TokenRevocationStorage.RevokeAccessToken) + revokeAndAppendErr("refresh", c.TokenRevocationStorage.RevokeRefreshToken) + + return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint(hint).WithDebug(debug.String())) +} + +func (c DeviceCodeTokenEndpointHandler) deviceCode(ctx context.Context, requester fosite.AccessRequester) (code string, signature string, err error) { code = requester.GetRequestForm().Get("device_code") signature, err = c.DeviceCodeStrategy.DeviceCodeSignature(ctx, code) @@ -30,7 +241,7 @@ func (c DeviceCodeHandler) Code(ctx context.Context, requester fosite.AccessRequ return } -func (c DeviceCodeHandler) ValidateCode(ctx context.Context, requester fosite.Requester, code string) error { +func (c DeviceCodeTokenEndpointHandler) validateCode(ctx context.Context, requester fosite.Requester, code string) error { shouldRateLimit, err := c.DeviceRateLimitStrategy.ShouldRateLimit(ctx, code) if err != nil { return err @@ -41,16 +252,8 @@ func (c DeviceCodeHandler) ValidateCode(ctx context.Context, requester fosite.Re return nil } -func (c DeviceCodeHandler) ValidateCodeSession(ctx context.Context, requester fosite.Requester, code string) error { - return c.DeviceCodeStrategy.ValidateDeviceCode(ctx, requester, code) -} - -type DeviceSessionHandler struct { - DeviceCodeStorage DeviceCodeStorage -} - -func (s DeviceSessionHandler) Session(ctx context.Context, requester fosite.AccessRequester, codeSignature string) (fosite.Requester, error) { - req, err := s.DeviceCodeStorage.GetDeviceCodeSession(ctx, codeSignature, requester.GetSession()) +func (s DeviceCodeTokenEndpointHandler) session(ctx context.Context, requester fosite.AccessRequester, codeSignature string) (fosite.Requester, error) { + req, err := s.CoreStorage.GetDeviceCodeSession(ctx, codeSignature, requester.GetSession()) if err != nil && errors.Is(err, fosite.ErrInvalidatedDeviceCode) { if req != nil { @@ -86,17 +289,7 @@ func (s DeviceSessionHandler) Session(ctx context.Context, requester fosite.Acce return req, err } -func (s DeviceSessionHandler) InvalidateSession(ctx context.Context, codeSignature string) error { - return s.DeviceCodeStorage.InvalidateDeviceCodeSession(ctx, codeSignature) -} - -type DeviceAccessRequestValidator struct{} - -func (v DeviceAccessRequestValidator) CanHandleRequest(requester fosite.AccessRequester) bool { - return requester.GetGrantTypes().ExactOne(string(fosite.GrantTypeDeviceCode)) -} - -func (v DeviceAccessRequestValidator) ValidateGrantTypes(requester fosite.AccessRequester) error { +func (v DeviceCodeTokenEndpointHandler) validateGrantTypes(requester fosite.AccessRequester) error { if !requester.GetClient().GetGrantTypes().Has(string(fosite.GrantTypeDeviceCode)) { return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"urn:ietf:params:oauth:grant-type:device_code\".")) } @@ -104,21 +297,13 @@ func (v DeviceAccessRequestValidator) ValidateGrantTypes(requester fosite.Access return nil } -func (v DeviceAccessRequestValidator) ValidateRedirectURI(accessRequester fosite.AccessRequester, authorizeRequester fosite.Requester) error { - return nil -} - -func (v DeviceAccessRequestValidator) GetGrantType(requester fosite.AccessRequester) fosite.GrantType { +func (v DeviceCodeTokenEndpointHandler) getGrantType(requester fosite.AccessRequester) fosite.GrantType { return fosite.GrantTypeDeviceCode } -type DeviceCodeTokenEndpointHandler struct { - oauth2.GenericCodeTokenEndpointHandler +func getExpiresIn(r fosite.Requester, key fosite.TokenType, defaultLifespan time.Duration, now time.Time) time.Duration { + if r.GetSession().GetExpiresAt(key).IsZero() { + return defaultLifespan + } + return time.Duration(r.GetSession().GetExpiresAt(key).UnixNano() - now.UnixNano()) } - -var ( - _ oauth2.AccessRequestValidator = (*DeviceAccessRequestValidator)(nil) - _ oauth2.CodeHandler = (*DeviceCodeHandler)(nil) - _ oauth2.SessionHandler = (*DeviceSessionHandler)(nil) - _ fosite.TokenEndpointHandler = (*DeviceCodeTokenEndpointHandler)(nil) -) diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index 3aab203b3..9fd9bc25e 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -37,7 +37,7 @@ var RFC8628HMACSHAStrategy = DefaultDeviceStrategy{ Enigma: &hmac.HMACStrategy{Config: &fosite.Config{GlobalSecret: []byte("foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar")}}, RateLimiterCache: freecache.NewCache(1024 * 1024), Config: &fosite.Config{ - DeviceAndUserCodeLifespan: time.Hour * 24, + DeviceAndUserCodeLifespan: time.Minute * 30, }, } @@ -51,18 +51,13 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { t.Run("strategy="+k, func(t *testing.T) { store := storage.NewMemoryStore() - h := oauth2.GenericCodeTokenEndpointHandler{ - AccessRequestValidator: &DeviceAccessRequestValidator{}, - CodeHandler: &DeviceCodeHandler{ - DeviceRateLimitStrategy: strategy, - DeviceCodeStrategy: strategy, - }, - SessionHandler: &DeviceSessionHandler{ - DeviceCodeStorage: store, - }, - CoreStorage: store, - AccessTokenStrategy: strategy.CoreStrategy, - RefreshTokenStrategy: strategy.CoreStrategy, + h := DeviceCodeTokenEndpointHandler{ + DeviceRateLimitStrategy: strategy, + DeviceCodeStrategy: strategy, + UserCodeStrategy: strategy, + CoreStorage: store, + AccessTokenStrategy: strategy.CoreStrategy, + RefreshTokenStrategy: strategy.CoreStrategy, Config: &fosite.Config{ ScopeStrategy: fosite.HierarchicScopeStrategy, AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, @@ -310,18 +305,13 @@ func TestDeviceUserCode_HandleTokenEndpointRequest_RateLimiting(t *testing.T) { t.Run("strategy="+k, func(t *testing.T) { store := storage.NewMemoryStore() - h := oauth2.GenericCodeTokenEndpointHandler{ - AccessRequestValidator: &DeviceAccessRequestValidator{}, - CodeHandler: &DeviceCodeHandler{ - DeviceRateLimitStrategy: strategy, - DeviceCodeStrategy: strategy, - }, - SessionHandler: &DeviceSessionHandler{ - DeviceCodeStorage: store, - }, - CoreStorage: store, - AccessTokenStrategy: strategy.CoreStrategy, - RefreshTokenStrategy: strategy.CoreStrategy, + h := DeviceCodeTokenEndpointHandler{ + DeviceRateLimitStrategy: strategy, + DeviceCodeStrategy: strategy, + UserCodeStrategy: strategy, + CoreStorage: store, + AccessTokenStrategy: strategy.CoreStrategy, + RefreshTokenStrategy: strategy.CoreStrategy, Config: &fosite.Config{ ScopeStrategy: fosite.HierarchicScopeStrategy, AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy, @@ -558,20 +548,15 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { AccessTokenLifespan: time.Minute, RefreshTokenScopes: []string{"offline"}, } - h := oauth2.GenericCodeTokenEndpointHandler{ - AccessRequestValidator: &DeviceAccessRequestValidator{}, - CodeHandler: &DeviceCodeHandler{ - DeviceRateLimitStrategy: strategy, - DeviceCodeStrategy: strategy, - }, - SessionHandler: &DeviceSessionHandler{ - DeviceCodeStorage: store, - }, - AccessTokenStrategy: strategy.CoreStrategy, - RefreshTokenStrategy: strategy.CoreStrategy, - Config: config, - CoreStorage: store, - TokenRevocationStorage: store, + h := DeviceCodeTokenEndpointHandler{ + DeviceRateLimitStrategy: strategy, + DeviceCodeStrategy: strategy, + UserCodeStrategy: strategy, + AccessTokenStrategy: strategy.CoreStrategy, + RefreshTokenStrategy: strategy.CoreStrategy, + Config: config, + CoreStorage: store, + TokenRevocationStorage: store, } if testCase.setup != nil { @@ -598,8 +583,7 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { var mockTransactional *internal.MockTransactional - var mockCoreStore *internal.MockCoreStorage - var mockDeviceCodeStore *internal.MockDeviceCodeStorage + var mockCoreStore *internal.MockRFC8628CoreStorage var mockDeviceRateLimitStrategy *internal.MockDeviceRateLimitStrategy strategy := hmacshaStrategy deviceStrategy := RFC8628HMACSHAStrategy @@ -636,14 +620,10 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { areq.Form = url.Values{"device_code": {code}} // some storage implementation that has support for transactions, notice the embedded type `storage.Transactional` - type coreTransactionalStore struct { - storage.Transactional - oauth2.CoreStorage - } type deviceTransactionalStore struct { storage.Transactional - DeviceCodeStorage + RFC8628CoreStorage } testCases := []struct { @@ -654,7 +634,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "transaction should be committed successfully if no errors occur", setup: func() { - mockDeviceCodeStore. + mockCoreStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(authreq, nil). @@ -663,7 +643,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockDeviceCodeStore. + mockCoreStore. EXPECT(). InvalidateDeviceCodeSession(gomock.Any(), gomock.Any()). Return(nil). @@ -688,7 +668,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "transaction should be rolled back if `InvalidateDeviceCodeSession` returns an error", setup: func() { - mockDeviceCodeStore. + mockCoreStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(authreq, nil). @@ -697,7 +677,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockDeviceCodeStore. + mockCoreStore. EXPECT(). InvalidateDeviceCodeSession(gomock.Any(), gomock.Any()). Return(errors.New("Whoops, a nasty database error occurred!")). @@ -713,7 +693,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "transaction should be rolled back if `CreateAccessTokenSession` returns an error", setup: func() { - mockDeviceCodeStore. + mockCoreStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(authreq, nil). @@ -722,7 +702,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockDeviceCodeStore. + mockCoreStore. EXPECT(). InvalidateDeviceCodeSession(gomock.Any(), gomock.Any()). Return(nil). @@ -743,7 +723,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "should result in a server error if transaction cannot be created", setup: func() { - mockDeviceCodeStore. + mockCoreStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(authreq, nil). @@ -758,7 +738,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "should result in a server error if transaction cannot be rolled back", setup: func() { - mockDeviceCodeStore. + mockCoreStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(authreq, nil). @@ -767,7 +747,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockDeviceCodeStore. + mockCoreStore. EXPECT(). InvalidateDeviceCodeSession(gomock.Any(), gomock.Any()). Return(errors.New("Whoops, a nasty database error occurred!")). @@ -783,7 +763,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { { description: "should result in a server error if transaction cannot be committed", setup: func() { - mockDeviceCodeStore. + mockCoreStore. EXPECT(). GetDeviceCodeSession(gomock.Any(), gomock.Any(), gomock.Any()). Return(authreq, nil). @@ -792,7 +772,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { EXPECT(). BeginTX(propagatedContext). Return(propagatedContext, nil) - mockDeviceCodeStore. + mockCoreStore. EXPECT(). InvalidateDeviceCodeSession(gomock.Any(), gomock.Any()). Return(nil). @@ -828,24 +808,15 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { defer ctrl.Finish() mockTransactional = internal.NewMockTransactional(ctrl) - mockCoreStore = internal.NewMockCoreStorage(ctrl) - mockDeviceCodeStore = internal.NewMockDeviceCodeStorage(ctrl) + mockCoreStore = internal.NewMockRFC8628CoreStorage(ctrl) mockDeviceRateLimitStrategy = internal.NewMockDeviceRateLimitStrategy(ctrl) testCase.setup() - h := oauth2.GenericCodeTokenEndpointHandler{ - AccessRequestValidator: &DeviceAccessRequestValidator{}, - CodeHandler: &DeviceCodeHandler{ - DeviceRateLimitStrategy: mockDeviceRateLimitStrategy, - DeviceCodeStrategy: &deviceStrategy, - }, - SessionHandler: &DeviceSessionHandler{ - DeviceCodeStorage: deviceTransactionalStore{ - mockTransactional, - mockDeviceCodeStore, - }, - }, - CoreStorage: coreTransactionalStore{ + h := DeviceCodeTokenEndpointHandler{ + DeviceCodeStrategy: &deviceStrategy, + UserCodeStrategy: &deviceStrategy, + DeviceRateLimitStrategy: mockDeviceRateLimitStrategy, + CoreStorage: deviceTransactionalStore{ mockTransactional, mockCoreStore, }, diff --git a/integration/authorize_code_grant_public_client_pkce_test.go b/integration/authorize_code_grant_public_client_pkce_test.go index 14d852547..74426daed 100644 --- a/integration/authorize_code_grant_public_client_pkce_test.go +++ b/integration/authorize_code_grant_public_client_pkce_test.go @@ -32,7 +32,7 @@ func runAuthorizeCodeGrantWithPublicClientAndPKCETest(t *testing.T, strategy int c := new(fosite.Config) c.EnforcePKCE = true c.EnablePKCEPlainChallengeMethod = true - f := compose.Compose(c, fositeStore, strategy, compose.OAuth2AuthorizeExplicitAuthFactory, compose.Oauth2AuthorizeExplicitTokenFactory, compose.OAuth2PKCEFactory, compose.OAuth2TokenIntrospectionFactory) + f := compose.Compose(c, fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2PKCEFactory, compose.OAuth2TokenIntrospectionFactory) ts := mockServer(t, f, &fosite.DefaultSession{}) defer ts.Close() diff --git a/integration/authorize_code_grant_public_client_test.go b/integration/authorize_code_grant_public_client_test.go index 6a517365c..24d8d64bd 100644 --- a/integration/authorize_code_grant_public_client_test.go +++ b/integration/authorize_code_grant_public_client_test.go @@ -27,7 +27,7 @@ func TestAuthorizeCodeFlowWithPublicClient(t *testing.T) { } func runAuthorizeCodeGrantWithPublicClientTest(t *testing.T, strategy interface{}) { - f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitAuthFactory, compose.Oauth2AuthorizeExplicitTokenFactory, compose.OAuth2TokenIntrospectionFactory) + f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2TokenIntrospectionFactory) ts := mockServer(t, f, &fosite.DefaultSession{Subject: "foo-sub"}) defer ts.Close() diff --git a/integration/authorize_code_grant_test.go b/integration/authorize_code_grant_test.go index 9ddb02cc8..13a663c7a 100644 --- a/integration/authorize_code_grant_test.go +++ b/integration/authorize_code_grant_test.go @@ -38,7 +38,7 @@ func TestAuthorizeCodeFlowDupeCode(t *testing.T) { } func runAuthorizeCodeGrantTest(t *testing.T, strategy interface{}) { - f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitAuthFactory, compose.Oauth2AuthorizeExplicitTokenFactory, compose.OAuth2TokenIntrospectionFactory) + f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2TokenIntrospectionFactory) ts := mockServer(t, f, &openid.DefaultSession{Subject: "foo-sub"}) defer ts.Close() @@ -148,7 +148,7 @@ func runAuthorizeCodeGrantTest(t *testing.T, strategy interface{}) { } func runAuthorizeCodeGrantDupeCodeTest(t *testing.T, strategy interface{}) { - f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitAuthFactory, compose.Oauth2AuthorizeExplicitTokenFactory, compose.OAuth2TokenIntrospectionFactory) + f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2TokenIntrospectionFactory) ts := mockServer(t, f, &fosite.DefaultSession{}) defer ts.Close() diff --git a/integration/pushed_authorize_code_grant_test.go b/integration/pushed_authorize_code_grant_test.go index 2aa9714a6..0d9a710d1 100644 --- a/integration/pushed_authorize_code_grant_test.go +++ b/integration/pushed_authorize_code_grant_test.go @@ -30,7 +30,7 @@ func TestPushedAuthorizeCodeFlow(t *testing.T) { } func runPushedAuthorizeCodeGrantTest(t *testing.T, strategy interface{}) { - f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitAuthFactory, compose.Oauth2AuthorizeExplicitTokenFactory, compose.OAuth2TokenIntrospectionFactory, compose.PushedAuthorizeHandlerFactory) + f := compose.Compose(new(fosite.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2TokenIntrospectionFactory, compose.PushedAuthorizeHandlerFactory) ts := mockServer(t, f, &fosite.DefaultSession{Subject: "foo-sub"}) defer ts.Close() From 4ae79b367bb7b5894f13d9970f5eefa48d344998 Mon Sep 17 00:00:00 2001 From: Nikos Date: Wed, 16 Oct 2024 12:44:47 +0300 Subject: [PATCH 24/36] ci: use hydra from branch --- .github/workflows/oidc-conformity.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/oidc-conformity.yml b/.github/workflows/oidc-conformity.yml index 79e5d11ea..2d000eeb2 100644 --- a/.github/workflows/oidc-conformity.yml +++ b/.github/workflows/oidc-conformity.yml @@ -13,8 +13,8 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 2 - repository: ory/hydra - ref: a35e78e364a26c4f87f37d9f545ef10b3ffa468a + repository: nsklikas/hydra + ref: canonical-master - uses: actions/setup-go@v2 with: go-version: "1.21" From 3d5c0713f91bd64a939c1549e90ca3e40b7abb64 Mon Sep 17 00:00:00 2001 From: Nikos Date: Wed, 16 Oct 2024 17:51:48 +0300 Subject: [PATCH 25/36] fix: remove rate limiting implementation --- compose/compose_strategy.go | 6 +- go.mod | 1 - go.sum | 3 - handler/openid/flow_device_auth_test.go | 7 +-- handler/openid/flow_device_token_test.go | 6 +- handler/rfc8628/strategy_hmacsha.go | 74 +----------------------- handler/rfc8628/strategy_hmacsha_test.go | 34 +---------- handler/rfc8628/token_handler.go | 2 +- handler/rfc8628/token_handler_test.go | 6 +- 9 files changed, 13 insertions(+), 126 deletions(-) diff --git a/compose/compose_strategy.go b/compose/compose_strategy.go index 21550ab91..f48ab9e0a 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 ba0423901..ae2581c70 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,6 @@ module github.com/ory/fosite 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 v1.0.0 github.com/go-jose/go-jose/v3 v3.0.3 diff --git a/go.sum b/go.sum index 735d4a191..9585cfb7d 100644 --- a/go.sum +++ b/go.sum @@ -45,7 +45,6 @@ github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd3 github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/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.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -56,8 +55,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= diff --git a/handler/openid/flow_device_auth_test.go b/handler/openid/flow_device_auth_test.go index 3de6aec8a..34bb3bbff 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 25442a74c..dbd7c6963 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 bf8ae2a41..dafe20787 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 } @@ -176,70 +173,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 40554cabd..666a47256 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 bc20f5307..22cc555f7 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 9fd9bc25e..6d65752b9 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) From 54a1ff0507f6d4b495069bb1f53d00eea2bae557 Mon Sep 17 00:00:00 2001 From: Nikos Date: Wed, 16 Oct 2024 19:18:24 +0300 Subject: [PATCH 26/36] fix: make user code creation configurable --- config.go | 6 ++++++ config_default.go | 23 +++++++++++++++++++++++ fosite.go | 1 + handler/rfc8628/strategy_hmacsha.go | 3 ++- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/config.go b/config.go index 24c4151c4..2d74753f8 100644 --- a/config.go +++ b/config.go @@ -51,6 +51,12 @@ type DeviceAndUserCodeLifespanProvider interface { GetDeviceAndUserCodeLifespan(ctx context.Context) time.Duration } +// DeviceAndUserCodeLifespanProvider returns the provider for configuring the device and user code lifespan +type UserCodeProvider interface { + GetUserCodeLength(ctx context.Context) int + GetUserCodeSymbols(ctx context.Context) []rune +} + // ScopeStrategyProvider returns the provider for configuring the scope strategy. type ScopeStrategyProvider interface { // GetScopeStrategy returns the scope strategy. diff --git a/config_default.go b/config_default.go index a73154f08..eb4acce9a 100644 --- a/config_default.go +++ b/config_default.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/go-retryablehttp" "github.com/ory/fosite/token/jwt" + "github.com/ory/x/randx" "github.com/ory/fosite/i18n" ) @@ -229,6 +230,12 @@ type Config struct { // IsPushedAuthorizeEnforced enforces pushed authorization request for /authorize IsPushedAuthorizeEnforced bool + + // UserCodeLength defines the length of the user_code + UserCodeLength int + + // UserCodeSymbols defines the symbols that will be used to construct the user_code + UserCodeSymbols []rune } func (c *Config) GetGlobalSecret(ctx context.Context) ([]byte, error) { @@ -540,3 +547,19 @@ func (c *Config) GetDeviceAuthTokenPollingInterval(ctx context.Context) time.Dur } return c.DeviceAuthTokenPollingInterval } + +// GetUserCodeLength returns configured user_code length +func (c *Config) GetUserCodeLength(ctx context.Context) int { + if c.UserCodeLength == 0 { + return 8 + } + return c.UserCodeLength +} + +// GetDeviceAuthTokenPollingInterval returns configured user_code allowed symbols +func (c *Config) GetUserCodeSymbols(ctx context.Context) []rune { + if c.UserCodeSymbols == nil { + return []rune(randx.AlphaUpper) + } + return c.UserCodeSymbols +} diff --git a/fosite.go b/fosite.go index d5610129f..90c30b4d4 100644 --- a/fosite.go +++ b/fosite.go @@ -148,6 +148,7 @@ type Configurator interface { RevocationHandlersProvider UseLegacyErrorFormatProvider DeviceEndpointHandlersProvider + UserCodeProvider DeviceProvider } diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go index dafe20787..f42b9fdb2 100644 --- a/handler/rfc8628/strategy_hmacsha.go +++ b/handler/rfc8628/strategy_hmacsha.go @@ -103,6 +103,7 @@ type DefaultDeviceStrategy struct { Config interface { fosite.DeviceProvider fosite.DeviceAndUserCodeLifespanProvider + fosite.UserCodeProvider } } @@ -110,7 +111,7 @@ var _ RFC8628CodeStrategy = (*DefaultDeviceStrategy)(nil) // GenerateUserCode generates a user_code func (h *DefaultDeviceStrategy) GenerateUserCode(ctx context.Context) (string, string, error) { - seq, err := randx.RuneSequence(8, []rune(randx.AlphaUpper)) + seq, err := randx.RuneSequence(h.Config.GetUserCodeLength(ctx), h.Config.GetUserCodeSymbols(ctx)) if err != nil { return "", "", err } From 4ca84a3bcf55b7197b2043fb8d7e4fbe8b08cf96 Mon Sep 17 00:00:00 2001 From: Nikos Date: Thu, 17 Oct 2024 11:00:11 +0300 Subject: [PATCH 27/36] refactor: simplify handler and test logic --- device_request_handler.go | 17 +++---- device_request_handler_test.go | 88 ++++++++++++++++++---------------- device_request_test.go | 18 ------- fosite_test.go | 11 +++++ 4 files changed, 68 insertions(+), 66 deletions(-) delete mode 100644 device_request_test.go diff --git a/device_request_handler.go b/device_request_handler.go index 2f3510839..a3421b30c 100644 --- a/device_request_handler.go +++ b/device_request_handler.go @@ -27,7 +27,7 @@ func (f *Fosite) NewDeviceRequest(ctx context.Context, r *http.Request) (_ Devic return request, errorsx.WithStack(ErrInvalidRequest.WithHintf("HTTP method is '%s', expected 'POST'.", r.Method)) } if err := r.ParseForm(); err != nil { - return nil, errorsx.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithWrap(err).WithDebug(err.Error())) + return request, errorsx.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithWrap(err).WithDebug(err.Error())) } if len(r.PostForm) == 0 { return request, errorsx.WithStack(ErrInvalidRequest.WithHint("The POST body can not be empty.")) @@ -44,11 +44,11 @@ func (f *Fosite) NewDeviceRequest(ctx context.Context, r *http.Request) (_ Devic request.Client = client if !client.GetGrantTypes().Has(string(GrantTypeDeviceCode)) { - return nil, errorsx.WithStack(ErrInvalidGrant.WithHint("The requested OAuth 2.0 Client does not have the 'urn:ietf:params:oauth:grant-type:device_code' grant.")) + return request, errorsx.WithStack(ErrInvalidGrant.WithHint("The requested OAuth 2.0 Client does not have the 'urn:ietf:params:oauth:grant-type:device_code' grant.")) } if err := f.validateDeviceScope(ctx, r, request); err != nil { - return nil, err + return request, err } if err := f.validateAudience(ctx, r, request); err != nil { @@ -59,12 +59,13 @@ func (f *Fosite) NewDeviceRequest(ctx context.Context, r *http.Request) (_ Devic } func (f *Fosite) validateDeviceScope(ctx context.Context, r *http.Request, request *DeviceRequest) error { - scope := RemoveEmpty(strings.Split(request.Form.Get("scope"), " ")) - for _, permission := range scope { - if !f.Config.GetScopeStrategy(ctx)(request.Client.GetScopes(), permission) { - return errorsx.WithStack(ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope '%s'.", permission)) + scopes := RemoveEmpty(strings.Split(request.Form.Get("scope"), " ")) + scopeStrategy := f.Config.GetScopeStrategy(ctx) + for _, scope := range scopes { + if !scopeStrategy(request.Client.GetScopes(), scope) { + return errorsx.WithStack(ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope '%s'.", scope)) } } - request.SetRequestedScopes(scope) + request.SetRequestedScopes(scopes) return nil } diff --git a/device_request_handler_test.go b/device_request_handler_test.go index 38cb336f4..6b0d4d117 100644 --- a/device_request_handler_test.go +++ b/device_request_handler_test.go @@ -22,7 +22,17 @@ import ( func TestNewDeviceRequestWithPublicClient(t *testing.T) { ctrl := gomock.NewController(t) store := internal.NewMockStorage(ctrl) - client := &DefaultClient{ID: "client_id"} + deviceClient := &DefaultClient{ID: "client_id"} + deviceClient.Public = true + deviceClient.Scopes = []string{"17", "42"} + deviceClient.Audience = []string{"aud2"} + deviceClient.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + + authCodeClient := &DefaultClient{ID: "client_id_2"} + authCodeClient.Public = true + authCodeClient.Scopes = []string{"17", "42"} + authCodeClient.GrantTypes = []string{"authorization_code"} + defer ctrl.Finish() config := &Config{ScopeStrategy: ExactScopeStrategy, AudienceMatchingStrategy: DefaultAudienceMatchingStrategy} fosite := &Fosite{Store: store, Config: config} @@ -63,10 +73,7 @@ func TestNewDeviceRequestWithPublicClient(t *testing.T) { }, method: "POST", mock: func() { - store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) - client.Public = true - client.Scopes = []string{"17", "42"} - client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(deviceClient, nil) }, expectedError: ErrInvalidScope, }, { @@ -74,29 +81,22 @@ func TestNewDeviceRequestWithPublicClient(t *testing.T) { form: url.Values{ "client_id": {"client_id"}, "scope": {"17 42"}, - "audience": {"aud"}, + "audience": {"random_aud"}, }, method: "POST", mock: func() { - store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) - client.Public = true - client.Scopes = []string{"17", "42"} - client.Audience = []string{"aud2"} - client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(deviceClient, nil) }, expectedError: ErrInvalidRequest, }, { description: "fails because it doesn't have the proper grant", form: url.Values{ - "client_id": {"client_id"}, + "client_id": {"client_id_2"}, "scope": {"17 42"}, }, method: "POST", mock: func() { - store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) - client.Public = true - client.Scopes = []string{"17", "42"} - client.GrantTypes = []string{"authorization_code"} + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id_2")).Return(authCodeClient, nil) }, expectedError: ErrInvalidGrant, }, { @@ -107,10 +107,7 @@ func TestNewDeviceRequestWithPublicClient(t *testing.T) { }, method: "POST", mock: func() { - store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) - client.Public = true - client.Scopes = []string{"17", "42"} - client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(deviceClient, nil) }, }} { t.Run(fmt.Sprintf("case=%d description=%s", k, c.description), func(t *testing.T) { @@ -123,10 +120,8 @@ func TestNewDeviceRequestWithPublicClient(t *testing.T) { } ar, err := fosite.NewDeviceRequest(context.Background(), r) - if c.expectedError != nil { - assert.EqualError(t, err, c.expectedError.Error()) - } else { - require.NoError(t, err) + require.ErrorIs(t, err, c.expectedError) + if c.expectedError == nil { assert.NotNil(t, ar.GetRequestedAt()) } }) @@ -141,6 +136,12 @@ func TestNewDeviceRequestWithClientAuthn(t *testing.T) { defer ctrl.Finish() config := &Config{ClientSecretsHasher: hasher, ScopeStrategy: ExactScopeStrategy, AudienceMatchingStrategy: DefaultAudienceMatchingStrategy} fosite := &Fosite{Store: store, Config: config} + + client.Public = false + client.Secret = []byte("client_secret") + client.Scopes = []string{"foo", "bar"} + client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + for k, c := range []struct { header http.Header form url.Values @@ -148,8 +149,8 @@ func TestNewDeviceRequestWithClientAuthn(t *testing.T) { expectedError error mock func() expect DeviceRequester + description string }{ - // No client authn provided { form: url.Values{ "client_id": {"client_id"}, @@ -159,14 +160,26 @@ func TestNewDeviceRequestWithClientAuthn(t *testing.T) { method: "POST", mock: func() { store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) - client.Public = false - client.Secret = []byte("client_secret") - client.Scopes = []string{"foo", "bar"} - client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} hasher.EXPECT().Compare(gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("")) }, + description: "Should failed becaue no client authn provided.", + }, + { + form: url.Values{ + "client_id": {"client_id2"}, + "scope": {"foo bar"}, + }, + header: http.Header{ + "Authorization": {basicAuth("client_id", "client_secret")}, + }, + expectedError: ErrInvalidRequest, + method: "POST", + mock: func() { + store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) + hasher.EXPECT().Compare(gomock.Any(), gomock.Eq([]byte("client_secret")), gomock.Eq([]byte("client_secret"))).Return(nil) + }, + description: "should fail because different client is used in authn than in form", }, - // success { form: url.Values{ "client_id": {"client_id"}, @@ -178,15 +191,12 @@ func TestNewDeviceRequestWithClientAuthn(t *testing.T) { method: "POST", mock: func() { store.EXPECT().GetClient(gomock.Any(), gomock.Eq("client_id")).Return(client, nil) - client.Public = false - client.Secret = []byte("client_secret") - client.Scopes = []string{"foo", "bar"} - client.GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} hasher.EXPECT().Compare(gomock.Any(), gomock.Eq([]byte("client_secret")), gomock.Eq([]byte("client_secret"))).Return(nil) }, + description: "should succeed", }, } { - t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + t.Run(fmt.Sprintf("case=%d description=%s", k, c.description), func(t *testing.T) { c.mock() r := &http.Request{ Header: c.header, @@ -196,11 +206,9 @@ func TestNewDeviceRequestWithClientAuthn(t *testing.T) { } req, err := fosite.NewDeviceRequest(context.Background(), r) - if c.expectedError != nil { - assert.EqualError(t, err, c.expectedError.Error()) - } else { - require.NoError(t, err) - assert.NotNil(t, req.GetRequestedAt()) + require.ErrorIs(t, err, c.expectedError) + if c.expectedError == nil { + assert.NotZero(t, req.GetRequestedAt()) } }) } diff --git a/device_request_test.go b/device_request_test.go deleted file mode 100644 index 7e67c0529..000000000 --- a/device_request_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright © 2024 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package fosite - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestDeviceRequest(t *testing.T) { - r := NewDeviceRequest() - r.Client = &DefaultClient{} - r.SetRequestedScopes([]string{"17", "42"}) - assert.True(t, r.GetRequestedScopes().Has("17", "42")) - assert.Equal(t, r.Client, r.GetClient()) -} diff --git a/fosite_test.go b/fosite_test.go index 2c86b498a..0a273fdc1 100644 --- a/fosite_test.go +++ b/fosite_test.go @@ -13,6 +13,7 @@ import ( . "github.com/ory/fosite" "github.com/ory/fosite/handler/oauth2" "github.com/ory/fosite/handler/par" + "github.com/ory/fosite/handler/rfc8628" ) func TestAuthorizeEndpointHandlers(t *testing.T) { @@ -25,6 +26,16 @@ func TestAuthorizeEndpointHandlers(t *testing.T) { assert.Equal(t, hs[0], h) } +func TestDeviceAuthorizeEndpointHandlers(t *testing.T) { + h := &rfc8628.DeviceAuthHandler{} + hs := DeviceEndpointHandlers{} + hs.Append(h) + hs.Append(h) + hs.Append(&rfc8628.DeviceAuthHandler{}) + assert.Len(t, hs, 1) + assert.Equal(t, hs[0], h) +} + func TestTokenEndpointHandlers(t *testing.T) { h := &oauth2.AuthorizeExplicitGrantHandler{} hs := TokenEndpointHandlers{} From 675f6f041bc4199dc04c28d7cb3464b5a576b1a1 Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 12 Nov 2024 13:43:18 +0200 Subject: [PATCH 28/36] refactor: merge user and device code storage --- errors.go | 2 + handler/rfc8628/auth_handler.go | 50 +++++------- handler/rfc8628/auth_handler_test.go | 50 +++++++----- handler/rfc8628/storage.go | 31 ++----- handler/rfc8628/token_handler_test.go | 32 ++++++-- integration/helper_setup_test.go | 5 +- internal/device_code_storage.go | 86 -------------------- internal/rfc8628_core_storage.go | 43 ---------- storage/memory.go | 111 +++++++------------------- 9 files changed, 114 insertions(+), 296 deletions(-) delete mode 100644 internal/device_code_storage.go diff --git a/errors.go b/errors.go index 5e324fc55..b986dbc92 100644 --- a/errors.go +++ b/errors.go @@ -25,6 +25,8 @@ var ( ErrInvalidatedAuthorizeCode = stderr.New("Authorization code has ben invalidated") // ErrInvalidatedDeviceCode is an error indicating that a device code has benn used previously. ErrInvalidatedDeviceCode = stderr.New("Device code has been invalidated") + // ErrExistingUserCodeSignature is an error indicating that a row already exists with the provided user_code signature. + ErrExistingUserCodeSignature = stderr.New("User code signature already exists in the database") // ErrSerializationFailure is an error indicating that the transactional capable storage could not guarantee // consistency of Update & Delete operations on the same rows between multiple sessions. ErrSerializationFailure = &RFC6749Error{ diff --git a/handler/rfc8628/auth_handler.go b/handler/rfc8628/auth_handler.go index 70a6af8a4..7ab48739a 100644 --- a/handler/rfc8628/auth_handler.go +++ b/handler/rfc8628/auth_handler.go @@ -10,6 +10,7 @@ import ( "github.com/ory/fosite" "github.com/ory/x/errorsx" + "github.com/pkg/errors" ) // MaxAttempts for retrying the generation of user codes. @@ -30,14 +31,7 @@ type DeviceAuthHandler struct { func (d *DeviceAuthHandler) HandleDeviceEndpointRequest(ctx context.Context, dar fosite.DeviceRequester, resp fosite.DeviceResponder) error { var err error - var deviceCode string - deviceCode, err = d.handleDeviceCode(ctx, dar) - if err != nil { - return err - } - - var userCode string - userCode, err = d.handleUserCode(ctx, dar) + deviceCode, userCode, err := d.handleDeviceAuthSession(ctx, dar) if err != nil { return err } @@ -52,23 +46,15 @@ func (d *DeviceAuthHandler) HandleDeviceEndpointRequest(ctx context.Context, dar return nil } -func (d *DeviceAuthHandler) handleDeviceCode(ctx context.Context, dar fosite.DeviceRequester) (string, error) { - code, signature, err := d.Strategy.GenerateDeviceCode(ctx) - if err != nil { - return "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } +func (d *DeviceAuthHandler) handleDeviceAuthSession(ctx context.Context, dar fosite.DeviceRequester) (string, string, error) { + var userCode, userCodeSignature string - dar.GetSession().SetExpiresAt(fosite.DeviceCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx))) - if err = d.Storage.CreateDeviceCodeSession(ctx, signature, dar.Sanitize(nil)); err != nil { - return "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + deviceCode, deviceCodeSignature, err := d.Strategy.GenerateDeviceCode(ctx) + if err != nil { + return "", "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } - return code, nil -} - -func (d *DeviceAuthHandler) handleUserCode(ctx context.Context, dar fosite.DeviceRequester) (string, error) { - var err error - var userCode, signature string + dar.GetSession().SetExpiresAt(fosite.UserCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx)).Round(time.Second)) // Note: the retries are added here because we need to ensure uniqueness of user codes. // The chances of duplicates should however be diminishing, because they are the same // chance an attacker will be able to hit a valid code with few guesses. However, as @@ -76,17 +62,23 @@ func (d *DeviceAuthHandler) handleUserCode(ctx context.Context, dar fosite.Devic // the chances of hitting a duplicate here can be higher. // Three retries should be plenty, as otherwise the entropy is definitely off. for i := 0; i < MaxAttempts; i++ { - userCode, signature, err = d.Strategy.GenerateUserCode(ctx) + userCode, userCodeSignature, err = d.Strategy.GenerateUserCode(ctx) if err != nil { - return "", err + return "", "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } - dar.GetSession().SetExpiresAt(fosite.UserCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx)).Round(time.Second)) - if err = d.Storage.CreateUserCodeSession(ctx, signature, dar.Sanitize(nil)); err == nil { - return userCode, nil + err = d.Storage.CreateDeviceAuthSession(ctx, deviceCodeSignature, userCodeSignature, dar.Sanitize(nil)) + if err == nil { + break + } + if !errors.Is(err, fosite.ErrExistingUserCodeSignature) { + return "", "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } } - errMsg := fmt.Sprintf("Exceeded user-code generation max attempts %v: %s", MaxAttempts, err.Error()) - return "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(errMsg)) + if err != nil { + errMsg := fmt.Sprintf("Exceeded user-code generation max attempts %v: %s", MaxAttempts, err.Error()) + return "", "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(errMsg)) + } + return deviceCode, userCode, nil } diff --git a/handler/rfc8628/auth_handler_test.go b/handler/rfc8628/auth_handler_test.go index bbe2d525b..514b072ea 100644 --- a/handler/rfc8628/auth_handler_test.go +++ b/handler/rfc8628/auth_handler_test.go @@ -85,20 +85,15 @@ func Test_HandleDeviceEndpointRequestWithRetry(t *testing.T) { EXPECT(). GenerateDeviceCode(ctx). Return("deviceCode", "signature", nil) - mockRFC8628CoreStorage. - EXPECT(). - CreateDeviceCodeSession(ctx, "signature", gomock.Any()). - Return(nil) mockRFC8628CodeStrategy. EXPECT(). GenerateUserCode(ctx). - Return("userCode", "signature", nil). + Return("userCode", "signature2", nil). Times(1) mockRFC8628CoreStorage. EXPECT(). - CreateUserCodeSession(ctx, "signature", gomock.Any()). - Return(nil). - Times(1) + CreateDeviceAuthSession(ctx, "signature", "signature2", gomock.Any()). + Return(nil) }, check: func(t *testing.T, resp *fosite.DeviceResponse) { assert.Equal(t, "userCode", resp.GetUserCode()) @@ -111,10 +106,6 @@ func Test_HandleDeviceEndpointRequestWithRetry(t *testing.T) { EXPECT(). GenerateDeviceCode(ctx). Return("deviceCode", "signature", nil) - mockRFC8628CoreStorage. - EXPECT(). - CreateDeviceCodeSession(ctx, "signature", gomock.Any()). - Return(nil) gomock.InOrder( mockRFC8628CodeStrategy. EXPECT(). @@ -122,15 +113,15 @@ func Test_HandleDeviceEndpointRequestWithRetry(t *testing.T) { Return("duplicatedUserCode", "duplicatedSignature", nil), mockRFC8628CoreStorage. EXPECT(). - CreateUserCodeSession(ctx, "duplicatedSignature", gomock.Any()). - Return(errors.New("unique constraint violation")), + CreateDeviceAuthSession(ctx, "signature", "duplicatedSignature", gomock.Any()). + Return(fosite.ErrExistingUserCodeSignature), mockRFC8628CodeStrategy. EXPECT(). GenerateUserCode(ctx). Return("uniqueUserCode", "uniqueSignature", nil), mockRFC8628CoreStorage. EXPECT(). - CreateUserCodeSession(ctx, "uniqueSignature", gomock.Any()). + CreateDeviceAuthSession(ctx, "signature", "uniqueSignature", gomock.Any()). Return(nil), ) }, @@ -145,10 +136,6 @@ func Test_HandleDeviceEndpointRequestWithRetry(t *testing.T) { EXPECT(). GenerateDeviceCode(ctx). Return("deviceCode", "signature", nil) - mockRFC8628CoreStorage. - EXPECT(). - CreateDeviceCodeSession(ctx, "signature", gomock.Any()). - Return(nil) mockRFC8628CodeStrategy. EXPECT(). GenerateUserCode(ctx). @@ -156,8 +143,8 @@ func Test_HandleDeviceEndpointRequestWithRetry(t *testing.T) { Times(rfc8628.MaxAttempts) mockRFC8628CoreStorage. EXPECT(). - CreateUserCodeSession(ctx, "duplicatedSignature", gomock.Any()). - Return(errors.New("unique constraint violation")). + CreateDeviceAuthSession(ctx, "signature", "duplicatedSignature", gomock.Any()). + Return(fosite.ErrExistingUserCodeSignature). Times(rfc8628.MaxAttempts) }, check: func(t *testing.T, resp *fosite.DeviceResponse) { @@ -165,6 +152,27 @@ func Test_HandleDeviceEndpointRequestWithRetry(t *testing.T) { }, expectError: fosite.ErrServerError, }, + { + description: "should fail if another error is returned", + setup: func() { + mockRFC8628CodeStrategy. + EXPECT(). + GenerateDeviceCode(ctx). + Return("deviceCode", "signature", nil) + mockRFC8628CodeStrategy. + EXPECT(). + GenerateUserCode(ctx). + Return("userCode", "userCodeSignature", nil) + mockRFC8628CoreStorage. + EXPECT(). + CreateDeviceAuthSession(ctx, "signature", "userCodeSignature", gomock.Any()). + Return(errors.New("some error")) + }, + check: func(t *testing.T, resp *fosite.DeviceResponse) { + assert.Empty(t, resp.GetUserCode()) + }, + expectError: fosite.ErrServerError, + }, } for _, testCase := range testCases { diff --git a/handler/rfc8628/storage.go b/handler/rfc8628/storage.go index 8ae1b35eb..e15dc97d3 100644 --- a/handler/rfc8628/storage.go +++ b/handler/rfc8628/storage.go @@ -12,16 +12,15 @@ import ( // RFC8628CoreStorage is the storage needed for the DeviceAuthHandler type RFC8628CoreStorage interface { - DeviceCodeStorage - UserCodeStorage + DeviceAuthStorage oauth2.AccessTokenStorage oauth2.RefreshTokenStorage } -// DeviceCodeStorage handles the device_code storage -type DeviceCodeStorage interface { - // CreateDeviceCodeSession stores the device request for a given device code. - CreateDeviceCodeSession(ctx context.Context, signature string, request fosite.Requester) (err error) +// DeviceAuthStorage handles the device auth session storage +type DeviceAuthStorage interface { + // CreateDeviceAuthSession stores the device auth request session. + CreateDeviceAuthSession(ctx context.Context, deviceCodeSignature, userCodeSignature string, request fosite.Requester) (err error) // GetDeviceCodeSession hydrates the session based on the given device code and returns the device request. // If the device code has been invalidated with `InvalidateDeviceCodeSession`, this @@ -30,26 +29,8 @@ type DeviceCodeStorage interface { // Make sure to also return the fosite.Requester value when returning the fosite.ErrInvalidatedDeviceCode error! GetDeviceCodeSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) - // InvalidateDeviceCodeSession is called when a device code is being used. The state of the user + // InvalidateDeviceCodeSession is called when a device code is being used. The state of the device // code should be set to invalid and consecutive requests to GetDeviceCodeSession should return the // ErrInvalidatedDeviceCode error. InvalidateDeviceCodeSession(ctx context.Context, signature string) (err error) } - -// UserCodeStorage handles the user_code storage -type UserCodeStorage interface { - // CreateUserCodeSession stores the device request for a given user code. - CreateUserCodeSession(ctx context.Context, signature string, request fosite.Requester) (err error) - - // GetUserCodeSession hydrates the session based on the given user code and returns the device request. - // If the user code has been invalidated with `InvalidateUserCodeSession`, this - // method should return the ErrInvalidatedUserCode error. - // - // Make sure to also return the fosite.Requester value when returning the fosite.ErrInvalidatedUserCode error! - GetUserCodeSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) - - // InvalidateUserCodeSession is called when a user code is being used. The state of the user - // code should be set to invalid and consecutive requests to GetUserCodeSession should return the - // ErrInvalidatedUserCode error. - InvalidateUserCodeSession(ctx context.Context, signature string) (err error) -} diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index 6d65752b9..c60bb40ce 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -154,9 +154,11 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) + _, userCodeSignature, err := strategy.GenerateUserCode(context.TODO()) + require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceAuthSession(context.TODO(), signature, userCodeSignature, authreq)) }, expectErr: fosite.ErrAuthorizationPending, }, @@ -192,9 +194,11 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) + _, userCodeSignature, err := strategy.GenerateUserCode(context.TODO()) + require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceAuthSession(context.TODO(), signature, userCodeSignature, authreq)) }, expectErr: fosite.ErrDeviceExpiredToken, }, @@ -227,9 +231,11 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { token, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) + _, userCodeSignature, err := strategy.GenerateUserCode(context.TODO()) + require.NoError(t, err) areq.Form = url.Values{"device_code": {token}} - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceAuthSession(context.TODO(), signature, userCodeSignature, authreq)) }, expectErr: fosite.ErrInvalidGrant, }, @@ -263,9 +269,11 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { token, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) + _, userCodeSignature, err := strategy.GenerateUserCode(context.TODO()) + require.NoError(t, err) areq.Form = url.Values{"device_code": {token}} - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceAuthSession(context.TODO(), signature, userCodeSignature, authreq)) }, }, } @@ -342,9 +350,11 @@ func TestDeviceUserCode_HandleTokenEndpointRequest_RateLimiting(t *testing.T) { token, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) + _, userCodeSignature, err := strategy.GenerateUserCode(context.TODO()) + require.NoError(t, err) areq.Form = url.Values{"device_code": {token}} - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceAuthSession(context.TODO(), signature, userCodeSignature, authreq)) err = h.HandleTokenEndpointRequest(context.Background(), areq) require.NoError(t, err, "%+v", err) err = h.HandleTokenEndpointRequest(context.Background(), areq) @@ -441,9 +451,11 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest, _ *fosite.Config) { code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) + _, userCodeSignature, err := strategy.GenerateUserCode(context.TODO()) + require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceAuthSession(context.TODO(), signature, userCodeSignature, authreq)) }, check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) @@ -483,9 +495,11 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { config.RefreshTokenScopes = []string{} code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) + _, userCodeSignature, err := strategy.GenerateUserCode(context.TODO()) + require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceAuthSession(context.TODO(), signature, userCodeSignature, authreq)) }, check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) @@ -524,9 +538,11 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest, config *fosite.Config) { code, signature, err := strategy.GenerateDeviceCode(context.TODO()) require.NoError(t, err) + _, userCodeSignature, err := strategy.GenerateUserCode(context.TODO()) + require.NoError(t, err) areq.Form.Add("device_code", code) - require.NoError(t, store.CreateDeviceCodeSession(context.TODO(), signature, authreq)) + require.NoError(t, store.CreateDeviceAuthSession(context.TODO(), signature, userCodeSignature, authreq)) }, check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.AccessToken) diff --git a/integration/helper_setup_test.go b/integration/helper_setup_test.go index 432fe58ea..b7a6ea83a 100644 --- a/integration/helper_setup_test.go +++ b/integration/helper_setup_test.go @@ -123,9 +123,8 @@ var fositeStore = &storage.MemoryStore{ AccessTokenRequestIDs: map[string]string{}, RefreshTokenRequestIDs: map[string]string{}, PARSessions: map[string]fosite.AuthorizeRequester{}, - DeviceCodes: map[string]fosite.Requester{}, - UserCodes: map[string]fosite.Requester{}, - DeviceCodesRequestIDs: map[string]string{}, + DeviceAuths: map[string]fosite.Requester{}, + DeviceCodesRequestIDs: map[string]storage.DeviceAuthPair{}, UserCodesRequestIDs: map[string]string{}, } diff --git a/internal/device_code_storage.go b/internal/device_code_storage.go deleted file mode 100644 index d43630445..000000000 --- a/internal/device_code_storage.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright © 2024 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ory/fosite/handler/rfc8628 (interfaces: DeviceCodeStorage) -// -// Generated by this command: -// -// mockgen -package internal -destination internal/device_code_storage.go github.com/ory/fosite/handler/rfc8628 DeviceCodeStorage -// -// Package internal is a generated GoMock package. -package internal - -import ( - context "context" - reflect "reflect" - - fosite "github.com/ory/fosite" - gomock "go.uber.org/mock/gomock" -) - -// MockDeviceCodeStorage is a mock of DeviceCodeStorage interface. -type MockDeviceCodeStorage struct { - ctrl *gomock.Controller - recorder *MockDeviceCodeStorageMockRecorder -} - -// MockDeviceCodeStorageMockRecorder is the mock recorder for MockDeviceCodeStorage. -type MockDeviceCodeStorageMockRecorder struct { - mock *MockDeviceCodeStorage -} - -// NewMockDeviceCodeStorage creates a new mock instance. -func NewMockDeviceCodeStorage(ctrl *gomock.Controller) *MockDeviceCodeStorage { - mock := &MockDeviceCodeStorage{ctrl: ctrl} - mock.recorder = &MockDeviceCodeStorageMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockDeviceCodeStorage) EXPECT() *MockDeviceCodeStorageMockRecorder { - return m.recorder -} - -// CreateDeviceCodeSession mocks base method. -func (m *MockDeviceCodeStorage) CreateDeviceCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateDeviceCodeSession", arg0, arg1, arg2) - ret0, _ := ret[0].(error) - return ret0 -} - -// CreateDeviceCodeSession indicates an expected call of CreateDeviceCodeSession. -func (mr *MockDeviceCodeStorageMockRecorder) CreateDeviceCodeSession(arg0, arg1, arg2 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDeviceCodeSession", reflect.TypeOf((*MockDeviceCodeStorage)(nil).CreateDeviceCodeSession), arg0, arg1, arg2) -} - -// GetDeviceCodeSession mocks base method. -func (m *MockDeviceCodeStorage) GetDeviceCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDeviceCodeSession", arg0, arg1, arg2) - ret0, _ := ret[0].(fosite.Requester) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetDeviceCodeSession indicates an expected call of GetDeviceCodeSession. -func (mr *MockDeviceCodeStorageMockRecorder) GetDeviceCodeSession(arg0, arg1, arg2 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeviceCodeSession", reflect.TypeOf((*MockDeviceCodeStorage)(nil).GetDeviceCodeSession), arg0, arg1, arg2) -} - -// InvalidateDeviceCodeSession mocks base method. -func (m *MockDeviceCodeStorage) InvalidateDeviceCodeSession(arg0 context.Context, arg1 string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InvalidateDeviceCodeSession", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// InvalidateDeviceCodeSession indicates an expected call of InvalidateDeviceCodeSession. -func (mr *MockDeviceCodeStorageMockRecorder) InvalidateDeviceCodeSession(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateDeviceCodeSession", reflect.TypeOf((*MockDeviceCodeStorage)(nil).InvalidateDeviceCodeSession), arg0, arg1) -} diff --git a/internal/rfc8628_core_storage.go b/internal/rfc8628_core_storage.go index ab021b950..30229bc92 100644 --- a/internal/rfc8628_core_storage.go +++ b/internal/rfc8628_core_storage.go @@ -86,20 +86,6 @@ func (mr *MockRFC8628CoreStorageMockRecorder) CreateRefreshTokenSession(ctx, sig return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRefreshTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateRefreshTokenSession), ctx, signature, accessSignature, request) } -// CreateUserCodeSession mocks base method. -func (m *MockRFC8628CoreStorage) CreateUserCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Requester) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateUserCodeSession", arg0, arg1, arg2) - ret0, _ := ret[0].(error) - return ret0 -} - -// CreateUserCodeSession indicates an expected call of CreateUserCodeSession. -func (mr *MockRFC8628CoreStorageMockRecorder) CreateUserCodeSession(arg0, arg1, arg2 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUserCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).CreateUserCodeSession), arg0, arg1, arg2) -} - // DeleteAccessTokenSession mocks base method. func (m *MockRFC8628CoreStorage) DeleteAccessTokenSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() @@ -173,21 +159,6 @@ func (mr *MockRFC8628CoreStorageMockRecorder) GetRefreshTokenSession(ctx, signat return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRefreshTokenSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetRefreshTokenSession), ctx, signature, session) } -// GetUserCodeSession mocks base method. -func (m *MockRFC8628CoreStorage) GetUserCodeSession(arg0 context.Context, arg1 string, arg2 fosite.Session) (fosite.Requester, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUserCodeSession", arg0, arg1, arg2) - ret0, _ := ret[0].(fosite.Requester) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUserCodeSession indicates an expected call of GetUserCodeSession. -func (mr *MockRFC8628CoreStorageMockRecorder) GetUserCodeSession(arg0, arg1, arg2 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).GetUserCodeSession), arg0, arg1, arg2) -} - // InvalidateDeviceCodeSession mocks base method. func (m *MockRFC8628CoreStorage) InvalidateDeviceCodeSession(ctx context.Context, signature string) error { m.ctrl.T.Helper() @@ -215,17 +186,3 @@ func (mr *MockRFC8628CoreStorageMockRecorder) RotateRefreshToken(ctx, requestID, mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RotateRefreshToken", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).RotateRefreshToken), ctx, requestID, refreshTokenSignature) } - -// InvalidateUserCodeSession mocks base method. -func (m *MockRFC8628CoreStorage) InvalidateUserCodeSession(arg0 context.Context, arg1 string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InvalidateUserCodeSession", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// InvalidateUserCodeSession indicates an expected call of InvalidateUserCodeSession. -func (mr *MockRFC8628CoreStorageMockRecorder) InvalidateUserCodeSession(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InvalidateUserCodeSession", reflect.TypeOf((*MockRFC8628CoreStorage)(nil).InvalidateUserCodeSession), arg0, arg1) -} diff --git a/storage/memory.go b/storage/memory.go index e6a06b5cd..31ba4bc68 100644 --- a/storage/memory.go +++ b/storage/memory.go @@ -36,21 +36,25 @@ type PublicKeyScopes struct { Scopes []string } +type DeviceAuthPair struct { + d string + u string +} + type MemoryStore struct { Clients map[string]fosite.Client AuthorizeCodes map[string]StoreAuthorizeCode IDSessions map[string]fosite.Requester AccessTokens map[string]fosite.Requester RefreshTokens map[string]StoreRefreshToken - DeviceCodes map[string]fosite.Requester - UserCodes map[string]fosite.Requester + DeviceAuths map[string]fosite.Requester PKCES map[string]fosite.Requester Users map[string]MemoryUserRelation BlacklistedJTIs map[string]time.Time // In-memory request ID to token signatures AccessTokenRequestIDs map[string]string RefreshTokenRequestIDs map[string]string - DeviceCodesRequestIDs map[string]string + DeviceCodesRequestIDs map[string]DeviceAuthPair UserCodesRequestIDs map[string]string // Public keys to check signature in auth grant jwt assertion. IssuerPublicKeys map[string]IssuerPublicKeys @@ -61,15 +65,13 @@ type MemoryStore struct { idSessionsMutex sync.RWMutex accessTokensMutex sync.RWMutex refreshTokensMutex sync.RWMutex - userCodesMutex sync.RWMutex - deviceCodesMutex sync.RWMutex + deviceAuthsMutex sync.RWMutex pkcesMutex sync.RWMutex usersMutex sync.RWMutex blacklistedJTIsMutex sync.RWMutex accessTokenRequestIDsMutex sync.RWMutex refreshTokenRequestIDsMutex sync.RWMutex - userCodesRequestIDsMutex sync.RWMutex - deviceCodesRequestIDsMutex sync.RWMutex + deviceAuthsRequestIDsMutex sync.RWMutex issuerPublicKeysMutex sync.RWMutex parSessionsMutex sync.RWMutex } @@ -81,13 +83,12 @@ func NewMemoryStore() *MemoryStore { IDSessions: make(map[string]fosite.Requester), AccessTokens: make(map[string]fosite.Requester), RefreshTokens: make(map[string]StoreRefreshToken), - DeviceCodes: make(map[string]fosite.Requester), - UserCodes: make(map[string]fosite.Requester), + DeviceAuths: make(map[string]fosite.Requester), PKCES: make(map[string]fosite.Requester), Users: make(map[string]MemoryUserRelation), AccessTokenRequestIDs: make(map[string]string), RefreshTokenRequestIDs: make(map[string]string), - DeviceCodesRequestIDs: make(map[string]string), + DeviceCodesRequestIDs: make(map[string]DeviceAuthPair), UserCodesRequestIDs: make(map[string]string), BlacklistedJTIs: make(map[string]time.Time), IssuerPublicKeys: make(map[string]IssuerPublicKeys), @@ -153,11 +154,10 @@ func NewExampleStore() *MemoryStore { AccessTokens: map[string]fosite.Requester{}, RefreshTokens: map[string]StoreRefreshToken{}, PKCES: map[string]fosite.Requester{}, - DeviceCodes: make(map[string]fosite.Requester), - UserCodes: make(map[string]fosite.Requester), + DeviceAuths: make(map[string]fosite.Requester), AccessTokenRequestIDs: map[string]string{}, RefreshTokenRequestIDs: map[string]string{}, - DeviceCodesRequestIDs: make(map[string]string), + DeviceCodesRequestIDs: make(map[string]DeviceAuthPair), UserCodesRequestIDs: make(map[string]string), IssuerPublicKeys: map[string]IssuerPublicKeys{}, PARSessions: map[string]fosite.AuthorizeRequester{}, @@ -520,41 +520,25 @@ func (s *MemoryStore) RotateRefreshToken(ctx context.Context, requestID string, return s.RevokeAccessToken(ctx, requestID) } -// CreateDeviceCodeSession stores the device code session -func (s *MemoryStore) CreateDeviceCodeSession(_ context.Context, signature string, req fosite.Requester) error { - // We first lock accessTokenRequestIDsMutex and then accessTokensMutex because this is the same order - // locking happens in RevokeAccessToken and using the same order prevents deadlocks. - s.deviceCodesRequestIDsMutex.Lock() - defer s.deviceCodesRequestIDsMutex.Unlock() - s.deviceCodesMutex.Lock() - defer s.deviceCodesMutex.Unlock() - - s.DeviceCodes[signature] = req - s.DeviceCodesRequestIDs[req.GetID()] = signature - return nil -} - -// UpdateDeviceCodeSession updates the device code session -func (s *MemoryStore) UpdateDeviceCodeSession(_ context.Context, signature string, req fosite.Requester) error { - s.deviceCodesRequestIDsMutex.Lock() - defer s.deviceCodesRequestIDsMutex.Unlock() - s.deviceCodesMutex.Lock() - defer s.deviceCodesMutex.Unlock() +// CreateDeviceAuthSession stores the device auth session +func (s *MemoryStore) CreateDeviceAuthSession(_ context.Context, deviceCodeSignature, userCodeSignature string, req fosite.Requester) error { + s.deviceAuthsRequestIDsMutex.Lock() + defer s.deviceAuthsRequestIDsMutex.Unlock() + s.deviceAuthsMutex.Lock() + defer s.deviceAuthsMutex.Unlock() - // Only update if exist - if _, exists := s.DeviceCodes[signature]; exists { - s.DeviceCodes[signature] = req - s.DeviceCodesRequestIDs[req.GetID()] = signature - } + s.DeviceAuths[deviceCodeSignature] = req + s.DeviceAuths[userCodeSignature] = req + s.DeviceCodesRequestIDs[req.GetID()] = DeviceAuthPair{d: deviceCodeSignature, u: userCodeSignature} return nil } // GetDeviceCodeSession gets the device code session func (s *MemoryStore) GetDeviceCodeSession(_ context.Context, signature string, _ fosite.Session) (fosite.Requester, error) { - s.deviceCodesMutex.RLock() - defer s.deviceCodesMutex.RUnlock() + s.deviceAuthsMutex.RLock() + defer s.deviceAuthsMutex.RUnlock() - rel, ok := s.DeviceCodes[signature] + rel, ok := s.DeviceAuths[signature] if !ok { return nil, fosite.ErrNotFound } @@ -563,46 +547,11 @@ func (s *MemoryStore) GetDeviceCodeSession(_ context.Context, signature string, // InvalidateDeviceCodeSession invalidates the device code session func (s *MemoryStore) InvalidateDeviceCodeSession(_ context.Context, code string) error { - s.deviceCodesRequestIDsMutex.Lock() - defer s.deviceCodesRequestIDsMutex.Unlock() - s.deviceCodesMutex.Lock() - defer s.deviceCodesMutex.Unlock() - - delete(s.DeviceCodes, code) - return nil -} - -// CreateUserCodeSession stores the user code session -func (s *MemoryStore) CreateUserCodeSession(_ context.Context, signature string, req fosite.Requester) error { - s.userCodesRequestIDsMutex.Lock() - defer s.userCodesRequestIDsMutex.Unlock() - s.userCodesMutex.Lock() - defer s.userCodesMutex.Unlock() - - s.UserCodes[signature] = req - s.UserCodesRequestIDs[req.GetID()] = signature - return nil -} - -// GetUserCodeSession gets the user code session -func (s *MemoryStore) GetUserCodeSession(_ context.Context, signature string, _ fosite.Session) (fosite.Requester, error) { - s.userCodesMutex.RLock() - defer s.userCodesMutex.RUnlock() - - rel, ok := s.UserCodes[signature] - if !ok { - return nil, fosite.ErrNotFound - } - return rel, nil -} - -// GetUserCodeSession invalidates the user code session -func (s *MemoryStore) InvalidateUserCodeSession(_ context.Context, code string) error { - s.userCodesRequestIDsMutex.Lock() - defer s.userCodesRequestIDsMutex.Unlock() - s.userCodesMutex.Lock() - defer s.userCodesMutex.Unlock() + s.deviceAuthsRequestIDsMutex.Lock() + defer s.deviceAuthsRequestIDsMutex.Unlock() + s.deviceAuthsMutex.Lock() + defer s.deviceAuthsMutex.Unlock() - delete(s.UserCodes, code) + delete(s.DeviceAuths, code) return nil } From f7ed555c62a02c0ff9e788b6ab6f2b3081c7ca7b Mon Sep 17 00:00:00 2001 From: Nikos Date: Fri, 15 Nov 2024 12:11:47 +0200 Subject: [PATCH 29/36] refactor: enhance deviceRequest struct --- device_request.go | 29 +++++- device_write_test.go | 2 +- handler/rfc8628/auth_handler.go | 2 +- handler/rfc8628/storage.go | 4 +- handler/rfc8628/strategy.go | 15 ++- handler/rfc8628/strategy_hmacsha.go | 81 +--------------- handler/rfc8628/strategy_hmacsha_test.go | 30 +++--- handler/rfc8628/token_handler.go | 22 ++--- handler/rfc8628/token_handler_test.go | 94 ++++++++----------- .../authorize_device_grant_request_test.go | 13 +-- integration/helper_setup_test.go | 2 +- oauth2.go | 6 ++ storage/memory.go | 10 +- 13 files changed, 128 insertions(+), 182 deletions(-) diff --git a/device_request.go b/device_request.go index 0b243b015..ef26c5d84 100644 --- a/device_request.go +++ b/device_request.go @@ -3,14 +3,41 @@ package fosite +type UserCodeState int16 + +const ( + // User code is active + UserCodeUnused = UserCodeState(0) + // User code has been accepted + UserCodeAccepted = UserCodeState(1) + // User code has been rejected + UserCodeRejected = UserCodeState(2) +) + // DeviceRequest is an implementation of DeviceRequester type DeviceRequest struct { + UserCodeState UserCodeState Request } +func (d *DeviceRequest) GetUserCodeState() UserCodeState { + return d.UserCodeState +} + +func (d *DeviceRequest) SetUserCodeState(state UserCodeState) { + d.UserCodeState = state +} + +func (d *DeviceRequest) Sanitize(allowedParameters []string) Requester { + r, _ := d.Request.Sanitize(allowedParameters).(*Request) + d.Request = *r + return d +} + // NewDeviceRequest returns a new device request func NewDeviceRequest() *DeviceRequest { return &DeviceRequest{ - Request: *NewRequest(), + UserCodeState: UserCodeUnused, + Request: *NewRequest(), } } diff --git a/device_write_test.go b/device_write_test.go index fc8ade099..5eae5e067 100644 --- a/device_write_test.go +++ b/device_write_test.go @@ -26,7 +26,7 @@ func TestWriteDeviceUserResponse(t *testing.T) { ctx := context.Background() rw := httptest.NewRecorder() - ar := &Request{} + ar := &DeviceRequest{} resp := &DeviceResponse{} resp.SetUserCode("AAAA") resp.SetDeviceCode("BBBB") diff --git a/handler/rfc8628/auth_handler.go b/handler/rfc8628/auth_handler.go index 7ab48739a..627e21700 100644 --- a/handler/rfc8628/auth_handler.go +++ b/handler/rfc8628/auth_handler.go @@ -67,7 +67,7 @@ func (d *DeviceAuthHandler) handleDeviceAuthSession(ctx context.Context, dar fos return "", "", errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } - err = d.Storage.CreateDeviceAuthSession(ctx, deviceCodeSignature, userCodeSignature, dar.Sanitize(nil)) + err = d.Storage.CreateDeviceAuthSession(ctx, deviceCodeSignature, userCodeSignature, dar.Sanitize(nil).(fosite.DeviceRequester)) if err == nil { break } diff --git a/handler/rfc8628/storage.go b/handler/rfc8628/storage.go index e15dc97d3..dea0b6a12 100644 --- a/handler/rfc8628/storage.go +++ b/handler/rfc8628/storage.go @@ -20,14 +20,14 @@ type RFC8628CoreStorage interface { // DeviceAuthStorage handles the device auth session storage type DeviceAuthStorage interface { // CreateDeviceAuthSession stores the device auth request session. - CreateDeviceAuthSession(ctx context.Context, deviceCodeSignature, userCodeSignature string, request fosite.Requester) (err error) + CreateDeviceAuthSession(ctx context.Context, deviceCodeSignature, userCodeSignature string, request fosite.DeviceRequester) (err error) // GetDeviceCodeSession hydrates the session based on the given device code and returns the device request. // If the device code has been invalidated with `InvalidateDeviceCodeSession`, this // method should return the ErrInvalidatedDeviceCode error. // // Make sure to also return the fosite.Requester value when returning the fosite.ErrInvalidatedDeviceCode error! - GetDeviceCodeSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) + GetDeviceCodeSession(ctx context.Context, signature string, session fosite.Session) (request fosite.DeviceRequester, err error) // InvalidateDeviceCodeSession is called when a device code is being used. The state of the device // code should be set to invalid and consecutive requests to GetDeviceCodeSession should return the diff --git a/handler/rfc8628/strategy.go b/handler/rfc8628/strategy.go index 67ca28084..cd32bb533 100644 --- a/handler/rfc8628/strategy.go +++ b/handler/rfc8628/strategy.go @@ -18,19 +18,30 @@ type RFC8628CodeStrategy interface { // DeviceRateLimitStrategy handles the rate limiting strategy type DeviceRateLimitStrategy interface { + // ShouldRateLimit checks whether the token request should be rate-limited ShouldRateLimit(ctx context.Context, code string) (bool, error) } // DeviceCodeStrategy handles the device_code strategy type DeviceCodeStrategy interface { + // DeviceCodeSignature calculates the signature of a device_code DeviceCodeSignature(ctx context.Context, code string) (signature string, err error) + + // GenerateDeviceCode generates a new device code and signature GenerateDeviceCode(ctx context.Context) (code string, signature string, err error) - ValidateDeviceCode(ctx context.Context, r fosite.Requester, code string) (err error) + + // ValidateDeviceCode validates the device_code + ValidateDeviceCode(ctx context.Context, r fosite.DeviceRequester, code string) (err error) } // UserCodeStrategy handles the user_code strategy type UserCodeStrategy interface { + // UserCodeSignature calculates the signature of a user_code UserCodeSignature(ctx context.Context, code string) (signature string, err error) + + // GenerateUserCode generates a new user code and signature GenerateUserCode(ctx context.Context) (code string, signature string, err error) - ValidateUserCode(ctx context.Context, r fosite.Requester, code string) (err error) + + // ValidateUserCode validates the user_code + ValidateUserCode(ctx context.Context, r fosite.DeviceRequester, code string) (err error) } diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go index f42b9fdb2..43e7ca4fa 100644 --- a/handler/rfc8628/strategy_hmacsha.go +++ b/handler/rfc8628/strategy_hmacsha.go @@ -8,8 +8,6 @@ import ( "strings" "time" - "github.com/mohae/deepcopy" - "github.com/ory/x/errorsx" "github.com/ory/x/randx" @@ -20,83 +18,6 @@ import ( const POLLING_RATE_LIMITING_LEEWAY = 200 * time.Millisecond -// DeviceFlowSession is a fosite.Session container specific for the device flow. -type DeviceFlowSession interface { - // GetBrowserFlowCompleted returns the flag indicating whether user has completed the browser flow or not. - GetBrowserFlowCompleted() bool - - // SetBrowserFlowCompleted allows client to mark user has completed the browser flow. - SetBrowserFlowCompleted(flag bool) - - fosite.Session -} - -// DefaultDeviceFlowSession is a DeviceFlowSession implementation for the device flow. -type DefaultDeviceFlowSession struct { - ExpiresAt map[fosite.TokenType]time.Time `json:"expires_at"` - Username string `json:"username"` - Subject string `json:"subject"` - Extra map[string]interface{} `json:"extra"` - BrowserFlowCompleted bool `json:"browser_flow_completed"` -} - -func (s *DefaultDeviceFlowSession) SetExpiresAt(key fosite.TokenType, exp time.Time) { - if s.ExpiresAt == nil { - s.ExpiresAt = make(map[fosite.TokenType]time.Time) - } - s.ExpiresAt[key] = exp -} - -func (s *DefaultDeviceFlowSession) GetExpiresAt(key fosite.TokenType) time.Time { - if s.ExpiresAt == nil { - s.ExpiresAt = make(map[fosite.TokenType]time.Time) - } - - if _, ok := s.ExpiresAt[key]; !ok { - return time.Time{} - } - return s.ExpiresAt[key] -} - -func (s *DefaultDeviceFlowSession) GetUsername() string { - if s == nil { - return "" - } - return s.Username -} - -func (s *DefaultDeviceFlowSession) SetSubject(subject string) { - s.Subject = subject -} - -func (s *DefaultDeviceFlowSession) GetSubject() string { - if s == nil { - return "" - } - - return s.Subject -} - -func (s *DefaultDeviceFlowSession) Clone() fosite.Session { - if s == nil { - return nil - } - - return deepcopy.Copy(s).(fosite.Session) -} - -func (s *DefaultDeviceFlowSession) GetBrowserFlowCompleted() bool { - if s == nil { - return false - } - - return s.BrowserFlowCompleted -} - -func (s *DefaultDeviceFlowSession) SetBrowserFlowCompleted(flag bool) { - s.BrowserFlowCompleted = flag -} - // DefaultDeviceStrategy implements the default device strategy type DefaultDeviceStrategy struct { Enigma *enigma.HMACStrategy @@ -159,7 +80,7 @@ func (h *DefaultDeviceStrategy) DeviceCodeSignature(ctx context.Context, token s } // ValidateDeviceCode validates a device_code -func (h *DefaultDeviceStrategy) ValidateDeviceCode(ctx context.Context, r fosite.Requester, code string) error { +func (h *DefaultDeviceStrategy) ValidateDeviceCode(ctx context.Context, r fosite.DeviceRequester, code string) error { exp := r.GetSession().GetExpiresAt(fosite.DeviceCode) if exp.IsZero() && r.GetRequestedAt().Add(h.Config.GetDeviceAndUserCodeLifespan(ctx)).Before(time.Now().UTC()) { return errorsx.WithStack(fosite.ErrDeviceExpiredToken.WithHintf("Device code expired at '%s'.", r.GetRequestedAt().Add(h.Config.GetDeviceAndUserCodeLifespan(ctx)))) diff --git a/handler/rfc8628/strategy_hmacsha_test.go b/handler/rfc8628/strategy_hmacsha_test.go index 666a47256..bb625251a 100644 --- a/handler/rfc8628/strategy_hmacsha_test.go +++ b/handler/rfc8628/strategy_hmacsha_test.go @@ -28,25 +28,27 @@ var hmacshaStrategy = DefaultDeviceStrategy{ }, } -var hmacValidCase = fosite.Request{ - Client: &fosite.DefaultClient{ - Secret: []byte("foobarfoobarfoobarfoobar"), - }, - Session: &fosite.DefaultSession{ - ExpiresAt: map[fosite.TokenType]time.Time{ - fosite.UserCode: time.Now().UTC().Add(time.Hour), - fosite.DeviceCode: time.Now().UTC().Add(time.Hour), +var hmacValidCase = fosite.DeviceRequest{ + Request: fosite.Request{ + Client: &fosite.DefaultClient{ + Secret: []byte("foobarfoobarfoobarfoobar"), + }, + Session: &fosite.DefaultSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.UserCode: time.Now().UTC().Add(time.Hour), + fosite.DeviceCode: time.Now().UTC().Add(time.Hour), + }, }, }, } func TestHMACUserCode(t *testing.T) { for k, c := range []struct { - r fosite.Request + r fosite.DeviceRequester pass bool }{ { - r: hmacValidCase, + r: &hmacValidCase, pass: true, }, } { @@ -56,7 +58,7 @@ func TestHMACUserCode(t *testing.T) { regex := regexp.MustCompile("[ABCDEFGHIJKLMNOPQRSTUVWXYZ]{8}") assert.Equal(t, len(regex.FindString(userCode)), len(userCode)) - err = hmacshaStrategy.ValidateUserCode(context.TODO(), &c.r, userCode) + err = hmacshaStrategy.ValidateUserCode(context.TODO(), c.r, userCode) if c.pass { assert.NoError(t, err) validate, _ := hmacshaStrategy.Enigma.GenerateHMACForString(context.TODO(), userCode) @@ -73,11 +75,11 @@ func TestHMACUserCode(t *testing.T) { func TestHMACDeviceCode(t *testing.T) { for k, c := range []struct { - r fosite.Request + r fosite.DeviceRequester pass bool }{ { - r: hmacValidCase, + r: &hmacValidCase, pass: true, }, } { @@ -92,7 +94,7 @@ func TestHMACDeviceCode(t *testing.T) { strings.TrimPrefix(token, "ory_dc_"), } { t.Run(fmt.Sprintf("prefix=%v", k == 0), func(t *testing.T) { - err = hmacshaStrategy.ValidateDeviceCode(context.TODO(), &c.r, token) + err = hmacshaStrategy.ValidateDeviceCode(context.TODO(), c.r, token) if c.pass { assert.NoError(t, err) validate := hmacshaStrategy.Enigma.Signature(token) diff --git a/handler/rfc8628/token_handler.go b/handler/rfc8628/token_handler.go index 22cc555f7..8e832c27b 100644 --- a/handler/rfc8628/token_handler.go +++ b/handler/rfc8628/token_handler.go @@ -62,12 +62,12 @@ func (c *DeviceCodeTokenEndpointHandler) PopulateTokenEndpointResponse(ctx conte return err } - var ar fosite.Requester + var ar fosite.DeviceRequester if ar, err = c.session(ctx, requester, signature); err != nil { return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } - if err = c.DeviceCodeStrategy.ValidateDeviceCode(ctx, requester, code); err != nil { + if err = c.DeviceCodeStrategy.ValidateDeviceCode(ctx, ar, code); err != nil { return errorsx.WithStack(err) } @@ -154,7 +154,7 @@ func (c *DeviceCodeTokenEndpointHandler) HandleTokenEndpointRequest(ctx context. return errorsx.WithStack(err) } - var ar fosite.Requester + var ar fosite.DeviceRequester if ar, err = c.session(ctx, requester, signature); err != nil { if ar != nil && (errors.Is(err, fosite.ErrInvalidatedAuthorizeCode) || errors.Is(err, fosite.ErrInvalidatedDeviceCode)) { return c.revokeTokens(ctx, requester.GetID()) @@ -252,7 +252,7 @@ func (c DeviceCodeTokenEndpointHandler) validateCode(ctx context.Context, reques return nil } -func (s DeviceCodeTokenEndpointHandler) session(ctx context.Context, requester fosite.AccessRequester, codeSignature string) (fosite.Requester, error) { +func (s DeviceCodeTokenEndpointHandler) session(ctx context.Context, requester fosite.AccessRequester, codeSignature string) (fosite.DeviceRequester, error) { req, err := s.CoreStorage.GetDeviceCodeSession(ctx, codeSignature, requester.GetSession()) if err != nil && errors.Is(err, fosite.ErrInvalidatedDeviceCode) { @@ -265,10 +265,6 @@ func (s DeviceCodeTokenEndpointHandler) session(ctx context.Context, requester f WithDebug("\"GetDeviceCodeSession\" must return a value for \"fosite.Requester\" when returning \"ErrInvalidatedDeviceCode\".") } - if err != nil && errors.Is(err, fosite.ErrAuthorizationPending) { - return nil, err - } - if err != nil && errors.Is(err, fosite.ErrNotFound) { return nil, errorsx.WithStack(fosite.ErrInvalidGrant.WithWrap(err).WithDebug(err.Error())) } @@ -277,14 +273,14 @@ func (s DeviceCodeTokenEndpointHandler) session(ctx context.Context, requester f return nil, errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) } - session, ok := req.GetSession().(DeviceFlowSession) - if !ok { - return nil, fosite.ErrServerError.WithHint("Wrong authorization request session.") - } + state := req.GetUserCodeState() - if !session.GetBrowserFlowCompleted() { + if state == fosite.UserCodeUnused { return nil, fosite.ErrAuthorizationPending } + if state == fosite.UserCodeRejected { + return nil, fosite.ErrAccessDenied + } return req, err } diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index c60bb40ce..8c0e3f16e 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -79,7 +79,7 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { Client: &fosite.DefaultClient{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, }, - Session: &DefaultDeviceFlowSession{}, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, @@ -94,7 +94,7 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { ID: "foo", GrantTypes: []string{""}, }, - Session: &DefaultDeviceFlowSession{}, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, @@ -109,7 +109,7 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, }, - Session: &DefaultDeviceFlowSession{}, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, @@ -130,11 +130,12 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, }, - Session: &DefaultDeviceFlowSession{}, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ + UserCodeState: fosite.UserCodeUnused, Request: fosite.Request{ Client: &fosite.DefaultClient{ ID: "foo", @@ -142,11 +143,10 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { }, RequestedScope: fosite.Arguments{"foo"}, GrantedScope: fosite.Arguments{"foo"}, - Session: &DefaultDeviceFlowSession{ + Session: &fosite.DefaultSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), }, - BrowserFlowCompleted: false, }, RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), }, @@ -173,20 +173,20 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, }, GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &DefaultDeviceFlowSession{}, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ + UserCodeState: fosite.UserCodeAccepted, Request: fosite.Request{ Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, RequestedScope: fosite.Arguments{"foo"}, GrantedScope: fosite.Arguments{"foo"}, - Session: &DefaultDeviceFlowSession{ + Session: &fosite.DefaultSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.DeviceCode: time.Now().Add(-time.Hour).UTC(), }, - BrowserFlowCompleted: true, }, RequestedAt: time.Now().Add(-2 * time.Hour).UTC(), }, @@ -211,20 +211,20 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, }, - Session: &DefaultDeviceFlowSession{}, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ + UserCodeState: fosite.UserCodeAccepted, Request: fosite.Request{ Client: &fosite.DefaultClient{ID: "bar"}, RequestedScope: fosite.Arguments{"foo"}, GrantedScope: fosite.Arguments{"foo"}, - Session: &DefaultDeviceFlowSession{ + Session: &fosite.DefaultSession{ ExpiresAt: map[fosite.TokenType]time.Time{ fosite.DeviceCode: time.Now().Add(time.Hour).UTC(), }, - BrowserFlowCompleted: true, }, }, }, @@ -248,11 +248,12 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}, }, - Session: &DefaultDeviceFlowSession{}, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ + UserCodeState: fosite.UserCodeAccepted, Request: fosite.Request{ Client: &fosite.DefaultClient{ ID: "foo", @@ -260,10 +261,8 @@ func TestDeviceUserCode_HandleTokenEndpointRequest(t *testing.T) { }, RequestedScope: fosite.Arguments{"foo"}, GrantedScope: fosite.Arguments{"foo"}, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, - RequestedAt: time.Now().UTC(), + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest) { @@ -332,19 +331,18 @@ func TestDeviceUserCode_HandleTokenEndpointRequest_RateLimiting(t *testing.T) { ID: "foo", GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, }, - Session: &DefaultDeviceFlowSession{}, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, } authreq := &fosite.DeviceRequest{ + UserCodeState: fosite.UserCodeAccepted, Request: fosite.Request{ Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, RequestedScope: fosite.Arguments{"foo"}, GrantedScope: fosite.Arguments{"foo"}, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, - RequestedAt: time.Now().UTC(), + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, } @@ -392,9 +390,7 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { Client: &fosite.DefaultClient{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, }, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, @@ -409,9 +405,7 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { Client: &fosite.DefaultClient{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, }, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, @@ -431,21 +425,18 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { Client: &fosite.DefaultClient{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, }, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ + UserCodeState: fosite.UserCodeAccepted, Request: fosite.Request{ Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, RequestedScope: fosite.Arguments{"foo", "bar", "offline"}, GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, - RequestedAt: time.Now().UTC(), + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest, _ *fosite.Config) { @@ -474,21 +465,18 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { Client: &fosite.DefaultClient{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, }, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ + UserCodeState: fosite.UserCodeAccepted, Request: fosite.Request{ Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, RequestedScope: fosite.Arguments{"foo", "bar"}, GrantedScope: fosite.Arguments{"foo"}, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, - RequestedAt: time.Now().UTC(), + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest, config *fosite.Config) { @@ -518,21 +506,18 @@ func TestDeviceUserCode_PopulateTokenEndpointResponse(t *testing.T) { Client: &fosite.DefaultClient{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"}, }, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, }, authreq: &fosite.DeviceRequest{ + UserCodeState: fosite.UserCodeAccepted, Request: fosite.Request{ Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, RequestedScope: fosite.Arguments{"foo", "bar"}, GrantedScope: fosite.Arguments{"foo"}, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, - RequestedAt: time.Now().UTC(), + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, }, setup: func(t *testing.T, areq *fosite.AccessRequest, authreq *fosite.DeviceRequest, config *fosite.Config) { @@ -603,14 +588,13 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { deviceStrategy := RFC8628HMACSHAStrategy authreq := &fosite.DeviceRequest{ + UserCodeState: fosite.UserCodeAccepted, Request: fosite.Request{ Client: &fosite.DefaultClient{ID: "foo", GrantTypes: []string{"urn:ietf:params:oauth:grant-type:device_code"}}, RequestedScope: fosite.Arguments{"foo", "offline"}, GrantedScope: fosite.Arguments{"foo", "offline"}, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, - RequestedAt: time.Now().UTC(), + Session: &fosite.DefaultSession{}, + RequestedAt: time.Now().UTC(), }, } @@ -620,9 +604,7 @@ func TestDeviceUserCodeTransactional_HandleTokenEndpointRequest(t *testing.T) { Client: &fosite.DefaultClient{ GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"}, }, - Session: &DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - }, + Session: &fosite.DefaultSession{}, RequestedAt: time.Now().UTC(), }, } diff --git a/integration/authorize_device_grant_request_test.go b/integration/authorize_device_grant_request_test.go index 9eb2460ae..209309717 100644 --- a/integration/authorize_device_grant_request_test.go +++ b/integration/authorize_device_grant_request_test.go @@ -8,8 +8,6 @@ import ( "fmt" "testing" - "github.com/ory/fosite/handler/rfc8628" - "github.com/ory/fosite" "github.com/ory/fosite/compose" "github.com/ory/fosite/internal/gen" @@ -24,7 +22,7 @@ func TestDeviceFlow(t *testing.T) { } func runDeviceFlowTest(t *testing.T) { - session := &rfc8628.DefaultDeviceFlowSession{} + session := &fosite.DefaultSession{} fc := &fosite.Config{ DeviceVerificationURL: "https://example.com/", @@ -124,9 +122,7 @@ func runDeviceFlowTest(t *testing.T) { } func runDeviceFlowAccessTokenTest(t *testing.T) { - session := &rfc8628.DefaultDeviceFlowSession{ - BrowserFlowCompleted: true, - } + session := &fosite.DefaultSession{} fc := &fosite.Config{ DeviceVerificationURL: "https://example.com/", @@ -147,6 +143,11 @@ func runDeviceFlowAccessTokenTest(t *testing.T) { }, } resp, _ := oauthClient.DeviceAuth(context.Background()) + deviceCodeSignature, err := compose.NewDeviceStrategy(fc).DeviceCodeSignature(context.Background(), resp.DeviceCode) + require.NoError(t, err) + d := fositeStore.DeviceAuths[deviceCodeSignature] + d.SetUserCodeState(fosite.UserCodeAccepted) + fositeStore.DeviceAuths[deviceCodeSignature] = d for k, c := range []struct { description string diff --git a/integration/helper_setup_test.go b/integration/helper_setup_test.go index b7a6ea83a..bd83e6030 100644 --- a/integration/helper_setup_test.go +++ b/integration/helper_setup_test.go @@ -123,7 +123,7 @@ var fositeStore = &storage.MemoryStore{ AccessTokenRequestIDs: map[string]string{}, RefreshTokenRequestIDs: map[string]string{}, PARSessions: map[string]fosite.AuthorizeRequester{}, - DeviceAuths: map[string]fosite.Requester{}, + DeviceAuths: map[string]fosite.DeviceRequester{}, DeviceCodesRequestIDs: map[string]storage.DeviceAuthPair{}, UserCodesRequestIDs: map[string]string{}, } diff --git a/oauth2.go b/oauth2.go index 9fc689cd0..cbae4cfec 100644 --- a/oauth2.go +++ b/oauth2.go @@ -286,6 +286,12 @@ type AccessRequester interface { // DeviceRequester is an device endpoint's request context. type DeviceRequester interface { + // GetUserCodeState returns the state of the user code + GetUserCodeState() UserCodeState + + // SetUserCodeState sets the state of the user code + SetUserCodeState(state UserCodeState) + Requester } diff --git a/storage/memory.go b/storage/memory.go index 31ba4bc68..c1d6ff1ae 100644 --- a/storage/memory.go +++ b/storage/memory.go @@ -47,7 +47,7 @@ type MemoryStore struct { IDSessions map[string]fosite.Requester AccessTokens map[string]fosite.Requester RefreshTokens map[string]StoreRefreshToken - DeviceAuths map[string]fosite.Requester + DeviceAuths map[string]fosite.DeviceRequester PKCES map[string]fosite.Requester Users map[string]MemoryUserRelation BlacklistedJTIs map[string]time.Time @@ -83,7 +83,7 @@ func NewMemoryStore() *MemoryStore { IDSessions: make(map[string]fosite.Requester), AccessTokens: make(map[string]fosite.Requester), RefreshTokens: make(map[string]StoreRefreshToken), - DeviceAuths: make(map[string]fosite.Requester), + DeviceAuths: make(map[string]fosite.DeviceRequester), PKCES: make(map[string]fosite.Requester), Users: make(map[string]MemoryUserRelation), AccessTokenRequestIDs: make(map[string]string), @@ -154,7 +154,7 @@ func NewExampleStore() *MemoryStore { AccessTokens: map[string]fosite.Requester{}, RefreshTokens: map[string]StoreRefreshToken{}, PKCES: map[string]fosite.Requester{}, - DeviceAuths: make(map[string]fosite.Requester), + DeviceAuths: make(map[string]fosite.DeviceRequester), AccessTokenRequestIDs: map[string]string{}, RefreshTokenRequestIDs: map[string]string{}, DeviceCodesRequestIDs: make(map[string]DeviceAuthPair), @@ -521,7 +521,7 @@ func (s *MemoryStore) RotateRefreshToken(ctx context.Context, requestID string, } // CreateDeviceAuthSession stores the device auth session -func (s *MemoryStore) CreateDeviceAuthSession(_ context.Context, deviceCodeSignature, userCodeSignature string, req fosite.Requester) error { +func (s *MemoryStore) CreateDeviceAuthSession(_ context.Context, deviceCodeSignature, userCodeSignature string, req fosite.DeviceRequester) error { s.deviceAuthsRequestIDsMutex.Lock() defer s.deviceAuthsRequestIDsMutex.Unlock() s.deviceAuthsMutex.Lock() @@ -534,7 +534,7 @@ func (s *MemoryStore) CreateDeviceAuthSession(_ context.Context, deviceCodeSigna } // GetDeviceCodeSession gets the device code session -func (s *MemoryStore) GetDeviceCodeSession(_ context.Context, signature string, _ fosite.Session) (fosite.Requester, error) { +func (s *MemoryStore) GetDeviceCodeSession(_ context.Context, signature string, _ fosite.Session) (fosite.DeviceRequester, error) { s.deviceAuthsMutex.RLock() defer s.deviceAuthsMutex.RUnlock() From 5db11b02c444691e952793f28188871b53fdd88b Mon Sep 17 00:00:00 2001 From: Nikos Date: Mon, 18 Nov 2024 11:25:36 +0200 Subject: [PATCH 30/36] fix: do not create openid session on device auth request --- handler/openid/flow_device_auth.go | 25 ++-------------- handler/openid/flow_device_auth_test.go | 38 ------------------------- 2 files changed, 3 insertions(+), 60 deletions(-) diff --git a/handler/openid/flow_device_auth.go b/handler/openid/flow_device_auth.go index efeb2115e..c780d5fe0 100644 --- a/handler/openid/flow_device_auth.go +++ b/handler/openid/flow_device_auth.go @@ -9,7 +9,6 @@ import ( "github.com/ory/fosite/handler/rfc8628" "github.com/ory/fosite" - "github.com/ory/x/errorsx" ) // OpenIDConnectDeviceHandler a response handler for the Device Authorization Grant with OpenID Connect identity layer @@ -25,26 +24,8 @@ type OpenIDConnectDeviceHandler struct { } func (c *OpenIDConnectDeviceHandler) HandleDeviceEndpointRequest(ctx context.Context, dar fosite.DeviceRequester, resp fosite.DeviceResponder) error { - if !(dar.GetRequestedScopes().Has("openid")) { - return nil - } - - if !dar.GetClient().GetGrantTypes().Has(string(fosite.GrantTypeDeviceCode)) { - return nil - } - - if resp.GetDeviceCode() == "" { - return errorsx.WithStack(fosite.ErrMisconfiguration.WithDebug("The device code has not been issued yet, indicating a broken code configuration.")) - } - - signature, err := c.DeviceCodeStrategy.DeviceCodeSignature(ctx, resp.GetDeviceCode()) - if err != nil { - return err - } - - if err := c.OpenIDConnectRequestStorage.CreateOpenIDConnectSession(ctx, signature, dar.Sanitize(oidcParameters)); err != nil { - return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) - } - + // We don't want to create the openid session on this call, because we don't know if the user + // will actually complete the flow and give consent. The implementer MUST call the CreateOpenIDConnectSession + // methods when the user logs in to instantiate the session. return nil } diff --git a/handler/openid/flow_device_auth_test.go b/handler/openid/flow_device_auth_test.go index 34bb3bbff..2daa4c5b8 100644 --- a/handler/openid/flow_device_auth_test.go +++ b/handler/openid/flow_device_auth_test.go @@ -10,7 +10,6 @@ import ( "time" "github.com/ory/fosite/internal" - "github.com/pkg/errors" gomock "go.uber.org/mock/gomock" "github.com/stretchr/testify/require" @@ -90,37 +89,6 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) { }, }, }, - { - description: "should fail because device code is not issued", - authreq: &fosite.DeviceRequest{ - Request: fosite.Request{ - RequestedScope: fosite.Arguments{"openid", "email"}, - Client: client, - }, - }, - authresp: &fosite.DeviceResponse{}, - expectErr: fosite.ErrMisconfiguration, - }, - { - description: "should fail because cannot create session", - authreq: &fosite.DeviceRequest{ - Request: fosite.Request{ - RequestedScope: fosite.Arguments{"openid", "email"}, - Client: client, - Session: session, - }, - }, - authresp: &fosite.DeviceResponse{ - DeviceCode: "device_code", - }, - setup: func(authreq *fosite.DeviceRequest) { - store. - EXPECT(). - CreateOpenIDConnectSession(gomock.Any(), gomock.Any(), gomock.Eq(authreq.Sanitize(oidcParameters))). - Return(errors.New("")) - }, - expectErr: fosite.ErrServerError, - }, { description: "should pass", authreq: &fosite.DeviceRequest{ @@ -133,12 +101,6 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) { authresp: &fosite.DeviceResponse{ DeviceCode: "device_code", }, - setup: func(authreq *fosite.DeviceRequest) { - store. - EXPECT(). - CreateOpenIDConnectSession(gomock.Any(), gomock.Any(), gomock.Eq(authreq.Sanitize(oidcParameters))). - Return(nil) - }, }, } From 846cf99f14c0ee6ec921ab707f6cbc1ee2477678 Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 7 Jan 2025 16:28:39 +0100 Subject: [PATCH 31/36] test: check for id and refresh token --- .../authorize_device_grant_request_test.go | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/integration/authorize_device_grant_request_test.go b/integration/authorize_device_grant_request_test.go index 209309717..7ba7eac83 100644 --- a/integration/authorize_device_grant_request_test.go +++ b/integration/authorize_device_grant_request_test.go @@ -11,6 +11,7 @@ import ( "github.com/ory/fosite" "github.com/ory/fosite/compose" "github.com/ory/fosite/internal/gen" + "github.com/ory/fosite/token/jwt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" goauth "golang.org/x/oauth2" @@ -58,7 +59,7 @@ func runDeviceFlowTest(t *testing.T) { assert.ErrorContains(t, err, "invalid_grant") }, cleanUp: func() { - fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"} }, }, { @@ -122,7 +123,7 @@ func runDeviceFlowTest(t *testing.T) { } func runDeviceFlowAccessTokenTest(t *testing.T) { - session := &fosite.DefaultSession{} + session := newIDSession(&jwt.IDTokenClaims{Subject: "peter"}) fc := &fosite.Config{ DeviceVerificationURL: "https://example.com/", @@ -141,10 +142,16 @@ func runDeviceFlowAccessTokenTest(t *testing.T) { TokenURL: ts.URL + tokenRelativePath, DeviceAuthURL: ts.URL + deviceAuthRelativePath, }, + Scopes: []string{"openid", "fosite", "offline"}, } resp, _ := oauthClient.DeviceAuth(context.Background()) deviceCodeSignature, err := compose.NewDeviceStrategy(fc).DeviceCodeSignature(context.Background(), resp.DeviceCode) require.NoError(t, err) + + req, err := fositeStore.GetDeviceCodeSession(context.TODO(), deviceCodeSignature, nil) + require.NoError(t, err) + fositeStore.CreateOpenIDConnectSession(context.TODO(), deviceCodeSignature, req) + d := fositeStore.DeviceAuths[deviceCodeSignature] d.SetUserCodeState(fosite.UserCodeAccepted) fositeStore.DeviceAuths[deviceCodeSignature] = d @@ -175,7 +182,7 @@ func runDeviceFlowAccessTokenTest(t *testing.T) { assert.ErrorContains(t, err, "unauthorized_client") }, cleanUp: func() { - fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code"} + fositeStore.Clients["device-client"].(*fosite.DefaultClient).GrantTypes = []string{"urn:ietf:params:oauth:grant-type:device_code", "refresh_token"} }, }, { @@ -203,6 +210,15 @@ func runDeviceFlowAccessTokenTest(t *testing.T) { check: func(t *testing.T, token *goauth.Token, err error) { assert.Equal(t, "bearer", token.TokenType) assert.NotEmpty(t, token.AccessToken) + assert.NotEmpty(t, token.RefreshToken) + assert.NotEmpty(t, token.Extra("id_token")) + + tokenSource := oauthClient.TokenSource(context.Background(), token) + refreshed, err := tokenSource.Token() + + assert.NotEmpty(t, refreshed.AccessToken) + assert.NotEmpty(t, refreshed.RefreshToken) + assert.NotEmpty(t, refreshed.Extra("id_token")) }, }, } { From 899457168c3d92399a19401d85f764cde0de670b Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 7 Jan 2025 16:30:03 +0100 Subject: [PATCH 32/36] chore: migrate to uber/gomock --- go.mod | 1 - go.sum | 9 --------- 2 files changed, 10 deletions(-) diff --git a/go.mod b/go.mod index ae2581c70..8713b3312 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ require ( github.com/cristalhq/jwt/v4 v4.0.2 github.com/dgraph-io/ristretto v1.0.0 github.com/go-jose/go-jose/v3 v3.0.3 - github.com/golang/mock v1.6.0 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 diff --git a/go.sum b/go.sum index 9585cfb7d..89abfbd5f 100644 --- a/go.sum +++ b/go.sum @@ -137,8 +137,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -419,7 +417,6 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -518,7 +515,6 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= @@ -556,7 +552,6 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= @@ -587,7 +582,6 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -632,10 +626,8 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -728,7 +720,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= From 54071feb35f59e6f71e144bc5a7c0bc413c019a9 Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 7 Jan 2025 16:32:48 +0100 Subject: [PATCH 33/36] fix: delete oidc session when used --- handler/openid/flow_device_token.go | 7 ++++++- handler/openid/flow_device_token_test.go | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/handler/openid/flow_device_token.go b/handler/openid/flow_device_token.go index c0e2660eb..7de50469c 100644 --- a/handler/openid/flow_device_token.go +++ b/handler/openid/flow_device_token.go @@ -26,7 +26,7 @@ func (c *OpenIDConnectDeviceHandler) PopulateTokenEndpointResponse(ctx context.C } deviceCode := requester.GetRequestForm().Get("device_code") - signature, err := c.DeviceCodeStrategy.DeviceCodeSignature(ctx, deviceCode) + signature, _ := c.DeviceCodeStrategy.DeviceCodeSignature(ctx, deviceCode) ar, err := c.OpenIDConnectRequestStorage.GetOpenIDConnectSession(ctx, signature, requester) if errors.Is(err, ErrNoSessionFound) { return errorsx.WithStack(fosite.ErrUnknownRequest.WithWrap(err).WithDebug(err.Error())) @@ -49,6 +49,11 @@ func (c *OpenIDConnectDeviceHandler) PopulateTokenEndpointResponse(ctx context.C return errorsx.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because subject is an empty string.")) } + err = c.OpenIDConnectRequestStorage.DeleteOpenIDConnectSession(ctx, deviceCode) + if err != nil { + return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error())) + } + claims.AccessTokenHash = c.GetAccessTokenHash(ctx, requester, responder) idTokenLifespan := fosite.GetEffectiveLifespan(requester.GetClient(), fosite.GrantTypeDeviceCode, fosite.IDToken, c.Config.GetIDTokenLifespan(ctx)) diff --git a/handler/openid/flow_device_token_test.go b/handler/openid/flow_device_token_test.go index dbd7c6963..d0d605b42 100644 --- a/handler/openid/flow_device_token_test.go +++ b/handler/openid/flow_device_token_test.go @@ -218,6 +218,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) { }, } store.EXPECT().GetOpenIDConnectSession(gomock.Any(), gomock.Any(), areq).Return(authreq, nil) + store.EXPECT().DeleteOpenIDConnectSession(gomock.Any(), gomock.Any()).Return(nil) }, check: func(t *testing.T, aresp *fosite.AccessResponse) { assert.NotEmpty(t, aresp.GetExtra("id_token")) From ae40a12f39a9a41baecb20697bd54896b5d21bd8 Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 7 Jan 2025 16:33:56 +0100 Subject: [PATCH 34/36] fix: remove rate limiting implementation --- handler/rfc8628/strategy_hmacsha.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go index 43e7ca4fa..099592765 100644 --- a/handler/rfc8628/strategy_hmacsha.go +++ b/handler/rfc8628/strategy_hmacsha.go @@ -16,8 +16,6 @@ import ( enigma "github.com/ory/fosite/token/hmac" ) -const POLLING_RATE_LIMITING_LEEWAY = 200 * time.Millisecond - // DefaultDeviceStrategy implements the default device strategy type DefaultDeviceStrategy struct { Enigma *enigma.HMACStrategy From 1f153152e7801d8fd1d57591417b371a4b26f77d Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 7 Jan 2025 17:00:09 +0100 Subject: [PATCH 35/36] chore: update copyright date --- access_error.go | 2 +- access_error_test.go | 2 +- access_request.go | 2 +- access_request_handler.go | 2 +- access_request_handler_test.go | 2 +- access_request_test.go | 2 +- access_response.go | 2 +- access_response_test.go | 2 +- access_response_writer.go | 2 +- access_response_writer_test.go | 2 +- access_write.go | 2 +- access_write_test.go | 2 +- arguments.go | 2 +- arguments_test.go | 2 +- audience_strategy.go | 2 +- audience_strategy_test.go | 2 +- authorize_error.go | 2 +- authorize_error_test.go | 2 +- authorize_helper.go | 2 +- authorize_helper_test.go | 2 +- authorize_helper_whitebox_test.go | 2 +- authorize_request.go | 2 +- authorize_request_handler.go | 2 +- authorize_request_handler_oidc_request_test.go | 2 +- authorize_request_handler_test.go | 2 +- authorize_request_test.go | 2 +- authorize_response.go | 2 +- authorize_response_test.go | 2 +- authorize_response_writer.go | 2 +- authorize_response_writer_test.go | 2 +- authorize_validators_test.go | 2 +- authorize_write.go | 2 +- authorize_write_test.go | 2 +- client.go | 2 +- client_authentication.go | 2 +- client_authentication_jwks_strategy.go | 2 +- client_authentication_jwks_strategy_test.go | 2 +- client_authentication_test.go | 2 +- client_manager.go | 2 +- client_test.go | 2 +- client_with_custom_token_lifespans.go | 2 +- client_with_custom_token_lifespans_test.go | 2 +- compose/compose.go | 2 +- compose/compose_oauth2.go | 2 +- compose/compose_openid.go | 2 +- compose/compose_par.go | 2 +- compose/compose_pkce.go | 2 +- compose/compose_rfc7523.go | 2 +- compose/compose_rfc8628.go | 2 +- compose/compose_strategy.go | 2 +- compose/compose_userinfo_vc.go | 2 +- config.go | 2 +- config_default.go | 2 +- context.go | 2 +- device_request.go | 2 +- device_request_handler.go | 2 +- device_request_handler_test.go | 2 +- device_response.go | 2 +- device_response_test.go | 2 +- device_response_writer.go | 2 +- device_write.go | 2 +- device_write_test.go | 2 +- equalKeys_test.go | 2 +- errors.go | 2 +- errors_test.go | 2 +- fosite.go | 2 +- fosite_test.go | 2 +- generate.go | 2 +- go_mod_indirect_pins.go | 2 +- handler.go | 2 +- handler/oauth2/flow_authorize_code_auth.go | 2 +- handler/oauth2/flow_authorize_code_auth_test.go | 2 +- handler/oauth2/flow_authorize_code_token.go | 2 +- handler/oauth2/flow_authorize_code_token_test.go | 2 +- handler/oauth2/flow_authorize_implicit.go | 2 +- handler/oauth2/flow_authorize_implicit_test.go | 2 +- handler/oauth2/flow_client_credentials.go | 2 +- handler/oauth2/flow_client_credentials_storage.go | 2 +- handler/oauth2/flow_client_credentials_test.go | 2 +- handler/oauth2/flow_refresh.go | 2 +- handler/oauth2/flow_refresh_test.go | 2 +- handler/oauth2/flow_resource_owner.go | 2 +- handler/oauth2/flow_resource_owner_storage.go | 2 +- handler/oauth2/flow_resource_owner_test.go | 2 +- handler/oauth2/helper.go | 2 +- handler/oauth2/helper_test.go | 2 +- handler/oauth2/introspector.go | 2 +- handler/oauth2/introspector_jwt.go | 2 +- handler/oauth2/introspector_jwt_test.go | 2 +- handler/oauth2/introspector_test.go | 2 +- handler/oauth2/providers.go | 2 +- handler/oauth2/revocation.go | 2 +- handler/oauth2/revocation_storage.go | 2 +- handler/oauth2/revocation_test.go | 2 +- handler/oauth2/storage.go | 2 +- handler/oauth2/strategy.go | 2 +- handler/oauth2/strategy_hmacsha_plain.go | 2 +- handler/oauth2/strategy_hmacsha_prefixed.go | 2 +- handler/oauth2/strategy_hmacsha_test.go | 2 +- handler/oauth2/strategy_jwt.go | 2 +- handler/oauth2/strategy_jwt_session.go | 2 +- handler/oauth2/strategy_jwt_test.go | 2 +- handler/openid/errors.go | 2 +- handler/openid/flow_device_auth.go | 2 +- handler/openid/flow_device_auth_test.go | 2 +- handler/openid/flow_device_token.go | 2 +- handler/openid/flow_device_token_test.go | 2 +- handler/openid/flow_explicit_auth.go | 2 +- handler/openid/flow_explicit_auth_test.go | 2 +- handler/openid/flow_explicit_token.go | 2 +- handler/openid/flow_explicit_token_test.go | 2 +- handler/openid/flow_hybrid.go | 2 +- handler/openid/flow_hybrid_test.go | 2 +- handler/openid/flow_implicit.go | 2 +- handler/openid/flow_implicit_test.go | 2 +- handler/openid/flow_refresh_token.go | 2 +- handler/openid/flow_refresh_token_test.go | 2 +- handler/openid/helper.go | 2 +- handler/openid/helper_test.go | 2 +- handler/openid/storage.go | 2 +- handler/openid/strategy.go | 2 +- handler/openid/strategy_jwt.go | 2 +- handler/openid/strategy_jwt_test.go | 2 +- handler/openid/validator.go | 2 +- handler/openid/validator_test.go | 2 +- handler/par/flow_pushed_authorize.go | 2 +- handler/par/flow_pushed_authorize_test.go | 2 +- handler/pkce/handler.go | 2 +- handler/pkce/handler_test.go | 2 +- handler/pkce/storage.go | 2 +- handler/rfc7523/handler.go | 2 +- handler/rfc7523/handler_test.go | 2 +- handler/rfc7523/session.go | 2 +- handler/rfc7523/storage.go | 2 +- handler/rfc8628/auth_handler.go | 2 +- handler/rfc8628/auth_handler_test.go | 2 +- handler/rfc8628/storage.go | 2 +- handler/rfc8628/strategy.go | 2 +- handler/rfc8628/strategy_hmacsha.go | 2 +- handler/rfc8628/strategy_hmacsha_test.go | 2 +- handler/rfc8628/token_handler.go | 2 +- handler/rfc8628/token_handler_test.go | 2 +- handler/verifiable/handler.go | 2 +- handler/verifiable/handler_test.go | 2 +- handler/verifiable/nonce.go | 2 +- hash.go | 2 +- hash_bcrypt.go | 2 +- hash_bcrypt_test.go | 2 +- helper.go | 2 +- helper_test.go | 2 +- i18n/default_catalog.go | 2 +- i18n/i18n.go | 2 +- i18n/i18n_test.go | 2 +- i18n_helper.go | 2 +- i18n_helper_test.go | 2 +- integration/authorize_code_grant_public_client_pkce_test.go | 2 +- integration/authorize_code_grant_public_client_test.go | 2 +- integration/authorize_code_grant_test.go | 2 +- integration/authorize_device_grant_request_test.go | 2 +- integration/authorize_form_post_test.go | 2 +- integration/authorize_implicit_grant_test.go | 2 +- integration/authorize_jwt_bearer_required_iat_test.go | 2 +- integration/authorize_jwt_bearer_required_jti_test.go | 2 +- integration/authorize_jwt_bearer_test.go | 2 +- integration/authorize_response_mode_test.go | 2 +- integration/client_credentials_grant_test.go | 2 +- integration/clients/error.go | 2 +- integration/clients/introspect.go | 2 +- integration/clients/jwt_bearer.go | 2 +- integration/helper_endpoints_test.go | 2 +- integration/helper_setup_test.go | 2 +- integration/introspect_jwt_bearer_token_test.go | 2 +- integration/introspect_token_test.go | 2 +- integration/oidc_explicit_test.go | 2 +- integration/oidc_implicit_hybrid_public_client_pkce_test.go | 2 +- integration/oidc_implicit_hybrid_test.go | 2 +- integration/placeholder.go | 2 +- integration/pushed_authorize_code_grant_test.go | 2 +- integration/refresh_token_grant_test.go | 2 +- integration/resource_owner_password_credentials_grant_test.go | 2 +- integration/revoke_token_test.go | 2 +- internal/access_request.go | 2 +- internal/access_response.go | 2 +- internal/access_token_storage.go | 2 +- internal/access_token_strategy.go | 2 +- internal/authorize_code_storage.go | 2 +- internal/authorize_code_strategy.go | 2 +- internal/authorize_handler.go | 2 +- internal/authorize_request.go | 2 +- internal/authorize_response.go | 2 +- internal/client.go | 2 +- internal/device_code_rate_limit_strategy.go | 2 +- internal/gen/key.go | 2 +- internal/hash.go | 2 +- internal/id_token_strategy.go | 2 +- internal/introspector.go | 2 +- internal/oauth2_auth_jwt_storage.go | 2 +- internal/oauth2_client_storage.go | 2 +- internal/oauth2_explicit_storage.go | 2 +- internal/oauth2_owner_storage.go | 2 +- internal/oauth2_refresh_storage.go | 2 +- internal/oauth2_revoke_storage.go | 2 +- internal/oauth2_storage.go | 2 +- internal/oauth2_strategy.go | 2 +- internal/openid_id_token_storage.go | 2 +- internal/pkce_storage_strategy.go | 2 +- internal/pushed_authorize_handler.go | 2 +- internal/refresh_token_strategy.go | 2 +- internal/request.go | 2 +- internal/revoke_handler.go | 2 +- internal/rfc8628_code_strategy.go | 2 +- internal/rfc8628_core_storage.go | 2 +- internal/rw.go | 2 +- internal/storage.go | 2 +- internal/test_helpers.go | 2 +- internal/token_handler.go | 2 +- internal/transactional.go | 2 +- introspect.go | 2 +- introspect_test.go | 2 +- introspection_request_handler.go | 2 +- introspection_request_handler_test.go | 2 +- introspection_response_writer.go | 2 +- introspection_response_writer_test.go | 2 +- oauth2.go | 2 +- pushed_authorize_request_handler.go | 2 +- pushed_authorize_request_handler_test.go | 2 +- pushed_authorize_response.go | 2 +- pushed_authorize_response_writer.go | 2 +- pushed_authorize_response_writer_test.go | 2 +- request.go | 2 +- request_test.go | 2 +- response_handler.go | 2 +- revoke_handler.go | 2 +- revoke_handler_test.go | 2 +- scope_strategy.go | 2 +- scope_strategy_test.go | 2 +- session.go | 2 +- session_test.go | 2 +- storage.go | 2 +- storage/memory.go | 2 +- storage/memory_test.go | 2 +- storage/transactional.go | 2 +- token/hmac/bytes.go | 2 +- token/hmac/bytes_test.go | 2 +- token/hmac/hmacsha.go | 2 +- token/hmac/hmacsha_test.go | 2 +- token/jwt/claims.go | 2 +- token/jwt/claims_id_token.go | 2 +- token/jwt/claims_id_token_test.go | 2 +- token/jwt/claims_jwt.go | 2 +- token/jwt/claims_jwt_test.go | 2 +- token/jwt/claims_test.go | 2 +- token/jwt/header.go | 2 +- token/jwt/header_test.go | 2 +- token/jwt/jwt.go | 2 +- token/jwt/jwt_test.go | 2 +- token/jwt/map_claims.go | 2 +- token/jwt/map_claims_test.go | 2 +- token/jwt/token.go | 2 +- token/jwt/token_test.go | 2 +- token/jwt/validation_error.go | 2 +- tools.go | 2 +- 262 files changed, 262 insertions(+), 262 deletions(-) diff --git a/access_error.go b/access_error.go index d4c59850e..85236715b 100644 --- a/access_error.go +++ b/access_error.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/access_error_test.go b/access_error_test.go index b6cbb19de..32987e17c 100644 --- a/access_error_test.go +++ b/access_error_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/access_request.go b/access_request.go index 2ef86c3f1..de546005e 100644 --- a/access_request.go +++ b/access_request.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/access_request_handler.go b/access_request_handler.go index 25dbd62a7..45ddec6db 100644 --- a/access_request_handler.go +++ b/access_request_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/access_request_handler_test.go b/access_request_handler_test.go index a5d63729c..f185c2ddd 100644 --- a/access_request_handler_test.go +++ b/access_request_handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/access_request_test.go b/access_request_test.go index 08d40656c..839cb86f3 100644 --- a/access_request_test.go +++ b/access_request_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/access_response.go b/access_response.go index 7e93edafb..be827644e 100644 --- a/access_response.go +++ b/access_response.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/access_response_test.go b/access_response_test.go index 5dec60020..270af6663 100644 --- a/access_response_test.go +++ b/access_response_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/access_response_writer.go b/access_response_writer.go index e2a8b288a..803250c03 100644 --- a/access_response_writer.go +++ b/access_response_writer.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/access_response_writer_test.go b/access_response_writer_test.go index 45f6089bf..d6f6bd8d7 100644 --- a/access_response_writer_test.go +++ b/access_response_writer_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/access_write.go b/access_write.go index 656acddd9..a8f1fd6a2 100644 --- a/access_write.go +++ b/access_write.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/access_write_test.go b/access_write_test.go index 4229185b9..46219eecd 100644 --- a/access_write_test.go +++ b/access_write_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/arguments.go b/arguments.go index 2fb99a8d7..f037919f6 100644 --- a/arguments.go +++ b/arguments.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/arguments_test.go b/arguments_test.go index 9466bc95e..6e5bef853 100644 --- a/arguments_test.go +++ b/arguments_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/audience_strategy.go b/audience_strategy.go index bcef40bbe..61d836da1 100644 --- a/audience_strategy.go +++ b/audience_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/audience_strategy_test.go b/audience_strategy_test.go index 304b77b5a..dccf5b359 100644 --- a/audience_strategy_test.go +++ b/audience_strategy_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_error.go b/authorize_error.go index 0421be6f5..7247cb743 100644 --- a/authorize_error.go +++ b/authorize_error.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_error_test.go b/authorize_error_test.go index a7f4d81fb..0ca2265bd 100644 --- a/authorize_error_test.go +++ b/authorize_error_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/authorize_helper.go b/authorize_helper.go index 0b98cfe96..51bfab2b4 100644 --- a/authorize_helper.go +++ b/authorize_helper.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_helper_test.go b/authorize_helper_test.go index 637c6bc69..00a84276b 100644 --- a/authorize_helper_test.go +++ b/authorize_helper_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/authorize_helper_whitebox_test.go b/authorize_helper_whitebox_test.go index e4d6eb139..52a4bba5e 100644 --- a/authorize_helper_whitebox_test.go +++ b/authorize_helper_whitebox_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_request.go b/authorize_request.go index c4526692c..a18747843 100644 --- a/authorize_request.go +++ b/authorize_request.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_request_handler.go b/authorize_request_handler.go index 9ec9bae45..61b5d957a 100644 --- a/authorize_request_handler.go +++ b/authorize_request_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_request_handler_oidc_request_test.go b/authorize_request_handler_oidc_request_test.go index 982bed317..f8a2636c5 100644 --- a/authorize_request_handler_oidc_request_test.go +++ b/authorize_request_handler_oidc_request_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_request_handler_test.go b/authorize_request_handler_test.go index e5c301fd1..84921ac4d 100644 --- a/authorize_request_handler_test.go +++ b/authorize_request_handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/authorize_request_test.go b/authorize_request_test.go index 89a789be1..5886435cc 100644 --- a/authorize_request_test.go +++ b/authorize_request_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_response.go b/authorize_response.go index 209716aba..fc84ffa41 100644 --- a/authorize_response.go +++ b/authorize_response.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_response_test.go b/authorize_response_test.go index 8a92e8ae3..fc47dba43 100644 --- a/authorize_response_test.go +++ b/authorize_response_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_response_writer.go b/authorize_response_writer.go index db53ee632..fa239f5b5 100644 --- a/authorize_response_writer.go +++ b/authorize_response_writer.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_response_writer_test.go b/authorize_response_writer_test.go index 0ff2c05d9..caa0d996c 100644 --- a/authorize_response_writer_test.go +++ b/authorize_response_writer_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/authorize_validators_test.go b/authorize_validators_test.go index bd6422e6b..36705fb62 100644 --- a/authorize_validators_test.go +++ b/authorize_validators_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_write.go b/authorize_write.go index 318bfd495..f254a8358 100644 --- a/authorize_write.go +++ b/authorize_write.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/authorize_write_test.go b/authorize_write_test.go index 36630e4c4..2174c52d2 100644 --- a/authorize_write_test.go +++ b/authorize_write_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/client.go b/client.go index fc14ae054..b40149671 100644 --- a/client.go +++ b/client.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/client_authentication.go b/client_authentication.go index 82f3c3872..251509199 100644 --- a/client_authentication.go +++ b/client_authentication.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/client_authentication_jwks_strategy.go b/client_authentication_jwks_strategy.go index 8f410a72a..3e90cb89b 100644 --- a/client_authentication_jwks_strategy.go +++ b/client_authentication_jwks_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/client_authentication_jwks_strategy_test.go b/client_authentication_jwks_strategy_test.go index ce8312281..93ce74710 100644 --- a/client_authentication_jwks_strategy_test.go +++ b/client_authentication_jwks_strategy_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/client_authentication_test.go b/client_authentication_test.go index 3f08e6e16..aee4d6b59 100644 --- a/client_authentication_test.go +++ b/client_authentication_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/client_manager.go b/client_manager.go index 60e3756ca..4e9685dc0 100644 --- a/client_manager.go +++ b/client_manager.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/client_test.go b/client_test.go index bc6ebfe6b..d1ce2e3be 100644 --- a/client_test.go +++ b/client_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/client_with_custom_token_lifespans.go b/client_with_custom_token_lifespans.go index be5b0ac63..b46e2ba54 100644 --- a/client_with_custom_token_lifespans.go +++ b/client_with_custom_token_lifespans.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/client_with_custom_token_lifespans_test.go b/client_with_custom_token_lifespans_test.go index 60d9018b1..813645c83 100644 --- a/client_with_custom_token_lifespans_test.go +++ b/client_with_custom_token_lifespans_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/compose/compose.go b/compose/compose.go index 9467d054c..2a5ee9187 100644 --- a/compose/compose.go +++ b/compose/compose.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package compose diff --git a/compose/compose_oauth2.go b/compose/compose_oauth2.go index c3f01073e..9f0eee3de 100644 --- a/compose/compose_oauth2.go +++ b/compose/compose_oauth2.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package compose diff --git a/compose/compose_openid.go b/compose/compose_openid.go index d7bc0ca79..1486bdf23 100644 --- a/compose/compose_openid.go +++ b/compose/compose_openid.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package compose diff --git a/compose/compose_par.go b/compose/compose_par.go index 2ed57fac0..dc2513313 100644 --- a/compose/compose_par.go +++ b/compose/compose_par.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package compose diff --git a/compose/compose_pkce.go b/compose/compose_pkce.go index d7df6c394..ff5d660e3 100644 --- a/compose/compose_pkce.go +++ b/compose/compose_pkce.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package compose diff --git a/compose/compose_rfc7523.go b/compose/compose_rfc7523.go index e584bad2f..0a9fe55ef 100644 --- a/compose/compose_rfc7523.go +++ b/compose/compose_rfc7523.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package compose diff --git a/compose/compose_rfc8628.go b/compose/compose_rfc8628.go index 428ad3a6f..2bba93b45 100644 --- a/compose/compose_rfc8628.go +++ b/compose/compose_rfc8628.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Package compose provides various objects which can be used to diff --git a/compose/compose_strategy.go b/compose/compose_strategy.go index f48ab9e0a..d29a2da8c 100644 --- a/compose/compose_strategy.go +++ b/compose/compose_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package compose diff --git a/compose/compose_userinfo_vc.go b/compose/compose_userinfo_vc.go index 079aa8933..d2ee6eb83 100644 --- a/compose/compose_userinfo_vc.go +++ b/compose/compose_userinfo_vc.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package compose diff --git a/config.go b/config.go index 2d74753f8..519b86324 100644 --- a/config.go +++ b/config.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/config_default.go b/config_default.go index eb4acce9a..95fd60373 100644 --- a/config_default.go +++ b/config_default.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/context.go b/context.go index ae01d9b31..34cdce1ee 100644 --- a/context.go +++ b/context.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/device_request.go b/device_request.go index ef26c5d84..35f454ef4 100644 --- a/device_request.go +++ b/device_request.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/device_request_handler.go b/device_request_handler.go index a3421b30c..e6cc40048 100644 --- a/device_request_handler.go +++ b/device_request_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/device_request_handler_test.go b/device_request_handler_test.go index 6b0d4d117..b9ec7e5a6 100644 --- a/device_request_handler_test.go +++ b/device_request_handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/device_response.go b/device_response.go index 5f8c95ff8..95b3993b4 100644 --- a/device_response.go +++ b/device_response.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/device_response_test.go b/device_response_test.go index a4e95e168..38e3f8413 100644 --- a/device_response_test.go +++ b/device_response_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/device_response_writer.go b/device_response_writer.go index a093ea878..722abbaee 100644 --- a/device_response_writer.go +++ b/device_response_writer.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/device_write.go b/device_write.go index d3337ab29..2da0f8386 100644 --- a/device_write.go +++ b/device_write.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/device_write_test.go b/device_write_test.go index 5eae5e067..3a1fcccdb 100644 --- a/device_write_test.go +++ b/device_write_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/equalKeys_test.go b/equalKeys_test.go index f7fd7bb63..5b965461d 100644 --- a/equalKeys_test.go +++ b/equalKeys_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/errors.go b/errors.go index b986dbc92..046241c81 100644 --- a/errors.go +++ b/errors.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/errors_test.go b/errors_test.go index 9465636cc..8b6c5e36f 100644 --- a/errors_test.go +++ b/errors_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/fosite.go b/fosite.go index 90c30b4d4..b7ab0547c 100644 --- a/fosite.go +++ b/fosite.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/fosite_test.go b/fosite_test.go index 0a273fdc1..a63650e20 100644 --- a/fosite_test.go +++ b/fosite_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/generate.go b/generate.go index d7a60d50c..e79ba0924 100644 --- a/generate.go +++ b/generate.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/go_mod_indirect_pins.go b/go_mod_indirect_pins.go index 8ac71d57f..8ec710c8a 100644 --- a/go_mod_indirect_pins.go +++ b/go_mod_indirect_pins.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 //go:build tools diff --git a/handler.go b/handler.go index 6a389b9fc..b98cd7f9d 100644 --- a/handler.go +++ b/handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/handler/oauth2/flow_authorize_code_auth.go b/handler/oauth2/flow_authorize_code_auth.go index 0b03c8a78..ef8511e7e 100644 --- a/handler/oauth2/flow_authorize_code_auth.go +++ b/handler/oauth2/flow_authorize_code_auth.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_authorize_code_auth_test.go b/handler/oauth2/flow_authorize_code_auth_test.go index f915fefbd..c2366e2ba 100644 --- a/handler/oauth2/flow_authorize_code_auth_test.go +++ b/handler/oauth2/flow_authorize_code_auth_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_authorize_code_token.go b/handler/oauth2/flow_authorize_code_token.go index 3b808aabc..7c1c8a44e 100644 --- a/handler/oauth2/flow_authorize_code_token.go +++ b/handler/oauth2/flow_authorize_code_token.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_authorize_code_token_test.go b/handler/oauth2/flow_authorize_code_token_test.go index 34e88830c..906cb946e 100644 --- a/handler/oauth2/flow_authorize_code_token_test.go +++ b/handler/oauth2/flow_authorize_code_token_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_authorize_implicit.go b/handler/oauth2/flow_authorize_implicit.go index c5c48d8e5..199296e3f 100644 --- a/handler/oauth2/flow_authorize_implicit.go +++ b/handler/oauth2/flow_authorize_implicit.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_authorize_implicit_test.go b/handler/oauth2/flow_authorize_implicit_test.go index 3cac0db34..ede6709f8 100644 --- a/handler/oauth2/flow_authorize_implicit_test.go +++ b/handler/oauth2/flow_authorize_implicit_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_client_credentials.go b/handler/oauth2/flow_client_credentials.go index bcf3cdc11..009c0cb95 100644 --- a/handler/oauth2/flow_client_credentials.go +++ b/handler/oauth2/flow_client_credentials.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_client_credentials_storage.go b/handler/oauth2/flow_client_credentials_storage.go index a8314b838..2928ee797 100644 --- a/handler/oauth2/flow_client_credentials_storage.go +++ b/handler/oauth2/flow_client_credentials_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_client_credentials_test.go b/handler/oauth2/flow_client_credentials_test.go index 8d9c906ca..46117a6c7 100644 --- a/handler/oauth2/flow_client_credentials_test.go +++ b/handler/oauth2/flow_client_credentials_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_refresh.go b/handler/oauth2/flow_refresh.go index bffddad64..b575eabd9 100644 --- a/handler/oauth2/flow_refresh.go +++ b/handler/oauth2/flow_refresh.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_refresh_test.go b/handler/oauth2/flow_refresh_test.go index 4f2bc57c2..43e8f49c8 100644 --- a/handler/oauth2/flow_refresh_test.go +++ b/handler/oauth2/flow_refresh_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_resource_owner.go b/handler/oauth2/flow_resource_owner.go index 8474092c9..ea9e14bcc 100644 --- a/handler/oauth2/flow_resource_owner.go +++ b/handler/oauth2/flow_resource_owner.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_resource_owner_storage.go b/handler/oauth2/flow_resource_owner_storage.go index b0b4efdb2..99b6f67d1 100644 --- a/handler/oauth2/flow_resource_owner_storage.go +++ b/handler/oauth2/flow_resource_owner_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/flow_resource_owner_test.go b/handler/oauth2/flow_resource_owner_test.go index c03d219d6..f39069a3d 100644 --- a/handler/oauth2/flow_resource_owner_test.go +++ b/handler/oauth2/flow_resource_owner_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/helper.go b/handler/oauth2/helper.go index 7edf805bc..0103a1409 100644 --- a/handler/oauth2/helper.go +++ b/handler/oauth2/helper.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/helper_test.go b/handler/oauth2/helper_test.go index 395000d9c..f963459e6 100644 --- a/handler/oauth2/helper_test.go +++ b/handler/oauth2/helper_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/introspector.go b/handler/oauth2/introspector.go index ebc69ac8b..49ff12d5c 100644 --- a/handler/oauth2/introspector.go +++ b/handler/oauth2/introspector.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/introspector_jwt.go b/handler/oauth2/introspector_jwt.go index 463842ae1..7ddba16b2 100644 --- a/handler/oauth2/introspector_jwt.go +++ b/handler/oauth2/introspector_jwt.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/introspector_jwt_test.go b/handler/oauth2/introspector_jwt_test.go index 77482dc8e..6d8463de5 100644 --- a/handler/oauth2/introspector_jwt_test.go +++ b/handler/oauth2/introspector_jwt_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/introspector_test.go b/handler/oauth2/introspector_test.go index 20834ab72..924a3a3ec 100644 --- a/handler/oauth2/introspector_test.go +++ b/handler/oauth2/introspector_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/providers.go b/handler/oauth2/providers.go index e02a696e4..864e75a66 100644 --- a/handler/oauth2/providers.go +++ b/handler/oauth2/providers.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/revocation.go b/handler/oauth2/revocation.go index 0a3e3fc44..8c53d3ba7 100644 --- a/handler/oauth2/revocation.go +++ b/handler/oauth2/revocation.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/revocation_storage.go b/handler/oauth2/revocation_storage.go index 33cf5b935..3e0abb7c1 100644 --- a/handler/oauth2/revocation_storage.go +++ b/handler/oauth2/revocation_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/revocation_test.go b/handler/oauth2/revocation_test.go index ad95d8e76..41f7a3e5d 100644 --- a/handler/oauth2/revocation_test.go +++ b/handler/oauth2/revocation_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/storage.go b/handler/oauth2/storage.go index 52c4c3b91..3ee56bbef 100644 --- a/handler/oauth2/storage.go +++ b/handler/oauth2/storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/strategy.go b/handler/oauth2/strategy.go index f8ae9a289..727078374 100644 --- a/handler/oauth2/strategy.go +++ b/handler/oauth2/strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/strategy_hmacsha_plain.go b/handler/oauth2/strategy_hmacsha_plain.go index 13000a299..1ee7a9c7c 100644 --- a/handler/oauth2/strategy_hmacsha_plain.go +++ b/handler/oauth2/strategy_hmacsha_plain.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/strategy_hmacsha_prefixed.go b/handler/oauth2/strategy_hmacsha_prefixed.go index 19d7509ee..c119fdca2 100644 --- a/handler/oauth2/strategy_hmacsha_prefixed.go +++ b/handler/oauth2/strategy_hmacsha_prefixed.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/strategy_hmacsha_test.go b/handler/oauth2/strategy_hmacsha_test.go index 7a6bc2870..28cdc9d49 100644 --- a/handler/oauth2/strategy_hmacsha_test.go +++ b/handler/oauth2/strategy_hmacsha_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/strategy_jwt.go b/handler/oauth2/strategy_jwt.go index 6af6ad16b..1e197d76a 100644 --- a/handler/oauth2/strategy_jwt.go +++ b/handler/oauth2/strategy_jwt.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/strategy_jwt_session.go b/handler/oauth2/strategy_jwt_session.go index e6c94b30d..062f9f76c 100644 --- a/handler/oauth2/strategy_jwt_session.go +++ b/handler/oauth2/strategy_jwt_session.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/oauth2/strategy_jwt_test.go b/handler/oauth2/strategy_jwt_test.go index cdfb9ce12..54a0e286a 100644 --- a/handler/oauth2/strategy_jwt_test.go +++ b/handler/oauth2/strategy_jwt_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oauth2 diff --git a/handler/openid/errors.go b/handler/openid/errors.go index e6641b700..81436b95c 100644 --- a/handler/openid/errors.go +++ b/handler/openid/errors.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_device_auth.go b/handler/openid/flow_device_auth.go index c780d5fe0..03cf634e6 100644 --- a/handler/openid/flow_device_auth.go +++ b/handler/openid/flow_device_auth.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_device_auth_test.go b/handler/openid/flow_device_auth_test.go index 2daa4c5b8..b5adf2202 100644 --- a/handler/openid/flow_device_auth_test.go +++ b/handler/openid/flow_device_auth_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_device_token.go b/handler/openid/flow_device_token.go index 7de50469c..62b9bf8ff 100644 --- a/handler/openid/flow_device_token.go +++ b/handler/openid/flow_device_token.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_device_token_test.go b/handler/openid/flow_device_token_test.go index d0d605b42..f73617806 100644 --- a/handler/openid/flow_device_token_test.go +++ b/handler/openid/flow_device_token_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_explicit_auth.go b/handler/openid/flow_explicit_auth.go index da973f8e0..ac9a87a2b 100644 --- a/handler/openid/flow_explicit_auth.go +++ b/handler/openid/flow_explicit_auth.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_explicit_auth_test.go b/handler/openid/flow_explicit_auth_test.go index db00bc232..8781d6969 100644 --- a/handler/openid/flow_explicit_auth_test.go +++ b/handler/openid/flow_explicit_auth_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_explicit_token.go b/handler/openid/flow_explicit_token.go index 67bea3402..100568c48 100644 --- a/handler/openid/flow_explicit_token.go +++ b/handler/openid/flow_explicit_token.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_explicit_token_test.go b/handler/openid/flow_explicit_token_test.go index eeddedd2c..775702f90 100644 --- a/handler/openid/flow_explicit_token_test.go +++ b/handler/openid/flow_explicit_token_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_hybrid.go b/handler/openid/flow_hybrid.go index c1dc6c645..3413e1aa2 100644 --- a/handler/openid/flow_hybrid.go +++ b/handler/openid/flow_hybrid.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_hybrid_test.go b/handler/openid/flow_hybrid_test.go index c6baac949..24df90a11 100644 --- a/handler/openid/flow_hybrid_test.go +++ b/handler/openid/flow_hybrid_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_implicit.go b/handler/openid/flow_implicit.go index caf9fa9b0..0efefc894 100644 --- a/handler/openid/flow_implicit.go +++ b/handler/openid/flow_implicit.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_implicit_test.go b/handler/openid/flow_implicit_test.go index 46cab8f74..f5003c219 100644 --- a/handler/openid/flow_implicit_test.go +++ b/handler/openid/flow_implicit_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_refresh_token.go b/handler/openid/flow_refresh_token.go index 73d15b2da..75ec94963 100644 --- a/handler/openid/flow_refresh_token.go +++ b/handler/openid/flow_refresh_token.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/flow_refresh_token_test.go b/handler/openid/flow_refresh_token_test.go index ec4e36bb1..7d1ce2dbb 100644 --- a/handler/openid/flow_refresh_token_test.go +++ b/handler/openid/flow_refresh_token_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/helper.go b/handler/openid/helper.go index e1dc13df6..44f5fbaa6 100644 --- a/handler/openid/helper.go +++ b/handler/openid/helper.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/helper_test.go b/handler/openid/helper_test.go index dc488225d..b09a5e317 100644 --- a/handler/openid/helper_test.go +++ b/handler/openid/helper_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/storage.go b/handler/openid/storage.go index 6f09a7b89..4e49c951d 100644 --- a/handler/openid/storage.go +++ b/handler/openid/storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/strategy.go b/handler/openid/strategy.go index f5353d0b4..cffc43fc7 100644 --- a/handler/openid/strategy.go +++ b/handler/openid/strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/strategy_jwt.go b/handler/openid/strategy_jwt.go index ecd75d8f4..52551fa22 100644 --- a/handler/openid/strategy_jwt.go +++ b/handler/openid/strategy_jwt.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/strategy_jwt_test.go b/handler/openid/strategy_jwt_test.go index fff455194..9a5b065d8 100644 --- a/handler/openid/strategy_jwt_test.go +++ b/handler/openid/strategy_jwt_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/validator.go b/handler/openid/validator.go index f25314943..868dded65 100644 --- a/handler/openid/validator.go +++ b/handler/openid/validator.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/openid/validator_test.go b/handler/openid/validator_test.go index d22bb33ef..df8750f03 100644 --- a/handler/openid/validator_test.go +++ b/handler/openid/validator_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package openid diff --git a/handler/par/flow_pushed_authorize.go b/handler/par/flow_pushed_authorize.go index 7d6b532c2..4850134b8 100644 --- a/handler/par/flow_pushed_authorize.go +++ b/handler/par/flow_pushed_authorize.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package par diff --git a/handler/par/flow_pushed_authorize_test.go b/handler/par/flow_pushed_authorize_test.go index 7b69f9515..0d9fa5f50 100644 --- a/handler/par/flow_pushed_authorize_test.go +++ b/handler/par/flow_pushed_authorize_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package par_test diff --git a/handler/pkce/handler.go b/handler/pkce/handler.go index 3deb94b31..24c11475b 100644 --- a/handler/pkce/handler.go +++ b/handler/pkce/handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package pkce diff --git a/handler/pkce/handler_test.go b/handler/pkce/handler_test.go index 83a563623..905a987db 100644 --- a/handler/pkce/handler_test.go +++ b/handler/pkce/handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package pkce diff --git a/handler/pkce/storage.go b/handler/pkce/storage.go index 2b74bedf8..89b47f6e7 100644 --- a/handler/pkce/storage.go +++ b/handler/pkce/storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package pkce diff --git a/handler/rfc7523/handler.go b/handler/rfc7523/handler.go index 4c7767e8a..921642912 100644 --- a/handler/rfc7523/handler.go +++ b/handler/rfc7523/handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc7523 diff --git a/handler/rfc7523/handler_test.go b/handler/rfc7523/handler_test.go index 45d8044e9..af5578e2e 100644 --- a/handler/rfc7523/handler_test.go +++ b/handler/rfc7523/handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc7523 diff --git a/handler/rfc7523/session.go b/handler/rfc7523/session.go index 43aecddb7..2e445514c 100644 --- a/handler/rfc7523/session.go +++ b/handler/rfc7523/session.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc7523 diff --git a/handler/rfc7523/storage.go b/handler/rfc7523/storage.go index 5bf008ed1..60da159a4 100644 --- a/handler/rfc7523/storage.go +++ b/handler/rfc7523/storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc7523 diff --git a/handler/rfc8628/auth_handler.go b/handler/rfc8628/auth_handler.go index 627e21700..af736d2a8 100644 --- a/handler/rfc8628/auth_handler.go +++ b/handler/rfc8628/auth_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628 diff --git a/handler/rfc8628/auth_handler_test.go b/handler/rfc8628/auth_handler_test.go index 514b072ea..10748cd83 100644 --- a/handler/rfc8628/auth_handler_test.go +++ b/handler/rfc8628/auth_handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628_test diff --git a/handler/rfc8628/storage.go b/handler/rfc8628/storage.go index dea0b6a12..9389a5d03 100644 --- a/handler/rfc8628/storage.go +++ b/handler/rfc8628/storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628 diff --git a/handler/rfc8628/strategy.go b/handler/rfc8628/strategy.go index cd32bb533..15d66b734 100644 --- a/handler/rfc8628/strategy.go +++ b/handler/rfc8628/strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628 diff --git a/handler/rfc8628/strategy_hmacsha.go b/handler/rfc8628/strategy_hmacsha.go index 099592765..e46e0f91c 100644 --- a/handler/rfc8628/strategy_hmacsha.go +++ b/handler/rfc8628/strategy_hmacsha.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628 diff --git a/handler/rfc8628/strategy_hmacsha_test.go b/handler/rfc8628/strategy_hmacsha_test.go index bb625251a..524ac25c2 100644 --- a/handler/rfc8628/strategy_hmacsha_test.go +++ b/handler/rfc8628/strategy_hmacsha_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628_test diff --git a/handler/rfc8628/token_handler.go b/handler/rfc8628/token_handler.go index 8e832c27b..e9be69a5d 100644 --- a/handler/rfc8628/token_handler.go +++ b/handler/rfc8628/token_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628 diff --git a/handler/rfc8628/token_handler_test.go b/handler/rfc8628/token_handler_test.go index 8c0e3f16e..6173251f7 100644 --- a/handler/rfc8628/token_handler_test.go +++ b/handler/rfc8628/token_handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package rfc8628 diff --git a/handler/verifiable/handler.go b/handler/verifiable/handler.go index be7b1a16d..10a0fc944 100644 --- a/handler/verifiable/handler.go +++ b/handler/verifiable/handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package verifiable diff --git a/handler/verifiable/handler_test.go b/handler/verifiable/handler_test.go index 930e49c9e..a23adaa78 100644 --- a/handler/verifiable/handler_test.go +++ b/handler/verifiable/handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package verifiable diff --git a/handler/verifiable/nonce.go b/handler/verifiable/nonce.go index 0e12c412e..754d5645f 100644 --- a/handler/verifiable/nonce.go +++ b/handler/verifiable/nonce.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package verifiable diff --git a/hash.go b/hash.go index 39cb4d1f5..10da2b2b3 100644 --- a/hash.go +++ b/hash.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/hash_bcrypt.go b/hash_bcrypt.go index 6f2675a1c..47a721fb2 100644 --- a/hash_bcrypt.go +++ b/hash_bcrypt.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/hash_bcrypt_test.go b/hash_bcrypt_test.go index f7aa04fff..97196ff91 100644 --- a/hash_bcrypt_test.go +++ b/hash_bcrypt_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/helper.go b/helper.go index 6a36c77cb..1f5d6911b 100644 --- a/helper.go +++ b/helper.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/helper_test.go b/helper_test.go index c8afcf7e0..5c0264791 100644 --- a/helper_test.go +++ b/helper_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/i18n/default_catalog.go b/i18n/default_catalog.go index 55914192c..e99df17c5 100644 --- a/i18n/default_catalog.go +++ b/i18n/default_catalog.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package i18n diff --git a/i18n/i18n.go b/i18n/i18n.go index ba2515331..a446ff2b9 100644 --- a/i18n/i18n.go +++ b/i18n/i18n.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package i18n diff --git a/i18n/i18n_test.go b/i18n/i18n_test.go index ffbd9d835..94a185a81 100644 --- a/i18n/i18n_test.go +++ b/i18n/i18n_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package i18n diff --git a/i18n_helper.go b/i18n_helper.go index fec72f1a7..600d1c6cb 100644 --- a/i18n_helper.go +++ b/i18n_helper.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/i18n_helper_test.go b/i18n_helper_test.go index a3472d23f..8a7bf3ce0 100644 --- a/i18n_helper_test.go +++ b/i18n_helper_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/integration/authorize_code_grant_public_client_pkce_test.go b/integration/authorize_code_grant_public_client_pkce_test.go index 74426daed..e8958d0be 100644 --- a/integration/authorize_code_grant_public_client_pkce_test.go +++ b/integration/authorize_code_grant_public_client_pkce_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/authorize_code_grant_public_client_test.go b/integration/authorize_code_grant_public_client_test.go index 24d8d64bd..a57f87d34 100644 --- a/integration/authorize_code_grant_public_client_test.go +++ b/integration/authorize_code_grant_public_client_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/authorize_code_grant_test.go b/integration/authorize_code_grant_test.go index 13a663c7a..2939adeca 100644 --- a/integration/authorize_code_grant_test.go +++ b/integration/authorize_code_grant_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/authorize_device_grant_request_test.go b/integration/authorize_device_grant_request_test.go index 7ba7eac83..24e35c81a 100644 --- a/integration/authorize_device_grant_request_test.go +++ b/integration/authorize_device_grant_request_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/authorize_form_post_test.go b/integration/authorize_form_post_test.go index ceafd3a44..c72782b11 100644 --- a/integration/authorize_form_post_test.go +++ b/integration/authorize_form_post_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/authorize_implicit_grant_test.go b/integration/authorize_implicit_grant_test.go index 7ac1704c4..c5981a541 100644 --- a/integration/authorize_implicit_grant_test.go +++ b/integration/authorize_implicit_grant_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/authorize_jwt_bearer_required_iat_test.go b/integration/authorize_jwt_bearer_required_iat_test.go index 6b91754cc..a63e453f2 100644 --- a/integration/authorize_jwt_bearer_required_iat_test.go +++ b/integration/authorize_jwt_bearer_required_iat_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/authorize_jwt_bearer_required_jti_test.go b/integration/authorize_jwt_bearer_required_jti_test.go index ff941d4b2..5938dcb5e 100644 --- a/integration/authorize_jwt_bearer_required_jti_test.go +++ b/integration/authorize_jwt_bearer_required_jti_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/authorize_jwt_bearer_test.go b/integration/authorize_jwt_bearer_test.go index 844383453..7d44888f0 100644 --- a/integration/authorize_jwt_bearer_test.go +++ b/integration/authorize_jwt_bearer_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/authorize_response_mode_test.go b/integration/authorize_response_mode_test.go index e1b7e227a..eaf849963 100644 --- a/integration/authorize_response_mode_test.go +++ b/integration/authorize_response_mode_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/client_credentials_grant_test.go b/integration/client_credentials_grant_test.go index 58ca6b3ed..acae590c6 100644 --- a/integration/client_credentials_grant_test.go +++ b/integration/client_credentials_grant_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/clients/error.go b/integration/clients/error.go index db5f6be85..46dc0a350 100644 --- a/integration/clients/error.go +++ b/integration/clients/error.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package clients diff --git a/integration/clients/introspect.go b/integration/clients/introspect.go index 2d77f8be7..abc233852 100644 --- a/integration/clients/introspect.go +++ b/integration/clients/introspect.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package clients diff --git a/integration/clients/jwt_bearer.go b/integration/clients/jwt_bearer.go index dce715fb9..6dbfd3fe6 100644 --- a/integration/clients/jwt_bearer.go +++ b/integration/clients/jwt_bearer.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package clients diff --git a/integration/helper_endpoints_test.go b/integration/helper_endpoints_test.go index 4f6ef0f56..d77e03fb1 100644 --- a/integration/helper_endpoints_test.go +++ b/integration/helper_endpoints_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/helper_setup_test.go b/integration/helper_setup_test.go index bd83e6030..5034c4c31 100644 --- a/integration/helper_setup_test.go +++ b/integration/helper_setup_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/introspect_jwt_bearer_token_test.go b/integration/introspect_jwt_bearer_token_test.go index a5b85a69c..a4cc5f7e1 100644 --- a/integration/introspect_jwt_bearer_token_test.go +++ b/integration/introspect_jwt_bearer_token_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/introspect_token_test.go b/integration/introspect_token_test.go index 5f3a14cc3..825709869 100644 --- a/integration/introspect_token_test.go +++ b/integration/introspect_token_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/oidc_explicit_test.go b/integration/oidc_explicit_test.go index 5fa06e526..10eef5009 100644 --- a/integration/oidc_explicit_test.go +++ b/integration/oidc_explicit_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/oidc_implicit_hybrid_public_client_pkce_test.go b/integration/oidc_implicit_hybrid_public_client_pkce_test.go index 35becff19..6aa5a23c0 100644 --- a/integration/oidc_implicit_hybrid_public_client_pkce_test.go +++ b/integration/oidc_implicit_hybrid_public_client_pkce_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/oidc_implicit_hybrid_test.go b/integration/oidc_implicit_hybrid_test.go index 7050cee80..b5bad4621 100644 --- a/integration/oidc_implicit_hybrid_test.go +++ b/integration/oidc_implicit_hybrid_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/placeholder.go b/integration/placeholder.go index f1b7fc193..eabb14bb7 100644 --- a/integration/placeholder.go +++ b/integration/placeholder.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration diff --git a/integration/pushed_authorize_code_grant_test.go b/integration/pushed_authorize_code_grant_test.go index 0d9a710d1..408df8782 100644 --- a/integration/pushed_authorize_code_grant_test.go +++ b/integration/pushed_authorize_code_grant_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/refresh_token_grant_test.go b/integration/refresh_token_grant_test.go index 1bfdc1d53..aefebb929 100644 --- a/integration/refresh_token_grant_test.go +++ b/integration/refresh_token_grant_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/resource_owner_password_credentials_grant_test.go b/integration/resource_owner_password_credentials_grant_test.go index f1b45b467..f1a1e710e 100644 --- a/integration/resource_owner_password_credentials_grant_test.go +++ b/integration/resource_owner_password_credentials_grant_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/integration/revoke_token_test.go b/integration/revoke_token_test.go index bb74dae96..cf9b5d02b 100644 --- a/integration/revoke_token_test.go +++ b/integration/revoke_token_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package integration_test diff --git a/internal/access_request.go b/internal/access_request.go index a37d0de3c..56694216b 100644 --- a/internal/access_request.go +++ b/internal/access_request.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/access_response.go b/internal/access_response.go index fd0b55e7f..4ba937883 100644 --- a/internal/access_response.go +++ b/internal/access_response.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/access_token_storage.go b/internal/access_token_storage.go index 937ee5cc7..0082eec34 100644 --- a/internal/access_token_storage.go +++ b/internal/access_token_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/access_token_strategy.go b/internal/access_token_strategy.go index d9d7545e5..cdd224ef8 100644 --- a/internal/access_token_strategy.go +++ b/internal/access_token_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/authorize_code_storage.go b/internal/authorize_code_storage.go index f0fef08b6..246b77e97 100644 --- a/internal/authorize_code_storage.go +++ b/internal/authorize_code_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/authorize_code_strategy.go b/internal/authorize_code_strategy.go index 67ec01220..a143faa85 100644 --- a/internal/authorize_code_strategy.go +++ b/internal/authorize_code_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/authorize_handler.go b/internal/authorize_handler.go index 80cf21a88..36bec0504 100644 --- a/internal/authorize_handler.go +++ b/internal/authorize_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/authorize_request.go b/internal/authorize_request.go index 85666eab5..69e6cbe49 100644 --- a/internal/authorize_request.go +++ b/internal/authorize_request.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/authorize_response.go b/internal/authorize_response.go index 659bb1369..13c4709d2 100644 --- a/internal/authorize_response.go +++ b/internal/authorize_response.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/client.go b/internal/client.go index 228ec8b81..522d9384e 100644 --- a/internal/client.go +++ b/internal/client.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/device_code_rate_limit_strategy.go b/internal/device_code_rate_limit_strategy.go index 1a3c037c5..a0903b55b 100644 --- a/internal/device_code_rate_limit_strategy.go +++ b/internal/device_code_rate_limit_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/gen/key.go b/internal/gen/key.go index 959032e80..35edfa61e 100644 --- a/internal/gen/key.go +++ b/internal/gen/key.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package gen diff --git a/internal/hash.go b/internal/hash.go index 786647a7f..1480152b8 100644 --- a/internal/hash.go +++ b/internal/hash.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/id_token_strategy.go b/internal/id_token_strategy.go index 01cade8fc..05b5f524d 100644 --- a/internal/id_token_strategy.go +++ b/internal/id_token_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/introspector.go b/internal/introspector.go index 585fd823b..c2dd27c3a 100644 --- a/internal/introspector.go +++ b/internal/introspector.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/oauth2_auth_jwt_storage.go b/internal/oauth2_auth_jwt_storage.go index 5aa937b23..e7e4398bb 100644 --- a/internal/oauth2_auth_jwt_storage.go +++ b/internal/oauth2_auth_jwt_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/oauth2_client_storage.go b/internal/oauth2_client_storage.go index 892f3b69a..4a52d2cdc 100644 --- a/internal/oauth2_client_storage.go +++ b/internal/oauth2_client_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/oauth2_explicit_storage.go b/internal/oauth2_explicit_storage.go index 9e78dcdb2..aff385540 100644 --- a/internal/oauth2_explicit_storage.go +++ b/internal/oauth2_explicit_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Automatically generated by MockGen. DO NOT EDIT! diff --git a/internal/oauth2_owner_storage.go b/internal/oauth2_owner_storage.go index 68bdfa7ee..57adf311a 100644 --- a/internal/oauth2_owner_storage.go +++ b/internal/oauth2_owner_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/oauth2_refresh_storage.go b/internal/oauth2_refresh_storage.go index 8cf6eaa75..7a7ffc6f9 100644 --- a/internal/oauth2_refresh_storage.go +++ b/internal/oauth2_refresh_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Automatically generated by MockGen. DO NOT EDIT! diff --git a/internal/oauth2_revoke_storage.go b/internal/oauth2_revoke_storage.go index 04e2dfae4..939baf420 100644 --- a/internal/oauth2_revoke_storage.go +++ b/internal/oauth2_revoke_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/oauth2_storage.go b/internal/oauth2_storage.go index 772e39fd9..bc6cf1bcb 100644 --- a/internal/oauth2_storage.go +++ b/internal/oauth2_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/oauth2_strategy.go b/internal/oauth2_strategy.go index 456ab2e20..2c15a3bb1 100644 --- a/internal/oauth2_strategy.go +++ b/internal/oauth2_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/openid_id_token_storage.go b/internal/openid_id_token_storage.go index cc2a4d198..d6e4cf640 100644 --- a/internal/openid_id_token_storage.go +++ b/internal/openid_id_token_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/pkce_storage_strategy.go b/internal/pkce_storage_strategy.go index 745add3a3..70672e050 100644 --- a/internal/pkce_storage_strategy.go +++ b/internal/pkce_storage_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/pushed_authorize_handler.go b/internal/pushed_authorize_handler.go index a017f56d9..7044cc8d3 100644 --- a/internal/pushed_authorize_handler.go +++ b/internal/pushed_authorize_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package internal diff --git a/internal/refresh_token_strategy.go b/internal/refresh_token_strategy.go index d160397c9..691031f67 100644 --- a/internal/refresh_token_strategy.go +++ b/internal/refresh_token_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/request.go b/internal/request.go index 7135980c5..6c22481dd 100644 --- a/internal/request.go +++ b/internal/request.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/revoke_handler.go b/internal/revoke_handler.go index e77291086..8679e99d0 100644 --- a/internal/revoke_handler.go +++ b/internal/revoke_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/rfc8628_code_strategy.go b/internal/rfc8628_code_strategy.go index 944a07b99..17abcc1fd 100644 --- a/internal/rfc8628_code_strategy.go +++ b/internal/rfc8628_code_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/rfc8628_core_storage.go b/internal/rfc8628_core_storage.go index 30229bc92..07e3884f9 100644 --- a/internal/rfc8628_core_storage.go +++ b/internal/rfc8628_core_storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/rw.go b/internal/rw.go index 674d323d2..0c9cafc2b 100644 --- a/internal/rw.go +++ b/internal/rw.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Automatically generated by MockGen. DO NOT EDIT! diff --git a/internal/storage.go b/internal/storage.go index 8a2cf9ce8..18ce1d483 100644 --- a/internal/storage.go +++ b/internal/storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/test_helpers.go b/internal/test_helpers.go index 323a934bf..805a0b27a 100644 --- a/internal/test_helpers.go +++ b/internal/test_helpers.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package internal diff --git a/internal/token_handler.go b/internal/token_handler.go index be25ceb9c..db895322a 100644 --- a/internal/token_handler.go +++ b/internal/token_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/internal/transactional.go b/internal/transactional.go index 4bcf74991..b7b6b898f 100644 --- a/internal/transactional.go +++ b/internal/transactional.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Code generated by MockGen. DO NOT EDIT. diff --git a/introspect.go b/introspect.go index 7e6e6058d..bffcd8c27 100644 --- a/introspect.go +++ b/introspect.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/introspect_test.go b/introspect_test.go index f2a4669ef..3f7da0fbe 100644 --- a/introspect_test.go +++ b/introspect_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/introspection_request_handler.go b/introspection_request_handler.go index f1fdedd6c..682841cae 100644 --- a/introspection_request_handler.go +++ b/introspection_request_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/introspection_request_handler_test.go b/introspection_request_handler_test.go index 3ab6fc8b6..067a5092d 100644 --- a/introspection_request_handler_test.go +++ b/introspection_request_handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/introspection_response_writer.go b/introspection_response_writer.go index e0a3763ec..73c683788 100644 --- a/introspection_response_writer.go +++ b/introspection_response_writer.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/introspection_response_writer_test.go b/introspection_response_writer_test.go index d512a54b9..431dd4e8d 100644 --- a/introspection_response_writer_test.go +++ b/introspection_response_writer_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/oauth2.go b/oauth2.go index cbae4cfec..cfd64a3bf 100644 --- a/oauth2.go +++ b/oauth2.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/pushed_authorize_request_handler.go b/pushed_authorize_request_handler.go index 17c493b33..d7a81df38 100644 --- a/pushed_authorize_request_handler.go +++ b/pushed_authorize_request_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/pushed_authorize_request_handler_test.go b/pushed_authorize_request_handler_test.go index 7898cb4f1..94ec8868c 100644 --- a/pushed_authorize_request_handler_test.go +++ b/pushed_authorize_request_handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/pushed_authorize_response.go b/pushed_authorize_response.go index 3b8f9de18..048788a8f 100644 --- a/pushed_authorize_response.go +++ b/pushed_authorize_response.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/pushed_authorize_response_writer.go b/pushed_authorize_response_writer.go index 46ed2780c..ecbab8ee0 100644 --- a/pushed_authorize_response_writer.go +++ b/pushed_authorize_response_writer.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/pushed_authorize_response_writer_test.go b/pushed_authorize_response_writer_test.go index e7a9269f3..5c82862ab 100644 --- a/pushed_authorize_response_writer_test.go +++ b/pushed_authorize_response_writer_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/request.go b/request.go index 26fe7365d..42c92abb1 100644 --- a/request.go +++ b/request.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/request_test.go b/request_test.go index 459d69cbf..204cd3c87 100644 --- a/request_test.go +++ b/request_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/response_handler.go b/response_handler.go index c26ba85d8..901185a7c 100644 --- a/response_handler.go +++ b/response_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/revoke_handler.go b/revoke_handler.go index 1bdcf17cf..214808b8a 100644 --- a/revoke_handler.go +++ b/revoke_handler.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/revoke_handler_test.go b/revoke_handler_test.go index 97f9063ce..55370fb51 100644 --- a/revoke_handler_test.go +++ b/revoke_handler_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite_test diff --git a/scope_strategy.go b/scope_strategy.go index 33b5b673c..358f3b7f3 100644 --- a/scope_strategy.go +++ b/scope_strategy.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/scope_strategy_test.go b/scope_strategy_test.go index cfd9cb2b2..a30a753b8 100644 --- a/scope_strategy_test.go +++ b/scope_strategy_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/session.go b/session.go index 6f95b2cf1..33d31479d 100644 --- a/session.go +++ b/session.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/session_test.go b/session_test.go index 52c5c3c64..bb8615d85 100644 --- a/session_test.go +++ b/session_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/storage.go b/storage.go index 11edee276..7e4aacd8b 100644 --- a/storage.go +++ b/storage.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package fosite diff --git a/storage/memory.go b/storage/memory.go index c1d6ff1ae..69e277204 100644 --- a/storage/memory.go +++ b/storage/memory.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package storage diff --git a/storage/memory_test.go b/storage/memory_test.go index d06f4a409..ddd806e4e 100644 --- a/storage/memory_test.go +++ b/storage/memory_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package storage diff --git a/storage/transactional.go b/storage/transactional.go index f144340fb..418428d38 100644 --- a/storage/transactional.go +++ b/storage/transactional.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package storage diff --git a/token/hmac/bytes.go b/token/hmac/bytes.go index b991e0754..cacdcd60d 100644 --- a/token/hmac/bytes.go +++ b/token/hmac/bytes.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package hmac diff --git a/token/hmac/bytes_test.go b/token/hmac/bytes_test.go index 5e1beb4e1..12aa1fc0f 100644 --- a/token/hmac/bytes_test.go +++ b/token/hmac/bytes_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package hmac diff --git a/token/hmac/hmacsha.go b/token/hmac/hmacsha.go index eaeb51d51..d319ef608 100644 --- a/token/hmac/hmacsha.go +++ b/token/hmac/hmacsha.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Package hmac is the default implementation for generating and validating challenges. It uses SHA-512/256 to diff --git a/token/hmac/hmacsha_test.go b/token/hmac/hmacsha_test.go index c9d464df9..43b1d0539 100644 --- a/token/hmac/hmacsha_test.go +++ b/token/hmac/hmacsha_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package hmac diff --git a/token/jwt/claims.go b/token/jwt/claims.go index a03155c9e..f60bbcf25 100644 --- a/token/jwt/claims.go +++ b/token/jwt/claims.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/token/jwt/claims_id_token.go b/token/jwt/claims_id_token.go index b560de6e5..225ae1f6e 100644 --- a/token/jwt/claims_id_token.go +++ b/token/jwt/claims_id_token.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/token/jwt/claims_id_token_test.go b/token/jwt/claims_id_token_test.go index e2dca9c6b..febb7c330 100644 --- a/token/jwt/claims_id_token_test.go +++ b/token/jwt/claims_id_token_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt_test diff --git a/token/jwt/claims_jwt.go b/token/jwt/claims_jwt.go index d8df95190..7605c38fc 100644 --- a/token/jwt/claims_jwt.go +++ b/token/jwt/claims_jwt.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/token/jwt/claims_jwt_test.go b/token/jwt/claims_jwt_test.go index 9e0baf303..af23afaad 100644 --- a/token/jwt/claims_jwt_test.go +++ b/token/jwt/claims_jwt_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt_test diff --git a/token/jwt/claims_test.go b/token/jwt/claims_test.go index 6041b0e43..739020d67 100644 --- a/token/jwt/claims_test.go +++ b/token/jwt/claims_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/token/jwt/header.go b/token/jwt/header.go index a955e9f0d..8fdaa3ddf 100644 --- a/token/jwt/header.go +++ b/token/jwt/header.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/token/jwt/header_test.go b/token/jwt/header_test.go index f92d34c28..3c5a66695 100644 --- a/token/jwt/header_test.go +++ b/token/jwt/header_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/token/jwt/jwt.go b/token/jwt/jwt.go index dc7f96e19..9c5aa5775 100644 --- a/token/jwt/jwt.go +++ b/token/jwt/jwt.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 // Package jwt is able to generate and validate json web tokens. diff --git a/token/jwt/jwt_test.go b/token/jwt/jwt_test.go index 44392f4df..1939d7bba 100644 --- a/token/jwt/jwt_test.go +++ b/token/jwt/jwt_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/token/jwt/map_claims.go b/token/jwt/map_claims.go index 35b722a8d..d4f75285c 100644 --- a/token/jwt/map_claims.go +++ b/token/jwt/map_claims.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/token/jwt/map_claims_test.go b/token/jwt/map_claims_test.go index a0fa00445..cc4f08219 100644 --- a/token/jwt/map_claims_test.go +++ b/token/jwt/map_claims_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/token/jwt/token.go b/token/jwt/token.go index 2650c030f..85acab177 100644 --- a/token/jwt/token.go +++ b/token/jwt/token.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/token/jwt/token_test.go b/token/jwt/token_test.go index 3d09a91af..e6c3cd583 100644 --- a/token/jwt/token_test.go +++ b/token/jwt/token_test.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/token/jwt/validation_error.go b/token/jwt/validation_error.go index d9324f61f..b39bafe4c 100644 --- a/token/jwt/validation_error.go +++ b/token/jwt/validation_error.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 package jwt diff --git a/tools.go b/tools.go index 12c3ef948..7e1cfbeb1 100644 --- a/tools.go +++ b/tools.go @@ -1,4 +1,4 @@ -// Copyright © 2024 Ory Corp +// Copyright © 2025 Ory Corp // SPDX-License-Identifier: Apache-2.0 //go:build tools From b77efc392574601140462d144f80ed6601cdf18c Mon Sep 17 00:00:00 2001 From: Nikos Date: Fri, 24 Jan 2025 16:56:49 +0100 Subject: [PATCH 36/36] fix: write device_code expiration in session --- handler/rfc8628/auth_handler.go | 1 + 1 file changed, 1 insertion(+) diff --git a/handler/rfc8628/auth_handler.go b/handler/rfc8628/auth_handler.go index af736d2a8..37fa1da5a 100644 --- a/handler/rfc8628/auth_handler.go +++ b/handler/rfc8628/auth_handler.go @@ -55,6 +55,7 @@ func (d *DeviceAuthHandler) handleDeviceAuthSession(ctx context.Context, dar fos } dar.GetSession().SetExpiresAt(fosite.UserCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx)).Round(time.Second)) + dar.GetSession().SetExpiresAt(fosite.DeviceCode, time.Now().UTC().Add(d.Config.GetDeviceAndUserCodeLifespan(ctx)).Round(time.Second)) // Note: the retries are added here because we need to ensure uniqueness of user codes. // The chances of duplicates should however be diminishing, because they are the same // chance an attacker will be able to hit a valid code with few guesses. However, as