Last active
March 11, 2022 02:57
-
-
Save jatinvaidya/33a07757c6a8b1651fbf41c408f6c8ea to your computer and use it in GitHub Desktop.
Client Specific Session Lifetime POC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* * * * | |
* This is just a library of utility functions | |
* There is NO STATE maintained in `global` | |
* NOT PRODUCTION READY !! | |
* * * */ | |
function functionsLibrary(user, context, callback) { | |
const uuid = require("[email protected]"); | |
const isInteractiveAuthentication = () => { | |
const leeway = 5; // seconds | |
if (context.authentication && context.authentication.methods) { | |
//Check if authn method match pwd or social connections | |
const authMethod = context.authentication.methods.find((method) => { | |
return method.name === "pwd" || method.name === "federated"; | |
}); | |
if (!!authMethod) { | |
let authnTimeStamp = authMethod.timestamp; | |
let currentDate = new Date(); | |
let currentEpochTimeStamp = currentDate.getTime(); | |
let currentAbsoluteSessionAge = Math.trunc( | |
(currentEpochTimeStamp - authnTimeStamp) / 1000 | |
); | |
return currentAbsoluteSessionAge <= leeway; | |
} else { | |
console.info(`invalid auth method`); | |
return false; | |
} | |
} | |
}; | |
const getInteractiveAuthenticationTimestamp = () => { | |
if (context.authentication && context.authentication.methods) { | |
//Check if authn method match pwd or social connections | |
const authMethod = context.authentication.methods.find((method) => { | |
return method.name === "pwd" || method.name === "federated"; | |
}); | |
if (!!authMethod) return authMethod.timestamp; | |
} | |
return null; | |
}; | |
const isSilentAuthentication = () => { | |
return isInteractiveAuthentication() ? false | |
: context.protocol === "oidc-basic-profile" ? true : false; | |
}; | |
const isRefreshTokenGrant = () => { | |
return context.protocol === "oauth2-refresh-token"; | |
}; | |
const isAbsoluteSessionTimeout = () => { | |
return ( | |
(getCurrentTimestamp() - getInteractiveAuthenticationTimestamp())/1000 >= | |
context.clientMetadata.absolute_session_lifetime | |
); | |
}; | |
const isInactivitySessionTimeout = (lastActivityTimestamp) => { | |
return ( | |
(getCurrentTimestamp() - lastActivityTimestamp)/1000 >= | |
context.clientMetadata.inactivity_session_lifetime | |
); | |
}; | |
const getCurrentTimestamp = () => new Date().getTime(); | |
const getRedisClient = () => { | |
let redisClient = global.redisClient; | |
if (!redisClient) { | |
const redis = require("[email protected]"); | |
redisClient = redis.createClient({ | |
host: "removed", | |
port: "35984", | |
}); | |
redisClient.auth("removed"); | |
redisClient.on("error", function (err) { | |
throw err; | |
}); | |
global.redisClient = redisClient; | |
} | |
return global.redisClient; | |
}; | |
const getLastActivityTimestamp = async () => { | |
const sessionId = getSessionId(); | |
console.info(`[getLastActivityTimestamp] sessionId: ${sessionId}`); | |
if (!!sessionId) { | |
const cacheKey = `${user.user_id}:${context.clientID}:${sessionId}:last_activity`; | |
console.info(`[getLastActivityTimestamp] cacheKey: ${cacheKey}`); | |
const lastActivityTimestamp = await getRedisString(cacheKey); | |
console.info( | |
`[getLastActivityTimestamp] lastActivityTimestamp: ${lastActivityTimestamp}` | |
); | |
return lastActivityTimestamp; | |
} | |
return null; | |
}; | |
const setLastActivityTimestamp = async (lastActivityTimestamp) => { | |
const sessionId = getSessionId(); | |
if (!!sessionId) { | |
const cacheKey = `${user.user_id}:${context.clientID}:${sessionId}:last_activity`; | |
console.info(`[setLastActivityTimestamp] cacheKey: ${cacheKey}`); | |
await setRedisString(cacheKey, lastActivityTimestamp); | |
//TBD TTL: context.clientMetadata.absolute_session_lifetime | |
} | |
}; | |
const getSessionId = () => { | |
if (isRefreshTokenGrant()) return context.request.body.x_session_id; | |
else if (isSilentAuthentication()) | |
return context.request.query.x_session_id; | |
else if (isInteractiveAuthentication()) return user.x_session_id; | |
}; | |
const generateSessionId = () => { | |
user.x_session_id = uuid.v4(); | |
}; | |
const getRedisString = (key) => { | |
return new Promise((resolve, reject) => { | |
getRedisClient().get(key, (error, response) => { | |
if (error) reject(error); | |
else resolve(response); | |
}); | |
}); | |
}; | |
const setRedisString = (key, value) => { | |
return new Promise((resolve, reject) => { | |
getRedisClient().set(key, value, (error, response) => { | |
if (error) reject(error); | |
else resolve(response); | |
}); | |
}); | |
}; | |
global.isInteractiveAuthentication = isInteractiveAuthentication; | |
global.isSilentAuthentication = isSilentAuthentication; | |
global.isRefreshTokenGrant = isRefreshTokenGrant; | |
global.getInteractiveAuthenticationTimestamp = | |
getInteractiveAuthenticationTimestamp; | |
global.isAbsoluteSessionTimeout = isAbsoluteSessionTimeout; | |
global.isInactivitySessionTimeout = isInactivitySessionTimeout; | |
global.getCurrentTimestamp = getCurrentTimestamp; | |
global.getRedisClient = getRedisClient; | |
global.getLastActivityTimestamp = getLastActivityTimestamp; | |
global.setLastActivityTimestamp = setLastActivityTimestamp; | |
global.getSessionId = getSessionId; | |
global.generateSessionId = generateSessionId; | |
return callback(null, user, context); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment