Fix HTTP authentication support in the cp module

If you have a userinfo component in an RFC 3986 URI, the default
handling of the python urllibs is to complain about a non-numeric
port.

This fix handles the case where there is a userinfo component (e.g.
http://user:pass@server.name/path/to/file), parsing it out,
creating a basicauth handler, and passing url_open a url it can
understand.

FIXES Issue #5641
This commit is contained in:
Thomas L. Kula 2013-07-27 15:42:43 -04:00
parent 60728c72f7
commit 4f3639301f
2 changed files with 24 additions and 2 deletions

View File

@ -113,6 +113,7 @@ Python 2: If ``s`` is an instance of ``text_type``, return
if PY3:
# pylint: disable=E0611
from urllib.parse import urlparse
from urllib.parse import urlunparse
from urllib.error import URLError
import http.server as BaseHTTPServer
from urllib.error import HTTPError
@ -121,10 +122,15 @@ if PY3:
from urllib.parse import unquote as url_unquote
from urllib.parse import urlencode as url_encode
from urllib.request import urlopen as url_open
from urllib.request import HTTPPasswordMgrWithDefaultRealm as url_passwd_mgr
from urllib.request import HTTPBasicAuthHandler as url_auth_handler
from urllib.request import build_opener as url_build_opener
from urllib.request import install_opener as url_install_opener
url_unquote_text = url_unquote
url_unquote_native = url_unquote
else:
from urlparse import urlparse
from urlparse import urlunparse
import BaseHTTPServer
from urllib2 import HTTPError, URLError
from urllib import quote as url_quote
@ -132,6 +138,10 @@ else:
from urllib import unquote as url_unquote
from urllib import urlencode as url_encode
from urllib2 import urlopen as url_open
from urllib2 import HTTPPasswordMgrWithDefaultRealm as url_passwd_mgr
from urllib2 import HTTPBasicAuthHandler as url_auth_handler
from urllib2 import build_opener as url_build_opener
from urllib2 import install_opener as url_install_opener
def url_unquote_text(v, encoding='utf-8', errors='replace'):
v = url_unquote(v)
return v.decode(encoding, errors)

View File

@ -24,7 +24,8 @@ import salt.utils
import salt.utils.templates
import salt.utils.gzip_util
from salt._compat import (
URLError, HTTPError, BaseHTTPServer, urlparse, url_open)
URLError, HTTPError, BaseHTTPServer, urlparse, urlunparse, url_open,
url_passwd_mgr, url_auth_handler, url_build_opener, url_install_opener )
log = logging.getLogger(__name__)
@ -346,8 +347,19 @@ class Client(object):
destdir = os.path.dirname(dest)
if not os.path.isdir(destdir):
os.makedirs(destdir)
if url_data.username is not None:
_, netloc = url_data.netloc.split('@', 1)
fixed_url = urlunparse((url_data.scheme, netloc, url_data.path,
url_data.params, url_data.query, url_data.fragment ))
passwd_mgr = url_passwd_mgr()
passwd_mgr.add_password(None, fixed_url, url_data.username, url_data.password)
auth_handler = url_auth_handler(passwd_mgr)
opener = url_build_opener(auth_handler)
url_install_opener(opener)
else:
fixed_url = url
try:
with contextlib.closing(url_open(url)) as srcfp:
with contextlib.closing(url_open(fixed_url)) as srcfp:
with salt.utils.fopen(dest, 'wb') as destfp:
shutil.copyfileobj(srcfp, destfp)
return dest