Add comprehensive security tests for authentication, roles, and user management
- Enhance `test-auth.sh` with SQL injection, XSS, and credential validation tests. - Extend `test-roles-permissions.sh` to include unauthorized access and duplicate role creation tests. - Improve `test-users.sh` with checks for invalid emails, duplicate users, and unauthorized actions. - Introduce `test-security.sh` for thorough security assessments including CSRF, SQL injection, XSS, rate limiting, and session management. - Add `.serena.gitignore` and `.serena/project.yml` for project configuration and file management.
This commit is contained in:
+61
-1
@@ -15,6 +15,9 @@ test_events_endpoints() {
|
||||
test_api_endpoint "GET Events (Search)" "GET" "/v1/cms/landing/events?search=test" 200 "" false
|
||||
test_api_endpoint "GET Events (Filter Online)" "GET" "/v1/cms/landing/events?filter=online" 200 "" false
|
||||
|
||||
# Security: Test SQL injection in search
|
||||
test_api_endpoint "GET Events with SQL Injection (Should Be Safe)" "GET" "/v1/cms/landing/events?search=' OR '1'='1" 200 "" false
|
||||
|
||||
# Get event by ID - use correct endpoint /detail/{id}
|
||||
local events_response=$(curl -s "$BASE_URL/v1/cms/landing/events")
|
||||
local test_event_id=$(echo "$events_response" | jq -r '.data[0].id // empty')
|
||||
@@ -23,8 +26,20 @@ test_events_endpoints() {
|
||||
test_api_endpoint "GET Event By ID" "GET" "/v1/cms/landing/events/detail/$test_event_id" 200 "" false
|
||||
fi
|
||||
|
||||
# Create event (protected) - use correct field name
|
||||
# Security: Test that create endpoint requires authentication
|
||||
local create_event_data=$(jq -n '{
|
||||
name: "Unauthorized Event '$(date +%s)'",
|
||||
description: "Should not be created",
|
||||
start_date: "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
|
||||
end_date: "'$(date -u -d '+2 hours' +%Y-%m-%dT%H:%M:%SZ)'",
|
||||
detail_link: "https://example.com/event",
|
||||
price: 0,
|
||||
is_online: true
|
||||
}')
|
||||
test_api_endpoint "POST Create Event without Auth (Should Fail)" "POST" "/v1/cms/landing/events/create" 401 "$create_event_data" false
|
||||
|
||||
# Create event (protected) - use correct field name
|
||||
create_event_data=$(jq -n '{
|
||||
name: "Test Event '$(date +%s)'",
|
||||
description: "Auto-generated test event",
|
||||
start_date: "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
|
||||
@@ -37,6 +52,14 @@ test_events_endpoints() {
|
||||
local created_event_id=$(echo "$create_event_response" | jq -r '.data.id // empty')
|
||||
|
||||
if [ -n "$created_event_id" ]; then
|
||||
# Security: Test XSS in event name
|
||||
local xss_event_data=$(jq -n --arg id "$created_event_id" '{
|
||||
name: "<script>alert(\"XSS\")</script>",
|
||||
description: "XSS test",
|
||||
is_online: false
|
||||
}')
|
||||
test_api_endpoint "PATCH Update Event with XSS (Should Be Sanitized)" "PATCH" "/v1/cms/landing/events/update/$created_event_id" 200 "$xss_event_data" true
|
||||
|
||||
# Update event - use correct endpoint /update/{id} with PATCH
|
||||
local update_event_data=$(jq -n '{
|
||||
name: "Updated Test Event",
|
||||
@@ -45,8 +68,19 @@ test_events_endpoints() {
|
||||
}')
|
||||
test_api_endpoint "PATCH Update Event" "PATCH" "/v1/cms/landing/events/update/$created_event_id" 200 "$update_event_data" true
|
||||
|
||||
# Security: Test unauthorized update
|
||||
local saved_token="$AUTH_TOKEN"
|
||||
AUTH_TOKEN=""
|
||||
test_api_endpoint "PATCH Update Event without Auth (Should Fail)" "PATCH" "/v1/cms/landing/events/update/$created_event_id" 401 "$update_event_data" false
|
||||
AUTH_TOKEN="$saved_token"
|
||||
|
||||
# Delete event - use correct endpoint /delete/{id}
|
||||
test_api_endpoint "DELETE Event" "DELETE" "/v1/cms/landing/events/delete/$created_event_id" 200 "" true
|
||||
|
||||
# Security: Test unauthorized delete
|
||||
AUTH_TOKEN=""
|
||||
test_api_endpoint "DELETE Event without Auth (Should Fail)" "DELETE" "/v1/cms/landing/events/delete/$created_event_id" 401 "" false
|
||||
AUTH_TOKEN="$saved_token"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -58,6 +92,9 @@ test_testimonials_endpoints() {
|
||||
test_api_endpoint "GET Testimonials (Paginated)" "GET" "/v1/cms/landing/testimonials?page=1&limit=10" 200 "" false
|
||||
test_api_endpoint "GET Testimonials (Search)" "GET" "/v1/cms/landing/testimonials?search=test" 200 "" false
|
||||
|
||||
# Security: Test SQL injection in search
|
||||
test_api_endpoint "GET Testimonials with SQL Injection (Should Be Safe)" "GET" "/v1/cms/landing/testimonials?search=' OR '1'='1" 200 "" false
|
||||
|
||||
# Get testimonial by ID - use correct endpoint /detail/{id}
|
||||
local testimonials_response=$(curl -s "$BASE_URL/v1/cms/landing/testimonials")
|
||||
local test_testimonial_id=$(echo "$testimonials_response" | jq -r '.data[0].id // empty')
|
||||
@@ -66,6 +103,13 @@ test_testimonials_endpoints() {
|
||||
test_api_endpoint "GET Testimonial By ID" "GET" "/v1/cms/landing/testimonials/detail/$test_testimonial_id" 200 "" false
|
||||
fi
|
||||
|
||||
# Security: Test that create endpoint requires authentication
|
||||
local unauth_testimonial_data=$(jq -n '{
|
||||
role: "Hacker",
|
||||
content: "Unauthorized testimonial"
|
||||
}')
|
||||
test_api_endpoint "POST Create Testimonial without Auth (Should Fail)" "POST" "/v1/cms/landing/testimonials/create" 401 "$unauth_testimonial_data" false
|
||||
|
||||
# Create testimonial (protected)
|
||||
local create_testimonial_data=$(jq -n '{
|
||||
role: "Student",
|
||||
@@ -75,6 +119,13 @@ test_testimonials_endpoints() {
|
||||
local created_testimonial_id=$(echo "$create_testimonial_response" | jq -r '.data.id // empty')
|
||||
|
||||
if [ -n "$created_testimonial_id" ]; then
|
||||
# Security: Test XSS in testimonial content
|
||||
local xss_testimonial_data=$(jq -n '{
|
||||
role: "Student",
|
||||
content: "<script>alert(\"XSS\")</script>"
|
||||
}')
|
||||
test_api_endpoint "PATCH Update Testimonial with XSS (Should Be Sanitized)" "PATCH" "/v1/cms/landing/testimonials/update/$created_testimonial_id" 200 "$xss_testimonial_data" true
|
||||
|
||||
# Update testimonial - use correct endpoint /update/{id} with PATCH
|
||||
local update_testimonial_data=$(jq -n '{
|
||||
role: "Alumni",
|
||||
@@ -82,8 +133,17 @@ test_testimonials_endpoints() {
|
||||
}')
|
||||
test_api_endpoint "PATCH Update Testimonial" "PATCH" "/v1/cms/landing/testimonials/update/$created_testimonial_id" 200 "$update_testimonial_data" true
|
||||
|
||||
# Security: Test unauthorized update
|
||||
local saved_token="$AUTH_TOKEN"
|
||||
AUTH_TOKEN=""
|
||||
test_api_endpoint "PATCH Update Testimonial without Auth (Should Fail)" "PATCH" "/v1/cms/landing/testimonials/update/$created_testimonial_id" 401 "$update_testimonial_data" false
|
||||
AUTH_TOKEN="$saved_token"
|
||||
|
||||
# Delete testimonial - use correct endpoint /delete/{id}
|
||||
test_api_endpoint "DELETE Testimonial" "DELETE" "/v1/cms/landing/testimonials/delete/$created_testimonial_id" 200 "" true
|
||||
|
||||
# Security: Test that non-existent resource returns proper error
|
||||
test_api_endpoint "DELETE Non-existent Testimonial (Should Fail)" "DELETE" "/v1/cms/landing/testimonials/delete/00000000-0000-0000-0000-000000000000" 404 "" true
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -17,20 +17,55 @@ test_authentication_endpoints() {
|
||||
invalid_login=$(jq -n '{email: "invalid@example.com", password: "wrongpassword"}')
|
||||
test_api_endpoint "Invalid Login Test" "POST" "/v1/auth/login" 401 "$invalid_login"
|
||||
|
||||
# Security: Test SQL injection in login
|
||||
local sql_injection_login=$(jq -n '{email: "admin@example.com\" OR \"1\"=\"1", password: "password"}')
|
||||
test_api_endpoint "SQL Injection in Login Email (Should Fail)" "POST" "/v1/auth/login" 401 "$sql_injection_login"
|
||||
|
||||
local sql_injection_pass=$(jq -n '{email: "admin@example.com", password: "password\" OR \"1\"=\"1"}')
|
||||
test_api_endpoint "SQL Injection in Login Password (Should Fail)" "POST" "/v1/auth/login" 401 "$sql_injection_pass"
|
||||
|
||||
# Security: Test XSS in login
|
||||
local xss_login=$(jq -n '{email: "<script>alert(\"XSS\")</script>", password: "password"}')
|
||||
test_api_endpoint "XSS in Login Email (Should Fail)" "POST" "/v1/auth/login" 401 "$xss_login"
|
||||
|
||||
# Security: Test empty credentials
|
||||
local empty_login=$(jq -n '{email: "", password: ""}')
|
||||
test_api_endpoint "Empty Credentials (Should Fail)" "POST" "/v1/auth/login" 400 "$empty_login"
|
||||
|
||||
# Security: Test missing fields
|
||||
local missing_password=$(jq -n '{email: "admin@example.com"}')
|
||||
test_api_endpoint "Missing Password (Should Fail)" "POST" "/v1/auth/login" 400 "$missing_password"
|
||||
|
||||
# Mentor login
|
||||
local mentor_login=$(jq -n '{email: "mentor@example.com", password: "password"}')
|
||||
test_api_endpoint "Mentor Login" "POST" "/v1/auth/login-mentor" 200 "$mentor_login" false
|
||||
|
||||
# Security: Test invalid mentor login
|
||||
local invalid_mentor=$(jq -n '{email: "nonexistent@example.com", password: "wrongpass"}')
|
||||
test_api_endpoint "Invalid Mentor Login (Should Fail)" "POST" "/v1/auth/login-mentor" 401 "$invalid_mentor"
|
||||
|
||||
# Forgot password
|
||||
local forgot_password_data
|
||||
forgot_password_data=$(jq -n --arg email "admin@example.com" '{email: $email}')
|
||||
test_api_endpoint "Forgot Password Test" "POST" "/v1/auth/forgot" 200 "$forgot_password_data"
|
||||
|
||||
# Security: Test forgot password with invalid email
|
||||
local invalid_forgot=$(jq -n '{email: "not_an_email"}')
|
||||
test_api_endpoint "Forgot Password with Invalid Email (Should Fail)" "POST" "/v1/auth/forgot" 400 "$invalid_forgot"
|
||||
|
||||
# Security: Test forgot password with non-existent email (should not reveal if user exists)
|
||||
local nonexistent_forgot=$(jq -n '{email: "nonexistent@example.com"}')
|
||||
test_api_endpoint "Forgot Password with Non-existent Email" "POST" "/v1/auth/forgot" 200 "$nonexistent_forgot"
|
||||
|
||||
# Invalid new password (invalid token)
|
||||
local new_password_data
|
||||
new_password_data=$(jq -n --arg token "some_reset_token" --arg pass "newpassword123!A" '{token: $token, password: $pass}')
|
||||
test_api_endpoint "New Password Test (Invalid Token)" "POST" "/v1/auth/new-password" 400 "$new_password_data"
|
||||
|
||||
# Security: Test weak password in reset
|
||||
local weak_reset=$(jq -n --arg token "some_reset_token" '{token: $token, password: "123456"}')
|
||||
test_api_endpoint "New Password with Weak Password (Should Fail)" "POST" "/v1/auth/new-password" 400 "$weak_reset"
|
||||
|
||||
# Refresh token
|
||||
local refresh_token=$(curl -s -X POST -H "Content-Type: application/json" \
|
||||
-d "$(jq -n '{email: "admin@example.com", password: "password"}')" \
|
||||
@@ -40,6 +75,14 @@ test_authentication_endpoints() {
|
||||
local refresh_data
|
||||
refresh_data=$(jq -n --arg token "$refresh_token" '{refresh_token: $token}')
|
||||
test_api_endpoint "Refresh Token Test" "POST" "/v1/auth/refresh" 200 "$refresh_data"
|
||||
|
||||
# Security: Test invalid refresh token
|
||||
local invalid_refresh=$(jq -n '{refresh_token: "invalid_token_12345"}')
|
||||
test_api_endpoint "Invalid Refresh Token (Should Fail)" "POST" "/v1/auth/refresh" 401 "$invalid_refresh"
|
||||
|
||||
# Security: Test expired/malformed refresh token
|
||||
local malformed_refresh=$(jq -n '{refresh_token: "Bearer.malformed.token"}')
|
||||
test_api_endpoint "Malformed Refresh Token (Should Fail)" "POST" "/v1/auth/refresh" 401 "$malformed_refresh"
|
||||
else
|
||||
write_test_log "WARN" "✗ Refresh Token Test - Dilewati: Refresh token tidak tersedia dari login"
|
||||
fi
|
||||
@@ -48,6 +91,10 @@ test_authentication_endpoints() {
|
||||
local resend_data=$(jq -n '{email: "admin@example.com"}')
|
||||
test_api_endpoint "Resend OTP" "POST" "/v1/auth/send-otp" 200 "$resend_data" false
|
||||
|
||||
# Security: Test resend OTP with invalid email
|
||||
local invalid_otp=$(jq -n '{email: "not_an_email"}')
|
||||
test_api_endpoint "Resend OTP with Invalid Email (Should Fail)" "POST" "/v1/auth/send-otp" 400 "$invalid_otp"
|
||||
|
||||
# Logout (skip - endpoint may not exist)
|
||||
# test_api_endpoint "Logout" "POST" "/v1/auth/logout" 200 "" true
|
||||
}
|
||||
|
||||
@@ -13,10 +13,20 @@ test_roles_and_permissions() {
|
||||
test_api_endpoint "GET Roles List" "GET" "/v1/roles" 200 "" true
|
||||
test_api_endpoint "GET Roles (Paginated)" "GET" "/v1/roles?page=1&limit=10" 200 "" true
|
||||
|
||||
# Security: Test unauthorized access to roles
|
||||
local saved_token="$AUTH_TOKEN"
|
||||
AUTH_TOKEN=""
|
||||
test_api_endpoint "GET Roles without Auth (Should Fail)" "GET" "/v1/roles" 401 "" false
|
||||
AUTH_TOKEN="$saved_token"
|
||||
|
||||
# Get role by ID - use correct endpoint /detail/{id}
|
||||
local test_role_id="5713cb37-dc02-4e87-8048-d7a41d352059"
|
||||
test_api_endpoint "GET Role By ID" "GET" "/v1/roles/detail/$test_role_id" 200 "" true
|
||||
|
||||
# Security: Test access to non-existent role
|
||||
local fake_role_id="00000000-0000-0000-0000-000000000000"
|
||||
test_api_endpoint "GET Non-existent Role (Should Fail)" "GET" "/v1/roles/detail/$fake_role_id" 404 "" true
|
||||
|
||||
# Create role - use correct endpoint /create
|
||||
local create_role_data=$(jq -n '{
|
||||
name: "Test Role '$(date +%s)'",
|
||||
@@ -27,6 +37,9 @@ test_roles_and_permissions() {
|
||||
local created_role_id=$(echo "$create_role_response" | jq -r '.data.id // empty')
|
||||
|
||||
if [ -n "$created_role_id" ]; then
|
||||
# Security: Test duplicate role creation
|
||||
test_api_endpoint "POST Create Duplicate Role (Should Fail)" "POST" "/v1/roles/create" 400 "$create_role_data" true
|
||||
|
||||
# Update role - use correct endpoint /update/{id}
|
||||
local update_role_data=$(jq -n --arg ts "$EPOCHSECONDS" '{
|
||||
name: ("Updated Test Role " + $ts),
|
||||
@@ -35,14 +48,27 @@ test_roles_and_permissions() {
|
||||
}')
|
||||
test_api_endpoint "PUT Update Role" "PUT" "/v1/roles/update/$created_role_id" 200 "$update_role_data" true
|
||||
|
||||
# Security: Test unauthorized update
|
||||
AUTH_TOKEN=""
|
||||
test_api_endpoint "PUT Update Role without Auth (Should Fail)" "PUT" "/v1/roles/update/$created_role_id" 401 "$update_role_data" false
|
||||
AUTH_TOKEN="$saved_token"
|
||||
|
||||
# Delete role - use correct endpoint /delete/{id}
|
||||
test_api_endpoint "DELETE Role" "DELETE" "/v1/roles/delete/$created_role_id" 200 "" true
|
||||
|
||||
# Security: Test double delete
|
||||
test_api_endpoint "DELETE Already Deleted Role (Should Fail)" "DELETE" "/v1/roles/delete/$created_role_id" 404 "" true
|
||||
fi
|
||||
|
||||
# Permissions
|
||||
test_api_endpoint "GET Permissions List" "GET" "/v1/permissions" 200 "" true
|
||||
test_api_endpoint "GET Permissions (Paginated)" "GET" "/v1/permissions?page=1&limit=10" 200 "" true
|
||||
|
||||
# Security: Test unauthorized access to permissions
|
||||
AUTH_TOKEN=""
|
||||
test_api_endpoint "GET Permissions without Auth (Should Fail)" "GET" "/v1/permissions" 401 "" false
|
||||
AUTH_TOKEN="$saved_token"
|
||||
|
||||
# Get permission by ID - use correct endpoint /detail/{id}
|
||||
local test_perm_id="023e2dfe-93c3-4008-94a8-b5dff403f73b"
|
||||
test_api_endpoint "GET Permission By ID" "GET" "/v1/permissions/detail/$test_perm_id" 200 "" true
|
||||
|
||||
@@ -0,0 +1,590 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==============================================================================
|
||||
# IAM Tests - Security & Authorization Tests
|
||||
# ==============================================================================
|
||||
|
||||
source "$(dirname "$0")/../common/test-common.sh"
|
||||
|
||||
test_unauthorized_access() {
|
||||
printf "\n${CYAN}=== Testing Unauthorized Access ===${NC}\n"
|
||||
|
||||
# Test protected endpoints without authentication token
|
||||
test_api_endpoint "GET Users without Auth" "GET" "/v1/users" 401 "" false
|
||||
test_api_endpoint "GET User Me without Auth" "GET" "/v1/users/me" 401 "" false
|
||||
test_api_endpoint "GET Roles without Auth" "GET" "/v1/roles" 401 "" false
|
||||
test_api_endpoint "GET Permissions without Auth" "GET" "/v1/permissions" 401 "" false
|
||||
test_api_endpoint "GET Teams Admin without Auth" "GET" "/v1/teams/admin" 401 "" false
|
||||
test_api_endpoint "GET Mentors without Auth" "GET" "/v1/mentors" 401 "" false
|
||||
|
||||
# Test CMS endpoints - some may return 404 if not implemented
|
||||
local cms_response=$(curl -s -w "\n%{http_code}" "$BASE_URL/v1/cms/events")
|
||||
local cms_code=$(echo "$cms_response" | tail -1)
|
||||
if [ "$cms_code" = "401" ] || [ "$cms_code" = "404" ]; then
|
||||
write_test_log "SUCCESS" "✓ CMS Events endpoint properly protected or not implemented (code: $cms_code)"
|
||||
else
|
||||
write_test_log "WARN" "✗ CMS Events endpoint returned unexpected code: $cms_code"
|
||||
fi
|
||||
|
||||
test_api_endpoint "GET Gacha Items without Auth" "GET" "/v1/gacha/items" 401 "" false
|
||||
|
||||
# Hackathon admin endpoint may return 404 if not implemented
|
||||
local hackathon_response=$(curl -s -w "\n%{http_code}" "$BASE_URL/v1/hackathon")
|
||||
local hackathon_code=$(echo "$hackathon_response" | tail -1)
|
||||
if [ "$hackathon_code" = "401" ] || [ "$hackathon_code" = "404" ]; then
|
||||
write_test_log "SUCCESS" "✓ Hackathon endpoint properly protected or not implemented (code: $hackathon_code)"
|
||||
else
|
||||
write_test_log "WARN" "✗ Hackathon endpoint returned unexpected code: $hackathon_code"
|
||||
fi
|
||||
}
|
||||
|
||||
test_invalid_token_access() {
|
||||
printf "\n${CYAN}=== Testing Invalid/Expired Token Access ===${NC}\n"
|
||||
|
||||
# Save the original token
|
||||
local original_token="$AUTH_TOKEN"
|
||||
|
||||
# Test with invalid token
|
||||
AUTH_TOKEN="invalid_token_12345"
|
||||
test_api_endpoint "GET Users with Invalid Token" "GET" "/v1/users" 401 "" true
|
||||
test_api_endpoint "GET User Me with Invalid Token" "GET" "/v1/users/me" 401 "" true
|
||||
|
||||
# Test with malformed token
|
||||
AUTH_TOKEN="Bearer.malformed.token"
|
||||
test_api_endpoint "GET Users with Malformed Token" "GET" "/v1/users" 401 "" true
|
||||
|
||||
# Test with empty token
|
||||
AUTH_TOKEN=""
|
||||
test_api_endpoint "GET Users with Empty Token" "GET" "/v1/users" 401 "" true
|
||||
|
||||
# Restore original token
|
||||
AUTH_TOKEN="$original_token"
|
||||
}
|
||||
|
||||
test_role_based_access_control() {
|
||||
printf "\n${CYAN}=== Testing Role-Based Access Control ===${NC}\n"
|
||||
|
||||
# Create a regular user (non-admin) and try to access admin endpoints
|
||||
local regular_user_email="regular_user_$(date +%s)@example.com"
|
||||
local create_user_data=$(jq -n \
|
||||
--arg email "$regular_user_email" \
|
||||
--arg pass "RegularUser123!" \
|
||||
--arg fullname "Regular User Test" \
|
||||
'{
|
||||
email: $email,
|
||||
password: $pass,
|
||||
fullname: $fullname,
|
||||
phone_number: "081234567890",
|
||||
is_active: true,
|
||||
role_id: "5713cb37-dc02-4e87-8048-d7a41d352059"
|
||||
}')
|
||||
|
||||
local create_response=$(curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
-d "$create_user_data" \
|
||||
"$BASE_URL/v1/users/create")
|
||||
|
||||
local created_user_id=$(echo "$create_response" | jq -r '.data.id // empty')
|
||||
|
||||
if [ -n "$created_user_id" ]; then
|
||||
# Login as regular user
|
||||
local user_login=$(jq -n --arg email "$regular_user_email" --arg pass "RegularUser123!" '{email: $email, password: $pass}')
|
||||
local login_response=$(curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$user_login" \
|
||||
"$BASE_URL/v1/auth/login")
|
||||
|
||||
local user_token=$(echo "$login_response" | jq -r '.data.token.access_token // empty')
|
||||
|
||||
if [ -n "$user_token" ]; then
|
||||
# Save admin token
|
||||
local admin_token="$AUTH_TOKEN"
|
||||
AUTH_TOKEN="$user_token"
|
||||
|
||||
# Try to access admin endpoints with regular user token
|
||||
test_api_endpoint "Regular User Access Admin Teams" "GET" "/v1/teams/admin" 403 "" true
|
||||
|
||||
# Try to create role - endpoint might be POST /v1/roles/create with 403 or POST /v1/roles with 405
|
||||
local create_role_response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $user_token" \
|
||||
-d '{"name":"test_role","description":"test","permissions":[]}' \
|
||||
"$BASE_URL/v1/roles/create")
|
||||
local role_code=$(echo "$create_role_response" | tail -1)
|
||||
if [ "$role_code" = "403" ] || [ "$role_code" = "405" ]; then
|
||||
write_test_log "SUCCESS" "✓ Regular User Create Role properly denied (code: $role_code)"
|
||||
else
|
||||
write_test_log "ERROR" "✗ Regular User Create Role not properly denied (code: $role_code)"
|
||||
fi
|
||||
|
||||
test_api_endpoint "Regular User Delete User" "DELETE" "/v1/users/delete/$created_user_id" 403 "" true
|
||||
|
||||
# Regular user should be able to access their own profile
|
||||
test_api_endpoint "Regular User Access Own Profile" "GET" "/v1/users/me" 200 "" true
|
||||
|
||||
# Restore admin token
|
||||
AUTH_TOKEN="$admin_token"
|
||||
else
|
||||
write_test_log "WARN" "Failed to login as regular user for RBAC tests"
|
||||
fi
|
||||
|
||||
# Cleanup: Delete the created user
|
||||
curl -s -X DELETE \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
"$BASE_URL/v1/users/delete/$created_user_id" > /dev/null
|
||||
else
|
||||
write_test_log "WARN" "Failed to create regular user for RBAC tests"
|
||||
fi
|
||||
}
|
||||
|
||||
test_csrf_and_headers() {
|
||||
printf "\n${CYAN}=== Testing CSRF and Security Headers ===${NC}\n"
|
||||
|
||||
# Test that server returns appropriate security headers
|
||||
local response_headers=$(curl -s -I "$BASE_URL/v1/auth/login")
|
||||
|
||||
# Check for security headers (these may vary based on your implementation)
|
||||
if echo "$response_headers" | grep -iq "X-Content-Type-Options"; then
|
||||
write_test_log "SUCCESS" "✓ X-Content-Type-Options header present"
|
||||
else
|
||||
write_test_log "WARN" "✗ X-Content-Type-Options header missing"
|
||||
fi
|
||||
|
||||
if echo "$response_headers" | grep -iq "X-Frame-Options"; then
|
||||
write_test_log "SUCCESS" "✓ X-Frame-Options header present"
|
||||
else
|
||||
write_test_log "WARN" "✗ X-Frame-Options header missing"
|
||||
fi
|
||||
|
||||
# Test CORS headers
|
||||
local cors_response=$(curl -s -I -H "Origin: https://malicious-site.com" "$BASE_URL/v1/auth/login")
|
||||
if echo "$cors_response" | grep -iq "Access-Control-Allow-Origin"; then
|
||||
write_test_log "INFO" "CORS headers present - verify configuration"
|
||||
fi
|
||||
}
|
||||
|
||||
test_sql_injection_attempts() {
|
||||
printf "\n${CYAN}=== Testing SQL Injection Protection ===${NC}\n"
|
||||
|
||||
# Test SQL injection in login - should fail validation (400) or auth (401)
|
||||
local sql_injection_login=$(jq -n '{email: "admin@example.com\" OR \"1\"=\"1", password: "password"}')
|
||||
local response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$sql_injection_login" \
|
||||
"$BASE_URL/v1/auth/login")
|
||||
local http_code=$(echo "$response" | tail -1)
|
||||
if [ "$http_code" = "400" ] || [ "$http_code" = "401" ]; then
|
||||
write_test_log "SUCCESS" "✓ SQL Injection in Login Email properly rejected (code: $http_code)"
|
||||
else
|
||||
write_test_log "ERROR" "✗ SQL Injection in Login Email not properly handled (code: $http_code)"
|
||||
fi
|
||||
|
||||
local sql_injection_pass=$(jq -n '{email: "admin@example.com", password: "password\" OR \"1\"=\"1"}')
|
||||
test_api_endpoint "SQL Injection in Login Password" "POST" "/v1/auth/login" 401 "$sql_injection_pass" false
|
||||
|
||||
# Test SQL injection in search parameters - properly URL encode
|
||||
local search_injection=$(printf "%s" "admin' OR '1'='1" | jq -sRr @uri)
|
||||
local response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
"$BASE_URL/v1/users?search=$search_injection")
|
||||
local http_code=$(echo "$response" | tail -1)
|
||||
if [ "$http_code" = "200" ]; then
|
||||
local body=$(echo "$response" | sed '$d')
|
||||
# Check if it returned all users or properly filtered
|
||||
local count=$(echo "$body" | jq '.data | length' 2>/dev/null || echo "0")
|
||||
write_test_log "SUCCESS" "✓ SQL Injection in User Search handled safely (returned $count users)"
|
||||
else
|
||||
write_test_log "WARN" "✗ SQL Injection in User Search failed (code: $http_code)"
|
||||
fi
|
||||
|
||||
# Test UNION injection
|
||||
local union_injection=$(printf "%s" "' UNION SELECT * FROM users--" | jq -sRr @uri)
|
||||
local response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
"$BASE_URL/v1/users?search=$union_injection")
|
||||
local http_code=$(echo "$response" | tail -1)
|
||||
if [ "$http_code" = "200" ]; then
|
||||
write_test_log "SUCCESS" "✓ SQL Injection UNION attack handled safely"
|
||||
else
|
||||
write_test_log "WARN" "✗ SQL Injection UNION test failed (code: $http_code)"
|
||||
fi
|
||||
|
||||
# Test sort injection
|
||||
local sort_injection=$(printf "%s" "email; DROP TABLE users--" | jq -sRr @uri)
|
||||
local response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
"$BASE_URL/v1/users?sort_by=$sort_injection")
|
||||
local http_code=$(echo "$response" | tail -1)
|
||||
if [ "$http_code" = "200" ] || [ "$http_code" = "400" ]; then
|
||||
write_test_log "SUCCESS" "✓ SQL Injection in Sort Parameter handled safely (code: $http_code)"
|
||||
else
|
||||
write_test_log "WARN" "✗ SQL Injection in Sort test failed (code: $http_code)"
|
||||
fi
|
||||
}
|
||||
|
||||
test_xss_attempts() {
|
||||
printf "\n${CYAN}=== Testing XSS Protection ===${NC}\n"
|
||||
|
||||
# Create user with XSS payloads
|
||||
local xss_email="xss_test_$(date +%s)@example.com"
|
||||
local xss_user_data=$(jq -n \
|
||||
--arg email "$xss_email" \
|
||||
--arg fullname "<script>alert('XSS')</script>" \
|
||||
--arg phone "<img src=x onerror=alert('XSS')>" \
|
||||
'{
|
||||
email: $email,
|
||||
password: "Test123!SecurePass",
|
||||
fullname: $fullname,
|
||||
phone_number: $phone,
|
||||
is_active: true,
|
||||
role_id: "5713cb37-dc02-4e87-8048-d7a41d352059"
|
||||
}')
|
||||
|
||||
local xss_response=$(curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
-d "$xss_user_data" \
|
||||
"$BASE_URL/v1/users/create")
|
||||
|
||||
local xss_user_id=$(echo "$xss_response" | jq -r '.data.id // empty')
|
||||
|
||||
if [ -n "$xss_user_id" ]; then
|
||||
# Retrieve the user and check if XSS payload is escaped/sanitized
|
||||
local get_user_response=$(curl -s \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
"$BASE_URL/v1/users/detail/$xss_user_id")
|
||||
|
||||
local fullname=$(echo "$get_user_response" | jq -r '.data.fullname // empty')
|
||||
|
||||
# Check if dangerous characters are escaped or removed
|
||||
if [[ "$fullname" == *"<script>"* ]] && [[ "$fullname" == *"</script>"* ]]; then
|
||||
write_test_log "ERROR" "✗ XSS payload not sanitized in fullname - SECURITY RISK!"
|
||||
elif [[ "$fullname" == *"<script>"* ]] || [[ "$fullname" != *"<"* ]]; then
|
||||
write_test_log "SUCCESS" "✓ XSS payload properly handled in fullname (escaped or stripped)"
|
||||
else
|
||||
write_test_log "SUCCESS" "✓ XSS payload handled in fullname (modified: $fullname)"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
curl -s -X DELETE \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
"$BASE_URL/v1/users/delete/$xss_user_id" > /dev/null
|
||||
else
|
||||
write_test_log "WARN" "Could not create user with XSS payload to test sanitization"
|
||||
fi
|
||||
}
|
||||
|
||||
test_rate_limiting() {
|
||||
printf "\n${CYAN}=== Testing Rate Limiting ===${NC}\n"
|
||||
|
||||
# Test rapid login attempts
|
||||
write_test_log "INFO" "Testing rapid login attempts (rate limiting)..."
|
||||
|
||||
local rate_limit_triggered=false
|
||||
for i in {1..20}; do
|
||||
local response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"admin@example.com","password":"wrongpassword"}' \
|
||||
"$BASE_URL/v1/auth/login")
|
||||
|
||||
local http_code=$(echo "$response" | tail -1)
|
||||
|
||||
if [ "$http_code" = "429" ]; then
|
||||
rate_limit_triggered=true
|
||||
write_test_log "SUCCESS" "✓ Rate limiting triggered after $i attempts"
|
||||
break
|
||||
fi
|
||||
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
if [ "$rate_limit_triggered" = false ]; then
|
||||
write_test_log "WARN" "✗ Rate limiting not detected (or threshold > 20 attempts)"
|
||||
fi
|
||||
}
|
||||
|
||||
test_password_security() {
|
||||
printf "\n${CYAN}=== Testing Password Security ===${NC}\n"
|
||||
|
||||
# Test weak passwords - they should be rejected (400 or 422)
|
||||
local weak_passwords=("123456" "admin" "test" "abc123" "password123")
|
||||
|
||||
for weak_pass in "${weak_passwords[@]}"; do
|
||||
local weak_user_data=$(jq -n \
|
||||
--arg email "weak_$(date +%s)_${RANDOM}@example.com" \
|
||||
--arg pass "$weak_pass" \
|
||||
'{
|
||||
email: $email,
|
||||
password: $pass,
|
||||
fullname: "Weak Password Test",
|
||||
phone_number: "081234567890",
|
||||
is_active: true,
|
||||
role_id: "5713cb37-dc02-4e87-8048-d7a41d352059"
|
||||
}')
|
||||
|
||||
local response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
-d "$weak_user_data" \
|
||||
"$BASE_URL/v1/users/create")
|
||||
|
||||
local http_code=$(echo "$response" | tail -1)
|
||||
|
||||
if [ "$http_code" = "400" ] || [ "$http_code" = "422" ]; then
|
||||
write_test_log "SUCCESS" "✓ Weak password '$weak_pass' rejected"
|
||||
else
|
||||
write_test_log "WARN" "✗ Weak password '$weak_pass' accepted (code: $http_code)"
|
||||
# Cleanup if created
|
||||
if [ "$http_code" = "201" ]; then
|
||||
local user_id=$(echo "$response" | sed '$d' | jq -r '.data.id // empty')
|
||||
if [ -n "$user_id" ]; then
|
||||
curl -s -X DELETE -H "Authorization: Bearer $AUTH_TOKEN" "$BASE_URL/v1/users/delete/$user_id" > /dev/null
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep 0.1
|
||||
done
|
||||
}
|
||||
|
||||
test_data_exposure() {
|
||||
printf "\n${CYAN}=== Testing Data Exposure Prevention ===${NC}\n"
|
||||
|
||||
# Ensure passwords are not returned in responses
|
||||
local user_response=$(curl -s \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
"$BASE_URL/v1/users/me")
|
||||
|
||||
if echo "$user_response" | jq -e '.data.password' > /dev/null 2>&1; then
|
||||
write_test_log "ERROR" "✗ Password field exposed in user response"
|
||||
else
|
||||
write_test_log "SUCCESS" "✓ Password field not exposed in user response"
|
||||
fi
|
||||
|
||||
# Test that error messages don't expose sensitive information
|
||||
local error_response=$(curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"nonexistent@example.com","password":"password"}' \
|
||||
"$BASE_URL/v1/auth/login")
|
||||
|
||||
local error_msg=$(echo "$error_response" | jq -r '.message // empty' | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# Check that error doesn't reveal if user exists
|
||||
if [[ "$error_msg" == *"user not found"* ]] || [[ "$error_msg" == *"user does not exist"* ]]; then
|
||||
write_test_log "WARN" "✗ Error message reveals user existence"
|
||||
else
|
||||
write_test_log "SUCCESS" "✓ Generic error message for invalid login"
|
||||
fi
|
||||
}
|
||||
|
||||
test_authorization_bypass() {
|
||||
printf "\n${CYAN}=== Testing Authorization Bypass Attempts ===${NC}\n"
|
||||
|
||||
# Test accessing other users' data
|
||||
local all_users=$(curl -s \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
"$BASE_URL/v1/users")
|
||||
|
||||
local other_user_id=$(echo "$all_users" | jq -r '.data[1].id // empty')
|
||||
|
||||
if [ -n "$other_user_id" ]; then
|
||||
# Create a new user
|
||||
local test_user_email="bypass_test_$(date +%s)@example.com"
|
||||
local create_user_data=$(jq -n \
|
||||
--arg email "$test_user_email" \
|
||||
'{
|
||||
email: $email,
|
||||
password: "Test123!",
|
||||
fullname: "Bypass Test User",
|
||||
phone_number: "081234567890",
|
||||
is_active: true,
|
||||
role_id: "5713cb37-dc02-4e87-8048-d7a41d352059"
|
||||
}')
|
||||
|
||||
local create_response=$(curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
-d "$create_user_data" \
|
||||
"$BASE_URL/v1/users/create")
|
||||
|
||||
local new_user_id=$(echo "$create_response" | jq -r '.data.id // empty')
|
||||
|
||||
if [ -n "$new_user_id" ]; then
|
||||
# Login as new user
|
||||
local user_login=$(jq -n --arg email "$test_user_email" '{email: $email, password: "Test123!"}')
|
||||
local login_response=$(curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$user_login" \
|
||||
"$BASE_URL/v1/auth/login")
|
||||
|
||||
local new_user_token=$(echo "$login_response" | jq -r '.data.token.access_token // empty')
|
||||
|
||||
if [ -n "$new_user_token" ]; then
|
||||
# Try to update another user's data
|
||||
local admin_token="$AUTH_TOKEN"
|
||||
AUTH_TOKEN="$new_user_token"
|
||||
|
||||
local update_data=$(jq -n '{fullname: "Hacked User"}')
|
||||
test_api_endpoint "User Update Other User" "PUT" "/v1/users/update/$other_user_id" 403 "$update_data" true
|
||||
|
||||
# Try to delete another user
|
||||
test_api_endpoint "User Delete Other User" "DELETE" "/v1/users/delete/$other_user_id" 403 "" true
|
||||
|
||||
# Restore admin token
|
||||
AUTH_TOKEN="$admin_token"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
curl -s -X DELETE \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
"$BASE_URL/v1/users/delete/$new_user_id" > /dev/null
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
test_input_validation() {
|
||||
printf "\n${CYAN}=== Testing Input Validation ===${NC}\n"
|
||||
|
||||
# Test invalid email formats
|
||||
local invalid_emails=("notanemail" "test@" "@example.com")
|
||||
|
||||
for invalid_email in "${invalid_emails[@]}"; do
|
||||
local invalid_data=$(jq -n \
|
||||
--arg email "$invalid_email" \
|
||||
'{
|
||||
email: $email,
|
||||
password: "Test123!SecurePass",
|
||||
fullname: "Invalid Email Test",
|
||||
phone_number: "081234567890",
|
||||
is_active: true,
|
||||
role_id: "5713cb37-dc02-4e87-8048-d7a41d352059"
|
||||
}')
|
||||
|
||||
local response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
-d "$invalid_data" \
|
||||
"$BASE_URL/v1/users/create")
|
||||
|
||||
local http_code=$(echo "$response" | tail -1)
|
||||
|
||||
if [ "$http_code" = "400" ] || [ "$http_code" = "422" ]; then
|
||||
write_test_log "SUCCESS" "✓ Invalid email '$invalid_email' rejected"
|
||||
else
|
||||
write_test_log "WARN" "✗ Invalid email '$invalid_email' accepted (code: $http_code)"
|
||||
# Cleanup if created
|
||||
if [ "$http_code" = "201" ]; then
|
||||
local user_id=$(echo "$response" | sed '$d' | jq -r '.data.id // empty')
|
||||
if [ -n "$user_id" ]; then
|
||||
curl -s -X DELETE -H "Authorization: Bearer $AUTH_TOKEN" "$BASE_URL/v1/users/delete/$user_id" > /dev/null
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Test excessively long inputs (reduced to 500 chars to be more reasonable)
|
||||
local long_string=$(printf 'A%.0s' {1..500})
|
||||
local long_input_data=$(jq -n \
|
||||
--arg email "long_$(date +%s)@example.com" \
|
||||
--arg fullname "$long_string" \
|
||||
'{
|
||||
email: $email,
|
||||
password: "Test123!SecurePass",
|
||||
fullname: $fullname,
|
||||
phone_number: "081234567890",
|
||||
is_active: true,
|
||||
role_id: "5713cb37-dc02-4e87-8048-d7a41d352059"
|
||||
}')
|
||||
|
||||
local response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
-d "$long_input_data" \
|
||||
"$BASE_URL/v1/users/create")
|
||||
|
||||
local http_code=$(echo "$response" | tail -1)
|
||||
|
||||
if [ "$http_code" = "400" ] || [ "$http_code" = "422" ]; then
|
||||
write_test_log "SUCCESS" "✓ Excessively long input rejected"
|
||||
else
|
||||
write_test_log "WARN" "✗ Excessively long input (500 chars) accepted (code: $http_code)"
|
||||
# Cleanup if created
|
||||
if [ "$http_code" = "201" ]; then
|
||||
local user_id=$(echo "$response" | sed '$d' | jq -r '.data.id // empty')
|
||||
if [ -n "$user_id" ]; then
|
||||
curl -s -X DELETE -H "Authorization: Bearer $AUTH_TOKEN" "$BASE_URL/v1/users/delete/$user_id" > /dev/null
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
test_session_management() {
|
||||
printf "\n${CYAN}=== Testing Session Management ===${NC}\n"
|
||||
|
||||
# Test token expiration (if applicable)
|
||||
write_test_log "INFO" "Testing session management..."
|
||||
|
||||
# Test logout functionality - try common logout endpoints
|
||||
local logout_endpoints=("/v1/auth/logout" "/v1/auth/signout" "/v2/auth/logout")
|
||||
local logout_exists=false
|
||||
|
||||
for endpoint in "${logout_endpoints[@]}"; do
|
||||
local logout_response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
"$BASE_URL$endpoint")
|
||||
|
||||
local logout_code=$(echo "$logout_response" | tail -1)
|
||||
|
||||
if [ "$logout_code" = "200" ] || [ "$logout_code" = "204" ]; then
|
||||
write_test_log "SUCCESS" "✓ Logout endpoint exists at $endpoint (code: $logout_code)"
|
||||
logout_exists=true
|
||||
|
||||
# Try to use token after logout
|
||||
local saved_token="$AUTH_TOKEN"
|
||||
local after_logout_response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: Bearer $saved_token" \
|
||||
"$BASE_URL/v1/users/me")
|
||||
|
||||
local after_logout_code=$(echo "$after_logout_response" | tail -1)
|
||||
|
||||
if [ "$after_logout_code" = "401" ]; then
|
||||
write_test_log "SUCCESS" "✓ Token invalidated after logout"
|
||||
else
|
||||
write_test_log "WARN" "✗ Token still valid after logout (code: $after_logout_code)"
|
||||
fi
|
||||
|
||||
# Re-authenticate for remaining tests
|
||||
get_auth_token
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$logout_exists" = false ]; then
|
||||
write_test_log "WARN" "⚠ Logout endpoint not found (tested: ${logout_endpoints[*]})"
|
||||
fi
|
||||
}
|
||||
|
||||
# Run all security tests
|
||||
run_security_tests() {
|
||||
test_unauthorized_access
|
||||
test_invalid_token_access
|
||||
test_role_based_access_control
|
||||
test_csrf_and_headers
|
||||
test_sql_injection_attempts
|
||||
test_xss_attempts
|
||||
test_rate_limiting
|
||||
test_password_security
|
||||
test_data_exposure
|
||||
test_authorization_bypass
|
||||
test_input_validation
|
||||
test_session_management
|
||||
}
|
||||
|
||||
# Run if executed directly
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
get_auth_token
|
||||
run_security_tests
|
||||
print_test_summary
|
||||
[ "$FAIL_COUNT" -eq 0 ] && exit 0 || exit 1
|
||||
fi
|
||||
@@ -9,15 +9,29 @@ source "$(dirname "$0")/../common/test-common.sh"
|
||||
test_user_management_endpoints() {
|
||||
printf "\n${CYAN}=== Testing User Management Endpoints ===${NC}\n"
|
||||
|
||||
# Security: Test that endpoints require authentication
|
||||
local saved_token="$AUTH_TOKEN"
|
||||
AUTH_TOKEN=""
|
||||
test_api_endpoint "GET Users without Auth (Should Fail)" "GET" "/v1/users" 401 "" false
|
||||
AUTH_TOKEN="$saved_token"
|
||||
|
||||
# Get users list
|
||||
test_api_endpoint "GET Users List" "GET" "/v1/users" 200 "" true
|
||||
test_api_endpoint "GET Users (Paginated)" "GET" "/v1/users?page=1&limit=10" 200 "" true
|
||||
test_api_endpoint "GET Users (Search)" "GET" "/v1/users?search=admin" 200 "" true
|
||||
test_api_endpoint "GET Users (Sorted)" "GET" "/v1/users?sort_by=created_at&order=DESC" 200 "" true
|
||||
|
||||
# Security: Test SQL injection in search
|
||||
test_api_endpoint "GET Users with SQL Injection (Should Be Safe)" "GET" "/v1/users?search=' OR '1'='1" 200 "" true
|
||||
|
||||
# Get user me
|
||||
test_api_endpoint "GET User Me" "GET" "/v1/users/me" 200 "" true
|
||||
|
||||
# Security: Test access without token
|
||||
AUTH_TOKEN=""
|
||||
test_api_endpoint "GET User Me without Auth (Should Fail)" "GET" "/v1/users/me" 401 "" false
|
||||
AUTH_TOKEN="$saved_token"
|
||||
|
||||
# Update user me - use correct endpoint /update/me
|
||||
local update_me_data=$(jq -n '{
|
||||
fullname: "Updated Admin User",
|
||||
@@ -27,10 +41,20 @@ test_user_management_endpoints() {
|
||||
}')
|
||||
test_api_endpoint "PUT User Me" "PUT" "/v1/users/update/me" 200 "$update_me_data" true
|
||||
|
||||
# Security: Test XSS in user update
|
||||
local xss_update_data=$(jq -n '{
|
||||
fullname: "<script>alert(\"XSS\")</script>",
|
||||
phone_number: "081234567890"
|
||||
}')
|
||||
test_api_endpoint "PUT User Me with XSS (Should Be Sanitized)" "PUT" "/v1/users/update/me" 200 "$xss_update_data" true
|
||||
|
||||
# Get user by ID
|
||||
local test_user_id="c3b1d6a8-8d4f-4b36-b789-2e532ec7a7b2"
|
||||
test_api_endpoint "GET User By ID" "GET" "/v1/users/detail/$test_user_id" 200 "" true
|
||||
|
||||
# Security: Test access to non-existent user
|
||||
test_api_endpoint "GET Non-existent User (Should Fail)" "GET" "/v1/users/detail/00000000-0000-0000-0000-000000000000" 404 "" true
|
||||
|
||||
# Create new user
|
||||
local new_user_email="test_user_$(date +%s)@example.com"
|
||||
local create_user_data=$(jq -n \
|
||||
@@ -51,6 +75,20 @@ test_user_management_endpoints() {
|
||||
local created_user_id=$(echo "$create_response" | jq -r '.data.id // empty')
|
||||
|
||||
if [ -n "$created_user_id" ]; then
|
||||
# Security: Test duplicate email
|
||||
test_api_endpoint "POST Create Duplicate User (Should Fail)" "POST" "/v1/users/create" 400 "$create_user_data" true
|
||||
|
||||
# Security: Test invalid email format
|
||||
local invalid_email_data=$(jq -n '{
|
||||
email: "not_an_email",
|
||||
password: "TestPassword123!",
|
||||
fullname: "Invalid Email User",
|
||||
phone_number: "089876543211",
|
||||
is_active: true,
|
||||
role_id: "5713cb37-dc02-4e87-8048-d7a41d352059"
|
||||
}')
|
||||
test_api_endpoint "POST Create User with Invalid Email (Should Fail)" "POST" "/v1/users/create" 400 "$invalid_email_data" true
|
||||
|
||||
# Update user
|
||||
local update_user_data=$(jq -n \
|
||||
--arg email "updated_$new_user_email" \
|
||||
@@ -66,6 +104,11 @@ test_user_management_endpoints() {
|
||||
}')
|
||||
test_api_endpoint "PUT Update User" "PUT" "/v1/users/update/$created_user_id" 200 "$update_user_data" true
|
||||
|
||||
# Security: Test unauthorized update
|
||||
AUTH_TOKEN=""
|
||||
test_api_endpoint "PUT Update User without Auth (Should Fail)" "PUT" "/v1/users/update/$created_user_id" 401 "$update_user_data" false
|
||||
AUTH_TOKEN="$saved_token"
|
||||
|
||||
# Deactivate user - endpoint uses PUT, not PATCH
|
||||
local deactivate_data=$(jq -n '{is_active: false}')
|
||||
test_api_endpoint "PUT Deactivate User" "PUT" "/v1/users/activate/$created_user_id" 200 "$deactivate_data" true
|
||||
@@ -76,6 +119,14 @@ test_user_management_endpoints() {
|
||||
|
||||
# Delete user
|
||||
test_api_endpoint "DELETE User" "DELETE" "/v1/users/delete/$created_user_id" 200 "" true
|
||||
|
||||
# Security: Test double delete
|
||||
test_api_endpoint "DELETE Already Deleted User (Should Fail)" "DELETE" "/v1/users/delete/$created_user_id" 404 "" true
|
||||
|
||||
# Security: Test unauthorized delete
|
||||
AUTH_TOKEN=""
|
||||
test_api_endpoint "DELETE User without Auth (Should Fail)" "DELETE" "/v1/users/delete/$created_user_id" 401 "" false
|
||||
AUTH_TOKEN="$saved_token"
|
||||
else
|
||||
write_test_log "WARN" "Skipping user update/delete tests - failed to create user"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user