Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(http-signature-utils): move http signature related code to this package #797

Merged
merged 57 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
97d10da
feat(http-signature-utils): initial commit
sabineschaller Nov 29, 2022
bd71bb0
chore(http-signature-utils): update lockfile
sabineschaller Nov 29, 2022
5a299e2
fix(http-signature-utils): fix package.json
sabineschaller Nov 29, 2022
359cbc9
fix: add http-signature-utils to tsconfig
sabineschaller Nov 29, 2022
29cd5e3
fix: include http-signature-utils in gh workflow
sabineschaller Nov 29, 2022
cc52dc6
fix: gh workflow build deps
sabineschaller Nov 29, 2022
d07b504
fix: builds
sabineschaller Nov 29, 2022
f505324
feat(HSU): pass keyId
sabineschaller Nov 29, 2022
458b88f
Merge branch 'main' into s2-http-sig-utils
sabineschaller Nov 30, 2022
ab5fe70
feat(HSU): add Dockerfile and add app to local infrastructure
sabineschaller Nov 30, 2022
f6eae9c
feat(HSU): move content digest creation into HSU
sabineschaller Nov 30, 2022
b8371bd
Revert "feat(HSU): move content digest creation into HSU"
sabineschaller Nov 30, 2022
cefd817
feat(MAP): load private key
sabineschaller Nov 30, 2022
1a111b1
chore: fix build:deps
sabineschaller Nov 30, 2022
e19a4a8
Merge branch 'main' into s2-http-sig-utils
sabineschaller Dec 1, 2022
46ab175
fix(MAP): graphql url
sabineschaller Dec 1, 2022
ceaa11c
feat(HSU): add content headers to app
sabineschaller Dec 2, 2022
e03aff4
fix(HSU): remove `conent-type` and `content-length` headers from app
sabineschaller Dec 2, 2022
c589ac7
feat(HSU): add content digest header to app
sabineschaller Dec 2, 2022
9dd1052
fix(HSU): allow for lower case headers
sabineschaller Dec 5, 2022
5bf116a
feat(HSU): move sig verification from auth to HSU
sabineschaller Dec 5, 2022
afc70f0
fix: export and imports
sabineschaller Dec 5, 2022
a027ee1
Merge branch 'main' into s2-http-sig-utils
sabineschaller Dec 5, 2022
e3b0af1
feat(HSU): move sig verification to HSU
sabineschaller Dec 6, 2022
8bcdda1
refactor(HSU): remove koa context from HSU
sabineschaller Dec 6, 2022
a293bf2
fix(backend): middleware context
sabineschaller Dec 7, 2022
019a7c5
Merge branch 'main' into s2-http-sig-utils
sabineschaller Dec 7, 2022
6664e26
fix(backend): imports
sabineschaller Dec 7, 2022
0951b09
fix(HSU): remove conent type and length headers from app response
sabineschaller Dec 7, 2022
b5dc812
fix(HSU): add missing dependency
sabineschaller Dec 7, 2022
4c8930a
fix: request URL
sabineschaller Dec 7, 2022
3764296
fix(local): readd redis network
sabineschaller Dec 7, 2022
c62549c
fix(HSU): removing whitespace
sabineschaller Dec 7, 2022
1db05d5
feat(local): enable sig validation
sabineschaller Dec 7, 2022
742af97
test(HSU): add tests
sabineschaller Dec 8, 2022
889ee01
fix: types
sabineschaller Dec 8, 2022
92d48dc
refactor(auth): remove console.log
sabineschaller Dec 8, 2022
0891bfa
fix(MAP): quote fees
sabineschaller Dec 12, 2022
8f08f94
Merge branch 'main' into s2-http-sig-utils
sabineschaller Dec 12, 2022
69a1089
docs(HSU): add Readme
sabineschaller Dec 12, 2022
21e06f0
feat(HSU): add postman scripts
sabineschaller Dec 13, 2022
1276e17
fix(HSU): formatting
sabineschaller Dec 13, 2022
6dfcb56
fix(HSU): add postman scripts to lintigonre file
sabineschaller Dec 13, 2022
7d2912d
refactor(HSU): verification
sabineschaller Dec 14, 2022
8f85413
fix(HSU): key tmp dir
sabineschaller Dec 14, 2022
5b61e5a
refactor(infrastructure): rename key files
sabineschaller Dec 14, 2022
bfa7353
chore(auth): remove jose
sabineschaller Dec 14, 2022
7658735
refactor(open-payments): use createHeaders from utils package
sabineschaller Dec 14, 2022
27d8936
style(HSU): rename validateHttpSigHeaders and verifySigAndChallenge
sabineschaller Dec 14, 2022
44d9241
refactor(auth): only store keyId, not entire key
sabineschaller Dec 14, 2022
9108d93
refactor: remove JWKWithRequired
sabineschaller Dec 14, 2022
96dcee0
refactor(HSU): remove unnecessary type cast
sabineschaller Dec 14, 2022
03a8a73
Merge branch 'main' into s2-http-sig-utils
sabineschaller Dec 14, 2022
45a51d4
chore: update gh workflow actions version
sabineschaller Dec 14, 2022
d448a24
chore(HSU): move postman scripts out of src
sabineschaller Dec 14, 2022
b759b36
test(HSU): add positive header validation tests
sabineschaller Dec 14, 2022
b5e035c
style(HSU): rename verification -> validation
sabineschaller Dec 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
public
generated
dist
build
build
postman-scripts
12 changes: 11 additions & 1 deletion .github/workflows/lint_test_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,18 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/rafiki/env-setup
- run: pnpm --filter openapi build
- run: pnpm --filter open-payments build:deps
- run: pnpm --filter open-payments test

http-signature-utils:
runs-on: ubuntu-latest
needs: checkout
timeout-minutes: 5
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/rafiki/env-setup
- run: pnpm --filter http-signature-utils test

build:
runs-on: ubuntu-latest
timeout-minutes: 5
Expand All @@ -93,6 +102,7 @@ jobs:
- openapi
- mock-account-provider
- open-payments
- http-signature-utils
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/rafiki/env-setup
Expand Down
19 changes: 17 additions & 2 deletions infrastructure/local/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ services:
NODE_ENV: development
AUTH_DATABASE_URL: postgresql://auth:auth@database/auth
INTROSPECTION_HTTPSIG: "false"
BYPASS_SIGNATURE_VALIDATION: "true"
BYPASS_SIGNATURE_VALIDATION: "false"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

depends_on:
- tigerbeetle
- database
Expand All @@ -32,8 +32,10 @@ services:
LOG_LEVEL: debug
PORT: 80
SEED_FILE_LOCATION: /workspace/seed.primary.yml
KEY_FILE: /workspace/private-key.pem
volumes:
- ./seed.primary.yml:/workspace/seed.primary.yml
- ./private-key.pem:/workspace/private-key.pem
depends_on:
- backend
backend:
Expand Down Expand Up @@ -70,7 +72,7 @@ services:
PRICES_URL: http://fynbos/prices
REDIS_URL: redis://redis:6379/0
QUOTE_URL: http://fynbos/quotes
BYPASS_SIGNATURE_VALIDATION: "true"
BYPASS_SIGNATURE_VALIDATION: "false"
PAYMENT_POINTER_URL: https://backend/.well-known/pay
depends_on:
- tigerbeetle
Expand Down Expand Up @@ -121,6 +123,19 @@ services:
restart: unless-stopped
networks:
- rafiki
signatures:
build:
context: ../..
dockerfile: ./packages/http-signature-utils/Dockerfile
restart: always
ports:
- '3040:3000'
environment:
KEY_FILE: /workspace/private-key.pem
volumes:
- ./private-key.pem:/workspace/private-key.pem
networks:
- rafiki
volumes:
database-data: # named volumes can be managed easier using docker-compose
tigerbeetle-data: # named volumes can be managed easier using docker-compose
Expand Down
17 changes: 15 additions & 2 deletions infrastructure/local/peer-docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ services:
NODE_ENV: development
AUTH_DATABASE_URL: postgresql://peerauth:peerauth@database/peerauth
INTROSPECTION_HTTPSIG: "false"
BYPASS_SIGNATURE_VALIDATION: "true"
BYPASS_SIGNATURE_VALIDATION: "false"
AUTH_SERVER_DOMAIN: "http://localhost:4006"
peer-backend:
image: ghcr.io/interledger/rafiki-backend:latest
Expand Down Expand Up @@ -50,7 +50,7 @@ services:
PRICES_URL: http://local-bank/prices
REDIS_URL: redis://redis:6379/1
QUOTE_URL: http://local-bank/quote
BYPASS_SIGNATURE_VALIDATION: "true"
BYPASS_SIGNATURE_VALIDATION: "false"
PAYMENT_POINTER_URL: https://peer-backend/.well-known/pay
local-bank:
build:
Expand All @@ -66,10 +66,23 @@ services:
LOG_LEVEL: debug
PORT: 80
SEED_FILE_LOCATION: /workspace/seed.peer.yml
KEY_FILE: /workspace/private-key.pem
volumes:
- ./seed.peer.yml:/workspace/seed.peer.yml
- ./peer-private-key.pem:/workspace/private-key.pem
depends_on:
- peer-backend
peer-signatures:
build:
context: ../..
dockerfile: ./packages/http-signature-utils/Dockerfile
restart: always
ports:
- '3041:3000'
environment:
KEY_FILE: /workspace/private-key.pem
volumes:
- ./peer-private-key.pem:/workspace/private-key.pem
networks:
local_rafiki:
external: true
3 changes: 3 additions & 0 deletions infrastructure/local/peer-private-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIEqezmcPhOE8bkwN+jQrppfRYzGIdFTVWQGTHJIKpz88
-----END PRIVATE KEY-----
3 changes: 3 additions & 0 deletions infrastructure/local/private-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEICxfM9mUurUGnwlMMQEDclDEQnX7c49BoGKOB48URBxO
-----END PRIVATE KEY-----
3 changes: 2 additions & 1 deletion packages/auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"@koa/router": "^12.0.0",
"ajv": "^8.11.2",
"axios": "^0.27.2",
"http-signature-utils": "workspace:../http-signature-utils",
"httpbis-digest-headers": "github:interledger/httpbis-digest-headers",
"jose": "^4.9.0",
"knex": "^0.95",
"koa": "^2.13.4",
"koa-bodyparser": "^4.3.0",
Expand All @@ -39,6 +39,7 @@
"uuid": "^8.3.2"
},
"devDependencies": {
"@faker-js/faker": "^7.4.0",
"@types/jest": "^28.1.8",
"@types/koa": "2.13.5",
"@types/koa-bodyparser": "^4.3.7",
Expand Down
34 changes: 21 additions & 13 deletions packages/auth/src/accessToken/routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,21 @@ import { AccessToken } from './model'
import { Access } from '../access/model'
import { AccessTokenRoutes } from './routes'
import { createContext } from '../tests/context'
import { generateTestKeys } from '../tests/signature'
import { JWKWithRequired } from '../client/service'
import {
generateJwk,
generateTestKeys,
JWK,
TestKeys
} from 'http-signature-utils'

describe('Access Token Routes', (): void => {
let deps: IocContract<AppServices>
let appContainer: TestContainer
let knex: Knex
let trx: Knex.Transaction
let accessTokenRoutes: AccessTokenRoutes
let testJwk: JWKWithRequired
let testKeys: TestKeys
let testClientKey: JWK

beforeAll(async (): Promise<void> => {
deps = await initIocContainer(Config)
Expand All @@ -36,8 +41,11 @@ describe('Access Token Routes', (): void => {
const openApi = await deps.use('openApi')
jestOpenAPI(openApi.authServerSpec)

const keys = await generateTestKeys()
testJwk = keys.publicKey
testKeys = await generateTestKeys()
testClientKey = generateJwk({
privateKey: testKeys.privateKey,
keyId: testKeys.keyId
})
})

afterEach(async (): Promise<void> => {
Expand Down Expand Up @@ -98,7 +106,7 @@ describe('Access Token Routes', (): void => {
beforeEach(async (): Promise<void> => {
grant = await Grant.query(trx).insertAndFetch({
...BASE_GRANT,
clientKeyId: testJwk.kid
clientKeyId: testKeys.keyId
})
access = await Access.query(trx).insertAndFetch({
grantId: grant.id,
Expand Down Expand Up @@ -141,7 +149,7 @@ describe('Access Token Routes', (): void => {
const scope = nock(CLIENT)
.get('/jwks.json')
.reply(200, {
keys: [testJwk]
keys: [testClientKey]
})

const ctx = createContext(
Expand Down Expand Up @@ -179,7 +187,7 @@ describe('Access Token Routes', (): void => {
],
key: {
proof: 'httpsig',
jwk: testJwk
jwk: testClientKey
},
client_id: clientId
})
Expand All @@ -190,7 +198,7 @@ describe('Access Token Routes', (): void => {
const scope = nock(CLIENT)
.get('/jwks.json')
.reply(200, {
keys: [testJwk]
keys: [testClientKey]
})
const tokenCreatedDate = new Date(token.createdAt)
const now = new Date(
Expand Down Expand Up @@ -238,7 +246,7 @@ describe('Access Token Routes', (): void => {
beforeEach(async (): Promise<void> => {
grant = await Grant.query(trx).insertAndFetch({
...BASE_GRANT,
clientKeyId: testJwk.kid
clientKeyId: testKeys.keyId
})
token = await AccessToken.query(trx).insertAndFetch({
grantId: grant.id,
Expand Down Expand Up @@ -269,7 +277,7 @@ describe('Access Token Routes', (): void => {
const scope = nock(CLIENT)
.get('/jwks.json')
.reply(200, {
keys: [testJwk]
keys: [testClientKey]
})

const ctx = createContext(
Expand Down Expand Up @@ -298,7 +306,7 @@ describe('Access Token Routes', (): void => {
const scope = nock(CLIENT)
.get('/jwks.json')
.reply(200, {
keys: [testJwk]
keys: [testClientKey]
})

const ctx = createContext(
Expand Down Expand Up @@ -333,7 +341,7 @@ describe('Access Token Routes', (): void => {
beforeEach(async (): Promise<void> => {
grant = await Grant.query(trx).insertAndFetch({
...BASE_GRANT,
clientKeyId: testJwk.kid
clientKeyId: testKeys.keyId
})
access = await Access.query(trx).insertAndFetch({
grantId: grant.id,
Expand Down
29 changes: 19 additions & 10 deletions packages/auth/src/accessToken/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,41 @@ import { v4 } from 'uuid'
import { createTestApp, TestContainer } from '../tests/app'
import { Config } from '../config/app'
import { IocContract } from '@adonisjs/fold'
import { initIocContainer, JWKWithRequired } from '..'
import { initIocContainer } from '..'
import { AppServices } from '../app'
import { truncateTables } from '../tests/tableManager'
import { FinishMethod, Grant, GrantState, StartMethod } from '../grant/model'
import { AccessType, Action } from '../access/types'
import { AccessToken } from './model'
import { AccessTokenService } from './service'
import { Access } from '../access/model'
import { generateTestKeys } from '../tests/signature'
import {
generateJwk,
generateTestKeys,
JWK,
TestKeys
} from 'http-signature-utils'

describe('Access Token Service', (): void => {
let deps: IocContract<AppServices>
let appContainer: TestContainer
let knex: Knex
let trx: Knex.Transaction
let accessTokenService: AccessTokenService
let testJwk: JWKWithRequired
let testKeys: TestKeys
let testClientKey: JWK

beforeAll(async (): Promise<void> => {
deps = await initIocContainer(Config)
appContainer = await createTestApp(deps)
knex = await deps.use('knex')
accessTokenService = await deps.use('accessTokenService')

const keys = await generateTestKeys()
testJwk = keys.publicKey
testKeys = await generateTestKeys()
testClientKey = generateJwk({
privateKey: testKeys.privateKey,
keyId: testKeys.keyId
})
})

afterEach(async (): Promise<void> => {
Expand Down Expand Up @@ -81,7 +90,7 @@ describe('Access Token Service', (): void => {
beforeEach(async (): Promise<void> => {
grant = await Grant.query(trx).insertAndFetch({
...BASE_GRANT,
clientKeyId: testJwk.kid,
clientKeyId: testKeys.keyId,
continueToken: crypto.randomBytes(8).toString('hex').toUpperCase(),
continueId: v4(),
interactId: v4(),
Expand Down Expand Up @@ -146,7 +155,7 @@ describe('Access Token Service', (): void => {
const scope = nock(CLIENT)
.get('/jwks.json')
.reply(200, {
keys: [testJwk]
keys: [testClientKey]
})

const introspection = await accessTokenService.introspect(token.value)
Expand All @@ -155,7 +164,7 @@ describe('Access Token Service', (): void => {
expect(introspection).toMatchObject({
...grant,
access: [access],
key: { proof: 'httpsig', jwk: testJwk },
key: { proof: 'httpsig', jwk: testClientKey },
clientId
})
scope.isDone()
Expand Down Expand Up @@ -194,7 +203,7 @@ describe('Access Token Service', (): void => {
beforeEach(async (): Promise<void> => {
grant = await Grant.query(trx).insertAndFetch({
...BASE_GRANT,
clientKeyId: testJwk.kid,
clientKeyId: testKeys.keyId,
continueToken: crypto.randomBytes(8).toString('hex').toUpperCase(),
continueId: v4(),
interactId: v4(),
Expand Down Expand Up @@ -241,7 +250,7 @@ describe('Access Token Service', (): void => {
beforeEach(async (): Promise<void> => {
grant = await Grant.query(trx).insertAndFetch({
...BASE_GRANT,
clientKeyId: testJwk.kid,
clientKeyId: testKeys.keyId,
continueToken: crypto.randomBytes(8).toString('hex').toUpperCase(),
continueId: v4(),
interactId: v4(),
Expand Down
5 changes: 3 additions & 2 deletions packages/auth/src/accessToken/service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as crypto from 'crypto'
import { v4 } from 'uuid'
import { Transaction, TransactionOrKnex } from 'objection'
import { JWK } from 'http-signature-utils'

import { BaseService } from '../shared/baseService'
import { Grant, GrantState } from '../grant/model'
import { ClientService, JWKWithRequired } from '../client/service'
import { ClientService } from '../client/service'
import { AccessToken } from './model'
import { IAppConfig } from '../config/app'
import { Access } from '../access/model'
Expand All @@ -26,7 +27,7 @@ interface ServiceDependencies extends BaseService {

export interface KeyInfo {
proof: string
jwk: JWKWithRequired
jwk: JWK
}

export interface Introspection extends Partial<Grant> {
Expand Down
Loading