You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
4.1 KiB
Python
108 lines
4.1 KiB
Python
#!/usr/bin/env python
|
|
"""
|
|
Test script for API security.
|
|
|
|
This script tests the security features of the API by attempting to access endpoints
|
|
with and without proper authentication.
|
|
"""
|
|
|
|
import requests
|
|
import argparse
|
|
import logging
|
|
import json
|
|
|
|
# Configure logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s [%(levelname)s] %(message)s',
|
|
datefmt='%Y-%m-%d %H:%M:%S'
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def test_api_security(base_url):
|
|
"""
|
|
Test API security features.
|
|
|
|
Args:
|
|
base_url: Base URL of the API
|
|
"""
|
|
logger.info("Testing API security...")
|
|
|
|
# Test health endpoint (should be accessible without authentication)
|
|
logger.info("\nTesting health endpoint (public)...")
|
|
health_url = f"{base_url}/health"
|
|
response = requests.get(health_url)
|
|
logger.info(f"Status code: {response.status_code}")
|
|
if response.status_code == 200:
|
|
logger.info("Success! Health endpoint is publicly accessible as expected.")
|
|
else:
|
|
logger.error("Error: Health endpoint should be publicly accessible.")
|
|
|
|
# Test token endpoint
|
|
logger.info("\nTesting token endpoint...")
|
|
token_url = f"{base_url}/auth/token"
|
|
|
|
# Test with invalid credentials
|
|
logger.info("Testing with empty username...")
|
|
response = requests.post(token_url, json={"username": "", "password": "password"})
|
|
logger.info(f"Status code: {response.status_code}")
|
|
if response.status_code == 400:
|
|
logger.info("Success! Token endpoint rejected empty username as expected.")
|
|
else:
|
|
logger.error("Error: Token endpoint should reject empty username.")
|
|
|
|
# Test with valid credentials
|
|
logger.info("Testing with valid username...")
|
|
response = requests.post(token_url, json={"username": "admin", "password": "password"})
|
|
logger.info(f"Status code: {response.status_code}")
|
|
|
|
if response.status_code == 200:
|
|
token_data = response.json()
|
|
access_token = token_data.get("access_token")
|
|
logger.info("Success! Received valid token.")
|
|
|
|
# Test protected endpoint without token
|
|
logger.info("\nTesting protected endpoint without token...")
|
|
patients_url = f"{base_url}/fhir/Patient"
|
|
response = requests.get(patients_url)
|
|
logger.info(f"Status code: {response.status_code}")
|
|
|
|
if response.status_code in (401, 403):
|
|
logger.info("Success! Access denied without token as expected.")
|
|
else:
|
|
logger.error("Error: Protected endpoint should deny access without token.")
|
|
|
|
# Test protected endpoint with token
|
|
logger.info("\nTesting protected endpoint with token...")
|
|
headers = {"Authorization": f"Bearer {access_token}"}
|
|
response = requests.get(patients_url, headers=headers)
|
|
logger.info(f"Status code: {response.status_code}")
|
|
|
|
if response.status_code == 200:
|
|
logger.info("Success! Access granted with token as expected.")
|
|
else:
|
|
logger.error("Error: Protected endpoint should grant access with token.")
|
|
|
|
# Test admin-only endpoint with user token
|
|
logger.info("\nTesting role-based access control...")
|
|
# For this POC, we use a generic endpoint that requires admin role
|
|
delete_url = f"{base_url}/fhir/Patient/non-existent-id"
|
|
response = requests.delete(delete_url, headers=headers)
|
|
|
|
if response.status_code == 403:
|
|
logger.info("Success! Regular user denied access to admin endpoint as expected.")
|
|
elif response.status_code == 404:
|
|
logger.info("Success! Admin user granted access to admin endpoint as expected.")
|
|
else:
|
|
logger.error(f"Unexpected response code: {response.status_code}")
|
|
else:
|
|
logger.error("Error: Could not obtain token for testing.")
|
|
|
|
logger.info("\nAPI security testing completed.")
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(description='Test API security')
|
|
parser.add_argument('--url', default='http://localhost:8000', help='Base URL of the API')
|
|
args = parser.parse_args()
|
|
|
|
test_api_security(args.url) |