Using Quota Policy for number of tries.

We're trying to implement something in our APP where a user is allowed only 5 times to enter their PIN numbers incorrectly per day. So if you entered your PIN 5 times incorrectly, you'll need to wait for 1 day in order to be able to try another time.

Can this be done using Quota Policy in any configuration? I tried doing it so that there is a condition of accessing the Quota Policy when the PIN is incorrect, but the problem is that you will no longer be able to access this value if you inserted the PIN correctly.

Could anyone assist please? And if there was a possible solution, is this recommended or not recommended?

1 7 284
7 REPLIES 7

sidd-harth
Participant V

Hi Ghassan, I guess this can be done in multiple ways, we can increment the value using Javascript, Store it in KVM to take the number of invalids attempts, use Cache to keep track of the number of attempts for each user for 24 hours, and finally use a Quota policy.

For a simple workaround, we can simply use Cache and Quota policies with Fault Rules.

I am assuming you are using a resource in proxy /validate to validate the submitted pin using a Service Callout Policy.

9975-policies.png

 <FaultRules>
        <FaultRule name="invalid_pin_rule">
            <Step>
                <Name>PC-StoreIncrementedCount</Name>
            </Step>
            <Step>
                <Name>AM-SetPayload-InvalidPin</Name>
            </Step>
            <Condition>(fault.name = "ExecutionFailed")</Condition>
        </FaultRule>
        <FaultRule name="over_quota">
            <Step>
                <Name>AM-SetPayload-User-Quota-Fault</Name>
            </Step>
            <Condition>(fault.name = "QuotaViolation")</Condition>
        </FaultRule>
    </FaultRules>
    
    <Flows>
        <Flow name="validatePin">
            <Description/>
            <Request>
                <Step>
                    <Name>LC-GetIncrementedValue</Name>
                </Step>
                <Step>
                    <Name>Quota</Name>
                    <Condition>count != null</Condition>
                </Step>
                <Step>
                    <Name>SC-HttpBin</Name>
                </Step>
            </Request>
            <Response/>
            <Condition>(proxy.pathsuffix MatchesPath "/validate") and (request.verb = "GET")</Condition>
        </Flow>
    </Flows>

I am using a Service Callout to call HTTPBIN service which would give me 200OK and 400Bad Request error when I sent a request header name code with either 200 or 400 as input.

If I get 400 error, then the FaultRules are executed and the Populate Cache will create a new Cache store the content of ServiceCallout Response and CacheKey is a unique Username. I am using a Username as a Key to identify the user from the Request Header. You need to decide how to identify each user. If required you can use an ExTractVariable policy before PopulateCache and extract key information that you can use for other policies like Quota and LookupCache. Then the SetPayload policy will send an error response back to the user.

After 5 failed attempts, the Quota policy will give QuotaViolation Error and block the user for one day. I have used the same Username as an Identifier here.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Quota async="false" continueOnError="false" enabled="true" name="Quota">
    <DisplayName>Quota</DisplayName>
    <Properties/>
    <Allow count="4"/>
    <Interval>1</Interval>
    <Distributed>true</Distributed>
    <Synchronous>true</Synchronous>
    <TimeUnit>day</TimeUnit>
    <Identifier ref="request.header.username"/>
</Quota>

Initially, when the user has entered an InvalidPin for the first time the LookUpCache will miss the cache because the InvalidPin Cache is not yet created and hence the Quota policy will be skipped because of its condition and it will go ahead run the FaultRules and then PopulateCache will create a Cache. For this reason, I have used Quota Allow Count value as 4. So at the end of the day, it exactly allows only 5 invalid pin calls per day per user.

LookUpCache

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LookupCache async="false" continueOnError="false" enabled="true" name="LC-GetIncrementedValue">
    <DisplayName>LC-GetIncrementedValue</DisplayName>
    <Properties/>
    <CacheKey>
        <Prefix>some-unique-prefix</Prefix>
        <KeyFragment ref="request.header.username"/>
    </CacheKey>
    <Scope>Exclusive</Scope>
    <AssignTo>count</AssignTo>
</LookupCache>

PopulateCache

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PopulateCache async="false" continueOnError="false" enabled="true" name="PC-StoreIncrementedCount">
    <DisplayName>PC-StoreIncrementedCount</DisplayName>
    <Properties/>
    <CacheKey>
        <Prefix>some-unique-prefix</Prefix>
        <KeyFragment ref="request.header.username"/>
    </CacheKey>
    <Scope>Exclusive</Scope>
    <ExpirySettings>
        <TimeoutInSec>86400</TimeoutInSec>
    </ExpirySettings>
    <Source>calloutResponse.content</Source>
</PopulateCache>

In Fault Rules, I have added conditions to match the Quota Violation Error and SC Error and send out separate error responses and status codes.

For Invalid Pins Status Code 400 -

9976-invalid-pin-username-sid.png

For Quota Error Status Code 429 -

9977-invalid-pin-username-sid-quota-error.png

Trace -

With ref to my proxy code, the first call with code=200 would give 200OK, if user sends code=400 it would give FIVE 400 errors from FaultRules and the SIXTH call with code=400 would raise Quota Violation error.

9979-trace.png

PFA Proxy for your reference. incrementcounter-rev3-2020-06-08.zip

Curl - Use a different username and change code to 200 for success and 400 for error(invalidPin) scenarios.

curl -X GET \
  https://onlineman477-eval-test.apigee.net/counter/validate \
  -H 'code: 200' \
  -H 'username: Mike'

Thank you for your reply. However I'm wondering what happens if the user inserted a correct PIN. Will the number also increment?

I'm also still not sure if Quota Policy has a limitation in the number of keys that are saved. Most examples seem to have keys per client_id. However, what if your production had 100 thousand users, can Quota Policy save 100 thousand keys? I looked everywhere but can't see anything about the limitation, just examples that make me worried about the consequences of using it in this purpose.

Yes, actually I have missed this point. I guess we need to use KVM to track the number of failed attempts. Let me revise this proxy.

Please try the attached proxy, I have only tested few cases, please test it and let me know if you find any issues.

 what happens if the user inserted a correct PIN. Will the number also increment?
<br>

No this will not increment the number.

Test -

Curl - Use a different username and change code to 200 for success and 400 for error(invalidPin) scenarios.

curl -X GET \
  https://onlineman477-eval-test.apigee.net/counter/validate \-H 'code: 200' \
  -H 'username: Mike'

incrementcounter-rev6-2020-06-08-1.zip

Thank you for the update, it may move me to the right direction. However, there are two things I'm concerned at here:

1- When I checked the KVM after a value got deleted, I saw something like __$$_EDGE_KVM_EMPTY_KEY_$$__

2- I'm not sure why KVM was used. Why not depend solely on Apigee Caching? I could Get, Delete, Update on the cache, without the KVM. Actually, in your example, we're saving on both KVM and Cache. Right?

sidd-harth
Participant V

Hi Ghassan Barghouti, I have revised the proxy and removed KVMs and JS. I was able to restrict invalid attempts to exactly 5 attempts per user per day just by using Quota and Cache Policies.

If the user inserted a correct PIN, the number will not increment. After 5 Invalid attempts in a day, the user will not be able to make another attempt for a day.

I have used a single Quota policy in both ResourceFlow and FaultRules. It is an Apigee Quota Reuse Antipattern. It is an anti-pattern, but it works for your scenario. You can read more on it here,

https://docs.apigee.com/api-platform/antipatterns/reusing-quota

Give it a try with the attached proxy. incrementcounter-rev8-2020-06-09.zip

My Trace with 3 different users, rename it to .xml - trace-1591697362363xml.txt

9993-trace2.png

 However, what if your production had 100 thousand users, can Quota Policy save 100 thousand keys? I looked everywhere but can't see anything about the limitation

Well nothing is mentioned in the Limits page, https://docs.apigee.com/api-platform/reference/limits

All configurations are stored in Cassandra and I guess it can handle it or maybe @Dino-at-Google can help us with this.

For testing you can stick with the earlier CURL - Use a different username and change code to 200 for success and 400 for error(invalidPin) scenarios.

curl -X GET \
  https://onlineman477-eval-test.apigee.net/counter/validate \-H 'code: 200' \
  -H 'username: Foochika'


curl -X GET \
  https://onlineman477-eval-test.apigee.net/counter/validate \-H 'code: 400' \
  -H 'username: Foochika'

Thank you. I'll look at tit and let you know.