Skip to content

Commit b068597

Browse files
authored
OIDC configuration (#4623)
* Login: more logs. * Login: map Oidc error to provide more information in the error dialog. * Oidc: use the application name. * Oidc: move configuration from OidcConfigurationProvider to OidcConfig and add some comments. * Oidc: limit to only 1 contact in the configuration. * Oidc: Move configuration to BuildConfig file. * Remove unused const. * Add missing test on Exception mapping * Remove contacts from OidcConfiguration. matrix-org/matrix-rust-sdk#4958
1 parent bc5c771 commit b068597

File tree

12 files changed

+110
-20
lines changed

12 files changed

+110
-20
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
<category android:name="android.intent.category.DEFAULT" />
6161
<category android:name="android.intent.category.BROWSABLE" />
6262

63+
<!-- Note: the scheme must match the scheme of the value of OidcConfig.REDIRECT_URI -->
6364
<data android:scheme="io.element" />
6465
</intent-filter>
6566
<!--

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/error/ChangeServerError.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,24 @@ import androidx.compose.runtime.Composable
1212
import androidx.compose.ui.res.stringResource
1313
import io.element.android.features.login.impl.R
1414
import io.element.android.libraries.matrix.api.auth.AuthenticationException
15+
import io.element.android.libraries.ui.strings.CommonStrings
1516

1617
sealed class ChangeServerError : Throwable() {
17-
data class Error(@StringRes val messageId: Int) : ChangeServerError() {
18+
data class Error(
19+
@StringRes val messageId: Int? = null,
20+
val messageStr: String? = null,
21+
) : ChangeServerError() {
1822
@Composable
19-
fun message(): String = stringResource(messageId)
23+
fun message(): String = messageStr ?: stringResource(messageId ?: CommonStrings.error_unknown)
2024
}
25+
2126
data object SlidingSyncAlert : ChangeServerError()
2227

2328
companion object {
2429
fun from(error: Throwable): ChangeServerError = when (error) {
2530
is AuthenticationException.SlidingSyncVersion -> SlidingSyncAlert
26-
else -> Error(R.string.screen_change_server_error_invalid_homeserver)
31+
is AuthenticationException.Oidc -> Error(messageStr = error.message)
32+
else -> Error(messageId = R.string.screen_change_server_error_invalid_homeserver)
2733
}
2834
}
2935
}

libraries/matrix/api/build.gradle.kts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import config.BuildTimeConfig
2+
import extension.buildConfigFieldStr
13
import extension.setupAnvil
24

35
/*
@@ -19,6 +21,32 @@ android {
1921
buildFeatures {
2022
buildConfig = true
2123
}
24+
25+
defaultConfig {
26+
buildConfigFieldStr(
27+
name = "CLIENT_URI",
28+
value = BuildTimeConfig.URL_WEBSITE ?: "https://element.io"
29+
)
30+
buildConfigFieldStr(
31+
name = "REDIRECT_URI",
32+
value = buildString {
33+
append(BuildTimeConfig.METADATA_HOST_REVERSED ?: "io.element")
34+
append(":/callback")
35+
}
36+
)
37+
buildConfigFieldStr(
38+
name = "LOGO_URI",
39+
value = BuildTimeConfig.URL_LOGO ?: "https://element.io/mobile-icon.png"
40+
)
41+
buildConfigFieldStr(
42+
name = "TOS_URI",
43+
value = BuildTimeConfig.URL_ACCEPTABLE_USE ?: "https://element.io/acceptable-use-policy-terms"
44+
)
45+
buildConfigFieldStr(
46+
name = "POLICY_URI",
47+
value = BuildTimeConfig.URL_POLICY ?: "https://element.io/privacy"
48+
)
49+
}
2250
}
2351

2452
setupAnvil()

libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthenticationException.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ package io.element.android.libraries.matrix.api.auth
1010
sealed class AuthenticationException(message: String) : Exception(message) {
1111
class InvalidServerName(message: String) : AuthenticationException(message)
1212
class SlidingSyncVersion(message: String) : AuthenticationException(message)
13+
class Oidc(message: String) : AuthenticationException(message)
1314
class Generic(message: String) : AuthenticationException(message)
1415
}

libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcConfig.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@
77

88
package io.element.android.libraries.matrix.api.auth
99

10+
import io.element.android.libraries.matrix.api.BuildConfig
11+
1012
object OidcConfig {
11-
const val REDIRECT_URI = "io.element:/callback"
13+
const val CLIENT_URI = BuildConfig.CLIENT_URI
14+
15+
// Notes:
16+
// 1. the scheme must match the value declared in the AndroidManifest.xml
17+
// 2. the scheme must be the reverse of the host of CLIENT_URI
18+
const val REDIRECT_URI = BuildConfig.REDIRECT_URI
19+
20+
// Note: host must match with the host of CLIENT_URI
21+
const val LOGO_URI = BuildConfig.LOGO_URI
22+
23+
// Note: host must match with the host of CLIENT_URI
24+
const val TOS_URI = BuildConfig.TOS_URI
25+
26+
// Note: host must match with the host of CLIENT_URI
27+
const val POLICY_URI = BuildConfig.POLICY_URI
28+
29+
// Some homeservers/auth issuers don't support dynamic client registration, and have to be registered manually
30+
val STATIC_REGISTRATIONS = mapOf(
31+
"https://id.thirdroom.io/realms/thirdroom" to "elementx",
32+
)
1233
}

libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationException.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package io.element.android.libraries.matrix.impl.auth
99

1010
import io.element.android.libraries.matrix.api.auth.AuthenticationException
1111
import org.matrix.rustcomponents.sdk.ClientBuildException
12+
import org.matrix.rustcomponents.sdk.OidcException
1213

1314
fun Throwable.mapAuthenticationException(): AuthenticationException {
1415
val message = this.message ?: "Unknown error"
@@ -24,6 +25,13 @@ fun Throwable.mapAuthenticationException(): AuthenticationException {
2425
is ClientBuildException.WellKnownLookupFailed -> AuthenticationException.Generic(message)
2526
is ClientBuildException.EventCache -> AuthenticationException.Generic(message)
2627
}
28+
is OidcException -> when (this) {
29+
is OidcException.Generic -> AuthenticationException.Oidc(message)
30+
is OidcException.CallbackUrlInvalid -> AuthenticationException.Oidc(message)
31+
is OidcException.Cancelled -> AuthenticationException.Oidc(message)
32+
is OidcException.MetadataInvalid -> AuthenticationException.Oidc(message)
33+
is OidcException.NotSupported -> AuthenticationException.Oidc(message)
34+
}
2735
else -> AuthenticationException.Generic(message)
2836
}
2937
}

libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfigurationProvider.kt

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,22 @@
77

88
package io.element.android.libraries.matrix.impl.auth
99

10+
import io.element.android.libraries.core.meta.BuildMeta
1011
import io.element.android.libraries.matrix.api.auth.OidcConfig
1112
import org.matrix.rustcomponents.sdk.OidcConfiguration
1213
import javax.inject.Inject
1314

14-
class OidcConfigurationProvider @Inject constructor() {
15+
class OidcConfigurationProvider @Inject constructor(
16+
private val buildMeta: BuildMeta,
17+
) {
1518
fun get(): OidcConfiguration = OidcConfiguration(
16-
clientName = "Element",
19+
clientName = buildMeta.applicationName,
1720
redirectUri = OidcConfig.REDIRECT_URI,
18-
clientUri = "https://element.io",
19-
logoUri = "https://element.io/mobile-icon.png",
20-
tosUri = "https://element.io/acceptable-use-policy-terms",
21-
policyUri = "https://element.io/privacy",
22-
contacts = listOf(
23-
24-
),
25-
// Some homeservers/auth issuers don't support dynamic client registration, and have to be registered manually
26-
staticRegistrations = mapOf(
27-
"https://id.thirdroom.io/realms/thirdroom" to "elementx",
28-
),
21+
clientUri = OidcConfig.CLIENT_URI,
22+
logoUri = OidcConfig.LOGO_URI,
23+
tosUri = OidcConfig.TOS_URI,
24+
policyUri = OidcConfig.POLICY_URI,
25+
contacts = null,
26+
staticRegistrations = OidcConfig.STATIC_REGISTRATIONS,
2927
)
3028
}

libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class RustMatrixAuthenticationService @Inject constructor(
137137
}.onFailure {
138138
clear()
139139
}.mapFailure { failure ->
140+
Timber.e(failure, "Failed to set homeserver to $homeserver")
140141
failure.mapAuthenticationException()
141142
}
142143
}
@@ -162,6 +163,7 @@ class RustMatrixAuthenticationService @Inject constructor(
162163

163164
SessionId(sessionData.userId)
164165
}.mapFailure { failure ->
166+
Timber.e(failure, "Failed to login")
165167
failure.mapAuthenticationException()
166168
}
167169
}
@@ -197,6 +199,7 @@ class RustMatrixAuthenticationService @Inject constructor(
197199
pendingOAuthAuthorizationData = oAuthAuthorizationData
198200
OidcDetails(url)
199201
}.mapFailure { failure ->
202+
Timber.e(failure, "Failed to get OIDC URL")
200203
failure.mapAuthenticationException()
201204
}
202205
}
@@ -210,6 +213,7 @@ class RustMatrixAuthenticationService @Inject constructor(
210213
}
211214
pendingOAuthAuthorizationData = null
212215
}.mapFailure { failure ->
216+
Timber.e(failure, "Failed to cancel OIDC login")
213217
failure.mapAuthenticationException()
214218
}
215219
}
@@ -243,6 +247,7 @@ class RustMatrixAuthenticationService @Inject constructor(
243247

244248
SessionId(sessionData.userId)
245249
}.mapFailure { failure ->
250+
Timber.e(failure, "Failed to login with OIDC")
246251
failure.mapAuthenticationException()
247252
}
248253
}

libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationExceptionMappingTest.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.google.common.truth.Truth.assertThat
1212
import io.element.android.libraries.matrix.api.auth.AuthenticationException
1313
import org.junit.Test
1414
import org.matrix.rustcomponents.sdk.ClientBuildException
15+
import org.matrix.rustcomponents.sdk.OidcException
1516

1617
class AuthenticationExceptionMappingTest {
1718
@Test
@@ -56,6 +57,20 @@ class AuthenticationExceptionMappingTest {
5657
.isException<AuthenticationException.Generic>("EventCache error")
5758
}
5859

60+
@Test
61+
fun `mapping Oidc exceptions map to the Oidc Kotlin`() {
62+
assertThat(OidcException.Generic("Generic").mapAuthenticationException())
63+
.isException<AuthenticationException.Oidc>("Generic")
64+
assertThat(OidcException.CallbackUrlInvalid("CallbackUrlInvalid").mapAuthenticationException())
65+
.isException<AuthenticationException.Oidc>("CallbackUrlInvalid")
66+
assertThat(OidcException.Cancelled("Cancelled").mapAuthenticationException())
67+
.isException<AuthenticationException.Oidc>("Cancelled")
68+
assertThat(OidcException.MetadataInvalid("MetadataInvalid").mapAuthenticationException())
69+
.isException<AuthenticationException.Oidc>("MetadataInvalid")
70+
assertThat(OidcException.NotSupported("NotSupported").mapAuthenticationException())
71+
.isException<AuthenticationException.Oidc>("NotSupported")
72+
}
73+
5974
private inline fun <reified T> ThrowableSubject.isException(message: String) {
6075
isInstanceOf(T::class.java)
6176
hasMessageThat().isEqualTo(message)

libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfigurationProviderTest.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@ package io.element.android.libraries.matrix.impl.auth
99

1010
import com.google.common.truth.Truth.assertThat
1111
import io.element.android.libraries.matrix.api.auth.OidcConfig
12+
import io.element.android.libraries.matrix.test.core.aBuildMeta
1213
import org.junit.Test
1314

1415
class OidcConfigurationProviderTest {
1516
@Test
1617
fun get() {
17-
val result = OidcConfigurationProvider().get()
18+
val result = OidcConfigurationProvider(
19+
aBuildMeta(
20+
applicationName = "myName",
21+
)
22+
).get()
23+
assertThat(result.clientName).isEqualTo("myName")
1824
assertThat(result.redirectUri).isEqualTo(OidcConfig.REDIRECT_URI)
1925
}
2026
}

0 commit comments

Comments
 (0)