Giter VIP home page Giter VIP logo

Comments (29)

veotax avatar veotax commented on May 3, 2024 8

Casbin-RS is an authorization library that supports models like ACL, RBAC, ABAC for Rust.

Related to RBAC, casbin has several advantages:

  1. roles can be cascaded, aka roles can have roles.
  2. support resource roles, so users have their roles and resource have their roles too. role = group here.
  3. the permission assignments (or policy in casbin's language) can be persisted in files or database.
  4. multiple models like ACL, BLP, RBAC, ABAC, RESTful are supported.

And you can even customize your own access control model, for example, mix RBAC and ABAC together by using roles and attributes at the same time. It's very flexible. Can we integrate it into Rocket?

from rocket.

SergioBenitez avatar SergioBenitez commented on May 3, 2024 2

@echochamber Flask-Auth seems to try to embody some of the ideals I'm hoping to achieve regarding extensibility. However, I think Rocket provides an array of tools that can be used to obtain greater correctness and security guarantees. And, of course, we have all of Rust at our disposal!

Seeing as this is a big target, I'm pushing this to 0.5 for the time being.

from rocket.

Weasy666 avatar Weasy666 commented on May 3, 2024 2

Building on the crate mentioned by @blackghost1987 i started to implement a "generic" authentication, rocket_auth.

It's still early, but functional. I know there is a lot missing, especially docs and tests, but i wanted to hear some opinions about it, before i put in a lot of work and effort to write the docs and tests.
So...is this even the right direction? Is it too less? If so, what is missing or needs to be changed?
Should there be a ready to use default implementation? I think this is not that easy, because of all the database connection/work that needs to be done for user signup, login and session verification.

from rocket.

jtmarmon avatar jtmarmon commented on May 3, 2024 1

Right now the handlers take arguments that are associated with params in the URL. Presumably you'd want to pass auth-related data to the handler (e.g. I want to get all posts for the currently authenticated user). How could we achieve this given the current structure?

from rocket.

blackghost1987 avatar blackghost1987 commented on May 3, 2024 1

FYI: rocket-simpleauth crate could be useful https://github.com/bramvdbogaerde/auth-rs

from rocket.

Weasy666 avatar Weasy666 commented on May 3, 2024 1

Ok...i'm back with another approach, rocket_airlock.

I was inspired by Jeb's rocket_oauth2 crate and tried to find a generic approach that can be used as basis for different authentication approaches.
I think it could be a good starting point and i would be willing to put some more work into it, when @SergioBenitez and @jebrosen think it is the right direction/approach and are willing to point me into the right direction for what is coming next. If it is completeley different to what you had in mind....then that is rather unfortunate, but i would be willing to rewrite Airlock under the condition that we keep the naming...because i rather like it. πŸ˜…πŸ˜€
This is currently not a plug&play solution since it only provides a basis on which auth methods/hatches could be implemented, but i have successfully used it in combination with openidconnect-rs for a OpenID Connect-Hatch.

from rocket.

SergioBenitez avatar SergioBenitez commented on May 3, 2024 1

Fairings seem like the feature to use for http security, but they can't return the request early.

They can, by diverting the request to any route of its choosing, including routes that it controls.

but to me it makes more sense to have an application secured by default and then configure unsecured routes manually (with path matchers for example):

You can do that with a fairing. Exposing the Request::matches() method would make it trivial to do so (see #1561), but your syntax in particular would be easy to implement even today.

@SergioBenitez How would one go about using a fairing to implement authentication or authorization?

See existing crates like rocket_oauth2 for what they do.

from rocket.

jtmarmon avatar jtmarmon commented on May 3, 2024

answer: request guards (or something similar)

from rocket.

eugene-bulkin avatar eugene-bulkin commented on May 3, 2024

More specifically, what is the best way to store session information in this manner? Would that just be in some global static manager of some sort?

from rocket.

shssoichiro avatar shssoichiro commented on May 3, 2024

Possible suggestions would be a global state within the framework (protected by a Mutex?), a directory on the filesystem, Redis, a database... basically anything supported by other popular frameworks. I listed them in order of (my estimation of) difficulty of implementation.

The ability to switch between different backends would be nice, but maybe it would be good to start with the simplest implementation first.

Edit: Stateless auth (JWT) support would also be nice, but may be a separate issue.

from rocket.

shssoichiro avatar shssoichiro commented on May 3, 2024

I'll take a shot at this. I'll make an implementation using in-memory state first as a proof of concept. I imagine later implementations can be added and switched between using a config parameter.

from rocket.

shssoichiro avatar shssoichiro commented on May 3, 2024

Does Rocket currently have a system similar to middleware that would allow the session to automatically set a cookie (containing the session ID) in the response? That is the most common way (from what I am aware) of handling server-side sessions, and may be a blocker for this (unless we tell users to manually set the cookie at the start of a session--probably not what we want).

from rocket.

Eijebong avatar Eijebong commented on May 3, 2024
#[post("/login", data="<form>")]
fn login_post(cookies: &Cookies,              
              user: AnonymousUser,            
              form: Form<LoginForm>)          
              -> Result<Redirect, Template> { 
    /* ... */
    /* Check credentials */
    if ok {
        /* Build session ID, insert it in whatever you're using for this (I'm personally using redis) */
        let cookie = Cookie::build("uid".to_owned(), uid).path("/").finish();
        cookies.add(cookie);                                                 
                                                                     
        return Ok(Redirect::to("/"));                                        
    }
    /* ... */

I'm personally using that snippet of code for my auth system. Wouldn't something like that work for you ?

from rocket.

shssoichiro avatar shssoichiro commented on May 3, 2024

Unfortunately that doesn't help me in this case, because I'm trying to implement a contrib module for rocket.

from rocket.

SergioBenitez avatar SergioBenitez commented on May 3, 2024

This is something that is very tricky to get right and where I'm likely to decline implementations as too inflexible, too hard to use, or as insecure. I caution anyone wanting to take this on to be open to spending a lot of time on this. This is something that absolutely has to be correct. It also needs to be flexible; it should be usable by most projects with most requirements.

@shssoichiro You can get, set, and remove cookies via the Request object; no need for middleware.

from rocket.

echochamber avatar echochamber commented on May 3, 2024

@SergioBenitez Any particular frameworks you think are a good example to model the API of Rocket's auth component after? Or just as a starting point.

from rocket.

jhpratt avatar jhpratt commented on May 3, 2024

Just running across this. Having built-in authentication would be great, especially a generic OAuth implementation. @SergioBenitez is there anything we could do to help out? I see you'll be quite picky, so I'd prefer to have a wasted effort.

from rocket.

jebrosen avatar jebrosen commented on May 3, 2024

@jhpratt you may be interested in jebrosen/rocket_oauth2. I wouldn't call it production-ready for several reasons and it is oauth-specific, but its model (good and bad) may serve as inspiration for a more complete solution.

EDIT: Links are hard

from rocket.

pickfire avatar pickfire commented on May 3, 2024

Maybe something like http://python-social-auth.readthedocs.org/ using 3rd party authentication?

from rocket.

conways-glider avatar conways-glider commented on May 3, 2024

I was wondering how in a pluggable auth library, one would handle external services - would we be able to write custom checkers? (e.g. Auth0, Firebase Auth, Cognito, etc.)

from rocket.

adhesivee avatar adhesivee commented on May 3, 2024

Looking at this thread and I see that stateless and stateful needs to be supported.
I think it will be good what is common between these and what isn't.
My experience with other projects is that the common element is a Principal, which is the bare minimum. As this is an abstraction this would fit perfectly as a trait:

trait Principal {
  fn name() ->&str
}

This should give the flexibility to adopt your own. For example:

impl UserPrincipal for Principal {
  fn roles(): &[&str];
  ...
}

impl ApplicationPrincipal for Principal {
  ...
}

This separation could be useful, for example if the application is interacting with users we expect UserPrincipal and if we want to communicate server to server we can expect ApplicationPrincipal (which also allows to add additional properties if we wanted to):

#[get("/v1/any-interaction")]
fn user_interaction(principal: Principal) {}
#[get("/v1/user-interaction")]
fn user_interaction(user: UserPrincipal) {}
#[get("/v1/server-interaction")]
fn server_to_server(application: ApplicationPrincipal) {}

Rocket could for example provide several implementations that always use UserPrincipal, this makes transition to a different implementation smoother.

from rocket.

tvallotton avatar tvallotton commented on May 3, 2024

For the last four days I've been working on my own implementation. I still haven't tested all the features I claim to support on the docs, since I'm just starting up. If you're interested, check it out at https://docs.rs/rocket_auth/0.1.1/rocket_auth/.
EDIT:
I just updated some of the docs to include some examples so you can picture the API. It is quite minimalist. It does not require the user to implement any trait. you can see the updated docs at https://docs.rs/rocket_auth/0.1.3/rocket_auth/.

from rocket.

hsluoyz avatar hsluoyz commented on May 3, 2024

See the Rocket Casbin middleware for authorization: https://github.com/casbin-rs/rocket-authz

from rocket.

tvallotton avatar tvallotton commented on May 3, 2024

Hi, in light of 0.5 coming up, I would love to hear some suggestions on how to improve my crate for authentication management https://github.com/tvallotton/rocket_auth. I fear there might be issues I'm missing.

from rocket.

tvallotton avatar tvallotton commented on May 3, 2024

I just released the new version of rocket_auth so it now supports Rocket 0.5-rc, as well as Sqlite3, Postgresql, Mysql and Redis. Check it out if you are interested.

from rocket.

ivandimitrov8080 avatar ivandimitrov8080 commented on May 3, 2024

I think it would be better to have something similar to spring's filter chain @SergioBenitez :
https://stackoverflow.com/a/41482134/11384519

Does rocket support request filters in any way?

from rocket.

SergioBenitez avatar SergioBenitez commented on May 3, 2024

I think it would be better to have something similar to spring's filter chain @SergioBenitez :

https://stackoverflow.com/a/41482134/11384519

Does rocket support request filters in any way?

To some degree, yes, but Rocket isn't Spring, so its mechanisms are different. Of particular relevance, see fairings and guards.

from rocket.

ivandimitrov8080 avatar ivandimitrov8080 commented on May 3, 2024

Fairings seem like the feature to use for http security, but they can't return the request early.

The docs state that it's better to have guards used for security:

You should not use a fairing to implement authentication or authorization (preferring to use a
 [request guard](https://rocket.rs/v0.5-rc/guide/requests/#request-guards) instead) unless
 the authentication or authorization applies to all or the overwhelming majority of the application

but to me it makes more sense to have an application secured by default and then configure unsecured routes manually (with path matchers for example):

httpSecurity.build()
    .paths(&["/unsecured/**", "/login", "/signup"]).permit()
    .paths(&["/unsecured/secret"]).deny()

Maybe it's the spring dev in me, but maybe it's more secure to explicitly allow access to a resource in a larger app instead of forgetting to secure it.

EDIT:

@SergioBenitez How would one go about using a fairing to implement authentication or authorization?

from rocket.

emirror-de avatar emirror-de commented on May 3, 2024

@SergioBenitez would the following idea meet your conception for auth support?

Technical details/Modelling:

  • Using JWT cookie for client side storage
  • User provider/storage interface responsible for user validation (with support for custom storages)
  • Authentication of a user by id and secret with scope and role (with support for custom user models)

Example usage in a rocket application:

#[get("/")]
async fn index() -> Option<NamedFile> {
    NamedFile::open("index.html").await.ok()
}

#[post("/login", format = "json", data = "<credentials>")]
async fn login(
    credentials: Json<AccountCredentials>, // user credentials submitted by the web application
    account_provider: &State<MemoryAccountProvider>, // interface to the user storage
    auth_settings: &State<AuthSettings>, // generic settings required on launch, see main fn
    cookies: &CookieJar<'_>,
) -> Status {
    match account_provider.login(
        credentials.into_inner(),
        auth_settings.inner(),
        cookies,
    ) {
        Ok(_) => Status::Ok,
        Err(e) => {
            log::error!("{e}");
            Status::Unauthorized
        }
    }
}

#[get("/private")]
async fn private(user: AccountClaims) -> String { // protected route by the request guard
    // your implementation for different roles here
    format!("{user:#?}")
}

#[launch]
fn simple_login() -> _ {
    // We create an immutable global state containing information with the cookie name, cookie path
    // and JWT settings like encryption secret and time validity.
    let auth_settings = AuthSettings::new()
        .with_cookie_name("rocket_user")
        .with_cookie_path("/") // IMO the path does not change in most applications
        // JWT encryption key, can also be randomly generated on every launch,
        // maybe one could add support for custom secret provider for custom implementations
        .with_secret("TOP_SECRET_ENCRYPTION_KEY")
        .with_valid_login(TimeDelta::try_weeks(1).unwrap()); // validity of JWT cookie
    // create a user storage, can be anything you require, like database connection
    // or just in memory storage for development or fast prototypes
    let auth_provider = MemoryAccountProvider::from(vec![Account::new(
        "simple_user",
        "somepassword",
        "simple_service", // scope of user
        AccountType::Admin, // some presets available, support for custom role like `Custom(String)`
    )
    .unwrap()]);

    rocket::build()
        .mount("/", routes![index, private, login])
        .manage(auth_settings)
        .manage(auth_provider)
}

I already have a prototype implementation which is not as flexible as described above yet. But I am happy to get my hands on this if your vision about the auth contrib crate aligns.
Happy to get your comments and adjustments!

from rocket.

Related Issues (20)

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.