Page MenuHomePhabricator

ValueError when using OAuth on HTTPS sites
Closed, ResolvedPublic

Description

OAuth mechanism of Pywikibot works well on HTTP sites, but ValueError is raised when enabling OAuth authentication on HTTPS sites.

https://travis-ci.org/VcamX/pywikibot-core/jobs/74350129#L379

Test a Page instance as parameter using ASCII chars. ... ERROR: Traceback (most recent call last):
  File "/home/travis/build/VcamX/pywikibot-core/pywikibot/data/api.py", line 1912, in submit
    body=body, headers=headers)
  File "/home/travis/build/VcamX/pywikibot-core/tests/utils.py", line 414, in request
    result = self.__wrapper._old_http.request(*args, **kwargs)
  File "/home/travis/build/VcamX/pywikibot-core/pywikibot/tools/__init__.py", line 1245, in wrapper
    return obj(*__args, **__kw)
  File "/home/travis/build/VcamX/pywikibot-core/pywikibot/comms/http.py", line 243, in request
    r = fetch(baseuri, method, body, headers, **kwargs)
  File "/home/travis/build/VcamX/pywikibot-core/pywikibot/comms/http.py", line 393, in fetch
    error_handling_callback(request)
  File "/home/travis/build/VcamX/pywikibot-core/pywikibot/comms/http.py", line 310, in error_handling_callback
    raise request.data
ValueError: GET/HEAD requests should not include body.

Workaround

The workaround is not to use GET when OAuth enabled. This is fixed since PS17 for T102602.

Event Timeline

VcamX raised the priority of this task from to Needs Triage.
VcamX updated the task description. (Show Details)
VcamX added a project: Pywikibot-OAuth.
VcamX added subscribers: VcamX, jayvdb, XZise.
XZise set Security to None.

So the workaround is to not use GET when oauth is available.

Do we know why the bug is happening? oauth is adding a body to the GET request? Is that a bug in mwoauth?

I can confirm that it's not a bug in mwoauth. It about how oauthlib and requests-oauth deal with it.
Our login request with OAuth will end up to the following branch in requests-oauthlib:

...
if is_form_encoded:
    r.headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED
    r.url, headers, r.body = self.client.sign(
        unicode(r.url), unicode(r.method), r.body or '', r.headers)
elif self.force_include_body:
    ...

Note that r.body or'' in self.client.sign, which mean this parameter will be '' instead of r.body since r.body is None here.

In function sign of oauthlib:

def sign(self, uri, http_method='GET', body=None, headers=None, realm=None):
    # normalize request data
    request = Request(uri, http_method, body, headers,
                      encoding=self.encoding)
    ...
    has_params = request.decoded_body is not None
    ...
    elif http_method.upper() in ('GET', 'HEAD') and has_params:
        raise ValueError('GET/HEAD requests should not include body.')
    ...

Note that if body is None for request, request.decoded_body can't work since it'll decode None.
So I have to say it's about the way oauthlib deal with request.decoded_body.

VcamX updated the task description. (Show Details)