Search code examples
pythoncharacter-encodingcherrypybasic-authentication

CherryPy allways decodes Basic Auth with ISO-8859-1


Is there a way to configure cherrypy to correctly decode utf-8 encoded authentication strings?

Update

It's know limitation documented in issue #1680.

Until the issue is resolved, CherryPy will not recognize UTF-8 encoded Basic-Auth Data.

Original Problem

I have trouble using basic-auth with name/passwords using umlaut characters. There seem to be no way to either bring the http-client to issue ISO-8859-1 (which cherrypy would unterstand) name:password or to configure cherrypy to decode the authentication string using utf-8.

Using Python 3.6 and CherryPy 13.1.0:

import cherrypy

class SimpleWebpage(object):
    @cherrypy.expose
    def index(self):
        return "<html><head></head><body>Authenticated</body></html>"

def dummy_validate(realm, username, password):
    print("realm: {realm!r}, username: {username!r}, password: {password!r}".format_map(locals()))
    return True

cherrypy.tree.mount(SimpleWebpage(), '/',
                    {'/': {'tools.auth_basic.checkpassword': dummy_validate,
                           'tools.auth_basic.on': True,
                           'tools.auth_basic.realm': 'MY_REALM',}})

cherrypy.config.update({'tools.sessions.on': True,})

cherrypy.engine.autoreload.unsubscribe()
cherrypy.engine.start()
cherrypy.engine.block()

Calling curl with the following arguments:

curl -u 'Céline:motörhead' -i -X GET http://127.0.0.1:8080/

Will give the following output from the cherrypy console:

[28/Dec/2017:15:52:57] ENGINE Bus STARTING
[28/Dec/2017:15:52:57] ENGINE Serving on http://127.0.0.1:8080
[28/Dec/2017:15:52:57] ENGINE Bus STARTED
realm: 'MY_REALM', username: 'Céline', password: 'motörhead'
127.0.0.1 - C\xc3\x83\xc2\xa9line [28/Dec/2017:15:53:18] "GET / HTTP/1.1" 200 52 "" "Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; en-US))"

Tested with curl 7.56.1 (i686-pc-cygwin) on cygwin and curl 7.19.7 (x86_64-redhat-linux-gnu) on redhat6. I've also tested it with google-chrome 63.0.3239.108 with the exact same results.

Kludge

def decode_utf8(s):
    s_bytes = bytes([ord(c) for c in s])
    return s_bytes.decode('utf-8')

def dummy_validate(realm, username, password):
    username = decode_utf8(username)
    password = decode_utf8(password)
    print("realm: {realm!r}, username: {username!r}, password: {password!r}".format_map(locals()))
    return True

Using this code will gives me correct results with google-chrome and curl. But it won't work with (as an example) Firefox 57.0.2 (32-Bit) on Windows 10 which sends ISO-8851-15 encoded string.

Also this doesn't fix the cherrypy.request.login value.


Solution

  • Update (22nd of April, 2018):

    Since CherryPy v14.2.0 auth_basic and auth_digest tools support RFC 7617 to the extent supported by HTTP clients (browsers), which tend to send corrupted data in some cases.

    Old answer:

    As @webKnjaZ has approved in the comments, this is a bug which either needs to be resolve within CherryPy or cheroot.

    I consider the question as answered. Further progress the concerning bug can be tracked on the corresponding CherryPy-Issue.