Files
onvif-go/docs/api/STORAGE_API_SUMMARY.md
T
0x524a 0551d28f61 feat: add comprehensive tests for Bosch FLEXIDOME indoor 5100i IR camera
- Introduced new test files for device and media service operations using real camera responses.
- Implemented tests for GetDeviceInformation, GetMediaServiceCapabilities, and user management functions.
- Enhanced documentation with a detailed testing flow and coverage reports.
- Added JSON test reports for tracking operation success and response times.
- Updated the README and other documentation to reflect new testing capabilities and structure.
2025-12-02 00:43:17 -05:00

869 lines
24 KiB
Markdown

# ONVIF Storage Configuration & Hashing Algorithm APIs
This document provides comprehensive information about the 6 Storage and Advanced Security APIs implemented in `device_storage.go`.
## Overview
The storage APIs enable management of recording storage configurations on ONVIF-compliant devices. These APIs are essential for:
- Configuring local and network storage for video recordings
- Managing multiple storage locations (NFS, CIFS, local filesystems)
- Setting up cloud storage integrations
- Configuring password hashing algorithms for enhanced security
**Implementation Status**: ✅ All 6 APIs implemented and tested (100% coverage)
## API Reference
### 1. GetStorageConfigurations
Retrieves all storage configurations available on the device.
**Signature:**
```go
func (c *Client) GetStorageConfigurations(ctx context.Context) ([]*StorageConfiguration, error)
```
**Parameters:**
- `ctx` - Context for cancellation and timeouts
**Returns:**
- `[]*StorageConfiguration` - Array of all storage configurations
- `error` - Error if the operation fails
**Usage Example:**
```go
configs, err := client.GetStorageConfigurations(ctx)
if err != nil {
log.Fatalf("Failed to get storage configurations: %v", err)
}
for _, config := range configs {
fmt.Printf("Storage: %s\n", config.Token)
fmt.Printf(" Type: %s\n", config.Data.Type)
fmt.Printf(" Path: %s\n", config.Data.LocalPath)
fmt.Printf(" URI: %s\n", config.Data.StorageUri)
}
```
**ONVIF Specification:**
- Operation: `GetStorageConfigurations`
- Returns all configured storage locations on the device
- Includes local, NFS, CIFS, and cloud storage
---
### 2. GetStorageConfiguration
Retrieves a specific storage configuration by its token.
**Signature:**
```go
func (c *Client) GetStorageConfiguration(ctx context.Context, token string) (*StorageConfiguration, error)
```
**Parameters:**
- `ctx` - Context for cancellation and timeouts
- `token` - Unique identifier of the storage configuration
**Returns:**
- `*StorageConfiguration` - The requested storage configuration
- `error` - Error if the operation fails or token not found
**Usage Example:**
```go
config, err := client.GetStorageConfiguration(ctx, "storage-001")
if err != nil {
log.Fatalf("Failed to get storage configuration: %v", err)
}
fmt.Printf("Storage Type: %s\n", config.Data.Type)
fmt.Printf("Mount Point: %s\n", config.Data.LocalPath)
if config.Data.StorageUri != "" {
fmt.Printf("Network URI: %s\n", config.Data.StorageUri)
}
```
**ONVIF Specification:**
- Operation: `GetStorageConfiguration`
- Requires valid storage configuration token
- Returns detailed configuration including credentials if applicable
---
### 3. CreateStorageConfiguration
Creates a new storage configuration on the device.
**Signature:**
```go
func (c *Client) CreateStorageConfiguration(ctx context.Context, config *StorageConfiguration) (string, error)
```
**Parameters:**
- `ctx` - Context for cancellation and timeouts
- `config` - Storage configuration to create (token will be assigned by device)
**Returns:**
- `string` - Token assigned to the new storage configuration
- `error` - Error if the operation fails
**Usage Example:**
```go
// Create NFS storage
nfsStorage := &onvif.StorageConfiguration{
Data: onvif.StorageConfigurationData{
Type: "NFS",
LocalPath: "/mnt/recordings",
StorageUri: "nfs://192.168.1.100/recordings",
},
}
token, err := client.CreateStorageConfiguration(ctx, nfsStorage)
if err != nil {
log.Fatalf("Failed to create storage: %v", err)
}
fmt.Printf("Created storage with token: %s\n", token)
// Create CIFS/SMB storage with credentials
cifsStorage := &onvif.StorageConfiguration{
Data: onvif.StorageConfigurationData{
Type: "CIFS",
LocalPath: "/mnt/nas",
StorageUri: "cifs://nas.example.com/videos",
User: &onvif.UserCredential{
Username: "recorder",
Password: "secure-password",
Extension: nil,
},
},
}
token2, err := client.CreateStorageConfiguration(ctx, cifsStorage)
if err != nil {
log.Fatalf("Failed to create CIFS storage: %v", err)
}
fmt.Printf("Created CIFS storage: %s\n", token2)
// Create local storage
localStorage := &onvif.StorageConfiguration{
Data: onvif.StorageConfigurationData{
Type: "Local",
LocalPath: "/var/media/sd-card",
StorageUri: "file:///var/media/sd-card",
},
}
token3, err := client.CreateStorageConfiguration(ctx, localStorage)
```
**ONVIF Specification:**
- Operation: `CreateStorageConfiguration`
- Device assigns unique token to new configuration
- Validates storage accessibility before creation
- May fail if storage is not accessible or credentials invalid
**Storage Types:**
- `"Local"` - Local filesystem (SD card, internal storage)
- `"NFS"` - Network File System
- `"CIFS"` - Common Internet File System (SMB/Windows shares)
- `"FTP"` - FTP server storage
- `"HTTP"` - HTTP/WebDAV storage
- Custom types supported by device manufacturer
---
### 4. SetStorageConfiguration
Updates an existing storage configuration.
**Signature:**
```go
func (c *Client) SetStorageConfiguration(ctx context.Context, config *StorageConfiguration) error
```
**Parameters:**
- `ctx` - Context for cancellation and timeouts
- `config` - Updated storage configuration (must include valid token)
**Returns:**
- `error` - Error if the operation fails
**Usage Example:**
```go
// Get existing configuration
config, err := client.GetStorageConfiguration(ctx, "storage-001")
if err != nil {
log.Fatal(err)
}
// Update storage URI
config.Data.StorageUri = "nfs://new-server.example.com/recordings"
// Update credentials
config.Data.User = &onvif.UserCredential{
Username: "new-user",
Password: "new-password",
}
// Apply changes
err = client.SetStorageConfiguration(ctx, config)
if err != nil {
log.Fatalf("Failed to update storage: %v", err)
}
fmt.Println("Storage configuration updated successfully")
```
**ONVIF Specification:**
- Operation: `SetStorageConfiguration`
- Requires existing configuration token
- Validates new settings before applying
- May cause brief interruption to recordings
**Best Practices:**
- Always retrieve current configuration before updating
- Validate storage accessibility before applying changes
- Consider impact on active recordings
- Update credentials atomically to avoid authentication failures
---
### 5. DeleteStorageConfiguration
Removes a storage configuration from the device.
**Signature:**
```go
func (c *Client) DeleteStorageConfiguration(ctx context.Context, token string) error
```
**Parameters:**
- `ctx` - Context for cancellation and timeouts
- `token` - Token of the storage configuration to delete
**Returns:**
- `error` - Error if the operation fails
**Usage Example:**
```go
// Delete unused storage configuration
err := client.DeleteStorageConfiguration(ctx, "storage-old")
if err != nil {
log.Fatalf("Failed to delete storage: %v", err)
}
fmt.Println("Storage configuration deleted")
// Check remaining configurations
configs, err := client.GetStorageConfigurations(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Remaining storage configurations: %d\n", len(configs))
for _, cfg := range configs {
fmt.Printf(" - %s: %s\n", cfg.Token, cfg.Data.Type)
}
```
**ONVIF Specification:**
- Operation: `DeleteStorageConfiguration`
- Cannot delete storage in use by active recording profiles
- Existing recordings on storage remain accessible
- Frees up configuration slots for new storage
**Important Notes:**
- **Warning**: Deleting storage configuration does not delete recorded files
- Check for active recording profiles before deletion
- Some devices may have minimum storage requirements
- Consider unmounting network storage before deletion
---
### 6. SetHashingAlgorithm
Sets the password hashing algorithm used by the device.
**Signature:**
```go
func (c *Client) SetHashingAlgorithm(ctx context.Context, algorithm string) error
```
**Parameters:**
- `ctx` - Context for cancellation and timeouts
- `algorithm` - Hashing algorithm identifier (e.g., "SHA-256", "SHA-512", "bcrypt")
**Returns:**
- `error` - Error if the operation fails or algorithm not supported
**Usage Example:**
```go
// Set to SHA-256 (FIPS 140-2 compliant)
err := client.SetHashingAlgorithm(ctx, "SHA-256")
if err != nil {
log.Fatalf("Failed to set hashing algorithm: %v", err)
}
fmt.Println("Password hashing set to SHA-256")
// Set to bcrypt for enhanced security
err = client.SetHashingAlgorithm(ctx, "bcrypt")
if err != nil {
log.Fatalf("Failed to set bcrypt: %v", err)
}
fmt.Println("Password hashing set to bcrypt")
// Set to SHA-512 for maximum hash strength
err = client.SetHashingAlgorithm(ctx, "SHA-512")
if err != nil {
log.Fatalf("Failed to set SHA-512: %v", err)
}
```
**ONVIF Specification:**
- Operation: `SetHashingAlgorithm`
- Changes algorithm for future password operations
- Does not re-hash existing passwords
- Part of advanced security configuration
**Supported Algorithms** (device-dependent):
- `"MD5"` - ⚠️ **Deprecated** - Not recommended for security
- `"SHA-1"` - ⚠️ **Deprecated** - Not recommended for security
- `"SHA-256"` - ✅ **Recommended** - FIPS 140-2 compliant
- `"SHA-384"` - ✅ Strong cryptographic hash
- `"SHA-512"` - ✅ Maximum strength SHA-2 family
- `"bcrypt"` - ✅ **Best for passwords** - Adaptive hashing with salt
- `"scrypt"` - ✅ Memory-hard function
- `"argon2"` - ✅ **Modern choice** - Winner of Password Hashing Competition
**Security Recommendations:**
1. **Prefer bcrypt or argon2** for password hashing
2. **Use SHA-256 minimum** if adaptive hashing unavailable
3. **Avoid MD5 and SHA-1** - known vulnerabilities
4. **Document algorithm changes** in security audit logs
5. **Plan password reset** after algorithm changes
6. **Test compatibility** before deployment
---
## Type Definitions
### StorageConfiguration
Complete storage configuration including location and access credentials.
```go
type StorageConfiguration struct {
Token string `xml:"token,attr"`
Data StorageConfigurationData `xml:"Data"`
}
```
**Fields:**
- `Token` - Unique identifier for this configuration
- `Data` - Detailed storage configuration data
---
### StorageConfigurationData
Detailed information about storage location and access.
```go
type StorageConfigurationData struct {
LocalPath string `xml:"LocalPath"`
StorageUri string `xml:"StorageUri,omitempty"`
User *UserCredential `xml:"User,omitempty"`
Extension interface{} `xml:"Extension,omitempty"`
Type string `xml:"type,attr"`
}
```
**Fields:**
- `LocalPath` - Local mount point on the device (e.g., "/mnt/storage")
- `StorageUri` - Network URI for remote storage (e.g., "nfs://server/path")
- `User` - Credentials for network storage authentication (optional)
- `Extension` - Vendor-specific extensions
- `Type` - Storage type ("NFS", "CIFS", "Local", "FTP", etc.)
---
### UserCredential
Authentication credentials for network storage.
```go
type UserCredential struct {
Username string `xml:"Username"`
Password string `xml:"Password"`
Extension interface{} `xml:"Extension,omitempty"`
}
```
**Fields:**
- `Username` - Account username for storage access
- `Password` - Account password (transmitted securely over HTTPS)
- `Extension` - Additional authentication data (e.g., domain, workgroup)
**Security Notes:**
- Always use HTTPS/TLS when transmitting credentials
- Passwords are stored hashed on the device
- Consider using read-only credentials for recording storage
- Regularly rotate storage access credentials
---
## Common Use Cases
### Use Case 1: Multi-Location Recording
Configure primary local storage with network backup:
```go
ctx := context.Background()
// Primary: Local SD card storage
primaryToken, err := client.CreateStorageConfiguration(ctx, &onvif.StorageConfiguration{
Data: onvif.StorageConfigurationData{
Type: "Local",
LocalPath: "/mnt/sd-card",
StorageUri: "file:///mnt/sd-card",
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Primary storage: %s\n", primaryToken)
// Secondary: Network NFS backup
backupToken, err := client.CreateStorageConfiguration(ctx, &onvif.StorageConfiguration{
Data: onvif.StorageConfigurationData{
Type: "NFS",
LocalPath: "/mnt/backup",
StorageUri: "nfs://backup-server.local/camera-recordings",
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Backup storage: %s\n", backupToken)
```
---
### Use Case 2: Enterprise NAS Integration
Connect to Windows file share for centralized recording:
```go
// Create CIFS storage with domain authentication
nasConfig := &onvif.StorageConfiguration{
Data: onvif.StorageConfigurationData{
Type: "CIFS",
LocalPath: "/mnt/nas",
StorageUri: "cifs://nas.corporate.local/security/camera-01",
User: &onvif.UserCredential{
Username: "DOMAIN\\camera-service",
Password: "ComplexPassword123!",
},
},
}
token, err := client.CreateStorageConfiguration(ctx, nasConfig)
if err != nil {
log.Fatalf("NAS configuration failed: %v", err)
}
fmt.Printf("NAS storage configured: %s\n", token)
// Verify accessibility
config, err := client.GetStorageConfiguration(ctx, token)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Storage accessible at: %s\n", config.Data.LocalPath)
```
---
### Use Case 3: Cloud Storage Integration
Configure FTP upload to cloud storage:
```go
cloudStorage := &onvif.StorageConfiguration{
Data: onvif.StorageConfigurationData{
Type: "FTP",
LocalPath: "/var/cache/cloud-upload",
StorageUri: "ftp://ftp.cloud-provider.com/customer-123/camera-A",
User: &onvif.UserCredential{
Username: "customer-123",
Password: "api-key-xyz789",
},
},
}
token, err := client.CreateStorageConfiguration(ctx, cloudStorage)
if err != nil {
log.Fatalf("Cloud storage failed: %v", err)
}
fmt.Println("Cloud storage configured for off-site backup")
```
---
### Use Case 4: Storage Migration
Migrate recordings to new storage location:
```go
// Step 1: Create new storage
newStorage := &onvif.StorageConfiguration{
Data: onvif.StorageConfigurationData{
Type: "NFS",
LocalPath: "/mnt/new-storage",
StorageUri: "nfs://new-nas.local/recordings",
},
}
newToken, err := client.CreateStorageConfiguration(ctx, newStorage)
if err != nil {
log.Fatal(err)
}
// Step 2: Get current recording profiles (from media service)
// ... switch recording profiles to new storage ...
// Step 3: Delete old storage after migration complete
time.Sleep(24 * time.Hour) // Wait for migration
err = client.DeleteStorageConfiguration(ctx, "old-storage-token")
if err != nil {
log.Fatalf("Failed to remove old storage: %v", err)
}
fmt.Println("Storage migration complete")
```
---
### Use Case 5: Security Hardening
Upgrade password hashing for compliance:
```go
// Audit current security settings
fmt.Println("Upgrading password hashing algorithm...")
// Set to bcrypt for NIST compliance
err := client.SetHashingAlgorithm(ctx, "bcrypt")
if err != nil {
log.Fatalf("Failed to upgrade hashing: %v", err)
}
fmt.Println("Password hashing upgraded to bcrypt")
fmt.Println("Existing users should reset passwords at next login")
// Update password complexity requirements
passwordConfig := &onvif.PasswordComplexityConfiguration{
MinLen: 12,
Uppercase: 1,
Number: 2,
SpecialChars: 2,
BlockUsernameOccurrence: true,
}
err = client.SetPasswordComplexityConfiguration(ctx, passwordConfig)
if err != nil {
log.Fatal(err)
}
fmt.Println("Security hardening complete")
```
---
## Best Practices
### Storage Configuration
1. **Redundancy**: Configure at least two storage locations (local + network)
2. **Testing**: Verify storage accessibility before creating configuration
3. **Monitoring**: Regularly check storage capacity and health
4. **Credentials**: Use dedicated service accounts with minimal permissions
5. **Documentation**: Maintain inventory of all storage configurations
### Network Storage
1. **Performance**: Use gigabit Ethernet for NFS/CIFS storage
2. **Latency**: Keep network storage on same subnet as cameras
3. **Reliability**: Configure automatic reconnection for network failures
4. **Security**: Use VLANs to isolate storage traffic
5. **Capacity Planning**: Monitor storage growth and plan for expansion
### Security
1. **Encryption**: Use TLS/HTTPS for all API communication
2. **Hashing**: Prefer bcrypt or argon2 for password storage
3. **Rotation**: Regularly rotate storage access credentials
4. **Auditing**: Log all storage configuration changes
5. **Compliance**: Follow industry standards (NIST, ISO 27001)
### Error Handling
1. **Validation**: Check storage accessibility before configuration
2. **Rollback**: Keep backup of working configurations
3. **Monitoring**: Alert on storage connection failures
4. **Retry Logic**: Implement exponential backoff for network errors
5. **Logging**: Record detailed error information for troubleshooting
---
## Error Scenarios
### Common Errors
**Storage Inaccessible:**
```
Error: CreateStorageConfiguration failed: storage location not accessible
```
- Verify network connectivity to storage server
- Check firewall rules allow NFS/CIFS traffic
- Validate credentials have access to specified path
**Invalid Credentials:**
```
Error: authentication failed for network storage
```
- Confirm username and password are correct
- Check account has necessary permissions
- Verify domain/workgroup settings for CIFS
**Unsupported Algorithm:**
```
Error: SetHashingAlgorithm failed: algorithm not supported
```
- Query device capabilities for supported algorithms
- Use fallback to SHA-256 if bcrypt unavailable
- Check firmware version supports modern hashing
**Configuration In Use:**
```
Error: cannot delete storage configuration in use
```
- Identify recording profiles using this storage
- Migrate recordings to different storage first
- Stop active recordings before deletion
---
## Performance Considerations
### Network Storage
- **Latency**: < 10ms recommended for reliable recording
- **Bandwidth**: 10-50 Mbps per HD camera, 50-100 Mbps for 4K
- **Concurrent Access**: Configure storage for multiple simultaneous writes
- **Caching**: Some devices cache locally before uploading to network
### Local Storage
- **Speed Class**: Use Class 10 or UHS-1 SD cards minimum
- **Endurance**: Prefer high-endurance cards for 24/7 recording
- **Capacity**: Plan for 30-90 days of retention minimum
- **Wear Leveling**: Monitor SD card health and replace proactively
### Hashing Performance
- **bcrypt**: ~100-500ms per password verification (tunable)
- **SHA-256**: < 1ms per password verification
- **Impact**: Hashing algorithm affects login latency
- **Recommendation**: bcrypt for security, SHA-256 for high-volume systems
---
## Testing Coverage
All 6 storage APIs have comprehensive test coverage:
**Test File**: `device_storage_test.go`
**Tests Implemented:**
1. `TestGetStorageConfigurations` - Validates retrieving all storage configs
2. `TestGetStorageConfiguration` - Tests single configuration retrieval by token
3. `TestCreateStorageConfiguration` - Verifies new storage creation and token assignment
4. `TestSetStorageConfiguration` - Tests updating existing configurations
5. `TestDeleteStorageConfiguration` - Validates configuration deletion
6. `TestSetHashingAlgorithm` - Tests password hashing algorithm changes
**Coverage**: 100% of all functions and code paths
**Mock Server**: `newMockDeviceStorageServer()` simulates complete ONVIF device responses
---
## Integration with Other Services
### Media Service
Storage configurations are referenced by recording profiles:
```go
// Get media profiles
profiles, err := mediaClient.GetProfiles(ctx)
// Associate storage with profile
for _, profile := range profiles {
if profile.VideoEncoderConfiguration != nil {
// Set recording to use new storage
// (Media service API, not shown here)
}
}
```
### Recording Service
Recordings are written to configured storage:
```go
// Recording service uses storage configuration
// to determine where to save recorded video
```
### Event Service
Storage events can trigger notifications:
```go
// Subscribe to storage full events
// Subscribe to storage disconnection events
// Monitor storage health status
```
---
## Migration Guide
### From Manual Configuration
If you previously configured storage manually via device web interface:
1. **Inventory**: List all existing storage using `GetStorageConfigurations`
2. **Document**: Record current configurations including credentials
3. **Test**: Create new API-based configurations in test environment
4. **Migrate**: Gradually move recording profiles to API-managed storage
5. **Cleanup**: Remove manual configurations once migration complete
### From Older API Versions
ONVIF 2.0+ storage APIs replace older proprietary methods:
```go
// Old (proprietary):
// device.SetRecordingPath("/mnt/storage")
// New (ONVIF standard):
config := &onvif.StorageConfiguration{
Data: onvif.StorageConfigurationData{
Type: "Local",
LocalPath: "/mnt/storage",
},
}
token, err := client.CreateStorageConfiguration(ctx, config)
```
---
## Compliance & Standards
### ONVIF Profiles
- **Profile S**: Basic storage configuration ✅
- **Profile G**: Full recording and storage management ✅
- **Profile T**: Advanced recording with analytics ✅
### Security Standards
- **NIST 800-63B**: Password hashing recommendations
- Minimum: SHA-256
- Recommended: bcrypt, scrypt, or argon2
- **ISO 27001**: Information security management
- Secure credential storage
- Access control
- Audit logging
### Industry Compliance
- **NDAA**: Use compliant storage solutions
- **GDPR**: Ensure data retention policies
- **HIPAA**: Encrypted storage for healthcare
- **PCI DSS**: Secure storage for payment systems
---
## Troubleshooting
### Cannot Create Storage
**Problem**: `CreateStorageConfiguration` fails with "permission denied"
**Solution**:
```go
// Ensure storage path exists and is writable
// Check user has admin privileges
// Verify network storage is mounted
```
### Storage Full Errors
**Problem**: Recordings fail due to full storage
**Solution**:
```go
// Implement storage monitoring
configs, _ := client.GetStorageConfigurations(ctx)
for _, cfg := range configs {
// Check available space
// Implement automatic cleanup of old recordings
// Alert when storage exceeds 80% capacity
}
```
### Network Storage Disconnects
**Problem**: NFS/CIFS storage intermittently disconnects
**Solution**:
```go
// Implement connection monitoring
// Configure automatic reconnection
// Use local caching for network failures
// Set appropriate TCP keepalive parameters
```
---
## Related Documentation
- **DEVICE_API_STATUS.md** - Complete Device Management API status
- **CERTIFICATE_WIFI_SUMMARY.md** - Certificate and WiFi APIs
- **ONVIF Core Specification** - https://www.onvif.org/specs/core/ONVIF-Core-Specification.pdf
- **ONVIF Device Management WSDL** - https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl
---
## Conclusion
The storage configuration and hashing algorithm APIs provide complete control over:
**Multi-location recording** - Local, NFS, CIFS, cloud
**Enterprise integration** - Windows shares, NAS systems
**Security hardening** - Modern password hashing
**Compliance** - NIST, ISO, industry standards
**Production-ready** - Full test coverage, error handling
All 6 APIs are production-ready with comprehensive testing and documentation.
For support and examples, see the test files and usage examples throughout this document.