-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Implement BasicAuth decode classmethod. #744
Conversation
raise ValueError('Unknown authorization method %s' % split[0]) | ||
to_decode = split[1] | ||
elif len(split) == 1: | ||
to_decode = split[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this case exists?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because https://github.com/rdegges/python-basicauth implements it. Happy to remove it if you want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be better strict to the specification where auth scheme is mandatory. Unlikely Authorization: Zm9vOmJhcg==
will be a valid basic auth header.
337346e
to
27a5feb
Compare
27a5feb
to
ef0e9f7
Compare
I want have a real use case anyway. |
So I can implement Basic Auth on my server. auth = BasicAuth.decode(request.headers['Authorization'])
if not (auth.login == 'admin' and auth.password == 'password123'):
raise HTTPForbidden(reason='Go away, hacker!') |
@luhn sounds good. |
Done. |
Almost perfect from my side but @kxepal are you ok with PR's functionality? |
header = self.headers.get(_AUTHORIZATION) | ||
if header is not None: | ||
try: | ||
return BasicAuth.decode(header) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is the trick:
>>> header = 'basic aGVsbG860LzQuNGAIQ=='
>>> auth = BasicAuth.decode(header)
>>> auth.password
'миÑ\x80!
'>>> bytearray([ord(i) for i in auth.password]).decode('utf-8')
'мир!'
So, unfortunately, this method will work correctly until you stay in latin1 name space. If your users will be allowed to have unicode wide password, they'll have to reimplement it. Somehow you'll have to inject encoding here. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could remain encoding-neutral and have BasicAuth store login and password as bytes rather than strings.
Or we could assume UTF-8, since it is fairly universal these days. Also, the latest update on HTTP Basic Auth defines a charset
field, but UTF-8
is the only allowed value (seems silly), so UTF-8 doesn't seem that bad of an assumption.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@luhn I would agree with that with happy, but you don't know how many services that works with the local national encoding by default (this includes latin1, cp1251, etc.) /:
The charset parameter you reference works only with the flow:
- Make request
- Receive HTTP 401 with WWW-Authenticate and that charset param
- Resend request with Authorization header where credentials respects previously mentioned charset
This means some interaction with the user and works perfectly with the browsers, but not with the libraries ):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Understood.
We could make authorization
a method instead of a property and have an encoding
argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suddenly, it seems so.
Or may be don't try to parse anything here and just return Authorization header as is. The more I'm thinking about the more I realize that to handle this header no matter for what auth scheme you need somehow interact with application config (for the encoding, secrets, hash algos etc.). The request eventually known nothing about these bits and it shouldn't. This will delegate parse task to user land where it's possible to do that correctly and without much hacks.
@asvetlov what do you think?
@asvetlov Basically, yes, but there are few edge cases. The |
Ok. Let's implement |
Hi guys, sorry for the delay, forgot about this PR. Is this what you wanted? |
header. | ||
|
||
:param auth_header: The value of the ``Authorization`` header. | ||
:type auth_header: str |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use :param str auth_header: ...
today, but aiohttp doesn't uses docstring in code, but separate files under doc/ directory.
LGFM except docs bit. |
How's that? |
I don't understand what it is you wish me to do. |
To clarify: I've already updated the docs in |
@luhn mmm...it seems I was look on some old commit then. Sorry for confusion, everything looks good for me. +1 |
Thanks! |
If you can encode, you should be able to decode.
Loosely based off of https://github.com/rdegges/python-basicauth, which is in the public domain.