Skip to content

Commit e8bd20d

Browse files
Fix caching for profile validators (#81)
* customize profile key name depending on the validator flavour * customize profile key name for local cache also * Fix local caching * Rename method * extract dictionary name into a constant * wrap delete from redis and local cache in a separate method
1 parent 16c0bed commit e8bd20d

1 file changed

Lines changed: 56 additions & 17 deletions

File tree

src/lua/api-gateway/validation/oauth2/userProfileValidator.lua

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ _M["redis_RW_upstream"] = redisConfigurationProvider["oauth"]["rw_upstream_name"
5555
_M["redis_pass_env"] = redisConfigurationProvider["oauth"]["env_password_variable"]
5656
_M.PROFILE_VALIDATION_LOCATION = "/validate-user"
5757

58+
--- Nginx shared dictionary for storing user profiles
59+
_M.USER_PROFILE_DICTIONARY = "cachedUserProfiles"
60+
5861
local RESPONSES = {
5962
P_MISSING_TOKEN = { error_code = "403020", message = "Oauth token is missing" },
6063
INVALID_PROFILE = { error_code = "403023", message = "Profile is not valid" },
@@ -70,7 +73,7 @@ local LOCAL_CACHE_TTL = 60
7073
-- Maximum time in milliseconds specifying how long to cache a valid token in Redis
7174
local REDIS_CACHE_TTL = 6 * 60 * 60
7275

73-
-- returns the key that should be used when looking up in the cache --
76+
--- returns the key that should be used when looking up in the cache --
7477
function _M:getCacheToken(token)
7578
local t = token;
7679
local oauth_host = ngx.var.oauth_host
@@ -81,6 +84,29 @@ function _M:getCacheToken(token)
8184
end
8285
end
8386

87+
function _M:getCacheTokenLookupKey()
88+
local oauth_token = ngx.var.authtoken
89+
local oauth_token_hash = hasher.hash(oauth_token)
90+
return self:getCacheToken(oauth_token_hash)
91+
end
92+
93+
function _M:getRedisCacheLookupProfileKey()
94+
if self.PROFILE_VALIDATOR_CODE ~= nil and self.PROFILE_VALIDATOR_CODE ~= "" then
95+
return "user_json:" .. self.PROFILE_VALIDATOR_CODE;
96+
else
97+
return "user_json";
98+
end
99+
end
100+
101+
function _M:getLocalCacheLookupProfileKey()
102+
local cacheLookupKey = self:getCacheTokenLookupKey()
103+
if self.PROFILE_VALIDATOR_CODE ~= nil and self.PROFILE_VALIDATOR_CODE ~= "" then
104+
return cacheLookupKey .. ":" .. self.PROFILE_VALIDATOR_CODE;
105+
else
106+
return cacheLookupKey;
107+
end
108+
end
109+
84110
--- Converts the expire_at into expire_in in seconds
85111
-- @param expire_at UTC expiration time in seconds
86112
--
@@ -112,27 +138,30 @@ function _M:getContextPropertiesObject(obj)
112138
return props
113139
end
114140

115-
function _M:getProfileFromCache(cacheLookupKey)
116-
local localCacheValue = self:getKeyFromLocalCache(cacheLookupKey, "cachedUserProfiles")
141+
function _M:getProfileFromCache(cacheTokenLookupKey)
142+
local redisCacheLookupProfileKey = self:getRedisCacheLookupProfileKey()
143+
local localCacheLookupProfileKey = self:getLocalCacheLookupProfileKey()
144+
145+
local localCacheValue = self:getKeyFromLocalCache(localCacheLookupProfileKey, self.USER_PROFILE_DICTIONARY)
117146
if ( localCacheValue ~= nil ) then
118147
-- ngx.log(ngx.INFO, "Found profile in local cache")
119148
return localCacheValue
120149
end
121150

122-
local redisCacheValue = self:getKeyFromRedis(cacheLookupKey, "user_json")
151+
local redisCacheValue = self:getKeyFromRedis(cacheTokenLookupKey, redisCacheLookupProfileKey)
123152
if ( redisCacheValue ~= nil ) then
124153
ngx.log(ngx.DEBUG, "Found User Profile in Redis cache")
125154
local oauthTokenExpiration = ngx.ctx.oauth_token_expires_at
126155
local expiresIn = self:getExpiresIn(oauthTokenExpiration)
127156
local localExpiresIn = math.min( expiresIn, LOCAL_CACHE_TTL )
128157
ngx.log(ngx.DEBUG, "Storing cached User Profile in the local cache for " .. tostring(localExpiresIn) .. " s out of a total validity of " .. tostring(expiresIn) .. " s.")
129-
self:setKeyInLocalCache(cacheLookupKey, redisCacheValue, localExpiresIn, "cachedUserProfiles")
158+
self:setKeyInLocalCache(localCacheLookupProfileKey, redisCacheValue, localExpiresIn, self.USER_PROFILE_DICTIONARY)
130159
return redisCacheValue
131160
end
132161
return nil;
133162
end
134163

135-
function _M:storeProfileInCache(cacheLookupKey, cachingObj)
164+
function _M:storeProfileInCache(cacheTokenLookupKey, cachingObj)
136165
local cachingObjString = cjson.encode(cachingObj)
137166

138167
local oauthTokenExpiration = (ngx.ctx.oauth_token_expires_at or ((ngx.time() + LOCAL_CACHE_TTL) * 1000))
@@ -150,9 +179,25 @@ function _M:storeProfileInCache(cacheLookupKey, cachingObj)
150179
if ngx.var.max_oauth_redis_cache_ttl ~= nil and ngx.var.max_oauth_redis_cache_ttl ~= '' then
151180
default_ttl_expire = ngx.var.max_oauth_redis_cache_ttl
152181
end
153-
self:setKeyInLocalCache(cacheLookupKey, cachingObjString, localExpiresIn , "cachedUserProfiles")
182+
183+
local redisCacheLookupProfileKey = self:getRedisCacheLookupProfileKey()
184+
local localCacheLookupProfileKey = self:getLocalCacheLookupProfileKey()
185+
186+
self:setKeyInLocalCache(localCacheLookupProfileKey, cachingObjString, localExpiresIn , self.USER_PROFILE_DICTIONARY)
187+
154188
-- cache the use profile for 5 minutes
155-
self:setKeyInRedis(cacheLookupKey, "user_json", math.min(oauthTokenExpiration, (ngx.time() + default_ttl_expire) * 1000), cachingObjString)
189+
self:setKeyInRedis(cacheTokenLookupKey, redisCacheLookupProfileKey, math.min(oauthTokenExpiration, (ngx.time() + default_ttl_expire) * 1000), cachingObjString)
190+
end
191+
192+
---
193+
-- Deletes user profile from redis and local cache.
194+
--
195+
function _M:deleteProfileFromCache()
196+
local localCacheLookupProfileKey = self:getLocalCacheLookupProfileKey()
197+
self:deleteKeyInLocalCache(localCacheLookupProfileKey, self.USER_PROFILE_DICTIONARY)
198+
199+
local cacheTokenLookupKey = self:getCacheTokenLookupKey()
200+
self:deleteKeyFromRedis(cacheTokenLookupKey)
156201
end
157202

158203
--- Returns true if the profile is valid for the request context. If profile is not valid then it returns the failure
@@ -180,16 +225,10 @@ function _M:extractContextVars(profile)
180225
return cachingObj
181226
end
182227

183-
function _M:getCacheLookupKey()
184-
local oauth_token = ngx.var.authtoken
185-
local oauth_token_hash = hasher.hash(oauth_token)
186-
return self:getCacheToken(oauth_token_hash)
187-
end
188-
189228
function _M:validateUserProfile()
190229
--1. try to get user's profile from the cache first ( local or redis cache )
191-
local cacheLookupKey = self:getCacheLookupKey()
192-
local cachedUserProfile = self:getProfileFromCache(cacheLookupKey)
230+
local cacheTokenLookupKey = self:getCacheTokenLookupKey()
231+
local cachedUserProfile = self:getProfileFromCache(cacheTokenLookupKey)
193232

194233
if ( cachedUserProfile ~= nil ) then
195234
if (type(cachedUserProfile) == 'string') then
@@ -222,7 +261,7 @@ function _M:validateUserProfile()
222261

223262
local isValid, failureErrorCode, failureMessage = self:isProfileValid(cachingObj)
224263
if isValid == true then
225-
self:storeProfileInCache(cacheLookupKey, cachingObj)
264+
self:storeProfileInCache(cacheTokenLookupKey, cachingObj)
226265
return ngx.HTTP_OK
227266
elseif failureErrorCode ~= nil and failureMessage ~= nil then
228267
return failureErrorCode, failureMessage

0 commit comments

Comments
 (0)