Skip to content

Commit e20228f

Browse files
authored
fix: always pass in identifier into token introspection (#2907)
* feat(auth): check identifier only if present in grant * chore(backend): always pass in identifier during token introspection
1 parent b9be601 commit e20228f

File tree

4 files changed

+140
-30
lines changed

4 files changed

+140
-30
lines changed

packages/auth/src/access/utils.test.ts

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,66 @@ describe('Access utilities', (): void => {
155155
).toBe(true)
156156
})
157157

158+
test('Can compare an access item on a grant and an access item from a request with different action ordering', async (): Promise<void> => {
159+
const grantAccessItemSuperAction = await Access.query(trx).insertAndFetch({
160+
grantId: grant.id,
161+
type: AccessType.OutgoingPayment,
162+
actions: [AccessAction.Create, AccessAction.ReadAll, AccessAction.List],
163+
identifier,
164+
limits: {
165+
receiver,
166+
debitAmount: {
167+
value: '400',
168+
assetCode: 'USD',
169+
assetScale: 2
170+
}
171+
}
172+
})
173+
174+
const requestAccessItem: AccessItem = {
175+
type: 'outgoing-payment',
176+
actions: ['read', 'list', 'create'],
177+
identifier,
178+
limits: {
179+
receiver,
180+
debitAmount: {
181+
value: '400',
182+
assetCode: 'USD',
183+
assetScale: 2
184+
}
185+
}
186+
}
187+
188+
expect(
189+
compareRequestAndGrantAccessItems(
190+
requestAccessItem,
191+
toOpenPaymentsAccess(grantAccessItemSuperAction)
192+
)
193+
).toBe(true)
194+
})
195+
196+
test('Can compare an access item on a grant without an identifier with a request with an identifier', async (): Promise<void> => {
197+
const grantAccessItemSuperAction = await Access.query(trx).insertAndFetch({
198+
grantId: grant.id,
199+
type: AccessType.IncomingPayment,
200+
actions: [AccessAction.ReadAll],
201+
identifier: undefined
202+
})
203+
204+
const requestAccessItem: AccessItem = {
205+
type: 'incoming-payment',
206+
actions: [AccessAction.ReadAll],
207+
identifier
208+
}
209+
210+
expect(
211+
compareRequestAndGrantAccessItems(
212+
requestAccessItem,
213+
toOpenPaymentsAccess(grantAccessItemSuperAction)
214+
)
215+
).toBe(true)
216+
})
217+
158218
test('access comparison fails if grant action items are insufficient', async (): Promise<void> => {
159219
const identifier = `https://example.com/${v4()}`
160220
const receiver =
@@ -206,4 +266,46 @@ describe('Access utilities', (): void => {
206266
)
207267
).toBe(false)
208268
})
269+
270+
test('access comparison fails if identifier mismatch', async (): Promise<void> => {
271+
const grantAccessItemSuperAction = await Access.query(trx).insertAndFetch({
272+
grantId: grant.id,
273+
type: AccessType.IncomingPayment,
274+
actions: [AccessAction.ReadAll],
275+
identifier
276+
})
277+
278+
const requestAccessItem: AccessItem = {
279+
type: 'incoming-payment',
280+
actions: [AccessAction.ReadAll],
281+
identifier: `https://example.com/${v4()}`
282+
}
283+
284+
expect(
285+
compareRequestAndGrantAccessItems(
286+
requestAccessItem,
287+
toOpenPaymentsAccess(grantAccessItemSuperAction)
288+
)
289+
).toBe(false)
290+
})
291+
292+
test('access comparison fails if type mismatch', async (): Promise<void> => {
293+
const grantAccessItemSuperAction = await Access.query(trx).insertAndFetch({
294+
grantId: grant.id,
295+
type: AccessType.Quote,
296+
actions: [AccessAction.Read]
297+
})
298+
299+
const requestAccessItem: AccessItem = {
300+
type: 'incoming-payment',
301+
actions: [AccessAction.Read]
302+
}
303+
304+
expect(
305+
compareRequestAndGrantAccessItems(
306+
requestAccessItem,
307+
toOpenPaymentsAccess(grantAccessItemSuperAction)
308+
)
309+
).toBe(false)
310+
})
209311
})

packages/auth/src/access/utils.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,22 @@ export function compareRequestAndGrantAccessItems(
4242
return false
4343
}
4444

45-
// Validate remaining keys
45+
if (restOfRequestAccessItem.type !== restOfGrantAccessItem.type) {
46+
return false
47+
}
48+
49+
// Validate identifier, if present on the grant
50+
const grantAccessIdentifier = (
51+
restOfGrantAccessItem as OutgoingPaymentOrIncomingPaymentAccess
52+
).identifier
53+
54+
const requestAccessIdentifier = (
55+
restOfRequestAccessItem as OutgoingPaymentOrIncomingPaymentAccess
56+
).identifier
57+
4658
if (
47-
restOfRequestAccessItem.type !== restOfGrantAccessItem.type ||
48-
(restOfRequestAccessItem as OutgoingPaymentOrIncomingPaymentAccess)
49-
.identifier !==
50-
(restOfGrantAccessItem as OutgoingPaymentOrIncomingPaymentAccess)
51-
.identifier
59+
grantAccessIdentifier &&
60+
requestAccessIdentifier !== grantAccessIdentifier
5261
) {
5362
return false
5463
}

packages/backend/src/open_payments/auth/middleware.test.ts

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ type IntrospectionCallObject = {
4646
access: {
4747
type: AccessType
4848
actions: AccessAction[]
49-
identifier?: string
49+
identifier: string
5050
}[]
5151
}
5252

@@ -193,7 +193,8 @@ describe('Auth Middleware', (): void => {
193193
access: [
194194
{
195195
type: type,
196-
actions: [action]
196+
actions: [action],
197+
identifier: ctx.walletAddressUrl
197198
}
198199
]
199200
})
@@ -217,7 +218,8 @@ describe('Auth Middleware', (): void => {
217218
access: [
218219
{
219220
type: type,
220-
actions: [action]
221+
actions: [action],
222+
identifier: ctx.walletAddressUrl
221223
}
222224
]
223225
})
@@ -286,15 +288,12 @@ describe('Auth Middleware', (): void => {
286288
access: [
287289
{
288290
type,
289-
actions: [action]
291+
actions: [action],
292+
identifier: ctx.walletAddressUrl
290293
}
291294
]
292295
}
293296

294-
if (type === AccessType.OutgoingPayment) {
295-
expectedCallObject.access[0].identifier = ctx.walletAddressUrl
296-
}
297-
298297
expect(introspectSpy).toHaveBeenCalledWith(expectedCallObject)
299298
expect(next).not.toHaveBeenCalled()
300299
}
@@ -313,7 +312,8 @@ describe('Auth Middleware', (): void => {
313312
access: [
314313
{
315314
type,
316-
actions: [action]
315+
actions: [action],
316+
identifier: ctx.walletAddressUrl
317317
}
318318
]
319319
})
@@ -349,7 +349,8 @@ describe('Auth Middleware', (): void => {
349349
access: [
350350
{
351351
type,
352-
actions: [subAction]
352+
actions: [subAction],
353+
identifier: ctx.walletAddressUrl
353354
}
354355
]
355356
})
@@ -376,7 +377,8 @@ describe('Auth Middleware', (): void => {
376377
access: [
377378
{
378379
type,
379-
actions: [superAction]
380+
actions: [superAction],
381+
identifier: ctx.walletAddressUrl
380382
}
381383
]
382384
})
@@ -436,13 +438,11 @@ describe('Auth Middleware', (): void => {
436438
access: [
437439
{
438440
type,
439-
actions: [action]
441+
actions: [action],
442+
identifier: ctx.walletAddressUrl
440443
}
441444
]
442445
}
443-
if (type === AccessType.OutgoingPayment) {
444-
expectedCallObject.access[0].identifier = ctx.walletAddressUrl
445-
}
446446

447447
expect(introspectSpy).toHaveBeenCalledWith(expectedCallObject)
448448
expect(next).toHaveBeenCalled()
@@ -473,7 +473,8 @@ describe('Auth Middleware', (): void => {
473473
access: [
474474
{
475475
type,
476-
actions: [action]
476+
actions: [action],
477+
identifier: ctx.walletAddressUrl
477478
}
478479
]
479480
})

packages/backend/src/open_payments/auth/middleware.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export interface Grant {
3636
export interface Access {
3737
type: string
3838
actions: AccessAction[]
39-
identifier?: string
39+
identifier: string
4040
}
4141

4242
function contextToRequestLike(ctx: HttpSigContext): RequestLike {
@@ -95,13 +95,11 @@ export function createTokenIntrospectionMiddleware({
9595
tokenInfo = await tokenIntrospectionClient.introspect({
9696
access_token: token,
9797
access: [
98-
requestType === AccessType.OutgoingPayment
99-
? toOpenPaymentsAccess(
100-
requestType,
101-
requestAction,
102-
ctx.walletAddressUrl
103-
)
104-
: toOpenPaymentsAccess(requestType, requestAction)
98+
toOpenPaymentsAccess(
99+
requestType,
100+
requestAction,
101+
ctx.walletAddressUrl
102+
)
105103
]
106104
})
107105
} catch (err) {

0 commit comments

Comments
 (0)