mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-07-16 04:03:47 +03:00
fix: device authorization resolve resource creating device_code
This commit is contained in:
@@ -50,6 +50,20 @@ func (s *deviceService) createDeviceAuthorization(ctx context.Context, req *http
|
||||
return nil, request, err
|
||||
}
|
||||
|
||||
client := request.GetClient().(Client)
|
||||
resource, err := request.GetResource()
|
||||
if err != nil {
|
||||
return nil, request, err
|
||||
}
|
||||
audience, grantedScopes, _, err := s.authorizationService.resolveGrant(ctx, client.GetID(), resource, request.GetRequestedScopes())
|
||||
if err != nil {
|
||||
if resource != "" && errors.Is(err, fosite.ErrAccessDenied) {
|
||||
return nil, request, fosite.ErrInvalidTarget.WithHintf("The requested resource '%s' is invalid, missing, unknown, or malformed.", resource)
|
||||
}
|
||||
return nil, request, err
|
||||
}
|
||||
grantResourceIndicator(request, audience, grantedScopes)
|
||||
|
||||
session := NewEmptySession()
|
||||
response, err := s.provider.NewDeviceResponse(ctx, request, session)
|
||||
if err != nil {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ory/fosite"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/model"
|
||||
testutils "github.com/pocket-id/pocket-id/backend/internal/utils/testing"
|
||||
@@ -84,31 +85,38 @@ func TestDeviceServiceAcceptUsesReauthenticationTimeForDeviceSession(t *testing.
|
||||
require.Equal(t, reauthenticatedAt, session.IDTokenClaims().AuthTime)
|
||||
}
|
||||
|
||||
func TestDeviceServiceCreateRejectsResourceWithoutUserDelegatedGrant(t *testing.T) {
|
||||
const (
|
||||
userID = "test-user"
|
||||
clientID = "test-client"
|
||||
audience = "https://api.orders.example.com"
|
||||
)
|
||||
apiAccess := fakeAPIAccess{allowed: map[string]map[SubjectType][]string{
|
||||
audience: {
|
||||
SubjectTypeClient: {"write:orders"},
|
||||
},
|
||||
}}
|
||||
service, store, _ := newTestDeviceService(t, clientID, userID, false, nil, apiAccess)
|
||||
|
||||
form := url.Values{
|
||||
"client_id": {clientID},
|
||||
"resource": {audience},
|
||||
"scope": {"write:orders"},
|
||||
}
|
||||
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/api/oidc/device/authorize", strings.NewReader(form.Encode()))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
_, _, err := service.createDeviceAuthorization(t.Context(), req)
|
||||
require.ErrorIs(t, err, fosite.ErrInvalidTarget)
|
||||
|
||||
var count int64
|
||||
require.NoError(t, store.db.Model(&OAuth2Session{}).Where("kind IN ?", []string{sessionKindDeviceCode, sessionKindUserCode}).Count(&count).Error)
|
||||
require.Zero(t, count)
|
||||
}
|
||||
|
||||
func newTestDeviceServiceWithCode(t *testing.T, clientID, userID string, requiresReauthentication bool, reauth ReauthenticationTokenConsumer) (*deviceService, *Store, *oidcProvider, string, string) {
|
||||
t.Helper()
|
||||
|
||||
db := testutils.NewDatabaseForTest(t)
|
||||
require.NoError(t, db.Create(&model.User{Base: model.Base{ID: userID}}).Error)
|
||||
require.NoError(t, db.Create(&model.OidcClient{
|
||||
Base: model.Base{ID: clientID},
|
||||
Name: "Test Client",
|
||||
IsPublic: true,
|
||||
RequiresReauthentication: requiresReauthentication,
|
||||
}).Error)
|
||||
|
||||
store := NewStore(db, nil)
|
||||
signerKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
require.NoError(t, err)
|
||||
provider, err := newProvider(store, nil, testTokenSigner{key: signerKey}, Config{ //nolint:gosec // static test-only provider secret
|
||||
BaseURL: "https://issuer.example.com",
|
||||
TokenBaseURL: "https://issuer.example.com",
|
||||
Secret: []byte("test-secret"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
claimsService := newClaimsService(db, nil, "", nil)
|
||||
authorizationService := newAuthorizationService(db, newInteractionSessionService(db), claimsService, reauth, &fakeAuditLogger{}, nil)
|
||||
service := newDeviceService(provider, store, provider.deviceStrategy, authorizationService, claimsService, &fakeAuditLogger{}, db)
|
||||
service, store, provider := newTestDeviceService(t, clientID, userID, requiresReauthentication, reauth, nil)
|
||||
|
||||
form := url.Values{
|
||||
"client_id": {clientID},
|
||||
@@ -121,3 +129,32 @@ func newTestDeviceServiceWithCode(t *testing.T, clientID, userID string, require
|
||||
|
||||
return service, store, provider, response.UserCode, response.DeviceCode
|
||||
}
|
||||
|
||||
func newTestDeviceService(t *testing.T, clientID, userID string, requiresReauthentication bool, reauth ReauthenticationTokenConsumer, apiAccess APIAccessProvider) (*deviceService, *Store, *oidcProvider) {
|
||||
t.Helper()
|
||||
|
||||
db := testutils.NewDatabaseForTest(t)
|
||||
require.NoError(t, db.Create(&model.User{Base: model.Base{ID: userID}}).Error)
|
||||
require.NoError(t, db.Create(&model.OidcClient{
|
||||
Base: model.Base{ID: clientID},
|
||||
Name: "Test Client",
|
||||
IsPublic: true,
|
||||
RequiresReauthentication: requiresReauthentication,
|
||||
}).Error)
|
||||
|
||||
store := NewStore(db, apiAccess)
|
||||
signerKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
require.NoError(t, err)
|
||||
provider, err := newProvider(store, nil, testTokenSigner{key: signerKey}, Config{ //nolint:gosec // static test-only provider secret
|
||||
BaseURL: "https://issuer.example.com",
|
||||
TokenBaseURL: "https://issuer.example.com",
|
||||
Secret: []byte("test-secret"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
claimsService := newClaimsService(db, nil, "", nil)
|
||||
authorizationService := newAuthorizationService(db, newInteractionSessionService(db), claimsService, reauth, &fakeAuditLogger{}, apiAccess)
|
||||
service := newDeviceService(provider, store, provider.deviceStrategy, authorizationService, claimsService, &fakeAuditLogger{}, db)
|
||||
|
||||
return service, store, provider
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user