Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(authentication): make cookie name unique between environments (#2095
)
  • Loading branch information
subotic committed Jul 14, 2022
1 parent e1d8d95 commit 7d420a4
Show file tree
Hide file tree
Showing 12 changed files with 272 additions and 56 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Expand Up @@ -70,7 +70,7 @@ lazy val sipi: Project = Project(id = "sipi", base = file("sipi"))
Docker / defaultLinuxInstallLocation := "/sipi",
Universal / mappings ++= {
// copy the sipi/scripts folder
directory("sipi/scripts")
directory("sipi/scripts"),
},
// use filterNot to return all items that do NOT meet the criteria
dockerCommands := dockerCommands.value.filterNot {
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Expand Up @@ -38,6 +38,7 @@ services:
- KNORA_WEBAPI_KNORA_API_EXTERNAL_HOST=0.0.0.0
- KNORA_WEBAPI_KNORA_API_EXTERNAL_PORT=3333
# entrypoint: [ "valgrind", "--leak-check=yes", "/sipi/sipi" ] ## uncomment to run SIPI under valgrind
# command: --config=/sipi/config/sipi.docker-test-config.lua ## command variant to start the sipi container with test routes enabled
command: --config=/sipi/config/sipi.docker-config.lua

api:
Expand Down
87 changes: 52 additions & 35 deletions sipi/config/sipi.docker-test-config.lua
@@ -1,8 +1,8 @@
-- * Copyright © 2021 - 2022 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors.
-- * SPDX-License-Identifier: Apache-2.0
-- Copyright © 2021 - 2022 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors.
-- SPDX-License-Identifier: Apache-2.0

--
-- configuration file for use with Knora
-- ATTENTION: This configuration file should only be used for integration testing. It has additional routes defined!!!
--
sipi = {
--
Expand All @@ -22,6 +22,34 @@ sipi = {
--
port = 1024,

--
-- Number of threads to use
--
nthreads = 8,

--
-- SIPI is using libjpeg to generate the JPEG images. libjpeg requires a quality value which
-- corresponds to the compression rate. 100 is (almost) no compression and best quality, 0
-- would be full compression and no quality. Reasonable values are between 30 and 95...
--
jpeg_quality = 60,

--
-- For scaling images, SIPI offers two methods. The value "high" offers best quality using expensive
-- algorithms: bilinear interpolation, if downscaling the image is first scaled up to an integer
-- multiple of the requires size, and then downscaled using averaging. This results in the best
-- image quality. "medium" uses bilinear interpolation but does not do upscaling before
-- downscaling. If scaling quality is set to "low", then just a lookup table and nearest integer
-- interpolation is being used to scale the images.
-- Recognized values are: "high", "medium", "low".
--
scaling_quality = {
jpeg = "medium",
tiff = "high",
png = "high",
j2k = "high"
},

--
-- Number of seconds a connection (socket) remains open
--
Expand All @@ -30,16 +58,16 @@ sipi = {
--
-- Maximal size of a post request
--
max_post_size = '30M',
max_post_size = '250M',

--
--
-- indicates the path to the root of the image directory. Depending on the settings of the variable
-- "prefix_as_path" the images are search at <imgroot>/<prefix>/<imageid> (prefix_as_path = TRUE)
-- or <imgroot>/<imageid> (prefix_as_path = FALSE). Please note that "prefix" and "imageid" are
-- expected to be urlencoded. Both will be decoded. That is, "/" will be recoignized and expanded
-- in the final path the image file!
--
imgroot = './test/_test_data/images', -- directory for Knora Sipi integration testing
imgroot = '/sipi/images', -- make sure that this directory exists

--
-- If FALSE, the prefix is not used to build the path to the image files
Expand Down Expand Up @@ -68,38 +96,44 @@ sipi = {
--
-- Lua script which is executed on initialization of the Lua interpreter
--
initscript = './scripts/sipi.init-test.lua',
initscript = '/sipi/scripts/sipi.init.lua',

--
-- path to the caching directory
--
cachedir = './cache',
cachedir = '/sipi/cache',

--
-- maxcimal size of the cache
-- maximal size of the cache
--
cachesize = '100M',

--
-- if the cache becomes full, the given percentage of file space is marked for reuase
--
cache_hysteresis = 0.1,
cache_hysteresis = 0.15,

--
-- Path to the directory where the scripts for the routes defined below are to be found
--
scriptdir = './scripts',
scriptdir = '/sipi/scripts',

---
--- Size of the thumbnails
--- Size of the thumbnails (to be used within Lua)
---
thumb_size = 'pct:4',
thumb_size = '!128,128',

--
-- Path to the temporary directory
--
tmpdir = '/tmp',

--
-- Maximum age of temporary files, in seconds (requires Knora's upload.lua).
-- Defaults to 86400 seconds (1 day).
--
max_temp_file_age = 86400,

--
-- Path to Knora Application
--
Expand All @@ -110,26 +144,6 @@ sipi = {
--
knora_port = '3333',

--
-- If compiled with SSL support, the port the server is listening for secure connections
--
-- ssl_port = 1025,

--
-- If compiled with SSL support, the path to the certificate (must be .pem file)
-- The follow commands can be used to generate a self-signed certificate
-- # openssl genrsa -out key.pem 2048
-- # openssl req -new -key key.pem -out csr.pem
-- #openssl req -x509 -days 365 -key key.pem -in csr.pem -out certificate.pem
--
-- ssl_certificate = './certificate/certificate.pem',

--
-- If compiled with SSL support, the path to the key file (see above to create)
--
-- ssl_key = './certificate/key.pem',


--
-- The secret for generating JWT's (JSON Web Tokens) (42 characters)
--
Expand All @@ -139,20 +153,23 @@ sipi = {
--
-- Name of the logfile (a ".txt" is added...)
--
logfile = "sipi.log",
-- logfile = "sipi.log",


--
-- loglevel, one of "DEBUG", "INFO", "NOTICE", "WARNING", "ERR",
-- "CRIT", "ALERT", "EMERG"
--
loglevel = "DEBUG"

}


fileserver = {
--
-- directory where the documents for the normal webserver are located
--
docroot = './server',
docroot = '/sipi/server',

--
-- route under which the normal webserver shouöd respond to requests
Expand Down
20 changes: 18 additions & 2 deletions sipi/scripts/basexx.lua
Expand Up @@ -109,7 +109,7 @@ end
-- generic function to decode and encode base32/base64
--------------------------------------------------------------------------------

local function from_basexx( str, alphabet, bits )
function from_basexx( str, alphabet, bits )
local result = {}
for i = 1, #str do
local c = string.sub( str, i, i )
Expand All @@ -127,7 +127,7 @@ local function from_basexx( str, alphabet, bits )
return pure_from_bit( string.sub( value, 1, #value - pad ) )
end

local function to_basexx( str, alphabet, bits, pad )
function to_basexx( str, alphabet, bits, pad )
local bitString = basexx.to_bit( str )

local chunks = divide_string( bitString, bits )
Expand Down Expand Up @@ -160,6 +160,22 @@ function basexx.to_base32( str )
return to_basexx( str, base32Alphabet, 5, base32PadMap[ #str % 5 + 1 ] )
end

--------------------------------------------------------------------------------
-- dsp-api custom variant
--------------------------------------------------------------------------------

local base32CustomAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
local base32CustomPadMap = { "", "999999", "9999", "999", "9" }

function basexx.from_base32Custom( str, ignore )
str = ignore_set( str, ignore )
return from_basexx( string.upper( str ), base32CustomAlphabet, 5 )
end

function basexx.to_base32Custom( str )
return to_basexx( str, base32CustomAlphabet, 5, base32CustomPadMap[ #str % 5 + 1 ] )
end

--------------------------------------------------------------------------------
-- crockford: http://www.crockford.com/wrmg/base32.html
--------------------------------------------------------------------------------
Expand Down
12 changes: 9 additions & 3 deletions sipi/scripts/get_knora_session.lua
Expand Up @@ -36,12 +36,14 @@ function get_session_id(cookie)
host_port = webapi_hostname .. ':' .. webapi_port
server.log("host_port: " .. host_port, server.loglevel.LOG_DEBUG)

local customPadMap = { "", "999999", "9999", "999", "9" }
host_port_base32 = basexx.to_basexx(host_port, base32Alphabet, 5, customPadMap)
host_port_base32 = basexx.to_base32Custom(host_port)
server.log("host_port_base32: " .. host_port_base32, server.loglevel.LOG_DEBUG)






-- tries to extract the Knora session id from the cookie:
-- gets the digits between "sid=" and the closing ";" (only given in case of several key value pairs)
-- ";" is expected to separate different key value pairs (https://tools.ietf.org/html/rfc6265#section-4.2.1)
Expand All @@ -51,6 +53,10 @@ function get_session_id(cookie)
local session_id = string.match(cookie, "KnoraAuthentication" .. host_port_base32 .. "=([^%s;]+)")
server.log("extracted session_id: " .. session_id, server.loglevel.LOG_DEBUG)

return session_id
local session = {}
session["id"] = session_id
session["name"] = "KnoraAuthentication" .. host_port_base32

return session

end
13 changes: 6 additions & 7 deletions sipi/scripts/sipi.init.lua
Expand Up @@ -42,17 +42,17 @@ function pre_flight(prefix, identifier, cookie)

if cookie ~='' then

-- tries to extract the Knora session id from the cookie:
-- tries to extract the Knora session name and id from the cookie:
-- gets the digits between "sid=" and the closing ";" (only given in case of several key value pairs)
-- returns nil if it cannot find it
session_id = get_session_id(cookie)
session = get_session_id(cookie)

if session_id == nil then
-- no session_id could be extracted
print("cookie key is invalid: " .. cookie)
if session == nil then
-- no session could be extracted
server.log("cookie key is invalid: " .. cookie, server.loglevel.LOG_ERR)
else
knora_cookie_header = { Cookie = "KnoraAuthentication=" .. session_id }
knora_cookie_header = { Cookie = session["name"] .. "=" .. session["id"] }
server.log("pre_flight - knora_cookie_header: " .. knora_cookie_header["Cookie"], server.loglevel.LOG_DEBUG)
end
end

Expand All @@ -78,7 +78,6 @@ function pre_flight(prefix, identifier, cookie)

-- print("knora_url: " .. knora_url)
server.log("pre_flight - knora_url: " .. knora_url, server.loglevel.LOG_DEBUG)
server.log("pre_flight - knora_cookie_header: " .. tostring(knora_cookie_header), server.loglevel.LOG_DEBUG)

success, result = server.http("GET", knora_url, knora_cookie_header, 5000)

Expand Down
Expand Up @@ -433,7 +433,7 @@ class ApplicationActor(
new ProjectsRouteADM(routeData).knoraApiPath ~
new StoreRouteADM(routeData).knoraApiPath ~
new UsersRouteADM(routeData).knoraApiPath ~
new SipiRouteADM(routeData).knoraApiPath ~
new FilesRouteADM(routeData).knoraApiPath ~
new SwaggerApiDocsRoute(routeData).knoraApiPath
}
}
Expand Down
Expand Up @@ -17,7 +17,7 @@ import org.knora.webapi.routing.RouteUtilADM
/**
* Provides a routing function for the API that Sipi connects to.
*/
class SipiRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) with Authenticator {
class FilesRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) with Authenticator {

/**
* A routing function for the API that Sipi connects to.
Expand Down
10 changes: 4 additions & 6 deletions webapi/src/test/resources/logback-test.xml
Expand Up @@ -37,12 +37,10 @@
<logger name="kamon.metric" level="ERROR"/>
<logger name="org.apache.http" level="INFO"/>
<logger name="org.apache.http.wire" level="INFO"/>
<logger name="org.testcontainers" level="INFO"/>
<logger name="com.github.dockerjava" level="WARN"/>
<logger name="org.testcontainers.dockerclient.DockerClientProviderStrategy" level="WARN" />
<logger name="org.testcontainers.DockerClientFactory" level="WARN" />
<logger name="org.testcontainers.utility.ImageNameSubstitutor" level="WARN" />
<logger name="org.testcontainers.utility.RegistryAuthLocator" level="WARN" />
<logger name="org.testcontainers" level="WARN" />
<logger name="com.github.dockerjava" level="WARN" />
<logger name="ch.qos.logback" level="WARN" />


<!-- Logging inside ZIO -->
<logger name="zio-slf4j-logger" level="INFO"/>
Expand Down
Expand Up @@ -21,6 +21,7 @@ import org.knora.webapi.util.MutableTestString

import scala.concurrent.Await
import scala.concurrent.duration._
import org.knora.webapi.routing.Authenticator

object AuthenticationV2E2ESpec {
val config: Config = ConfigFactory.parseString("""
Expand Down Expand Up @@ -212,6 +213,24 @@ class AuthenticationV2E2ESpec
assert(response.status === StatusCodes.OK)
}

"authenticate with token in cookie" in {
val KnoraAuthenticationCookieName = Authenticator.calculateCookieName(settings)
val cookieHeader = headers.Cookie(KnoraAuthenticationCookieName, token.get)

val request = Get(baseApiUrl + "/v2/authentication") ~> addHeader(cookieHeader)
val response = singleAwaitingRequest(request)
assert(response.status === StatusCodes.OK)
}

"fail authentication with invalid token in cookie" in {
val KnoraAuthenticationCookieName = Authenticator.calculateCookieName(settings)
val cookieHeader = headers.Cookie(KnoraAuthenticationCookieName, "not_a_valid_token")

val request = Get(baseApiUrl + "/v2/authentication") ~> addHeader(cookieHeader)
val response = singleAwaitingRequest(request)
assert(response.status === StatusCodes.Unauthorized)
}

"logout when providing token in header" in {
// do logout with stored token
val request =
Expand Down

0 comments on commit 7d420a4

Please sign in to comment.