Skip to content

Commit 3200984

Browse files
committed
refactor: Provider authentication fixes for authenticator flows
1 parent 2610066 commit 3200984

File tree

15 files changed

+210
-173
lines changed

15 files changed

+210
-173
lines changed

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ android {
1414
minSdk = 26
1515
//noinspection EditedTargetSdkVersion,OldTargetApi
1616
targetSdk = 35
17-
versionCode = 3
18-
versionName = "0.3"
17+
versionCode = 5
18+
versionName = "1.0.0"
1919

2020
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2121
vectorDrawables {

app/src/main/java/com/sap/cdc/bitsnbytes/feature/auth/AuthenticationFlowDelegate.kt

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class AuthenticationFlowDelegate(context: Context) {
7777
/**
7878
* Creates and configures a new AuthenticationService instance.
7979
* Centralizes service initialization to avoid duplication.
80-
*
80+
*
8181
* @param config The SiteConfig to initialize the service with
8282
* @return Configured AuthenticationService instance
8383
*/
@@ -107,33 +107,33 @@ class AuthenticationFlowDelegate(context: Context) {
107107

108108
/**
109109
* Re-initializes the entire authentication system with a new SiteConfig.
110-
*
110+
*
111111
* This method performs a complete reinitialization when configuration changes:
112112
* 1. Clears existing authentication state and session data
113113
* 2. Creates new AuthenticationService with fresh CoreClient and SessionService
114114
* 3. Re-registers all authentication providers with new config
115115
* 4. Resets biometric authentication (will reinitialize on next use)
116-
*
116+
*
117117
* **Important:** Sessions are API-key specific, so changing configuration
118118
* requires clearing the old session and starting fresh.
119-
*
119+
*
120120
* @param newSiteConfig The new site configuration to use
121121
*/
122122
fun reinitializeWithNewConfig(newSiteConfig: SiteConfig) {
123123
// 1. Clear existing state
124124
clearAuthenticationState()
125125
clearCDCSession()
126126
clearAuthOptionsState()
127-
127+
128128
// 2. Update siteConfig reference
129129
this.siteConfig = newSiteConfig
130-
130+
131131
// 3. Create NEW AuthenticationService (includes fresh CoreClient + SessionService)
132132
authenticationService = createAuthenticationService(newSiteConfig)
133-
133+
134134
// 4. Re-register authentication providers
135135
initializeProviders()
136-
136+
137137
// Note: biometricAuth is lazy - will reinitialize with new sessionService on next access
138138
}
139139

@@ -156,21 +156,23 @@ class AuthenticationFlowDelegate(context: Context) {
156156
*/
157157
private fun initializeProviders() {
158158
authenticationProviderMap.clear()
159-
159+
160160
// Register application specific authentication providers
161161
registerAuthenticationProvider("facebook", FacebookAuthenticationProvider())
162-
162+
163163
// Register Google with both modern and legacy names (google + googleplus)
164164
// This supports legacy server configurations that use "googleplus" without duplicating instances
165165
registerAuthenticationProvider(
166166
aliases = listOf("google", "googleplus"),
167167
provider = GoogleAuthenticationProvider()
168168
)
169169

170-
registerAuthenticationProvider("linkedIn", WebAuthenticationProvider(
171-
"linked",
172-
siteConfig = authenticationService.siteConfig,
173-
))
170+
registerAuthenticationProvider(
171+
"linkedIn", WebAuthenticationProvider(
172+
"linked",
173+
siteConfig = authenticationService.siteConfig,
174+
)
175+
)
174176
}
175177

176178
init {
@@ -244,6 +246,7 @@ class AuthenticationFlowDelegate(context: Context) {
244246
fun handleSessionExpired() {
245247
clearCDCSession()
246248
clearAuthenticationState()
249+
biometricAuth.invalidateBiometricAuthenticationState()
247250
}
248251

249252
//region LOGIN / LOGOUT / REGISTER METHODS
@@ -648,30 +651,30 @@ class AuthenticationFlowDelegate(context: Context) {
648651

649652
/**
650653
* Register authentication provider with multiple aliases.
651-
*
654+
*
652655
* This method allows registering the same provider instance under multiple names,
653656
* which is useful for supporting legacy provider names without duplicating instances.
654-
*
657+
*
655658
* ## Use Case: Legacy Provider Names
656-
*
659+
*
657660
* Some servers may use legacy provider names (e.g., "googleplus") while the client
658661
* uses modern names (e.g., "google"). Rather than creating duplicate provider instances,
659662
* this method allows mapping multiple names to a single provider.
660-
*
663+
*
661664
* ## Example
662-
*
665+
*
663666
* ```
664667
* // Google provider can be accessed via "google" OR "googleplus"
665668
* registerAuthenticationProvider(
666669
* aliases = listOf("google", "googleplus"),
667670
* provider = GoogleAuthenticationProvider()
668671
* )
669-
*
672+
*
670673
* // Both work and return the same instance:
671674
* getAuthenticationProvider("google") // Same instance
672675
* getAuthenticationProvider("googleplus") // Same instance
673676
* ```
674-
*
677+
*
675678
* @param aliases List of names (including primary and legacy names) that map to this provider
676679
* @param provider The authentication provider instance to register
677680
*/
@@ -684,7 +687,7 @@ class AuthenticationFlowDelegate(context: Context) {
684687
/**
685688
* Register authentication provider with a single name.
686689
* Convenience method for providers without legacy names.
687-
*
690+
*
688691
* @param name The provider name
689692
* @param provider The authentication provider instance
690693
*/

app/src/main/java/com/sap/cdc/bitsnbytes/feature/provider/FacebookAuthenticationProvider.kt

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import com.sap.cdc.android.sdk.feature.provider.IAuthenticationProvider
1212
import com.sap.cdc.android.sdk.feature.provider.ProviderException
1313
import com.sap.cdc.android.sdk.feature.provider.ProviderExceptionType
1414
import com.sap.cdc.android.sdk.feature.provider.ProviderType
15-
import kotlinx.serialization.json.JsonObject
16-
import kotlinx.serialization.json.JsonPrimitive
1715
import kotlin.coroutines.resume
1816
import kotlin.coroutines.resumeWithException
1917
import kotlin.coroutines.suspendCoroutine
@@ -65,24 +63,13 @@ class FacebookAuthenticationProvider : IAuthenticationProvider {
6563
override fun onSuccess(result: LoginResult) {
6664
val accessToken = result.accessToken
6765

68-
// Generate the relevant providerSession object required for CDC servers to validate the token.
69-
val data = JsonObject(
70-
mapOf(
71-
"facebook" to JsonObject(
72-
mapOf(
73-
"authToken" to JsonPrimitive(accessToken.token),
74-
"tokenExpiration" to JsonPrimitive(accessToken.expires.time / 1000)
75-
)
76-
)
77-
)
78-
)
79-
80-
val providerSession = data.toString()
81-
8266
val authenticatorProviderResult = AuthenticatorProviderResult(
8367
provider = getProvider(),
8468
type = ProviderType.NATIVE,
85-
providerSessions = providerSession,
69+
providerSessionData = mapOf(
70+
"authToken" to accessToken.token,
71+
"tokenExpiration" to (accessToken.expires.time / 1000).toString()
72+
),
8673
)
8774
continuation.resume(authenticatorProviderResult)
8875
}

app/src/main/java/com/sap/cdc/bitsnbytes/feature/provider/GoogleAuthenticationProvider.kt

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import com.sap.cdc.android.sdk.feature.provider.ProviderExceptionType
1818
import com.sap.cdc.android.sdk.feature.provider.ProviderType
1919
import com.sap.cdc.bitsnbytes.R
2020
import io.ktor.util.generateNonce
21-
import kotlinx.serialization.json.JsonObject
22-
import kotlinx.serialization.json.JsonPrimitive
2321

2422
/**
2523
* Created by Tal Mirmelshtein on 10/06/2024
@@ -66,22 +64,12 @@ class GoogleAuthenticationProvider : IAuthenticationProvider {
6664
val googleIdTokenCredential = GoogleIdTokenCredential
6765
.createFrom(credential.data)
6866

69-
// Generate the relevant providerSession object required for CDC servers to validate the token.
70-
val data = JsonObject(
71-
mapOf(
72-
"google" to JsonObject(
73-
mapOf(
74-
"idToken" to JsonPrimitive(googleIdTokenCredential.idToken),
75-
)
76-
)
77-
)
78-
)
79-
val providerSession = data.toString()
80-
8167
val authenticatorProviderResult = AuthenticatorProviderResult(
8268
provider = getProvider(),
8369
type = ProviderType.NATIVE,
84-
providerSessions = providerSession
70+
providerSessionData = mapOf(
71+
"idToken" to googleIdTokenCredential.idToken,
72+
)
8573
)
8674
return authenticatorProviderResult
8775
}

app/src/main/java/com/sap/cdc/bitsnbytes/feature/provider/LineAuthenticationProvider.kt

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.sap.cdc.bitsnbytes.feature.provider
22

3+
import android.R.attr.data
34
import android.content.Context
45
import android.content.Intent
56
import android.util.Log
@@ -19,8 +20,6 @@ import com.sap.cdc.android.sdk.feature.provider.ProviderException
1920
import com.sap.cdc.android.sdk.feature.provider.ProviderExceptionType
2021
import com.sap.cdc.android.sdk.feature.provider.ProviderType
2122
import com.sap.cdc.bitsnbytes.R
22-
import kotlinx.serialization.json.JsonObject
23-
import kotlinx.serialization.json.JsonPrimitive
2423
import kotlin.coroutines.resume
2524
import kotlin.coroutines.resumeWithException
2625
import kotlin.coroutines.suspendCoroutine
@@ -33,6 +32,11 @@ import kotlin.coroutines.suspendCoroutine
3332

3433
class LineAuthenticationProvider() : IAuthenticationProvider {
3534

35+
companion object {
36+
37+
const val LOG_TAG = "LineAuthenticationProvider"
38+
}
39+
3640
private var launcher: ActivityResultLauncher<Intent>? = null
3741

3842
override fun getProvider(): String = "line"
@@ -55,7 +59,7 @@ class LineAuthenticationProvider() : IAuthenticationProvider {
5559
hostActivity,
5660
channelId,
5761
LineAuthenticationParams.Builder()
58-
.scopes(listOf(Scope.PROFILE))
62+
.scopes(listOf(Scope.PROFILE, Scope.OC_EMAIL, Scope.OPENID_CONNECT))
5963
.build()
6064
)
6165

@@ -77,34 +81,27 @@ class LineAuthenticationProvider() : IAuthenticationProvider {
7781
val lineResult = LineLoginApi.getLoginResultFromIntent(resultData)
7882
when (lineResult.responseCode) {
7983
LineApiResponseCode.SUCCESS -> {
80-
Log.d("LineAuthenticationProvider", "SUCCESS")
84+
Log.d(LOG_TAG, "SUCCESS")
8185
val token = lineResult.lineCredential?.accessToken?.tokenString
82-
83-
// Generate the relevant providerSession object required for CDC servers to validate the token.
84-
val data = JsonObject(
85-
mapOf(
86-
"line" to JsonObject(
87-
mapOf(
88-
"authToken" to JsonPrimitive(token),
89-
)
90-
)
91-
)
92-
)
86+
val idToken = lineResult.lineIdToken?.rawString
9387

9488
val providerSession = data.toString()
9589

9690
val authenticatorProviderResult = AuthenticatorProviderResult(
9791
provider = getProvider(),
9892
type = ProviderType.NATIVE,
99-
providerSessions = providerSession
93+
providerSessionData = mapOf(
94+
"authToken" to token,
95+
"idToken" to idToken
96+
)
10097
)
10198

10299
dispose()
103100
continuation.resume(authenticatorProviderResult)
104101
}
105102

106103
LineApiResponseCode.CANCEL -> {
107-
Log.d("LineAuthenticationProvider", "CANCEL")
104+
Log.d(LOG_TAG, "CANCEL")
108105

109106
dispose()
110107
continuation.resumeWithException(
@@ -116,8 +113,8 @@ class LineAuthenticationProvider() : IAuthenticationProvider {
116113
}
117114

118115
else -> {
119-
Log.d("LineAuthenticationProvider", "ERROR")
120-
Log.d("LineAuthenticationProvider", lineResult.errorData.toString())
116+
Log.d(LOG_TAG, "ERROR")
117+
Log.d(LOG_TAG, lineResult.errorData.toString())
121118

122119
val providerException =
123120
ProviderException(

app/src/main/java/com/sap/cdc/bitsnbytes/feature/provider/WeChatAuthenticationProvider.kt

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ import com.sap.cdc.bitsnbytes.wxapi.WXEntryActivity
2121
import com.tencent.mm.opensdk.modelmsg.SendAuth
2222
import com.tencent.mm.opensdk.openapi.IWXAPI
2323
import com.tencent.mm.opensdk.openapi.WXAPIFactory
24-
import kotlinx.serialization.json.JsonObject
25-
import kotlinx.serialization.json.JsonPrimitive
2624
import kotlin.coroutines.resume
2725
import kotlin.coroutines.resumeWithException
2826
import kotlin.coroutines.suspendCoroutine
@@ -112,23 +110,13 @@ class WeChatAuthenticationProvider : IAuthenticationProvider {
112110
val code = resultData.getStringExtra("code")
113111
if (code != null) {
114112

115-
// Generate the relevant providerSession object required for CDC servers to validate the token.
116-
val data = JsonObject(
117-
mapOf(
118-
"wechat" to JsonObject(
119-
mapOf(
120-
"authToken" to JsonPrimitive(code),
121-
"providerID" to JsonPrimitive(WXEntryActivity.API_ID)
122-
)
123-
)
124-
)
125-
)
126-
val providerSession = data.toString()
127-
128113
val authenticatorProviderResult = AuthenticatorProviderResult(
129114
provider = getProvider(),
130115
type = ProviderType.NATIVE,
131-
providerSessions = providerSession
116+
providerSessionData = mapOf(
117+
"authToken" to code,
118+
"providerID" to WXEntryActivity.API_ID
119+
)
132120
)
133121
dispose()
134122
continuation.resume(authenticatorProviderResult)

gradle/libs.versions.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[versions]
2-
android = "8.13.0"
2+
android = "8.13.1"
33
browser = "1.9.0"
44
accompanistPermissions = "0.37.3"
55
firebaseBom = "34.6.0"
@@ -10,20 +10,20 @@ dokka = "2.1.0"
1010
jreleaser = "1.21.0"
1111
ktorClientMock = "3.3.3"
1212
ktx = "1.17.0"
13-
activityCompose = "1.12.0"
13+
activityCompose = "1.12.1"
1414
ktor = "3.3.3"
1515
appcompat = "1.7.1"
1616
biometric = "1.1.0"
1717
credentials = "1.5.0"
1818
coilCompose = "2.7.0"
19-
composeBom = "2025.11.01"
19+
composeBom = "2025.12.00"
2020
coreSplashscreen = "1.2.0"
2121
lifecycleRuntimeKtx = "2.10.0"
2222
material = "1.13.0"
2323
material3Version = "1.4.0"
2424
materialIconsExtended = "1.7.8"
2525
navigationCompose = "2.9.6"
26-
runtimeLivedata = "1.9.5"
26+
runtimeLivedata = "1.10.0"
2727
workRuntimeKtx = "2.11.0"
2828
material3 = "1.4.0"
2929

@@ -39,7 +39,7 @@ junitVersion = "1.3.0"
3939
mockitoCore = "5.20.0"
4040
mockitoInline = "5.2.0"
4141
mockitoKotlin = "6.1.0"
42-
foundation = "1.9.5"
42+
foundation = "1.10.0"
4343

4444
[libraries]
4545
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanistPermissions" }

library/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ plugins {
88
}
99

1010
group = "com.sap.oss.cdc-android-sdk"
11-
version = "0.3.0"
11+
version = "1.0.0"
1212

1313
ext["name"] = "SAP Customer Data Cloud SDK for Android"
1414
ext["artifactId"] = "cdc-android-sdk"

0 commit comments

Comments
 (0)