diff --git a/forgerock-auth/src/main/java/org/forgerock/android/auth/callback/AbstractProtectCallback.kt b/forgerock-auth/src/main/java/org/forgerock/android/auth/callback/AbstractProtectCallback.kt new file mode 100644 index 00000000..3342329f --- /dev/null +++ b/forgerock-auth/src/main/java/org/forgerock/android/auth/callback/AbstractProtectCallback.kt @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2024 ForgeRock. All rights reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +package org.forgerock.android.auth.callback + +import androidx.annotation.Keep +import org.forgerock.android.auth.Node +import org.json.JSONException +import org.json.JSONObject + +const val _ACTION = "_action" +const val _TYPE = "_type" +const val CLIENT_ERROR = "clientError" +const val PING_ONE_RISK_EVALUATION_SIGNALS = "pingone_risk_evaluation_signals" +const val PING_ONE_PROTECT = "PingOneProtect" +const val PROTECT_INITIALIZE = "protect_initialize" +const val PROTECT_RISK_EVALUATION = "protect_risk_evaluation" +const val PING_ONE_PROTECT_INITIALIZE_CALLBACK = "PingOneProtectInitializeCallback" +const val PING_ONE_PROTECT_EVALUATION_CALLBACK = "PingOneProtectEvaluationCallback" + +/** + * Abstract Protect Callback that provides the raw content of the Callback, and common methods + * for sub classes to access. + */ +abstract class AbstractProtectCallback: NodeAware, AbstractCallback { + + /** + * Indicates if this callback is derived from a [MetadataCallback] + */ + protected var derivedCallback: Boolean = false + + /** + * Constructor for [AbstractProtectCallback]. Capable of parsing the [MetadataCallback] used for Protect. + */ + @Keep + constructor(jsonObject: JSONObject, index: Int) : super(jsonObject, index) { + val type = jsonObject.optString("type") + if (type == "MetadataCallback") { + derivedCallback = true + jsonObject.optJSONArray("output")?.let { output -> + output.getJSONObject(0)?.let { nameValuePair -> + if (nameValuePair.optString("name") == "data") { + nameValuePair.optJSONObject("value")?.let { value -> + value.keys().forEach { attr -> + setAttribute(attr, value.get(attr)) + } + } + } + } + } + } + } + + @Keep + constructor() : super() + + /** + * The [Node] that associate with this Callback + */ + private lateinit var node: Node + + override fun setNode(node: Node) { + this.node = node + } + + /** + * Get the [Node] that associate with this Callback + * + * @return The [Node] that associate with this Callback + */ + protected fun getNode(): Node { + return node + } + + /** + * Input the Client Error to the server + * + * @param value Protect ErrorType + * @param index The index of the error + */ + fun setClientError(value: String, index: Int) { + if (derivedCallback) { + setClientErrorInHiddenCallback(value); + } else { + super.setValue(value, index) + } + } + + /** + * Set the client error to the [HiddenValueCallback] which associated with the Protect + * Callback. + * + * @param value The Value to set to the [HiddenValueCallback] + */ + private fun setClientErrorInHiddenCallback(value: String) { + for (callback in node.callbacks) { + if (callback is HiddenValueCallback) { + if (callback.id.contains(CLIENT_ERROR)) { + callback.value = value + } + } + } + } + + companion object { + + /** + * Check if this callback is [PingOneProtectInitializeCallback] Type + * + * @param value The callback raw data json. + * @return True if this is a [PingOneProtectInitializeCallback] Type, else false + */ + @JvmStatic + fun isPingOneProtectInitializeCallback(value: JSONObject): Boolean { + return try { + value.has(_TYPE) && value.getString(_TYPE) == PING_ONE_PROTECT && (value.has( + _ACTION + ) && value.getString(_ACTION) == PROTECT_INITIALIZE) + } catch (e: JSONException) { + false + } + } + + /** + * Check if this callback is [PingOneProtectEvaluationCallback] Type + * + * @param value The callback raw data json. + * @return True if this is a [PingOneProtectEvaluationCallback] Type, else false + */ + @JvmStatic + fun isPingOneProtectEvaluationCallback(value: JSONObject): Boolean { + return try { + value.has(_TYPE) && value.getString(_TYPE) == PING_ONE_PROTECT && (value.has( + _ACTION + ) && value.getString(_ACTION) == PROTECT_RISK_EVALUATION) + } catch (e: JSONException) { + false + } + } + + } + +} \ No newline at end of file diff --git a/forgerock-auth/src/main/java/org/forgerock/android/auth/callback/MetadataCallback.java b/forgerock-auth/src/main/java/org/forgerock/android/auth/callback/MetadataCallback.java index 272c8509..7c037903 100644 --- a/forgerock-auth/src/main/java/org/forgerock/android/auth/callback/MetadataCallback.java +++ b/forgerock-auth/src/main/java/org/forgerock/android/auth/callback/MetadataCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2022 ForgeRock. All rights reserved. + * Copyright (c) 2021 - 2024 ForgeRock. All rights reserved. * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. @@ -7,6 +7,9 @@ package org.forgerock.android.auth.callback; +import static org.forgerock.android.auth.callback.AbstractProtectCallbackKt.PING_ONE_PROTECT_EVALUATION_CALLBACK; +import static org.forgerock.android.auth.callback.AbstractProtectCallbackKt.PING_ONE_PROTECT_INITIALIZE_CALLBACK; + import androidx.annotation.Keep; import org.json.JSONException; @@ -86,6 +89,12 @@ public Class getDerivedCallback() { if (WebAuthnAuthenticationCallback.instanceOf(value)) { return CallbackFactory.getInstance().getCallbacks().get("WebAuthnAuthenticationCallback"); } + if (AbstractProtectCallback.isPingOneProtectInitializeCallback(value)) { + return CallbackFactory.getInstance().getCallbacks().get(PING_ONE_PROTECT_INITIALIZE_CALLBACK); + } + if (AbstractProtectCallback.isPingOneProtectEvaluationCallback(value)) { + return CallbackFactory.getInstance().getCallbacks().get(PING_ONE_PROTECT_EVALUATION_CALLBACK); + } return null; } } diff --git a/forgerock-auth/src/test/java/org/forgerock/android/auth/callback/MetadataCallbackTest.kt b/forgerock-auth/src/test/java/org/forgerock/android/auth/callback/MetadataCallbackTest.kt index 9a41fde0..59f766db 100644 --- a/forgerock-auth/src/test/java/org/forgerock/android/auth/callback/MetadataCallbackTest.kt +++ b/forgerock-auth/src/test/java/org/forgerock/android/auth/callback/MetadataCallbackTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 ForgeRock. All rights reserved. + * Copyright (c) 2023 - 2024 ForgeRock. All rights reserved. * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. @@ -58,6 +58,22 @@ class MetadataCallbackTest : BaseTest() { WebAuthnAuthenticationCallback::class.java) } + @Test + @Throws(JSONException::class) + fun testDerivedCallbackProtectInitialize() { + val callback = MetadataCallback(JSONObject(getJson("/protect_initialize.json")) + .getJSONArray("callbacks").getJSONObject(0), 0) + Assertions.assertThat(AbstractProtectCallback.isPingOneProtectInitializeCallback(callback.value)).isTrue() + } + + @Test + @Throws(JSONException::class) + fun testDerivedCallbackProtectRiskEvaluation() { + val callback = MetadataCallback(JSONObject(getJson("/protect_risk_evaluation.json")) + .getJSONArray("callbacks").getJSONObject(0), 0) + Assertions.assertThat(AbstractProtectCallback.isPingOneProtectEvaluationCallback(callback.value)).isTrue() + } + @Test @Throws(JSONException::class) fun testDerivedCallbackUndefined() { diff --git a/forgerock-auth/src/test/resources/protect_initialize.json b/forgerock-auth/src/test/resources/protect_initialize.json new file mode 100644 index 00000000..5585c4f3 --- /dev/null +++ b/forgerock-auth/src/test/resources/protect_initialize.json @@ -0,0 +1,46 @@ +{ + "authId": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRoSW5kZXhWYWx1ZSI6IndlYmF1dGhuX3JlZyIsIm90ayI6Ijluc2E1YWVva2E3YXBuaW84bHBycXAxc242IiwiYXV0aEluZGV4VHlwZSI6InNlcnZpY2UiLCJyZWFsbSI6Ii8iLCJzZXNzaW9uSWQiOiIqQUFKVFNRQUNNREVBQkhSNWNHVUFDRXBYVkY5QlZWUklBQUpUTVFBQSpleUowZVhBaU9pSktWMVFpTENKamRIa2lPaUpLVjFRaUxDSmhiR2NpT2lKSVV6STFOaUo5LlpYbEtNR1ZZUVdsUGFVcExWakZSYVV4RFNteGliVTFwVDJsS1FrMVVTVFJSTUVwRVRGVm9WRTFxVlRKSmFYZHBXVmQ0YmtscWIybGFSMng1U1c0d0xpNWpVSHBGZG1OVFpIRk9UbHB4UVZsaExWaEhhMWhSTG1wMVVscEZkRFZ4Y2tsRlpWQTNOMDh4TUhSbk5IbGlVRTV2UW5acmIzUjBiM2RXWDA5dGFYaDVjWE5uWm1OelFXVlJTR1pWVVRrd2NsaHRiRXBFVTNkNFZVUjZibEJrZUVWWVJXSllkRUZYUlhWeVdXWjVOMnhwT0Vaa1ZHcDNaSGxDT1VjM2Nrd3ROVlJsZG1VNFlsazRUM1ZSU0VOclkweDBSbEZYT1ZkdmNtRlpNSFpvWlVWMGJWZFhTM3BaWlZsT2FXSTJPSEV0Um5SUGFVcGlVbGxFUkRCeVdEWllPRFF4ZDJaRmNGaGxXRTF5UjBORVJEaE1aMnhWV0ZkMWNIVnRaelkxU0VsM1QwMDBRMnRFWVVjM1MybEZjMWxEUlRkRlVFOTJRM1ZqWTJReFNYaGtlbWt0ZWs5d09UVlVPR1IzTTFWcVZrbE5VMUpMUzNWSGJtVkVlRjl4VWxGdlNHOVFVa1ptU1dOek9XZHNObWxtWkRKd1gwSTBPR3hDTWpKRU5XZEJhaTFJUzBKRlRuRkhOSFV0TjBoNlgyOXROWGgwWVdNNWJISTBSRnBhZUMxcVRtUm1YMVp0ZERSNU4wWkpNRXQ0Tmkwd2NsTlNVVXRIT0ZsSFExWXdWMFZMTWt0QlMzcHRaalpyWVZaaVdETTFTR3BFVHpCMUxYUlFVV1ZSU1hnMVMwaFVXRmhMTmxNelZsOXBhVTlaTmxoTlpURXllV3A0Y0VWTlJUWmlSbkozWm5wc2VYQlpjSFJhZVZreE4xcGZYMWhVY2pkWk0xcHhTVlJST0RWaWJWZHZTMFowTkRoZlgyeEVWbTFZUkVSblIydHlWR3hMZFRoTlNVazFNWGszUWxKVFFrZEdkV2N4VUhwaVVuazRVRGx3TlZKaFJtVXRORU5GVEhGdFNsOUdMV2RDZG1ob1RUWldibUZaVVdoTGJ6Y3laR05rV2s1a1pUaEllazVCYm1WTVQzTkNVRE5aTkRscVdHVkNaR2gwVmpaalNsOXBMWHBxYjFSVVowSktVVkJXVUdoSVNtTnhkamhzTFRaa05sZGhlRWgzWnpaSmJUUlNhek4zTFVNMFlVVlBNREI0U1U5Nk0zVTJRVU5HVFRGakxVaE5jMUZsZVV0c1NtOUtOVFZuT0ZSMFJubE9WVFpVVm5OemRYVmlSRzVTTlVoYWJWazVVRGhuZEZSQmJ6VlBUakk0V1c5WVgxcDRZVk5aUXpGek1UUktTV3hoYzJ4NE1uTmFOelUzVWpVMGVFNUlWM3BtVDNkTlJtazVWWHA0VjFjNVpVVnVjSGw2YUhsT1NqRnlNelJNYnk1R1UyTnNabk10YkdSalpWSmhNVjh5VmtWWGRqaEIuSElHZFprUVNwbzR4U0dUVmlabEdSN3psRExvV09uOHhNQmt3MVRVZ05qVSIsImV4cCI6MTYxMzY5NTI1MywiaWF0IjoxNjEzNjk0OTUzfQ.BOdMUcaZbRNGkYAQu-Z_sBZMMHW4hdKDrXnBCbZhrxA", + "callbacks": [ + { + "type": "MetadataCallback", + "output": [ + { + "name": "data", + "value": { + "_type": "PingOneProtect", + "_action": "protect_initialize", + "envId": "some_id", + "consoleLogEnabled": true, + "deviceAttributesToIgnore": [], + "customHost": "", + "lazyMetadata": true, + "behavioralDataCollection": true, + "disableHub": true, + "deviceKeyRsyncIntervals": 10, + "enableTrust": true, + "disableTags": true + } + } + ] + }, + { + "type": "HiddenValueCallback", + "output": [ + { + "name": "value", + "value": "" + }, + { + "name": "id", + "value": "clientError" + } + ], + "input": [ + { + "name": "IDToken2", + "value": "clientError" + } + ] + } + ] +} \ No newline at end of file diff --git a/forgerock-auth/src/test/resources/protect_risk_evaluation.json b/forgerock-auth/src/test/resources/protect_risk_evaluation.json new file mode 100644 index 00000000..41fa3017 --- /dev/null +++ b/forgerock-auth/src/test/resources/protect_risk_evaluation.json @@ -0,0 +1,57 @@ +{ + "authId": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRoSW5kZXhWYWx1ZSI6IndlYmF1dGhuX3JlZyIsIm90ayI6Ijluc2E1YWVva2E3YXBuaW84bHBycXAxc242IiwiYXV0aEluZGV4VHlwZSI6InNlcnZpY2UiLCJyZWFsbSI6Ii8iLCJzZXNzaW9uSWQiOiIqQUFKVFNRQUNNREVBQkhSNWNHVUFDRXBYVkY5QlZWUklBQUpUTVFBQSpleUowZVhBaU9pSktWMVFpTENKamRIa2lPaUpLVjFRaUxDSmhiR2NpT2lKSVV6STFOaUo5LlpYbEtNR1ZZUVdsUGFVcExWakZSYVV4RFNteGliVTFwVDJsS1FrMVVTVFJSTUVwRVRGVm9WRTFxVlRKSmFYZHBXVmQ0YmtscWIybGFSMng1U1c0d0xpNWpVSHBGZG1OVFpIRk9UbHB4UVZsaExWaEhhMWhSTG1wMVVscEZkRFZ4Y2tsRlpWQTNOMDh4TUhSbk5IbGlVRTV2UW5acmIzUjBiM2RXWDA5dGFYaDVjWE5uWm1OelFXVlJTR1pWVVRrd2NsaHRiRXBFVTNkNFZVUjZibEJrZUVWWVJXSllkRUZYUlhWeVdXWjVOMnhwT0Vaa1ZHcDNaSGxDT1VjM2Nrd3ROVlJsZG1VNFlsazRUM1ZSU0VOclkweDBSbEZYT1ZkdmNtRlpNSFpvWlVWMGJWZFhTM3BaWlZsT2FXSTJPSEV0Um5SUGFVcGlVbGxFUkRCeVdEWllPRFF4ZDJaRmNGaGxXRTF5UjBORVJEaE1aMnhWV0ZkMWNIVnRaelkxU0VsM1QwMDBRMnRFWVVjM1MybEZjMWxEUlRkRlVFOTJRM1ZqWTJReFNYaGtlbWt0ZWs5d09UVlVPR1IzTTFWcVZrbE5VMUpMUzNWSGJtVkVlRjl4VWxGdlNHOVFVa1ptU1dOek9XZHNObWxtWkRKd1gwSTBPR3hDTWpKRU5XZEJhaTFJUzBKRlRuRkhOSFV0TjBoNlgyOXROWGgwWVdNNWJISTBSRnBhZUMxcVRtUm1YMVp0ZERSNU4wWkpNRXQ0Tmkwd2NsTlNVVXRIT0ZsSFExWXdWMFZMTWt0QlMzcHRaalpyWVZaaVdETTFTR3BFVHpCMUxYUlFVV1ZSU1hnMVMwaFVXRmhMTmxNelZsOXBhVTlaTmxoTlpURXllV3A0Y0VWTlJUWmlSbkozWm5wc2VYQlpjSFJhZVZreE4xcGZYMWhVY2pkWk0xcHhTVlJST0RWaWJWZHZTMFowTkRoZlgyeEVWbTFZUkVSblIydHlWR3hMZFRoTlNVazFNWGszUWxKVFFrZEdkV2N4VUhwaVVuazRVRGx3TlZKaFJtVXRORU5GVEhGdFNsOUdMV2RDZG1ob1RUWldibUZaVVdoTGJ6Y3laR05rV2s1a1pUaEllazVCYm1WTVQzTkNVRE5aTkRscVdHVkNaR2gwVmpaalNsOXBMWHBxYjFSVVowSktVVkJXVUdoSVNtTnhkamhzTFRaa05sZGhlRWgzWnpaSmJUUlNhek4zTFVNMFlVVlBNREI0U1U5Nk0zVTJRVU5HVFRGakxVaE5jMUZsZVV0c1NtOUtOVFZuT0ZSMFJubE9WVFpVVm5OemRYVmlSRzVTTlVoYWJWazVVRGhuZEZSQmJ6VlBUakk0V1c5WVgxcDRZVk5aUXpGek1UUktTV3hoYzJ4NE1uTmFOelUzVWpVMGVFNUlWM3BtVDNkTlJtazVWWHA0VjFjNVpVVnVjSGw2YUhsT1NqRnlNelJNYnk1R1UyTnNabk10YkdSalpWSmhNVjh5VmtWWGRqaEIuSElHZFprUVNwbzR4U0dUVmlabEdSN3psRExvV09uOHhNQmt3MVRVZ05qVSIsImV4cCI6MTYxMzY5NTI1MywiaWF0IjoxNjEzNjk0OTUzfQ.BOdMUcaZbRNGkYAQu-Z_sBZMMHW4hdKDrXnBCbZhrxA", + "callbacks": [ + { + "type": "MetadataCallback", + "output": [ + { + "name": "data", + "value": { + "_type": "PingOneProtect", + "_action": "protect_risk_evaluation", + "envId" : "some_id", + "pauseBehavioralData" : true + } + } + ] + }, + { + "type": "HiddenValueCallback", + "output": [ + { + "name": "value", + "value": "" + }, + { + "name": "id", + "value": "pingone_risk_evaluation_signals" + } + ], + "input": [ + { + "name": "IDToken1", + "value": "pingone_risk_evaluation_signals" + } + ] + }, + { + "type": "HiddenValueCallback", + "output": [ + { + "name": "value", + "value": "" + }, + { + "name": "id", + "value": "clientError" + } + ], + "input": [ + { + "name": "IDToken1", + "value": "clientError" + } + ] + } + ] +} \ No newline at end of file diff --git a/ping-protect/src/main/java/org/forgerock/android/auth/PingOneProtectEvaluationCallback.kt b/ping-protect/src/main/java/org/forgerock/android/auth/PingOneProtectEvaluationCallback.kt index 5d281aa8..112aa71f 100644 --- a/ping-protect/src/main/java/org/forgerock/android/auth/PingOneProtectEvaluationCallback.kt +++ b/ping-protect/src/main/java/org/forgerock/android/auth/PingOneProtectEvaluationCallback.kt @@ -8,7 +8,9 @@ package org.forgerock.android.auth import android.content.Context import androidx.annotation.Keep -import org.forgerock.android.auth.callback.AbstractCallback +import org.forgerock.android.auth.callback.AbstractProtectCallback +import org.forgerock.android.auth.callback.HiddenValueCallback +import org.forgerock.android.auth.callback.PING_ONE_RISK_EVALUATION_SIGNALS import org.json.JSONObject private val TAG = PingOneProtectEvaluationCallback::class.java.simpleName @@ -16,13 +18,14 @@ private val TAG = PingOneProtectEvaluationCallback::class.java.simpleName /** * Callback to evaluate Ping One Protect */ -open class PingOneProtectEvaluationCallback : AbstractCallback { +open class PingOneProtectEvaluationCallback : AbstractProtectCallback { @Keep constructor(jsonObject: JSONObject, index: Int) : super(jsonObject, index) @Keep constructor() : super() + /** * The pauseBehavioralData received from server */ @@ -43,15 +46,26 @@ open class PingOneProtectEvaluationCallback : AbstractCallback { * @param value The JWS value. */ fun setSignals(value: String) { - super.setValue(value, 0) + if (derivedCallback) { + setSignalsInHiddenCallback(value) + } else { + super.setValue(value, 0) + } } /** - * Input the Client Error to the server - * @param value Protect ErrorType . + * Set the signals to the [HiddenValueCallback] which associated with the callback. + * + * @param value The Value to set to the [HiddenValueCallback]. */ - fun setClientError(value: String) { - super.setValue(value, 1) + private fun setSignalsInHiddenCallback(value: String) { + for (callback in getNode().callbacks) { + if (callback is HiddenValueCallback) { + if (callback.id.contains(PING_ONE_RISK_EVALUATION_SIGNALS)) { + callback.value = value + } + } + } } /** @@ -69,10 +83,11 @@ open class PingOneProtectEvaluationCallback : AbstractCallback { } catch (e: Exception) { Logger.error(TAG, t = e, message = e.message) - setClientError(e.message ?: "clientError") + setClientError(e.message ?: "clientError", 1) throw e } } + } /** diff --git a/ping-protect/src/main/java/org/forgerock/android/auth/PingOneProtectInitializeCallback.kt b/ping-protect/src/main/java/org/forgerock/android/auth/PingOneProtectInitializeCallback.kt index 0487363b..8e99d4ee 100644 --- a/ping-protect/src/main/java/org/forgerock/android/auth/PingOneProtectInitializeCallback.kt +++ b/ping-protect/src/main/java/org/forgerock/android/auth/PingOneProtectInitializeCallback.kt @@ -8,7 +8,7 @@ package org.forgerock.android.auth import android.content.Context import androidx.annotation.Keep -import org.forgerock.android.auth.callback.AbstractCallback +import org.forgerock.android.auth.callback.AbstractProtectCallback import org.json.JSONArray import org.json.JSONException import org.json.JSONObject @@ -19,7 +19,8 @@ private val TAG = PingOneProtectInitializeCallback::class.java.simpleName /** * Callback to initialize the ping one protect */ -open class PingOneProtectInitializeCallback : AbstractCallback { +open class PingOneProtectInitializeCallback : AbstractProtectCallback { + @Keep constructor(jsonObject: JSONObject, index: Int) : super(jsonObject, index) @@ -77,14 +78,6 @@ open class PingOneProtectInitializeCallback : AbstractCallback { return "PingOneProtectInitializeCallback" } - /** - * Input the Client Error to the server - * @param value Protect ErrorType . - */ - fun setClientError(value: String) { - super.setValue(value, 0) - } - /** * Collect the behavior. Calling the [start] function. * @@ -110,7 +103,7 @@ open class PingOneProtectInitializeCallback : AbstractCallback { } } catch (e: Exception) { Logger.error(TAG, t = e, message = e.message) - setClientError(e.message ?: "clientError") + setClientError(e.message ?: "clientError", 0) throw e } } diff --git a/ping-protect/src/test/java/org/forgerock/android/auth/PingOneProtectEvaluationCallbackTest.kt b/ping-protect/src/test/java/org/forgerock/android/auth/PingOneProtectEvaluationCallbackTest.kt index 7a4d6363..bedd30ff 100644 --- a/ping-protect/src/test/java/org/forgerock/android/auth/PingOneProtectEvaluationCallbackTest.kt +++ b/ping-protect/src/test/java/org/forgerock/android/auth/PingOneProtectEvaluationCallbackTest.kt @@ -31,6 +31,7 @@ class PingOneProtectEvaluationCallbackTest { fun setUp() { MockKAnnotations.init(this) } + @Test fun basicTest() { val json = "{\"type\":\"PingOneProtectEvaluationCallback\",\"output\":[{\"name\":\"pauseBehavioralData\",\"value\":true}],\"input\":[{\"name\":\"IDToken1signals\",\"value\":\"HcSd8yBF7G0g0d0lzzz6rci4I0IB+VZdFl6bBiRN2RjMhjSsipf0h0JC4ganxwiBRzSoGwMMZagmq7Teoabm6cZ8X0mStPL\\/bzCCAQPc5wmGmW2M7GKEITiEQbgHN+ZB\\/cd8g6MmCJsYK5OYplbG\\/SDuCtWZDIS4mUdxywlTFDMmXm9tC2Fy5vfgk+9DX4eOSPIHiQq5wPpGsILrY17H87A4Qt4gb6ITC2s9Oo7qf8R0gfiJttuPyWYFL7w1KoiuUi6JPf5v2H0HW04Mc1qlZwD44Dd7RlHGQeGs\\/fk21KZ6kKI4cTd8eHAt3Vrl29yIhn6Ce\\/go1Ve\\/0qj0DWx703SRbuc5IBm8AR\\/q9DpxQkEd8PC8+FWBisuGLTQyjqTS6DCEy7LwgR0LU28Hwdw1jDeZgoZy54kCpo6v9B6x1\\/bkNH8YtlSt9uz\\/A9UinS4g0VdN09H6SXKXNxn4bYhJeWK7c4q9Byvuye1M08qh7JWzMKpkWyZwaeC6zIaMQhiwrodyjS+S25dBk1YcQ==.eDE=\"},{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}" @@ -39,6 +40,29 @@ class PingOneProtectEvaluationCallbackTest { assertEquals(true, pingOneEvalCallback.pauseBehavioralData) } + + @Test + fun parseMetadataCallbackTest() { + val raw = JSONObject("""{ + "type": "MetadataCallback", + "output": [ + { + "name": "data", + "value": { + "_type": "PingOneProtect", + "_action": "protect_risk_evaluation", + "envId" : "some_id", + "pauseBehavioralData" : true + } + } + ], + "_id": 0 + }""") + + val pingOneEvalCallback = PingOneProtectEvaluationCallback(raw, 0) + assertEquals(true, pingOneEvalCallback.pauseBehavioralData) + } + @Test fun initBehaviorData() = runBlocking { mockkObject(PIProtect) @@ -47,7 +71,10 @@ class PingOneProtectEvaluationCallbackTest { } returns("result") val json = "{\"type\":\"PingOneProtectEvaluationCallback\",\"output\":[{\"name\":\"pauseBehavioralData\",\"value\":true}],\"input\":[{\"name\":\"IDToken1signals\",\"value\":\"HcSd8yBF7G0g0d0lzzz6rci4I0IB+VZdFl6bBiRN2RjMhjSsipf0h0JC4ganxwiBRzSoGwMMZagmq7Teoabm6cZ8X0mStPL\\/bzCCAQPc5wmGmW2M7GKEITiEQbgHN+ZB\\/cd8g6MmCJsYK5OYplbG\\/SDuCtWZDIS4mUdxywlTFDMmXm9tC2Fy5vfgk+9DX4eOSPIHiQq5wPpGsILrY17H87A4Qt4gb6ITC2s9Oo7qf8R0gfiJttuPyWYFL7w1KoiuUi6JPf5v2H0HW04Mc1qlZwD44Dd7RlHGQeGs\\/fk21KZ6kKI4cTd8eHAt3Vrl29yIhn6Ce\\/go1Ve\\/0qj0DWx703SRbuc5IBm8AR\\/q9DpxQkEd8PC8+FWBisuGLTQyjqTS6DCEy7LwgR0LU28Hwdw1jDeZgoZy54kCpo6v9B6x1\\/bkNH8YtlSt9uz\\/A9UinS4g0VdN09H6SXKXNxn4bYhJeWK7c4q9Byvuye1M08qh7JWzMKpkWyZwaeC6zIaMQhiwrodyjS+S25dBk1YcQ==.eDE=\"},{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}" val raw = JSONObject(json) + val node = Node("dummy-auth-id", "", "", + "", "", mutableListOf()) val pingOneEvalCallback = PingOneProtectEvaluationCallback(raw, 0) + pingOneEvalCallback.setNode(node) pingOneEvalCallback.getData(context) assertTrue(pingOneEvalCallback.content.contains("result")) coVerify(exactly = 1) { PIProtect.getData() } @@ -64,7 +91,10 @@ class PingOneProtectEvaluationCallbackTest { try { val json = "{\"type\":\"PingOneProtectEvaluationCallback\",\"output\":[{\"name\":\"pauseBehavioralData\",\"value\":true}],\"input\":[{\"name\":\"IDToken1signals\",\"value\":\"HcSd8yBF7G0g0d0lzzz6rci4I0IB+VZdFl6bBiRN2RjMhjSsipf0h0JC4ganxwiBRzSoGwMMZagmq7Teoabm6cZ8X0mStPL\\/bzCCAQPc5wmGmW2M7GKEITiEQbgHN+ZB\\/cd8g6MmCJsYK5OYplbG\\/SDuCtWZDIS4mUdxywlTFDMmXm9tC2Fy5vfgk+9DX4eOSPIHiQq5wPpGsILrY17H87A4Qt4gb6ITC2s9Oo7qf8R0gfiJttuPyWYFL7w1KoiuUi6JPf5v2H0HW04Mc1qlZwD44Dd7RlHGQeGs\\/fk21KZ6kKI4cTd8eHAt3Vrl29yIhn6Ce\\/go1Ve\\/0qj0DWx703SRbuc5IBm8AR\\/q9DpxQkEd8PC8+FWBisuGLTQyjqTS6DCEy7LwgR0LU28Hwdw1jDeZgoZy54kCpo6v9B6x1\\/bkNH8YtlSt9uz\\/A9UinS4g0VdN09H6SXKXNxn4bYhJeWK7c4q9Byvuye1M08qh7JWzMKpkWyZwaeC6zIaMQhiwrodyjS+S25dBk1YcQ==.eDE=\"},{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}" val raw = JSONObject(json) + val node = Node("dummy-auth-id", "", "", + "", "", mutableListOf()) val pingOneEvalCallback = PingOneProtectEvaluationCallback(raw, 0) + pingOneEvalCallback.setNode(node) pingOneEvalCallback.getData(context) fail() } catch (e: Exception) { diff --git a/ping-protect/src/test/java/org/forgerock/android/auth/PingOneProtectInitializeCallbackTest.kt b/ping-protect/src/test/java/org/forgerock/android/auth/PingOneProtectInitializeCallbackTest.kt index e7ff9ec7..ae7ae293 100644 --- a/ping-protect/src/test/java/org/forgerock/android/auth/PingOneProtectInitializeCallbackTest.kt +++ b/ping-protect/src/test/java/org/forgerock/android/auth/PingOneProtectInitializeCallbackTest.kt @@ -45,6 +45,43 @@ class PingOneProtectInitializeCallbackTest { pingOneInitCallback.consoleLogEnabled) } + @Test + fun parseMetadataCallbackTest() { + val raw = JSONObject("""{ + "type": "MetadataCallback", + "output": [ + { + "name": "data", + "value": { + "_type": "PingOneProtect", + "_action": "protect_initialize", + "envId" : "02fb4743-189a-4bc7-9d6c-a919edfe6447", + "consoleLogEnabled" : true, + "deviceAttributesToIgnore" : [], + "customHost" : "", + "lazyMetadata" : true, + "behavioralDataCollection" : true, + "disableHub" : true, + "deviceKeyRsyncIntervals" : 10, + "enableTrust" : true, + "disableTags" : true + } + } + ], + "_id": 0 + }""") + + val pingOneInitCallback = PingOneProtectInitializeCallback(raw, 0) + assertEquals("02fb4743-189a-4bc7-9d6c-a919edfe6447", + pingOneInitCallback.envId) + assertEquals(true, + pingOneInitCallback.behavioralDataCollection) + assertEquals(true, + pingOneInitCallback.consoleLogEnabled) + assertEquals(true, + pingOneInitCallback.lazyMetadata) + } + @Test fun basicTestDifferentParam() { val json = "{\"type\":\"PingOneProtectInitializeCallback\",\"output\":[{\"name\":\"envId\",\"value\":\"02fb4743-189a-4bc7-9d6c-a919edfe6447\"},{\"name\":\"consoleLogEnabled\",\"value\":false},{\"name\":\"deviceAttributesToIgnore\",\"value\":[]},{\"name\":\"customHost\",\"value\":\"\"},{\"name\":\"lazyMetadata\",\"value\":false},{\"name\":\"behavioralDataCollection\",\"value\":false},{\"name\":\"deviceKeyRsyncIntervals\",\"value\":14},{\"name\":\"enableTrust\",\"value\":false},{\"name\":\"disableTags\",\"value\":false},{\"name\":\"disableHub\",\"value\":false}],\"input\":[{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}" @@ -128,6 +165,8 @@ class PingOneProtectInitializeCallbackTest { fun `test exception`() = runBlocking { mockkObject(PIProtect) val mockSlot = slot() + val node = Node("dummy-auth-id", "", "", + "", "", mutableListOf()) coEvery { PIProtect.start(context, capture(mockSlot)) } throws(PingOneProtectInitException("init failed")) @@ -142,6 +181,7 @@ class PingOneProtectInitializeCallbackTest { "{\"type\":\"PingOneProtectInitializeCallback\",\"output\":[{\"name\":\"envId\",\"value\":\"02fb4743-189a-4bc7-9d6c-a919edfe6447\"},{\"name\":\"consoleLogEnabled\",\"value\":false},{\"name\":\"deviceAttributesToIgnore\",\"value\":[\"value1\", \"value2\"]},{\"name\":\"customHost\",\"value\":\"\"},{\"name\":\"lazyMetadata\",\"value\":false},{\"name\":\"behavioralDataCollection\",\"value\":false},{\"name\":\"deviceKeyRsyncIntervals\",\"value\":14},{\"name\":\"enableTrust\",\"value\":false},{\"name\":\"disableTags\",\"value\":false},{\"name\":\"disableHub\",\"value\":false}],\"input\":[{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}" val raw = JSONObject(json) val pingOneInitCallback = PingOneProtectInitializeCallback(raw, 0) + pingOneInitCallback.setNode(node) pingOneInitCallback.start(context) fail() } catch (e: Exception) {