Updated SSO ViewModel to allow for client ID to be changed through remote provisioning or to use client_id from URL query parameters

This commit is contained in:
Sylvain Berfini 2025-03-11 08:49:32 +01:00
parent 2ceebdcdda
commit a99067f701
9 changed files with 65 additions and 35 deletions

View file

@ -103,7 +103,7 @@ android {
versionCode = 600000 // 6.00.000
versionName = "6.0.0"
manifestPlaceholders["appAuthRedirectScheme"] = "org.linphone"
manifestPlaceholders["appAuthRedirectScheme"] = packageName
ndk {
//noinspection ChromeOsAbiSupport
@ -155,6 +155,7 @@ android {
}
resValue("string", "linphone_app_version", gitVersion.trim())
resValue("string", "linphone_app_branch", gitBranch.toString().trim())
resValue("string", "linphone_openid_callback_scheme", packageName)
if (crashlyticsAvailable) {
val path = File("$sdkPath/libs-debug/").toString()
@ -177,6 +178,7 @@ android {
resValue("string", "file_provider", "$packageName.fileprovider")
resValue("string", "linphone_app_version", gitVersion.trim())
resValue("string", "linphone_app_branch", gitBranch.toString().trim())
resValue("string", "linphone_openid_callback_scheme", packageName)
if (crashlyticsAvailable) {
val path = File("$sdkPath/libs-debug/").toString()

View file

@ -283,6 +283,10 @@ class CorePreferences
val hideAssistantThirdPartySipAccount: Boolean
get() = config.getBool("ui", "assistant_hide_third_party_account", false)
@get:WorkerThread
val singleSignOnClientId: String
get() = config.getString("app", "oidc_client_id", "linphone")!!
@get:WorkerThread
val useUsernameAsSingleSignOnLoginHint: Boolean
get() = config.getBool("ui", "use_username_as_sso_login_hint", false)

View file

@ -35,6 +35,7 @@ import net.openid.appauth.ResponseTypeValues
import org.json.JSONObject
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R
import org.linphone.core.Factory
import org.linphone.core.tools.Log
import org.linphone.ui.GenericViewModel
@ -43,16 +44,18 @@ import org.linphone.utils.FileUtils
import org.linphone.utils.TimestampUtils
import androidx.core.net.toUri
class SingleSignOnViewModel : GenericViewModel() {
class SingleSignOnViewModel
@UiThread
constructor() : GenericViewModel() {
companion object {
private const val TAG = "[Single Sign On ViewModel]"
private const val CLIENT_ID = "linphone"
private const val REDIRECT_URI = "org.linphone:/openidcallback"
}
val singleSignOnProcessCompletedEvent = MutableLiveData<Event<Boolean>>()
private var clientId: String
private val redirectUri: String
private var singleSignOnUrl = ""
private var username: String = ""
@ -68,14 +71,37 @@ class SingleSignOnViewModel : GenericViewModel() {
private lateinit var authState: AuthState
private lateinit var authService: AuthorizationService
init {
clientId = corePreferences.singleSignOnClientId
val openIdCallbackScheme = coreContext.context.getString(R.string.linphone_openid_callback_scheme)
redirectUri = "$openIdCallbackScheme:/openidcallback"
Log.i("$TAG Using client ID [$clientId] and redirect URI [$redirectUri]")
}
@UiThread
fun setUp(ssoUrl: String, user: String = "") {
viewModelScope.launch {
singleSignOnUrl = ssoUrl
username = user
try {
val parsedUrl = ssoUrl.toUri()
val urlClientId = parsedUrl.getQueryParameter("client_id")
if (urlClientId.isNullOrEmpty()) {
Log.i("$TAG No client_id query parameter in URL, using value from config [$clientId]")
} else {
Log.w("$TAG client_id query parameter found in URL, overriding value from config [$clientId] to [$urlClientId]")
clientId = urlClientId
}
} catch (e: Exception) {
Log.e("$TAG Failed to parse SSO URL [$singleSignOnUrl]: $e")
}
Log.i(
"$TAG Setting up SSO environment for username [$username] and URL [$singleSignOnUrl], redirect URI is [$REDIRECT_URI]"
"$TAG Setting up SSO environment for username [$username] and URL [$singleSignOnUrl]"
)
authState = getAuthState()
updateTokenInfo()
@ -128,9 +154,9 @@ class SingleSignOnViewModel : GenericViewModel() {
val authRequestBuilder = AuthorizationRequest.Builder(
serviceConfiguration, // the authorization service configuration
CLIENT_ID, // the client ID, typically pre-registered and static
clientId, // the client ID, typically pre-registered and static
ResponseTypeValues.CODE, // the response_type value: we want a code
REDIRECT_URI.toUri() // the redirect URI to which the auth response is sent
redirectUri.toUri() // the redirect URI to which the auth response is sent
)
// Needed for SDK to be able to refresh the token, otherwise it will return
@ -346,7 +372,7 @@ class SingleSignOnViewModel : GenericViewModel() {
)
}
authInfo.clientId = CLIENT_ID
authInfo.clientId = clientId
core.addAuthInfo(authInfo)
Log.i(

View file

@ -39,7 +39,7 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style"
android:id="@+id/message"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
android:layout_marginTop="16dp"

View file

@ -39,7 +39,7 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style"
android:id="@+id/message"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
android:layout_marginTop="16dp"

View file

@ -39,7 +39,7 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style"
android:id="@+id/message"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
android:layout_marginTop="16dp"

View file

@ -30,30 +30,15 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<ImageView
android:id="@+id/header"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="19dp"
android:src="@drawable/mountains"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:contentDescription="@null"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/back"
app:layout_constraintBottom_toBottomOf="@id/title"
app:tint="?attr/color_main1_500"/>
<androidx.appcompat.widget.AppCompatTextView
style="@style/assistant_page_title_style"
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:paddingBottom="27dp"
android:text="@string/assistant_login_using_single_sign_on"
app:layout_constraintTop_toTopOf="parent"
android:textColor="?attr/color_text"
app:layout_constraintTop_toTopOf="@id/back"
app:layout_constraintBottom_toBottomOf="@id/back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
@ -65,7 +50,7 @@
app:indicatorColor="?attr/color_main1_500"
android:indeterminate="true"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/message"/>
@ -84,7 +69,21 @@
app:layout_constraintTop_toBottomOf="@id/progress"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
app:layout_constraintBottom_toTopOf="@id/mountains"/>
<ImageView
android:id="@+id/mountains"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="19dp"
android:src="@drawable/mountains"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:contentDescription="@null"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:tint="?attr/color_main1_500"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -6,7 +6,6 @@
<!-- Common words -->
<string name="sip_address">Adresse SIP</string>
<string name="device_id">ID du téléphone</string>
<string name="sip_address_hint">utilisateur@domaine</string>
<string name="sip_address_display_name">Nom d\'affichage</string>
<string name="sip_address_domain">Domaine</string>
<string name="username">Nom d\'utilisateur</string>
@ -14,7 +13,7 @@
<string name="password">Mot de passe</string>
<string name="phone_number">Numéro de téléphone</string>
<string name="or">ou</string>
<string name="next">suivant</string>
<string name="next">Suivant</string>
<string name="start">Commencer</string>
<string name="today">Aujourd\'hui</string>
<string name="yesterday">Hier</string>

View file

@ -51,7 +51,7 @@
<string name="password">Password</string>
<string name="phone_number">Phone number</string>
<string name="or">or</string>
<string name="next">next</string>
<string name="next">Next</string>
<string name="start">Start</string>
<string name="today">Today</string>
<string name="yesterday">Yesterday</string>