Exemple #1
0
 def _curl_perform(self, curl, header, more_headers=[]):
     """Perform curl operation and translate exceptions."""
     try:
         # There's no way in http/1.0 to say "must
         # revalidate"; we don't want to force it to always
         # retrieve.  so just turn off the default Pragma
         # provided by Curl.
         headers = [
             'Cache-control: max-age=0', 'Pragma: no-cache',
             'Connection: Keep-Alive'
         ]
         curl.setopt(pycurl.HTTPHEADER, headers + more_headers)
         curl.perform()
     except pycurl.error, e:
         url = curl.getinfo(pycurl.EFFECTIVE_URL)
         trace.mutter('got pycurl error: %s, %s, %s, url: %s ', e[0], e[1],
                      e, url)
         if e[0] in (
                 CURLE_COULDNT_RESOLVE_HOST,
                 CURLE_COULDNT_RESOLVE_PROXY,
                 CURLE_COULDNT_CONNECT,
                 CURLE_FTP_WEIRD_SERVER_REPLY,
                 CURLE_GOT_NOTHING,
                 CURLE_SSL_CACERT,
                 CURLE_SSL_CACERT_BADFILE,
         ):
             raise errors.ConnectionError(
                 'curl connection error (%s)\non %s' % (e[1], url))
         elif e[0] == CURLE_RECV_ERROR:
             raise errors.ConnectionReset(
                 'curl connection error (%s)\non %s' % (e[1], url))
         elif e[0] == CURLE_PARTIAL_FILE:
             # Pycurl itself has detected a short read.  We do not have all
             # the information for the ShortReadvError, but that should be
             # enough
             raise errors.ShortReadvError(
                 url,
                 offset='unknown',
                 length='unknown',
                 actual='unknown',
                 extra='Server aborted the request')
         raise
Exemple #2
0
        supported_auth_types = e.allowed_types
    except paramiko.SSHException, e:
        # Don't know what happened, but just ignore it
        pass
    # We treat 'keyboard-interactive' and 'password' auth methods identically,
    # because Paramiko's auth_password method will automatically try
    # 'keyboard-interactive' auth (using the password as the response) if
    # 'password' auth is not available.  Apparently some Debian and Gentoo
    # OpenSSH servers require this.
    # XXX: It's possible for a server to require keyboard-interactive auth that
    # requires something other than a single password, but we currently don't
    # support that.
    if ('password' not in supported_auth_types
            and 'keyboard-interactive' not in supported_auth_types):
        raise errors.ConnectionError('Unable to authenticate to SSH host as'
                                     '\n  %s@%s\nsupported auth types: %s' %
                                     (username, host, supported_auth_types))

    if password:
        try:
            paramiko_transport.auth_password(username, password)
            return
        except paramiko.SSHException, e:
            pass

    # give up and ask for a password
    password = auth.get_password('ssh', host, username, port=port)
    # get_password can still return None, which means we should not prompt
    if password is not None:
        try:
            paramiko_transport.auth_password(username, password)
class LaunchpadService(object):
    """A service to talk to Launchpad via XMLRPC.

    See http://wiki.bazaar.canonical.com/Specs/LaunchpadRpc for the methods we can call.
    """

    LAUNCHPAD_DOMAINS = {
        'production': 'launchpad.net',
        'staging': 'staging.launchpad.net',
        'qastaging': 'qastaging.launchpad.net',
        'demo': 'demo.launchpad.net',
        'dev': 'launchpad.dev',
    }

    # NB: these should always end in a slash to avoid xmlrpclib appending
    # '/RPC2'
    LAUNCHPAD_INSTANCE = {}
    for instance, domain in LAUNCHPAD_DOMAINS.iteritems():
        LAUNCHPAD_INSTANCE[instance] = 'https://xmlrpc.%s/bazaar/' % domain

    # We use production as the default because edge has been deprecated circa
    # 2010-11 (see bug https://bugs.launchpad.net/bzr/+bug/583667)
    DEFAULT_INSTANCE = 'production'
    DEFAULT_SERVICE_URL = LAUNCHPAD_INSTANCE[DEFAULT_INSTANCE]

    transport = None
    registrant_email = None
    registrant_password = None

    def __init__(self, transport=None, lp_instance=None):
        """Construct a new service talking to the launchpad rpc server"""
        self._lp_instance = lp_instance
        if transport is None:
            uri_type = urllib.splittype(self.service_url)[0]
            transport = XMLRPCTransport(uri_type)
            transport.user_agent = 'bzr/%s (xmlrpclib/%s)' \
                    % (_bzrlib_version, xmlrpclib.__version__)
        self.transport = transport

    @property
    def service_url(self):
        """Return the http or https url for the xmlrpc server.

        This does not include the username/password credentials.
        """
        key = 'BZR_LP_XMLRPC_URL'
        if key in os.environ:
            return os.environ[key]
        elif self._lp_instance is not None:
            try:
                return self.LAUNCHPAD_INSTANCE[self._lp_instance]
            except KeyError:
                raise InvalidLaunchpadInstance(self._lp_instance)
        else:
            return self.DEFAULT_SERVICE_URL

    @classmethod
    def for_url(cls, url, **kwargs):
        """Return the Launchpad service corresponding to the given URL."""
        result = urlsplit(url)
        lp_instance = result[1]
        if lp_instance == '':
            lp_instance = None
        elif lp_instance not in cls.LAUNCHPAD_INSTANCE:
            raise errors.InvalidURL(path=url)
        return cls(lp_instance=lp_instance, **kwargs)

    def get_proxy(self, authenticated):
        """Return the proxy for XMLRPC requests."""
        if authenticated:
            # auth info must be in url
            # TODO: if there's no registrant email perhaps we should
            # just connect anonymously?
            scheme, hostinfo, path = urlsplit(self.service_url)[:3]
            if '@' in hostinfo:
                raise AssertionError(hostinfo)
            if self.registrant_email is None:
                raise AssertionError()
            if self.registrant_password is None:
                raise AssertionError()
            # TODO: perhaps fully quote the password to make it very slightly
            # obscured
            # TODO: can we perhaps add extra Authorization headers
            # directly to the request, rather than putting this into
            # the url?  perhaps a bit more secure against accidentally
            # revealing it.  std66 s3.2.1 discourages putting the
            # password in the url.
            hostinfo = '%s:%s@%s' % (urlutils.quote(
                self.registrant_email), urlutils.quote(
                    self.registrant_password), hostinfo)
            url = urlunsplit((scheme, hostinfo, path, '', ''))
        else:
            url = self.service_url
        return xmlrpclib.ServerProxy(url, transport=self.transport)

    def gather_user_credentials(self):
        """Get the password from the user."""
        the_config = config.GlobalConfig()
        self.registrant_email = the_config.user_email()
        if self.registrant_password is None:
            auth = config.AuthenticationConfig()
            scheme, hostinfo = urlsplit(self.service_url)[:2]
            prompt = 'launchpad.net password for %s: ' % \
                    self.registrant_email
            # We will reuse http[s] credentials if we can, prompt user
            # otherwise
            self.registrant_password = auth.get_password(scheme,
                                                         hostinfo,
                                                         self.registrant_email,
                                                         prompt=prompt)

    def send_request(self, method_name, method_params, authenticated):
        proxy = self.get_proxy(authenticated)
        method = getattr(proxy, method_name)
        try:
            result = method(*method_params)
        except xmlrpclib.ProtocolError, e:
            if e.errcode == 301:
                # TODO: This can give a ProtocolError representing a 301 error, whose
                # e.headers['location'] tells where to go and e.errcode==301; should
                # probably log something and retry on the new url.
                raise NotImplementedError(
                    "should resend request to %s, but this isn't implemented" %
                    e.headers.get('Location', 'NO-LOCATION-PRESENT'))
            else:
                # we don't want to print the original message because its
                # str representation includes the plaintext password.
                # TODO: print more headers to help in tracking down failures
                raise errors.BzrError(
                    "xmlrpc protocol error connecting to %s: %s %s" %
                    (self.service_url, e.errcode, e.errmsg))
        except socket.gaierror, e:
            raise errors.ConnectionError("Could not resolve '%s'" %
                                         self.domain,
                                         orig_error=e)
Exemple #4
0
        return

    if password:
        try:
            paramiko_transport.auth_password(username, password)
            return
        except paramiko.SSHException, e:
            pass

    # give up and ask for a password
    password = auth.get_password('ssh', host, username, port=port)
    try:
        paramiko_transport.auth_password(username, password)
    except paramiko.SSHException, e:
        raise errors.ConnectionError(
            'Unable to authenticate to SSH host as %s@%s' % (username, host),
            e)


def _try_pkey_auth(paramiko_transport, pkey_class, username, filename):
    filename = os.path.expanduser('~/.ssh/' + filename)
    try:
        key = pkey_class.from_private_key_file(filename)
        paramiko_transport.auth_publickey(username, key)
        return True
    except paramiko.PasswordRequiredException:
        password = ui.ui_factory.get_password(
            prompt='SSH %(filename)s password', filename=filename)
        try:
            key = pkey_class.from_private_key_file(filename, password)
            paramiko_transport.auth_publickey(username, key)