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

refactor(cmd-api-server): pull OAuth2 endpoint scopes from openapi.json #3463

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

aldousalvarez
Copy link
Contributor

@aldousalvarez aldousalvarez commented Aug 7, 2024

Commit to be reviewed


refactor(cmd-api-server): pull OAuth2 endpoint scopes from openapi.json

Primary Changes
----------------
1. added OAuth2 security endpoints scopes to openapi.json
2. added a test to make sure if the scopes are indeed getting 
   pulled from the spec file

Fixes #2693

Pull Request Requirements

  • Rebased onto upstream/main branch and squashed into single commit to help maintainers review it more efficient and to avoid spaghetti git commit graphs that obfuscate which commit did exactly what change, when and, why.
  • Have git sign off at the end of commit message to avoid being marked red. You can add -s flag when using git commit command. You may refer to this link for more information.
  • Follow the Commit Linting specification. You may refer to this link for more information.

Character Limit

  • Pull Request Title and Commit Subject must not exceed 72 characters (including spaces and special characters).
  • Commit Message per line must not exceed 80 characters (including spaces and special characters).

A Must Read for Beginners
For rebasing and squashing, here's a must read guide for beginners.

}

describe("cmd-api-server:getOpenApiSpecV1Endpoint", () => {
const logLevel: LogLevelDesc = "TRACE";
Copy link
Contributor

Choose a reason for hiding this comment

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

Change log level to info, dont use trace for tests in CI

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@outSH Got it, just finished updating it.

Copy link
Contributor

@outSH outSH left a comment

Choose a reason for hiding this comment

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

LGTM, Thank you!

Comment on lines 120 to 206
it("HTTP - returns the OpenAPI spec .json document of the API server itself", async () => {
const res1Promise = apiClient.getOpenApiSpecV1();
await expect(res1Promise).resolves.toHaveProperty("data.openapi");
const res1 = await res1Promise;
expect(res1.status).toEqual(200);
expect(res1.data).toBeTruthy();

console.log("Response data type:", typeof res1.data);
console.log("Response data:", res1.data);

let openApiSpec;
try {
openApiSpec =
typeof res1.data === "string" ? JSON.parse(res1.data) : res1.data;
} catch (error) {
throw new Error(`Failed to parse OpenAPI spec: ${error.message}`);
}

expect(openApiSpec).toHaveProperty("components");
expect(openApiSpec.components).toHaveProperty("securitySchemes");

const securitySchemes = openApiSpec.components.securitySchemes;
expect(securitySchemes).toBeObject();

const expectedScopes: IExpectedScopes = {
"read:health": "Read health information",
"read:metrics": "Read metrics information",
"read:spec": "Read OpenAPI specification",
};

const securitySchemeNames = Object.keys(securitySchemes);

securitySchemeNames.forEach((schemeName) => {
const scheme = securitySchemes[schemeName];
expect(scheme).toHaveProperty("flows");
const flows = scheme.flows;
expect(flows).toHaveProperty("authorizationCode");
const scopes = flows.authorizationCode.scopes as IExpectedScopes;

Object.keys(expectedScopes).forEach((scope) => {
expect(scopes).toHaveProperty(scope);
expect(scopes[scope]).toEqual(expectedScopes[scope]);
});
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

@aldousalvarez This verifies that the OpenAPI .json file has the security scheme declared. It does not verify that those are being respected by the endpoint implementations themselves. Please update the endpoints touched by this diff to make use of the declared scopes and then write 2 more test cases for each endpoint in addition this one I'm commenting on. One of them should be the positive test case where with a valid JWT the API client can execute the request and with an invalid JWT the request execution fails with an HTTP 401 unauthorized error.
Note: by test cases I just mean another it("does something...", async () => {...}) block not a separate file.

@aldousalvarez
Copy link
Contributor Author

aldousalvarez commented Aug 21, 2024

Hello @petermetz, Already done the requested changes, re-requested for your review. Thank you

Copy link
Contributor

@petermetz petermetz left a comment

Choose a reason for hiding this comment

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

@aldousalvarez Looking much better now but it's still missing the crucial negative test case for missing or incorrect scopes, please see my comment above.

Comment on lines 128 to 129
expect(res1.status).toEqual(200);
expect(res1.data).toBeTruthy();
Copy link
Contributor

Choose a reason for hiding this comment

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

@aldousalvarez In this test case it is supposed to fail because you are executing with a JWT that does not have the scope declared (so the JWT has a valid signature but it does not declare the correct role based access control and therefore should not work)

Copy link
Contributor

@petermetz petermetz left a comment

Choose a reason for hiding this comment

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

@aldousalvarez Please fix the rest of the failing tests of the cmd-api-server package and also the custom-checks check which also is failing.

const resPromise = apiClient.getHealthCheckV1({
headers: { Authorization: invalidBearerToken },
});
await expect(resPromise).rejects.toThrow(
Copy link
Contributor

Choose a reason for hiding this comment

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

@aldousalvarez Almost there! Please make sure to explicitly assert that the status property of the is 401 or 403 depending on which one is applicable (403 if the token is valid BUT missing the correct scope, 401 otherwise)

});
await expect(resPromise).rejects.toThrow(
"Request failed with status code 401",
);
Copy link
Contributor

Choose a reason for hiding this comment

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

@aldousalvarez Almost there! Please make sure to explicitly assert that the status property of the is 401 or 403 depending on which one is applicable (403 if the token is valid BUT missing the correct scope, 401 otherwise)

@aldousalvarez
Copy link
Contributor Author

Hello @petermetz I added another test case where it would be 403, and then I also added that it logs which status code it gets,. Should I also add 403 in the responses on the openapi.json as well? Thanks

@petermetz
Copy link
Contributor

Hello @petermetz I added another test case where it would be 403, and then I also added that it logs which status code it gets,. Should I also add 403 in the responses on the openapi.json as well? Thanks

@aldousalvarez Sorry for the slow response! Thank you for the changes and to your question: Yes, please declare the 403 in the openapi.tpl.json spec as well (and make sure to run codegen so that it updates openapi.json also)

@aldousalvarez aldousalvarez force-pushed the aldousalvarez/issue2693 branch 11 times, most recently from 30dbad7 to 614db4e Compare November 6, 2024 03:08
@aldousalvarez
Copy link
Contributor Author

Hello @petermetz re-requested for review. already done with the requested changes and updated some of the tests with the required scope after running yarn run codegen so the tests would pass. Thank you

Comment on lines 222 to 229
try {
await resPromise;
} catch (error) {
const statusCode = error.response?.status;
console.log(`Request failed with status code: ${statusCode}`);
}
});
Copy link
Contributor

@petermetz petermetz Nov 7, 2024

Choose a reason for hiding this comment

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

@adrianbatuto Please clean up this other code statements, the line above this already verifies that the request will fail.

This applies to the entire PR - please go through all the assertions in all the test cases that you've modified to make the requested changes.

Sorry I meant to say @aldousalvarez

const resPromise = apiClient.getHealthCheckV1({
headers: { Authorization: invalidBearerToken },
});
await expect(resPromise).rejects.toThrow();
Copy link
Contributor

@petermetz petermetz Nov 7, 2024

Choose a reason for hiding this comment

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

@adrianbatuto Please verify not just that it gets rejected but also that the status code is as expected. You can look at other test cases to see how we do negative test cases with HTTP status code assertions (let me know if you need more detailed pointers)

This applies to the entire PR - please go through all the assertions in all the test cases that you've modified to make the requested changes.

Sorry I meant to say @aldousalvarez

@aldousalvarez aldousalvarez force-pushed the aldousalvarez/issue2693 branch 9 times, most recently from 1d9b6c6 to dcbc153 Compare November 26, 2024 04:22
Primary Changes
----------------
1. added OAuth2 security endpoints scopes to openapi.json
2. added a test to make sure if the scopes are indeed getting
   pulled from the spec file

Fixes hyperledger-cacti#2693

Signed-off-by: aldousalvarez <[email protected]>

1. Please also refactor the third endpoint (prometheus metrics) accordingly
2. Also please extend the test case with each tokens having specific scopes
and then assert that the tokesn with the correct scopes work and the ones
that don't have the correct scopes do not even when they are otherwise
valid tokens.

Signed-off-by: Peter Somogyvari <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

refactor(cmd-api-server): pull OAuth2 endpoint scopes from openapi.json
3 participants