Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
189 changes: 185 additions & 4 deletions src/test/kotlin/org/prebid/cache/functional/AuthenticationCacheSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.kotest.assertions.throwables.shouldThrowExactly
import io.kotest.core.spec.style.ShouldSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.beEmpty
import io.kotest.matchers.string.shouldContain
import io.ktor.client.statement.bodyAsText
import io.ktor.http.contentType
import org.prebid.cache.functional.BaseSpec.Companion.prebidCacheConfig
Expand All @@ -13,6 +14,7 @@ import org.prebid.cache.functional.model.request.RequestObject
import org.prebid.cache.functional.model.request.TransferValue
import org.prebid.cache.functional.service.ApiException
import org.prebid.cache.functional.util.getRandomString
import org.prebid.cache.functional.util.getRandomUuid
import org.springframework.http.HttpStatus.UNAUTHORIZED

class AuthenticationCacheSpec : ShouldSpec({
Expand Down Expand Up @@ -102,7 +104,7 @@ class AuthenticationCacheSpec : ShouldSpec({
// when: POST cache endpoint is called
val exception = shouldThrowExactly<ApiException> { prebidCacheApi.postCache(requestObject, apiKey = null) }

// then: Bad Request exception is thrown
// then: Unauthorized exception is thrown
assertSoftly {
exception.statusCode shouldBe UNAUTHORIZED.value()
exception.responseBody should beEmpty()
Expand All @@ -126,7 +128,7 @@ class AuthenticationCacheSpec : ShouldSpec({
val exception =
shouldThrowExactly<ApiException> { prebidCacheApi.postCache(requestObject, apiKey = "") }

// then: Bad Request exception is thrown
// then: Unauthorized exception is thrown
assertSoftly {
exception.statusCode shouldBe UNAUTHORIZED.value()
exception.responseBody should beEmpty()
Expand All @@ -150,7 +152,7 @@ class AuthenticationCacheSpec : ShouldSpec({
val exception =
shouldThrowExactly<ApiException> { prebidCacheApi.postCache(requestObject, apiKey = getRandomString()) }

// then: Bad Request exception is thrown
// then: Unauthorized exception is thrown
assertSoftly {
exception.statusCode shouldBe UNAUTHORIZED.value()
exception.responseBody should beEmpty()
Expand All @@ -175,10 +177,189 @@ class AuthenticationCacheSpec : ShouldSpec({
val exception =
shouldThrowExactly<ApiException> { prebidCacheApi.postCache(requestObject, apiKey = prebidApiKey.uppercase()) }

// then: Bad Request exception is thrown
// then: Unauthorized exception is thrown
assertSoftly {
exception.statusCode shouldBe UNAUTHORIZED.value()
exception.responseBody should beEmpty()
}
}

should("should save JSON transfer value with proper api-key in header when cache-write-secured and external-uuid-secured are enabled") {
// given: Prebid Cache with external-uuid-secured=true property
val prebidApiKey = getRandomString()
val prebidCacheApi = BaseSpec.getPrebidCacheApi(
prebidCacheConfig.getBaseRedisConfig(
allowExternalUuid = true,
cacheWriteSecured = true,
externalUuidSecured = true,
apiKey = prebidApiKey
)
)

// and: Request object with JSON transfer value
val requestObject = RequestObject.getDefaultJsonRequestObject()
val requestTransferValue = objectMapper.readValue(requestObject.puts[0].value, TransferValue::class.java)

// when: POST cache endpoint is called
val postResponse = prebidCacheApi.postCache(requestObject, apiKey = prebidApiKey)

// when: GET cache endpoint is called
val getCacheResponse = BaseSpec.getPrebidCacheApi().getCache(postResponse.responses[0].uuid)

// then: response content type is the same as request object type
getCacheResponse.contentType()?.contentType shouldBe "application"
getCacheResponse.contentType()?.contentSubtype shouldBe requestObject.puts[0].type.getValue()

// and: transfer value is returned
val responseTransferValue = objectMapper.readValue(getCacheResponse.bodyAsText(), TransferValue::class.java)

assertSoftly {
responseTransferValue.adm shouldBe requestTransferValue.adm
responseTransferValue.width shouldBe requestTransferValue.width
responseTransferValue.height shouldBe requestTransferValue.height
}
}

should("should save JSON transfer value with proper api-key in header when cache-write-secured disabled and external-uuid-secured enabled") {
// given: Prebid Cache with external-uuid-secured=true property
val prebidApiKey = getRandomString()
val prebidCacheApi = BaseSpec.getPrebidCacheApi(
prebidCacheConfig.getBaseRedisConfig(
allowExternalUuid = true,
cacheWriteSecured = false,
externalUuidSecured = true,
apiKey = prebidApiKey
)
)

// and: Request object with JSON transfer value
val requestObject = RequestObject.getDefaultJsonRequestObject()
val requestTransferValue = objectMapper.readValue(requestObject.puts[0].value, TransferValue::class.java)

// when: POST cache endpoint is called
val postResponse = prebidCacheApi.postCache(requestObject, apiKey = prebidApiKey)

// when: GET cache endpoint is called
val getCacheResponse = BaseSpec.getPrebidCacheApi().getCache(postResponse.responses[0].uuid)

// then: response content type is the same as request object type
getCacheResponse.contentType()?.contentType shouldBe "application"
getCacheResponse.contentType()?.contentSubtype shouldBe requestObject.puts[0].type.getValue()

// and: transfer value is returned
val responseTransferValue = objectMapper.readValue(getCacheResponse.bodyAsText(), TransferValue::class.java)

assertSoftly {
responseTransferValue.adm shouldBe requestTransferValue.adm
responseTransferValue.width shouldBe requestTransferValue.width
responseTransferValue.height shouldBe requestTransferValue.height
}
}

should("should save JSON transfer value with proper api-key in header when cache-write-secured and external-uuid-secured are disabled") {
// given: Prebid Cache with external-uuid-secured=false property
val prebidCacheApi = BaseSpec.getPrebidCacheApi(
prebidCacheConfig.getBaseRedisConfig(
allowExternalUuid = true,
cacheWriteSecured = false,
externalUuidSecured = false,
apiKey = getRandomString()
)
)

// and: Request object with JSON transfer value
val requestObject = RequestObject.getDefaultJsonRequestObject()
val requestTransferValue = objectMapper.readValue(requestObject.puts[0].value, TransferValue::class.java)

// when: POST cache endpoint is called
val postResponse = prebidCacheApi.postCache(requestObject)

// when: GET cache endpoint is called
val getCacheResponse = BaseSpec.getPrebidCacheApi().getCache(postResponse.responses[0].uuid)

// then: response content type is the same as request object type
getCacheResponse.contentType()?.contentType shouldBe "application"
getCacheResponse.contentType()?.contentSubtype shouldBe requestObject.puts[0].type.getValue()

// and: transfer value is returned
val responseTransferValue = objectMapper.readValue(getCacheResponse.bodyAsText(), TransferValue::class.java)

assertSoftly {
responseTransferValue.adm shouldBe requestTransferValue.adm
responseTransferValue.width shouldBe requestTransferValue.width
responseTransferValue.height shouldBe requestTransferValue.height
}
}

should("throw an exception when api key is missing for request cache_write_secured=true and external_uuid_Secured=true") {
// given: Prebid Cache with external-uuid-secured=true property
val prebidCacheApi = BaseSpec.getPrebidCacheApi(
prebidCacheConfig.getBaseRedisConfig(
allowExternalUuid = true,
cacheWriteSecured = true,
externalUuidSecured = true,
apiKey = getRandomString()
)
)

// and: Request object with set payload transfer key
val requestObject = RequestObject.getDefaultJsonRequestObject().apply { puts[0].key = getRandomUuid() }

// when: POST cache endpoint is called
val exception = shouldThrowExactly<ApiException> { prebidCacheApi.postCache(requestObject) }

// then: Unauthorized exception is thrown
assertSoftly {
exception.statusCode shouldBe UNAUTHORIZED.value()
exception.responseBody should beEmpty()
}
}

should("throw an exception when api key is missing for request and external_uuid_Secured=true") {
// given: Prebid Cache with external-uuid-secured=true property
val prebidCacheApi = BaseSpec.getPrebidCacheApi(
prebidCacheConfig.getBaseRedisConfig(
allowExternalUuid = true,
cacheWriteSecured = false,
externalUuidSecured = true,
apiKey = getRandomString()
)
)

// and: Request object with set payload transfer key
val requestObject = RequestObject.getDefaultJsonRequestObject().apply { puts[0].key = getRandomUuid() }

// when: POST cache endpoint is called
val exception = shouldThrowExactly<ApiException> { prebidCacheApi.postCache(requestObject) }

// then: Unauthorized exception is thrown
assertSoftly {
exception.statusCode shouldBe UNAUTHORIZED.value()
exception.responseBody shouldContain "\"message\":\"Prebid cache host forbids specifying UUID in request by unauthorized users.\""
}
}

should("throw an exception when api key is mismatched for request and external-uuid-secured=true") {
// given: Prebid Cache with external-uuid-secured=true property
val prebidCacheApi = BaseSpec.getPrebidCacheApi(
prebidCacheConfig.getBaseRedisConfig(
allowExternalUuid = true,
cacheWriteSecured = false,
externalUuidSecured = true,
apiKey = getRandomString()
)
)

// and: Request object with set payload transfer key
val requestObject = RequestObject.getDefaultJsonRequestObject().apply { puts[0].key = getRandomUuid() }

// when: POST cache endpoint is called
val exception = shouldThrowExactly<ApiException> { prebidCacheApi.postCache(requestObject, apiKey = getRandomString()) }

// then: Unauthorized exception is thrown
assertSoftly {
exception.statusCode shouldBe UNAUTHORIZED.value()
exception.responseBody shouldContain "\"message\":\"Prebid cache host forbids specifying UUID in request by unauthorized users.\""
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ class PrebidCacheContainerConfig(
fun getBaseRedisConfig(
allowExternalUuid: Boolean,
cacheWriteSecured: Boolean = false,
externalUuidSecured: Boolean = false,
apiKey: String? = null
): Map<String, String> =
getBaseConfig(allowExternalUuid, cacheWriteSecured, apiKey) + getRedisConfig()
getBaseConfig(allowExternalUuid, cacheWriteSecured, apiKey, externalUuidSecured) + getRedisConfig()

fun getBaseAerospikeConfig(
allowExternalUuid: Boolean,
Expand Down Expand Up @@ -104,13 +105,14 @@ class PrebidCacheContainerConfig(
allowExternalUuid: Boolean,
cacheWriteSecured: Boolean = false,
apiKey: String? = null,
externalUuidSecured: Boolean? = null,
endpoint: String = "/storage"
): Map<String, String> =
getCachePrefixConfig() +
getCacheExpiryConfig() +
getAllowExternalUuidConfig(allowExternalUuid) +
getCacheTimeoutConfig("2500") +
getApiConfig(endpoint, apiKey, cacheWriteSecured)
getApiConfig(endpoint, apiKey, externalUuidSecured, cacheWriteSecured)

private fun getCachePrefixConfig(): Map<String, String> = mapOf("cache.prefix" to "prebid_")

Expand All @@ -120,10 +122,12 @@ class PrebidCacheContainerConfig(
private fun getApiConfig(
endpoint: String,
apiKey: String? = null,
externalUuidSecured: Boolean? = null,
allowPublicWrite: Boolean? = null
): Map<String, String> = buildMap {
put("api.storage-path", endpoint)
apiKey?.let { put("api.api-key", it) }
externalUuidSecured?.let { put("api.external-u-u-i-d-secured", it.toString()) }
allowPublicWrite?.let { put("api.cache-write-secured", it.toString()) }
}
}