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(auth)!: move consent interaction to different port #2665

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
281ca71
feat(mase): call consent choice on different port
golobitch Apr 16, 2024
0310fac
feat(localenv): expose auth choice port
golobitch Apr 16, 2024
075ab8d
feat(auth)!: move interaction choice to different port
golobitch Apr 16, 2024
c7d562b
feat(auth): change env variable name
golobitch May 1, 2024
bf4abee
test(docker): start auth choice server on specific port and expose it
golobitch May 1, 2024
1e55aa7
test(interactions): set auth choice port to 0
golobitch May 1, 2024
ad31cfb
test(integration-tests): auth choice port
golobitch May 2, 2024
64fcf16
docs(open-payments): specify port for auth choice route
golobitch May 2, 2024
0f96db8
chore(lint): documentation
golobitch May 2, 2024
25cb61e
feat: rename auth choice server to interaction server and update tests
golobitch May 3, 2024
308f5e9
docs(integration): add env variable for interaction port
golobitch May 3, 2024
7581bfd
feat(auth)!: move grant lookup to different non-exposed port
golobitch May 14, 2024
60a32b5
feat(localenv): use different port for grant lookup
golobitch May 14, 2024
b5c28a4
fix(auth): interaction server start log entry
golobitch May 15, 2024
525e54f
feat(localenv): expose auth interaction port for happy life bank
golobitch May 15, 2024
d2414be
docs(open-payments): note that grant lookup is running on interaction…
golobitch May 15, 2024
7461f68
chore(integration): accept response base url from config
golobitch May 21, 2024
f97bb43
Merge branch 'main' into 2649-auth-move-interaction-routes-to-a-diffe…
golobitch May 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions localenv/cloud-nine-wallet/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ services:
- '3003:3003'
- '3006:3006'
- "9230:9229"
- '3009:3009'
golobitch marked this conversation as resolved.
Show resolved Hide resolved
environment:
NODE_ENV: ${NODE_ENV:-development}
TRUST_PROXY: ${TRUST_PROXY}
Expand Down
1 change: 1 addition & 0 deletions localenv/happy-life-bank/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ services:
- '4003:3003'
- '4006:3006'
- '9232:9229'
- '4009:3009'
environment:
NODE_ENV: development
AUTH_DATABASE_URL: postgresql://happy_life_bank_auth:happy_life_bank_auth@shared-database/happy_life_bank_auth
Expand Down
4 changes: 2 additions & 2 deletions localenv/mock-account-servicing-entity/app/lib/apiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class ApiClient {
// get grant --> GET /grant/:id/:nonce
const { interactId, nonce } = params
const response = await axios.get(
`http://localhost:3006/grant/${interactId}/${nonce}`,
`http://localhost:3009/grant/${interactId}/${nonce}`,
{
headers: {
'x-idp-secret': idpSecret
Expand Down Expand Up @@ -71,7 +71,7 @@ export class ApiClient {
const acceptanceSubPath = acceptanceDecision ? 'accept' : 'reject'

const response = await axios.post(
`http://localhost:3006/grant/${interactId}/${nonce}/${acceptanceSubPath}`,
`http://localhost:3009/grant/${interactId}/${nonce}/${acceptanceSubPath}`,
{},
{
headers: {
Expand Down
76 changes: 56 additions & 20 deletions packages/auth/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export type AppContainer = IocContract<AppServices>

export class App {
private authServer!: Server
private interactionServer!: Server
private introspectionServer!: Server
private adminServer!: Server
private logger!: Logger
Expand Down Expand Up @@ -328,26 +329,6 @@ export class App {
interactionRoutes.finish
)

// Grant lookup
router.get<DefaultState, GetContext>(
'/grant/:id/:nonce',
createValidatorMiddleware<GetContext>(openApi.idpSpec, {
path: '/grant/{id}/{nonce}',
method: HttpMethod.GET
}),
interactionRoutes.details
)

// Grant accept/reject
router.post<DefaultState, ChooseContext>(
'/grant/:id/:nonce/:choice',
createValidatorMiddleware<ChooseContext>(openApi.idpSpec, {
path: '/grant/{id}/{nonce}/{choice}',
method: HttpMethod.POST
}),
interactionRoutes.acceptOrReject
)

koa.use(cors())
koa.keys = [this.config.cookieKey]

Expand Down Expand Up @@ -418,6 +399,54 @@ export class App {
this.introspectionServer = koa.listen(port)
}

public async startInteractionServer(port: number | string): Promise<void> {
const koa = await this.createKoaServer()

const router = new Router<DefaultState, AppContext>()
router.use(bodyParser())

const openApi = await this.container.use('openApi')
const interactionRoutes = await this.container.use('interactionRoutes')

// Grant accept/reject
router.post<DefaultState, ChooseContext>(
'/grant/:id/:nonce/:choice',
createValidatorMiddleware<ChooseContext>(openApi.idpSpec, {
golobitch marked this conversation as resolved.
Show resolved Hide resolved
path: '/grant/{id}/{nonce}/{choice}',
method: HttpMethod.POST
}),
interactionRoutes.acceptOrReject
)

// Grant lookup
router.get<DefaultState, GetContext>(
'/grant/:id/:nonce',
createValidatorMiddleware<GetContext>(openApi.idpSpec, {
path: '/grant/{id}/{nonce}',
method: HttpMethod.GET
}),
interactionRoutes.details
)

koa.use(cors())
koa.keys = [this.config.cookieKey]
koa.use(
session(
{
key: 'sessionId',
maxAge: 60 * 1000,
signed: true
},
koa
)
)

koa.use(router.middleware())
koa.use(router.routes())

this.interactionServer = koa.listen(port)
}

private async createKoaServer(): Promise<Koa<Koa.DefaultState, AppContext>> {
const koa = new Koa<DefaultState, AppContext>({
proxy: this.config.trustProxy
Expand Down Expand Up @@ -454,6 +483,9 @@ export class App {
if (this.authServer) {
await this.stopServer(this.authServer)
}
if (this.interactionServer) {
await this.stopServer(this.interactionServer)
}
if (this.adminServer) {
await this.stopServer(this.adminServer)
}
Expand Down Expand Up @@ -482,6 +514,10 @@ export class App {
return this.getPort(this.authServer)
}

public getInteractionPort(): number {
return this.getPort(this.interactionServer)
}

public getIntrospectionPort(): number {
return this.getPort(this.introspectionServer)
}
Expand Down
1 change: 1 addition & 0 deletions packages/auth/src/config/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const Config = {
logLevel: envString('LOG_LEVEL', 'info'),
adminPort: envInt('ADMIN_PORT', 3003),
authPort: envInt('AUTH_PORT', 3006),
interactionPort: envInt('INTERACTION_PORT', 3009),
introspectionPort: envInt('INTROSPECTION_PORT', 3007),
env: envString('NODE_ENV', 'development'),
trustProxy: envBool('TRUST_PROXY', false),
Expand Down
3 changes: 3 additions & 0 deletions packages/auth/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ export const start = async (
await app.startAuthServer(config.authPort)
logger.info(`Auth server listening on ${app.getAuthPort()}`)

await app.startInteractionServer(config.interactionPort)
logger.info(`Interaction server listening on ${app.getInteractionPort()}`)

await app.startIntrospectionServer(config.introspectionPort)
logger.info(`Introspection server listening on ${app.getIntrospectionPort()}`)
}
Expand Down
1 change: 1 addition & 0 deletions packages/auth/src/tests/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const createTestApp = async (
config.authPort = 0
config.introspectionPort = 0
config.adminPort = 0
config.interactionPort = 0

const logger = createLogger({
transport: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ If the AS deems interaction necessary to issue a grant, there are five main endp

- `GET /interact/:id/:nonce` (made by the client to the AS, establishes an interaction session, redirects browser session to IDP consent screen)
- `GET /grant/:id/:nonce` (made by the IDP to the AS, secured with `x-idp-secret` header, returns grant info for the consent screen to enumerate )
- **This is served on INTERACTION_PORT and its default value is 3009**
- `POST /grant/:id/:nonce/(accept OR reject)` (made by the IDP to the AS, secured with `x-idp-secret` header, accepts or rejects the grant based on the user's input on the consent screen. **IDP then redirects to `GET /interact/:id/:nonce/finish`**)
- **This is served on INTERACTION_PORT and its default value is 3009**
golobitch marked this conversation as resolved.
Show resolved Hide resolved
- `GET /interact/:id/:nonce/finish` (ends the interaction established by `GET /interact/:id/:nonce`, redirects browser session to client callback. Contains a query param that either indicates a failure, or on success, a `hash` parameter that the client can use to verify the successful interaction, and the `interact_ref` that identifies the interaction on the AS.)
- Examples include: - `?result=grant_rejected` (if interaction was rejected) - `?result=grant_invalid` (if grant is not in a state where it may be accepted or rejected, e.g. already approved) - `?hash=p28jsq0Y2KK3WS__a42tavNC64ldGTBroywsWxT4md_jZQ1R\HZT8BOWYHcLmObM7XHPAdJzTZMtKBsaraJ64A
&interact_ref=4IFWWIKYBC2PQ6U56NL1` (if interaction was accepted) - `hash` is a `sha-256` hash of values provided by the client in the body of the [grant initialization request](https://docs.openpayments.guide/reference/post-request) (`interact.finish.nonce`), values returned in the AS response for that request (`interact.finish`), the `interact_ref` provided alongside the `hash`, and the uri of the grant initialization request (`https://auth-server.com/`).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ Now, the Admin UI can be found on localhost:3010.
| `IDENTITY_SERVER_SECRET` | auth.identityServer.secret | | API key to fetch the identity server endpoint |
| `INCOMING_PAYMENT_INTERACTION` | auth.interaction.incomingPayment | `false` | flag - incoming payments grant requests are interactive or not |
| `INTERACTION_EXPIRY_SECONDS` | auth.interactionExpirySeconds | `600` | time in seconds for which a user can interact with a grant request |
| `INTERACTION_PORT` | auth.port.interaction | `3009` | Port number for the interaction APIs |
| `INTROSPECTION_PORT` | auth.port.introspection | `3007` | port of this Open Payments Auth - Token Introspection Server |
| `LIST_ALL_ACCESS_INTERACTION` | | `true` | Specify whether grant requests including a `list-all` action should require interaction. In these requests, the client asks to list resources that they themselves did not create. |
| `LOG_LEVEL` | auth.logLevel | `info` | [Pino Log Level](https://getpino.io/#/docs/api?id=levels) |
Expand Down
13 changes: 10 additions & 3 deletions test/integration/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,16 @@ describe('Integration tests', (): void => {
})
expect(senderWalletAddress.id).toBe(senderWalletAddressUrl)

const incomingPaymentGrant = await grantRequestIncomingPayment(
receiverWalletAddress
)
let incomingPaymentGrant
try {
incomingPaymentGrant = await grantRequestIncomingPayment(
receiverWalletAddress
)
} catch (err) {
console.log('ERROR: ', err)
throw err
}

const incomingPayment = await createIncomingPayment(
receiverWalletAddress,
incomingPaymentGrant.access_token.value,
Expand Down
4 changes: 4 additions & 0 deletions test/integration/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import { resolve } from 'path'

export type TestConfig = Config & {
integrationServerPort: number
interactionServer: string
walletAddressUrl: string
keyId: string
}

type EnvConfig = {
OPEN_PAYMENTS_URL: string
AUTH_SERVER_DOMAIN: string
INTERACTION_SERVER: string
INTEGRATION_SERVER_PORT: string
WALLET_ADDRESS_URL: string
GRAPHQL_URL: string
Expand All @@ -24,6 +26,7 @@ type EnvConfig = {
const REQUIRED_KEYS: (keyof EnvConfig)[] = [
'OPEN_PAYMENTS_URL',
'AUTH_SERVER_DOMAIN',
'INTERACTION_SERVER',
'INTEGRATION_SERVER_PORT',
'WALLET_ADDRESS_URL',
'GRAPHQL_URL',
Expand Down Expand Up @@ -61,6 +64,7 @@ const createConfig = (name: string): TestConfig => {
publicHost: env.OPEN_PAYMENTS_URL,
testnetAutoPeerUrl: '',
authServerDomain: env.AUTH_SERVER_DOMAIN,
interactionServer: env.INTERACTION_SERVER,
integrationServerPort: parseInt(env.INTEGRATION_SERVER_PORT),
walletAddressUrl: env.WALLET_ADDRESS_URL,
graphqlUrl: env.GRAPHQL_URL,
Expand Down
5 changes: 4 additions & 1 deletion test/integration/lib/test-actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ async function consentInteraction(
) {
const { idpSecret } = deps.sendingASE.config
const { interactId, nonce, cookie } = await _startAndAcceptInteraction(
deps,
outgoingPaymentGrant,
senderWalletAddress,
idpSecret
Expand All @@ -74,6 +75,7 @@ async function consentInteractionWithInteractRef(
): Promise<string> {
const { idpSecret } = deps.sendingASE.config
const { interactId, nonce, cookie } = await _startAndAcceptInteraction(
deps,
outgoingPaymentGrant,
senderWalletAddress,
idpSecret
Expand Down Expand Up @@ -104,6 +106,7 @@ async function consentInteractionWithInteractRef(
}

async function _startAndAcceptInteraction(
deps: TestActionsDeps,
outgoingPaymentGrant: PendingGrant,
senderWalletAddress: WalletAddress,
idpSecret: string
Expand All @@ -125,7 +128,7 @@ async function _startAndAcceptInteraction(

// Accept
const acceptResponse = await fetch(
`${senderWalletAddress.authServer}/grant/${interactId}/${nonce}/accept`,
`${deps.sendingASE.config.interactionServer}/grant/${interactId}/${nonce}/accept`,
Copy link
Contributor

Choose a reason for hiding this comment

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

final thing, I think we just need to expose interactionServer on the TestConfig interface

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Let me check that. I also need to rebase to main

{
method: 'POST',
headers: {
Expand Down
1 change: 1 addition & 0 deletions test/integration/lib/test-actions/open-payments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ async function grantRequestIncomingPayment(
receiverWalletAddress: WalletAddress
): Promise<Grant> {
const { sendingASE } = deps

const grant = await sendingASE.opClient.grant.request(
{
url: receiverWalletAddress.authServer
Expand Down
1 change: 1 addition & 0 deletions test/integration/testenv/cloud-nine-wallet/.env
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
OPEN_PAYMENTS_URL=https://cloud-nine-wallet-test-backend:3100
AUTH_SERVER_DOMAIN=http://cloud-nine-wallet-test-auth:3106
INTERACTION_SERVER=http://cloud-nine-wallet-test-auth:3109
INTEGRATION_SERVER_PORT=8888
WALLET_ADDRESS_URL=https://cloud-nine-wallet-test-backend:3100/.well-known/pay
GRAPHQL_URL=http://cloud-nine-wallet-test-backend:3101/graphql
Expand Down
3 changes: 3 additions & 0 deletions test/integration/testenv/cloud-nine-wallet/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,14 @@ services:
- '3103:3103'
- '3106:3106'
- '3107:3107'
- '3109:3109'
environment:
NODE_ENV: ${NODE_ENV:-development}
AUTH_SERVER_URL: http://cloud-nine-wallet-test-auth:3106
INTERACTION_SERVER: http://cloud-nine-wallet-test-auth:3109
AUTH_DATABASE_URL: postgresql://cloud_nine_wallet_test_auth:cloud_nine_wallet_test_auth@shared-database/cloud_nine_wallet_test_auth
INTROSPECTION_PORT: 3107
INTERACTION_PORT: 3109
AUTH_PORT: 3106
ADMIN_PORT: 3103
REDIS_URL: redis://shared-redis:6379/1
Expand Down
1 change: 1 addition & 0 deletions test/integration/testenv/happy-life-bank/.env
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
OPEN_PAYMENTS_URL=https://happy-life-bank-test-backend:4100
AUTH_SERVER_DOMAIN=http://happy-life-bank-test-auth:4106
INTERACTION_SERVER=http://happy-life-bank-test-auth:4109
INTEGRATION_SERVER_PORT=8889
WALLET_ADDRESS_URL=https://happy-life-bank-test-backend:4100/accounts/pfry
GRAPHQL_URL=http://happy-life-bank-test-backend:4101/graphql
Expand Down
4 changes: 4 additions & 0 deletions test/integration/testenv/happy-life-bank/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,20 @@ services:
- '4103:4103'
- '4106:4106'
- '4107:4107'
- '4109:4109'
environment:
NODE_ENV: development
AUTH_DATABASE_URL: postgresql://happy_life_bank_test_auth:happy_life_bank_test_auth@shared-database/happy_life_bank_test_auth
AUTH_SERVER_URL: http://happy-life-bank-test-auth:4106
INTERACTION_SERVER: http://happy-life-bank-test-auth:4109
INTERACTION_PORT: 4109
INTROSPECTION_PORT: 4107
ADMIN_PORT: 4103
AUTH_PORT: 4106
REDIS_URL: redis://shared-redis:6379/3
IDENTITY_SERVER_URL: http://localhost:3030/mock-idp/
IDENTITY_SERVER_SECRET: 2pEcn2kkCclbOHQiGNEwhJ0rucATZhrA807HTm2rNXE=
COOKIE_KEY: 42397d1f371dd4b8b7d0308a689a57c882effd4ea909d792302542af47e2cd37
AUTH_CHOICE_PORT: 4109
depends_on:
- cloud-nine-wallet-test-auth