-
Notifications
You must be signed in to change notification settings - Fork 15
1180 refactor foxx authz #1181
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
1180 refactor foxx authz #1181
Conversation
Reviewer's Guide by SourceryThis PR refactors the authorization system by introducing new modules for better code organization and maintainability. The changes include splitting functionality into dedicated modules for record management, path handling, and authorization checks, along with comprehensive unit tests to ensure reliability. Sequence diagram for the authorization check processsequenceDiagram
participant Client
participant Router
participant AuthzModule
participant Record
participant PathModule
Client->>Router: GET /gridftp
Router->>AuthzModule: isRecordActionAuthorized(client, data_key, req_perm)
AuthzModule-->>Router: Authorization result
Router->>Record: new Record(data_key)
Record->>PathModule: splitPOSIXPath(file)
PathModule-->>Record: Path components
Record-->>Router: Path consistency result
Router-->>Client: Authorization response
Class diagram for the refactored authorization systemclassDiagram
class Record {
-error
-err_msg
-exists
-loc
-alloc
-key
-data_id
+constructor(a_key)
+exists() boolean
+key() string
+error() string
+errorMessage() string
+isManaged() boolean
+isPathConsistent(a_path) boolean
}
class AuthzModule {
+isRecordActionAuthorized(a_client, a_data_key, a_perm) boolean
}
class PathModule {
+splitPOSIXPath(a_posix_path) string[]
}
Record --> AuthzModule : uses
Record --> PathModule : uses
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
@sourcery-ai review |
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.
Hey @JoshuaSBrown - I've reviewed your changes and found some issues that need to be addressed.
Blocking issues:
- Security issue: data_id variable is undefined in public read access check (link)
Here's what I looked at during the review
- 🟢 General issues: all looks good
- 🔴 Security: 1 blocking issue
- 🟢 Testing: all looks good
- 🟡 Complexity: 1 issue found
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
// if record exists and if it is a public record | ||
if (!client) { | ||
if (record.exists()) { | ||
if (req.queryParams.act != "read" || !g_lib.hasPublicRead(data_id)) { |
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.
🚨 issue (security): Security issue: data_id variable is undefined in public read access check
The data_id variable is not defined at this point in the code. Should use record.key() or similar method from the Record class to maintain consistency and prevent potential security vulnerabilities.
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.
Nice catch.
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.
Thank you for your feedback, we will generate more comments like this in the future according to the following instructions:
- Ensure the comment identifies a specific issue in the code, such as a security vulnerability or bug.
- The comment should provide a clear explanation of the issue, including why it is a problem.
- Suggest a specific solution or improvement to address the issue.
- Use clear and concise language to communicate the problem and solution effectively.
…80-refactor-authz
Co-authored-by: Aaron Perez <aperez0295@gmail.com>
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.
Questions about testing and some comments left in
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.
I have a few questions and comments!
|
||
Note The granularity of CMake is dependent on how they are defined in the CMakeLists.txt file. The tests are specified in | ||
CMake by passing a string that is matched against the chai test cases in the | ||
"it()" sections of the chai unit tests. Any test cases that match the pattern will run when that test is triggered. |
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.
It will also match against the "describe" blocks
* | ||
* @param - the permission type that is being checked i.e. | ||
* | ||
* PERM_CREATE |
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.
If these permissions are stored somewhere as a type, the above jsdoc reference can show their type
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.
That's a good suggestion. The client is not currently defined in a single location as it is what is pulled out of the database.
* PERM_RD_DATA | ||
**/ | ||
obj.isRecordActionAuthorized = function (a_client, a_data_key, a_perm) { | ||
const data_id = "d/" + a_data_key; |
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.
I am asking out of curiosity, is it best practice to construct an ID? I feel like if we ask for a key and use an ID, it may be better to either 1. Just ask for the ID or 2. Search for the record based on the key, and use the record ID.
A reason that I ask is because I am unsure if we can be 100% certain that the ID will always be collection/key
, is that the case?
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.
Great question, and yes you can. Thie is from the official documentation.
https://docs.arangodb.com/stable/concepts/data-structure/documents/
All documents contain special attributes at the top-level that start with an underscore, known as system attributes:
The document key is stored as a string in the _key attribute.
The document identifier is stored as a string in the _id attribute.
The document revision is stored as a string in the _rev attribute.
You can specify a value for the _key attribute when creating a document. The _id attribute is automatically set based on the collection and _key. The _id and _key values are immutable once the document has been created. The _rev value is maintained by ArangoDB automatically.
keys are unique to the collection, ids globally unique.
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.
I would say that if you don't conform to the pattern, it is likely an anti-pattern.
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.
Ok yeah I see that in the docs. Cool to know.
@@ -1001,6 +1034,31 @@ module.exports = (function () { | |||
return false; | |||
}; | |||
|
|||
/** | |||
* @breif checks to make sure the client has admin permissions on an object |
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.
Typo? @brief
var idx = req.queryParams.file.lastIndexOf("/"); | ||
var data_key = req.queryParams.file.substr(idx + 1); | ||
var data_id = "d/" + data_key; | ||
// Will split a posix path into an array |
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.
I think this comment is unnecessary because of the splitPOSIXPath
jsdoc
throw [record.error(), record.errorMessage()]; | ||
} | ||
} else { | ||
// If the record does not exist then the path would noe be consistent. |
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.
Typo? noe -> not ?
console.log("Loc is:"); | ||
console.log(loc); | ||
if (!loc) { | ||
if (record.exists()) { |
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.
There are a lot of checks for record existence. Is there a way to pull this check up a level or two in the nested conditionals?
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.
Good catch, This is addressed in a follow up PR. see here. https://github.com/ORNL/DataFed/pull/1196/files#diff-2a4e90aa74276bb3ccc3605ae33282b2cfa475fd702f7239150b202e6a4ed152
* @brief Checks if the record exists in the database. | ||
* @return {boolean} True if the record exists, otherwise false. | ||
*/ | ||
exists() { |
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.
Ok I see the exists()
calls are inexpensive. That's good.
g_db.u.truncate(); | ||
}); | ||
|
||
it("unit_authz: if admin should return true", () => { |
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.
Should we also have a test for not admin, but has write? And another for no admin, no write?
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.
Good catch, These are addressed in a follow up PR here: https://github.com/ORNL/DataFed/pull/1196/files#diff-29f2f796d64cb649168cf5d450247a757a3f3b2d0c252f8ad394c76ac48ee08c
PR Description
Tasks
Summary by Sourcery
Refactor the authorization router by modularizing the code into separate modules for better maintainability and readability. Introduce new unit tests for the Record class and path handling to ensure robustness and correct error handling.
Enhancements:
Tests: