Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AccessManager is based on PAM V3 token instead of PAM V2 authKey. #104

Merged
merged 5 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ internal class AccessManager(private val chat: Chat) {
internal enum class Permission { READ, WRITE, MANAGE, DELETE, GET, JOIN, UPDATE }

fun canI(permission: Permission, resourceType: ResourceType, resourceName: String): Boolean {
val authKey = chat.pubNub.configuration.authKey
if (authKey.isEmpty()) {
val token: String? = chat.pubNub.getToken()
if (token.isNullOrEmpty()) {
return true
}
val parsedToken = chat.pubNub.parseToken(authKey)
val parsedToken = chat.pubNub.parseToken(token)
return Companion.canI(resourceType, parsedToken, resourceName, permission)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.pubnub.integration

import com.pubnub.api.models.consumer.access_manager.v3.ChannelGrant
import com.pubnub.api.models.consumer.access_manager.v3.UUIDGrant
import com.pubnub.api.v2.callbacks.Result
import com.pubnub.chat.Channel
import com.pubnub.chat.Event
import com.pubnub.chat.internal.message.MessageImpl
import com.pubnub.chat.listenForEvents
import com.pubnub.chat.types.EventContent
import com.pubnub.test.await
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals

class AccessManagerTest : BaseChatIntegrationTest() {
@Test
fun pubNubClient_with_PAM_enabled_should_not_getChannel_when_no_token_set() = runTest {
val channelId = channelPam.id
var statusCode = 0
val expectedStatusCode = 403 // Forbidden, no valid security Token provided
chatPamClient.getChannel(channelId).async { result: Result<Channel?> ->
result.onFailure { e ->
statusCode = e.statusCode
}.onSuccess { channel: Channel? ->
throw IllegalStateException("Should not enter here. Should return exception.")
marcin-cebo marked this conversation as resolved.
Show resolved Hide resolved
}
}
delayInMillis(1000)
assertEquals(expectedStatusCode, statusCode)
}

@Test
fun pubNubClient_with_PAM_enabled_should_getChannel_when_token_set() = runTest {
// getToken from server
val channelId = channelPam.id
chatPamServer.createChannel(id = channelId).await()
val token = chatPamServer.pubNub.grantToken(
ttl = 1,
channels = listOf(ChannelGrant.name(get = true, name = channelId, read = true, write = true, manage = true)) // get = true
).await().token
// client uses token generated by server
chatPamClient.pubNub.setToken(token)

var actualChannelId: String? = ""
val token1 = chatPamClient.pubNub.getToken()
assertEquals(token1, token)
chatPamClient.getChannel(channelId).async { result: Result<Channel?> ->
result.onFailure {
throw IllegalStateException("Should not enter here. Should return channel.")
}.onSuccess { channel: Channel? ->
actualChannelId = channel?.id
}
}
delayInMillis(1000)
marcin-cebo marked this conversation as resolved.
Show resolved Hide resolved
assertEquals(channelId, actualChannelId)

chatPamServer.deleteChannel(id = channelId).await()
}

@Test
fun setLastReadMessageTimetoken_should_send_Receipt_event_when_has_token() = runTest {
var numberOfReceiptEvents = 0
val timetoken = 1000L
val channelId = channelPam.id

// server generates token
val token = chatPamServer.pubNub.grantToken(
ttl = 1,
authorizedUUID = chatPamClient.currentUser.id,
channels = listOf(
ChannelGrant.name(
name = channelId,
read = true,
write = true,
get = true,
join = true,
update = true,
manage = true,
delete = true,
create = true
)
),
uuids = listOf(UUIDGrant.id(id = chatPamClient.currentUser.id, get = true, update = true, delete = true))
).await().token

// client uses token retrieved from server
chatPamClient.pubNub.setToken(token)

chatPamClient.listenForEvents(channelId) { event: Event<EventContent.Receipt> ->
numberOfReceiptEvents++
}

val channel = chatPamClient.createChannel(channelId).await()
delayInMillis(1000)
val membership1 = channel.join().await().membership
membership1.setLastReadMessage(
MessageImpl(
chatPamClient,
timetoken,
EventContent.TextMessageContent("abc"),
channelId = channel.id,
userId = someUser.id
)
).await()
delayInMillis(1000)
assertEquals(2, numberOfReceiptEvents) // join and setLastReadMessage sets LastReadMessageTimetoken

chatPamServer.deleteChannel(channelId).await()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,26 @@ internal const val THREAD_CHANNEL_ID_PREFIX = "threadChannel_id_"
abstract class BaseChatIntegrationTest : BaseIntegrationTest() {
lateinit var chat: ChatImpl
lateinit var chat02: ChatImpl
lateinit var chatPam: ChatImpl
lateinit var chatPamServer: ChatImpl
lateinit var chatPamClient: ChatImpl
lateinit var channel01: Channel // this simulates first user in channel01
lateinit var channel01Chat02: Channel // this simulates second user in channel01
lateinit var channel02: Channel
lateinit var threadChannel: ThreadChannel
lateinit var channelPam: Channel
lateinit var someUser: User
lateinit var someUser02: User
lateinit var userPam: User
lateinit var userPamServer: User
lateinit var userPamClient: User
var cleanup: MutableList<suspend () -> Unit> = mutableListOf() // todo is this used?

@BeforeTest
override fun before() {
super.before()
chat = ChatImpl(ChatConfiguration(), pubnub)
chat02 = ChatImpl(ChatConfiguration(), pubnub02)
chatPam = ChatImpl(ChatConfiguration(), pubnubPam)
chatPamServer = ChatImpl(ChatConfiguration(), pubnubPamServer)
chatPamClient = ChatImpl(ChatConfiguration(), pubnubPamClient)
val channel01Id = randomString() + "!_=-@"
channel01 = ChannelImpl(
chat = chat,
Expand Down Expand Up @@ -96,7 +99,7 @@ abstract class BaseChatIntegrationTest : BaseIntegrationTest() {
type = ChannelType.DIRECT,
)
channelPam = ChannelImpl(
chat = chatPam,
chat = chatPamServer,
id = randomString() + "!_=-@",
name = randomString(),
custom = mapOf(randomString() to randomString()),
Expand All @@ -108,13 +111,15 @@ abstract class BaseChatIntegrationTest : BaseIntegrationTest() {
// user has chat and chat has user they should be the same?
someUser = chat.currentUser
someUser02 = chat02.currentUser
userPam = chatPam.currentUser
userPamServer = chatPamServer.currentUser
userPamClient = chatPamClient.currentUser
}

@AfterTest
fun afterTest() = runTest {
pubnub.removeUUIDMetadata(someUser.id).await()
pubnub.removeUUIDMetadata(userPam.id).await()
pubnubPamServer.removeUUIDMetadata(userPamServer.id).await()
pubnubPamServer.removeUUIDMetadata(userPamClient.id).await()
pubnub.removeChannelMetadata(channel01.id).await()
pubnub.removeChannelMetadata(channel01Chat02.id).await()
pubnub.removeChannelMetadata(channel02.id).await()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class ChannelIntegrationTest : BaseChatIntegrationTest() {
return@runTest
}
val userId = "userId"
val user = UserImpl(chat = chatPam, id = userId)
val user = UserImpl(chat = chatPamServer, id = userId)
val ban = true
val mute = true
val reason = "rude"
Expand All @@ -222,23 +222,23 @@ class ChannelIntegrationTest : BaseChatIntegrationTest() {
var mute = true
val reason = "rude"

channelPam.setRestrictions(user = userPam, mute = mute, reason = reason).await()
var restriction = channelPam.getUserRestrictions(userPam).await()
channelPam.setRestrictions(user = userPamServer, mute = mute, reason = reason).await()
var restriction = channelPam.getUserRestrictions(userPamServer).await()
assertEquals(mute, restriction.mute)

mute = false
channelPam.setRestrictions(user = userPam, mute = mute, reason = reason).await()
restriction = channelPam.getUserRestrictions(userPam).await()
channelPam.setRestrictions(user = userPamServer, mute = mute, reason = reason).await()
restriction = channelPam.getUserRestrictions(userPamServer).await()
assertEquals(mute, restriction.mute)
assertFalse(restriction.ban)
assertNull(restriction.reason)
}

@Test
fun canGetRestrictionForUserThatDoesNotHaveRestrictionSet() = runTest {
val restriction = channel01.getUserRestrictions(userPam).await()
val restriction = channel01.getUserRestrictions(userPamServer).await()
assertEquals(channel01.id, restriction.channelId)
assertEquals(userPam.id, restriction.userId)
assertEquals(userPamServer.id, restriction.userId)
assertFalse(restriction.mute)
assertFalse(restriction.ban)
assertNull(restriction.reason)
Expand All @@ -261,14 +261,14 @@ class ChannelIntegrationTest : BaseChatIntegrationTest() {
val channelId = channelPam.id

channelPam.setRestrictions(
user = UserImpl(chat = chatPam, id = userId01),
user = UserImpl(chat = chatPamServer, id = userId01),
ban = ban,
mute = mute,
reason = reason
)
.await()
channelPam.setRestrictions(
user = UserImpl(chat = chatPam, id = userId02),
user = UserImpl(chat = chatPamServer, id = userId02),
ban = ban,
mute = mute,
reason = reason
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class MembershipIntegrationTest : BaseChatIntegrationTest() {
@Test
fun setLastReadMessage() = runTest {
val timetoken = 1000L
chat.createChannel(
val channel = chat.createChannel(
channel01.id,
channel01.name,
channel01.description,
Expand All @@ -108,14 +108,14 @@ class MembershipIntegrationTest : BaseChatIntegrationTest() {
channel01.status
).await()
delayInMillis(1000)
val membership1 = channel01.join().await().membership
val membership1 = channel.join().await().membership

val membershipUpdated = membership1.setLastReadMessage(
MessageImpl(
chat,
timetoken,
EventContent.TextMessageContent("abc"),
channelId = channel01.id,
channelId = channel.id,
userId = someUser.id
)
).await()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ class UserIntegrationTest : BaseChatIntegrationTest() {
return@runTest
}
val channelId = "channelId01"
val channel = ChannelImpl(chat = chatPam, id = channelId)
val channel = ChannelImpl(chat = chatPamServer, id = channelId)
val ban = true
val mute = true
val reason = "rude"

userPam.setRestrictions(channel = channel, ban = ban, mute = mute, reason = reason).await()
userPamServer.setRestrictions(channel = channel, ban = ban, mute = mute, reason = reason).await()

val restriction: Restriction = userPam.getChannelRestrictions(channel).await()
assertEquals(userPam.id, restriction.userId)
val restriction: Restriction = userPamServer.getChannelRestrictions(channel).await()
assertEquals(userPamServer.id, restriction.userId)
assertEquals(channelId, restriction.channelId)
assertEquals(ban, restriction.ban)
assertEquals(mute, restriction.mute)
Expand All @@ -59,20 +59,20 @@ class UserIntegrationTest : BaseChatIntegrationTest() {
val page = null
val sort: Collection<PNSortKey<PNMembershipKey>> = listOf(PNSortKey.PNAsc(PNMembershipKey.CHANNEL_ID))

userPam.setRestrictions(
channel = ChannelImpl(chat = chatPam, id = channelId01),
userPamServer.setRestrictions(
channel = ChannelImpl(chat = chatPamServer, id = channelId01),
ban = ban,
mute = mute,
reason = reason
).await()
userPam.setRestrictions(
channel = ChannelImpl(chat = chatPam, id = channelId02),
userPamServer.setRestrictions(
channel = ChannelImpl(chat = chatPamServer, id = channelId02),
ban = ban,
mute = mute,
reason = reason
).await()

val getRestrictionsResponse = userPam.getChannelsRestrictions(limit = limit, page = page, sort = sort).await()
val getRestrictionsResponse = userPamServer.getChannelsRestrictions(limit = limit, page = page, sort = sort).await()

assertEquals(limit, getRestrictionsResponse.total)
assertEquals(200, getRestrictionsResponse.status)
Expand Down Expand Up @@ -103,21 +103,21 @@ class UserIntegrationTest : BaseChatIntegrationTest() {
val page = null
val sort: Collection<PNSortKey<PNMembershipKey>> = listOf(PNSortKey.PNDesc(PNMembershipKey.CHANNEL_ID))

userPam.setRestrictions(
channel = ChannelImpl(chat = chatPam, id = channelId01),
userPamServer.setRestrictions(
channel = ChannelImpl(chat = chatPamServer, id = channelId01),
ban = ban,
mute = mute,
reason = reason
).await()
userPam.setRestrictions(
channel = ChannelImpl(chat = chatPam, id = channelId02),
userPamServer.setRestrictions(
channel = ChannelImpl(chat = chatPamServer, id = channelId02),
ban = ban,
mute = mute,
reason = reason
).await()

val getRestrictionsResponse: GetRestrictionsResponse =
userPam.getChannelsRestrictions(limit = limit, page = page, sort = sort).await()
userPamServer.getChannelsRestrictions(limit = limit, page = page, sort = sort).await()

val firstRestriction = getRestrictionsResponse.restrictions.first()
assertEquals(channelId02, firstRestriction.channelId)
Expand Down Expand Up @@ -216,13 +216,13 @@ class UserIntegrationTest : BaseChatIntegrationTest() {
val mute = true
val ban = true
val reason = "rude"
userPam.setRestrictions(channel = channelPam, mute = true, ban = true, reason = reason).await()
val restrictions = userPam.getChannelRestrictions(channel = channelPam).await()
userPamServer.setRestrictions(channel = channelPam, mute = true, ban = true, reason = reason).await()
val restrictions = userPamServer.getChannelRestrictions(channel = channelPam).await()
assertEquals(mute, restrictions.mute)
assertEquals(ban, restrictions.ban)
assertEquals(reason, restrictions.reason)

val membershipsResponse: MembershipsResponse = userPam.getMemberships().await()
val membershipsResponse: MembershipsResponse = userPamServer.getMemberships().await()
val internalModerationChannelCount = membershipsResponse.memberships.filter { membership ->
membership.channel.id.contains(INTERNAL_MODERATION_PREFIX)
}.size
Expand Down
2 changes: 1 addition & 1 deletion pubnub-kotlin
Submodule pubnub-kotlin updated 24 files
+1 −1 build-logic/gradle-plugins/src/main/kotlin/com/pubnub/gradle/PubNubKotlinMultiplatformPlugin.kt
+17 −1,430 kotlin-js-store/yarn.lock
+3 −0 pubnub-gson/pubnub-gson-api/src/main/java/com/pubnub/api/java/PubNub.kt
+17 −2 pubnub-gson/pubnub-gson-api/src/main/java/com/pubnub/api/java/v2/PNConfiguration.kt
+2 −2 pubnub-kotlin/pubnub-kotlin-api/config/ktlint/baseline.xml
+1 −1 pubnub-kotlin/pubnub-kotlin-api/pubnub_kotlin_api.podspec
+2 −0 pubnub-kotlin/pubnub-kotlin-api/src/commonMain/kotlin/com/pubnub/api/PubNub.kt
+1 −1 ...in/pubnub-kotlin-api/src/commonMain/kotlin/com/pubnub/api/models/consumer/access_manager/v3/ChannelGrant.kt
+5 −0 pubnub-kotlin/pubnub-kotlin-api/src/iosMain/kotlin/com/pubnub/api/PubNubImpl.kt
+5 −0 pubnub-kotlin/pubnub-kotlin-api/src/jsMain/kotlin/com/pubnub/api/PubNubImpl.kt
+2 −0 pubnub-kotlin/pubnub-kotlin-api/src/jvmMain/kotlin/com/pubnub/api/PubNub.kt
+2 −0 pubnub-kotlin/pubnub-kotlin-api/src/nonJvm/kotlin/com/pubnub/api/PubNub.nonJvm.kt
+1 −1 pubnub-kotlin/pubnub-kotlin-core-api/pubnub_kotlin_core_api.podspec
+24 −1 pubnub-kotlin/pubnub-kotlin-core-api/src/commonMain/kotlin/com/pubnub/api/v2/PNConfiguration.kt
+38 −1 pubnub-kotlin/pubnub-kotlin-core-api/src/iosMain/kotlin/com/pubnub/api/v2/PNConfiguration.ios.kt
+43 −1 pubnub-kotlin/pubnub-kotlin-core-api/src/jsMain/kotlin/com/pubnub/api/v2/PNConfiguration.js.kt
+27 −0 pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/v2/PNConfiguration.jvm.kt
+18 −3 pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/v2/PNConfiguration.kt
+7 −0 pubnub-kotlin/pubnub-kotlin-impl/config/ktlint/baseline.xml
+0 −1 ...-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PublishIntegrationTests.kt
+4 −0 pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/PubNubImpl.kt
+9 −0 pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/v2/PNConfigurationImpl.kt
+10 −7 pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/workers/SubscribeMessageProcessor.kt
+17 −6 pubnub-kotlin/pubnub-kotlin-test/src/commonMain/kotlin/com.pubnub.test/BaseIntegrationTest.kt
Loading