Are there any empty values to trick Python hashlib? - python

So I am working on Python FastAPI project.
My current objective is to correctly authenticate password so correct password should trigger HTTP 204 response code, in every other case (also empty params) HTTP 401 should be triggered.
The examples look like that:
Here the response should be: 204
/auth?password=haslo&password_hash=013c6889f799cd986a735118e1888727d1435f7f623d05d58c61bf2cd8b49ac90105e5786ceaabd62bbc27336153d0d316b2d13b36804080c44aa6198c533215
And here: 401
/auth?password=haslo&password_hash=f34ad4b3ae1e2cf33092e2abb60dc0444781c15d0e2e9ecdb37e4b14176a0164027b05900e09fa0f61a1882e0b89fbfa5dcfcc9765dd2ca4377e2c794837e091
I am correctly handling RequestValidationError, and my hashed password validation looks like this:
class AuthResponse(BaseModel):
status_code: int
#app.get("/auth", response_model=AuthResponse)
async def auth(password: str, password_hash: str, response: Response):
try:
m = hashlib.sha512(bytes(password, encoding="ASCII"))
if str(m.hexdigest()) == password_hash:
response.status_code = 204
else:
response.status_code = 401
except Exception:
response.status_code = 401
return AuthResponse(status_code=response.status_code)
Now I cannot think of any passed parameter that would trigger incorrect validation (passing 204 code instead of 401), but it seems that it is possible, as external assertion shows. I know it must be something about empty values other than None, but I can't figure it out by myself.
I have already tried patterns like:
/auth?password=&password_hash=
/auth?password=%00&password_hash=%00
http://127.0.0.1:8000/auth?password=%0&password_hash=%0
I would really appreciate some kind of help, hint or suggestion.

Thank you all, it is only a coding exercise project, so many things could be a little bit off. But as it happens I didn't check the empty password parameter which creates valid hash, but is not correct according to task.

Related

How to create a unit test in Python for specific code in pytest

I have the following function:
def update_installation_register(
remote: RemoteRegisterData, install_id: str, data: dict, verify: bool
) -> None:
"""Updates an Installation register"""
credentials = (remote.auth_user, remote.auth_pass)
url = f"https://{remote.hostname}/api/instalaciones/{install_id}/"
resp = requests.put(url=url, auth=credentials, json=data, verify=verify)
if resp.status_code != 200:
raise RemoteRegisterRequestError()
It's part of a existing codebase, and I'm trying to add unit test to it.
I am not figuring out how to create a simple test for it, maybe a test that checks return None if all goes well and to catch an exception if it does not?
I'm not sure how to mock that request, if I write a test_update_installation_register for pytest
I am willing to refactor the code if necessary, although I'd prefer to leave it the way it is,
I'm puzzled by how this simple function managed to confuse me this much, but there it is.
The thing is, and maybe this is the fundamental question... How do I test a function that is merely a simple wrapper to a http request, without actually testing the request?
This is the best I could come up with, but I'm not entirely sure this is the right approach
def test_update_installation_register_valid():
with requests_mock.Mocker() as mock:
remote_register = remote_register_data()
mock.put(
f"https://{remote_register.hostname}/api/instalaciones/{req_test_id()}/",
status_code=200,
)
resp = update_installation_register(
remote_register, req_test_id(), req_test_data(), verify=True
)
assert resp == None
where
remote_register_data()
req_test_id()
req_test_id()
req_test_data()
are just returning a hardcoded "test" value
Is this a good solution?

Spyne Fault - HTTP Return Codes

I have read information on Spyne Faults (http://spyne.io/docs/2.10/manual/03_types.html), but cant get my head around raising a Fault properly with a 400 Return code. I have the Fault response forming properly, but with a 500 HTTP return code when I have a requirement to return 400.
#srpc(Boolean, _returns=String)
def requestConfiguration(value):
#if value is true, get all the data
if value == True:
#todo - get the config
return 'True Received'
else:
# if anything other than True is received, MUST respond with a SOAP fault and HTTP 400
raise Fault(faultcode="Client.", faultstring="Value must be True")
# raise error.InvalidInputError("problem", "problem")
Reading some of the documentation (http://spyne.io/docs/2.10/modules/spyne/model/fault.html#Fault) , i am interpreting it as the FaultCode must be a string starting with Client and it will return a 400 error. (I know if-else is bad, im just trying to get a proof of concept working before i write the code up properly)
I think i need to subclass the fault instead of just raising it but cant get my head around it. I dived into the code /protocol/soap/soap11 and saw that the fault_to_http_reponse_code simply returns HTTP 500.
Thanks in advance
I gave up on the subclass approach, instead i just updated the fault_to_http_reponse_code function in soap11.py. Its a gross patch but it does the job for what i want.
def fault_to_http_response_code(self, fault):
from spyne.const.http import HTTP_400, HTTP_401, HTTP_404, HTTP_405, HTTP_413, HTTP_500
from spyne.error import Fault, InternalError, ResourceNotFoundError, RequestTooLongError, RequestNotAllowed, InvalidCredentialsError
if isinstance(fault, RequestTooLongError):
return HTTP_413
if isinstance(fault, ResourceNotFoundError):
return HTTP_404
if isinstance(fault, RequestNotAllowed):
return HTTP_405
if isinstance(fault, InvalidCredentialsError):
return HTTP_401
if isinstance(fault, Fault) and (fault.faultcode.startswith('Client.')
or fault.faultcode == 'Client'):
return HTTP_400
return HTTP_500
Then im just raising a normal fault, with the faultcode beginning with Client.
raise Fault(faultcode="Client.", faultstring="value must be True)
Hopfully someone will chip in with the proper approach to this.

Getting twitter friends number with Python

I need to get twitter friends from an user. With twitter "friends" I mean user A follows user B, and also user B follows A.
Ok, so my idea was getting a list of people who are followed by user A, and if they are followed by user B, it increases numFriends.
First part works fine, but when I do that second request it falls apart and throws me an ugly 'error 400' :(
I read about the restrictions of twitter and all that, but it seems weird that second request so I don't know if it's doing ok.
Thank you in advance, I'm a noob at python and twitter api, and my mother tongue is not english, so I really hope it is everything clear. I will thank any help about this.
Here is the code :)
def getNumFriends(user):
dataUser=0
numFriends=0
url ="https://api.twitter.com/1.1/friends/ids.json?cursor=-1&screen_name=%s&count=5000"%(user.screen_name)
auth = OAuth1(getConsumerKey(), getConsumerSecret(), getAccessToken(), getAccessTokenSecret())
response = requests.get(url, auth=auth)
if response.status_code == 200:
dataUser = response.json()
userIDs = dataUser['ids']
else:
print "Error code %s" %response.status_code
#Here comes the problem :S
for friend in userIDs:
url = "https://api.twitter.com/1.1/friendships/show.json?source_id=%s&target_screen_name=%s"%(friend, user)
response = requests.get(url, auth)
if response.status_code == 200:
dataCompare = response.json()
mutualfriends = dataCompare['relationship']['target']['followed_by']
if mutualfriends =='true':
numFriends=numFriends+1
else:
print "First request OK. Second request error code %s" %response.status_code
break
return numFriends
Your code is fine, there are only a couple of minor mistakes. The error code 400, "bad request", does not give you very concrete info, but it tells you that something in the way you've written the url is wrong.
It should be:
url = "https://api.twitter.com/1.1/friendships/show.json?source_id=%s&target_screen_name=%s"%(friend, user.screen_name)
i.e it should be user.screen_name instead of user.
Besides, the second argument of requests.get() is not auth, thus you should specify always the name of the argument,
response = requests.get(url, auth=auth)
which wasn't the case in your second call.
BTW, just curious, any reason why you are not using a library like twython?
Hope it helps.
** EDIT after comments: **
There was another minor mistake in the code. Note that your variable mutualfriends is already boolean, in order to check its value you can do it like this,
if mutualfriends:
...
BTW, to check the type of a variable,
print(type(mutualfriends))

Return text/html on exceptions

I was trying to modify the code example here but it seems that jsonify is making it hard... I did the following without jsonify:
#app.errorhandler(InvalidUsage)
def handle_invalid_usage(error):
response = error.to_dict()
response.status_code = error.status_code
return response
Originally, the third line was like:
response = jsonify(error.to_dict())
How can I make this work? I don't want to use JSON. Only text/html
Well, I presume that error.to_dict() returns a dict, which wouldn't have a status code attribute (it's just a regular old dict). You might try this instead:
#app.errorhandler(InvalidUsage)
def handle_invalid_usage(error):
response = error.to_dict()
response["status_code"] = error.status_code
return response
That said, it seems odd that the dictionary wouldn't already have the error code in it. Maybe a bit more detail on what what you are trying to accomplish would help? If you don't call the second-to-last line, and just return response, what do you see?

Picture property format using run with friends fb app

I am editing the Runwithfriends FB sample app to build one of my own. It was working fine and I was making a few changes here and there. I took a break from it for about a fortnight but now when I try to access the app, I get a strange python error:
C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\ROOT\app\main.py in init_facebook(self=<main.RecentRunsHandler object>)
316 user_id=facebook.user_id, friends=friends,
317 access_token=facebook.access_token, name=me[u'name'],
=> 318 email=me.get(u'email'), picture=me[u'picture'])
319 user.put()
320 except KeyError, ex:
<..some portion clipped..>
class 'google.appengine.api.datastore_errors.BadValueError'>: Property picture must be a str or unicode instance, not a dict
args = ('Property picture must be a str or unicode instance, not a dict',)
message = 'Property picture must be a str or unicode instance, not a dict'"
I know this is a very generic error but its pointing to the following code. This code has always been there and I have never touched it. I really do not know where else to look now - I have searched exhaustively but couldnt find a clue. Sorry, if this is still too broad but I would be glad if you can tell me what other info can I provide to debug this :-(
def init_facebook(self):
"""Sets up the request specific Facebook and User instance"""
facebook = Facebook()
user = None
# initial facebook request comes in as a POST with a signed_request
if u'signed_request' in self.request.POST:
facebook.load_signed_request(self.request.get('signed_request'))
# we reset the method to GET because a request from facebook with a
# signed_request uses POST for security reasons, despite it
# actually being a GET. in webapp causes loss of request.POST data.
self.request.method = u'GET'
self.set_cookie(
'u', facebook.user_cookie, datetime.timedelta(minutes=1440))
elif 'u' in self.request.cookies:
facebook.load_signed_request(self.request.cookies.get('u'))
# try to load or create a user object
if facebook.user_id:
user = User.get_by_key_name(facebook.user_id)
if user:
# update stored access_token
if facebook.access_token and \
facebook.access_token != user.access_token:
user.access_token = facebook.access_token
user.put()
# refresh data if we failed in doing so after a realtime ping
if user.dirty:
user.refresh_data()
# restore stored access_token if necessary
if not facebook.access_token:
facebook.access_token = user.access_token
if not user and facebook.access_token:
me = facebook.api(u'/me', {u'fields': _USER_FIELDS})
try:
friends = [user[u'id'] for user in me[u'friends'][u'data']]
user = User(key_name=facebook.user_id,
user_id=facebook.user_id, friends=friends,
access_token=facebook.access_token, name=me[u'name'],
email=me.get(u'email'), picture=me[u'picture'])
user.put()
except KeyError, ex:
pass # ignore if can't get the minimum fields
self.facebook = facebook
self.user = user
Might have to do with the October 2012 Breaking Changes, quote:
/picture connection will return a dictionary when a callback is specified
We will start returning a dictionary containing the fields url, height, width, and is_silhouette when accessing the /picture connection for an object and specifying a callback property. Currently we just return the picture URL as a string.
So at this point in your code, where you are currently using picture=me[u'picture'], try accessing the url property of the picture dictionary instead. (If it has one; I can’t tell you for sure if this is applicable, since I don’t know if your code would be considered as having specified a callback property.)
If my assumption is correct, you could also enable the migration as described in the roadmap; but that will only make your app work in the old way until Oct. 3rd, so probably better to try and fix it right away.
This is the way to get the picture:
picture=me[u'picture'][u'data'][u'url']

Categories

Resources