Fix user delete flow 11
This commit is contained in:
@@ -199,7 +199,8 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
|||||||
"user_id": payload["user_id"],
|
"user_id": payload["user_id"],
|
||||||
"email": payload["email"],
|
"email": payload["email"],
|
||||||
"exp": payload["exp"],
|
"exp": payload["exp"],
|
||||||
"valid": True
|
"valid": True,
|
||||||
|
"role": payload.get("role", "user"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload.get("service"):
|
if payload.get("service"):
|
||||||
|
|||||||
@@ -28,13 +28,16 @@ from shared.auth.decorators import (
|
|||||||
logger = structlog.get_logger()
|
logger = structlog.get_logger()
|
||||||
router = APIRouter(tags=["users"])
|
router = APIRouter(tags=["users"])
|
||||||
|
|
||||||
|
|
||||||
@router.get("/me", response_model=UserResponse)
|
@router.get("/me", response_model=UserResponse)
|
||||||
async def get_current_user_info(
|
async def get_current_user_info(
|
||||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||||
db: AsyncSession = Depends(get_db)
|
db: AsyncSession = Depends(get_db)
|
||||||
):
|
):
|
||||||
"""Get current user information"""
|
"""Get current user information - FIXED VERSION"""
|
||||||
try:
|
try:
|
||||||
|
logger.debug(f"Getting user info for: {current_user}")
|
||||||
|
|
||||||
# Handle both User object (direct auth) and dict (from gateway headers)
|
# Handle both User object (direct auth) and dict (from gateway headers)
|
||||||
if isinstance(current_user, dict):
|
if isinstance(current_user, dict):
|
||||||
# Coming from gateway headers - need to fetch user from DB
|
# Coming from gateway headers - need to fetch user from DB
|
||||||
@@ -45,19 +48,12 @@ async def get_current_user_info(
|
|||||||
detail="Invalid user context"
|
detail="Invalid user context"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Fetch full user from database
|
# ✅ FIX: Fetch full user from database to get the real role
|
||||||
from sqlalchemy import select
|
user = await UserService.get_user_by_id(user_id, db)
|
||||||
from app.models.users import User
|
|
||||||
|
|
||||||
result = await db.execute(select(User).where(User.id == user_id))
|
logger.debug(f"Fetched user from DB - Role: {user.role}, Email: {user.email}")
|
||||||
user = result.scalar_one_or_none()
|
|
||||||
|
|
||||||
if not user:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
|
||||||
detail="User not found"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
# ✅ FIX: Return role from database, not from JWT headers
|
||||||
return UserResponse(
|
return UserResponse(
|
||||||
id=str(user.id),
|
id=str(user.id),
|
||||||
email=user.email,
|
email=user.email,
|
||||||
@@ -65,13 +61,16 @@ async def get_current_user_info(
|
|||||||
is_active=user.is_active,
|
is_active=user.is_active,
|
||||||
is_verified=user.is_verified,
|
is_verified=user.is_verified,
|
||||||
phone=user.phone,
|
phone=user.phone,
|
||||||
language=user.language,
|
language=user.language or "es",
|
||||||
timezone=user.timezone,
|
timezone=user.timezone or "Europe/Madrid",
|
||||||
created_at=user.created_at,
|
created_at=user.created_at,
|
||||||
last_login=user.last_login
|
last_login=user.last_login,
|
||||||
|
role=user.role, # ✅ CRITICAL: Use role from database, not headers
|
||||||
|
tenant_id=current_user.get("tenant_id")
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Direct User object (when called directly)
|
# Direct User object (shouldn't happen in microservice architecture)
|
||||||
|
logger.debug(f"Direct user object received - Role: {current_user.role}")
|
||||||
return UserResponse(
|
return UserResponse(
|
||||||
id=str(current_user.id),
|
id=str(current_user.id),
|
||||||
email=current_user.email,
|
email=current_user.email,
|
||||||
@@ -79,13 +78,18 @@ async def get_current_user_info(
|
|||||||
is_active=current_user.is_active,
|
is_active=current_user.is_active,
|
||||||
is_verified=current_user.is_verified,
|
is_verified=current_user.is_verified,
|
||||||
phone=current_user.phone,
|
phone=current_user.phone,
|
||||||
language=current_user.language,
|
language=current_user.language or "es",
|
||||||
timezone=current_user.timezone,
|
timezone=current_user.timezone or "Europe/Madrid",
|
||||||
created_at=current_user.created_at,
|
created_at=current_user.created_at,
|
||||||
last_login=current_user.last_login
|
last_login=current_user.last_login,
|
||||||
|
role=current_user.role, # ✅ Use role from database
|
||||||
|
tenant_id=None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Get current user error: {e}")
|
logger.error(f"Get user info error: {e}")
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
detail="Failed to get user information"
|
detail="Failed to get user information"
|
||||||
@@ -99,7 +103,8 @@ async def update_current_user(
|
|||||||
):
|
):
|
||||||
"""Update current user information"""
|
"""Update current user information"""
|
||||||
try:
|
try:
|
||||||
updated_user = await UserService.update_user(current_user.id, user_update, db)
|
user_id = current_user.get("user_id") if isinstance(current_user, dict) else current_user.id
|
||||||
|
updated_user = await UserService.update_user(user_id, user_update, db)
|
||||||
return UserResponse(
|
return UserResponse(
|
||||||
id=str(updated_user.id),
|
id=str(updated_user.id),
|
||||||
email=updated_user.email,
|
email=updated_user.email,
|
||||||
@@ -110,7 +115,9 @@ async def update_current_user(
|
|||||||
language=updated_user.language,
|
language=updated_user.language,
|
||||||
timezone=updated_user.timezone,
|
timezone=updated_user.timezone,
|
||||||
created_at=updated_user.created_at,
|
created_at=updated_user.created_at,
|
||||||
last_login=updated_user.last_login
|
last_login=updated_user.last_login,
|
||||||
|
role=updated_user.role, # ✅ Include role
|
||||||
|
tenant_id=current_user.get("tenant_id") if isinstance(current_user, dict) else None
|
||||||
)
|
)
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
@@ -151,13 +158,6 @@ async def delete_admin_user(
|
|||||||
detail="Invalid user ID format"
|
detail="Invalid user ID format"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Prevent self-deletion
|
|
||||||
if user_id == current_user.id:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
detail="Cannot delete your own account"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Quick validation that user exists before starting background task
|
# Quick validation that user exists before starting background task
|
||||||
deletion_service = AdminUserDeleteService(db)
|
deletion_service = AdminUserDeleteService(db)
|
||||||
user_info = await deletion_service._validate_admin_user(user_id)
|
user_info = await deletion_service._validate_admin_user(user_id)
|
||||||
|
|||||||
436
tests/debug_admin_role.sh
Executable file
436
tests/debug_admin_role.sh
Executable file
@@ -0,0 +1,436 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# COMPREHENSIVE ADMIN ROLE DEBUG SCRIPT
|
||||||
|
# =================================================================
|
||||||
|
# This script will trace the entire flow of admin role assignment
|
||||||
|
# from registration through JWT token creation to API calls
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
API_BASE="http://localhost:8000"
|
||||||
|
AUTH_BASE="http://localhost:8001"
|
||||||
|
TEST_EMAIL="debug.admin.test.$(date +%s)@bakery.com"
|
||||||
|
TEST_PASSWORD="DebugPassword123!"
|
||||||
|
TEST_NAME="Debug Admin User"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
PURPLE='\033[0;35m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${CYAN}🔍 COMPREHENSIVE ADMIN ROLE DEBUG${NC}"
|
||||||
|
echo -e "${CYAN}=================================${NC}"
|
||||||
|
echo "Test Email: $TEST_EMAIL"
|
||||||
|
echo "API Base: $API_BASE"
|
||||||
|
echo "Auth Base: $AUTH_BASE"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Utility functions
|
||||||
|
log_step() {
|
||||||
|
echo -e "${BLUE}📋 $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_success() {
|
||||||
|
echo -e "${GREEN}✅ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}❌ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warning() {
|
||||||
|
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug() {
|
||||||
|
echo -e "${PURPLE}🐛 DEBUG: $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to decode JWT token (requires jq and base64)
|
||||||
|
decode_jwt() {
|
||||||
|
local token="$1"
|
||||||
|
local part="$2" # header=0, payload=1, signature=2
|
||||||
|
|
||||||
|
if [ -z "$token" ]; then
|
||||||
|
echo "No token provided"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Split token by dots
|
||||||
|
IFS='.' read -ra PARTS <<< "$token"
|
||||||
|
|
||||||
|
if [ ${#PARTS[@]} -ne 3 ]; then
|
||||||
|
echo "Invalid JWT format"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Decode the specified part (default to payload)
|
||||||
|
local part_index=${part:-1}
|
||||||
|
local encoded_part="${PARTS[$part_index]}"
|
||||||
|
|
||||||
|
# Add padding if needed
|
||||||
|
local padding=$(( 4 - ${#encoded_part} % 4 ))
|
||||||
|
if [ $padding -ne 4 ]; then
|
||||||
|
encoded_part="${encoded_part}$(printf '%*s' $padding | tr ' ' '=')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Decode and format as JSON
|
||||||
|
echo "$encoded_part" | base64 -d 2>/dev/null | jq '.' 2>/dev/null || echo "Failed to decode JWT part"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to extract JSON field
|
||||||
|
extract_json_field() {
|
||||||
|
local json="$1"
|
||||||
|
local field="$2"
|
||||||
|
echo "$json" | python3 -c "
|
||||||
|
import json, sys
|
||||||
|
try:
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
print(data.get('$field', ''))
|
||||||
|
except:
|
||||||
|
print('')
|
||||||
|
" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 1: VERIFY SERVICES ARE RUNNING
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 1: Verifying services are running"
|
||||||
|
|
||||||
|
# Check API Gateway
|
||||||
|
if ! curl -s "$API_BASE/health" > /dev/null; then
|
||||||
|
log_error "API Gateway is not responding at $API_BASE"
|
||||||
|
echo "Please ensure services are running: docker-compose up -d"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log_success "API Gateway is responding"
|
||||||
|
|
||||||
|
# Check Auth Service directly
|
||||||
|
if ! curl -s "$AUTH_BASE/health" > /dev/null; then
|
||||||
|
log_error "Auth Service is not responding at $AUTH_BASE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log_success "Auth Service is responding"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 2: USER REGISTRATION WITH DETAILED DEBUGGING
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 2: User Registration with Admin Role"
|
||||||
|
echo "Email: $TEST_EMAIL"
|
||||||
|
echo "Role: admin (explicitly set)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
log_debug "Sending registration request..."
|
||||||
|
|
||||||
|
# Registration request with explicit role
|
||||||
|
REGISTER_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X POST "$API_BASE/api/v1/auth/register" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"email\": \"$TEST_EMAIL\",
|
||||||
|
\"password\": \"$TEST_PASSWORD\",
|
||||||
|
\"full_name\": \"$TEST_NAME\",
|
||||||
|
\"role\": \"admin\"
|
||||||
|
}")
|
||||||
|
|
||||||
|
# Extract HTTP code and response
|
||||||
|
HTTP_CODE=$(echo "$REGISTER_RESPONSE" | grep "HTTP_CODE:" | cut -d: -f2)
|
||||||
|
REGISTER_RESPONSE=$(echo "$REGISTER_RESPONSE" | sed '/HTTP_CODE:/d')
|
||||||
|
|
||||||
|
echo "Registration HTTP Status: $HTTP_CODE"
|
||||||
|
echo "Registration Response:"
|
||||||
|
echo "$REGISTER_RESPONSE" | python3 -m json.tool 2>/dev/null || echo "$REGISTER_RESPONSE"
|
||||||
|
|
||||||
|
if [ "$HTTP_CODE" != "200" ] && [ "$HTTP_CODE" != "201" ]; then
|
||||||
|
log_error "Registration failed with HTTP $HTTP_CODE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract user information from registration response
|
||||||
|
USER_ID=$(extract_json_field "$REGISTER_RESPONSE" "user_id")
|
||||||
|
if [ -z "$USER_ID" ]; then
|
||||||
|
# Try alternative field names
|
||||||
|
USER_ID=$(echo "$REGISTER_RESPONSE" | python3 -c "
|
||||||
|
import json, sys
|
||||||
|
try:
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
user = data.get('user', {})
|
||||||
|
print(user.get('id', data.get('id', '')))
|
||||||
|
except:
|
||||||
|
print('')
|
||||||
|
" 2>/dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
ACCESS_TOKEN=$(extract_json_field "$REGISTER_RESPONSE" "access_token")
|
||||||
|
REFRESH_TOKEN=$(extract_json_field "$REGISTER_RESPONSE" "refresh_token")
|
||||||
|
|
||||||
|
log_debug "Extracted from registration:"
|
||||||
|
echo " User ID: $USER_ID"
|
||||||
|
echo " Access Token: ${ACCESS_TOKEN:0:50}..."
|
||||||
|
echo " Refresh Token: ${REFRESH_TOKEN:0:50}..."
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 3: DECODE AND ANALYZE JWT TOKEN
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 3: JWT Token Analysis"
|
||||||
|
|
||||||
|
if [ -n "$ACCESS_TOKEN" ]; then
|
||||||
|
log_debug "Decoding JWT Header:"
|
||||||
|
JWT_HEADER=$(decode_jwt "$ACCESS_TOKEN" 0)
|
||||||
|
echo "$JWT_HEADER"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_debug "Decoding JWT Payload:"
|
||||||
|
JWT_PAYLOAD=$(decode_jwt "$ACCESS_TOKEN" 1)
|
||||||
|
echo "$JWT_PAYLOAD"
|
||||||
|
|
||||||
|
# Extract role from JWT payload
|
||||||
|
JWT_ROLE=$(echo "$JWT_PAYLOAD" | jq -r '.role // "NOT_FOUND"' 2>/dev/null)
|
||||||
|
JWT_USER_ID=$(echo "$JWT_PAYLOAD" | jq -r '.user_id // "NOT_FOUND"' 2>/dev/null)
|
||||||
|
JWT_EMAIL=$(echo "$JWT_PAYLOAD" | jq -r '.email // "NOT_FOUND"' 2>/dev/null)
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_debug "JWT Payload Analysis:"
|
||||||
|
echo " Role in JWT: $JWT_ROLE"
|
||||||
|
echo " User ID in JWT: $JWT_USER_ID"
|
||||||
|
echo " Email in JWT: $JWT_EMAIL"
|
||||||
|
|
||||||
|
if [ "$JWT_ROLE" = "admin" ]; then
|
||||||
|
log_success "JWT contains admin role correctly"
|
||||||
|
else
|
||||||
|
log_error "JWT role is '$JWT_ROLE', expected 'admin'"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_error "No access token received in registration response"
|
||||||
|
echo "Cannot analyze JWT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 4: VERIFY USER PROFILE ENDPOINT
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 4: User Profile Verification"
|
||||||
|
|
||||||
|
if [ -n "$ACCESS_TOKEN" ]; then
|
||||||
|
log_debug "Calling /users/me endpoint..."
|
||||||
|
|
||||||
|
USER_PROFILE_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X GET "$API_BASE/api/v1/users/me" \
|
||||||
|
-H "Authorization: Bearer $ACCESS_TOKEN")
|
||||||
|
|
||||||
|
# Extract HTTP code and response
|
||||||
|
HTTP_CODE=$(echo "$USER_PROFILE_RESPONSE" | grep "HTTP_CODE:" | cut -d: -f2)
|
||||||
|
USER_PROFILE_RESPONSE=$(echo "$USER_PROFILE_RESPONSE" | sed '/HTTP_CODE:/d')
|
||||||
|
|
||||||
|
echo "User Profile HTTP Status: $HTTP_CODE"
|
||||||
|
echo "User Profile Response:"
|
||||||
|
echo "$USER_PROFILE_RESPONSE" | python3 -m json.tool 2>/dev/null || echo "$USER_PROFILE_RESPONSE"
|
||||||
|
|
||||||
|
if [ "$HTTP_CODE" = "200" ]; then
|
||||||
|
PROFILE_ROLE=$(extract_json_field "$USER_PROFILE_RESPONSE" "role")
|
||||||
|
PROFILE_EMAIL=$(extract_json_field "$USER_PROFILE_RESPONSE" "email")
|
||||||
|
PROFILE_USER_ID=$(extract_json_field "$USER_PROFILE_RESPONSE" "id")
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_debug "Profile endpoint analysis:"
|
||||||
|
echo " Role from profile: $PROFILE_ROLE"
|
||||||
|
echo " Email from profile: $PROFILE_EMAIL"
|
||||||
|
echo " User ID from profile: $PROFILE_USER_ID"
|
||||||
|
|
||||||
|
if [ "$PROFILE_ROLE" = "admin" ]; then
|
||||||
|
log_success "Profile endpoint shows admin role correctly"
|
||||||
|
else
|
||||||
|
log_error "Profile endpoint shows role '$PROFILE_ROLE', expected 'admin'"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_error "Failed to get user profile (HTTP $HTTP_CODE)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_error "No access token available for profile verification"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 5: DIRECT DATABASE VERIFICATION (if possible)
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 5: Database Verification"
|
||||||
|
|
||||||
|
log_debug "Attempting to verify user role in database..."
|
||||||
|
|
||||||
|
# Try to connect to the auth database directly
|
||||||
|
DB_QUERY_RESULT=$(docker exec bakery-auth-db psql -U auth_user -d auth_db -t -c "SELECT id, email, role, created_at FROM users WHERE email='$TEST_EMAIL';" 2>/dev/null || echo "DB_ACCESS_FAILED")
|
||||||
|
|
||||||
|
if [ "$DB_QUERY_RESULT" != "DB_ACCESS_FAILED" ]; then
|
||||||
|
echo "Database Query Result:"
|
||||||
|
echo "$DB_QUERY_RESULT"
|
||||||
|
|
||||||
|
# Parse the database result
|
||||||
|
DB_ROLE=$(echo "$DB_QUERY_RESULT" | awk -F'|' '{print $3}' | tr -d ' ')
|
||||||
|
|
||||||
|
log_debug "Role in database: '$DB_ROLE'"
|
||||||
|
|
||||||
|
if [ "$DB_ROLE" = "admin" ]; then
|
||||||
|
log_success "Database shows admin role correctly"
|
||||||
|
else
|
||||||
|
log_error "Database shows role '$DB_ROLE', expected 'admin'"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_warning "Cannot access database directly (this is normal in some setups)"
|
||||||
|
echo "You can manually check with:"
|
||||||
|
echo " docker exec bakery-auth-db psql -U auth_user -d auth_db -c \"SELECT id, email, role FROM users WHERE email='$TEST_EMAIL';\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 6: TEST ADMIN ENDPOINT ACCESS
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 6: Testing Admin Endpoint Access"
|
||||||
|
|
||||||
|
if [ -n "$ACCESS_TOKEN" ] && [ -n "$USER_ID" ]; then
|
||||||
|
log_debug "Attempting to call admin deletion preview endpoint..."
|
||||||
|
|
||||||
|
ADMIN_TEST_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X GET "$API_BASE/api/v1/users/delete/$USER_ID/deletion-preview" \
|
||||||
|
-H "Authorization: Bearer $ACCESS_TOKEN")
|
||||||
|
|
||||||
|
# Extract HTTP code and response
|
||||||
|
HTTP_CODE=$(echo "$ADMIN_TEST_RESPONSE" | grep "HTTP_CODE:" | cut -d: -f2)
|
||||||
|
ADMIN_TEST_RESPONSE=$(echo "$ADMIN_TEST_RESPONSE" | sed '/HTTP_CODE:/d')
|
||||||
|
|
||||||
|
echo "Admin Endpoint HTTP Status: $HTTP_CODE"
|
||||||
|
echo "Admin Endpoint Response:"
|
||||||
|
echo "$ADMIN_TEST_RESPONSE" | python3 -m json.tool 2>/dev/null || echo "$ADMIN_TEST_RESPONSE"
|
||||||
|
|
||||||
|
case "$HTTP_CODE" in
|
||||||
|
"200")
|
||||||
|
log_success "Admin endpoint access successful!"
|
||||||
|
;;
|
||||||
|
"403")
|
||||||
|
log_error "Access denied - user does not have admin privileges"
|
||||||
|
echo "This confirms the role issue!"
|
||||||
|
;;
|
||||||
|
"401")
|
||||||
|
log_error "Authentication failed - token may be invalid"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_warning "Unexpected response from admin endpoint (HTTP $HTTP_CODE)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
log_error "Cannot test admin endpoint - missing access token or user ID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 7: AUTH SERVICE LOGS ANALYSIS
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 7: Auth Service Logs Analysis"
|
||||||
|
|
||||||
|
log_debug "Checking recent auth service logs..."
|
||||||
|
|
||||||
|
AUTH_LOGS=$(docker logs --tail 50 bakery-auth-service 2>/dev/null | grep -E "(register|role|admin|$TEST_EMAIL)" || echo "NO_LOGS_FOUND")
|
||||||
|
|
||||||
|
if [ "$AUTH_LOGS" != "NO_LOGS_FOUND" ]; then
|
||||||
|
echo "Recent Auth Service Logs (filtered):"
|
||||||
|
echo "$AUTH_LOGS"
|
||||||
|
else
|
||||||
|
log_warning "Cannot access auth service logs"
|
||||||
|
echo "You can check manually with:"
|
||||||
|
echo " docker logs bakery-auth-service | grep -E \"(register|role|admin)\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 8: SUMMARY AND RECOMMENDATIONS
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 8: Debug Summary and Recommendations"
|
||||||
|
|
||||||
|
echo -e "${CYAN}🔍 DEBUG SUMMARY${NC}"
|
||||||
|
echo -e "${CYAN}===============${NC}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Test User Details:"
|
||||||
|
echo " Email: $TEST_EMAIL"
|
||||||
|
echo " Expected Role: admin"
|
||||||
|
echo " User ID: ${USER_ID:-'NOT_EXTRACTED'}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Token Analysis:"
|
||||||
|
echo " Access Token Received: $([ -n "$ACCESS_TOKEN" ] && echo 'YES' || echo 'NO')"
|
||||||
|
echo " Role in JWT: ${JWT_ROLE:-'NOT_FOUND'}"
|
||||||
|
echo " JWT User ID: ${JWT_USER_ID:-'NOT_FOUND'}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "API Responses:"
|
||||||
|
echo " Registration HTTP: ${HTTP_CODE:-'UNKNOWN'}"
|
||||||
|
echo " Profile Role: ${PROFILE_ROLE:-'NOT_CHECKED'}"
|
||||||
|
echo " Admin Endpoint Access: $([ -n "$ADMIN_TEST_RESPONSE" ] && echo "TESTED" || echo "NOT_TESTED")"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Database Verification:"
|
||||||
|
echo " DB Role: ${DB_ROLE:-'NOT_CHECKED'}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_debug "Potential Issues:"
|
||||||
|
|
||||||
|
# Issue 1: Role not in JWT
|
||||||
|
if [ "$JWT_ROLE" != "admin" ]; then
|
||||||
|
echo " ❌ Role not correctly encoded in JWT token"
|
||||||
|
echo " → Check auth service JWT creation logic"
|
||||||
|
echo " → Verify SecurityManager.create_access_token includes role"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Issue 2: Registration not setting role
|
||||||
|
if [ "$PROFILE_ROLE" != "admin" ]; then
|
||||||
|
echo " ❌ User profile doesn't show admin role"
|
||||||
|
echo " → Check user registration saves role correctly"
|
||||||
|
echo " → Verify database schema allows role field"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Issue 3: Admin endpoint still denies access
|
||||||
|
if [ "$HTTP_CODE" = "403" ]; then
|
||||||
|
echo " ❌ Admin endpoint denies access despite admin role"
|
||||||
|
echo " → Check require_admin_role_dep implementation"
|
||||||
|
echo " → Verify role extraction from token in auth decorators"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}🔧 RECOMMENDED NEXT STEPS:${NC}"
|
||||||
|
echo "1. Check the auth service logs during registration"
|
||||||
|
echo "2. Verify the database schema has a 'role' column"
|
||||||
|
echo "3. Check if the JWT creation includes the role field"
|
||||||
|
echo "4. Verify the role extraction in get_current_user_dep"
|
||||||
|
echo "5. Test with a direct database role update if needed"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}🧪 Manual Verification Commands:${NC}"
|
||||||
|
echo "# Check database directly:"
|
||||||
|
echo "docker exec bakery-auth-db psql -U auth_user -d auth_db -c \"SELECT id, email, role FROM users WHERE email='$TEST_EMAIL';\""
|
||||||
|
echo ""
|
||||||
|
echo "# Check auth service logs:"
|
||||||
|
echo "docker logs bakery-auth-service | grep -A5 -B5 '$TEST_EMAIL'"
|
||||||
|
echo ""
|
||||||
|
echo "# Decode JWT manually:"
|
||||||
|
echo "echo '$ACCESS_TOKEN' | cut -d. -f2 | base64 -d | jq ."
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_success "Debug script completed!"
|
||||||
|
echo -e "${YELLOW}Review the analysis above to identify the root cause.${NC}"
|
||||||
361
tests/debug_onboarding_flow.sh
Executable file
361
tests/debug_onboarding_flow.sh
Executable file
@@ -0,0 +1,361 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# ONBOARDING FLOW DEBUG SCRIPT
|
||||||
|
# =================================================================
|
||||||
|
# This script replicates the exact onboarding flow to debug the 403 issue
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
API_BASE="http://localhost:8000"
|
||||||
|
TEST_EMAIL="onboarding.debug.$(date +%s)@bakery.com"
|
||||||
|
TEST_PASSWORD="OnboardingDebug123!"
|
||||||
|
TEST_NAME="Onboarding Debug User"
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
PURPLE='\033[0;35m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
echo -e "${CYAN}🔍 ONBOARDING FLOW DEBUG - EXACT REPLICATION${NC}"
|
||||||
|
echo -e "${CYAN}=============================================${NC}"
|
||||||
|
echo "Test Email: $TEST_EMAIL"
|
||||||
|
echo "API Base: $API_BASE"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Utility functions
|
||||||
|
log_step() {
|
||||||
|
echo -e "${BLUE}📋 $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_success() {
|
||||||
|
echo -e "${GREEN}✅ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}❌ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug() {
|
||||||
|
echo -e "${PURPLE}🐛 DEBUG: $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_json_field() {
|
||||||
|
local json="$1"
|
||||||
|
local field="$2"
|
||||||
|
echo "$json" | python3 -c "
|
||||||
|
import json, sys
|
||||||
|
try:
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
user = data.get('user', {})
|
||||||
|
print(user.get('$field', data.get('$field', '')))
|
||||||
|
except:
|
||||||
|
print('')
|
||||||
|
" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 1: REGISTER USER (EXACTLY LIKE ONBOARDING SCRIPT)
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 1: User Registration (Onboarding Style)"
|
||||||
|
echo "Email: $TEST_EMAIL"
|
||||||
|
echo "Role: admin (explicitly set)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
log_debug "Registering via API Gateway (same as onboarding script)..."
|
||||||
|
|
||||||
|
REGISTER_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/auth/register" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"email\": \"$TEST_EMAIL\",
|
||||||
|
\"password\": \"$TEST_PASSWORD\",
|
||||||
|
\"full_name\": \"$TEST_NAME\",
|
||||||
|
\"role\": \"admin\"
|
||||||
|
}")
|
||||||
|
|
||||||
|
echo "Registration Response:"
|
||||||
|
echo "$REGISTER_RESPONSE" | python3 -m json.tool 2>/dev/null || echo "$REGISTER_RESPONSE"
|
||||||
|
|
||||||
|
# Extract user ID exactly like onboarding script
|
||||||
|
USER_ID=$(echo "$REGISTER_RESPONSE" | python3 -c "
|
||||||
|
import json, sys
|
||||||
|
try:
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
user = data.get('user', {})
|
||||||
|
print(user.get('id', ''))
|
||||||
|
except:
|
||||||
|
print('')
|
||||||
|
")
|
||||||
|
|
||||||
|
if [ -n "$USER_ID" ]; then
|
||||||
|
log_success "User ID extracted: $USER_ID"
|
||||||
|
else
|
||||||
|
log_error "Failed to extract user ID"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 2: LOGIN (EXACTLY LIKE ONBOARDING SCRIPT)
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 2: User Login (Onboarding Style)"
|
||||||
|
|
||||||
|
LOGIN_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/auth/login" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"email\": \"$TEST_EMAIL\",
|
||||||
|
\"password\": \"$TEST_PASSWORD\"
|
||||||
|
}")
|
||||||
|
|
||||||
|
echo "Login Response:"
|
||||||
|
echo "$LOGIN_RESPONSE" | python3 -m json.tool 2>/dev/null || echo "$LOGIN_RESPONSE"
|
||||||
|
|
||||||
|
ACCESS_TOKEN=$(extract_json_field "$LOGIN_RESPONSE" "access_token")
|
||||||
|
|
||||||
|
if [ -n "$ACCESS_TOKEN" ]; then
|
||||||
|
log_success "Access token obtained: ${ACCESS_TOKEN:0:50}..."
|
||||||
|
else
|
||||||
|
log_error "Failed to extract access token"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 3: CHECK PROFILE ENDPOINT
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 3: Check Profile Endpoint"
|
||||||
|
|
||||||
|
PROFILE_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X GET "$API_BASE/api/v1/users/me" \
|
||||||
|
-H "Authorization: Bearer $ACCESS_TOKEN")
|
||||||
|
|
||||||
|
HTTP_CODE=$(echo "$PROFILE_RESPONSE" | grep "HTTP_CODE:" | cut -d: -f2)
|
||||||
|
PROFILE_RESPONSE=$(echo "$PROFILE_RESPONSE" | sed '/HTTP_CODE:/d')
|
||||||
|
|
||||||
|
echo "Profile HTTP Status: $HTTP_CODE"
|
||||||
|
echo "Profile Response:"
|
||||||
|
echo "$PROFILE_RESPONSE" | python3 -m json.tool 2>/dev/null || echo "$PROFILE_RESPONSE"
|
||||||
|
|
||||||
|
PROFILE_ROLE=$(extract_json_field "$PROFILE_RESPONSE" "role")
|
||||||
|
echo ""
|
||||||
|
log_debug "Profile role: $PROFILE_ROLE"
|
||||||
|
|
||||||
|
if [ "$PROFILE_ROLE" = "admin" ]; then
|
||||||
|
log_success "Profile shows admin role correctly"
|
||||||
|
else
|
||||||
|
log_error "Profile shows role '$PROFILE_ROLE', expected 'admin'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 4: TEST ADMIN DELETION PREVIEW (EXACTLY LIKE ONBOARDING)
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 4: Admin Deletion Preview (Onboarding Style)"
|
||||||
|
|
||||||
|
log_debug "Calling deletion preview endpoint..."
|
||||||
|
|
||||||
|
DELETION_PREVIEW_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X GET "$API_BASE/api/v1/users/delete/$USER_ID/deletion-preview" \
|
||||||
|
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||||
|
-H "Content-Type: application/json")
|
||||||
|
|
||||||
|
HTTP_CODE=$(echo "$DELETION_PREVIEW_RESPONSE" | grep "HTTP_CODE:" | cut -d: -f2)
|
||||||
|
DELETION_PREVIEW_RESPONSE=$(echo "$DELETION_PREVIEW_RESPONSE" | sed '/HTTP_CODE:/d')
|
||||||
|
|
||||||
|
echo "Deletion Preview HTTP Status: $HTTP_CODE"
|
||||||
|
echo "Deletion Preview Response:"
|
||||||
|
echo "$DELETION_PREVIEW_RESPONSE" | python3 -m json.tool 2>/dev/null || echo "$DELETION_PREVIEW_RESPONSE"
|
||||||
|
|
||||||
|
case "$HTTP_CODE" in
|
||||||
|
"200")
|
||||||
|
log_success "Deletion preview successful!"
|
||||||
|
;;
|
||||||
|
"403")
|
||||||
|
log_error "403 Forbidden - Admin access denied!"
|
||||||
|
echo "This is the same error as in onboarding script"
|
||||||
|
;;
|
||||||
|
"401")
|
||||||
|
log_error "401 Unauthorized - Token issue"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_error "Unexpected HTTP status: $HTTP_CODE"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 5: TEST ACTUAL DELETION (EXACTLY LIKE ONBOARDING)
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 5: Admin User Deletion (Onboarding Style)"
|
||||||
|
|
||||||
|
if [ "$HTTP_CODE" = "200" ]; then
|
||||||
|
log_debug "Attempting actual deletion..."
|
||||||
|
|
||||||
|
DELETION_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X DELETE "$API_BASE/api/v1/users/delete/$USER_ID" \
|
||||||
|
-H "Authorization: Bearer $ACCESS_TOKEN")
|
||||||
|
|
||||||
|
HTTP_CODE=$(echo "$DELETION_RESPONSE" | grep "HTTP_CODE:" | cut -d: -f2)
|
||||||
|
DELETION_RESPONSE=$(echo "$DELETION_RESPONSE" | sed '/HTTP_CODE:/d')
|
||||||
|
|
||||||
|
echo "Deletion HTTP Status: $HTTP_CODE"
|
||||||
|
echo "Deletion Response:"
|
||||||
|
echo "$DELETION_RESPONSE" | python3 -m json.tool 2>/dev/null || echo "$DELETION_RESPONSE"
|
||||||
|
|
||||||
|
case "$HTTP_CODE" in
|
||||||
|
"200")
|
||||||
|
log_success "Admin deletion successful!"
|
||||||
|
;;
|
||||||
|
"403")
|
||||||
|
log_error "403 Forbidden - Admin deletion denied!"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_error "Deletion failed with HTTP $HTTP_CODE"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
log_error "Skipping deletion test due to preview failure"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 6: DETAILED TOKEN ANALYSIS
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 6: Detailed Token Analysis"
|
||||||
|
|
||||||
|
log_debug "Decoding access token from login..."
|
||||||
|
|
||||||
|
if [ -n "$ACCESS_TOKEN" ]; then
|
||||||
|
# Decode JWT payload
|
||||||
|
JWT_PAYLOAD=$(echo "$ACCESS_TOKEN" | cut -d. -f2)
|
||||||
|
# Add padding if needed
|
||||||
|
JWT_PAYLOAD="${JWT_PAYLOAD}$(printf '%*s' $((4 - ${#JWT_PAYLOAD} % 4)) | tr ' ' '=')"
|
||||||
|
|
||||||
|
echo "JWT Payload:"
|
||||||
|
echo "$JWT_PAYLOAD" | base64 -d 2>/dev/null | python3 -m json.tool 2>/dev/null || echo "Failed to decode"
|
||||||
|
|
||||||
|
JWT_ROLE=$(echo "$JWT_PAYLOAD" | base64 -d 2>/dev/null | python3 -c "
|
||||||
|
import json, sys
|
||||||
|
try:
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
print(data.get('role', 'NOT_FOUND'))
|
||||||
|
except:
|
||||||
|
print('DECODE_ERROR')
|
||||||
|
" 2>/dev/null)
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_debug "JWT token role: $JWT_ROLE"
|
||||||
|
else
|
||||||
|
log_error "No access token available for analysis"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 7: CHECK GATEWAY VS DIRECT AUTH
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 7: Gateway vs Direct Auth Comparison"
|
||||||
|
|
||||||
|
log_debug "Testing direct auth service call..."
|
||||||
|
|
||||||
|
DIRECT_PROFILE=$(curl -s -X GET "http://localhost:8001/me" \
|
||||||
|
-H "Authorization: Bearer $ACCESS_TOKEN" 2>/dev/null || echo "DIRECT_FAILED")
|
||||||
|
|
||||||
|
if [ "$DIRECT_PROFILE" != "DIRECT_FAILED" ]; then
|
||||||
|
echo "Direct Auth Service Profile:"
|
||||||
|
echo "$DIRECT_PROFILE" | python3 -m json.tool 2>/dev/null || echo "$DIRECT_PROFILE"
|
||||||
|
|
||||||
|
DIRECT_ROLE=$(extract_json_field "$DIRECT_PROFILE" "role")
|
||||||
|
log_debug "Direct auth service role: $DIRECT_ROLE"
|
||||||
|
else
|
||||||
|
log_debug "Direct auth service call failed (expected in some setups)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 8: CHECK AUTH SERVICE LOGS
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 8: Auth Service Logs for This Session"
|
||||||
|
|
||||||
|
log_debug "Checking auth service logs for this user..."
|
||||||
|
|
||||||
|
AUTH_LOGS=$(docker logs --tail 50 bakery-auth-service 2>/dev/null | grep -E "($TEST_EMAIL|$USER_ID)" || echo "NO_LOGS_FOUND")
|
||||||
|
|
||||||
|
if [ "$AUTH_LOGS" != "NO_LOGS_FOUND" ]; then
|
||||||
|
echo "Auth Service Logs (filtered for this user):"
|
||||||
|
echo "$AUTH_LOGS"
|
||||||
|
else
|
||||||
|
log_debug "No specific logs found for this user"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# STEP 9: SUMMARY AND COMPARISON
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
log_step "Step 9: Onboarding Flow Analysis Summary"
|
||||||
|
|
||||||
|
echo -e "${CYAN}🔍 ONBOARDING FLOW ANALYSIS${NC}"
|
||||||
|
echo -e "${CYAN}===========================${NC}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Registration Results:"
|
||||||
|
echo " User ID: $USER_ID"
|
||||||
|
echo " Access Token: $([ -n "$ACCESS_TOKEN" ] && echo 'YES' || echo 'NO')"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Authentication Flow:"
|
||||||
|
echo " Profile Role: $PROFILE_ROLE"
|
||||||
|
echo " JWT Role: $JWT_ROLE"
|
||||||
|
echo " Direct Auth Role: ${DIRECT_ROLE:-'NOT_TESTED'}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Admin Endpoint Tests:"
|
||||||
|
echo " Deletion Preview: HTTP $HTTP_CODE"
|
||||||
|
echo " Admin Access: $([ "$HTTP_CODE" = "200" ] && echo 'SUCCESS' || echo 'FAILED')"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
if [ "$HTTP_CODE" != "200" ]; then
|
||||||
|
echo -e "${RED}🚨 ISSUE IDENTIFIED:${NC}"
|
||||||
|
echo "The onboarding flow is still getting 403 errors"
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}Possible causes:${NC}"
|
||||||
|
echo "1. Token from login different from registration token"
|
||||||
|
echo "2. Gateway headers not set correctly"
|
||||||
|
echo "3. Role being overridden somewhere in the flow"
|
||||||
|
echo "4. Cache or session issue"
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}Next steps:${NC}"
|
||||||
|
echo "1. Compare JWT tokens from registration vs login"
|
||||||
|
echo "2. Check gateway request headers"
|
||||||
|
echo "3. Verify auth service restart picked up the fix"
|
||||||
|
echo "4. Check if there are multiple auth service instances"
|
||||||
|
else
|
||||||
|
log_success "Onboarding flow working correctly!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}Manual commands to investigate:${NC}"
|
||||||
|
echo "# Check user in database:"
|
||||||
|
echo "docker exec bakery-auth-db psql -U auth_user -d auth_db -c \"SELECT id, email, role FROM users WHERE email='$TEST_EMAIL';\""
|
||||||
|
echo ""
|
||||||
|
echo "# Restart auth service:"
|
||||||
|
echo "docker-compose restart auth-service"
|
||||||
|
echo ""
|
||||||
|
echo "# Check auth service status:"
|
||||||
|
echo "docker-compose ps auth-service"
|
||||||
157
tests/verify_db_schema.sh
Executable file
157
tests/verify_db_schema.sh
Executable file
@@ -0,0 +1,157 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# DATABASE SCHEMA AND DATA VERIFICATION SCRIPT
|
||||||
|
# =================================================================
|
||||||
|
# This script checks the auth database schema and data
|
||||||
|
|
||||||
|
echo "🔍 DATABASE VERIFICATION"
|
||||||
|
echo "========================"
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
# Check if auth database container is running
|
||||||
|
if ! docker ps | grep -q "bakery-auth-db"; then
|
||||||
|
echo -e "${RED}❌ Auth database container is not running${NC}"
|
||||||
|
echo "Start with: docker-compose up -d auth-db"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}✅ Auth database container is running${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 1. Check database schema
|
||||||
|
echo "📋 1. CHECKING DATABASE SCHEMA"
|
||||||
|
echo "=============================="
|
||||||
|
|
||||||
|
echo "Users table structure:"
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "\d users;" 2>/dev/null || {
|
||||||
|
echo -e "${RED}❌ Cannot access database or users table doesn't exist${NC}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Checking if 'role' column exists:"
|
||||||
|
ROLE_COLUMN=$(docker exec bakery-auth-db psql -U auth_user -d auth_db -t -c "SELECT column_name FROM information_schema.columns WHERE table_name='users' AND column_name='role';" 2>/dev/null | tr -d ' ')
|
||||||
|
|
||||||
|
if [ "$ROLE_COLUMN" = "role" ]; then
|
||||||
|
echo -e "${GREEN}✅ 'role' column exists in users table${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}❌ 'role' column is missing from users table${NC}"
|
||||||
|
echo "This is likely the root cause!"
|
||||||
|
echo ""
|
||||||
|
echo "Available columns in users table:"
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "SELECT column_name, data_type FROM information_schema.columns WHERE table_name='users';"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 2. Check existing users and their roles
|
||||||
|
echo "📋 2. CHECKING EXISTING USERS"
|
||||||
|
echo "============================="
|
||||||
|
|
||||||
|
echo "All users in database:"
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "SELECT id, email, role, is_active, created_at FROM users ORDER BY created_at DESC LIMIT 10;"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 3. Check for test users
|
||||||
|
echo "📋 3. CHECKING FOR TEST USERS"
|
||||||
|
echo "============================="
|
||||||
|
|
||||||
|
echo "Test users (containing 'test' in email):"
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "SELECT id, email, role, is_active, created_at FROM users WHERE email LIKE '%test%' ORDER BY created_at DESC;"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 4. Check database constraints and defaults
|
||||||
|
echo "📋 4. CHECKING ROLE CONSTRAINTS"
|
||||||
|
echo "==============================="
|
||||||
|
|
||||||
|
echo "Role column details:"
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "SELECT column_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_name='users' AND column_name='role';"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Role check constraints (if any):"
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "SELECT conname, consrc FROM pg_constraint WHERE conrelid = 'users'::regclass AND consrc LIKE '%role%';" 2>/dev/null || echo "No role constraints found"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 5. Test role insertion
|
||||||
|
echo "📋 5. TESTING ROLE INSERTION"
|
||||||
|
echo "============================"
|
||||||
|
|
||||||
|
TEST_EMAIL="schema.test.$(date +%s)@example.com"
|
||||||
|
|
||||||
|
echo "Creating test user with admin role:"
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "
|
||||||
|
INSERT INTO users (id, email, full_name, hashed_password, role, is_active, is_verified, created_at, updated_at)
|
||||||
|
VALUES (gen_random_uuid(), '$TEST_EMAIL', 'Schema Test', 'dummy_hash', 'admin', true, false, NOW(), NOW());
|
||||||
|
" 2>/dev/null
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}✅ Successfully inserted user with admin role${NC}"
|
||||||
|
|
||||||
|
echo "Verifying insertion:"
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "SELECT id, email, role FROM users WHERE email='$TEST_EMAIL';"
|
||||||
|
|
||||||
|
echo "Cleaning up test user:"
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "DELETE FROM users WHERE email='$TEST_EMAIL';" 2>/dev/null
|
||||||
|
else
|
||||||
|
echo -e "${RED}❌ Failed to insert user with admin role${NC}"
|
||||||
|
echo "This indicates a database constraint or permission issue"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 6. Check for migration history
|
||||||
|
echo "📋 6. CHECKING MIGRATION HISTORY"
|
||||||
|
echo "================================="
|
||||||
|
|
||||||
|
echo "Alembic version table (if exists):"
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "SELECT * FROM alembic_version;" 2>/dev/null || echo "No alembic_version table found"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "📋 SUMMARY AND RECOMMENDATIONS"
|
||||||
|
echo "==============================="
|
||||||
|
|
||||||
|
# Check if we found any obvious issues
|
||||||
|
ISSUES_FOUND=0
|
||||||
|
|
||||||
|
# Check if role column exists
|
||||||
|
if [ "$ROLE_COLUMN" != "role" ]; then
|
||||||
|
echo -e "${RED}❌ CRITICAL: 'role' column missing from users table${NC}"
|
||||||
|
echo " → Run database migrations: alembic upgrade head"
|
||||||
|
echo " → Or add the column manually"
|
||||||
|
ISSUES_FOUND=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if we can insert admin roles
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "INSERT INTO users (id, email, full_name, hashed_password, role, is_active, is_verified, created_at, updated_at) VALUES (gen_random_uuid(), 'temp.test@example.com', 'Test', 'hash', 'admin', true, false, NOW(), NOW());" 2>/dev/null
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
docker exec bakery-auth-db psql -U auth_user -d auth_db -c "DELETE FROM users WHERE email='temp.test@example.com';" 2>/dev/null
|
||||||
|
else
|
||||||
|
echo -e "${RED}❌ ISSUE: Cannot insert users with admin role${NC}"
|
||||||
|
echo " → Check database constraints or permissions"
|
||||||
|
ISSUES_FOUND=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $ISSUES_FOUND -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}✅ Database schema appears correct${NC}"
|
||||||
|
echo " → The issue is likely in the application code, not the database"
|
||||||
|
echo " → Check JWT token creation and role extraction logic"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠️ Database issues found - fix these first${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}🔧 Next steps:${NC}"
|
||||||
|
echo "1. If role column is missing: Run 'alembic upgrade head' in auth service"
|
||||||
|
echo "2. If schema is OK: Run the main debug script to check application logic"
|
||||||
|
echo "3. Check auth service logs during user registration"
|
||||||
Reference in New Issue
Block a user