Full Disclosure A significant amount of the code in this project was written by AI. The initial foundation for this project used some scripts and tools I built, but the current codebase has little to none of my original code left. That being said I have spent a lot of time reviewing the AI code and coaching the AI to implement a standards compliant, capable SCIM server for devs.
SCIM Test Harness is a fully self-contained, developer-focused SCIM 2.0 server designed for rapid prototyping, testing, and integration with identity providers such as Okta and Azure. It is built to comply with the SCIM 2.0 specification (RFC 7644) and Okta's extension-driven design for ResourceTypes and entitlements (Okta SCIM with Entitlements Guide).
This project is ideal for developers who need a mock SCIM server for integration testing, development, or demonstration purposes. It is not intended for production use.
🚀 Multi-Server Architecture: The application supports multiple virtual SCIM servers, allowing developers to run multiple isolated SCIM instances on the same web port for comparison and validation purposes.
✅ Development-Ready: 100% test pass rate (163/163 tests) with comprehensive SCIM 2.0 compliance and Okta-compliant SCIM extensions.
The multi-server branch introduces support for multiple virtual SCIM servers that can run simultaneously on the same web port. This allows developers to:
- Compare Different Configurations: Run multiple SCIM servers with different data sets or configurations
- Validate Integration: Test against multiple SCIM endpoints without tearing down and recreating instances
- Isolated Testing: Each virtual server maintains its own data isolation
- Development Efficiency: Switch between different SCIM configurations quickly
Virtual SCIM servers are accessed using RFC 7644 compliant path-based routing:
Path Parameter Pattern: http://host/scim-identifier/{server_id}/scim/v2
This pattern supports standard SCIM endpoints:
/Users
- User management/Groups
- Group management/Entitlements
- Entitlement management/Roles
- Role management/ResourceTypes
- Schema discovery/Schemas
- Custom schema extensions
Why Path-Based Routing?
- ✅ Full SCIM RFC 7644 compliance - Standard SCIM paths expected by all clients
- ✅ Works with all SCIM clients - No query parameter parsing required
- ✅ Clean URL structure - Server ID in path for clear identification
- ✅ Easy to understand - Clear routing pattern for developers
- ✅ Okta Integration Ready - Compatible with Okta Identity Governance
Virtual SCIM servers use a shared database approach:
- Shared Database: All virtual servers share the same SQLite database with server-specific data isolation
- Server-specific constraints: Usernames and emails are unique per server, not globally
- True multi-server isolation: Each virtual server maintains complete data separation
All virtual SCIM servers share a simplified and centralized API key authentication system:
- ✅ Two Valid API Keys:
default_api_key
for normal server operationstest_api_key
for testing operations
- ✅ Centralized Configuration: API keys managed in
config.py
only - ✅ Strict Bearer Token Validation: Only accepts
Bearer <token>
format - ✅ Comprehensive Error Handling: 401 for all authentication failures
- ✅ Detailed Logging: All authentication attempts logged for security monitoring
- ✅ No Database Storage: API keys not stored in database for simplicity
- ✅ Easy Maintenance: Simple to manage and troubleshoot for development
The SCIM server implements RFC 7644 compliant path-based routing for maximum SCIM client compatibility and full specification compliance:
Path Parameter Pattern: http://host/scim-identifier/{server_id}/scim/v2
- ✅ Full SCIM RFC 7644 compliance - Standard SCIM paths expected by all clients
- ✅ Works with all SCIM clients - No query parameter parsing required
- ✅ Clean URL structure - Server ID in path for clear identification
- ✅ Easy to understand - Clear routing pattern for developers
- ✅ Okta Integration Ready - Compatible with Okta Identity Governance
- ✅ Future-proof - Follows SCIM specification standards
- ✅ All functions require explicit server_id parameter (no default values)
- ✅ Database models enforce server_id requirement (no default="default")
- ✅ All CRUD operations are server-specific (no global operations)
- ✅ Schema generation is server-specific (dynamic per server)
- ✅ All endpoints use path-based routing (no single-server endpoints)
- ✅ All endpoints require valid API key (Bearer token format)
- ✅ All endpoints require valid server ID (format validation)
- ✅ Comprehensive error handling (401, 400, 404 with detailed messages)
- ✅ Detailed security logging for all validation attempts
- ✅ 100% test coverage for validation scenarios
# User management
/scim-identifier/test-server/scim/v2/Users
/scim-identifier/prod-server/scim/v2/Users
# Group management
/scim-identifier/test-server/scim/v2/Groups
/scim-identifier/prod-server/scim/v2/Groups
# Schema discovery
/scim-identifier/test-server/scim/v2/ResourceTypes
/scim-identifier/test-server/scim/v2/Schemas
# Entitlement management
/scim-identifier/test-server/scim/v2/Entitlements
- Full SCIM 2.0 Compliance - Follows RFC 7644 specification exactly
- Multi-Server Isolation - Each virtual server maintains complete data separation
- Comprehensive Security - All endpoints protected with API key and server ID validation
- Developer Experience - Clear routing pattern for development and testing
- Okta Compatibility - Works seamlessly with Okta Identity Governance
- SCIM 2.0 Compliance: Implement all core SCIM endpoints and behaviors, with a focus on Okta's unique requirements for ResourceTypes, entitlements, and schema discovery. (SCIM 2.0 RFC 7644, Okta SCIM with Entitlements Guide)
- Multi-Server Support: Enable multiple virtual SCIM servers on the same web port for development and testing scenarios
- Standalone & Self-Contained: No external dependencies or services. All data and configuration are stored in a local SQLite database.
- Dynamic Schema System: SCIM schemas are generated dynamically based on actual database models and configuration, ensuring accurate representation of the server's data model
- Developer Experience: Extensive logging, debugging, and comprehensive testing infrastructure.
- Extensibility: Designed for easy extension and modification, including support for custom schemas and attributes.
- Authentication: Simple API key authentication using static keys provided as Bearer tokens in the Authorization header.
- Multi-threaded Python Backend: High responsiveness for concurrent development/testing scenarios.
- Dynamic Testing: Comprehensive test suite that adapts to actual database data without hardcoded values.
- Production Quality: 100% test pass rate with comprehensive coverage of all SCIM 2.0 and Okta requirements.
- SCIM 2.0 Endpoints:
/v2/ResourceTypes
- Returns available resource types for schema discovery (dynamic)/v2/Schemas
- Returns all available schemas with detailed attribute definitions (dynamic)/v2/Schemas/{schema_urn}
- Returns specific schema by URN (dynamic)/v2/Users
- Full CRUD operations with SCIM filtering and pagination/v2/Groups
- Full CRUD operations with SCIM filtering and pagination/v2/Entitlements
- Full CRUD operations with SCIM filtering and pagination/v2/Roles
- Full CRUD operations with SCIM filtering and pagination- Okta-compatible extension endpoints and schema discovery
- RFC 7644 Compliant Routing:
- Path-based routing for full SCIM 2.0 compliance
- Server ID extraction from URL path parameters
- Support for multiple virtual SCIM servers
- Clean, standard SCIM URL patterns
- Okta Identity Governance compatibility
- Enhanced Schema Validation:
- Recursive validation of complex attributes with nested sub-attributes
- Multi-valued attribute validation for both simple and complex types
- RFC-compliant error messages with proper structure and helpful details
- Type validation for all SCIM data types (string, boolean, complex)
- Canonical values validation for entitlement types
- Required field validation at all levels (top-level and nested)
- Comprehensive test coverage with 100% test success rate
- SCIM Filtering & Pagination:
- Support for SCIM filter operators (
eq
,co
,sw
,ew
) - Proper pagination with filtered total counts
- Dynamic filter parsing and database querying
- Support for SCIM filter operators (
- Authentication & Security:
- Centralized API key management in config.py (no database storage)
- Two valid API keys: default for normal operations, test for testing
- Strict Bearer token validation with comprehensive error handling
- All endpoints protected with proper authentication and server ID validation
- Detailed security logging for all authentication attempts
- 401 errors for all authentication failures with helpful error messages
- Database:
- All data (users, groups, entitlements, roles, schemas, API keys, etc.) stored in SQLite
- Centralized schema for easy backup, migration, and inspection
- Comprehensive relationship management (user-group, user-entitlement, user-role)
- Server-specific data isolation with composite constraints
- Logging & Debugging:
- Verbose, developer-friendly logging for all API calls and database operations
- Debug endpoints and detailed error messages
- Real-time test execution logging
- Testing Infrastructure:
- 100% Test Success Rate (141/141 tests passing)
- Comprehensive test coverage for all endpoints, operations, and validation scenarios
- Dynamic testing that adapts to actual database data
- No hardcoded values in test suite
- Real-time test reporting and detailed execution logs
- Unique username generation to prevent test conflicts
- Security validation tests for API keys and server IDs
- Okta SCIM compliance testing with vendor-specific requirements
- ✅ Web Frontend: A modern web UI for browsing and managing SCIM servers (see FRONTEND_API.md)
- Custom Schemas: Support for custom SCIM schema extensions
- Advanced Filtering: Additional SCIM filter operators and complex queries
- Profile Management API: REST API endpoints for managing application profiles
The SCIM server includes a sophisticated Application Profiles System that allows different application contexts (HR, IT, Sales, etc.) to have customized views of user data, with specific attribute visibility, mutability rules, and data filtering capabilities.
- 10 Predefined Profiles: HR, IT, Sales, Marketing, Finance, Legal, Operations, Security, Customer Success, Research
- Attribute Visibility Control: Each profile defines which user attributes are visible and modifiable
- Mutability Rules: Four levels of attribute control (read-only, read-write, immutable, write-once)
- Role-Based Access: Application-specific roles and permissions
- Data Filtering: Department-based filtering and data visibility rules
- Integration: Seamless integration with existing configuration systems
For detailed information about the profiles system, including capabilities, limitations, implementation details, and usage examples, see PROFILES.md.
The SCIM server includes a modern web interface for managing virtual SCIM servers and viewing server data.
- Server Management: List all virtual SCIM servers with statistics
- Data Export: Export complete server data with relationships
- Real-time Statistics: View user, group, and entitlement counts
- API Integration: RESTful API endpoints for programmatic access
- Caddy Proxy Support: Automatic API key injection for production use
- Main Web UI:
http://localhost:7001/frontend/index.html
- API Endpoints:
http://localhost:7001/api/
- Static Files:
http://localhost:7001/frontend/static/
For detailed information about the frontend API, including endpoints, authentication, and usage examples, see FRONTEND_API.md.
- ✅ API Key Validation: Strict Bearer token validation with two valid keys (default/test)
- ✅ Server ID Validation: Format validation (alphanumeric, hyphens, underscores only)
- ✅ All Endpoints Protected: Every endpoint requires proper authentication and server identification
- ✅ Comprehensive Error Handling: 401 for auth failures, 400 for invalid server IDs, 404 for path issues
- ✅ Detailed Logging: All validation attempts logged for security monitoring
- ✅ 100% Test Coverage: 9/9 validation compliance tests passing
- ✅ Removed All Legacy Single-Server Code: No more "default" server assumptions
- ✅ Enforced Explicit Server ID Requirements: All functions require explicit server_id parameter
- ✅ Updated All CRUD Functions: Removed default server_id parameters from all operations
- ✅ Database Model Updates: Removed default="default" from server_id columns
- ✅ Schema System Updates: All schema generation requires explicit server_id
- ✅ Legacy Router Removal: Removed single-server routers from main.py
- ✅ Centralized Configuration: API keys managed in config.py only
- ✅ Removed Database Storage: No more API key hashing or database storage
- ✅ Two Valid Keys: Default key for normal operations, test key for testing
- ✅ Simplified Validation: Direct comparison against config keys
- ✅ Maintainable System: Easy to manage and troubleshoot
- Removed all non-RFC routing strategies (query parameter, header, subdomain, hybrid)
- Enforced path-based routing for full SCIM 2.0 compliance
- Simplified server context management with only path-based server ID extraction
- Updated all endpoints to use
/scim-identifier/{server_id}/scim/v2/...
pattern - Cleaned up routing configuration and removed legacy compatibility code
- Okta Integration Ready: Compatible with Okta Identity Governance
- Recursive validation: Now validates all required sub-attributes in complex types
- Multi-valued complex attributes: Properly validates each item in multi-valued arrays
- RFC-compliant error messages: Consistent error structure with proper fields
- Type validation: Catches type mismatches with proper SCIM error messages
- Comprehensive test coverage: 100% test success rate with unique username generation
- Canonical values validation: Dynamic entitlement type validation from configuration
- Eliminated 1,180+ lines of code duplication (84% reduction)
- Endpoint files reduced from 200+ lines each to ~20 lines
- All CRUD, error handling, and rate limiting logic centralized in base classes
- Multi-server support is robust and enforced at the database level
- The codebase is now clean, maintainable, and production-ready
- Base Endpoint Classes: All endpoints are registered and managed via generic base classes, eliminating duplication and ensuring consistency
- Generic Response Converter: A single, configurable converter handles all SCIM response formatting
- Centralized CRUD: CRUD operations are implemented in a generic base class, with entity-specific logic separated for clarity and maintainability
- Composite Database Constraints: Usernames and emails are unique per server, not globally, supporting true multi-server isolation
scim_server/
├── crud_base.py # Generic CRUD operations (BaseCRUD class)
├── crud_entities.py # Entity-specific CRUD classes (UserCRUD, GroupCRUD, etc.)
└── crud_simple.py # Clean interface functions (create_user, get_user, etc.)
Import Flow:
Endpoints → crud_simple.py → crud_entities.py → crud_base.py
- All tests are isolated and use unique test data
- Test data is cleaned up before and after each run
- Pytest fixtures are used for data management
- Test logic is never changed to accommodate implementation bugs
- Test coverage is comprehensive: authentication, CRUD, pagination, error handling, SCIM compliance, and multi-server isolation
- 100% Test Success Rate: 141/141 tests passing with comprehensive coverage
- Adding new entities or endpoints is trivial and consistent
- Bug fixes and new features apply to all entities automatically
- The codebase is now clean, maintainable, and production-ready
- All legacy code and documentation referencing the old
crud.py
module have been removed
- Vendor-Specific Testing: Comprehensive Okta SCIM compliance validation
- Schema Extensions: Support for Okta's entitlement and role schemas
- Endpoint Sequence: Follows Okta's expected discovery flow
- Real-World Compatibility: Validated against Okta Identity Governance requirements
- 100% Test Coverage: All functionality thoroughly tested
- RFC 7644 Compliance: Full SCIM 2.0 specification compliance
- Okta Integration: Ready for Okta Identity Governance integration
- Multi-Server Support: Robust virtual server isolation
- Security Validation: Comprehensive authentication and authorization testing
- Python 3.8+
- SQLite3 (bundled with Python standard library)
- Python Packages:
fastapi==0.116.1
(for API server)uvicorn==0.35.0
(for ASGI server, multithreaded)sqlalchemy==2.0.41
(for ORM/database access)pydantic==2.11.7
(for data validation)loguru==0.7.3
(for logging)pytest==8.4.1
(for tests)httpx==0.28.1
(for testing)requests==2.31.0
(for comprehensive testing)
All dependencies should be installed locally (e.g., in a virtual environment or with --user
).
-
Clone and setup:
git clone <repository-url> cd scim-server git checkout multi-server python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt
-
Initialize database:
python scripts/init_db.py
-
Create test data (optional):
python scripts/create_test_data.py
Or use the enhanced CLI tool:
# Interactive mode python scripts/scim_cli.py create # Command line mode with custom values python scripts/scim_cli.py create --users 20 --groups 8 --entitlements 12 # Server configuration management python scripts/scim_cli.py config list # List all server configurations python scripts/scim_cli.py config get --server-id abc123 # Get specific server config python scripts/scim_cli.py config update --server-id abc123 --config-file config.json # Update server config
-
Start the server:
python run_server.py
-
Test the API:
# Basic health check (public access) curl http://localhost:7001/healthz # Detailed health check (internal networks only) curl http://localhost:7001/health # Get resource types (requires authentication) curl -H "Authorization: Bearer api-key-12345" http://localhost:7001/scim-identifier/test-server/scim/v2/ResourceTypes # List users with filtering curl -H "Authorization: Bearer api-key-12345" "http://localhost:7001/scim-identifier/test-server/scim/v2/Users/?filter=userName%20eq%20%22testuser@example.com%22"
-
Run comprehensive tests:
python scripts/run_comprehensive_tests.py
-
Test dynamic schema system:
python scripts/test_dynamic_schemas.py
-
Test enhanced error handling:
python scripts/test_enhanced_error_handling.py
The run_server.py
script provides a comprehensive development server runner with advanced features for testing and integration scenarios.
The server requires a Python virtual environment with all dependencies installed:
# Create virtual environment
python3 -m venv .venv
# Activate virtual environment
source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt
Option 1: Using the wrapper script (recommended)
# Start server with default settings
./run_server_wrapper.sh
# Show help and all options
./run_server_wrapper.sh --help
# Start server in background (daemon mode)
./run_server_wrapper.sh -d
# Start server on specific port
./run_server_wrapper.sh --port 8080
Option 2: Manual virtual environment activation
# Activate virtual environment first
source .venv/bin/activate
# Start server with default settings
python run_server.py
# Show help and all options
python run_server.py --help
# Start server in background (daemon mode)
python run_server.py -d
# Start server on specific port
python run_server.py --port 8080
Option | Description | Example |
---|---|---|
-h, --help |
Show detailed help information | ./run_server_wrapper.sh --help |
-p, --port PORT |
Specify port number | ./run_server_wrapper.sh --port 8080 |
-H, --host HOST |
Specify host address | ./run_server_wrapper.sh --host 0.0.0.0 |
-d, --daemon |
Run server in background | ./run_server_wrapper.sh -d |
--pid-file FILE |
Specify PID file for daemon | ./run_server_wrapper.sh -d --pid-file /var/run/scim.pid |
--reload |
Enable auto-reload for development | ./run_server_wrapper.sh --reload |
--no-reload |
Disable auto-reload | ./run_server_wrapper.sh --no-reload |
--log-level LEVEL |
Set log level (debug, info, warning, error) | ./run_server_wrapper.sh --log-level debug |
--version |
Show version information | ./run_server_wrapper.sh --version |
# Start with default settings (localhost:7001)
./run_server_wrapper.sh
# Start on specific host and port
./run_server_wrapper.sh --host 0.0.0.0 --port 9000
# Start with debug logging
./run_server_wrapper.sh --log-level debug
# Start with auto-reload enabled
./run_server_wrapper.sh --reload
# Start with auto-reload disabled
./run_server_wrapper.sh --no-reload
# Start server in background
./run_server_wrapper.sh -d
# Start daemon with custom PID file
./run_server_wrapper.sh -d --pid-file /var/run/scim_server.pid
# Start daemon on specific port
./run_server_wrapper.sh -d --port 8080
# Check if daemon is running
ps aux | grep run_server.py
# Stop the daemon
kill $(cat /tmp/scim_server.pid)
# View daemon logs
tail -f /tmp/scim_server.log
The server requires a Python virtual environment with all dependencies installed. The wrapper script (run_server_wrapper.sh
) automatically:
- ✅ Activates the virtual environment (
.venv
) - ✅ Validates the environment before running
- ✅ Provides clear error messages if setup is incorrect
- ✅ Passes all arguments to the Python script
If you prefer to run manually:
# Activate virtual environment
source .venv/bin/activate
# Run the server
python run_server.py [options]
When using daemon mode (-d
flag), the server runs in the background with these features:
- PID File: Created at
/tmp/scim_server.pid
(or custom location) - Log File: All output captured in
/tmp/scim_server.log
- Process Safety: Prevents duplicate daemons and handles cleanup
- Signal Handling: Graceful shutdown with SIGTERM/SIGINT
- Virtual Environment: Automatically uses the correct Python environment
# Check if daemon is running
if [ -f /tmp/scim_server.pid ]; then
echo "Daemon PID: $(cat /tmp/scim_server.pid)"
ps -p $(cat /tmp/scim_server.pid) > /dev/null && echo "Daemon is running" || echo "Daemon is not running"
else
echo "No daemon PID file found"
fi
The development server includes:
- ✅ Multi-server support with virtual SCIM servers
- ✅ RFC 7644 compliant SCIM 2.0 endpoints
- ✅ Okta integration ready with entitlement support
- ✅ Enhanced Application Profiles System with 13 profile types
- ✅ Comprehensive test coverage (198/198 tests)
- ✅ Dynamic schema system with server-specific configurations
- ✅ Authentication system with API key support
When the server starts, it displays available endpoints:
Available endpoints:
/healthz # Basic health check (public access)
/health # Detailed health check (internal networks only)
/scim-identifier/{server_id}/scim/v2/Users
/scim-identifier/{server_id}/scim/v2/Groups
/scim-identifier/{server_id}/scim/v2/Entitlements
/scim-identifier/{server_id}/scim/v2/Roles
/scim-identifier/{server_id}/scim/v2/ResourceTypes
/scim-identifier/{server_id}/scim/v2/Schemas
Use Bearer token authentication with API keys:
default_api_key
: For normal operationstest_api_key
: For testing operations
# Example API call
curl -H "Authorization: Bearer default_api_key" \
http://localhost:7001/scim-identifier/test-server/scim/v2/Users
The server uses settings from scim_server.config
:
- Host: Default
0.0.0.0
- Port: Default
7001
- Reload: Default
True
for development - Log Level: Default
debug
-
Port already in use:
# Check what's using the port lsof -i :7001 # Use different port python run_server.py --port 8080
-
Daemon already running:
# Stop existing daemon kill $(cat /tmp/scim_server.pid) # Or remove stale PID file rm /tmp/scim_server.pid
-
Permission denied:
# Use different PID file location python run_server.py -d --pid-file /tmp/my_scim.pid
- Daemon logs:
/tmp/scim_server.log
- Application logs: Check console output for non-daemon mode
- Error logs: Both console and log file for daemon mode
The SCIM server now features a dynamic server configuration system that allows each virtual SCIM server to have unique attributes, schemas, and validation rules:
- Dynamic Resource Types - Each server can enable/disable specific resource types (User, Group, Entitlement)
- Custom Attributes - Server-specific custom attributes with type validation
- Validation Rules - Per-server validation settings (strict mode, unknown attributes, canonical values)
- Rate Limits - Server-specific API rate limiting
- Schema Extensions - Custom schema extensions per server
- Attribute Configuration - Required/optional attributes, complex attributes, multi-valued attributes
# List all server configurations
python scripts/scim_cli.py config list
# Get configuration for specific server
python scripts/scim_cli.py config get --server-id abc123
# Update server configuration from JSON file
python scripts/scim_cli.py config update --server-id abc123 --config-file config.json
{
"enabled_resource_types": ["User", "Group"],
"validation_rules": {
"strict_mode": false,
"allow_unknown_attributes": true,
"validate_canonical_values": false,
"validate_required_fields": true,
"validate_complex_attributes": true
},
"user_attributes": {
"required_attributes": ["userName"],
"optional_attributes": ["displayName", "emails", "name", "active"],
"custom_attributes": {
"department": {
"type": "string",
"required": false,
"description": "User's department"
}
},
"complex_attributes": {
"emails": {
"type": "complex",
"multiValued": true,
"subAttributes": [
{"name": "value", "type": "string", "required": true},
{"name": "primary", "type": "boolean", "required": false}
]
}
}
},
"rate_limits": {
"create": 100,
"read": 200,
"update": 100,
"delete": 100
}
}
The SCIM server now features a dynamic schema system that generates SCIM schema definitions at runtime based on:
- Database Models - SQLAlchemy model definitions
- Configuration Values - Settings from
config.py
(e.g., entitlement types) - Actual Data - Current state of the database
- SCIM 2.0 Compliance - RFC 7643 specification adherence
- Server-Specific Configuration - Dynamic attributes and validation rules per server
- Dynamic Resource Types -
/v2/ResourceTypes
endpoint generates resource types dynamically - Dynamic Schema Discovery -
/v2/Schemas
endpoint returns all available schemas with detailed attribute definitions - Individual Schema Access -
/v2/Schemas/{schema_urn}
endpoint provides specific schema information - Configuration Reflection - Entitlement types from
config.py
are automatically included as canonical values - No Hardcoded Values - All schema information is generated from actual system state
- Enhanced Error Handling - Detailed, developer-friendly error messages with troubleshooting guidance
{
"schemas": ["urn:okta:scim:schemas:core:1.0:Entitlement"],
"id": "urn:okta:scim:schemas:core:1.0:Entitlement",
"name": "Entitlement",
"description": "Entitlement",
"attributes": [
{
"name": "type",
"type": "string",
"multiValued": false,
"description": "The type of entitlement",
"required": true,
"caseExact": false,
"mutability": "readWrite",
"returned": "default",
"uniqueness": "none",
"canonicalValues": [
"E5", "Administrator", "Paid User", "Contributor", "Member",
"Read-only", "Standard User", "Basic User", "Limited", "Full",
"Standard", "Employee", "User", "Full-time", "Developer"
]
}
]
}
{
"detail": {
"error": "SCIM_VALIDATION_ERROR",
"message": "Field 'type' value 'InvalidType' is not valid",
"field": "type",
"provided_value": "InvalidType",
"allowed_values": ["Administrator", "Paid User", "Contributor", "Member", "Read-only", "Standard User", "Basic User", "Limited", "Full", "Standard", "Employee", "User", "Full-time", "Developer", "E5"],
"type": "invalid_canonical_value",
"resource_type": "Entitlement",
"help": "Use one of the allowed values: Administrator, Paid User, Contributor, Member, Read-only, Standard User, Basic User, Limited, Full, Standard, Employee, User, Full-time, Developer, E5"
}
}
# Test all schema functionality
python scripts/test_dynamic_schemas.py
# Test enhanced error handling
python scripts/test_enhanced_error_handling.py
# Test individual endpoints
curl -H "Authorization: Bearer test-api-key-12345" http://localhost:7001/v2/ResourceTypes
curl -H "Authorization: Bearer test-api-key-12345" http://localhost:7001/v2/Schemas
curl -H "Authorization: Bearer test-api-key-12345" "http://localhost:7001/v2/Schemas/urn:okta:scim:schemas:core:1.0:Entitlement"
# Test error handling examples
curl -X POST -H "Authorization: Bearer test-api-key-12345" -H "Content-Type: application/json" \
-d '{"displayName": "Test Entitlement", "type": "InvalidType"}' \
http://localhost:7001/v2/Entitlements/
# Access virtual server with ID "12345"
curl -H "Authorization: Bearer dev-api-key-12345" \
"http://localhost:7001/v2/Users?serverID=12345"
# Access virtual server with ID "test-env"
curl -H "Authorization: Bearer dev-api-key-12345" \
"http://localhost:7001/v2/Groups?serverID=test-env"
# Access virtual server with UUID "550e8400-e29b-41d4-a716-446655440000"
curl -H "Authorization: Bearer dev-api-key-12345" \
"http://localhost:7001/scim-identifier/550e8400-e29b-41d4-a716-446655440000/scim/v2/Users"
# Access virtual server with UUID "test-uuid-123"
curl -H "Authorization: Bearer dev-api-key-12345" \
"http://localhost:7001/scim-identifier/test-uuid-123/scim/v2/Groups"
All virtual servers support the same SCIM endpoints:
/Users
- User CRUD operations/Groups
- Group CRUD operations/Entitlements
- Entitlement CRUD operations/Roles
- Role CRUD operations/ResourceTypes
- Schema discovery/Schemas
- Custom schema extensions
The SCIM.Cloud project includes a comprehensive CLI tool (scripts/scim_cli.py
) for managing virtual SCIM servers. This tool provides both interactive and command-line modes for creating, listing, and managing virtual servers.
- Create Virtual Servers: Generate new virtual SCIM servers with populated test data
- List Servers: View all virtual servers with their statistics including relationships
- Delete Servers: Remove specific virtual servers and their data
- Reset Database: Clear all data for environment reset
- Interactive Mode: User-friendly prompts with default values
- Command Line Mode: Scriptable operations with parameters
- Configurable Defaults: All settings configurable via
scim_server/config.py
- Realistic Data Generation: Creates diverse user data with realistic names, emails, and attributes
- Relationship Management: Automatically creates user-group, user-entitlement, and user-role relationships
- Configurable Distribution: Control the percentage of users with various attributes and relationships
# Interactive mode - guided prompts with defaults
python scripts/scim_cli.py create
# Command line mode - specify exact values
python scripts/scim_cli.py create --users 20 --groups 8 --entitlements 12 --roles 6
# Create with custom server ID
python scripts/scim_cli.py create --server-id my-test-server --users 5
# List all virtual servers
python scripts/scim_cli.py list
# Delete a specific server
python scripts/scim_cli.py delete --server-id abc123
# Interactive delete mode
python scripts/scim_cli.py delete --interactive
# Reset entire database (with confirmation)
python scripts/scim_cli.py reset
The CLI tool uses configuration values from scim_server/config.py
:
# Default counts for virtual server creation
cli_default_users: int = 10
cli_default_groups: int = 5
cli_default_entitlements: int = 8
cli_default_roles: int = 4
# Predefined test data names and types
cli_group_names: list = [
"Engineering Team", "Marketing Team", "Sales Team", "HR Team", "Finance Team",
"Product Team", "Design Team", "Support Team", "Operations Team", "Legal Team"
]
cli_entitlement_types: list = [
("Office 365 License", "License"),
("Salesforce Access", "Profile"),
("GitHub Access", "Profile"),
# ... more predefined types
]
cli_role_names: list = [
"Developer", "Manager", "Admin", "Analyst", "Designer"
]
# Enhanced realistic data generation
cli_first_names: list = ["James", "Mary", "John", "Patricia", ...] # 100 realistic first names
cli_last_names: list = ["Smith", "Johnson", "Williams", "Brown", ...] # 100 realistic last names
cli_departments: list = ["Engineering", "Marketing", "Sales", "HR", ...] # 20 departments
cli_job_titles: list = ["Software Engineer", "Marketing Manager", ...] # 53 job titles
cli_company_domains: list = ["example.com", "testcompany.com", ...] # 9 company domains
# User attribute distribution settings (percentages)
cli_user_active_rate: float = 0.95 # 95% of users are active
cli_user_department_rate: float = 0.85 # 85% of users have departments assigned
cli_user_job_title_rate: float = 0.90 # 90% of users have job titles
cli_user_multiple_groups_rate: float = 0.60 # 60% of users belong to multiple groups
cli_user_entitlements_rate: float = 0.80 # 80% of users have entitlements
cli_user_roles_rate: float = 0.70 # 70% of users have roles
# Relationship distribution settings
cli_max_groups_per_user: int = 4 # Maximum groups a user can belong to
cli_max_entitlements_per_user: int = 6 # Maximum entitlements a user can have
cli_max_roles_per_user: int = 3 # Maximum roles a user can have
- Consistent Data Population: Ensures all virtual servers have consistent, well-structured test data
- Developer Efficiency: Quick setup of test environments with realistic data
- Testing Integration: Can be used in automated test scripts for consistent test data
- Environment Management: Easy cleanup and reset capabilities for development environments
- Configurable: All defaults and data types can be customized via configuration
- Realistic User Data: Generates diverse user profiles with realistic names, emails, and attributes
- Complex Relationships: Creates realistic user-group, user-entitlement, and user-role relationships
- Configurable Distribution: Control the percentage of users with various attributes and relationships
- Enhanced Testing: More representative test data for complex SCIM scenarios and edge cases
The SCIM server now includes a sophisticated Application Profiles System that provides comprehensive context documentation and enhanced user attributes for realistic testing scenarios. This system allows different application contexts (HR, IT, Sales, etc.) to have customized views of user data with specific attribute visibility, mutability rules, and data filtering capabilities.
- Mutability Rules: Clear explanation of READ_ONLY, READ_WRITE, IMMUTABLE, and WRITE_ONCE
- Acceptable Values: Format requirements for emails, phone numbers, addresses, employee numbers, etc.
- Profile-Specific Rules: Context for each profile type and their unique requirements
- Compliance Awareness: Each profile explains its compliance requirements and data sensitivity levels
- Multiple Email Addresses: Support for work and personal email addresses following SCIM 2.0 specification
- Multiple Phone Numbers: Support for work, mobile, and other phone number types
- Location Information: Comprehensive address attributes including city, state, country, and postal code
- Enhanced Employment Details: Improved field organization with logical grouping and descriptive comments
- Engineering Profile: Software development and engineering operations
- Product Profile: Product management and development
- Support Profile: Customer support and technical assistance
The system supports 13 application profiles with detailed context documentation:
Profile Type | Purpose | Data Sensitivity | Key Restrictions |
---|---|---|---|
HR | Employee lifecycle management | HIGH | Employee numbers and hire dates are WRITE_ONCE |
IT | System administration and access control | HIGH | Technical entitlements require approval workflows |
Sales | Sales operations and CRM access | MEDIUM | Territory assignments may require management approval |
Marketing | Campaign management and brand communications | MEDIUM | Creative tool access requires brand compliance approval |
Finance | Financial operations and accounting | HIGH | Cost centers require approval, financial data access requires audit logging |
Legal | Legal operations and compliance management | HIGH | Legal document access requires privilege level verification |
Operations | Business operations and process management | MEDIUM | Process changes require operational review and approval |
Security | Security operations and access control | HIGH | Security access requires background checks and approval |
Customer Success | Customer relationship management | MEDIUM | Customer data access requires customer consent and privacy compliance |
Research | Research operations and data analysis | MEDIUM | Research data access requires research ethics approval |
Engineering | Software development and engineering | MEDIUM | Code repository access requires code review and security approval |
Product | Product management and development | MEDIUM | Product roadmap access requires product strategy approval |
Support | Technical support and customer assistance | MEDIUM | Customer data access requires customer consent and privacy compliance |
@dataclass
class AppProfileConfig:
app_type: AppType
name: str
description: str
user_attributes: List[AttributeConfig]
roles: List[RoleConfig]
entitlements: List[EntitlementConfig]
data_filters: Dict[str, Any]
mutability_rules: Dict[str, MutabilityLevel]
compatible_entitlements: List[str]
compatible_departments: List[str]
compatible_groups: List[str]
- READ_ONLY: Attribute cannot be modified
- READ_WRITE: Full read/write access
- IMMUTABLE: Cannot be changed after creation
- WRITE_ONCE: Can be set during creation only
{
"userName": "john.doe",
"displayName": "John Doe",
"emails": [
{"value": "john.doe@company.com", "type": "work", "primary": true},
{"value": "john.doe@gmail.com", "type": "home"}
],
"phoneNumbers": [
{"value": "+1-555-123-4567", "type": "work"},
{"value": "+1-555-987-6543", "type": "mobile"}
],
"addresses": [
{
"type": "work",
"streetAddress": "123 Main St",
"locality": "San Francisco",
"region": "CA",
"postalCode": "94105",
"country": "US"
}
]
}
# Get HR profile and understand its restrictions
manager = AppProfileManager()
hr_profile = manager.get_profile(AppType.HR)
# Check if employee number can be modified (it cannot - WRITE_ONCE)
can_modify = manager.validate_attribute_mutability(
AppType.HR, "employeeNumber", "write"
) # Returns False
# Get compatible entitlements for IT profile
it_entitlements = manager.get_compatible_entitlements(AppType.IT)
# Returns: ['Office 365 License', 'GitHub Access', 'Slack Access', 'VPN Access', ...]
# Get visible attributes for Sales profile
sales_attrs = manager.get_visible_attributes(AppType.SALES)
# Returns all attributes visible to sales applications
- Developers understand exactly what can be changed and when
- Clear guidance on acceptable values and formats
- Context for why certain restrictions exist
- Each profile explains its compliance requirements
- Data sensitivity levels are clearly documented
- Approval workflows and restrictions are explained
- Code examples show how to use the profile system
- Real-world scenarios for each profile type
- Clear guidance on integration with existing systems
- Clear documentation prevents common mistakes
- Understanding of mutability rules prevents invalid operations
- Knowledge of acceptable values prevents data format errors
All tests continue to pass with the enhanced documentation:
- 57/57 profile tests ✅
- 19/19 CLI tests ✅
- Enhanced documentation ✅
- Backward compatibility ✅
The enhanced documentation provides developers with comprehensive guidance while maintaining full functionality and test coverage.
- Simplicity First: Prioritize clear, maintainable code and a simple, functional UI (for the planned frontend). Avoid unnecessary complexity or "fancy" features.
- Centralized Data: All configuration and data are stored in SQLite. No hardcoded users, groups, or entitlements outside the database.
- Multi-Server Isolation: Virtual SCIM servers maintain data isolation while sharing the same web port and authentication system.
- Extensive Logging: All actions, errors, and API calls are logged in detail to aid development and debugging.
- Okta Compatibility: Special attention to Okta's SCIM extension requirements, including
/ResourceTypes
,/Schemas
, and entitlement/role endpoints. - Stateless API: All state is persisted in the database; the server itself is stateless between requests.
- Authentication: Only API key authentication is supported. No OAuth, SAML, or other auth mechanisms.
- Dynamic Testing: All tests read actual data from endpoints instead of using hardcoded values. Tests adapt to whatever data is present in the database.
- Frontend Separation: The backend is designed to support a simple web frontend for debugging, but the frontend is a separate phase and should not affect backend design.
scim-server/
├── scim_server/ # Python package for the SCIM backend
│ ├── __init__.py
│ ├── main.py # FastAPI app and basic endpoints
│ ├── database.py # SQLAlchemy setup and database utilities
│ ├── models.py # Database models for all SCIM entities
│ ├── auth.py # API key authentication
│ ├── schemas.py # Pydantic models for SCIM entities
│ ├── crud_base.py # Base CRUD operations (generic)
│ ├── crud_entities.py # Entity-specific CRUD operations
│ ├── crud_simple.py # Simplified CRUD interface
│ ├── utils.py # Utility functions for SCIM operations
│ ├── scim_endpoints.py # SCIM 2.0 discovery endpoints
│ ├── user_endpoints.py # User CRUD endpoints
│ ├── group_endpoints.py # Group CRUD endpoints
│ ├── entitlement_endpoints.py # Entitlement CRUD endpoints
│ └── role_endpoints.py # Role CRUD endpoints
├── tests/ # Automated tests
│ ├── __init__.py
│ ├── conftest.py # Pytest configuration and fixtures
│ ├── test_health.py # Health check tests
│ ├── test_auth.py # Authentication tests
│ ├── test_scim_endpoints.py # SCIM endpoint tests
│ ├── test_user_endpoints.py # User endpoint tests
│ ├── reports/ # Test report files
│ ├── data/ # Test data files
│ └── debug/ # Debug scripts
├── scripts/ # Utility scripts
│ ├── init_db.py # Database initialization script
│ ├── create_test_data.py # Test data creation script
│ ├── scim_cli.py # CLI tool for virtual server management
│ └── run_comprehensive_tests.py # Comprehensive test runner
├── .cursor/rules/ # Project coding and design guidelines
├── README.md # This file
├── requirements.txt # Python dependencies
├── run_server.py # Development server runner
└── scim.db # SQLite database file (created at runtime)
The SCIM server uses a simple configuration file (scim_server/config.py
) with all settings defined in one place. To customize settings, simply edit the values in this file.
database_url
: Database connection string (default:sqlite:///./scim.db
)max_results_per_page
: Maximum results per page (default:100
)default_page_size
: Default page size (default:100
)max_count_limit
: Maximum limit for counting total results (default:1000
)rate_limit_create
: Rate limit for create operations (default:10
requests per minute)rate_limit_read
: Rate limit for read operations (default:100
requests per minute)rate_limit_window
: Rate limit window in seconds (default:60
)host
: Server host (default:0.0.0.0
)port
: Server port (default:7001
)log_level
: Logging level (default:debug
)default_api_key
: Development API key (default:api-key-12345
)test_api_key
: Test API key (default:test-api-key-12345
)
cli_default_users
: Default number of users for new virtual servers (default:10
)cli_default_groups
: Default number of groups for new virtual servers (default:5
)cli_default_entitlements
: Default number of entitlements for new virtual servers (default:8
)cli_default_roles
: Default number of roles for new virtual servers (default:4
)cli_group_names
: List of predefined group names for test datacli_entitlement_types
: List of predefined entitlement types and namescli_role_names
: List of predefined role names for test datacli_first_names
: List of realistic first names for user generation (100 names)cli_last_names
: List of realistic last names for user generation (100 names)cli_departments
: List of department names for organizational structure (20 departments)cli_job_titles
: List of realistic job titles (53 titles)cli_company_domains
: List of company email domains for realistic email generationcli_user_active_rate
: Percentage of users that should be active (default:0.95
)cli_user_department_rate
: Percentage of users with department assignments (default:0.85
)cli_user_job_title_rate
: Percentage of users with job titles (default:0.90
)cli_user_multiple_groups_rate
: Percentage of users in multiple groups (default:0.60
)cli_user_entitlements_rate
: Percentage of users with entitlements (default:0.80
)cli_user_roles_rate
: Percentage of users with roles (default:0.70
)cli_max_groups_per_user
: Maximum groups a user can belong to (default:4
)cli_max_entitlements_per_user
: Maximum entitlements a user can have (default:6
)cli_max_roles_per_user
: Maximum roles a user can have (default:3
)
Additional settings for multi-server functionality will be added to support:
- Virtual server management
- Database isolation strategies
- URL pattern configuration
Simply edit scim_server/config.py
to change any settings:
# Example: Change port and API keys
port: int = 7001
default_api_key: str = "my-custom-dev-key"
test_api_key: str = "my-custom-test-key"
- All API requests must include an
Authorization: Bearer <API_KEY>
header. - API keys are stored in the SQLite database and can be managed via the API.
- Requests without a valid API key will receive a 401 Unauthorized response.
- Default development API key: Configurable in
scim_server/config.py
(default:api-key-12345
) - Test API key: Configurable in
scim_server/config.py
(default:test-api-key-12345
) - Multi-Server Note: All virtual SCIM servers share the same API key authentication system.
The server supports SCIM 2.0 filtering and pagination:
# Exact username match
curl -H "Authorization: Bearer dev-api-key-12345" \
"http://localhost:7001/v2/Users/?filter=userName%20eq%20%22testuser@example.com%22"
# Contains display name
curl -H "Authorization: Bearer dev-api-key-12345" \
"http://localhost:7001/v2/Users/?filter=displayName%20co%20%22John%22"
# Group filtering
curl -H "Authorization: Bearer dev-api-key-12345" \
"http://localhost:7001/v2/Groups/?filter=displayName%20co%20%22Engineering%22"
# Get first 2 users
curl -H "Authorization: Bearer dev-api-key-12345" \
"http://localhost:7001/v2/Users/?startIndex=1&count=2"
# Get users 3-5
curl -H "Authorization: Bearer dev-api-key-12345" \
"http://localhost:7001/v2/Users/?startIndex=3&count=3"
- All API calls, errors, and database operations are logged with timestamps and context.
- Debug endpoints and detailed error messages are provided for developer convenience.
- Real-time test execution logging shows exactly what's happening during tests.
- Logging verbosity can be configured via environment variables or config file.
- Multi-Server Note: Virtual server identification will be included in all log entries for proper debugging.
- Uses SQLite for all persistent storage.
- All entities (users, groups, entitlements, roles, schemas, API keys, etc.) are stored in the database.
- Database schema is designed for extensibility and easy inspection.
- Comprehensive relationship management between entities.
- Multi-Server Note: Database strategy (shared vs. separate) will be determined based on performance and implementation complexity analysis.
tests/
- Main test directorytests/reports/
- Test report files (JSON format)tests/data/
- Test data files (databases, etc.)tests/debug/
- Debug scripts and utilities
scripts/
- Test-related scriptsscripts/create_test_data.py
- Populates database with test datascripts/validate_test_environment.py
- Validates test environmentscripts/run_comprehensive_tests.py
- Runs comprehensive integration tests
Before running tests, the environment is automatically validated to ensure:
- ✅ At least 5 users, groups, entitlements, and roles exist
- ✅ Required test users (
john.doe@example.com
,jane.smith@example.com
, etc.) are present - ✅ Required test groups (
Engineering Team
,Marketing Team
, etc.) are present - ✅ Test API key (configurable in
scim_server/config.py
) is available
The test suite will be extended to support:
- Virtual server creation and management
- Data isolation validation
- Cross-server data integrity testing
- URL pattern validation for both query and path parameter approaches
# Validate test environment first
python scripts/validate_test_environment.py
# Create test data (if validation fails)
python scripts/create_test_data.py
# Run unit tests
PYTHONPATH=. pytest tests/ -v
# Run comprehensive integration tests
python scripts/run_comprehensive_tests.py
- Success Rate: 100% (141/141 tests passing)
- Coverage: All endpoints and operations tested
- Real-time Database Access: Tests read from live database (no caching)
- Environment Validation: Automatic validation ensures consistent test state
- Dynamic Data: Tests read actual data from endpoints
- Real-time Reporting: Detailed execution logs and progress tracking
- Server Verification: Automatic server availability checking
- Comprehensive Coverage: All CRUD operations, filtering, pagination, and error handling
- Okta SCIM Compliance: Vendor-specific testing for Okta integration
- RFC 7644 Compliance: Full SCIM 2.0 specification validation
- Custom schemas and attributes are supported via the
/Schemas
endpoint and database extensions. - Designed to be easily modifiable for new resource types or attributes.
- Modular endpoint structure allows easy addition of new SCIM resources.
- Multi-Server Note: Virtual server functionality is designed to be extensible for additional server management features.
- A minimal web UI for browsing and editing users, groups, entitlements, and other data in the SQLite database.
- Intended for debugging and development only; not for production use.
- Will be implemented in a later phase.
- Multi-Server Note: The frontend will include virtual server management and switching capabilities.
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 4,
"startIndex": 1,
"itemsPerPage": 4,
"Resources": [
{
"id": "User",
"name": "User",
"endpoint": "/Users",
"schema": "urn:ietf:params:scim:schemas:core:2.0:User"
},
{
"id": "Group",
"name": "Group",
"endpoint": "/Groups",
"schema": "urn:ietf:params:scim:schemas:core:2.0:Group"
},
{
"id": "Entitlement",
"name": "Entitlement",
"endpoint": "/Entitlements",
"schema": "urn:okta:scim:schemas:core:1.0:Entitlement"
},
{
"id": "Role",
"name": "Role",
"endpoint": "/Roles",
"schema": "urn:okta:scim:schemas:core:1.0:Role"
}
]
}
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 1,
"startIndex": 1,
"itemsPerPage": 1,
"Resources": [
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "998dd507-27fb-4f74-a84a-90ab3c0454e1",
"userName": "testuser@example.com",
"displayName": "Test User",
"active": true,
"meta": {
"resourceType": "User",
"created": "2025-07-25T20:00:00Z",
"lastModified": "2025-07-25T20:00:00Z",
"version": "1"
}
}
]
}
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": "401",
"scimType": "invalidToken",
"detail": "Invalid or missing API key. Please provide a valid Bearer token in the Authorization header."
}
- All code must follow the guidelines in
.cursor/rules/
(MDC format, see Cursor Project Rules). - All new features and bugfixes must include automated tests covering all endpoints.
- Tests must use dynamic data and avoid hardcoded values.
- Update this README as new decisions are made or features are added.
- Multi-Server Note: All multi-server functionality must maintain SCIM 2.0 compliance and backward compatibility.
This project is open source and intended for development and testing purposes only. See LICENSE
for details.
For questions or suggestions, please open an issue or contact the maintainer.