ForgeRock Developer Experience

Customize the storage client

The ForgeRock Authenticator module lets you customize the storage client and manages all data through that client.

Android

The ForgeRock Authenticator module offers a default storage client that uses SecuredSharedPreferences, an encrypted storage mechanism built on Android SharedPreferences. It is available in the forgerock-core module.

SecuredSharedPreferences stores and manages all shared secret account information and notifications.

The Authenticator module lets you customize the StorageClient. You can implement the StorageClient interface, and register your own StorageClient in the module.

You can implement it with SQLite EncryptedSharedPreferences, or any other storage destination.

The ForgeRock Authenticator module uses your storage client and manages all data through that client.

To customize the StorageClient, implement the following interfaces:

public interface StorageClient {
    /**
     * Get the Account object with its id
     * @param accountId The account unique ID
     * @return The account object.
     */
    Account getAccount(String accountId);
    /**
     * Get all accounts stored in the system.
     * @return The complete list of accounts.
     */
    List<Account> getAllAccounts();
    /**
     * Delete the Account that was passed in.
     * @param account The account object to delete.
     * @return boolean as result of the operation
     */
    boolean removeAccount(Account account);
    /**
     * Add or Update the Account to the storage system.
     * @param account The Account to store or update.
     * @return boolean as result of the operation
     */
    boolean setAccount(Account account);
    /**
     * Get the mechanisms associated with an account.
     * @param account The Account object
     * @return The list of mechanisms for the account.
     */
    List<Mechanism> getMechanismsForAccount(Account account);
    /**
     * Get the mechanism by UUID.
     * @param mechanismUID The uniquely identifiable UUID for the mechanism
     * @return The mechanism object.
     */
    Mechanism getMechanismByUUID(String mechanismUID);
    /**
     * Delete the mechanism uniquely identified by an id.
     * @param mechanism The mechanism object to delete.
     * @return boolean as result of the operation
     */
    boolean removeMechanism(Mechanism mechanism);
    /**
     * Add or update the mechanism to the storage system.
     * If the owning Account is not yet stored, store that as well.
     * @param mechanism The mechanism to store or update.
     * @return boolean as result of the operation
     */
    boolean setMechanism(Mechanism mechanism);
    /**
     * Get all notifications for within the mechanism.
     * @param mechanism The mechanism object
     * @return The list of notifications for the mechanism.
     */
    List<PushNotification> getAllNotificationsForMechanism(Mechanism mechanism);
    /**
     * Delete the pushNotification uniquely identified by an id.
     * @param pushNotification The pushNotification object to delete.
     */
    boolean removeNotification(PushNotification pushNotification);
    /**
     * Add or update the pushNotification to the storage system.
     * @param pushNotification The pushNotification to store.
     * @return boolean as result of the operation
     */
    boolean setNotification(PushNotification pushNotification);
    /**
     * Whether the storage system currently contains any data.
     * @return True if the storage system is empty, false otherwise.
     */
    boolean isEmpty();
}

For each method of getting an Account, Mechanism, or PushNotification object, your StorageClient should only be responsible for retrieving the objects, and not any other object associated with it.

For example, when retrieving Account objects, the StorageClient should not be responsible for retrieving Mechanism and PushNotification objects. All object mapping and associations are handled by the ForgeRock Authenticator module itself.

After implementing your custom StorageClient, register it to FRAClient as follows:

//Initiate your custom StorageClient
StorageClient customStorageClient = CustomStorageClient()

//Register it to FRAClient
FRAClient fraClient = new FRAClient.FRAClientBuilder()
                .withContext(this)
                .withStorage(customStorageClient)
                .start();

You must register the StorageClient before you start the ForgeRock SDK.

Once the SDK starts, the StorageClient used by FRAClient cannot be changed.

iOS

The ForgeRock Authenticator default storage client utilizes both Apple’s Keychain Service, and Secure Enclave.

This means that the ForgeRock Authenticator module safely stores all shared secrets, account information, and notifications.

You can also customize the StorageClient. You can implement the StorageClient protocol, and register your own StorageClient with the ForgeRock Authenticator module.

For example, you could customize StorageClient to use SQLite, CoreData, or any other storage destination.

The ForgeRock Authenticator module uses your storage client and manages all data through that client.

To customize StorageClient you must implement the following interfaces:

/// StorageClient protocol represents predefined interfaces and protocols for FRAuthenticator's storage method.
public protocol StorageClient {

    /// Stores Account object into Storage Client and returns discardable Boolean result of operation.
    /// - Parameter account: Account object to store.
    @discardableResult func setAccount(account: Account) -> Bool

    /// Removes Account object from Storage Client, and returns discardable Boolean result of operation.
    /// - Parameter account: Account object to remove.
    @discardableResult func removeAccount(account: Account) -> Bool

    /// Retrieves Account object with its unique identifier.
    /// - Parameter accountIdentifier: String value of Account's unique identifier.
    func getAccount(accountIdentifier: String) -> Account?

    /// Retrieves all Account objects stored in Storage Client.
    func getAllAccounts() -> [Account]

    /// Stores Mechanism object into Storage Client, and returns discardable Boolean result of operation.
    /// - Parameter mechanism: Mechanism object to store.
    @discardableResult func setMechanism(mechanism: Mechanism) -> Bool

    /// Removes Mechanism object from Storage Client, and returns discardable Boolean result of operation.
    /// - Parameter mechanism: Mechanism object to remove.
    @discardableResult func removeMechanism(mechanism: Mechanism) -> Bool

    /// Retrieves all Mechanism objects stored in Storage Client.
    /// - Parameter account: Account object that is associated with Mechanism(s).
    func getMechanismsForAccount(account: Account) -> [Mechanism]

    /// Retrieves Mechanism object with given Mechanism UUID.
    /// - Parameter uuid: UUID of Mechanism.
    func getMechanismForUUID(uuid: String) -> Mechanism?

    /// Stores PushNotification object into Storage Client, and returns discardable Boolean result of operation.
    /// - Parameter notification: PushNotification object to store.
    @discardableResult func setNotification(notification: PushNotification) -> Bool

    /// Removes PushNotification object from Storage Client, and returns discardable Boolean result of operation.
    /// - Parameter notification: PushNotification object to remove.
    @discardableResult func removeNotification(notification: PushNotification) -> Bool

    /// Retrieves all Notification objects from Storage Client with given Mechanism object.
    /// - Parameter mechanism: Mechanism object that is associated with Notification(s).
    func getAllNotificationsForMechanism(mechanism: Mechanism) -> [PushNotification]

    /// Returns whether or not StorageClient has any data stored.
    @discardableResult func isEmpty() -> Bool
}

For each method of getting an Account, Mechanism, or PushNotification object, your StorageClient should only be responsible for retrieving the objects, and not any other object associated with it.

For example, when retrieving Account objects, the StorageClient should not be responsible for retrieving Mechanism and PushNotification objects. All object mapping and associations are handled by the ForgeRock Authenticator module itself.

After implementing your custom StorageClient, register it with your FRAClient as follows:

// Initiate your custom StorageClient
let customStorageClient = CustomStorageClient()
// Register it with your FRAClient
FRAClient.setStorage(storage: customStorageClient)
// Initiate the SDK
FRAClient.start()

You must register the StorageClient before you start the ForgeRock SDK.

Once the SDK starts, the StorageClient used by FRAClient cannot be changed.