views:

253

answers:

1

The answer to a previous question showed that Nexus implement a custom authentication helper called "NxBASIC".

How do I begin to implement a handler in python?


Update:

Implementing the handler per Alex's suggestion looks to be the right approach, but fails trying to extract the scheme and realm from the authreq. The returned value for authreq is:

str: NxBASIC realm="Sonatype Nexus Repository Manager API""

AbstractBasicAuthHandler.rx.search(authreq) is only returning a single tuple:

tuple: ('NxBASIC', '"', 'Sonatype Nexus Repository Manager API')

so scheme,realm = mo.groups() fails. From my limited regex knowledge it looks like the standard regex from AbstractBasicAuthHandler should match scheme and realm, but it seems not to.

The regex is:

rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+'
                'realm=(["\'])(.*?)\\2', re.I)


Update 2: From inspection of AbstractBasicAuthHandler, the default processing is to do:

scheme, quote, realm = mo.groups()

Changing to this works. I now just need to set the password against the correct realm. Thanks Alex!

+1  A: 

If, as described, name and description are the only differences between this "NxBasic" and good old "Basic", then you could essentially copy-paste-edit some code from urllib2.py (which unfortunately doesn't expose the scheme name as easily overridable in itself), as follows (see urllib2.py's online sources):

import urllib2

class HTTPNxBasicAuthHandler(urllib2.HTTPBasicAuthHandler):

    def http_error_auth_reqed(self, authreq, host, req, headers):
        # host may be an authority (without userinfo) or a URL with an
        # authority
        # XXX could be multiple headers
        authreq = headers.get(authreq, None)
        if authreq:
            mo = AbstractBasicAuthHandler.rx.search(authreq)
            if mo:
                scheme, realm = mo.groups()
                if scheme.lower() == 'nxbasic':
                    return self.retry_http_basic_auth(host, req, realm)

    def retry_http_basic_auth(self, host, req, realm):
        user, pw = self.passwd.find_user_password(realm, host)
        if pw is not None:
            raw = "%s:%s" % (user, pw)
            auth = 'NxBasic %s' % base64.b64encode(raw).strip()
            if req.headers.get(self.auth_header, None) == auth:
                return None
            req.add_header(self.auth_header, auth)
            return self.parent.open(req)
        else:
            return None

As you can see by inspection, I've just changed two strings from "Basic" to "NxBasic" (and the lowercase equivalents) from what's in urrlib2.py (in the abstract basic auth handler superclass of the http basic auth handler class).

Try using this version -- and if it's still not working, at least having it be your code can help you add print/logging statements, breakpoints, etc, to better understand what's breaking and how. Best of luck! (Sorry I can't help further but I don't have any Nexus around to experiment with).

Alex Martelli
thanks Alex I will give this a try when I get to a proper computer
Rich Seller
no idea you only had improper ones -- well then, guess I'll just have to wait until you fix that before I hear whether this helps you or not!-)
Alex Martelli
access to a browser does not mean access to development tools (or approval from significant other to use them). It is helping, but please see my update for latest problem.
Rich Seller