Code Monkey home page Code Monkey logo

protect-endpoints's Introduction

DDtKey's GitHub stats

protect-endpoints's People

Contributors

augustocdias avatar chaostheorie avatar curiouscorrelation avatar ddtkey avatar dependabot[bot] avatar github-actions[bot] avatar grifs avatar gwendalf avatar mgrachev avatar rodmitry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

protect-endpoints's Issues

Error "type `Config` is not a member of trait `FromRequest`"

When I try to use "actix-web-grants" I get the following error:

error[E0437]: type Config is not a member of trait FromRequest
--> C:\Users\myuser.cargo\registry\src\github.com-1ecc6299db9ec823\actix-web-grants-3.0.0-beta.3\src\permissions\mod.rs:92:5

What could be the reason to get this error?

Reorganize `*-grants` crates into single repo (workspace)

This issue exists to inform about the status and plans.

There is an initiative to reorganize structure of existing crates:

The interface of these crate is really close to each other and gonna be aligned as long as possible.

It's possible to extract some reusable stuff, documentation, CI and improve code quality.
In addition it should improve maintainability, will be much easier to manage issues and reflect changes into related crates.

For example, that's really helpful to implement DDtKey/rocket-grants#3 for all crates.

404 instead of 403 for Scope

I know it's not a documented use case, but it works and somehow returns 404 error instead of 403.

.service(
    web::scope("/admin")
        .service(index)
        .service(users)
        .guard(PermissionGuard::new(ROLE_ADMIN.to_string()))
);

Was checked on v3.0.0-beta.1

New release with Actix Web 4 support

I would like to request a new major release (3.0.0) with support for the stabilized Actix Web 4.0. Most of the work for such a release has already been done, with the changes added in 3.0.0-beta.x. The required changes have been done in #30.

PS:
Thank you for your awesome work on Actix Web grants. I've recently started to use Actix Web for a personal project, and the permission guarding with the grant macros was very helpful for getting everything started.

custom attribute panicked message: called `Option::unwrap()` on a `None`

I am using poem and poem-grants and copied the JWT example, but am getting the following error: custom attribute panicked message: called Option::unwrap() on a None on the #[poem_grants::protect("ADMIN")] macro. The code is:

#[poem_grants::protect("ADMIN")]
#[handler]
fn post_blog(mut pool: Data<&PgPool>, Json(blog): Json<NewBlog>) -> Response {
    let r = match blog.id {
        Some(id) => Blog::update(pool_handler(pool)?.borrow_mut(), id, blog.into()),
        None => Blog::create(pool_handler(pool)?.borrow_mut(), blog.into()),
    };

    match r {
        Ok(blog) => ResponseBuilder::builder()
            .status(StatusCode::OK)
            .body(json!({
                "blog": r.expect("Error")
            })),
        Err(e) => {
            eprintln!("Failed to save or update blog: {}", e);
            ResponseBuilder::builder()
                .status(StatusCode::SERVICE_UNAVAILABLE)
                .body(MessageResponse {
                    message: "Failed to update or insert".to_string(),
                })
        }
    }
}

...

pub fn api() -> JwtMiddlewareImpl<Route> {
    Route::new()
        .at("/getBlogs", get(get_blogs))
        .at("/getBlog", get(get_blog))
        .at("/updateBlog", post(post_blog))
        .at("/getFaq", get(get_faq))
        .at("/getTestimonial", get(get_testimonial))
        .with(JwtMiddleware)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    tracing_subscriber::fmt::init();
    let connection_pool = db_helpers::establish_connection();
    let app = Route::new()
        .nest("/api/content", api())
        .with(AddData::new(connection_pool))
        .with(Tracing);
    Server::new(TcpListener::bind("0.0.0.0:3000"))
        .run_with_graceful_shutdown(
            app,
            async move {
                let _ = tokio::signal::ctrl_c().await;
            },
            Some(Duration::from_secs(1)),
        )
        .await?;
    Ok(())
}

Mismatch between compiler message and function arg position in tests

Message on failing a test with common::test_body(left, right) fn look like this:

---- proc_macro::different_fn_types::test_str stdout ----
thread '...' panicked at 'assertion failed: `(left == right)`
  left: `"Hi!"`,
 right: `"Hello!"`', tests/file...
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

which corrosponds to

common::test_body("Hello!", "Hi!").await;

The lhs/rhs mismatch between compiler's message and the function params is due to the underlying assert_eq! swap of expected and received args

pub async fn test_body(resp: ServiceResponse, expected_body: &str) {let body = test::read_body(resp).await;assert_eq!(expected_body, String::from_utf8(body.to_vec()).unwrap());
}

Swapping lhs and rhs

pub async fn test_body(resp: ServiceResponse, expected_body: &str) {let body = test::read_body(resp).await;assert_eq!(String::from_utf8(body.to_vec()).unwrap(), expected_body);
}

fixes this issue.

This follows The Rust Book convention of

assert_eq!(actual, expected);

I have a PR ready to go if this feels like a worthwhile issue and doesn't violate library wide chosen convention.

Support for custom access denied response in `proc-macro`

The access denied response is currently fixed/hardcoded for actix-grants-proc-macro: 403 Forbidden (see this line)

It makes sense, but I found it helpful to let users specify their response.

My suggestion: add new optional attribute (denied or error for example) for macros (which will apply expression syn::Expr)
As a result, the user can specify response something like this:

#[get("/secured")]
#[has_role("ADMIN", error = "access_denied()")]
async fn secured() -> HttpResponse {
    HttpResponse::Ok().body("some response for allowed requests")
}

fn access_denied() -> HttpResponse {
    HttpResponse::with_body(StatusCode::FORBIDDEN, BoxBody::new("This resource allowed only for ADMIN"))
}

?-operator and `proc-macro`-method

Hi!

I have been trying this for my own project and I have to say it is very convenient. However I am noticing that functions with lots of calls that can fail are a bit awkward to write since the ?-operator does not work.

#[get("/foo")]
#[has_permissions("foo")]
pub async fn foo() -> Result<HttpResponse, SomeError> {
    let a = thing_that_might_fail().await?;  //<-- Error: ? can only be used in a function that returns Result or...
    let b = other_thing(a).await?;           //<-- Error
    let c = yet_other_thing(b).await?;       //<-- Error
    Ok(and_so_on(c).await)
}

Do you have any suggestions for how I should write a similar function? Or might I request some way of supporting the ?-operator :)

use enum in attribute?

Hi,

Is it possible to use an enum value in the has_permissions attribute at all? I understand that what i have below is not valid syntax but want to understand if something like this is possible?

from:

#[has_permissions("CanRead")]

to:

#[has_permissions(Permissions::CanRead.to_string())]

Customise token lookup location

The Gofiber JWT middleware provides flexibility in configuring the token lookup location, allowing adherence to OpenAPI specifications. The TokenLookup key supports options such as Cookie, Header, Path, and Query. The default setting is "header:Authorization", mirroring the behavior of this crate. However, in my frontend website, where I store the access token in cookies, ensuring compliance with OpenAPI specs, to transmit the access token to the Authorization header, the cookie cannot be set as HttpOnly, compromising security. Therefore, I aim to maintain HttpOnly while employing this crate to extract the token by reading cookies with a custom key.

image

Support for allowing 1 permission or the other

Hi there!
I wanted to make it so the user either has ROLE_ADMIN OR has a specific permission, instead of the user having both. Is this supported?

// User should be ADMIN with OP_GET_SECRET permission
#[actix_web_grants::protect("ROLE_ADMIN", "OP_GET_SECRET")]
async fn macro_secured() -> &'static str {
    "some secured info"
}

(taken from docs)
From what i understand here, the user woiuld have to have both ROLE_ADMIN and OP_GET_SECRET. I wanted it so a certain permission can inherit other permissions. I am writing a custom extractor so i could theoretically add all the inherited permissions when i see a certain permission, but I was wondering if there was a built-in way to do so.

Thanks!

Why this change

poem-grants v2.0.0

1
2

I remember that in the ^1 version, there was no permission. The error message returned by interception was Forbidden 403.
Why is the current request Unauthorized?
This is completely inconsistent with the operational logic.
Because Unauthorized means that the server cannot obtain the identity of the request, but my current request is that I have logged in and got the Token issued by the server, but I just don’t have permission to access a certain resource, so I think Forbidden 403 is right

401 Unauthorized
403 Forbidden
They are two different things

Fails to build against actix_web 4.0.0-beta.14

After trying to update to beta.14, I get the following error. The second one looks like a quick fix. Not so sure about the first one.

error[E0599]: no method named `extensions` found for reference `&RequestHead` in the current scope
  --> /home/.cargo/git/checkouts/actix-web-grants-fc366f5a984b4e1f/f2f9964/src/guards.rs:44:14
   |
44 |             .extensions()
   |              ^^^^^^^^^^ method not found in `&RequestHead`

error[E0599]: no method named `extensions` found for struct `HttpRequest` in the current scope
  --> /home/.cargo/git/checkouts/actix-web-grants-fc366f5a984b4e1f/f2f9964/src/permissions/mod.rs:97:17
   |
97 |             req.extensions()
   |                 ^^^^^^^^^^ method not found in `HttpRequest`
   |
  ::: /home/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-http-3.0.0-beta.15/src/http_message.rs:29:8
   |
29 |     fn extensions(&self) -> Ref<'_, Extensions>;
   |        ---------- the method is available for `HttpRequest` here
   |
   = help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
   |
16 | use actix_web::HttpMessage;

I have reverted to an old Cargo.lock file which I'll stay with for now.

Check user name in route

Hello,
first of all thanks for your nice and simple to use crate!

Is it possible, to check the login user name in a route? I have only seen that AuthDetails has only a permissions value.

I ask because I would like to implement a function that a user can change his credentials, but for that I have to be sure, that the user can only change his own ones, and not from other users.

Using HttpAuthentication wrapper on the same named scope but different handler

Thank you for the amazing package!
This is more of a question than an issue.

I've been following the jwt-httpauth example:

let auth = HttpAuthentication::bearer(validator);
App::new().service(create_token).service(
    web::scope("/api")
        .wrap(auth)
        .service(permission_secured)
        .service(manager_secured),
)

The unguarded create_token handler is outside the /api scope.
The problem arises when you want to nest the unguarded route inside /api:

App::new()
    .service(
        web::scope("/api/v1")
            .wrap(HttpAuthentication::bearer(validator))
            .service(
                web::scope("/reservations")
                    .configure(reservations_controllers::secured_routes),
            ),
    )
    .service(
        web::scope("/api/v1")
            .service(web::scope("/auth").configure(auth_controller::routes)),
    )
    .app_data(data.clone())

Here, the first route works, but the second one returns 401.
Adding regexp {regex:$|/.*?} on the second scope doesn't work either.

Is there a way to achieve this? (Other than wrapping the handlers individually)

Question: Use multiple proc macros at the same time

More of a question than an issue.

Was hoping to do something like the following:

#[get("/read")] #[has_permissions("UserPermissions::UserRead")] #[has_any_role("UserRole::Admin", "UserRole::User")]

where I can check 2 different types (a UserPermissions enumeration and a UserRole enumeration on a singular endpoint.

Aka, I'd like for the permission to be UserRead, but also the user's role to be either an Admin or a User.

Given the 2 approaches to macros (has or has_any), I can't shove all of these into the same enumeration to solve this? (since the has_permissions/has_roles would exclude the 'or' logic for the roles, and has_any_role/has_any_permission, would just return true if any one is true.

And so far what I can see, the has_any_role/has_roles proc macros are the same logic as the permissions ones, just looking for a ROLES_ prefix in the string.

Trying to do the above on a struct provides me with:

identifier auth_details is bound more than once in this parameter list used as parameter more than once

Am I going about this/thinking about this wrong? I'd like to have a user role AND set of associated permissions checked.

Allow some routes to non authenticated users?

Hello,
this is a bit related to #37. Sometimes there are routes in the same scope, but some of them need authentication and some not.

Is there a strait way in actix-web-grants to implement this? My idea was, to map all users which send requests without authentication header to role Guest and use this in the route as:

#[has_any_role("Role::Admin", "Role::Guest", type = "Role")]
#[get("/my_route/")]
async fn my_route( ...

My only solution is s very bad workaround:

async fn validator(req: ServiceRequest, credentials: BearerAuth) -> Result<ServiceRequest, Error> {
    match auth::decode_jwt(credentials.token()).await {
        Ok(_) => req.attach(vec![Role::Admin]),
        Err(e) => {
            error!("validation: {e}");
            req.attach(vec![Role::Guest])
        }
    };
    req.attach(vec![Role::Admin]);

    Ok(req)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
   HttpServer::new(move || {
            let auth = HttpAuthentication::bearer(validator);

            App::new()
                .wrap_fn(|mut req, srv| {
                    if req.headers().get("authorization").is_none() {
                        req.headers_mut().append(
                            actix_web::http::header::HeaderName::from_static("authorization"),
                            actix_web::http::header::HeaderValue::from_static("Bearer guest"),
                        );
                    }
                    srv.call(req).map(|res| res)
                })
                .service(
                    web::scope("/api/v2")
                        .wrap(auth)
                        .service(my_route)
                        ...

is there a better way to solve the problem here?

Adding authentication to OpenAPI definition using poem_openapi

With poem_openapi, the openapi definition of every endpoint is generated from the endpoint definition. The poem-grants crate integrates seamlessly with poem_openapi, but sadly, I'm unable to show the required authentication in the openapi.json.

I did manage this with poem_openapi itself, but it's not nearly as ergonomic as poem-grants.
Is there any solution I'm missing? Or is this something that needs contribution?

Add support for ABAC-like model to procedural macro

It's proposed to add support for additional checking of custom conditions in proc-macro via an additional macro argument (e.g. secure).

The responsibility for having access to the properties specified in the secure section rests with the user of the library.
That is, the function must have arguments of the same name.

For example:

#[get("/users/{user_id}")]
#[has_permissions("READ_INFO", secure = "user_id==user.id")]
async fn secure_id(web::Path(user_id): web::Path<i32>, user: web::Data<User>) {
    // ...
}

The function parameters already contain user_id and user structure, accordingly, the implementation of the macro will add (in generated code) the specified condition to check access.

This is acceptable, because if there are no fields, we will receive a compilation error when expanding macros.

how custom fallback type

hi im new user for this framework
i want return cutom type if user no permission,
return json format not 403 only , how to do?

Redirect to another page if not granted instead of error page

I know I can make the redirect manually, but I think it's possible to make a redirect look good in macro, something like that:
#[has_permissions("ROLE_ADMIN", redirect = "/login")]

That is the response, right? We can make a redirect there, if it was passed in macro. Does it make sense?

Upd: I guess not, that's repeating. We need middleware for that I guess.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.