metricq / aiocouch

🛋 An asynchronous client library for CouchDB 2.x and 3.x
https://aiocouch.readthedocs.io/en/latest/
BSD 3-Clause "New" or "Revised" License
29 stars 10 forks source link

403 due to lockout on CouchDB v3.4.0 and above #55

Open H--o-l opened 4 weeks ago

H--o-l commented 4 weeks ago

Hey!

Since CouchDB v3.4.0, there has been a new "Lockout" feature, i.e., a rate limit on tuples (IP, login) after multiple authentication failures. It's highlighted in the release note: https://docs.couchdb.org/en/stable/whatsnew/3.4.html#id4 (see the second to last bullet point).

As the following upstream discussion shows, this adds a new case of HTTP 403 possible on all routes: https://github.com/apache/couchdb/issues/5315#issuecomment-2427009998

I was going to add the case in aiocouch, in remote.py, to return clean aiocouch Python exceptions on these 403, but I noticed that there are already a few 403 caught and raise for other cases inside remote.py.

I wanted your idea on the best way to add the new HTTP 403 lockout case on all the routes before making a PR.

For info, CouchDB return looks like this:

$ http localhost:5984 --auth login:wrong_password
HTTP/1.1 403 Forbidden
Cache-Control: must-revalidate
Content-Length: 103
Content-Type: application/json
Date: Wed, 23 Oct 2024 10:19:19 GMT
Server: CouchDB
X-Couch-Request-ID: cb6518342c
X-CouchDB-Body-Time: 0

{
    "error": "forbidden",
    "reason": "Account is temporarily locked due to multiple authentication failures"
}
bmario commented 4 weeks ago

Given the situation, I think a good way forward is to use the decorator like this @raises(403, "Access forbidden: {reason}") and add reason to message_input here, which should be parseable from the ClientResponseError.message.