Skip to content

Commit 9afe9d5

Browse files
authored
Merge pull request #465 from ForgeRock/SDKS-3697
SDKS-3697 Prevent duplicated notification on the SDK
2 parents 9e3be1e + d4b7b38 commit 9afe9d5

10 files changed

+160
-10
lines changed

forgerock-authenticator/src/main/java/org/forgerock/android/auth/AuthenticatorManager.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 - 2023 ForgeRock. All rights reserved.
2+
* Copyright (c) 2020 - 2025 Ping Identity. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -247,6 +247,10 @@ PushNotification getNotification(String notificationId) {
247247
return notification;
248248
}
249249

250+
PushNotification getNotificationByMessageId(String messageId) {
251+
return storageClient.getNotificationByMessageId(messageId);
252+
}
253+
250254
void registerForRemoteNotifications(String newDeviceToken) throws AuthenticatorException {
251255
if(this.deviceToken == null) {
252256
this.deviceToken = newDeviceToken;

forgerock-authenticator/src/main/java/org/forgerock/android/auth/DefaultStorageClient.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 - 2023 ForgeRock. All rights reserved.
2+
* Copyright (c) 2020 - 2025 Ping Identity. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -209,6 +209,17 @@ public PushNotification getNotification(String notificationId) {
209209
return PushNotification.deserialize(json);
210210
}
211211

212+
@Override
213+
public PushNotification getNotificationByMessageId(String messageId) {
214+
List<PushNotification> allPushNotifications = getAllNotifications();
215+
for(PushNotification pushNotification : allPushNotifications){
216+
if(pushNotification.getMessageId().equals(messageId)){
217+
return pushNotification;
218+
}
219+
}
220+
return null;
221+
}
222+
212223
@Override
213224
public boolean isEmpty() {
214225
return accountData.getAll().isEmpty() &&

forgerock-authenticator/src/main/java/org/forgerock/android/auth/FRAClient.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 - 2023 ForgeRock. All rights reserved.
2+
* Copyright (c) 2020 - 2025 Ping Identity. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -283,6 +283,15 @@ public PushNotification getNotification(@NonNull String notificationId) {
283283
return this.authenticatorManager.getNotification(notificationId);
284284
}
285285

286+
/**
287+
* Get the PushNotification object with its messageId.
288+
* @param messageId The message unique ID
289+
* @return The PushNotification object
290+
*/
291+
public PushNotification getNotificationByMessageId(@NonNull String messageId) {
292+
return this.authenticatorManager.getNotificationByMessageId(messageId);
293+
}
294+
286295
/**
287296
* Remove from the storage the {@link PushNotification} that was passed in.
288297
* @param notification The PushNotification object to delete

forgerock-authenticator/src/main/java/org/forgerock/android/auth/NotificationFactory.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 - 2023 ForgeRock. All rights reserved.
2+
* Copyright (c) 2020 - 2025 Ping Identity. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -84,6 +84,13 @@ PushNotification handleMessage(@NonNull String messageId, @NonNull String messag
8484
String numbersChallenge;
8585
String contextInfo;
8686

87+
// Check if notification with given messageId already exists
88+
pushNotification = storageClient.getNotificationByMessageId(messageId);
89+
if (pushNotification != null) {
90+
Logger.debug(TAG, "PushNotification object with messageId %s already exists.", messageId);
91+
return pushNotification;
92+
}
93+
8794
// Reconstruct JWT
8895
try {
8996
signedJwt = SignedJWT.parse(message);

forgerock-authenticator/src/main/java/org/forgerock/android/auth/StorageClient.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 - 2021 ForgeRock. All rights reserved.
2+
* Copyright (c) 2020 - 2025 Ping Identity. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -105,6 +105,13 @@ public interface StorageClient {
105105
*/
106106
PushNotification getNotification(String notificationId);
107107

108+
/**
109+
* Get the PushNotification object with its messageId
110+
* @param messageId The PushNotification messageId
111+
* @return The PushNotification object.
112+
*/
113+
PushNotification getNotificationByMessageId(String messageId);
114+
108115
/**
109116
* Whether the storage system currently contains any data.
110117
* @return True if the storage system is empty, false otherwise.

forgerock-authenticator/src/test/java/org/forgerock/android/auth/AuthenticatorManagerTest.java

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 - 2023 ForgeRock. All rights reserved.
2+
* Copyright (c) 2020 - 2025 Ping Identity. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -764,6 +764,30 @@ public void testShouldGetStoredNotificationByID() {
764764
assertEquals(notification, notificationFromStorage);
765765
}
766766

767+
@Test
768+
public void testShouldGetStoredNotificationByMessageID() {
769+
Account account = createAccount(ACCOUNT_NAME, ISSUER);
770+
Mechanism push = createPushMechanism(ACCOUNT_NAME, ISSUER, MECHANISM_UID);
771+
PushNotification notification = createPushNotification(MESSAGE_ID, push);
772+
773+
List<Mechanism> mechanismList= new ArrayList<>();
774+
mechanismList.add(push);
775+
776+
List<PushNotification> notificationList = new ArrayList<>();
777+
notificationList.add(createPushNotification(MESSAGE_ID, push));
778+
notificationList.add(createPushNotification(OTHER_MESSAGE_ID, push));
779+
780+
given(storageClient.getAccount(any(String.class))).willReturn(account);
781+
given(storageClient.getMechanismsForAccount(any(Account.class))).willReturn(mechanismList);
782+
given(storageClient.getAllNotificationsForMechanism(any(Mechanism.class))).willReturn(notificationList);
783+
given(storageClient.getNotificationByMessageId(anyString())).willReturn(notification);
784+
785+
PushNotification notificationFromStorage = authenticatorManager.getNotificationByMessageId(notification.getMessageId());
786+
787+
assertNotNull(notificationFromStorage);
788+
assertEquals(notification, notificationFromStorage);
789+
}
790+
767791
@Test
768792
public void testShouldRemoveExistingAccount() {
769793
Account account = createAccount(ACCOUNT_NAME, ISSUER);

forgerock-authenticator/src/test/java/org/forgerock/android/auth/CustomStorageClient.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 - 2021 ForgeRock. All rights reserved.
2+
* Copyright (c) 2020 - 2025 Ping Identity. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -94,6 +94,11 @@ public PushNotification getNotification(String notificationId) {
9494
return null;
9595
}
9696

97+
@Override
98+
public PushNotification getNotificationByMessageId(String messageId) {
99+
return null;
100+
}
101+
97102
@Override
98103
public boolean isEmpty() {
99104
return false;

forgerock-authenticator/src/test/java/org/forgerock/android/auth/DefaultStorageClientTest.java

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 ForgeRock. All rights reserved.
2+
* Copyright (c) 2020 - 2025 Ping Identity. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -389,6 +389,39 @@ public void testShouldGetNotificationById() {
389389
assertEquals(pushNotificationFromStorage.getMessageId(), MESSAGE_ID);
390390
}
391391

392+
@Test
393+
public void testShouldGetNotificationByMessageId() {
394+
DefaultStorageClient defaultStorage = new DefaultStorageClient(context);
395+
defaultStorage.setAccountData(context.getApplicationContext()
396+
.getSharedPreferences(TEST_SHARED_PREFERENCES_DATA_ACCOUNT, Context.MODE_PRIVATE));
397+
defaultStorage.setMechanismData(context.getApplicationContext()
398+
.getSharedPreferences(TEST_SHARED_PREFERENCES_DATA_MECHANISM, Context.MODE_PRIVATE));
399+
defaultStorage.setNotificationData(context.getApplicationContext()
400+
.getSharedPreferences(TEST_SHARED_PREFERENCES_DATA_NOTIFICATIONS, Context.MODE_PRIVATE));
401+
402+
Calendar timeAdded = Calendar.getInstance();
403+
404+
Account account = createAccountWithoutAdditionalData(ISSUER, ACCOUNT_NAME);
405+
Mechanism mechanism = createPushMechanism(MECHANISM_UID, ISSUER, ACCOUNT_NAME, SECRET,
406+
REGISTRATION_ENDPOINT, AUTHENTICATION_ENDPOINT);
407+
PushNotification pushNotification = createPushNotification(MECHANISM_UID, MESSAGE_ID, CHALLENGE,
408+
AMLB_COOKIE, timeAdded, TTL);
409+
410+
defaultStorage.setAccount(account);
411+
defaultStorage.setMechanism(mechanism);
412+
defaultStorage.setNotification(pushNotification);
413+
414+
Account accountFromStorage = defaultStorage.getAccount(account.getId());
415+
PushMechanism pushMechanismFromStorage = (PushMechanism) defaultStorage.getMechanismsForAccount(accountFromStorage).get(0);
416+
PushNotification pushNotificationFromStorage = defaultStorage.getNotificationByMessageId(pushNotification.getMessageId());
417+
418+
assertNotNull(accountFromStorage);
419+
assertNotNull(pushMechanismFromStorage);
420+
assertNotNull(pushNotificationFromStorage);
421+
assertEquals(pushNotificationFromStorage.getMechanismUID(), MECHANISM_UID);
422+
assertEquals(pushNotificationFromStorage.getMessageId(), MESSAGE_ID);
423+
}
424+
392425
@Test
393426
public void testStoreMultipleNotificationsForSameAccount() {
394427
DefaultStorageClient defaultStorage = new DefaultStorageClient(context);

forgerock-authenticator/src/test/java/org/forgerock/android/auth/FRAClientTest.java

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 - 2023 ForgeRock. All rights reserved.
2+
* Copyright (c) 2020 - 2025 Ping Identity. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -724,6 +724,39 @@ public void testShouldGetStoredNotificationByID() throws Exception {
724724
assertEquals(notification, notificationFromStorage);
725725
}
726726

727+
@Test
728+
public void testShouldGetStoredNotificationByMessageID() throws Exception {
729+
FRAClient fraClient = FRAClient.builder()
730+
.withContext(context)
731+
.withDeviceToken("s-o-m-e-t-o-k-e-n")
732+
.withStorage(storageClient)
733+
.start();
734+
735+
assertNotNull(fraClient);
736+
assertNotNull(fraClient.getAuthenticatorManagerInstance());
737+
738+
Account account = createAccount(ACCOUNT_NAME, ISSUER);
739+
Mechanism push = createPushMechanism(ACCOUNT_NAME, ISSUER, MECHANISM_UID);
740+
PushNotification notification = createPushNotification(MESSAGE_ID, push);
741+
742+
List<Mechanism> mechanismList= new ArrayList<>();
743+
mechanismList.add(push);
744+
745+
List<PushNotification> notificationList = new ArrayList<>();
746+
notificationList.add(createPushNotification(MESSAGE_ID, push));
747+
notificationList.add(createPushNotification(OTHER_MESSAGE_ID, push));
748+
749+
given(storageClient.getAccount(any(String.class))).willReturn(account);
750+
given(storageClient.getMechanismsForAccount(any(Account.class))).willReturn(mechanismList);
751+
given(storageClient.getAllNotificationsForMechanism(any(Mechanism.class))).willReturn(notificationList);
752+
given(storageClient.getNotificationByMessageId(anyString())).willReturn(notification);
753+
754+
PushNotification notificationFromStorage = fraClient.getNotificationByMessageId(notification.getMessageId());
755+
756+
assertNotNull(notificationFromStorage);
757+
assertEquals(notification, notificationFromStorage);
758+
}
759+
727760
@Test
728761
public void testShouldNotGetStoredNotificationByID() throws Exception {
729762
FRAClient fraClient = FRAClient.builder()

forgerock-authenticator/src/test/java/org/forgerock/android/auth/NotificationFactoryTest.java

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 - 2022 ForgeRock. All rights reserved.
2+
* Copyright (c) 2020 - 2025 Ping Identity. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -26,6 +26,7 @@
2626
import org.junit.runner.RunWith;
2727
import org.robolectric.RobolectricTestRunner;
2828

29+
import java.util.Calendar;
2930
import java.util.Map;
3031

3132
@RunWith(RobolectricTestRunner.class)
@@ -289,4 +290,20 @@ public void testShouldNotHandleRemoteUnableToPersist() throws Exception {
289290
}
290291
}
291292

293+
@Test
294+
public void testShouldReturnExistingPushNotification() throws Exception {
295+
RemoteMessage remoteMessage = generateMockRemoteMessage(MESSAGE_ID, CORRECT_SECRET, generateBaseMessage());
296+
PushNotification storedPushNotification = createPushNotification(MECHANISM_UID, MESSAGE_ID, CHALLENGE,
297+
AMLB_COOKIE, Calendar.getInstance(), TTL);
298+
given(storageClient.getNotificationByMessageId(MESSAGE_ID)).willReturn(storedPushNotification);
299+
300+
PushNotification pushNotification = notificationFactory.handleMessage(remoteMessage);
301+
302+
assertNotNull(pushNotification);
303+
assertEquals(MESSAGE_ID, pushNotification.getMessageId());
304+
assertEquals(CHALLENGE, pushNotification.getChallenge());
305+
assertEquals(MECHANISM_UID, pushNotification.getMechanismUID());
306+
assertEquals(TTL, pushNotification.getTtl());
307+
}
308+
292309
}

0 commit comments

Comments
 (0)