Code Monkey home page Code Monkey logo

rocket_auth's Introduction

Hello folks, this is my github account. I'm a narcissist so here are my user profile stats:

Tomas' GitHub stats

Top Langs

rocket_auth's People

Contributors

jaybosamiya avatar tvallotton avatar ywegel 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

Watchers

 avatar  avatar

rocket_auth's Issues

Make email none-case-sensitive

When creating/signing up a user with the same email but upper and lowercase (e.g.: [email protected] and [email protected]) your crate creates two different users. As far as i know emails are none-case-sensitive. I fixed this by applying .to_lowercase() to the email, but i think it would be good to warn for this in the documentation or to apply this in your users.create_user() and signup() function

Password checking

Check that passwords are not among the 20,000 most common passwords.

Email field of `User` should be public

I'm using sailfish for templates, and I don't wanna serialize the type because of overhead, and I only need the email field of User. This should probably be public, unless there's a specific security reason for it not to be.

Default Argon2 config does not meet OWASP minimum security

I was going through this crate to decide whether I should use it for a personal project, and I noticed that the rust-argon2 defaults are used:

#[throws(Error)]
pub async fn create_user(&self, email: &str, password: &str, is_admin: bool) {
let password = password.as_bytes();
let salt = rand_string(30);
let config = argon2::Config::default();
let hash = argon2::hash_encoded(password, salt.as_bytes(), &config).unwrap();
self.conn.create_user(email, &hash, is_admin).await?;
}

#[throws(Error)]
pub fn set_password(&mut self, new: &str) {
crate::forms::is_secure(new)?;
let password = new.as_bytes();
let salt = rand_string(10);
let config = argon2::Config::default();
let hash = argon2::hash_encoded(password, salt.as_bytes(), &config).unwrap();
self.password = hash;
}

(By the way, create_user uses a 30-byte salt, but set_password only uses a 10-byte salt. That seems...weird, and RFC9106 section 3.1 recommends 16-byte salts.)

Going through the rust-argon2 crate, we can see in a test that the defaults are configured to Argon2i, m=4096, t=3, p=1 (the mem_cost, time_cost and lanes parameters).

However, the OWASP guidelines that match most closely suggest that Argon2id, m=12288, t=3, p=1 should be used instead. One blog agrees with these values, although another (see "Password Hashing") recommends Argon2id, m=65536, t=3, p=1.

Either way, even though I'm no cryptographer, I think there's a consensus here that the defaults of the rust-argon2 crate are not secure enough. While I'm aware that there's a 0.5 major version in the works, it would be nice if you could release a 0.4.1 with the defaults improved.

Configuration parameter

Add a confiuration parameter that allows to specify the language for error messages, and the hashing algorithm

add `cargo test` to workflow

currently the workflow only checks if the project builds, but doesn't run any tests

i'll open a PR for this later today if that's alright!

ValidationError leaks password if signup fails

When singing up a user with a password, that does not meet the requirements, the error message leaks the password that was used in the signup. I don't know if this is intended. I narrowed it down to the ValidationError::new(...) function. The error message is inserted into the code and the actual message is left empty. Then in the Display implementation for ValidationError there is a check if the error message is empty, which is always the case. Then it skips printing the actual error message, and instead prints the code (which contains the error message, because it is set wrongly) and only shows "Validation error: " with the params (which is the password). I am showing these errors to my api response directly. This way the password pops up on screen, even though it is supposed to be hidden in the signup page.
i know this is actually an issue of the validator page, but i have an idea to avoid this. You could instead of using the display method to show the message, print the actual "code" field of the error. If you don't have enough time to fix this, i could create a pr

Document all Auth

Document all Auth fields and methods. Each one should include an example of its use.

Customizable SQL Schema

It looks like if I would like to use a different SQL schema than this project has built into it I would have to do it in a fork.

Since rocket_auth::db is private I cannot begin to make my own DBConnection implementation that used my own queries.

I'll probably cave and let your schema win, but this will make it difficult for people to integrate this authentication with existing systems.

Session is not invalidated after time expires using login_for

login_for method takes a Duration parameter, for how long the user should be logged in, after whose expiration I'm expecting the user to not be authorized anymore.
I'm trying this with one minute.

    auth.login_for(&form, std::time::Duration::from_secs(60))
        .await?;

In session/default/mod.rs this sets the auth key for that amout of time, but it seems it doesn't have effect...

    #[throws(Error)]
    fn insert_for(&self, id: i32, key: String, time: Duration) {
        let key = AuthKey {
            expires: time.as_secs() as i64,
            secret: key,
        };
        self.insert(id, key);
    }

User session keeps letting me make requests even after 1 minute has passed.

Shouldn't rocket_auth automatically invalidate the session after expiration?

PostgreSQL

Finish the DBConnection implementantion for tokio_postgres::Client

User FromRequest not found with git rocket and TLS

Hi. I'm hoping to implement a simple web app that includes user authentication and uses TLS. I am using a Cargo.toml that allows me to use TLS with Rocket:

[package]
name = "vhallway"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1.0.56"
rocket = { version = "0.5.0-rc.1", git = "https://github.com/SergioBenitez/Rocket.git", features = ["mtls", "secrets", "tls"] }
rocket_auth = { version = "0.4.0", features = ["tokio-postgres"] }

I have a minimal main.rs:

#[macro_use]
extern crate rocket;

use rocket_auth::User;

#[get("/user")]
fn user_info(user: User) -> String {
    format!("{:?}", user)
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![user_info])
}

... and see the following error when doing cargo build:

error[E0277]: the trait bound `User: FromRequest<'_>` is not satisfied
 --> src/main.rs:7:20
  |
7 | fn user_info(user: User) -> String {
  |                    ^^^^ the trait `FromRequest<'_>` is not implemented for `User`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `vhallway` due to previous error

But cargo test --doc works on rocket_auth cloned from github, and the User doctest is similar to my usage.

Add constructor for Signup

It is quite inconvenient to get a Signup form if one requires an username parameter in addition to password and email.

Improve error messages

Some error messages aren't very clear or are outright empty. Such as when you try to sign up, and the email is already taken, there is no helpful error message.

Feat: Redis Stack as a Persistant Data Storage.

Hi, I recently came across Redis Stack, which can also be used to store permanent data. And I was wondering like MySQL, PostgreSQL, and SQLite, which are supported by this repository, is it also possible to support Redis Stack as well? If it is possible please let me know where can I start. I would like to contribute in adding this feature to this repo.

From what I've seen till now is we can add it as a feature called rustis (A Redis Client package that supports Redis Stack) like other features [mysql, postgres, redis, sqlite] and add all the user-related queries using Redis Search.

or

Add the Redis Stack support in [redis] feature itself. This will actually enable users to use the full Redis Stack instead of using Redis for caching and SQLite for storing permanent data.

Please let me know your thoughts.
Thank you.

Async api

Rebuild the API for non-blocking calls to the database.

How to get the value chosen in an html form select, and having that value in a rust variable

Hello i have a form with a dropdown select where i chose a date, when a date is chosen i would like to have the chosen value to a rust variable.

main.rs:

#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] extern crate rocket;
use rocket::{State, form::*, get, post, response::Redirect, routes, response::content};
use rocket_auth::{prelude::Error, *};
use rocket_dyn_templates::Template;
use serde_json::json;
use sqlx::*;
mod api;
use api::{call_api, db_fill, query_select, ResultsStruct};
use std::result::Result;
use std::*;
use serde::{Deserialize, Serialize};
use rocket::serde::json::Json;

#[get("/style.css")]              // <- route attribute
fn style() -> content::RawCss<&'static str> {
content::RawCss(include_str!("style.css"))
}

#[get("/show_on_click")]              // <- route attribute
fn show_on_click() -> content::RawJavaScript<&'static str> {
content::RawJavaScript(include_str!("showOnClick.js"))
}

#[get("/login")]
fn get_login() -> Template {
Template::render("login", json!({}))
}

#[post("/login", data = "<form>")]
async fn post_login(auth: Auth<'_>, form: Form<Login>) -> Result<Redirect, Error> {
let result = auth.login(&form).await;
println!("login attempt: {:?}", result);
result?;
Ok(Redirect::to("/"))
}

#[get("/signup")]
async fn get_signup() -> Template {
Template::render("signup", json!({}))
}

#[post("/signup", data = "<form>")]
async fn post_signup(auth: Auth<'_>, form: Form<Signup>) -> Result<Redirect, Error> {
auth.signup(&form).await?;
auth.login(&form.into()).await?;

Ok(Redirect::to("/"))
}

#[get("/")]
async fn index(user: Option<User>) -> Template {
let color = "";
/*let c_api = thread::spawn( move || {
    let call_api = call_api().unwrap();
    call_api
}).join().expect("Thread panicked");*/

let query_result_fn = thread::spawn( move || {
    let query_result = query_select();
    query_result
}).join().expect("Thread panicked");
let query_result = query_result_fn.await.unwrap();

Template::render("index", json!({ "user": user, /*"c_api": c_api,*/ "query_result": query_result }))
}

#[derive(FromForm, Deserialize, Serialize)]
struct Time {
commence_time: String
}

#[get("/time")]
async fn time_get(user: Option<User>) -> Template {
let date_chosen= ""; // here i would like to have the chosen date in string.

let query_result_fn = thread::spawn( move || {
    let query_result = query_select();
    query_result
}).join().expect("Thread panicked");
let query_result = query_result_fn.await.unwrap();

Template::render("time", json!({ "user": user, /*"c_api": c_api,*/ "query_result": query_result }))
}

#[post("/time", format="json", data="<user>")]
fn post_time(user: Json<Time>) -> String {
String::from(format!(
    "Created user: {}", user.commence_time))
}


#[get("/logout")]
fn logout(auth: Auth<'_>) -> Result<Template, Error> {
auth.logout()?;
Ok(Template::render("logout", json!({})))
}
#[get("/delete")]
async fn delete(auth: Auth<'_>) -> Result<Template, Error> {
auth.delete().await?;
Ok(Template::render("deleted", json!({})))
}

#[get("/show_all_users")]
async fn show_all_users(conn: &State<SqlitePool>, user: Option<User>) -> Result<Template, Error> {
let users: Vec<User> = query_as("select * from users;").fetch_all(&**conn).await?;
println!("{:?}", users);
Ok(Template::render(
    "users",
    json!({"users": users, "user": user}),
))
}

#[tokio::main]
async fn main() -> Result<(), Error> {

let conn = SqlitePool::connect("/home/erty/Programming/rocket_app/users.db").await?;
let users: Users = conn.clone().into();
users.create_table().await?;

/*thread::spawn( move || {
    let db_fill = db_fill().unwrap();
    db_fill
}).join().expect("Thread panicked");*/

let _ = rocket::build()
    .mount(
        "/",
        routes![
            index,
            style,
            show_on_click,
            get_login,
            post_signup,
            get_signup,
            post_login,
            logout,
            delete,
            show_all_users,
            time_get
        ],
    )
    .manage(conn)
    .manage(users)
    .attach(Template::fairing())
    .launch()
    .await
    .unwrap();
Ok(())
}

index.html.tera

{% extends "base" %}

{% block body %}

    {% if not user %}

        <h1 class="text">Please login!</h1>
        <h3 class="text">For the use of this site you need to create an account or login</h3>
        <br>
        <div class="container">
            <a href="/login"><button id="Cbutton" type="Button" class="Cbutton btn btn-primary w-100">Login</button></a>
        </div>
            
    {% endif %}

    {% if user %}
        <script src="/show_on_click"></script>
        <h1 class="text">Welcome to My Website Index! </h1>
        <br>
        <h3 class="text">You are logged in as {{ user.email }}</h3>
        <br>
            <form action="/time" method="post">
                <select>
                    {% set vec_num = 0 -%}
                    {% for i in query_result %}
                        {% set_global commence_time = query_result[vec_num].commence_time %} 
                        <option value = {{ commence_time }} > {{ commence_time }} </option>
                        {% set_global vec_num = vec_num + 1 %}
                    {% endfor %}
                </select>
                <div class="mb-3 row">
                    <button id="Cbutton" type="Button submit" class="Cbutton btn btn-primary">Submit</button>
                </div>
            </form>
    </div>
        
    {% endif %}

{% endblock body %}

if i submit i get this error

No matching routes for POST /time application/x-www-form-urlencoded.

Compile error

So the next crate does not compile anymore, because i can't find the id, as id is not a filed anymore. It can be fixed by changing line 316 in auth.rs from let user: User = self.users.get_by_id(session.id).await?; to let user: User = self.users.get_by_id(session.id()?).await?;. I tried to fix it myself, it works locally, but i can't update my fork

Add metadata to users

Possible values could include: creation date, is active, and the number of failed login attempts, a reset password token and its date.

Check if String is same as hashed password

I am currently implementing a feature to change a users password and email. To do that the user has to reenter the password, even if he is logged in. After that i want to hash the password and compare it to the current one.
My Problem is:
I can't find a method to easily hash a String with the same salt as the current password. For now i can try to use the argon2 crate as you do and hash it that way, but It would be nice to have a function to compare the hashed password to a string. Maybe you can add that in the next release :)

Trait FromRequest not implemented for User/Admin when trying to use guards

rust 1.60 stable
rocket_auth = { version = "0.4.0", features = ["sqlx-postgres"] }
rocket = { git = "https://github.com/SergioBenitez/Rocket/", features = ["json", "secrets", "uuid"]}
rocket_dyn_templates = { git = "https://github.com/SergioBenitez/Rocket/", features = ["tera"]}

I see the traits in the rocket_auth lib.......so, obviously, I'm doing something silly. Looking for input on what I'm doing wrong.

use rocket_auth::{Users, Error, Auth, Signup, Login, User, AdminUser};

#[get("/admin-panel")]
fn admin_panel(user: AdminUser) -> String {
format!("Hello {}.", user.email())
}

error[E0277]: the trait bound rocket_auth::AdminUser: FromRequest<'_> is not satisfied
--> src/admin/bp_user.rs:27:22
|
27 | fn admin_panel(user: AdminUser) -> String {
| ^^^^^^^^^ the trait FromRequest<'_> is not implemented for rocket_auth::AdminUser

Redis Session

Finish implementing a redis backend for managing sessions.

Database error during password change (tokio_postgres)

It causes a database error during a password change:

database-db-1  | 2023-08-13 22:02:05.531 UTC [1462] ERROR:  syntax error at or near "table" at character 9
database-db-1  | 2023-08-13 22:02:05.531 UTC [1462] STATEMENT:
database-db-1  | 	UPDATE table SET
database-db-1  | 	    email = $2,
database-db-1  | 	    password = $3,
database-db-1  | 	    is_admin = $4,
database-db-1  | 	WHERE
database-db-1  | 	    id = $1

I think under the tokio_postgres implementation the UPDATE_USER sql code is wrong.

Localization support?

Hi, thanks for what looks like a cool and ambitious project.

I see there are localization files for en/es/pt but unless I'm mistaken they seem not to be used anywhere?
In any case I can provide a PR for a french translation if that's welcome.

Failed to run sqlite example

I used cargo run --example sqlite since no info about running examples was provided.
The build fails at multiple places.
I hardcoded it to load sqlite feature support but there were other errors.
Can you provide the intended way of running examples, or potentially fix them if that was the problem?

Compilation failing due to SQLX features

Hi,

I am attempting to use rocket_auth within a project already using Sqlx 0.6.1 and getting the following error:

error: one of the features ['runtime-actix-native-tls', 'runtime-async-std-native-tls', 'runtime-tokio-native-tls', 'runtime-actix-rustls', 'runtime-async-std-rustls', 'runtime-tokio-rustls'] must be enabled
  --> /Users/george/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-rt-0.5.13/src/lib.rs:9:1
   |
9  | / compile_error!(
10 | |     "one of the features ['runtime-actix-native-tls', 'runtime-async-std-native-tls', \
11 | |      'runtime-tokio-native-tls', 'runtime-actix-rustls', 'runtime-async-std-rustls', \
12 | |      'runtime-tokio-rustls'] must be enabled"
13 | | );
   | |_^

I was able to fix this error by locally cloning the rocket_auth repository and adding in the following to the SQLX dependency section

[dependencies.sqlx]
version = "0.6.0"
optional = true
features = ["runtime-tokio-rustls"]

This is my dependencies (edited for brevity):

[dependencies]
rocket = {version = "0.5.0-rc.1", features = ["json"]}
rocket_auth = {path = "../rocket_auth", features = ["sqlx-sqlite"]}
serde = {version = "1.0", features = ["derive"]}
serde_json = "1.0"
tokio = {version = "1.17", features = ["full"]}
sqlx = {version = "0.6", features = ["runtime-tokio-rustls", "sqlite"]}

Just wondering if this is some perculiarity in the way my project is set up or is this a new bug?

New release with Users table update fix?

Hello,

I'm trying to create an admin user, but also keep the email and password validation via the Signup form (avoiding to use create_user method directly).
I see there was a fix for the update of the Users table (almost a year ago): 815682e, but this is not yet available if I add the crate version 0.4.0, without the --git flag.

Currently I have to add a normal user via the Signup form, get the user and set its is_admin flag to true and modify the user (but this only works if I add the crate with the --git flag...), basically manually upgrading the user to admin status which feels a bit unnatural.

Would it be possible to publish this fix above as a new crate version, or maybe add a SignupAdmin form which would set is_admin to true by default?

Document Users

Document all Users' fields and methods. Each one should include an example of its use.

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.