Lock a session cookie to the user IP address
If you like to prevent the session cookie (Navajo) from being used by another client or browser from another computer, the cookie may be locked to the user's IP address. This may be enabled by choosing the appropriate client identification method, see "identification" in the table "UserAgent attributes". Alternatively, you may configure a more sophisticated logic how to handle the change of the user's IP address during an authenticated session. A Lua script may be used to detect an IP change and to initiate a reauthentication of the user, see the chapter LuaFilter.
The following example script stores the user's IP address and locks the user's session if the address changes during the session. The user has then to reauthenticate against nevisAuth to get the new IP address approved (from then, both addresses are valid and may be used during the session.
<filter>
<filter-name>Session2IPLock</filter-name>
<filter-class>ch::nevis::isiweb4::filter::lua::LuaFilter</filter-class>
<init-param>
<param-name>Script</param-name>
<param-value>
function enforceIP(request, response, chunk)
trace = request:getTracer()
currentAddr = request:getEnv("REMOTE_ADDR")
session = request:getSession(true)
prevAddrStr = session:getAttribute("lua:addr")
lock = session:getAttribute("lua:addr:lock")
if lock ~= nil then
-- already locked
return
end
if prevAddrStr ~= nil then
-- existing addresses: check current against previous
checkStr = "#" .. currentAddr .. "#"
if string.find(prevAddrStr, checkStr, 1, true) == nil then
logstr = string.gsub(prevAddrStr, "##", ",")
logstr = string.gsub(logstr, "#", "")
trace:notice("IP check: address changed to " .. currentAddr .. ", allowed=" .. logstr ..", action=lock session")
request:setAttribute("ch.nevis.isiweb4.auth.ExternalHint", "lock")
session:setAttribute("lua:addr:lock", prevAddrStr)
end
end
end
authProcessed = 0
function storeIP(request, response, chunk)
if authProcessed == 0 then
trace = request:getTracer()
event = request:getEnv("Event")
if event ~= nil then
if string.find(event, "AU05", 1, true) then
-- authentication event: unlock and store IP
session = request:getSession(true)
session:removeAttribute("lua:addr:lock")
currentAddr = request:getEnv("REMOTE_ADDR")
checkStr = "#" .. currentAddr .. "#"
prevAddrStr = session:getAttribute("lua:addr")
if prevAddrStr ~= nil then
-- has alread an address
if string.find(prevAddrStr, checkStr, 1, true) == nil then
-- additional address
newPrevAddrStr = prevAddrStr .. checkStr
session:setAttribute("lua:addr", newPrevAddrStr)
trace:notice("IP check: add address " .. currentAddr)
end
else
-- first authentication
session:setAttribute("lua:addr", checkStr)
trace:notice("IP check: set address " .. currentAddr)
end
end
end
end
-- process only once per response
authProcessed = 1
return chunk
end
</param-value>
</init-param>
<init-param>
<param-name>Script.InputHeaderFunctionName</param-name>
<param-value>enforceIP</param-value>
</init-param>
<init-param>
<param-name>Script.OutputFunctionName</param-name>
<param-value>storeIP</param-value>
</init-param>
</filter>
The filter has to be mapped above the IdenityCreationFilter authenticating the user and nevisAuth uses the authentication method "unlock" to define t he process to unlock a user if the session has been locked by this Lua filter.