-
Notifications
You must be signed in to change notification settings - Fork 284
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
base: main
Are you sure you want to change the base?
refactor(cmd-api-server): pull OAuth2 endpoint scopes from openapi.json #3463
Conversation
5d2cd8e
to
3321ed3
Compare
} | ||
|
||
describe("cmd-api-server:getOpenApiSpecV1Endpoint", () => { | ||
const logLevel: LogLevelDesc = "TRACE"; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
3321ed3
to
f44cf0c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, Thank you!
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]); | ||
}); | ||
}); | ||
}); |
There was a problem hiding this comment.
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.
f44cf0c
to
25c1eba
Compare
Hello @petermetz, Already done the requested changes, re-requested for your review. Thank you |
There was a problem hiding this 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.
expect(res1.status).toEqual(200); | ||
expect(res1.data).toBeTruthy(); |
There was a problem hiding this comment.
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)
dade3eb
to
4c58d17
Compare
4c58d17
to
20d64d4
Compare
af634c3
to
21fdde9
Compare
21fdde9
to
a637f50
Compare
There was a problem hiding this 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( |
There was a problem hiding this comment.
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", | ||
); |
There was a problem hiding this comment.
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)
a637f50
to
916d802
Compare
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) |
bf9ae91
to
30dbad7
Compare
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]>
30dbad7
to
614db4e
Compare
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 |
try { | ||
await resPromise; | ||
} catch (error) { | ||
const statusCode = error.response?.status; | ||
console.log(`Request failed with status code: ${statusCode}`); | ||
} | ||
}); |
There was a problem hiding this comment.
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.
const resPromise = apiClient.getHealthCheckV1({ | ||
headers: { Authorization: invalidBearerToken }, | ||
}); | ||
await expect(resPromise).rejects.toThrow(); |
There was a problem hiding this comment.
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.
Commit to be reviewed
refactor(cmd-api-server): pull OAuth2 endpoint scopes from openapi.json
Fixes #2693
Pull Request Requirements
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.-s
flag when usinggit commit
command. You may refer to this link for more information.Character Limit
A Must Read for Beginners
For rebasing and squashing, here's a must read guide for beginners.