feat: add rights check for endpoints#48
Merged
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces endpoint-level security primitives for the library by adding JWT authentication middleware, a DB-backed access-check middleware, and the supporting test/setup changes needed to exercise them.
Changes:
- Add Actix security middleware for JWT authentication and
check_access-based authorization. - Expose new security APIs publicly and adjust shared app state / JWT helpers to support the middleware flow.
- Rework test fixtures to use dynamically discovered IDs and add middleware integration tests.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
tests/queries_tests.rs |
Updates query tests to use seeded dynamic IDs. |
tests/middlewares_tests.rs |
Adds integration tests for JWT and access middlewares. |
src/test_setup/queries_setup.rs |
Reworks shared DB seeding and stores fixture IDs in OnceCells. |
src/security/right_middleware.rs |
Adds authorization middleware calling check_access. |
src/security/mod.rs |
Re-exports the new security components. |
src/security/auth_user.rs |
Adds an AuthenticatedUser extractor. |
src/security/auth_middleware.rs |
Adds JWT validation middleware for Actix requests. |
src/pool/redis/handle_get.rs |
Handles missing Redis pool in the Redis endpoint. |
src/pool/mod.rs |
Makes app pools optional and changes pool access helpers. |
src/lib.rs |
Exports the security module publicly. |
src/jwt_manager/get_jwt_timeout.rs |
Changes JWT timeout helper error handling. |
src/jwt_manager/get_jwt_secret.rs |
Changes JWT secret helper error handling. |
src/jwt_manager/generate_jwt.rs |
Simplifies JWT generation error propagation. |
Cargo.toml |
Adds middleware/runtime dependencies. |
Cargo.lock |
Updates the resolved dependency set. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if path == "/" | ||
| || path.starts_with("/swagger-ui") | ||
| || path.starts_with("/api-docs") | ||
| || path.contains("/auth") |
Comment on lines
+117
to
+123
| match check_jwt_validity(&jwt, pool).await { | ||
| Ok(_) => { | ||
| // ON AJOUTE L'UTILISATEUR DANS LES EXTENSIONS | ||
| // Supposons que claims.sub contient l'ID | ||
| req.extensions_mut().insert(AuthenticatedUser { | ||
| id: get_user_id_from_jwt(&jwt).unwrap().parse().unwrap_or(0), | ||
| }); |
Comment on lines
+40
to
+46
| if let Some(val) = req.match_info().get(param_name) { | ||
| instance_id = val.parse::<i32>().ok(); | ||
| if instance_id.is_none() { | ||
| return Err(actix_web::error::ErrorBadRequest( | ||
| "Invalid ID format in URL", | ||
| )); | ||
| } |
Comment on lines
27
to
+34
| Self { | ||
| redis_pool, | ||
| db_pool, | ||
| redis_pool: match redis_pool { | ||
| Ok(pool) => Some(pool), | ||
| Err(_) => None, | ||
| }, | ||
| db_pool: match db_pool { | ||
| Ok(pool) => Some(pool), | ||
| Err(_) => None, |
Comment on lines
+112
to
+115
| setup(); | ||
| env::set_var("JWT_TIMEOUT", "0"); | ||
| let token = generate_jwt("2").unwrap(); | ||
| std::thread::sleep(std::time::Duration::from_secs(2)); |
|
|
||
| let view = IsSessionTokenValidQueryView::new( | ||
| mairie360_api_lib::test_setup::queries_setup::ALICE_ID, | ||
| *mairie360_api_lib::test_setup::queries_setup::BOB_ID |
Comment on lines
+262
to
+266
| let alice_id = *mairie360_api_lib::test_setup::queries_setup::ALICE_ID | ||
| .get() | ||
| .unwrap(); | ||
|
|
||
| let view = HasAccessQueryView::new(alice_id as u64, "groups", "read", 50); |
Comment on lines
+7
to
+8
| redis_pool: Option<Pool>, | ||
| pub db_pool: Option<PgPool>, |
Comment on lines
+5
to
+12
| pub fn get_jwt_timeout() -> Result<usize, jsonwebtoken::errors::ErrorKind> { | ||
| match get_env_var("JWT_TIMEOUT") { | ||
| Some(secret) => secret | ||
| .parse::<usize>() | ||
| .map_err(|_| "JWT_TIMEOUT is not a valid usize".to_string()), | ||
| None => Err("JWT_TIMEOUT environment variable not set".to_string()), | ||
| Some(secret) => { | ||
| let secret = secret.parse::<usize>().map_err(|_| InvalidKeyFormat)?; | ||
| Ok(secret) | ||
| } | ||
| None => Err(jsonwebtoken::errors::ErrorKind::MissingRequiredClaim( | ||
| "JWT_TIMEOUT environment variable not set".to_string(), |
Comment on lines
+3
to
+8
| pub fn get_jwt_secret() -> Result<Vec<u8>, jsonwebtoken::errors::ErrorKind> { | ||
| match get_env_var("JWT_SECRET") { | ||
| Some(secret) => Ok(secret.into_bytes()), | ||
| None => Err("JWT_SECRET environment variable not set".to_string()), | ||
| None => Err(jsonwebtoken::errors::ErrorKind::MissingRequiredClaim( | ||
| "JWT_SECRET environment variable not set".to_string(), | ||
| )), |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.