Session object cache

Hi team,

I’m using a custom auth plugin to control users rate limit.
My goal is to set a global limit for all users, with the possibility to extend this limit for specific users.
Per user limit it set on Redis. If the key return nothing, the plugin automatically get an hardcoded limit :
The mechanism itself works corretly. But, when I change an user value already known on Tyk, it will keep its previous value.

Let’s take an example :
Default rate limit : 10 request / minute
Token : foo
Sending 11 requests :

Status code distribution:
  [200]	10 responses
  [429]	1 responses

Redis data :

127.0.0.1:6379> GET apikey-7406e1d1
"{\"last_check\":0,\"allowance\":0,\"rate\":10,\"per\":60,\"expires\":0,\"quota_max\":0,\"quota_renews\":1529506001,\"quota_remaining\":0,\"quota_renewal_rate\":0,\"access_rights\":{},\"org_id\":\"\",\"oauth_client_id\":\"\",\"oauth_keys\":null,\"certificate\":\"\",\"basic_auth_data\":{\"password\":\"\",\"hash_type\":\"\"},\"jwt_data\":{\"secret\":\"\"},\"hmac_enabled\":false,\"hmac_string\":\"\",\"is_inactive\":false,\"apply_policy_id\":\"\",\"apply_policies\":null,\"data_expires\":0,\"monitor\":{\"trigger_limits\":null},\"enable_detail_recording\":false,\"meta_data\":{\"token\":\"foo\"},\"tags\":[],\"alias\":\"\",\"last_updated\":\"\",\"id_extractor_deadline\":1529506061,\"session_lifetime\":0}"
127.0.0.1:6379> TTL apikey-7406e1d1
(integer) 24

The TTL have been applied because of "session_lifetime": 60 set on the API definition.
So, that’s perfect.
Now, let’s set the new limit to my user :

127.0.0.1:6379> SET coprocess-data:rate:foo 15
OK

Then, send 16 requests with this key :

 Status code distribution:
  [200]	10 responses
  [429]	6 responses

=> The old limit is still applied. On redis side, the new rate limit is registered :

127.0.0.1:6379> GET apikey-7406e1d1
"{\"last_check\":0,\"allowance\":0,\"rate\":15,\"per\":60,\"expires\":0,\"quota_max\":0,\"quota_renews\":1529506183,\"quota_remaining\":0,\"quota_renewal_rate\":0,\"access_rights\":{},\"org_id\":\"\",\"oauth_client_id\":\"\",\"oauth_keys\":null,\"certificate\":\"\",\"basic_auth_data\":{\"password\":\"\",\"hash_type\":\"\"},\"jwt_data\":{\"secret\":\"\"},\"hmac_enabled\":false,\"hmac_string\":\"\",\"is_inactive\":false,\"apply_policy_id\":\"\",\"apply_policies\":null,\"data_expires\":0,\"monitor\":{\"trigger_limits\":null},\"enable_detail_recording\":false,\"meta_data\":{\"token\":\"foo\"},\"tags\":[],\"alias\":\"\",\"last_updated\":\"\",\"id_extractor_deadline\":1529506243,\"session_lifetime\":0}"

Question : Is there another place where rate limit are kept in cache, and how to flush it ?

Thanks,
Anthony

Can you share your plugin code (at least in a simplified way)? Are you using just an authentication hook or additional ones?

Hi Matias,

I’m only using the auth plugin + the ID extractor.
Here is the ugly code used for the PoC :

from tyk.decorators import *
from time import time
from gateway import TykGateway as tyk

@Hook
def MyAuthMiddleware(request, session, metadata, spec):
    if request.get_header('Key'):
        tyk.log("Key header detected %s" % request.get_header('Key'), "info")
        key = request.get_header('Key')
        redis_key = "rate:%s" % key
        tyk.log(redis_key, "info")
        rate = tyk.get_data(redis_key)
        if rate == "":
            rate = 10
        tyk.log("a = %s" % str(rate), "info")
        metadata['token'] = key
        session.rate = int(rate)
        session.per = 60
        session.id_extractor_deadline = int(time()) + 60
    else:
        tyk.log("No Key header - switching to per IP limit", "info")
        metadata['token'] = request.get_header('X-Real-Ip')
        session.rate = 2.0
        session.per = 10.0
    return request, session, metadata

Manifest :

    "file_list": [
        "middleware.py"
    ],
    "custom_middleware": {
        "driver": "python",
        "auth_check": {
            "name": "MyAuthMiddleware"
        },
	"id_extractor": {
    		"extract_from": "header",
    		"extract_with": "value",
    		"extractor_config": {
    			"header_name": "Key"
    		}
	}
    }
}

Thanks !
Anthony