Browse Source

Restore OIDC support.

pull/1127/head
Benoit Marty 1 year ago
parent
commit
6928dc6e44
  1. 4
      docs/oidc.md
  2. 45
      features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenter.kt
  3. 2
      features/login/impl/src/main/kotlin/io/element/android/features/login/impl/util/LoginConstants.kt
  4. 59
      features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenterTest.kt
  5. 4
      features/logout/api/src/main/kotlin/io/element/android/features/logout/api/LogoutPreferenceScreen.kt
  6. 2
      features/logout/api/src/main/kotlin/io/element/android/features/logout/api/LogoutPreferenceState.kt
  7. 4
      features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/DefaultLogoutPreferencePresenter.kt
  8. 15
      features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootNode.kt
  9. 3
      features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt
  10. 7
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt
  11. 3
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthenticationException.kt
  12. 29
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt
  13. 1
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt
  14. 7
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationException.kt
  15. 2
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetails.kt
  16. 18
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfig.kt
  17. 35
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt
  18. 3
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt
  19. 1
      libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt
  20. 2
      libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt
  21. 3
      libraries/session-storage/impl/src/main/sqldelight/io/element/android/libraries/matrix/session/SessionData.sq
  22. 1
      libraries/session-storage/impl/src/main/sqldelight/migrations/2.sqm
  23. 1
      libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt

4
docs/oidc.md

@ -45,3 +45,7 @@ state: ex6mNJVFZ5jn9wL8 @@ -45,3 +45,7 @@ state: ex6mNJVFZ5jn9wL8
Oidc client example: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/examples/oidc_cli/src/main.rs
Oidc sdk doc: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/crates/matrix-sdk/src/oidc.rs
Test server:
synapse-oidc.lab.element.dev

45
features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenter.kt

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package io.element.android.features.login.impl.screens.confirmaccountprovider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@ -26,8 +27,11 @@ import androidx.compose.runtime.rememberCoroutineScope @@ -26,8 +27,11 @@ import androidx.compose.runtime.rememberCoroutineScope
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import io.element.android.features.login.api.oidc.OidcAction
import io.element.android.features.login.impl.DefaultLoginUserStory
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
import io.element.android.features.login.impl.error.ChangeServerError
import io.element.android.features.login.impl.oidc.customtab.DefaultOidcActionFlow
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
@ -40,7 +44,9 @@ import java.net.URL @@ -40,7 +44,9 @@ import java.net.URL
class ConfirmAccountProviderPresenter @AssistedInject constructor(
@Assisted private val params: Params,
private val accountProviderDataSource: AccountProviderDataSource,
private val authenticationService: MatrixAuthenticationService
private val authenticationService: MatrixAuthenticationService,
private val defaultOidcActionFlow: DefaultOidcActionFlow,
private val defaultLoginUserStory: DefaultLoginUserStory,
) : Presenter<ConfirmAccountProviderState> {
data class Params(
@ -61,6 +67,14 @@ class ConfirmAccountProviderPresenter @AssistedInject constructor( @@ -61,6 +67,14 @@ class ConfirmAccountProviderPresenter @AssistedInject constructor(
mutableStateOf(Async.Uninitialized)
}
LaunchedEffect(Unit) {
launch {
defaultOidcActionFlow.collect {
onOidcAction(it, loginFlowAction)
}
}
}
fun handleEvents(event: ConfirmAccountProviderEvents) {
when (event) {
ConfirmAccountProviderEvents.Continue -> {
@ -97,4 +111,33 @@ class ConfirmAccountProviderPresenter @AssistedInject constructor( @@ -97,4 +111,33 @@ class ConfirmAccountProviderPresenter @AssistedInject constructor(
}.getOrThrow()
}.runCatchingUpdatingState(loginFlowAction, errorTransform = ChangeServerError::from)
}
private suspend fun onOidcAction(
oidcAction: OidcAction?,
loginFlowAction: MutableState<Async<LoginFlow>>,
) {
oidcAction ?: return
loginFlowAction.value = Async.Loading()
when (oidcAction) {
OidcAction.GoBack -> {
authenticationService.cancelOidcLogin()
.onSuccess {
loginFlowAction.value = Async.Uninitialized
}
.onFailure { failure ->
loginFlowAction.value = Async.Failure(failure)
}
}
is OidcAction.Success -> {
authenticationService.loginWithOidc(oidcAction.url)
.onSuccess { _ ->
defaultLoginUserStory.setLoginFlowIsDone(true)
}
.onFailure { failure ->
loginFlowAction.value = Async.Failure(failure)
}
}
}
defaultOidcActionFlow.reset()
}
}

2
features/login/impl/src/main/kotlin/io/element/android/features/login/impl/util/LoginConstants.kt

@ -21,7 +21,7 @@ import io.element.android.features.login.impl.accountprovider.AccountProvider @@ -21,7 +21,7 @@ import io.element.android.features.login.impl.accountprovider.AccountProvider
object LoginConstants {
const val MATRIX_ORG_URL = "matrix.org"
const val DEFAULT_HOMESERVER_URL = "matrix.org" // TODO Oidc "synapse-oidc.lab.element.dev"
const val DEFAULT_HOMESERVER_URL = "matrix.org"
const val SLIDING_SYNC_READ_MORE_URL = "https://github.com/matrix-org/sliding-sync/blob/main/docs/Landing.md"
}

59
features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenterTest.kt

@ -20,9 +20,12 @@ import app.cash.molecule.RecompositionMode @@ -20,9 +20,12 @@ import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.features.login.impl.DefaultLoginUserStory
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
import io.element.android.features.login.impl.oidc.customtab.DefaultOidcActionFlow
import io.element.android.features.login.impl.util.defaultAccountProvider
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
import io.element.android.libraries.matrix.test.A_HOMESERVER
import io.element.android.libraries.matrix.test.A_HOMESERVER_OIDC
import io.element.android.libraries.matrix.test.A_THROWABLE
@ -33,11 +36,7 @@ import org.junit.Test @@ -33,11 +36,7 @@ import org.junit.Test
class ConfirmAccountProviderPresenterTest {
@Test
fun `present - initial test`() = runTest {
val presenter = ConfirmAccountProviderPresenter(
ConfirmAccountProviderPresenter.Params(isAccountCreation = false),
AccountProviderDataSource(),
FakeAuthenticationService(),
)
val presenter = createConfirmAccountProviderPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -51,13 +50,11 @@ class ConfirmAccountProviderPresenterTest { @@ -51,13 +50,11 @@ class ConfirmAccountProviderPresenterTest {
@Test
fun `present - continue password login`() = runTest {
val authServer = FakeAuthenticationService()
val presenter = ConfirmAccountProviderPresenter(
ConfirmAccountProviderPresenter.Params(isAccountCreation = false),
AccountProviderDataSource(),
authServer,
val authenticationService = FakeAuthenticationService()
val presenter = createConfirmAccountProviderPresenter(
matrixAuthenticationService = authenticationService,
)
authServer.givenHomeserver(A_HOMESERVER)
authenticationService.givenHomeserver(A_HOMESERVER)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -75,13 +72,11 @@ class ConfirmAccountProviderPresenterTest { @@ -75,13 +72,11 @@ class ConfirmAccountProviderPresenterTest {
@Test
fun `present - continue oidc`() = runTest {
val authServer = FakeAuthenticationService()
val presenter = ConfirmAccountProviderPresenter(
ConfirmAccountProviderPresenter.Params(isAccountCreation = false),
AccountProviderDataSource(),
authServer,
val authenticationService = FakeAuthenticationService()
val presenter = createConfirmAccountProviderPresenter(
matrixAuthenticationService = authenticationService,
)
authServer.givenHomeserver(A_HOMESERVER_OIDC)
authenticationService.givenHomeserver(A_HOMESERVER_OIDC)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -99,17 +94,15 @@ class ConfirmAccountProviderPresenterTest { @@ -99,17 +94,15 @@ class ConfirmAccountProviderPresenterTest {
@Test
fun `present - submit fails`() = runTest {
val authServer = FakeAuthenticationService()
val presenter = ConfirmAccountProviderPresenter(
ConfirmAccountProviderPresenter.Params(isAccountCreation = false),
AccountProviderDataSource(),
authServer,
val authenticationService = FakeAuthenticationService()
val presenter = createConfirmAccountProviderPresenter(
matrixAuthenticationService = authenticationService,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
authServer.givenChangeServerError(Throwable())
authenticationService.givenChangeServerError(Throwable())
initialState.eventSink.invoke(ConfirmAccountProviderEvents.Continue)
skipItems(1) // Loading
val failureState = awaitItem()
@ -121,10 +114,8 @@ class ConfirmAccountProviderPresenterTest { @@ -121,10 +114,8 @@ class ConfirmAccountProviderPresenterTest {
@Test
fun `present - clear error`() = runTest {
val authenticationService = FakeAuthenticationService()
val presenter = ConfirmAccountProviderPresenter(
ConfirmAccountProviderPresenter.Params(isAccountCreation = false),
AccountProviderDataSource(),
authenticationService,
val presenter = createConfirmAccountProviderPresenter(
matrixAuthenticationService = authenticationService,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@ -147,4 +138,18 @@ class ConfirmAccountProviderPresenterTest { @@ -147,4 +138,18 @@ class ConfirmAccountProviderPresenterTest {
assertThat(clearedState.loginFlow).isEqualTo(Async.Uninitialized)
}
}
private fun createConfirmAccountProviderPresenter(
params: ConfirmAccountProviderPresenter.Params = ConfirmAccountProviderPresenter.Params(isAccountCreation = false),
accountProviderDataSource: AccountProviderDataSource = AccountProviderDataSource(),
matrixAuthenticationService: MatrixAuthenticationService = FakeAuthenticationService(),
defaultOidcActionFlow: DefaultOidcActionFlow = DefaultOidcActionFlow(),
defaultLoginUserStory: DefaultLoginUserStory = DefaultLoginUserStory(),
) = ConfirmAccountProviderPresenter(
params = params,
accountProviderDataSource = accountProviderDataSource,
authenticationService = matrixAuthenticationService,
defaultOidcActionFlow = defaultOidcActionFlow,
defaultLoginUserStory = defaultLoginUserStory,
)
}

4
features/logout/api/src/main/kotlin/io/element/android/features/logout/api/LogoutPreferenceScreen.kt

@ -34,12 +34,12 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewLight @@ -34,12 +34,12 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewLight
@Composable
fun LogoutPreferenceView(
state: LogoutPreferenceState,
onSuccessLogout: () -> Unit = {}
onSuccessLogout: (String?) -> Unit = {}
) {
val eventSink = state.eventSink
if (state.logoutAction is Async.Success) {
LaunchedEffect(state.logoutAction) {
onSuccessLogout()
onSuccessLogout(state.logoutAction.data)
}
return
}

2
features/logout/api/src/main/kotlin/io/element/android/features/logout/api/LogoutPreferenceState.kt

@ -19,6 +19,6 @@ package io.element.android.features.logout.api @@ -19,6 +19,6 @@ package io.element.android.features.logout.api
import io.element.android.libraries.architecture.Async
data class LogoutPreferenceState(
val logoutAction: Async<Unit>,
val logoutAction: Async<String?>,
val eventSink: (LogoutPreferenceEvents) -> Unit,
)

4
features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/DefaultLogoutPreferencePresenter.kt

@ -40,7 +40,7 @@ class DefaultLogoutPreferencePresenter @Inject constructor(private val matrixCli @@ -40,7 +40,7 @@ class DefaultLogoutPreferencePresenter @Inject constructor(private val matrixCli
@Composable
override fun present(): LogoutPreferenceState {
val localCoroutineScope = rememberCoroutineScope()
val logoutAction: MutableState<Async<Unit>> = remember {
val logoutAction: MutableState<Async<String?>> = remember {
mutableStateOf(Async.Uninitialized)
}
@ -56,7 +56,7 @@ class DefaultLogoutPreferencePresenter @Inject constructor(private val matrixCli @@ -56,7 +56,7 @@ class DefaultLogoutPreferencePresenter @Inject constructor(private val matrixCli
)
}
private fun CoroutineScope.logout(logoutAction: MutableState<Async<Unit>>) = launch {
private fun CoroutineScope.logout(logoutAction: MutableState<Async<String?>>) = launch {
suspend {
matrixClient.logout()
}.runCatchingUpdatingState(logoutAction)

15
features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootNode.kt

@ -16,8 +16,10 @@ @@ -16,8 +16,10 @@
package io.element.android.features.preferences.impl.root
import android.app.Activity
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
@ -25,7 +27,9 @@ import com.bumble.appyx.core.plugin.plugins @@ -25,7 +27,9 @@ import com.bumble.appyx.core.plugin.plugins
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
import io.element.android.libraries.di.SessionScope
import timber.log.Timber
@ContributesNode(SessionScope::class)
class PreferencesRootNode @AssistedInject constructor(
@ -65,6 +69,7 @@ class PreferencesRootNode @AssistedInject constructor( @@ -65,6 +69,7 @@ class PreferencesRootNode @AssistedInject constructor(
@Composable
override fun View(modifier: Modifier) {
val state = presenter.present()
val activity = LocalContext.current as Activity
PreferencesRootView(
state = state,
modifier = modifier,
@ -73,7 +78,15 @@ class PreferencesRootNode @AssistedInject constructor( @@ -73,7 +78,15 @@ class PreferencesRootNode @AssistedInject constructor(
onOpenAnalytics = this::onOpenAnalytics,
onOpenAbout = this::onOpenAbout,
onVerifyClicked = this::onVerifyClicked,
onOpenDeveloperSettings = this::onOpenDeveloperSettings
onOpenDeveloperSettings = this::onOpenDeveloperSettings,
onSuccessLogout = { onSuccessLogout(activity, it) }
)
}
private fun onSuccessLogout(activity: Activity, url: String?) {
Timber.d("Success logout with result url: $url")
url?.let {
activity.openUrlInChromeCustomTab(null, false, it)
}
}
}

3
features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt

@ -55,6 +55,7 @@ fun PreferencesRootView( @@ -55,6 +55,7 @@ fun PreferencesRootView(
onOpenRageShake: () -> Unit,
onOpenAbout: () -> Unit,
onOpenDeveloperSettings: () -> Unit,
onSuccessLogout: (String?) -> Unit,
modifier: Modifier = Modifier,
) {
val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage)
@ -98,6 +99,7 @@ fun PreferencesRootView( @@ -98,6 +99,7 @@ fun PreferencesRootView(
HorizontalDivider()
LogoutPreferenceView(
state = state.logoutState,
onSuccessLogout = onSuccessLogout,
)
Text(
modifier = Modifier
@ -140,5 +142,6 @@ private fun ContentToPreview(matrixUser: MatrixUser) { @@ -140,5 +142,6 @@ private fun ContentToPreview(matrixUser: MatrixUser) {
onOpenDeveloperSettings = {},
onOpenAbout = {},
onVerifyClicked = {},
onSuccessLogout = {},
)
}

7
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt

@ -55,7 +55,12 @@ interface MatrixClient : Closeable { @@ -55,7 +55,12 @@ interface MatrixClient : Closeable {
* Will close the client and delete the cache data.
*/
suspend fun clearCache()
suspend fun logout()
/**
* Logout the user.
* Returns an optional URL. When the URL is there, it should be presented to the user after logout for RP initiated logout on their account page.
*/
suspend fun logout(): String?
suspend fun loadUserDisplayName(): Result<String>
suspend fun loadUserAvatarURLString(): Result<String?>
suspend fun uploadMedia(mimeType: String, data: ByteArray, progressCallback: ProgressCallback?): Result<String>

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

@ -22,6 +22,5 @@ sealed class AuthenticationException(message: String) : Exception(message) { @@ -22,6 +22,5 @@ sealed class AuthenticationException(message: String) : Exception(message) {
class SlidingSyncNotAvailable(message: String) : AuthenticationException(message)
class SessionMissing(message: String) : AuthenticationException(message)
class Generic(message: String) : AuthenticationException(message)
// TODO Oidc
// class OidcError(type: String, message: String) : AuthenticationException(message)
data class OidcError(val type: String, override val message: String) : AuthenticationException(message)
}

29
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt

@ -119,6 +119,11 @@ class RustMatrixClient constructor( @@ -119,6 +119,11 @@ class RustMatrixClient constructor(
Timber.v("didReceiveAuthError -> already cleaning up")
}
}
override fun didRefreshTokens() {
Timber.w("didRefreshTokens()")
// TODO handle refresh token
}
}
private val rustRoomListService: RoomListService =
@ -287,19 +292,23 @@ class RustMatrixClient constructor( @@ -287,19 +292,23 @@ class RustMatrixClient constructor(
baseDirectory.deleteSessionDirectory(userID = sessionId.value, deleteCryptoDb = false)
}
override suspend fun logout() = doLogout(doRequest = true)
override suspend fun logout(): String? = doLogout(doRequest = true)
private suspend fun doLogout(doRequest: Boolean) = withContext(sessionDispatcher) {
if (doRequest) {
try {
client.logout()
} catch (failure: Throwable) {
Timber.e(failure, "Fail to call logout on HS. Still delete local files.")
private suspend fun doLogout(doRequest: Boolean): String? {
var result: String? = null
withContext(sessionDispatcher) {
if (doRequest) {
try {
result = client.logout()
} catch (failure: Throwable) {
Timber.e(failure, "Fail to call logout on HS. Still delete local files.")
}
}
close()
baseDirectory.deleteSessionDirectory(userID = sessionId.value, deleteCryptoDb = true)
sessionStore.removeSession(sessionId.value)
}
close()
baseDirectory.deleteSessionDirectory(userID = sessionId.value, deleteCryptoDb = true)
sessionStore.removeSession(sessionId.value)
return result
}
override suspend fun loadUserDisplayName(): Result<String> = withContext(sessionDispatcher) {

1
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt

@ -75,4 +75,5 @@ private fun SessionData.toSession() = Session( @@ -75,4 +75,5 @@ private fun SessionData.toSession() = Session(
deviceId = deviceId,
homeserverUrl = homeserverUrl,
slidingSyncProxy = slidingSyncProxy,
oidcData = oidcData,
)

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

@ -26,15 +26,12 @@ fun Throwable.mapAuthenticationException(): AuthenticationException { @@ -26,15 +26,12 @@ fun Throwable.mapAuthenticationException(): AuthenticationException {
is RustAuthenticationException.InvalidServerName -> AuthenticationException.InvalidServerName(this.message!!)
is RustAuthenticationException.SessionMissing -> AuthenticationException.SessionMissing(this.message!!)
is RustAuthenticationException.SlidingSyncNotAvailable -> AuthenticationException.SlidingSyncNotAvailable(this.message!!)
/* TODO Oidc
is RustAuthenticationException.OidcException -> AuthenticationException.OidcError("OidcException", message!!)
is RustAuthenticationException.OidcMetadataInvalid -> AuthenticationException.OidcError("OidcMetadataInvalid", message!!)
is RustAuthenticationException.OidcMetadataMissing -> AuthenticationException.OidcError("OidcMetadataMissing", message!!)
is RustAuthenticationException.OidcNotStarted -> AuthenticationException.OidcError("OidcNotStarted", message!!)
is RustAuthenticationException.OidcNotSupported -> AuthenticationException.OidcError("OidcNotSupported", message!!)
*/
is RustAuthenticationException.OidcCancelled -> AuthenticationException.OidcError("OidcCancelled", message!!)
is RustAuthenticationException.OidcCallbackUrlInvalid -> AuthenticationException.OidcError("OidcCallbackUrlInvalid", message!!)
else -> AuthenticationException.Generic(this.message ?: "Unknown error")
}
}

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

@ -23,6 +23,6 @@ fun HomeserverLoginDetails.map(): MatrixHomeServerDetails = use { @@ -23,6 +23,6 @@ fun HomeserverLoginDetails.map(): MatrixHomeServerDetails = use {
MatrixHomeServerDetails(
url = url(),
supportsPasswordLogin = supportsPasswordLogin(),
supportsOidcLogin = false // TODO Oidc supportsOidcLogin(),
supportsOidcLogin = supportsOidcLogin(),
)
}

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

@ -16,17 +16,19 @@ @@ -16,17 +16,19 @@
package io.element.android.libraries.matrix.impl.auth
// TODO Oidc
// import io.element.android.libraries.matrix.api.auth.OidcConfig
// import org.matrix.rustcomponents.sdk.OidcClientMetadata
import io.element.android.libraries.matrix.api.auth.OidcConfig
import org.matrix.rustcomponents.sdk.OidcConfiguration
/*
val oidcClientMetadata: OidcClientMetadata = OidcClientMetadata(
val oidcConfiguration: OidcConfiguration = OidcConfiguration(
clientName = "Element",
redirectUri = OidcConfig.redirectUri,
clientUri = "https://element.io",
tosUri = "https://element.io/user-terms-of-service",
policyUri = "https://element.io/privacy"
policyUri = "https://element.io/privacy",
/**
* Some homeservers/auth issuers don't support dynamic client registration, and have to be registered manually
*/
staticRegistrations = mapOf(
"https://id.thirdroom.io/realms/thirdroom" to "elementx",
),
)
*/

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

@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
package io.element.android.libraries.matrix.impl.auth
// TODO Oidc
// import org.matrix.rustcomponents.sdk.OidcAuthenticationUrl
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.extensions.mapFailure
@ -37,6 +35,7 @@ import kotlinx.coroutines.flow.Flow @@ -37,6 +35,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.OidcAuthenticationData
import org.matrix.rustcomponents.sdk.Session
import org.matrix.rustcomponents.sdk.use
import java.io.File
@ -57,9 +56,8 @@ class RustMatrixAuthenticationService @Inject constructor( @@ -57,9 +56,8 @@ class RustMatrixAuthenticationService @Inject constructor(
private val authService: RustAuthenticationService = RustAuthenticationService(
basePath = baseDirectory.absolutePath,
passphrase = null,
// TODO Oidc
// oidcClientMetadata = oidcClientMetadata,
userAgent = userAgentProvider.provide(),
oidcConfiguration = oidcConfiguration,
customSlidingSyncProxy = null,
)
private var currentHomeserver = MutableStateFlow<MatrixHomeServerDetails?>(null)
@ -112,60 +110,50 @@ class RustMatrixAuthenticationService @Inject constructor( @@ -112,60 +110,50 @@ class RustMatrixAuthenticationService @Inject constructor(
}
}
// TODO Oidc
// private var pendingUrlForOidcLogin: OidcAuthenticationUrl? = null
private var pendingOidcAuthenticationData: OidcAuthenticationData? = null
override suspend fun getOidcUrl(): Result<OidcDetails> {
TODO("Oidc")
/*
return withContext(coroutineDispatchers.io) {
runCatching {
val urlForOidcLogin = authService.urlForOidcLogin()
val url = urlForOidcLogin.loginUrl()
pendingUrlForOidcLogin = urlForOidcLogin
val oidcAuthenticationData = authService.urlForOidcLogin()
val url = oidcAuthenticationData.loginUrl()
pendingOidcAuthenticationData = oidcAuthenticationData
OidcDetails(url)
}.mapFailure { failure ->
failure.mapAuthenticationException()
}
}
*/
}
override suspend fun cancelOidcLogin(): Result<Unit> {
TODO("Oidc")
/*
return withContext(coroutineDispatchers.io) {
runCatching {
pendingUrlForOidcLogin?.close()
pendingUrlForOidcLogin = null
pendingOidcAuthenticationData?.close()
pendingOidcAuthenticationData = null
}.mapFailure { failure ->
failure.mapAuthenticationException()
}
}
*/
}
/**
* callbackUrl should be the uriRedirect from OidcClientMetadata (with all the parameters).
*/
override suspend fun loginWithOidc(callbackUrl: String): Result<SessionId> {
TODO("Oidc")
/*
return withContext(coroutineDispatchers.io) {
runCatching {
val urlForOidcLogin = pendingUrlForOidcLogin ?: error("You need to call `getOidcUrl()` first")
val urlForOidcLogin = pendingOidcAuthenticationData ?: error("You need to call `getOidcUrl()` first")
val client = authService.loginWithOidcCallback(urlForOidcLogin, callbackUrl)
val sessionData = client.use { it.session().toSessionData() }
pendingUrlForOidcLogin = null
pendingOidcAuthenticationData?.close()
pendingOidcAuthenticationData = null
sessionStore.storeData(sessionData)
SessionId(sessionData.userId)
}.mapFailure { failure ->
failure.mapAuthenticationException()
}
}
*/
}
}
private fun Session.toSessionData() = SessionData(
@ -174,6 +162,7 @@ private fun Session.toSessionData() = SessionData( @@ -174,6 +162,7 @@ private fun Session.toSessionData() = SessionData(
accessToken = accessToken,
refreshToken = refreshToken,
homeserverUrl = homeserverUrl,
oidcData = oidcData,
slidingSyncProxy = slidingSyncProxy,
loginTimestamp = Date(),
)

3
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt

@ -109,9 +109,10 @@ class FakeMatrixClient( @@ -109,9 +109,10 @@ class FakeMatrixClient(
override suspend fun clearCache() {
}
override suspend fun logout() {
override suspend fun logout(): String? {
delay(100)
logoutFailure?.let { throw it }
return null
}
override fun close() = Unit

1
libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt

@ -24,6 +24,7 @@ data class SessionData( @@ -24,6 +24,7 @@ data class SessionData(
val accessToken: String,
val refreshToken: String?,
val homeserverUrl: String,
val oidcData: String?,
val slidingSyncProxy: String?,
val loginTimestamp: Date?,
)

2
libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt

@ -27,6 +27,7 @@ internal fun SessionData.toDbModel(): DbSessionData { @@ -27,6 +27,7 @@ internal fun SessionData.toDbModel(): DbSessionData {
accessToken = accessToken,
refreshToken = refreshToken,
homeserverUrl = homeserverUrl,
oidcData = oidcData,
slidingSyncProxy = slidingSyncProxy,
loginTimestamp = loginTimestamp?.time,
)
@ -39,6 +40,7 @@ internal fun DbSessionData.toApiModel(): SessionData { @@ -39,6 +40,7 @@ internal fun DbSessionData.toApiModel(): SessionData {
accessToken = accessToken,
refreshToken = refreshToken,
homeserverUrl = homeserverUrl,
oidcData = oidcData,
slidingSyncProxy = slidingSyncProxy,
loginTimestamp = loginTimestamp?.let { Date(it) }
)

3
libraries/session-storage/impl/src/main/sqldelight/io/element/android/libraries/matrix/session/SessionData.sq

@ -5,7 +5,8 @@ CREATE TABLE SessionData ( @@ -5,7 +5,8 @@ CREATE TABLE SessionData (
refreshToken TEXT,
homeserverUrl TEXT NOT NULL,
slidingSyncProxy TEXT,
loginTimestamp INTEGER
loginTimestamp INTEGER,
oidcData TEXT
);

1
libraries/session-storage/impl/src/main/sqldelight/migrations/2.sqm

@ -0,0 +1 @@ @@ -0,0 +1 @@
ALTER TABLE SessionData ADD COLUMN oidcData TEXT;

1
libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt

@ -37,6 +37,7 @@ class DatabaseSessionStoreTests { @@ -37,6 +37,7 @@ class DatabaseSessionStoreTests {
homeserverUrl = "homeserverUrl",
slidingSyncProxy = null,
loginTimestamp = null,
oidcData = "aOidcData",
)
@Before

Loading…
Cancel
Save