Set up device profiling in Android apps
This page shows how to detect the DeviceProfileCallback
, how to collect the device profile,
and how to send the profile to AM.
AM includes collected device information in its audit logs by default. To configure AM to filter out this information and ensure no personally identifiable information (PII) is written to the audit logs, refer to Prevent auditing of device data. |
Handle a device profile callback
If an authentication journey uses the device profile node,
the SDK returns DeviceProfileCallback
to collect device attributes.
You use various SDK methods to handle the callback.
Use the default device profile callback
Call the DeviceProfileCallback.execute()
method to collect the device profile:
callback.execute(context, new FRListener<Void>() {
@Override
public void onSuccess(Void result) {
// call next
}
@Override
public void onException(Exception e) {
}
});
Customize the device profile callback
-
Extend the callback that you want to override, providing two constructors that match the parent constructors.
-
Annotate the constructor with the
@Keep
annotation. -
Override the default implementation:
public class MyCustomDeviceProfileCallback extends DeviceProfileCallback { public MyCustomDeviceProfileCallback() { } @Keep public MyCustomDeviceProfileCallback(JSONObject jsonObject, int index) { super(jsonObject, index); } @Override public void execute(Context context, FRListener<Void> listener) { super.execute(context, listener); } }
-
Register the callback:
CallbackFactory.getInstance().register(MyCustomDeviceProfileCallback.class);
Manually collect device profile information
Instead of responding to a device callback, your app can get the device profile using default collectors.
You can also modify the default collectors. A set of collectors are predefined.
The FRDevice
uses the default predefined collector to collect device profile:
The following code collects the device profile using the default collectors:
FRDeviceCollector.DEFAULT.collect(context, listener);
Default collectors
Collector name | Description |
---|---|
|
Main collector that includes other collectors and provides a collector version. |
|
Collect BLE support information of the device. |
|
Collect browser information of the device; specifically, the |
|
Collect camera information of the device. |
|
Collect display information of the device. |
|
Collect hardware-related information, such as the number of CPUs, number of active CPUs, and so on. |
|
Collect location Information of the device. |
|
Collect network information of the device. |
|
Collect platform-related information, such as device jailbreak status, time zone/locale, OS version, device name, and device model. |
|
Collect telephony information of the device. |
Sample device profile
{
"identifier": "d50cdb5ce8d055a3-86bd35e1b975a14d76b40940112c2380264c8efd",
"metadata": {
"platform": {
"platform": "Android",
"version": 31,
"device": "emulator64_x86_64_arm64",
"deviceName": "sdk_gphone64_x86_64",
"model": "sdk_gphone64_x86_64",
"brand": "google",
"locale": "en_US",
"timeZone": "America/Vancouver",
"jailBreakScore": 1
},
"hardware": {
"hardware": "ranchu",
"manufacturer": "Google",
"storage": 5951,
"memory": 1968,
"cpu": 4,
"display": {
"width": 1080,
"height": 2148,
"orientation": 1
},
"camera": {
"numberOfCameras": 2
}
},
"browser": {
"userAgent": "Mozilla/5.0 (Linux; Android 12; sdk_gphone64_x86_64 Build/SPB5.210812.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/91.0.4472.114 Mobile Safari/537.36"
},
"bluetooth": {
"supported": true
},
"network": {
"connected": true
},
"telephony": {
"networkCountryIso": "us",
"carrierName": "T-Mobile"
}
},
"location": {
"latitude": 37.4219711,
"longitude": -122.0849955
},
"lastSelectedDate": 1634068456582,
"alias": "sdk_gphone64_x86_64"
}
Create a custom collector
-
Create a custom "DeviceCollector" class that implements the
DeviceCollector
interface:public class MyCustomMetadataCollector implements DeviceCollector { private static final List<DeviceCollector> COLLECTORS = new ArrayList<>(); static { //Pick from existing Collector or implement your own collector COLLECTORS.add(new PlatformCollector()); COLLECTORS.add(new NetworkCollector()); COLLECTORS.add(new TelephonyCollector()); } @Override public String getName() { return "metadata"; } @Override public void collect(Context context, FRListener<JSONObject> listener) { collect(context, listener, new JSONObject(), COLLECTORS); } }
-
Use
FRDeviceCollectorBuilder
to add your customCollector
:public class MyCustomDeviceProfileCallback extends DeviceProfileCallback { public MyCustomDeviceProfileCallback() { } @Keep public MyCustomDeviceProfileCallback(JSONObject jsonObject, int index) { super(jsonObject, index); } @Override public void execute(Context context, FRListener<Void> listener) { FRDeviceCollector.FRDeviceCollectorBuilder builder = FRDeviceCollector.builder(); if (isMetadata()) { builder.collector(new MyCustomMetadataCollector()); } if (isLocation()) { builder.collector(new LocationCollector()); } builder.build().collect(context, new FRListener<JSONObject>() { @Override public void onSuccess(JSONObject result) { setValue(result.toString()); Listener.onSuccess(listener, null); } @Override public void onException(Exception e) { Listener.onException(listener, null); } }); } }
Device profile attributes
By default, the ForgeRock SDK collects the following device attributes:
Attribute | Value |
---|---|
|
A unique ID for the device. To learn more about the device identifier, refer to Uniquely identifying devices. |
|
The location of a device (longitude and latitude values). This is configured in the node and requires user permissions. |
|
Metadata for the device, including:
|
Obtain user permission for the device location
Your app requires the user’s authorization to access the device location.
For information about how to request the authorization, refer to Request location permissions.
Implement default jailbreak/rooted device detection
The FRRootDetector
class is responsible for analyzing whether the device is tampered.
The class analyzes the device by using multiple device tamper detectors,
and returns the highest score in the range between 0.0
to 1.0
from all the detectors.
You can customize the metadata.platform.jailBreakScore with Root Detector .
|
Sample using default tamper detection:
// The DEFAULT Detector uses all available detectors in the SDK to determine if the device is rooted.
RootDetector rootDetector = FRRootDetector.DEFAULT;
// Check if device is rooted
double rootedScore = rootDetector.isRooted(context)
// Evaluate the result
if rootedScore == 0.0 {
// Detectors score result with 0.0, likely device is not rooted
}
else if rootedScore <= 0.5 {
// Some of the detectors returned a possible positive result that indicates the device might be rooted
}
else {
// Most of the detectors returned a possible positive result that indicates the device is likely rooted
}
Customize jailbreak/rooted detection
The SDKs provide a set of industry-standard detectors that allow you to customize the detectors to use.
Sample custom tamper detection code:
// Using Builder to choose two detectors
RootDetector rootDetector = FRRootDetector.builder()
.detector(new SuCommandDetector())
.detector(new RootAppDetector())
.build();
// Get result
double rootedScore = rootDetector.isRooted(context)
Implement custom detectors
You can provide your own detectors by implementing the RootDetector
interface on Android.
The interface represents the definition of an individual analyzer for detecting when the device is rooted or jailbroken.
Each detector determines whether the device is rooted or jailbroken.
Each collector returns a result score as a Double
, within the range of 0.0
to 1.0
.
Sample custom detector code:
// Add custom detector to RootDetector
RootDetector rootDetector = FRRootDetector.builder()
.detectors(FRRootDetector.DEFAULT_DETECTORS)
.detector(new RootDetector() {
@Override
public double isRooted(Context context) {
return 0;
}
})
.build();
// Get result
double rootedScore = rootDetector.isRooted(context);