Giter Club home page Giter Club logo

axumsession's Introduction

Axum Session

https://crates.io/crates/axum_session Docs

πŸ“‘ Overview

`axum_session` provide's a Session management middleware that stores all session data within a MemoryStore internally. Optionally it can save data to a persistent database for long term storage. Uses Cookie or Header stored UUID's to sync back to the session store.

  • Cookies or Header Store of Generated Session UUID and a Store Boolean.
  • Uses a DatabasePool Trait so you can implement your own Sub Storage Layer.
  • Convenient API for Session no need to mark as Read or Write making Usage Easier.
  • Uses dashmap for internal memory lookup and storage to achieve high throughput.
  • Uses Serdes for Data Serialization so it can store any Serdes supported type's into the Sessions data.
  • Supports Redis, SurrealDB, MongoDB and SQLx optional Databases out of the Box.
  • Supports Memory Only usage. No need to use a persistant database.
  • Supports Cookie and Header Signing for integrity, and authenticity.
  • Supports Database Session Data Encryption for confidentiality, integrity.
  • Supports SessionID renewal for enhanced Security.
  • Optional Fastbloom key storage for reduced Database lookups during new UUID generation. Boosting Bandwidth.
  • Optional Rest Mode that Disables Cookies and uses the Header values instead.
  • uses #![forbid(unsafe_code)] to ensure everything is implemented as safe rust.
  • has an advanced API to allow further control of a session.
  • uses IP address's and user agent to deter spoofing of signed cookies and headers.

🚨 Help

If you need help with this library or have suggestions please go to our Discord Group

πŸ“¦ Install

Axum Session uses tokio. to your cargo include for Axum Session.

# Cargo.toml
[dependencies]
# Postgres + rustls
axum_session = { version = "0.14.0" }

πŸ“± Cargo Feature Flags

Features Description
advanced Enable functions allowing more direct control over the sessions.
rest_mode Disables Cookie Handlering In place of Header only usage for Rest API Requests and Responses.
key-store Enabled the optional key storage. Will increase ram usage based on Fastbloom settings.
Database Crate Persistent Description
axum_session_sqlx Yes Sqlx session store
axum_session_surreal Yes Surreal session store
axum_session_mongo Yes Mongo session store
axum_session_redispool Yes RedisPool session store

πŸ”Ž Example Default Setup

You can find examples within the Repository

use sqlx::{ConnectOptions, postgres::{PgPoolOptions, PgConnectOptions}};
use std::net::SocketAddr;
use axum_session::{Session, SessionPgPool, SessionConfig, SessionStore, SessionLayer};
use axum::{
    Router,
    routing::get,
};
use tokio::net::TcpListener;

#[tokio::main]
async fn main() {

    let poll = connect_to_database().await.unwrap();

    //This Defaults as normal Cookies.
    //To enable Private cookies for integrity, and authenticity please check the next Example.
    let session_config = SessionConfig::default()
        .with_table_name("sessions_table");

    // create SessionStore and initiate the database tables
    let session_store = SessionStore::<SessionPgPool>::new(Some(poll.clone().into()), session_config).await.unwrap();

    // build our application with some routes
    let app = Router::new()
        .route("/greet", get(greet))
        .layer(SessionLayer::new(session_store));

    // run it
    let addr = SocketAddr::from(([0, 0, 0, 0], 8000));

    println!("listening on {}", addr);
    let listener = TcpListener::bind(addr).await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

async fn greet(session: Session<SessionPgPool>) -> String {
    let mut count: usize = session.get("count").unwrap_or(0);

    count += 1;
    session.set("count", count);

    count.to_string()
}

async fn connect_to_database() -> anyhow::Result<sqlx::Pool<sqlx::Postgres>> {
    // ...
    unimplemented!()
}

πŸ”‘ Key Store Details

To enable and use fastbloom key storage for less database lookups. Add the feature "key-store" to the crate’s features. This feature will increase the ram usage server side. but will heavily improve the bandwidth limitations and reduce latency of returns from the server. This is based on how much the filter_expected_elements and filter_false_positive_probability are set too. The higher they are the more ram is used. You will also need to Enable the bloom filter in the config for it to be used. By default, the use_bloom_filters is enabled and these config options exist whither or not the feature is enabled. Please refer to with_filter_expected_elements and with_filter_false_positive_probability within the documents to set the options. Otherwise stick with the default settings which should work in most situations. Just do note these options provide on how many False positives could possibly occur when comparing a UUID to what currently exists, which means it will keep trying till it finds none that match. Higher values decrease the chance of a false positive but increase ram usage.

😎 Session Login and Authentication via axum_session_auth

For user login, login caching and authentication please see axum_session_auth.

axumsession's People

Contributors

89q12 avatar aflac01 avatar apps4uco avatar atila-m-schrieber avatar chrisjefferson avatar cking avatar cold-brewed avatar damccull avatar genusistimelord avatar h-michael avatar hosmercury avatar jkristell avatar mohenjodaro avatar mrxiaozhuox avatar mwcz avatar smessmer avatar tadic-luka avatar ymijorski 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

axumsession's Issues

SessionRedisPool Implementation Improvements

I noticed a couple ways that the SessionRedisPool could be improved:

  1. Using ConnectionManager (https://docs.rs/redis/0.23.0/redis/aio/struct.ConnectionManager.html) so that it is not establishing a new connection for every operation.
  2. Utilize the table_name argument. It would essentially act as a prefix for session ids so that they don't conflict with other keys in the database.

I'm not sure how contributing is generally handled on this project, but I can make the changes and publish a PR if you'd like.

Update internal Hashmap's

Update the internal Hashmaps to use Dashmap instead to increase output and simplify code.
Add capability to support Alternative Hasher FX Hash.

Add Advanced Feature

Add an Advanced Feature that unlocks functions that allow you to manually manage the SessionStores Data.

Add Manual Data Session Mode.

Add a Manual data Session mode to Prevent Creation of SessionData on Page Requests unless Generated by the end user. Useful to prevent Mass memory loads and unloads when a very few of the users are not logging in ETC.

Github CI

Need to figure out how to setup a Github CI that can be used with Axum, sqlx and this library. to be able to have a few tests running.

Expose AxumSessionStore::migrate() from AxumSessionLayer

I may be jumping the gun as you havent released the crate yet and its a minor point ... but....

The only way I saw to migrate the session table is by using

{
  let store=AxumSessionStore::new(pool.clone().into(),session_config.clone());
   store.migrate().await.expect("Error creating session table in database");
} //inside a scope so that store gets dropped after use

However the session store is again created by AxumSessionLayer::new

I think it would be a good idea to do one of the following:

  • add a public method to obtain the store from the AxumSessionLayer
  • or allow a created store to be passed to AxumSessionLayer
  • or alternatively provide a migrate method on AxumSessionLayer that calls store.migrate()

Thanks

error when using main branch

   Compiling axum_session v0.5.0 (https://github.com/AscendingCreations/AxumSession.git#4c073bd5)
error[E0659]: `redis_pool` is ambiguous
  --> /home/sachnr/.cargo/git/checkouts/axumsession-4dbf4d2adab911cf/4c073bd/src/databases.rs:19:9
   |
19 | pub use redis_pool::*;
   |         ^^^^^^^^^^ ambiguous name
   |
   = note: ambiguous because of multiple potential import sources
   = note: `redis_pool` could refer to a crate passed with `--extern`
   = help: use `::redis_pool` to refer to this crate unambiguously
note: `redis_pool` could also refer to the module defined here
  --> /home/sachnr/.cargo/git/checkouts/axumsession-4dbf4d2adab911cf/4c073bd/src/databases.rs:17:1
   |
17 | mod redis_pool;
   | ^^^^^^^^^^^^^^^
   = help: use `self::redis_pool` to refer to this module unambiguously

For more information about this error, try `rustc --explain E0659`.
error: could not compile `axum_session` (lib) due to previous error

support rest mode and cookie mode at the same time

I have a web interface and would like to add a cli tool too. Currently the user registers or signs in and gets a cookie. I would like to add a page create api token which creates a permanent until revoked session id and support using rest mode with these tokens. Is this a common use case or is it already possible?

Documentation update needed

The correct documentation for creating a new session store says you need this:

let session_store = SessionStore::<SessionNullPool>::new(None, config).await.unwrap();
(https://docs.rs/axum_session/latest/axum_session/struct.SessionStore.html)

But under the main page, it omits the await.unwrap() in the examples:

let session_store = SessionStore::<SessionPgPool>::new(None, session_config);
(https://docs.rs/axum_session/latest/axum_session/)

This omission gives you a cryptic error message when you try to initialize the session_store.

Can I make it compiled with latest axum version on github?

I've the following code:

use axum::{routing::get, Router};
use axum_session::{Session, SessionConfig, SessionLayer, SessionNullPool, SessionStore};

#[tokio::main]
async fn main() {
    let session_config = SessionConfig::default().with_table_name("sessions_table");

    let session_store = SessionStore::<SessionNullPool>::new(None, session_config)
        .await
        .unwrap();

    // build our application with some routes
    let app = Router::new()
        .route("/greet", get(greet))
        .layer(SessionLayer::new(session_store));

    // run it
    let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:3000"))
        .await
        .unwrap();
    axum::serve(listener, app.into_make_service())
        .await
        .unwrap()
}

async fn greet(session: Session<SessionNullPool>) -> String {
    let mut count: usize = session.get("count").unwrap_or(0);

    count += 1;
    session.set("count", count);

    count.to_string()
}

And with the following Cargo.toml:

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

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
axum = { git = "https://github.com/tokio-rs/axum.git", features = ["tokio"] }
axum_session = { version = "0.3" }
tokio = { version = "1.28", features = ["macros", "net"]}

But finally it's failed to compile, I get the following error message:

error[E0277]: the trait bound `fn(Session<SessionNullPool>) -> impl Future<Output = String> {greet}: Handler<_, _>` is not satisfied

Update to SQLx 0.6

We will update to SQLx 0.6 in a few days. this is just a placeholder reminder for that.

Signing?

Hi there, curious if this crate will support signing? Without it, the cookie can be tampered with. Tide for example provides this capability.

GDPR Additions

  1. Make GDPR Optional. Useful for internal websites where workers already agreed to gain access to them.
  2. Add GDPR Cookie name for Acceptance.
  3. Add lifetime for Acceptance Cookie.
  4. Add Boolean to AxumSessionData for Accepted.
  5. If by_pass_gdpr is False then do not set session UID cookie till accepted and unload inner session if not accepted yet.

@tgolsson what do you think?

Change name of Github repo to axum_session

Given there is another very similar crate call axum-sessions, I found it confusing when I was first looking at these crates. I suggest renaming the Gihtub repo to axum_session which will make it much clearer which crate this repo corresponds to.

parse Headers for API services

Add the ability to parse Headers from a request instead of a cookie's this would make it more compatible with an API Service.

cookie expiration question

I am seeing weird expired timestamp:

axum_session

You can see the date header, it's 2023, yet the expiration date is 1 year behind.

creating the layer:

  let session_config = SessionConfig::default()
    .with_key(key_master)
    .with_database_key(key_db)
    .with_security_mode(SecurityMode::PerSession)
    .with_cookie_name("session")
    .with_cookie_path("/")
    .with_cookie_same_site(axum_session::SameSite::Strict)
    .with_http_only(true)
    .with_mode(SessionMode::Storable);
  let session_store =
    SessionStore::<SessionPgPool>::new(Some(SessionPgPool::from(db.clone())), session_config)
      .await
      .unwrap();
  session_store
    .initiate()
    .await
    .context("session store seed data")?;

  Ok(SessionLayer::new(session_store))

delete_by_expiry differs for databases

Hello,
I was updating my pool to newer axum_session version
https://github.com/alexichepura/lapa/blob/main/admin/src/axum_session_prisma.rs

And noticed delete_by_expiry differs for databases.

mysql uses greater less than (i think this is correct) (UPDATED LINE)
https://github.com/AscendingCreations/AxumSessions/blob/main/src/databases/mysql.rs#L46

postgres and sqlite uses less greater than (i think this is bug) (UPDATED LINE)
https://github.com/AscendingCreations/AxumSessions/blob/main/src/databases/postgres.rs#L46
https://github.com/AscendingCreations/AxumSessions/blob/main/src/databases/sqlite.rs#L46

These bugs are not leading to issue yet because real deletion goes later with correct sign.
But anyway it's confusing.

And maybe can be changed to deletion of loaded already ids: ... WHERE id IN (value1, value2, ...);

Consider allowing cookie creation to be configured, and to be deferred until user accepts

Session cookies are complicated that's why I wanted to use this crate :)

Some best practices:

Taken from the Microsoft page (Fair Use .. hope MS agrees)

  • Change the default session ID name. In ASP.NET, the default name is ASP.NET_SessionId. This immediately gives away that the application is ASP.NET and that that cookie contains the session ID value
    Make the cookie name configurable

  • Make sure the length of the session ID is long enough to prevent brute force attacks. Recommended length is 128 bits
    checked

  • Make sure to create the session ID in a completely random way. This ensures that attackers can’t guess the session ID by using predictability analysis checked

  • Ensure that the session ID does not contain any additional sensitive data. The data should be a random string of characters with no meaning
    checked

  • HTTPS should be used for all session based applications handling sensitive data that depends on the user - but it could be logged server side

  • Session cookies should be created with the Secure and HttpOnly attributes note secure wont work if not using https

  • Prevent concurrent sessions where possible optional and may be complex to implement use ip address / UserAgent?

  • Destroy sessions upon timeout, logoff, browser close or log-in from a separate location optionally store ip address and destroy session if it changes

  • Do not store any critical information in cookies. For example, do not store a user’s password in a cookie. As a rule, do not keep anything in a cookie that can compromise your application. Instead, keep a reference in the cookie to a location on the server where the data is checked

  • Set expiration dates on cookies to the shortest practical time. Avoid using permanent cookies allow to be configured / or left as a session cookie (by not setting expiration)

  • Consider encrypting information in cookies not useful in this case

Current code in src/manager.rs

hardcodes the session expiry duration:

sess.expires = Utc::now() + Duration::hours(6);

sets the cookie to expire in 20 years:

cookie.make_permanent();

Also in Europe legally you should not set a cookie until the user agrees.

https://www.cookielaw.org/your-cookie-law-rights/

So the cookie should only be created when the session is written to for the first time. Granted this could be handled by configuring layers and routers but at least an example would be good. However, seeing as most websites will get used in Europe as well it would be good to have this as default policy, i.e. when the user agrees to cookies then the session and cookie are created,.

Maybe it would be a good idea to allow all of the following to be configured by a configuration struct:

let cookie = Cookie::build("configuredname", "value")
    .domain("configured domain")
    .same_site(SameSite::Strict)
    .max_age(Duration::minutes(30)) //optional if not set expire on browser close
    .path("/")
    .secure(true)
    .http_only(true)
    .finish();

I could work on a PR if you are interested.

Session not saved sometimes

I'm using set() with a redirect right after and in some conditions, the change is not saved to the database.

session.set(SESSION_KEY_USER, user_id).await;
return Ok(Redirect::to("/"));

Any ideas?

The demo in the README gives a HTTP 401 Unauthorized error

I created a bare-bones repo jmoore34/axum-session-test to test the non-persistent example given in the README. When starting the server and navigating to the route 127.0.0.1:3000/greet/jon, I get a 401 Unauthorized error in the browser.

image

(Note: I initially noticed this error in a larger project that used this library, so I created this bare-bones repo to try to help isolate the issue.)

Add Option to Generate Keys per SessionID.

This is to increase Security to the max by enforcing a server side managed Key per Session Cookie that gets a keyID sent to the Browser to allow decryption of the Other SessionID and Storage Cookies. This allows use to do Key cycling to prevent more types of Attacks on the system.

Needed for this to work.

  1. Database Needs to support Saving KeyID separate from SessionID Storage.
  2. KeyID needs to be a UUID too and can be encrypted to increase reliability.
  3. Key Database side needs to be Encrypted for long term Storage and Security.
  4. Key is only accessible to the Server Side and is loaded via the KeyID.
  5. KeyID needs the capability to be Renewed like SessionID.
  6. Key needs the ability to be Renewed.
  7. System need to not break the current API config enabled.

Reduce Session size in database.

This is to Reduce the Needed stored size in the database to the minimal of what is needed.

Mostly

Data HashMap and LongTerm bool.

the rest are not needed to be stored in the database.

Reduce Database Query lookups when generating UUID's

We would like to reduce Database lookups by storing all the UUID upon load and advancement of the Sessions into some sort of Data structure.

Was thinking either

HashSet

  • Downside can take lots of Ram if lots of UUID Exist.
  • No False Positives or Negatives.
  • If a Collision happens becomes whatever the speed of a String to String comparison would be per Amount of Collisions there are.

Counting Bloom Filter

  • Uses much less memory as it mathematically stores it as bitsets.
  • Can have lots of False Positives the more data there is if the Storage is to small.
  • False Positives just means a new UUID has to be generated until it comes out as a Negative or None Existent in the data structure.
  • No False Negatives
  • No collisions checks Either Exists or Doesnt.

Exclude session creation for certain routes

I have certain routes that do not need to be linked to a session (one off webhooks), i would like to exclude them to not wastefully add rows to my database. How would I do this, if possible?

Surrealdb Any not clone-able

This issue is being stored here as we are unable to use surrealdb::engine::any::Any within our pool for Sessions as Any needs to have Clone derived.

Possibly suspicious activity randomly

Hi there,

I experience the following warning everye once in a while:
axum_session::sec::signed: possibly suspicious activity: Verification failed for Cookie. err=value did not verify

The result is that the session gets discarded and the user has to login again. I sometimes see this locally while developing, but more frequent on the deployed application on a server.

Any idea what might cause this behavior?

Notes:
I use the following dependencies

sqlx = { version = "0.7", features = [
  "runtime-tokio",
  "tls-native-tls",
  "any",
  "postgres",
  "chrono",
] }
axum_session = { version = "0.12.4", default-features = false, features = [
  "postgres-native",
  "key-store",
] }

Is it possible to have the async runtime and tls crate to be "features" in Cargo.toml

Hi, hope you dont mind me submitting an issue on a pre release crate...

I ran into the problem that I was using native-tls in my project and encountered the problem that "runtime-tokio-rustls" is currently hard coded in AxumSessions Cargo.toml

In my case I could solve it by changing to rustls in my project as the other crates I am using do not hard code the async runtime + tls crate. However, it is not always the case with all crates.

Would it be possible to change this to be a feature like in the sqlx crate.

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.