PingProtect Module: Advanced Security Integration
Note: The module name differs depending on the dependency manager. Use
PingProtectfor Swift Package Manager (SPM), andPingOneProtectfor CocoaPods.
Overview
The PingProtect module is a powerful component of the Ping Identity iOS SDK, designed to seamlessly integrate Ping
Identity’s Protect service into your mobile applications. It provides comprehensive tools for real-time behavioral data
collection, sophisticated risk analysis, and adaptive authentication strategies. By leveraging this module, developers
can significantly enhance application security, detect and mitigate fraudulent activities, and create a more secure and
user-friendly authentication experience.
Integrating the SDK into your project
Add dependency to your project
To integrate the PingProtect module into your iOS project, add the following dependency to your
Podfile or Package.swift file.
Note: The module name differs depending on the dependency manager. Use
PingProtectfor SPM, andPingOneProtectfor CocoaPods.
pod 'PingOneProtect', '<version>'
or for Swift Package Manager:
.package(url: "https://github.com/ForgeRock/ping-ios-sdk.git", from: "<version>")
Replace <version> with the latest version of the PingProtect SDK.
Usage
DaVinci Integration:
The ProtectCollector class, implementing the Collector protocol, is a critical component for gathering
behavioral risk data. It enables real-time risk assessment during DaVinci flows.
Detailed Data Collection Process:
node.collectors.forEach { collector in
switch collector {
case let protectCollector as ProtectCollector:
let result = await protectCollector.collect()
switch result {
case .success:
// Data collection successful: Proceed to the next node in the DaVinci flow.
node.next()
case .failure:
// Data collection failed: Implement robust error handling.
// Example: Log the error, display an informative message, or implement a retry mechanism.
break
}
// ... Handle other collector types (e.g., OidcCollector, etc.)
default:
break
}
}
The collect() method triggers the risk data collection, returning a .success or .failure result. Upon
success, node.next() advances the DaVinci flow. In case of failure, implement detailed error handling to maintain a
smooth user experience.
Out of scope
The PingProtect module’s data collection results in a payload size that exceeds the practical limits for URL parameters in a GET request. Consequently, the data cannot be included during DaVinci’s start. Instead, the collect() function is employed to retrieve the necessary data when required by the flow.
Journey Integration
The PingOneProtectInitializeCallback is a specialized callback designed to initialize the Protect SDK within the
Journey. It ensures that the SDK is properly configured and ready to collect behavioral data during the user journey.
The PingOneProtectEvaluationCallback is another callback that collects data from the Protect SDK,
allowing the Journey to collect and utilize risk data for decision-making.
node.callbacks.forEach { callback in
switch callback {
case let protectInitCallback as PingOneProtectInitializeCallback:
// Initialize the Protect SDK
let result = await protectInitCallback.start()
switch result {
case .success:
// Initialization successful: Proceed to the next step in the Journey.
break
case .failure(let error):
// Initialization failed: Implement robust error handling.
print("Protect initialization failed: \(error)")
}
case let protectEvalCallback as PingOneProtectEvaluationCallback:
// Collect risk data from the Protect SDK
let result = await protectEvalCallback.collect()
switch result {
case .success:
// Data collection successful: Process the collected data.
break
case .failure(let error):
// Data collection failed: Implement robust error handling.
print("Protect data collection failed: \(error)")
}
// ... Handle other callback types
default:
break
}
}
PingProtect SDK Initialization
Proper initialization is crucial for the PingProtect SDK’s functionality. The SDK offers multiple initialization methods to suit various application architectures and requirements.
Direct Initialization Using the Protect Interface: Fine-Grained Control
For maximum control over SDK configuration, use the Protect interface directly:
await Protect.config { protectConfig in
protectConfig.isBehavioralDataCollection = true // Enable behavioral data collection.
protectConfig.isLazyMetadata = true // Enable lazy loading of device metadata.
protectConfig.envId = URL(string: "https://api.pingone.com")?.host // Set the PingOne environment ID.
protectConfig.deviceAttributesToIgnore = ["deviceId", "androidId", "serialNumber"] // Exclude sensitive device attributes.
protectConfig.isConsoleLogEnabled = true // Enable detailed console logging for debugging.
}
try await Protect.initialize() // Initialize the Protect SDK with the provided configuration.
print("Protect SDK initialized.")
await Protect.pauseBehavioralData() // Temporarily pause behavioral data collection.
await Protect.resumeBehavioralData() // Resume behavioral data collection.
}
Configuration Parameters Explained:
isBehavioralDataCollection: Enables or disables the collection of user behavioral data.isLazyMetadata: Enables lazy loading of device metadata, improving performance by deferring metadata retrieval until needed.envId: Specifies the PingOne environment ID, essential for connecting to your PingOne tenant.deviceAttributesToIgnore: Provides a list of device attributes to exclude from data collection, enhancing privacy and security.customHost: Allows specifying a custom host for the Protect API, useful in specific deployment scenarios.isConsoleLogEnabled: Enables detailed console logging, aiding in debugging and troubleshooting.
sequenceDiagram
participant App
participant Protect
participant DaVinci
participant ProtectCollector
App ->> Protect: config()
App ->> Protect: init()
App ->> DaVinci: start()
DaVinci ->> ProtectCollector: create()
DaVinci ->> App: ProtectCollector
App ->> ProtectCollector: collect()
ProtectCollector ->> Protect: data()
Protect ->> ProtectCollector: data
App ->> DaVinci: next()
note over App: Other interfaces for App
App ->> Protect: pauseBehavioralData()
App ->> Protect: resumeBehavioralData()
Automatic Initialization with the ProtectLifecycle Module: Simplified Management
The ProtectLifecycle module automates the SDK’s lifecycle management, simplifying its integration within DaVinci
flows:
let davinci = DaVinci.createDaVinci { config in
config.module(OidcModule.config) { oidcValue in
oidcValue.clientId = "dummy"
// ... Other Oidc configurations
}
config.module(ProtectLifecycleModule.config) { protectValue in
protectValue.isBehavioralDataCollection = true // Default: true
protectValue.isLazyMetadata = true // Default: false
protectValue.envId = "api.pingone.com" // Default: null
protectValue.deviceAttributesToIgnore = ["deviceId"] // Default: empty list
protectValue.customHost = "https://api.pingone.com" // Default: null
protectValue.isConsoleLogEnabled = true // Default: false
protectValue.pauseBehavioralDataOnSuccess = true // Pause data collection after successful authentication.
protectValue.resumeBehavioralDataOnStart = true // Resume data collection on application start.
}
}
sequenceDiagram
participant App
participant DaVinci
participant Protect
participant ProtectCollector
App ->> DaVinci: start()
DaVinci ->> Protect: config()
DaVinci ->> Protect: init()
DaVinci ->> Protect: resumeBehavioralData()
DaVinci ->> ProtectCollector: create()
DaVinci ->> App: ProtectCollector
App ->> ProtectCollector: collect()
ProtectCollector ->> Protect: data()
Protect ->> ProtectCollector: data
ProtectCollector ->> App: data
App ->> DaVinci: next()
alt isSuccess
DaVinci ->> Protect: pauseBehavioralData()
end
Lazy Initialization: On-Demand SDK Activation
The SDK employs lazy initialization, meaning it only activates when triggered by server responses, such as the instantiation of Collector or Callback objects. This approach conserves resources and accelerates application startup. However, the initial interaction with the PingProtect SDK might experience a slight delay. Furthermore, if behavioral data collection is active, the initial lack of SDK activation could result in incomplete data capture, potentially requiring data collection later in the application flow.
sequenceDiagram
participant App
participant DaVinci
participant Protect
participant ProtectCollector
App ->> DaVinci: start()
DaVinci ->> ProtectCollector: create()
DaVinci ->> App: ProtectCollector
App ->> ProtectCollector: collect()
ProtectCollector ->> Protect: config()
ProtectCollector ->> Protect: init()
ProtectCollector ->> Protect: data()
Protect ->> ProtectCollector: data
ProtectCollector ->> App: data
App ->> DaVinci: next()
[!WARNING] The Signal SDK, used internally by the Protect SDK, employs a Singleton pattern. This means it can only be initialized once. Subsequent
init()calls are ignored.
Pause and Resume Behavioral Data Collection: Granular Control
Control behavioral data collection with the following methods:
await Protect.pauseBehavioralData() // Pause data collection.
await Protect.resumeBehavioralData() // Resume data collection.
These methods allow for granular control over data collection, enabling you to pause collection during sensitive operations or when required by user privacy preferences.
View on GitHub