-
-
Notifications
You must be signed in to change notification settings - Fork 745
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
auth_username_field
clobbering client-supplied filter
#77
auth_username_field
clobbering client-supplied filter
#77
Conversation
Yeah nice catch @bcattle ! Like the update but it took me a little while to grasp what it was doing, so I re-wrote your code in the way that I personally thought it through logically. Would love to know what you think of this one. My rationale for this slight layout modification: I find that the code is easier to break down logically if it first handles the standard condition and then considers the tricky conditions / exceptions (like when the username_field exists in the query and then when the field is an ObjectId).
|
Good call, I like the idea of handling the most common case first. But the ternary operator was confusing to me. How about this? if username_field not in query:
query.update({username_field: request.authorization.username})
else:
# If the username_field *replaces* a field in the query,
# and the two values are different, deny the request
if query[username_field] != request.authorization.username:
# If `auth_username_field` is ID_FIELD,
# also perform an ObjectId comparison
if username_field != config.ID_FIELD or \
query[username_field] != ObjectId(request.authorization.username):
abort(401) |
The part that confused me the most with your version was the sub-check. Your description says "If auth_username_field is ID_FIELD...", but your code describes something very different, which is more like "If auth_username_field is not ID_FIELD or ...". In order to mentally parse that line, you have to move from the first nonequivalence check down to the abort statement then up to the second check, etc. How about this?
Also, what are you using to make your code look different than mine? |
The only problem is that the Prefix your code with three backticks and the name of the language to turn on syntax highlighting, see here. |
Updated: if username_field not in query:
query.update({username_field: request.authorization.username})
else:
# If the username_field *replaces* a field in the query,
# and the two values are different, deny the request
if username_field == config.ID_FIELD and \
query[username_field] != ObjectId(request.authorization.username):
abort(401)
elif query[username_field] != request.authorization.username:
abort(401) And thanks for the tip :) |
Here's another option. IMO it's a little more elegant, but slightly more verbose. Also, it has a try except to catch the case when def smart_compare(a, b):
""" Compares a and b. A special case is handled where a is an ObjectId
but b is a string representation of an ObjectId. """
if isinstance(a, ObjectId):
try:
return a == ObjectId(b)
except:
return False
else:
return a == b
if username_field not in query:
query.update({username_field: request.authorization.username})
else:
# If the username_field *replaces* a field in the query,
# and the two values are different, deny the request
if not smart_compare(query[username_field], request.authorization.username):
abort(401) |
Interesting idea but we don't want to test for the validity of
Also you shouldn't do |
Good catch! We'll sort this out once #73 is fixed (soon enough - have it on a local branch already). |
It's relevant if anyone would ever perform a filter on |
Not necessarily and |
@bcattle good call |
… the results of the refactoring performed in pyeve#73. Added new methods to `eve.io.mongo`: `_convert_query_objectids`, `combine_queries`, `get_value_from_query`, and `query_contains_field`.
Superceded by #104 |
There is a conflict when
auth_username_field
is defined and the client provides a filter affecting that same field. The issue is thatauth_username_field
adds a new filter criteria, e.g.{'username': 'bcattle'}
. This criteria replaces any filter criteria supplied by the client (io/base.py line 188):Hence if I was trying to look up
/profiles/nicolaiarocci/
withauth_username_field='username'
and myusername==bcattle
, internally Eve callsfindOne()
which returns/profiles/bcattle/
rather than failing.On an update the request will then fail with HTTP 412, because the ETag I supplied for
/profiles/nicolaiarocci/
fails to validate. This is the problem - the wrong error code is getting reported.I added a special case to check for this conflict. Unfortunately the logic is convoluted. If
auth_username_field=='_id'
we also need to perform anObjectId()
comparison:Does this logic seem reasonable?
This code may change with the fix proposed by @nicolaiarocci in #73 here. I'll write tests once that shakes out.
cc @rxl @asdine