Skip to content

Commit

Permalink
fix: Make Sipi handle multiple KnoraAuthentication* cookies correc…
Browse files Browse the repository at this point in the history
…tly (DEV-2271) (#2713)
  • Loading branch information
seakayone committed Jun 20, 2023
1 parent 85a30a5 commit 1330d2b
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 10 deletions.
21 changes: 16 additions & 5 deletions sipi/scripts/authentication.lua
Expand Up @@ -167,11 +167,22 @@ end
-- @return jwt token or nil if the cookie is missing or invalid.
function _get_jwt_token_from_cookie()
log("authentication: checking for jwt token in cookie header", server.loglevel.LOG_DEBUG)
local cookie_header_value = _get_cookie_header()
if cookie_header_value == nil then
local cookie_name = env_knora_authentication_cookie_name()
local cookies = _get_cookie_header()
if cookies == nil then
log("authentication: no cookie header found", server.loglevel.LOG_DEBUG)
return nil
end
local cookie_name = env_knora_authentication_cookie_name()
local jwt_token = str_strip_prefix(cookie_header_value, cookie_name .. "=")
return jwt_token

cookie_name = cookie_name:lower()
for entry in cookies:gmatch("([^,]+)") do
local key, value = entry:match("([^=]+)=(.+)")
if key and value then
if key:lower() == cookie_name then
return value
end
end
end
log("authentication: cookie header does not contain " .. cookie_name, server.loglevel.LOG_DEBUG)
return nil
end
2 changes: 1 addition & 1 deletion sipi/scripts/env.lua
Expand Up @@ -34,5 +34,5 @@ end
-- Returns the name of the cookie used for authentication.
function env_knora_authentication_cookie_name()
local host_port_base32 = basexx.to_base32Custom(env_dsp_api_host_port())
return "KnoraAuthentication" .. host_port_base32
return string.lower("KnoraAuthentication" .. host_port_base32)
end
28 changes: 24 additions & 4 deletions sipi/scripts/strings.lua
Expand Up @@ -3,6 +3,26 @@

--- Utility functions for working with strings.

-- Break a string up at occurrences of the first single character.
-- In Lua, there is no built-in function for splitting a string at a specific character.
-- http://lua-users.org/wiki/SplitJoin
-- @param str the string to split.
-- @param separator the separator character.
-- @return a table containing:
--- * the split string or
--- * the original string if the separator was not found.
function str_splitString(str, separator)
local result = {}
local pattern = string.format("([^%s]+)", separator)

for match in str:gmatch(pattern) do
table.insert(result, match)
end

return result
end


--- Checks if a string starts with a specific prefix.
-- In Lua, there is no built-in function for checking if a string starts with a specific prefix.
-- This function implements this functionality.
Expand Down Expand Up @@ -33,18 +53,18 @@ end
-- @param tbl the table to transform.
-- @return a string representation of the table.
function tableToString(tbl)
local str = "{"
local str = "{\n"
local isFirst = true

for key, value in pairs(tbl) do
if not isFirst then
str = str .. ", "
str = str .. "\n"
end

if type(value) == "table" then
str = str .. key .. "=" .. tableToString(value)
str = str .. key .. " = " .. tableToString(value) .. "\n"
else
str = str .. key .. "=" .. tostring(value)
str = str .. key .. " = " .. tostring(value) .. "\n"
end

isFirst = false
Expand Down
53 changes: 53 additions & 0 deletions webapi/src/it/scala/org/knora/sipi/SipiIT.scala
Expand Up @@ -14,6 +14,8 @@ import com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor
import com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo
import com.github.tomakehurst.wiremock.core.WireMockConfiguration.options
import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder
import org.apache.commons.codec.binary.Base32
import spray.json.JsString
import zio._
import zio.http._
import zio.http.model.Status
Expand All @@ -26,9 +28,17 @@ import scala.util.Success
import scala.util.Try

import org.knora.sipi.MockDspApiServer.verify._
import org.knora.webapi.messages.StringFormatter
import org.knora.webapi.messages.admin.responder.KnoraResponseADM
import org.knora.webapi.messages.admin.responder.sipimessages._
import org.knora.webapi.routing.JwtService
import org.knora.webapi.routing.JwtServiceLive
import org.knora.webapi.sharedtestdata.SharedTestDataADM
import org.knora.webapi.testcontainers.SipiTestContainer
import com.github.tomakehurst.wiremock.client.WireMock.equalTo
import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder.newRequestPattern

import org.knora.sipi.SipiIT.fileEndpointSuite

object SipiIT extends ZIOSpecDefault {

Expand All @@ -43,6 +53,48 @@ object SipiIT extends ZIOSpecDefault {
private def getWithoutAuthorization(path: String) =
SipiTestContainer.resolveUrl(path).map(Request.get).flatMap(Client.request(_))

private val jwt =
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIwLjAuMC4wOjMzMzMiLCJzdWIiOiJodHRwOi8vcmRmaC5jaC91c2Vycy9yb290IiwiYXVkIjpbIktub3JhIiwiU2lwaSJdLCJleHAiOjE2ODk3NTY1MzksImlhdCI6MTY4NzE2NDUzOSwianRpIjoiSG9SSFg5V1lSZHV6VnVmTXZFT1c4USJ9.tlTqr1NGjsOqnMRxjDW1TokDjGAPO5nvG-pcbn09Hrw"

private val cookiesSuite =
suite("Given a Request contains multiple auth cookies")(
test(
"When getting an existing file, " +
"then Sipi should extract the correct cookie, send it to dsp-api " +
"and responds with Ok"
) {
for {
_ <- copyTestFilesToSipi
mockServer <- MockDspApiServer.resetAndStubGetResponse(
s"/admin/files/$prefix/$imageTestfile",
200,
SipiFileInfoGetResponseADM(permissionCode = 2, restrictedViewSettings = None)
)
response <-
SipiTestContainer
.resolveUrl(s"/$prefix/$imageTestfile/file")
.map { url =>
Request
.get(url)
.withCookie(s"KnoraAuthenticationGAXDALRQFYYDUMZTGMZQ9999aSecondCookie=anotherValueShouldBeIgnored")
.withCookie(s"KnoraAuthenticationGAXDALRQFYYDUMZTGMZQ9999=$jwt")
}
.flatMap(Client.request(_))
requestToDspApiContainsJwt <- ZIO
.attempt(
mockServer.verify(
// Number of times the request should be received (in this case, only once)
1,
// The expected request with header and value
newRequestPattern().withHeader("Authorization", equalTo(s"Bearer $jwt"))
)
)
.logError
.fold(err => false, succ => true)
} yield assertTrue(response.status == Status.Ok, requestToDspApiContainsJwt)
}
)

private val knoraJsonEndpointSuite =
suite("Endpoint /{prefix}/{identifier}/knora.json")(
suite("Given the user is unauthorized")(
Expand Down Expand Up @@ -208,6 +260,7 @@ object SipiIT extends ZIOSpecDefault {

override def spec: Spec[TestEnvironment with Scope, Any] =
suite("Sipi integration tests with mocked dsp-api")(
cookiesSuite,
knoraJsonEndpointSuite,
fileEndpointSuite,
iiifEndpoint,
Expand Down

0 comments on commit 1330d2b

Please sign in to comment.