Skip to content

Commit 80bcec4

Browse files
authored
[RKOTLIN-1091] Decouple authentication errors from server error messages (#1762)
1 parent cd6cc63 commit 80bcec4

File tree

8 files changed

+27
-70
lines changed

8 files changed

+27
-70
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This release will bump the Realm file format 24. Opening a file with an older fo
88
* Removed `LogConfiguration`. Log levels and custom loggers can be set with `RealmLog`. (Issue [#1691](https://github.com/realm/realm-kotlin/issues/1691) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1038))
99
* Removed deprecated `io.realm.kotlin.types.ObjectId`. Use `org.mongodb.kbson.BsonObjectId` or its type alias `org.mongodb.kbson.ObjectId` instead. (Issue [#1749](https://github.com/realm/realm-kotlin/issues/1749) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1082))
1010
* Removed deprecated `RealmClass.isEmbedded`. Class embeddeness can be check with `RealmClassKind.EMBEDDED`. (Issue [#1753](https://github.com/realm/realm-kotlin/issues/1753) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1080))
11+
* Some authentication related operations will no longer throw specialized `InvalidCredentialsException` and `CredentialsCannotBeLinkedException` but the more general `AuthException` and `ServiceException`. (Issue [#1763](https://github.com/realm/realm-kotlin/issues/1763)/[RKOTLIN-1091](https://jira.mongodb.org/browse/RKOTLIN-1091))
1112
* [Sync] Removed deprecated methods `User.identity` and `User.provider`, user identities can be accessed with the already existing `User.identities`. (Issue [#1751](https://github.com/realm/realm-kotlin/issues/1751) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1083))
1213
* [Sync] `App.allUsers` does no longer return a map, but only a list of users known locally. (Issue [#1751](https://github.com/realm/realm-kotlin/issues/1751) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1083))
1314
* [Sync ]Removed deprecated `DiscardUnsyncedChangesStrategy.onError`. (Issue [#1755](https://github.com/realm/realm-kotlin/issues/1755) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1085))

packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/App.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import io.realm.kotlin.mongodb.annotations.ExperimentalEdgeServerApi
2121
import io.realm.kotlin.mongodb.auth.EmailPasswordAuth
2222
import io.realm.kotlin.mongodb.exceptions.AppException
2323
import io.realm.kotlin.mongodb.exceptions.AuthException
24-
import io.realm.kotlin.mongodb.exceptions.InvalidCredentialsException
2524
import io.realm.kotlin.mongodb.internal.AppConfigurationImpl
2625
import io.realm.kotlin.mongodb.internal.AppImpl
2726
import io.realm.kotlin.mongodb.sync.Sync
@@ -115,10 +114,6 @@ public interface App {
115114
*
116115
* @param credentials the credentials representing the type of login.
117116
* @return the logged in [User].
118-
* @throws InvalidCredentialsException if the provided credentials were not correct. Note, only
119-
* [AuthenticationProvider.EMAIL_PASSWORD], [AuthenticationProvider.API_KEY] and
120-
* [AuthenticationProvider.JWT] can throw this exception. Other authentication providers throw
121-
* an [AuthException] instead.
122117
* @throws AuthException if a problem occurred when logging in. See the exception message for
123118
* further details.
124119
* @throws io.realm.kotlin.mongodb.exceptions.ServiceException for other failures that can happen when

packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/exceptions/ServiceExceptions.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ public class BadRequestException internal constructor(message: String) : Service
6666
* This exception is considered the top-level or "catch-all" for problems related to user account
6767
* actions. The exact reason for the error can be found in [Throwable.message].
6868
*
69-
* Generally, this exception does not need to be caught as more specific subtypes are available.
70-
* These will be documented for the relevant API methods.
69+
* For some error scenarios there are more specific and descriptive subtypes available.
70+
* These are documented for the relevant API methods where they can be thrown.
7171
*
7272
* @see UserAlreadyConfirmedException
7373
* @see UserNotFoundException

packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/RealmSyncUtils.kt

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -172,39 +172,14 @@ internal fun convertAppError(appError: AppError): Throwable {
172172
// generic `ServiceException`'s.
173173
when (appError.code) {
174174
ErrorCode.RLM_ERR_INTERNAL_SERVER_ERROR -> {
175-
if (msg.contains("linking an anonymous identity is not allowed") || // Trying to link an anonymous account to a named one.
176-
msg.contains("linking a local-userpass identity is not allowed") // Trying to link two email logins with each other
177-
) {
178-
CredentialsCannotBeLinkedException(msg)
179-
} else {
180-
ServiceException(msg)
181-
}
175+
ServiceException(msg)
182176
}
183177
ErrorCode.RLM_ERR_INVALID_SESSION -> {
184-
if (msg.contains("a user already exists with the specified provider")) {
185-
CredentialsCannotBeLinkedException(msg)
186-
} else {
187-
ServiceException(msg)
188-
}
178+
ServiceException(msg)
189179
}
190180
ErrorCode.RLM_ERR_USER_DISABLED,
191181
ErrorCode.RLM_ERR_AUTH_ERROR -> {
192-
// Some auth providers return a generic AuthError when
193-
// invalid credentials are presented. We make a best effort
194-
// to map these to a more sensible `InvalidCredentialsExceptions`
195-
if (msg.contains("invalid API key")) {
196-
// API Key
197-
// See https://github.com/10gen/baas/blob/master/authprovider/providers/apikey/provider.go
198-
InvalidCredentialsException(msg)
199-
} else if (msg.contains("invalid custom auth token:")) {
200-
// Custom JWT
201-
// See https://github.com/10gen/baas/blob/master/authprovider/providers/custom/provider.go
202-
InvalidCredentialsException(msg)
203-
} else {
204-
// It does not look possible to reliably detect Facebook, Google and Apple
205-
// invalid tokens: https://github.com/10gen/baas/blob/master/authprovider/providers/oauth2/oauth.go#L139
206-
AuthException(msg)
207-
}
182+
AuthException(msg)
208183
}
209184
ErrorCode.RLM_ERR_USER_NOT_FOUND -> {
210185
UserNotFoundException(msg)

packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/UserImpl.kt

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ import io.realm.kotlin.mongodb.Functions
2525
import io.realm.kotlin.mongodb.User
2626
import io.realm.kotlin.mongodb.UserIdentity
2727
import io.realm.kotlin.mongodb.auth.ApiKeyAuth
28-
import io.realm.kotlin.mongodb.exceptions.CredentialsCannotBeLinkedException
29-
import io.realm.kotlin.mongodb.exceptions.ServiceException
3028
import io.realm.kotlin.mongodb.mongo.MongoClient
3129
import kotlinx.coroutines.channels.Channel
3230
import org.mongodb.kbson.ExperimentalKBsonSerializerApi
@@ -153,29 +151,17 @@ public class UserImpl(
153151
if (state != User.State.LOGGED_IN) {
154152
throw IllegalStateException("User must be logged in, in order to link credentials to it.")
155153
}
156-
try {
157-
Channel<Result<User>>(1).use { channel ->
158-
RealmInterop.realm_app_link_credentials(
159-
app.nativePointer,
160-
nativePointer,
161-
(credentials as CredentialsImpl).nativePointer,
162-
channelResultCallback<RealmUserPointer, User>(channel) { userPointer ->
163-
UserImpl(userPointer, app)
164-
}
165-
)
166-
channel.receive().getOrThrow()
167-
return this
168-
}
169-
} catch (ex: ServiceException) {
170-
// Linking an account with itself throws a different error code than other linking errors:
171-
// It is unclear if this error is shared between other error scenarios, so for now,
172-
// we remap the exception type here instead of in the generic handler in
173-
// `RealmSyncUtils.kt`.
174-
if (ex.message?.contains("[Service][InvalidSession(2)] a user already exists with the specified provider.") == true) {
175-
throw CredentialsCannotBeLinkedException(ex.message!!)
176-
} else {
177-
throw ex
178-
}
154+
Channel<Result<User>>(1).use { channel ->
155+
RealmInterop.realm_app_link_credentials(
156+
app.nativePointer,
157+
nativePointer,
158+
(credentials as CredentialsImpl).nativePointer,
159+
channelResultCallback<RealmUserPointer, User>(channel) { userPointer ->
160+
UserImpl(userPointer, app)
161+
}
162+
)
163+
channel.receive().getOrThrow()
164+
return this
179165
}
180166
}
181167

packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/AppTests.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import io.realm.kotlin.mongodb.LoggedOut
3333
import io.realm.kotlin.mongodb.Removed
3434
import io.realm.kotlin.mongodb.User
3535
import io.realm.kotlin.mongodb.annotations.ExperimentalEdgeServerApi
36-
import io.realm.kotlin.mongodb.exceptions.InvalidCredentialsException
36+
import io.realm.kotlin.mongodb.exceptions.AuthException
3737
import io.realm.kotlin.mongodb.exceptions.ServiceException
3838
import io.realm.kotlin.mongodb.sync.SyncConfiguration
3939
import io.realm.kotlin.test.mongodb.SyncServerConfig
@@ -144,7 +144,7 @@ class AppTests {
144144
null
145145
}
146146
}?.let { credentials: Credentials ->
147-
assertFailsWith<InvalidCredentialsException> {
147+
assertFailsWith<AuthException> {
148148
app.login(credentials)
149149
}
150150
}

packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/CredentialsTests.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ class CredentialsTests {
369369
payload = mapOf("mail" to TestHelper.randomEmail(), "id" to 0)
370370
)
371371

372-
assertFailsWithMessage<AuthException>("Error: Authentication failed.") {
372+
assertFailsWithMessage<AuthException>("unauthorized") {
373373
runBlocking {
374374
app.login(credentials)
375375
}
@@ -383,7 +383,7 @@ class CredentialsTests {
383383
}
384384
fail()
385385
} catch (error: AppException) {
386-
assertTrue(error.message!!.contains("authentication via"), error.message)
386+
assertTrue(error.message!!.contains("unauthorized"), error.message)
387387
}
388388
}
389389
}

packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/UserTests.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -459,11 +459,11 @@ class UserTests {
459459
app.emailPasswordAuth.registerUser(otherEmail, otherPassword)
460460
val credentials = Credentials.emailPassword(otherEmail, otherPassword)
461461

462-
assertFailsWith<CredentialsCannotBeLinkedException> {
462+
assertFailsWith<ServiceException> {
463463
anonUser.linkCredentials(credentials)
464464
}.let {
465465
assertTrue(
466-
it.message!!.contains("linking a local-userpass identity is not allowed when one is already linked"),
466+
it.message!!.contains("unauthorized"),
467467
it.message
468468
)
469469
}
@@ -478,11 +478,11 @@ class UserTests {
478478
val (email2, password2) = randomEmail() to "123456"
479479
app.emailPasswordAuth.registerUser(email2, password2)
480480
val credentials2 = Credentials.emailPassword(email2, password2)
481-
assertFailsWith<CredentialsCannotBeLinkedException> {
481+
assertFailsWith<ServiceException> {
482482
emailUser1.linkCredentials(credentials2)
483483
}.let {
484484
assertTrue(
485-
it.message!!.contains("linking a local-userpass identity is not allowed when one is already linked"),
485+
it.message!!.contains("unauthorized"),
486486
it.message
487487
)
488488
}
@@ -512,11 +512,11 @@ class UserTests {
512512
app.emailPasswordAuth.registerUser(email, password)
513513
val creds = Credentials.emailPassword(email, password)
514514
app.login(creds)
515-
assertFailsWith<CredentialsCannotBeLinkedException> {
515+
assertFailsWith<ServiceException> {
516516
anonUser.linkCredentials(creds)
517517
}.let {
518518
assertTrue(
519-
it.message!!.contains("a user already exists with the specified provider"),
519+
it.message!!.contains("unauthorized"),
520520
it.message
521521
)
522522
}

0 commit comments

Comments
 (0)