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

IMN-616 BFF Tools router #976

Open
wants to merge 448 commits into
base: main
Choose a base branch
from
Open

IMN-616 BFF Tools router #976

wants to merge 448 commits into from

Conversation

paologaleotti
Copy link
Collaborator

@paologaleotti paologaleotti commented Sep 17, 2024

Merge after #956 !!!

This PR adds the Tools router to BFF

The implementation differs a bit from scala (see this slack thread https://buildo.slack.com/archives/C0527LU1K4G/p1726583989026809).

When reviewing please pay particular attention to the logic behind the error handling (handleValidationResults) and retrieveKey, as it is not a direct porting of scala logic.

Copy link
Collaborator

@ecamellini ecamellini left a comment

Choose a reason for hiding this comment

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

Looks good! I left some comments duplicated from the first review since they are buried under the hundreds of commits 😄

packages/backend-for-frontend/src/model/errors.ts Outdated Show resolved Hide resolved
packages/backend-for-frontend/src/services/toolService.ts Outdated Show resolved Hide resolved
data: {
clientKind: authorizationApi.ClientKind.enum.API,
kid: jwt.header.kid,
algorithm: "RS256",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Pass the algorithm from the key (you can extract it where you extract encodedPem), the validation of this value is on the client assertion side when it performs validations on the key, later in the code.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We have the same problem as the request params here: the only accepted value for ApiKey and ConsumerKey is a const of "RS256".. What should we do here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you modify the client assertion to accept a generic string for the types ApiKey and ConsumerKey in this same PR?

Copy link
Contributor

Choose a reason for hiding this comment

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

@paologaleotti @taglioni-r if we change the headers.alg inside ClientAssertion (returned by verifyClientAssertion function) to a branded type we should solve this, right?
Then use the same type in ApiKey and ConsumerKey.

But let me know if I'm missing any conflict

clientKind: authorizationApi.ClientKind.enum.CONSUMER,
clientId: unsafeBrandId<ClientId>(jwt.payload.iss),
kid: jwt.header.kid,
algorithm: "RS256",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Pass the algorithm from the key (you can extract it where you extract encodedPem), the validation of this value is on the client assertion side when it performs validations on the key, later in the code.

packages/backend-for-frontend/src/services/toolService.ts Outdated Show resolved Hide resolved
packages/backend-for-frontend/src/services/toolService.ts Outdated Show resolved Hide resolved
): Promise<
SuccessfulValidation<ApiKey | ConsumerKey> | FailedValidation<ErrorCodes>
> {
if (!jwt.payload.purposeId) {
Copy link
Contributor

Choose a reason for hiding this comment

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

the missing purposeId is not an error because we have 2 kinds of tokens that can be generated:

  • eservice Voucher - needs the purposeId
  • m2m jwt - does not need the purposeId (and it is not related to states)

The debugger should be able to handle both.
If the purposeId is missing the eservice is not retrieved/returned and platform states check is skipped (handled inside the validateClientKindAndPlatformState function).

TL;DR: this check is required only if the client kind is CONSUMER

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Perfect, thank you. The only doubt i have is: if the client kind is API, a purposeId is still required in the object. In this case what should i use as purposeId?

Copy link
Contributor

Choose a reason for hiding this comment

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

you're right, it seems an erro on the Key parent type.
@taglioni-r can you check? the purposeId should be only in ConsumerKey


assertIsConsumer(ctx.authData.organizationId, keyWithClient);

const { encodedPem } = await authorizationClient.client.getClientKeyById({
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion for another PR: getKeyWithClientByKeyId is now used only here, we could change its spec and return the encodedPem instead of the JWK, so we would not need another call

packages/backend-for-frontend/src/services/toolService.ts Outdated Show resolved Hide resolved
packages/backend-for-frontend/src/services/toolService.ts Outdated Show resolved Hide resolved
}

function retrievePurposeItemState(purpose: purposeApi.Purpose): ItemState {
const activePurposeVersion = [...purpose.versions]
Copy link
Contributor

Choose a reason for hiding this comment

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

we should take the last version with a state in ACTIVE, SUSPENDED, ARCHIVED.

We could centralize the state logic by converting all states with purposeVersionStateToItemState, taking the ACTIVE if exists, otherwise return INACTIVE

Copy link
Contributor

Choose a reason for hiding this comment

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

Correct me if I'm wrong, but with the current sort + find and these states

  • Version1: ARCHIVED
  • Version2: ACTIVE
    the function wouldn't return the Archived version?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In this case it will just return the first one it finds. This differs from the retrieveAgreement as in that the active or suspended have priority. Should this be the logic also in this function?

return purposeVersionStateToItemState(activePurposeVersion.state);
}

async function retrieveTokenValidationEService(
Copy link
Contributor

Choose a reason for hiding this comment

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

this function and retrieveKey make the same call to retrieve the same values, can we re-use them?

Note: the agreement is retrieved using 2 different approaches

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I tried but i don't think it is cleaner, the agreement is retrieved differently and also the descriptor (each one throws a different error). Maybe there is a way to write a more generic function so each one can use it but it can make the code a lot less readable.. let me know 👍🏻

Copy link
Collaborator

@ecamellini ecamellini left a comment

Choose a reason for hiding this comment

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

Dismissing my previous change request, once the remaining comments are resolved works for me :)

@ecamellini ecamellini dismissed their stale review October 10, 2024 09:52

Avoid blocking this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants