diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt index 1982b8b503842cbce8db6c2d8ed4d2befd41bc07..455bdff772511e233b603a562bd2ae7674aa0d6f 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt @@ -85,7 +85,7 @@ class AuthManager @Inject constructor( sealed class MailboxPrincipal : Principal { object OwnerPrincipal : MailboxPrincipal() - class ContactPrincipal(val contact: Contact) : MailboxPrincipal() + data class ContactPrincipal(val contact: Contact) : MailboxPrincipal() } class AuthException : IllegalStateException() diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt index 2a9abd05bca1b569c945e5ae0cc888f6bef197ec..a21277876b3f7b760a9ec9bac1397a11bd6fad11 100644 --- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt +++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt @@ -4,6 +4,7 @@ import dagger.Component import org.briarproject.mailbox.core.db.Database import org.briarproject.mailbox.core.lifecycle.LifecycleManager import org.briarproject.mailbox.core.settings.SettingsManager +import org.briarproject.mailbox.core.system.RandomIdManager import javax.inject.Singleton @Singleton @@ -17,4 +18,5 @@ interface TestComponent { fun getLifecycleManager(): LifecycleManager fun getSettingsManager(): SettingsManager fun getDatabase(): Database + fun getRandomIdManager(): RandomIdManager } diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/AuthManagerTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/AuthManagerTest.kt index 546e5ce16d0328a75371b8ad252e02d1dc543c55..1a3d6f5b0992b952674f1771900e817c070f5935 100644 --- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/AuthManagerTest.kt +++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/AuthManagerTest.kt @@ -1,5 +1,173 @@ package org.briarproject.mailbox.core.server +import io.mockk.every +import io.mockk.mockk +import org.briarproject.mailbox.core.TestUtils.everyTransactionWithResult +import org.briarproject.mailbox.core.TestUtils.getNewRandomContact +import org.briarproject.mailbox.core.TestUtils.getNewRandomId +import org.briarproject.mailbox.core.db.Database +import org.briarproject.mailbox.core.server.MailboxPrincipal.OwnerPrincipal +import org.briarproject.mailbox.core.settings.Settings +import org.briarproject.mailbox.core.settings.SettingsManager +import org.briarproject.mailbox.core.system.InvalidIdException +import org.briarproject.mailbox.core.system.RandomIdManager +import org.briarproject.mailbox.core.system.toHex +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import kotlin.random.Random +import kotlin.test.assertEquals +import kotlin.test.assertNull + class AuthManagerTest { - // TODO write unit tests + + private val db: Database = mockk() + private val settingsManager: SettingsManager = mockk() + private val randomIdManager = RandomIdManager() + + private val authManager = AuthManager(db, settingsManager, randomIdManager) + + private val id = getNewRandomId() + private val otherId = getNewRandomId() + private val invalidId = Random.nextBytes(Random.nextInt(0, 32)).toHex() + private val contact = getNewRandomContact() + private val contactPrincipal = MailboxPrincipal.ContactPrincipal(contact) + + @Test + fun `rejects invalid token for getPrincipal()`() { + assertThrows<InvalidIdException> { + authManager.getPrincipal(invalidId) + } + } + + @Test + fun `getPrincipal() returns authenticated contact`() { + everyTransactionWithResult(db, true) { txn -> + every { db.getContactWithToken(txn, id) } returns contactPrincipal.contact + } + assertEquals(contactPrincipal, authManager.getPrincipal(id)) + } + + @Test + fun `getPrincipal() returns authenticated owner`() { + val settings = Settings().apply { + put(SETTINGS_OWNER_TOKEN, id) + } + + everyTransactionWithResult(db, true) { txn -> + every { db.getContactWithToken(txn, id) } returns null + every { settingsManager.getSettings(txn, SETTINGS_NAMESPACE_OWNER) } returns settings + } + + assertEquals(OwnerPrincipal, authManager.getPrincipal(id)) + } + + @Test + fun `getPrincipal() returns null when unauthenticated`() { + val settings = Settings().apply { + put(SETTINGS_OWNER_TOKEN, otherId) + } + + everyTransactionWithResult(db, true) { txn -> + every { db.getContactWithToken(txn, id) } returns null + every { settingsManager.getSettings(txn, SETTINGS_NAMESPACE_OWNER) } returns settings + } + + assertNull(authManager.getPrincipal(id)) + } + + @Test + fun `assertCanDownloadFromFolder() throws for null MailboxPrincipal`() { + assertThrows<AuthException> { + authManager.assertCanDownloadFromFolder(null, id) + } + } + + @Test + fun `assertCanDownloadFromFolder() throws if owner wants non-existent folder`() { + everyTransactionWithResult(db, true) { txn -> + every { db.getContacts(txn) } returns emptyList() + } + + assertThrows<AuthException> { + authManager.assertCanDownloadFromFolder(OwnerPrincipal, id) + } + } + + @Test + fun `throws if contact wants to download from folder that is not their inbox`() { + assertThrows<AuthException> { + authManager.assertCanDownloadFromFolder(contactPrincipal, id) + } + assertThrows<AuthException> { + authManager.assertCanDownloadFromFolder(contactPrincipal, contact.outboxId) + } + } + + @Test + fun `assertCanDownloadFromFolder() lets owner access contact's outbox folder`() { + everyTransactionWithResult(db, true) { txn -> + every { db.getContacts(txn) } returns listOf(contact, getNewRandomContact()) + } + + authManager.assertCanDownloadFromFolder(OwnerPrincipal, contact.outboxId) + } + + @Test + fun `assertCanDownloadFromFolder() lets contact access their inbox folder`() { + authManager.assertCanDownloadFromFolder(contactPrincipal, contact.inboxId) + } + + @Test + fun `assertCanPostToFolder() throws for null MailboxPrincipal`() { + assertThrows<AuthException> { + authManager.assertCanPostToFolder(null, id) + } + } + + @Test + fun `assertCanPostToFolder() throws if owner wants non-existent folder`() { + everyTransactionWithResult(db, true) { txn -> + every { db.getContacts(txn) } returns emptyList() + } + + assertThrows<AuthException> { + authManager.assertCanPostToFolder(OwnerPrincipal, id) + } + } + + @Test + fun `throws if contact wants to post to folder that is not their outbox`() { + assertThrows<AuthException> { + authManager.assertCanPostToFolder(contactPrincipal, id) + } + assertThrows<AuthException> { + authManager.assertCanPostToFolder(contactPrincipal, contact.inboxId) + } + } + + @Test + fun `assertCanPostToFolder() lets owner access contact's inbox folder`() { + everyTransactionWithResult(db, true) { txn -> + every { db.getContacts(txn) } returns listOf(contact, getNewRandomContact()) + } + + authManager.assertCanPostToFolder(OwnerPrincipal, contact.inboxId) + } + + @Test + fun `assertCanPostToFolder() lets contact access their outbox folder`() { + authManager.assertCanPostToFolder(contactPrincipal, contact.outboxId) + } + + @Test + fun `assertIsOwner() throws for non-owners`() { + assertThrows<AuthException> { authManager.assertIsOwner(null) } + assertThrows<AuthException> { authManager.assertIsOwner(contactPrincipal) } + } + + @Test + fun `assertIsOwner() passes for owner`() { + authManager.assertIsOwner(OwnerPrincipal) + } + }