This repository was archived by the owner on Nov 23, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Merged
Dev #18
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
38c800c
Update CORS configuration for enhanced security
mehara-rothila 8a7f5cd
Add username lookup endpoint to user controller
mehara-rothila e46bec4
Improve user authentication flow
mehara-rothila 697d99e
Merge pull request #16 from TechTorque-2025/MRR-Integration
RandithaK 9c90c17
Update CORS filter and application properties to clarify CORS handlin…
RandithaK 97fca6b
chore: commit all changes (automated)
RandithaK dfbcf7f
Enhance login error handling for disabled accounts with specific mess…
RandithaK 5b84c00
feat: Add role-based access control for user role management and upda…
Akith-002 aa67391
Merge pull request #17 from TechTorque-2025/randitha-superbranch
RandithaK 76340ac
Merge branch 'main' into dev
RandithaK File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| #!/bin/bash | ||
|
|
||
| echo "==========================================" | ||
| echo "🔧 Complete Fix for User Roles Issue" | ||
| echo "==========================================" | ||
| echo "" | ||
|
|
||
| # Database connection details (adjust if needed) | ||
| DB_HOST="${DB_HOST:-localhost}" | ||
| DB_PORT="${DB_PORT:-5432}" | ||
| DB_NAME="${DB_NAME:-techtorque}" | ||
| DB_USER="${DB_USER:-techtorque}" | ||
| DB_PASS="${DB_PASS:-techtorque123}" | ||
|
|
||
| echo "Step 1: Fixing database - Assigning roles to existing users" | ||
| echo "Database: $DB_NAME @ $DB_HOST:$DB_PORT" | ||
| echo "" | ||
|
|
||
| # SQL to fix existing data | ||
| SQL=$(cat <<'EOSQL' | ||
| -- Display current state | ||
| SELECT 'BEFORE FIX:' as status; | ||
| SELECT u.username, COUNT(ur.role_id) as role_count | ||
| FROM users u | ||
| LEFT JOIN user_roles ur ON u.id = ur.user_id | ||
| GROUP BY u.id, u.username | ||
| ORDER BY u.id; | ||
|
|
||
| -- Assign roles to all users based on their username | ||
| -- Assign SUPER_ADMIN role | ||
| INSERT INTO user_roles (user_id, role_id) | ||
| SELECT u.id, r.id | ||
| FROM users u | ||
| CROSS JOIN roles r | ||
| WHERE u.username = 'superadmin' | ||
| AND r.name = 'SUPER_ADMIN' | ||
| AND NOT EXISTS ( | ||
| SELECT 1 FROM user_roles ur | ||
| WHERE ur.user_id = u.id AND ur.role_id = r.id | ||
| ); | ||
|
|
||
| -- Assign ADMIN role | ||
| INSERT INTO user_roles (user_id, role_id) | ||
| SELECT u.id, r.id | ||
| FROM users u | ||
| CROSS JOIN roles r | ||
| WHERE u.username = 'admin' | ||
| AND r.name = 'ADMIN' | ||
| AND NOT EXISTS ( | ||
| SELECT 1 FROM user_roles ur | ||
| WHERE ur.user_id = u.id AND ur.role_id = r.id | ||
| ); | ||
|
|
||
| -- Assign EMPLOYEE role | ||
| INSERT INTO user_roles (user_id, role_id) | ||
| SELECT u.id, r.id | ||
| FROM users u | ||
| CROSS JOIN roles r | ||
| WHERE u.username = 'employee' | ||
| AND r.name = 'EMPLOYEE' | ||
| AND NOT EXISTS ( | ||
| SELECT 1 FROM user_roles ur | ||
| WHERE ur.user_id = u.id AND ur.role_id = r.id | ||
| ); | ||
|
|
||
| -- Assign CUSTOMER role to customer and test users | ||
| INSERT INTO user_roles (user_id, role_id) | ||
| SELECT u.id, r.id | ||
| FROM users u | ||
| CROSS JOIN roles r | ||
| WHERE u.username IN ('customer', 'user', 'testuser', 'demo', 'test') | ||
| AND r.name = 'CUSTOMER' | ||
| AND NOT EXISTS ( | ||
| SELECT 1 FROM user_roles ur | ||
| WHERE ur.user_id = u.id AND ur.role_id = r.id | ||
| ); | ||
|
|
||
| -- Display fixed state | ||
| SELECT 'AFTER FIX:' as status; | ||
| SELECT u.username, u.email, r.name as role_name | ||
| FROM users u | ||
| INNER JOIN user_roles ur ON u.id = ur.user_id | ||
| INNER JOIN roles r ON ur.role_id = r.id | ||
| ORDER BY u.id, r.name; | ||
|
|
||
| -- Summary | ||
| SELECT 'SUMMARY:' as status; | ||
| SELECT u.username, | ||
| ARRAY_AGG(r.name ORDER BY r.name) as roles | ||
| FROM users u | ||
| LEFT JOIN user_roles ur ON u.id = ur.user_id | ||
| LEFT JOIN roles r ON ur.role_id = r.id | ||
| GROUP BY u.id, u.username | ||
| ORDER BY u.id; | ||
| EOSQL | ||
| ) | ||
|
|
||
| # Execute SQL | ||
| echo "Executing SQL fixes..." | ||
| PGPASSWORD="$DB_PASS" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" << EOF | ||
| $SQL | ||
| EOF | ||
|
|
||
| echo "" | ||
| echo "==========================================" | ||
| echo "Step 2: Restart Authentication Service" | ||
| echo "==========================================" | ||
| echo "" | ||
| echo "The User entity has been fixed with cascade settings." | ||
| echo "You need to rebuild and restart the service:" | ||
| echo "" | ||
| echo " cd Authentication/auth-service" | ||
| echo " mvn clean install -DskipTests" | ||
| echo " mvn spring-boot:run" | ||
| echo "" | ||
| echo "Or if running in Docker:" | ||
| echo " docker-compose restart auth-service" | ||
| echo "" | ||
| echo "==========================================" | ||
| echo "✅ Fix Complete!" | ||
| echo "==========================================" | ||
| echo "" | ||
| echo "What was fixed:" | ||
| echo "1. ✅ Added cascade settings to User entity @ManyToMany relationship" | ||
| echo "2. ✅ Assigned roles to all existing users in database" | ||
| echo "" | ||
| echo "Test the fix:" | ||
| echo "1. Login again:" | ||
| echo ' curl -X POST http://localhost:8081/login \' | ||
| echo ' -H "Content-Type: application/json" \' | ||
| echo ' -d '"'"'{"username":"customer","password":"cust123"}'"'" | ||
| echo "" | ||
| echo "2. Decode JWT at https://jwt.io - should show roles" | ||
| echo "" | ||
| echo "3. Test /users/me with the new token" | ||
| echo "" | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,239 @@ | ||
| # 🔧 Login Issue Fix - Empty Roles in JWT Token | ||
|
|
||
| ## 🎯 Problem Summary | ||
|
|
||
| **Symptom**: User can login successfully but gets `403 Forbidden` when accessing `/api/v1/users/me` | ||
|
|
||
| **Root Cause**: The JWT token contains `"roles":[]` (empty array) because the user in the database has no roles assigned in the `user_roles` table. | ||
|
|
||
| **Error in logs**: | ||
| ``` | ||
| Access denied: Access Denied | ||
| AuthorizationDeniedException: Access Denied | ||
| ``` | ||
|
|
||
| ## 🔍 Diagnosis | ||
|
|
||
| Your JWT token shows: | ||
| ```json | ||
| { | ||
| "roles": [], // <-- EMPTY! This is the problem | ||
| "sub": "customer", | ||
| "iat": 1762805825, | ||
| "exp": 1762892225 | ||
| } | ||
| ``` | ||
|
|
||
| The endpoint requires: | ||
| ```java | ||
| @PreAuthorize("hasRole('CUSTOMER') or hasRole('EMPLOYEE') or hasRole('ADMIN') or hasRole('SUPER_ADMIN')") | ||
| ``` | ||
|
|
||
| Since the roles array is empty, Spring Security denies access. | ||
|
|
||
| ## ✅ Solution Options | ||
|
|
||
| ### Option 1: Fix via SQL (Immediate Fix) | ||
|
|
||
| Connect to your database and run: | ||
|
|
||
| ```bash | ||
| # Connect to MySQL/MariaDB | ||
| mysql -u root -p techtorque | ||
|
|
||
| # Or connect to PostgreSQL | ||
| # psql -U postgres -d techtorque | ||
| ``` | ||
|
|
||
| Then execute: | ||
| ```sql | ||
| -- Check current user roles | ||
| SELECT u.username, u.email, r.name as role_name | ||
| FROM users u | ||
| LEFT JOIN user_roles ur ON u.id = ur.user_id | ||
| LEFT JOIN roles r ON ur.role_id = r.id | ||
| WHERE u.username = 'customer'; | ||
|
|
||
| -- Assign CUSTOMER role if missing | ||
| INSERT INTO user_roles (user_id, role_id) | ||
| SELECT u.id, r.id | ||
| FROM users u, roles r | ||
| WHERE u.username = 'customer' | ||
| AND r.name = 'CUSTOMER' | ||
| AND NOT EXISTS ( | ||
| SELECT 1 FROM user_roles ur | ||
| WHERE ur.user_id = u.id AND ur.role_id = r.id | ||
| ); | ||
|
|
||
| -- Verify fix | ||
| SELECT u.username, r.name as role_name | ||
| FROM users u | ||
| INNER JOIN user_roles ur ON u.id = ur.user_id | ||
| INNER JOIN roles r ON ur.role_id = r.id | ||
| WHERE u.username = 'customer'; | ||
| ``` | ||
|
|
||
| **Quick script included**: Run `Authentication/fix_user_roles.sql` | ||
|
|
||
| ### Option 2: Delete and Recreate Users (Clean Slate) | ||
|
|
||
| If you want to start fresh: | ||
|
|
||
| ```sql | ||
| -- Delete all users (roles and other tables will be preserved) | ||
| DELETE FROM user_roles; | ||
| DELETE FROM users; | ||
|
|
||
| -- Restart your Authentication service to trigger DataSeeder | ||
| # The DataSeeder will recreate all default users with proper roles | ||
| ``` | ||
|
|
||
| Then restart the Authentication service: | ||
| ```bash | ||
| cd Authentication/auth-service | ||
| mvn spring-boot:run | ||
| ``` | ||
|
|
||
| ### Option 3: Use Admin Endpoint to Assign Role | ||
|
|
||
| If you have access to an admin account with a valid token: | ||
|
|
||
| ```bash | ||
| ADMIN_TOKEN="your-admin-jwt-token" | ||
|
|
||
| curl -X POST "http://localhost:8081/users/customer/roles" \ | ||
| -H "Authorization: Bearer $ADMIN_TOKEN" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "role": "CUSTOMER", | ||
| "action": "ASSIGN" | ||
| }' | ||
| ``` | ||
|
|
||
| ## 🧪 Verify the Fix | ||
|
|
||
| After applying the fix: | ||
|
|
||
| ### 1. Login Again | ||
| ```bash | ||
| curl -X POST http://localhost:8081/login \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "username": "customer", | ||
| "password": "cust123" | ||
| }' | jq | ||
| ``` | ||
|
|
||
| ### 2. Check JWT Token | ||
| Decode the token at https://jwt.io and verify it now shows: | ||
| ```json | ||
| { | ||
| "roles": ["CUSTOMER"], // <-- Should have role now! | ||
| "sub": "customer", | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| ### 3. Test /users/me Endpoint | ||
| ```bash | ||
| TOKEN="your-new-jwt-token" | ||
|
|
||
| curl -X GET http://localhost:8081/users/me \ | ||
| -H "Authorization: Bearer $TOKEN" | jq | ||
| ``` | ||
|
|
||
| **Expected**: Should return `200 OK` with user profile | ||
|
|
||
| ### 4. Test via API Gateway | ||
| ```bash | ||
| curl -X GET http://localhost:8080/api/v1/users/me \ | ||
| -H "Authorization: Bearer $TOKEN" | jq | ||
| ``` | ||
|
|
||
| ## 🔧 Prevention - Ensure Data Seeder Works | ||
|
|
||
| Check your `application.properties` or `application.yml`: | ||
|
|
||
| ```properties | ||
| # Make sure dev profile is active for development | ||
| spring.profiles.active=dev | ||
|
|
||
| # Or set environment variable | ||
| # SPRING_PROFILES_ACTIVE=dev | ||
| ``` | ||
|
|
||
| The `DataSeeder` only creates test users in `dev` profile. Make sure it's active: | ||
|
|
||
| ```bash | ||
| # Check if seeder ran on startup | ||
| # Look for these logs when starting the service: | ||
| # "Starting data seeding..." | ||
| # "Created role: CUSTOMER" | ||
| # "Created user: customer with role CUSTOMER" | ||
| # "Data seeding completed successfully!" | ||
| ``` | ||
|
|
||
| ## 📊 Database Schema Reference | ||
|
|
||
| Correct structure for user-role assignment: | ||
|
|
||
| ``` | ||
| users table: | ||
| +----+----------+-------------------+ | ||
| | id | username | email | | ||
| +----+----------+-------------------+ | ||
| | 1 | customer | customer@... | | ||
| +----+----------+-------------------+ | ||
|
|
||
| roles table: | ||
| +----+----------+ | ||
| | id | name | | ||
| +----+----------+ | ||
| | 1 | CUSTOMER | | ||
| +----+----------+ | ||
|
|
||
| user_roles table (join table): | ||
| +---------+---------+ | ||
| | user_id | role_id | | ||
| +---------+---------+ | ||
| | 1 | 1 | <-- This row MUST exist! | ||
| +---------+---------+ | ||
| ``` | ||
|
|
||
| ## 🚨 Common Causes | ||
|
|
||
| 1. **DataSeeder didn't run** - Not in dev profile | ||
| 2. **Database was reset** - Roles exist but user_roles table is empty | ||
| 3. **Manual user creation** - User created without assigning roles | ||
| 4. **Transaction rollback** - Role assignment failed during user creation | ||
|
|
||
| ## 📞 Still Having Issues? | ||
|
|
||
| Check Authentication service logs for: | ||
| ``` | ||
| Hibernate: select r1_0.user_id ... from user_roles r1_0 ... where r1_0.user_id=? | ||
| ``` | ||
|
|
||
| If this query returns 0 rows, the user has no roles assigned. | ||
|
|
||
| Enable debug logging in `application.properties`: | ||
| ```properties | ||
| logging.level.com.techtorque.auth_service=DEBUG | ||
| logging.level.org.hibernate.SQL=DEBUG | ||
| logging.level.org.springframework.security=DEBUG | ||
| ``` | ||
|
|
||
| ## ✅ Summary Checklist | ||
|
|
||
| - [ ] User exists in database | ||
| - [ ] Roles exist in database (CUSTOMER, EMPLOYEE, ADMIN, SUPER_ADMIN) | ||
| - [ ] User-role mapping exists in `user_roles` table | ||
| - [ ] JWT token contains roles array with at least one role | ||
| - [ ] Can access `/users/me` endpoint with 200 response | ||
| - [ ] DataSeeder ran successfully on service startup | ||
|
|
||
| --- | ||
|
|
||
| **Created**: 2025-11-11 | ||
| **Issue**: Empty roles in JWT causing 403 Forbidden on authenticated endpoints | ||
| **Resolution**: Ensure user has roles assigned in user_roles table |
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The script uses PostgreSQL-specific syntax (
ARRAY_AGG, line 89) but the codebase may support MySQL/MariaDB (referenced in comments at line 41-42).ARRAY_AGGdoesn't exist in MySQL; useGROUP_CONCATinstead for MySQL compatibility, or detect the database type and use conditional SQL.