diff --git a/CHANGELOG.md b/CHANGELOG.md
index 32c185ff..bdf1acca 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,14 +1,17 @@
## [4.6.0]
#### Added
-- Skip Type 4 TextOutputCallback [SDKS-3227]
-- Allow developers to customize SDK Storage [SDKS-3378]
-- Support PingOne Protect Marketplace Node [SDKS-3279]
+- Allow developers to customize SDK storage [SDKS-3378]
+- Support PingOne Protect Marketplace nodes [SDKS-3297]
+- Support reCAPTCHA Enterprise node [SDKS-3325]
- Expose Realm, Success Url with SSOToken [SDKS-3351]
- Support Android 15 [SDKS-3098]
-- Allow http/https scheme for Centralize Login redirect [SDKS-3433]
+- Support http/https scheme for Centralize Login redirect [SDKS-3433]
#### Fixed
-- Potential CustomTabManager ServiceConnection leak. [SDKS-3346]
+- Skip Type 4 TextOutputCallback [SDKS-3227]
+- Potential CustomTabManager ServiceConnection leak [SDKS-3346]
+- access_token api call triggered twice on force refresh [SDKS-3254]
+- Allow http/https as redirect scheme in centralize login flow [SDKS-3433]
## [4.5.0]
#### Added
diff --git a/README.md b/README.md
index f4ed61bb..6f157472 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ Use the SDKs to leverage _[Intelligent Authentication](https://www.forgerock.com
* Access Management (AM) 6.5.2+
* Android API level 23+
- * Android 6.0 (Marshmallow), 7.0 (Nougat), 8.0 (Oreo), 9.0 (Pie), 10.0, 11.0, 12.0, 13.0, 14.0
+ * Android 6.0 (Marshmallow), 7.0 (Nougat), 8.0 (Oreo), 9.0 (Pie), 10.0, 11.0, 12.0, 13.0, 14.0, 15.0
diff --git a/forgerock-integration-tests/src/androidTest/AndroidManifest.xml b/forgerock-integration-tests/src/androidTest/AndroidManifest.xml
index 0db558ec..f15aa650 100644
--- a/forgerock-integration-tests/src/androidTest/AndroidManifest.xml
+++ b/forgerock-integration-tests/src/androidTest/AndroidManifest.xml
@@ -15,6 +15,7 @@
diff --git a/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/AndroidBaseTest.java b/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/AndroidBaseTest.java
index a9e92766..dfce5723 100644
--- a/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/AndroidBaseTest.java
+++ b/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/AndroidBaseTest.java
@@ -99,12 +99,12 @@ public void onCallbackReceived(Node node) {
firstQuestion.setSelectedQuestion(firstQuestion.getPredefinedQuestions().get(0));
firstQuestion.setSelectedAnswer("Test");
- // Uncomment this block if there are more than one KbaCreateCallbacks in the tree
- /*
- KbaCreateCallback secondQuestion = (KbaCreateCallback) callbacks.get(1);
- secondQuestion.setSelectedQuestion(secondQuestion.getPredefinedQuestions().get(1));
- secondQuestion.setSelectedAnswer("Test");
- */
+ // If there are more than one KBA questions, answer the second one
+ if (callbacks.size() > 1) {
+ KbaCreateCallback secondQuestion = (KbaCreateCallback) callbacks.get(1);
+ secondQuestion.setSelectedQuestion(secondQuestion.getPredefinedQuestions().get(1));
+ secondQuestion.setSelectedAnswer("Test");
+ }
node.next(context, this );
}
diff --git a/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/BaseDeviceBindingTest.java b/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/BaseDeviceBindingTest.java
index e7aae22a..833d73b7 100644
--- a/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/BaseDeviceBindingTest.java
+++ b/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/BaseDeviceBindingTest.java
@@ -23,6 +23,7 @@
import org.forgerock.android.auth.Logger;
import org.forgerock.android.auth.RetryTestRule;
import org.junit.After;
+import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
@@ -36,7 +37,7 @@ public abstract class BaseDeviceBindingTest {
protected static Context context = ApplicationProvider.getApplicationContext();
// This test uses dynamic configuration with the following settings:
- protected final static String AM_URL = "https://openam-dbind.forgeblocks.com/am";
+ protected final static String AM_URL = "https://openam-sdks2.forgeblocks.com/am";
protected final static String REALM = "alpha";
protected final static String OAUTH_CLIENT = "AndroidTest";
protected final static String OAUTH_REDIRECT_URI = "org.forgerock.demo:/oauth2redirect";
@@ -86,8 +87,15 @@ public static void setUpSDK() {
}
}
+ @Before
+ public void logoutSessionBeforeTest() {
+ if (FRSession.getCurrentSession() != null) {
+ FRSession.getCurrentSession().logout();
+ }
+ }
+
@After
- public void logoutSession() {
+ public void logoutSessionAfterTest() {
if (FRSession.getCurrentSession() != null) {
FRSession.getCurrentSession().logout();
}
diff --git a/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/BasePingOneProtectTest.kt b/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/BasePingOneProtectTest.kt
index 0cf75fad..9d6ac51d 100644
--- a/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/BasePingOneProtectTest.kt
+++ b/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/BasePingOneProtectTest.kt
@@ -21,9 +21,9 @@ import java.util.concurrent.TimeUnit
abstract class BasePingOneProtectTest {
val context: Context = ApplicationProvider.getApplicationContext()
- private val AM_URL = "https://openam-protect2.forgeblocks.com/am"
+ private val AM_URL = "https://openam-sdks2.forgeblocks.com/am"
private val REALM = "alpha"
- private val COOKIE_NAME = "c1c805de4c9b333"
+ private val COOKIE_NAME = "9dfa82bc124226d"
private val OAUTH_CLIENT = "AndroidTest"
private val OAUTH_REDIRECT_URI = "org.forgerock.demo:/oauth2redirect"
private val SCOPE = "openid profile email address phone"
diff --git a/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/DeviceBindingCallbackTest.java b/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/DeviceBindingCallbackTest.java
index 64503806..9f08eee3 100644
--- a/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/DeviceBindingCallbackTest.java
+++ b/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/DeviceBindingCallbackTest.java
@@ -22,17 +22,20 @@
import org.forgerock.android.auth.NodeListenerFuture;
import org.forgerock.android.auth.devicebind.ApplicationPinDeviceAuthenticator;
import org.junit.Assert;
+import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
import java.util.concurrent.ExecutionException;
@RunWith(AndroidJUnit4.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING) // These tests must run in order
public class DeviceBindingCallbackTest extends BaseDeviceBindingTest {
protected final static String TREE = "device-bind";
@Test
- public void testDeviceBindingDefaults() throws ExecutionException, InterruptedException {
+ public void test01DeviceBindingDefaults() throws ExecutionException, InterruptedException {
NodeListenerFuture nodeListenerFuture = new DeviceBindingNodeListener(context, "default") {
final NodeListener nodeListener = this;
@@ -68,7 +71,7 @@ public void onCallbackReceived(Node node) {
}
@Test
- public void testDeviceBindingCustom() throws ExecutionException, InterruptedException {
+ public void test02DeviceBindingCustom() throws ExecutionException, InterruptedException {
NodeListenerFuture nodeListenerFuture = new DeviceBindingNodeListener(context, "custom") {
final NodeListener nodeListener = this;
@@ -103,7 +106,7 @@ public void onCallbackReceived(Node node) {
}
@Test
- public void testDeviceBindingBind() throws ExecutionException, InterruptedException {
+ public void test03DeviceBindingBind() throws ExecutionException, InterruptedException {
final int[] hit = {0};
NodeListenerFuture nodeListenerFuture = new DeviceBindingNodeListener(context, "custom") {
final NodeListener nodeListener = this;
@@ -141,7 +144,7 @@ public void onException(Exception e) {
}
@Test
- public void testDeviceBindingExceed() throws ExecutionException, InterruptedException {
+ public void test04DeviceBindingExceed() throws ExecutionException, InterruptedException {
final int[] hit = {0};
NodeListenerFuture nodeListenerFuture = new DeviceBindingNodeListener(context, "exceed-limit") {
final NodeListener nodeListener = this;
@@ -174,7 +177,7 @@ public void onCallbackReceived(Node node) {
}
@Test
- public void testDeviceBindingCustomOutcome() throws ExecutionException, InterruptedException {
+ public void test05DeviceBindingCustomOutcome() throws ExecutionException, InterruptedException {
final int[] hit = {0};
NodeListenerFuture nodeListenerFuture = new DeviceBindingNodeListener(context, "custom") {
final NodeListener nodeListener = this;
@@ -210,7 +213,7 @@ public void onCallbackReceived(Node node) {
}
@Test
- public void testDeviceBindingApplicationPin() throws ExecutionException, InterruptedException {
+ public void test06DeviceBindingApplicationPin() throws ExecutionException, InterruptedException {
final int[] bindSuccess = {0};
ActivityScenario scenario = ActivityScenario.launch(DummyActivity.class);
@@ -254,7 +257,7 @@ public void onException(Exception e) {
}
@Test
- public void testDeviceBindApplicationIdNotMatchingError() {
+ public void test07DeviceBindApplicationIdNotMatchingError() {
final int[] bindSuccess = {0};
boolean executionExceptionOccurred = false;
NodeListenerFuture nodeListenerFuture = new DeviceBindingNodeListener(context, "wrong-app-id") {
@@ -299,7 +302,7 @@ public void onException(Exception e) {
}
@Test
- public void testDeviceBindingDeviceDataVariable() throws ExecutionException, InterruptedException {
+ public void test08DeviceBindingDeviceDataVariable() throws ExecutionException, InterruptedException {
// This test is to ensure that the Device Binding node sets DeviceBinding.DEVICE variable in shared state
final int[] bindSuccess = {0};
final int[] deviceDataVarPresentInAM = {0};
@@ -351,7 +354,7 @@ public void onException(Exception e) {
* Make sure that when user does NOT exist, the Device Binding node triggers the failure outcome (SDKS-2935)
*/
@Test
- public void testDeviceBindingUnknownUser() throws ExecutionException, InterruptedException {
+ public void test09DeviceBindingUnknownUser() throws ExecutionException, InterruptedException {
final int[] hit = {0};
final int[] failureOutcome = {0};
NodeListenerFuture nodeListenerFuture = new DeviceBindingNodeListener(context, "default")
diff --git a/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/ReCaptchaEnterpriseCallbackFailureTest.kt b/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/ReCaptchaEnterpriseCallbackFailureTest.kt
index 0fbe09ef..c83a8daa 100644
--- a/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/ReCaptchaEnterpriseCallbackFailureTest.kt
+++ b/forgerock-integration-tests/src/androidTest/java/org/forgerock/android/auth/callback/ReCaptchaEnterpriseCallbackFailureTest.kt
@@ -14,6 +14,7 @@ import org.forgerock.android.auth.FRSession
import org.forgerock.android.auth.Logger
import org.forgerock.android.auth.Node
import org.forgerock.android.auth.NodeListener
+import org.json.JSONObject
import org.junit.Assert
import org.junit.FixMethodOrder
import org.junit.Test
@@ -49,11 +50,29 @@ class ReCaptchaEnterpriseCallbackFailureTest : ReCaptchaEnterpriseCallbackBaseTe
if (node.getCallback(TextOutputCallback::class.java) != null) {
nodeTextOutputHit[0]++
- // Note: The journey sends back to us the content of CaptchaEnterpriseNode.FAILURE
- // in the message of the TextOutputCallback... so we can parse it here and verify results...
+ /*
+ Note:
+ The journey sends back to us the content of CaptchaEnterpriseNode.FAILURE
+ in the message of the TextOutputCallback... so we can parse it here and verify results...
+ However, tt is also possible that the score is equal exactly to 1.0 (when running on real device)
+ In that case the node will succeed, and the journey will send back the content of the
+ CaptchaEnterpriseNode.ASSESSMENT_RESULT variable. We need to account for this in the test,
+ and make sure tha the score is exactly 1.0...
+ */
+
val message = node.getCallback(TextOutputCallback::class.java).message
- Assertions.assertThat(message).contains("VALIDATION_ERROR")
+ if (!message.contains("VALIDATION_ERROR")) {
+ // If the node doesn't fail, make sure that in case the node doesn't fail the score is exactly 1.0
+ val jsonObject = JSONObject(message)
+ Assert.assertNotNull(jsonObject)
+ Logger.debug("RecaptchaEnterpriseCallbackTest", jsonObject.toString(2))
+ val score = jsonObject.getJSONObject("riskAnalysis").getDouble("score")
+ Assertions.assertThat(score).isEqualTo(1.0)
+ }
+ else {
+ Assertions.assertThat(message).contains("VALIDATION_ERROR")
+ }
node.next(context, nodeListener)
}
super.onCallbackReceived(node)
diff --git a/forgerock-integration-tests/src/androidTest/res/values/strings.xml b/forgerock-integration-tests/src/androidTest/res/values/strings.xml
index f670ebbd..9e06fd2b 100644
--- a/forgerock-integration-tests/src/androidTest/res/values/strings.xml
+++ b/forgerock-integration-tests/src/androidTest/res/values/strings.xml
@@ -14,15 +14,15 @@
AndroidTest
org.forgerock.demo:/oauth2redirect
openid profile email address phone
- https://openam-sdks.forgeblocks.com/am
+ https://openam-sdks2.forgeblocks.com/am
30
- https://openam-sdks.forgeblocks.com/am
+ https://openam-sdks2.forgeblocks.com/am
alpha
30
- 5421aeddf91aa20
+ 9dfa82bc124226d
NamePasswordCallbackTest
diff --git a/gradle.properties b/gradle.properties
index 94a7340e..4cd954ba 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -22,8 +22,8 @@ org.gradle.jvmargs=-Xmx1536m
kotlin.code.style=official
android.useAndroidX=true
GROUP=org.forgerock
-VERSION=4.6.0-beta2
-VERSION_CODE=24
+VERSION=4.6.0
+VERSION_CODE=25
android.nonTransitiveRClass=false
android.nonFinalResIds=false
android.suppressUnsupportedCompileSdk=35
\ No newline at end of file