Skip to content

Conversation

DDtKey
Copy link
Contributor

@DDtKey DDtKey commented Dec 8, 2023

Description

  • fix not-exposed endpoints to return 404 instead of 403 (they literally not intended to be exposed) - the only breaking change, can be extracted to separate PR
  • keep authz rules cohesive
  • use HashSet instead of Vec to check tokens
  • clean up boilerplate code using macro from actix-web-grants to protect endpoints
  • utilize ErrorHandlers to log unauthorized errors instead of in-place host handling & etc
  • disallow blank tokens

Motivation and Context

I came across rustypaste and decided to check the code a little & play locally with it. As a result, some of the authorization rules were not obvious to me. For example:

  • lack of delete_tokens - hides the endpoint
  • lack of auth_tokens - allows the access (btw, is it intended? because sound like a bug)
  • disabled endpoints return 403, but from the point of view of security and correctness it is more likely to be 404 - we literally do not expose them

So I decided to do a little refactoring, which I hope you find useful.

Another part of the changes is the introduction of actix-web-grants - this is a small but quite flexible library, with which it will also be easy to change the rules, for example, switch to RBAC/ABAC or something else (actually I'm maintainer of the library, so it's may be subjective)

How Has This Been Tested?

Mostly by current test-coverage, I kept the same behavior, except 403 -> 404

Changelog Entry

### Fixed

- Return `404` for not exposed endpoints instead of `403`
- Disallow blank `delete_tokens` and `auth_tokens`

Types of Changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation (no code change)
  • Refactor (refactoring production code)
  • Other

Checklist:

  • My code follows the code style of this project.
  • I have updated the documentation accordingly.
  • I have formatted the code with rustfmt.
  • I checked the lints with clippy.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@DDtKey DDtKey requested a review from orhun as a code owner December 8, 2023 21:07
@DDtKey DDtKey force-pushed the switch-to-actix-web-grants branch from 57dd3ed to 310cdca Compare December 8, 2023 21:10
@DDtKey
Copy link
Contributor Author

DDtKey commented Dec 8, 2023

feel free to close PR if you don't find it useful

@orhun
Copy link
Owner

orhun commented Dec 8, 2023

Definitely sounds/looks useful! I can review the code tomorrow.

One thing to note here, you can add fixture tests to test the new behavior.

@codecov-commenter
Copy link

codecov-commenter commented Dec 8, 2023

Codecov Report

Attention: 6 lines in your changes are missing coverage. Please review.

Comparison is base (adbd67a) 70.23% compared to head (8d35ca8) 70.16%.

Files Patch % Lines
src/auth.rs 87.87% 4 Missing ⚠️
src/config.rs 87.50% 1 Missing ⚠️
src/server.rs 92.30% 1 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #199      +/-   ##
==========================================
- Coverage   70.23%   70.16%   -0.08%     
==========================================
  Files          11       11              
  Lines         598      610      +12     
==========================================
+ Hits          420      428       +8     
- Misses        178      182       +4     
Flag Coverage Δ
unit-tests 70.16% <88.88%> (-0.08%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@DDtKey
Copy link
Contributor Author

DDtKey commented Dec 9, 2023

Thanks for the reference!

I took a look at fixtures and think it makes sense to add new fixtures for not-exposed endpoints (list, version or delete-tokens not configured)

Otherwise I have mostly kept the behavior and there is coverage of the main cases.

Except probably one more case, which hasn’t been covered before: if auth-tokens unset/not configured - access is allowed (just to clarify, is this intended?)

There are unit tests ofc, but I’ll add fixtures a bit later for all these cases!

@orhun
Copy link
Owner

orhun commented Dec 9, 2023

fix not-exposed endpoints to return 404 instead of 403 (they literally not intended to be exposed) - the only breaking change, can be extracted to separate PR

disabled endpoints return 403, but from the point of view of security and correctness it is more likely to be 404 - we literally do not expose them

I think it makes sense. We can mention this in the changelog as breaking.

lack of delete_tokens - hides the endpoint

The intention was to require tokens to delete files on the server. Do you think we should change that?

lack of auth_tokens - allows the access (btw, is it intended? because sound like a bug)
Except probably one more case, which hasn’t been covered before: if auth-tokens unset/not configured - access is allowed (just to clarify, is this intended?)

Yeah, this is intended. Do you think we should have an empty list of tokens for allowing access? It is not a big deal imo.

Another part of the changes is the introduction of actix-web-grants

I saw a derive macro on the endpoints that we want to protect but can you tell me how that works? Also it would be nice to get some information in terms of which version of Actix do you support, what are the plans for the future (will there be any breaking changes) etc.

I took a look at fixtures and think it makes sense to add new fixtures for not-exposed endpoints (list, version or delete-tokens not configured)
There are unit tests ofc, but I’ll add fixtures a bit later for all these cases!

Great! Just let me know if you have problems / need guidance while adding them.

@DDtKey
Copy link
Contributor Author

DDtKey commented Dec 9, 2023

lack of delete_tokens - hides the endpoint

The intention was to require tokens to delete files on the server. Do you think we should change that?

Not sure, the main confusion is that we have expose flag for list & version - which is really clear, but in case of delete it depends on delete_tokens. Not so clear when configuring the app, the first thing that comes to mind is that it should be 401 (any token won't match configured ones, they are unset), but in fact 404 seems safer in this case.

So I think we can keep it as is, probably improve the documentation related to the config - if delete_tokens unset then delete endpoint won't be exposed at all.

lack of auth_tokens - allows the access (btw, is it intended? because sound like a bug)

Yeah, this is intended. Do you think we should have an empty list of tokens for allowing access? It is not a big deal imo.

I thought more about explicit configuration flag, like disable_auth. Just looks less fragile when configuring the app, but the behavior itself is ok, just there was no any comments and I have been concerned. I've added comment & logging with this behavior anyway.

I saw a derive macro on the endpoints that we want to protect but can you tell me how that works?

Actually it works pretty straightforward:

  • Middleware which extracts some "authority" entity from request (in our case we do extract TokenType)
  • it adds specific type (AuthDetails<T>) to extensions
  • macro actually helps to get rid of the following boilerplate, it expands to something like that:
async fn endpoint(details: AuthDetails) -> HttpResponse {
    if details.has_authority(TokenType::Auth) {
        // body of our function
    } else {
       // error we want to see, defaults to `Forbidden`
    }
}

But we can write it manually as well

Also it would be nice to get some information in terms of which version of Actix do you support, what are the plans for the future (will there be any breaking changes) etc.

actix-web was the first framework within this ecosystem, there is mention here: https://github.com/DDtKey/protect-endpoints/tree/main/actix-web-grants#supported-actix-web-versions, any major update of the actix-web gonna be supported with new major version of actix-web-grants

Recently I've delivered a huge update and I'd say it's likely long-term vision of API. As part of that update I also switched to release-plz (with cargo-semver-checks & git-cliff under the hood), so we have some validations.

Current macro-syntax flexible enough and should fit a lot of cases, including ABAC & RBAC, for example, you can combine the conditions in Rust-friendly way, using all & any:

// snippet from examples
#[actix_web_grants::protect(any("ADMIN", expr = "user.is_super_user()"), ty = "Role")]
async fn admin_or_super_user(user_id: web::Path<i32>, user: web::Data<User>) -> HttpResponse {
    HttpResponse::Ok().body("some secured response")
}

So I don't expect the breaking changes in the near future, and if they would be - it will be major (semver) update without breaking existing applications, and with back-porting the changes if they're compatible & makes sense.

@DDtKey
Copy link
Contributor Author

DDtKey commented Dec 9, 2023

Great! Just let me know if you have problems / need guidance while adding them.

I've added fixtures, it looks pretty clear to me, thanks!

Some not related observations:

  • Would be nice to call teardown even in case of failure, to clean up
  • macos: sleep doesn't work with time-units (e.g sleep 1s)
  • macos: there is no fallocate (alternative would be to use dd if=/dev/random of=normalfile count=10000 bs=1024 status=none)

I think would be nice to ensure it works on any platform, or provide fast way to run it with docker for example.
See #200

@orhun
Copy link
Owner

orhun commented Dec 10, 2023

So I think we can keep it as is, probably improve the documentation related to the config - if delete_tokens unset then delete endpoint won't be exposed at all.

Makes sense - would you be interested in making a PR to update README.md about this?

I thought more about explicit configuration flag, like disable_auth [...] I've added comment & logging with this behavior anyway.

👍🏼

Actually it works pretty straightforward:

Thanks for the explanation! It is more clear now.

I also switched to release-plz (with cargo-semver-checks & git-cliff under the hood)

Aye that's me! Let me know if you need help with any configuration.

Current macro-syntax flexible enough and should fit a lot of cases, including ABAC & RBAC, for example, you can combine the conditions in Rust-friendly way, using all & any:

Wow that's nice!

So I don't expect the breaking changes in the near future, and if they would be - it will be major (semver) update without breaking existing applications, and with back-porting the changes if they're compatible & makes sense.

Alright, sounds good.

@DDtKey
Copy link
Contributor Author

DDtKey commented Dec 10, 2023

Makes sense - would you be interested in making a PR to update README.md about this?

Take a look at #202, please

Aye that's me! Let me know if you need help with any configuration.

Yes, thanks for the wonderful tool! 🙏 Actually I've been using it for about a year on different projects! 😅

@orhun
Copy link
Owner

orhun commented Dec 11, 2023

LGTM! Just one last thing.

I usually put the user-facing changes in the changelog so I guess the only things that have changed are:

  • we now return 404 instead of 403 for non-exposed endpoints
  • we don't allow blank (whitespace) tokens

Do we need to mention something else in the changelog?

@DDtKey
Copy link
Contributor Author

DDtKey commented Dec 11, 2023

In that case I think these two are enough, I'll update the changelog entry

Copy link
Owner

@orhun orhun left a comment

Choose a reason for hiding this comment

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

Thanks!

@orhun orhun changed the title refactor!: cleanup authorization boilerplate refactor(server)!: cleanup authorization boilerplate Dec 12, 2023
@orhun orhun merged commit e21f99a into orhun:master Dec 12, 2023
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.

3 participants