#!/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}"