Skip to content

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

Merged
merged 46 commits into from
Jan 7, 2025
Merged

1180 refactor foxx authz #1181

merged 46 commits into from
Jan 7, 2025

Conversation

JoshuaSBrown
Copy link
Collaborator

@JoshuaSBrown JoshuaSBrown commented Dec 13, 2024

PR Description

Tasks

  • - A description of the PR has been provided, and a diagram included if it is a new feature.
  • - Formatter has been run
  • - Labels have been assigned to the pr
  • - A reviwer has been added
  • - A user has been assigned to work on the pr
  • - If new feature a unit test has been added

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:

  • Refactor the authorization router to improve code readability and maintainability by modularizing the logic into separate modules.

Tests:

  • Add new unit tests for the Record class and path handling to ensure correct functionality and error handling.

Copy link

sourcery-ai bot commented Dec 13, 2024

Reviewer's Guide by Sourcery

This 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 process

sequenceDiagram
    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
Loading

Class diagram for the refactored authorization system

classDiagram
    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
Loading

File-Level Changes

Change Details Files
Refactored authorization router to use new modular architecture
  • Split authorization logic into separate modules (Record, Path, and Authz)
  • Improved error handling and messaging
  • Added structured logging for authorization events
  • Simplified path validation logic using new Path module
core/database/foxx/api/authz_router.js
Created new Record class for managing data records
  • Implemented methods for checking record existence and management status
  • Added path consistency validation
  • Created error handling system with codes and messages
  • Added support for handling record relocations and ownership changes
core/database/foxx/api/record.js
Added POSIX path handling module
  • Created utility for splitting POSIX paths into components
  • Added input validation for path strings
  • Implemented filtering for empty path components
core/database/foxx/api/posix_path.js
Added authorization utility module
  • Created function for checking record action authorization
  • Implemented permission validation logic
  • Added support for admin permission checks
core/database/foxx/api/authz.js
Enhanced testing infrastructure
  • Added comprehensive unit tests for Record class
  • Created test suite for POSIX path handling
  • Updated CMake configuration to include new tests
  • Added documentation for test configuration
core/database/tests/test_foxx.sh
core/database/CMakeLists.txt
core/database/foxx/tests/record.test.js
core/database/foxx/tests/path.test.js
core/database/README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time. You can also use
    this command to specify where the summary should be inserted.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@JoshuaSBrown JoshuaSBrown changed the base branch from master to devel December 13, 2024 19:31
@JoshuaSBrown JoshuaSBrown added the Component: GridFTP Auth Module Relates to GridFTP authorization library label Dec 13, 2024
@JoshuaSBrown JoshuaSBrown self-assigned this Dec 13, 2024
@JoshuaSBrown JoshuaSBrown linked an issue Dec 18, 2024 that may be closed by this pull request
3 tasks
@JoshuaSBrown JoshuaSBrown added Type: Refactor Imlplementation change, same functionality Priority: High Highest priority Component: Scripts Helper scripts or admin scripts Component: Build Related to the build system Type: Test Related to unit or integration testing labels Dec 18, 2024
@JoshuaSBrown
Copy link
Collaborator Author

@sourcery-ai review

Copy link

@sourcery-ai sourcery-ai bot left a 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

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
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)) {
Copy link

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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Nice catch.

Copy link

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.

@JoshuaSBrown JoshuaSBrown changed the title 1180 refactor authz 1180 refactor foxx authz Dec 30, 2024
@JoshuaSBrown JoshuaSBrown requested a review from AronPerez January 2, 2025 21:14
Copy link
Collaborator

@AronPerez AronPerez left a 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

@JoshuaSBrown JoshuaSBrown requested a review from AronPerez January 2, 2025 21:35
Copy link
Collaborator

@t-ramz t-ramz left a 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.
Copy link
Collaborator

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
Copy link
Collaborator

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

Copy link
Collaborator Author

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;
Copy link
Collaborator

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?

Copy link
Collaborator Author

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.

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 would say that if you don't conform to the pattern, it is likely an anti-pattern.

Copy link
Collaborator

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
Copy link
Collaborator

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
Copy link
Collaborator

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.
Copy link
Collaborator

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()) {
Copy link
Collaborator

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?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

* @brief Checks if the record exists in the database.
* @return {boolean} True if the record exists, otherwise false.
*/
exists() {
Copy link
Collaborator

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", () => {
Copy link
Collaborator

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?

Copy link
Collaborator Author

@JoshuaSBrown JoshuaSBrown Jan 6, 2025

Choose a reason for hiding this comment

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

@JoshuaSBrown JoshuaSBrown merged commit f60d2f7 into devel Jan 7, 2025
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Build Related to the build system Component: GridFTP Auth Module Relates to GridFTP authorization library Component: Scripts Helper scripts or admin scripts Priority: High Highest priority Type: Refactor Imlplementation change, same functionality Type: Test Related to unit or integration testing
Projects
None yet
3 participants