Skip to content

Commit 1945f21

Browse files
committed
Applied logic for Push TFA.
1 parent aefedb7 commit 1945f21

File tree

6 files changed

+133
-7
lines changed

6 files changed

+133
-7
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,23 @@
3434

3535
</activity>
3636

37+
<service
38+
android:name=".cdc.AppMessagingService"
39+
android:exported="false">
40+
<intent-filter>
41+
<action android:name="com.google.firebase.MESSAGING_EVENT" />
42+
</intent-filter>
43+
</service>
44+
45+
<receiver
46+
android:name="com.sap.cdc.android.sdk.auth.notifications.CDCNotificationReceiver"
47+
android:exported="false">
48+
<intent-filter>
49+
<action android:name="approve" />
50+
<action android:name="deny" />
51+
</intent-filter>
52+
</receiver>
53+
3754
<activity
3855
android:name="com.sap.cdc.android.sdk.auth.provider.activity.WebLoginActivity"
3956
android:allowTaskReparenting="true"

app/src/main/java/com/sap/cdc/bitsnbytes/cdc/IdentityServiceRepository.kt

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@ package com.sap.cdc.bitsnbytes.cdc
33
import android.content.Context
44
import android.util.Log
55
import androidx.activity.ComponentActivity
6+
import com.google.android.gms.tasks.OnCompleteListener
7+
import com.google.firebase.messaging.FirebaseMessaging
8+
import com.sap.cdc.android.sdk.CDCMessageEventBus
9+
import com.sap.cdc.android.sdk.MessageEvent
610
import com.sap.cdc.android.sdk.auth.AuthenticationService
711
import com.sap.cdc.android.sdk.auth.IAuthResponse
812
import com.sap.cdc.android.sdk.auth.ResolvableContext
13+
import com.sap.cdc.android.sdk.auth.notifications.IFCMTokenRequest
914
import com.sap.cdc.android.sdk.auth.provider.IAuthenticationProvider
1015
import com.sap.cdc.android.sdk.auth.provider.SSOAuthenticationProvider
1116
import com.sap.cdc.android.sdk.auth.provider.WebAuthenticationProvider
@@ -47,7 +52,21 @@ class IdentityServiceRepository private constructor(context: Context) {
4752
/**
4853
* Initialize authentication service.
4954
*/
50-
var authenticationService = AuthenticationService(siteConfig)
55+
var authenticationService = AuthenticationService(siteConfig).registerForPushAuthentication(
56+
object : IFCMTokenRequest {
57+
override fun requestFCMToken() {
58+
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
59+
if (!task.isSuccessful) {
60+
return@OnCompleteListener
61+
}
62+
63+
// Get new FCM registration token
64+
val token = task.result
65+
CDCMessageEventBus.emitMessageEvent(MessageEvent.EventWithToken(token))
66+
})
67+
}
68+
}
69+
)
5170

5271
/**
5372
* Authentication providers map.
@@ -56,7 +75,6 @@ class IdentityServiceRepository private constructor(context: Context) {
5675
private var authenticationProviderMap: MutableMap<String, IAuthenticationProvider> =
5776
mutableMapOf()
5877

59-
6078
init {
6179
// Using session migrator to try and migrate an existing session in an application using old versions
6280
// of the gigya-android-sdk library.
@@ -219,6 +237,14 @@ class IdentityServiceRepository private constructor(context: Context) {
219237
parameters: MutableMap<String, String>
220238
): IAuthResponse = authenticationService.authenticate().otpSendCode(parameters)
221239

240+
//region PUSH
241+
242+
suspend fun optInForPushTFA(): IAuthResponse {
243+
return authenticationService.tfa().optInForPushAuthentication()
244+
}
245+
246+
//endregion
247+
222248
//endregion
223249

224250
//region RESOLVE INTERRUPTIONS

app/src/main/java/com/sap/cdc/bitsnbytes/ui/view/screens/LoginOptions.kt

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
@file:OptIn(ExperimentalPermissionsApi::class)
2+
13
package com.sap.cdc.bitsnbytes.ui.view.screens
24

5+
import android.Manifest
6+
import android.annotation.SuppressLint
37
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
48
import androidx.biometric.BiometricPrompt
59
import androidx.compose.foundation.background
@@ -16,7 +20,10 @@ import androidx.compose.material3.CardDefaults
1620
import androidx.compose.material3.Switch
1721
import androidx.compose.material3.Text
1822
import androidx.compose.runtime.Composable
23+
import androidx.compose.runtime.getValue
24+
import androidx.compose.runtime.mutableStateOf
1925
import androidx.compose.runtime.remember
26+
import androidx.compose.runtime.setValue
2027
import androidx.compose.ui.Alignment
2128
import androidx.compose.ui.Modifier
2229
import androidx.compose.ui.graphics.Color
@@ -25,10 +32,15 @@ import androidx.compose.ui.tooling.preview.Preview
2532
import androidx.compose.ui.unit.dp
2633
import androidx.core.content.ContextCompat
2734
import androidx.fragment.app.FragmentActivity
35+
import com.google.accompanist.permissions.ExperimentalPermissionsApi
36+
import com.google.accompanist.permissions.rememberPermissionState
2837
import com.sap.cdc.bitsnbytes.ui.theme.AppTheme
2938
import com.sap.cdc.bitsnbytes.ui.view.composables.ActionOutlineButton
3039
import com.sap.cdc.bitsnbytes.ui.view.composables.ActionOutlineInverseButton
3140
import com.sap.cdc.bitsnbytes.ui.view.composables.LargeHorizontalSpacer
41+
import com.sap.cdc.bitsnbytes.ui.view.composables.LargeVerticalSpacer
42+
import com.sap.cdc.bitsnbytes.ui.view.composables.LoadingStateColumn
43+
import com.sap.cdc.bitsnbytes.ui.view.composables.SimpleErrorMessages
3244
import com.sap.cdc.bitsnbytes.ui.view.composables.SmallVerticalSpacer
3345
import com.sap.cdc.bitsnbytes.ui.viewmodel.ILoginOptionsViewModel
3446
import com.sap.cdc.bitsnbytes.ui.viewmodel.LoginOptionsViewModelPreview
@@ -39,19 +51,26 @@ import com.sap.cdc.bitsnbytes.ui.viewmodel.LoginOptionsViewModelPreview
3951
* Copyright: SAP LTD.
4052
*/
4153

54+
@SuppressLint("InlinedApi")
4255
@Composable
4356
fun LoginOptionsView(viewModel: ILoginOptionsViewModel) {
4457
val context = LocalContext.current
58+
var loading by remember { mutableStateOf(false) }
4559
val executor = remember { ContextCompat.getMainExecutor(context) }
60+
var optionsError by remember { mutableStateOf("") }
61+
62+
val notificationPermission = rememberPermissionState(
63+
permission = Manifest.permission.POST_NOTIFICATIONS
64+
)
4665

4766
// UI elements.
4867

49-
Column(
68+
LoadingStateColumn(
69+
loading = loading,
5070
modifier = Modifier
5171
.background(Color.White)
5272
.fillMaxWidth()
5373
.fillMaxHeight(),
54-
verticalArrangement = Arrangement.spacedBy(6.dp)
5574
) {
5675
// Option cards
5776
OptionCard(
@@ -61,13 +80,30 @@ fun LoginOptionsView(viewModel: ILoginOptionsViewModel) {
6180
onClick = { /* Handle deactivation */ },
6281
inverse = false
6382
)
83+
SmallVerticalSpacer()
6484
OptionCard(
6585
title = "Push 2-Factor Authentication",
66-
status = "Deactivated",
86+
status = "",
6787
actionLabel = "Activate",
68-
onClick = { /* Handle activation */ },
88+
onClick = {
89+
if (!notificationPermission.hasPermission) {
90+
notificationPermission.launchPermissionRequest()
91+
}
92+
loading = true
93+
viewModel.optInForPushTFA(
94+
success = {
95+
optionsError = ""
96+
loading = false
97+
},
98+
onFailedWith = { error ->
99+
optionsError = error?.errorDescription!!
100+
loading = false
101+
}
102+
)
103+
},
69104
inverse = false
70105
)
106+
SmallVerticalSpacer()
71107
OptionCard(
72108
title = "Biometrics",
73109
status = when (viewModel.isBiometricActive()) {
@@ -140,6 +176,15 @@ fun LoginOptionsView(viewModel: ILoginOptionsViewModel) {
140176
}
141177
)
142178
}
179+
180+
LargeVerticalSpacer()
181+
182+
// Error message
183+
if (optionsError.isNotEmpty()) {
184+
SimpleErrorMessages(
185+
text = optionsError
186+
)
187+
}
143188
}
144189
}
145190

app/src/main/java/com/sap/cdc/bitsnbytes/ui/viewmodel/LoginOptionsViewModel.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ import androidx.compose.runtime.getValue
66
import androidx.compose.runtime.mutableStateOf
77
import androidx.compose.runtime.setValue
88
import androidx.fragment.app.FragmentActivity
9+
import androidx.lifecycle.viewModelScope
10+
import com.sap.cdc.android.sdk.auth.AuthState
911
import com.sap.cdc.android.sdk.auth.biometric.BiometricAuth
1012
import com.sap.cdc.android.sdk.auth.session.SessionSecureLevel
13+
import com.sap.cdc.android.sdk.core.api.model.CDCError
14+
import kotlinx.coroutines.launch
1115
import java.util.concurrent.Executor
1216

1317
interface ILoginOptionsViewModel {
@@ -44,6 +48,13 @@ interface ILoginOptionsViewModel {
4448
// Stub.
4549
}
4650

51+
fun optInForPushTFA(
52+
success: () -> Unit,
53+
onFailedWith: (CDCError?) -> Unit
54+
) {
55+
//Stub.
56+
}
57+
4758
}
4859

4960
// Mocked preview class for LoginOptionsViewModel
@@ -153,5 +164,24 @@ class LoginOptionsViewModel(context: Context) : BaseViewModel(context),
153164
}
154165
)
155166
}
167+
168+
override fun optInForPushTFA(
169+
success: () -> Unit,
170+
onFailedWith: (CDCError?) -> Unit
171+
) {
172+
viewModelScope.launch {
173+
val response = identityService.optInForPushTFA()
174+
when (response.state()) {
175+
AuthState.SUCCESS -> {
176+
// Success.
177+
success()
178+
}
179+
180+
else -> {
181+
onFailedWith(response.toDisplayError())
182+
}
183+
}
184+
}
185+
}
156186
}
157187

library/src/main/java/com/sap/cdc/android/sdk/auth/AuthenticationService.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.sap.cdc.android.sdk.auth.session.SessionService
77
import com.sap.cdc.android.sdk.core.CoreClient
88
import com.sap.cdc.android.sdk.core.SiteConfig
99
import com.sap.cdc.android.sdk.extensions.getEncryptedPreferences
10+
import kotlinx.serialization.encodeToString
1011
import kotlinx.serialization.json.Json
1112

1213
/**
@@ -59,7 +60,8 @@ class AuthenticationService(
5960
val json = Json {
6061
encodeDefaults = true
6162
}
62-
esp.edit().putString(CDC_DEVICE_INFO, json.encodeToString(deviceInfo)).apply()
63+
val deviceInfoJson = json.encodeToString(deviceInfo)
64+
esp.edit().putString(CDC_DEVICE_INFO, deviceInfoJson).apply()
6365
}
6466

6567
/**

library/src/main/java/com/sap/cdc/android/sdk/auth/notifications/NotificationsManager.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ class CDCNotificationManager(
235235
* @param data: The data fields of the notification.
236236
*/
237237
private fun notifyActionable(mode: String, data: Map<String, String>) {
238+
CDCDebuggable.log(LOG_TAG, "notifyActionable: mode: $mode, data: $data")
238239

239240
// Parse data fields from cdc push.
240241
val title = data["title"]
@@ -333,8 +334,13 @@ class CDCNotificationManager(
333334
approvePendingIntent
334335
)
335336

337+
336338
// Notify.
337339
if (notificationManager.areNotificationsEnabled()) {
340+
CDCDebuggable.log(
341+
LOG_TAG,
342+
"Notify actionable notification with id = $notificationId"
343+
)
338344
notificationManager.notify(notificationId, builder.build())
339345
} else {
340346
CDCDebuggable.log(LOG_TAG, "Notifications permissions not enabled.")

0 commit comments

Comments
 (0)