Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for KEYRING storage of the password of ROSDEP #895

Open
wants to merge 3 commits into
base: cottsay/auth_urls
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions doc/sources_list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ source first. The general format is::
URL should point to the HTTP location of a rosdep YAML file. URL
must contain an scheme (e.g. ``http://``), hostname, and path.

HTTPS locations are also supported with authentication. To add a remote server with
authentication to rosdep, you can specify the username and the password following
the ``https://username:password@url`` pattern that is also used by apt.

Since the passwords are stored in plain text and are readable by all users, you can
also use your operating system's keyring to protect the password. To do that, you
must specify the url by replacing your password with the literal ``KEYRING``
like so ``https://username:KEYRING@url``. Then you must manually
add your password on your keyring for your username on ``rosdep``.
You can do in python with::

import keyring
keyring.set_password("rosdep", "username", "password")


``tags``

Tags are optional. Currently, the OS name (e.g. ``ubuntu``), OS
Expand Down
30 changes: 27 additions & 3 deletions src/rosdep2/url_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,19 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

from __future__ import print_function

import base64
import sys
from gzip import GzipFile
from io import BytesIO
try:
from urllib.request import urlopen
from urllib.error import URLError
from urllib.parse import splituser
from urllib.parse import urlparse
from urllib.parse import urlunparse
import urllib.request as request
except ImportError:
from urllib2 import splituser
from urllib2 import urlopen
from urllib2 import URLError
import urllib2 as request
Expand All @@ -58,11 +59,34 @@ def urlopen_gzip(url, **kwargs):
'User-Agent': 'rosdep/{version}'.format(version=__version__),
})
if auth:
url_request.add_header('Authorization', b'Basic ' + base64.b64encode(auth.encode())[:-1])
if auth.endswith(":KEYRING"):
try:
import keyring
username = auth.split(":")[0]
password = keyring.get_password("rosdep", username)
auth = "{}:{}".format(username, password)
except ImportError:
print('Cannot import keyring, rosdep will not function properly with passwords stored in keyring',
file=sys.stderr)
if sys.version_info[0] >= 3:
base64string = base64.b64encode(auth.encode()).decode()
else:
base64string = base64.b64encode(auth)
auth_header = "Basic " + base64string
url_request.add_header('Authorization', auth_header)
response = urlopen(url_request, **kwargs)
if response.info().get('Content-Encoding') == 'gzip':
buffer = BytesIO(response.read())
return GzipFile(fileobj=buffer, mode='rb')
return response

return urlopen(url, **kwargs)


# copy of urllib.parse._splituser from Python 3.8
# This is required because no fully featured alternative has been provided since splituser was deprecated
# Reference: https://github.com/pypa/setuptools/pull/1670
def splituser(host):
"""splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'."""
user, delim, host = host.rpartition('@')
return (user if delim else None), host
8 changes: 8 additions & 0 deletions test/test_rosdep_sources_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,14 @@ def test_download_rosdep_data():
assert False, 'should have raised'
except DownloadFailure as e:
pass
# try with an authorized resource
try:
data = download_rosdep_data('https://username:[email protected]/rosdep.yaml')
assert False, 'should have raised'
except DownloadFailure as e:
pass
# Should also have a successful authorized resource test
# Is there such a service available publicly?


BADHOSTNAME_URL = 'https://badhostname.willowgarage.com/rosdep.yaml'
Expand Down