Merge lp:~mvo/aptdaemon/use-apt-auth.conf into lp:aptdaemon

Proposed by Michael Vogt on 2012-03-05
Status: Merged
Merged at revision: 777
Proposed branch: lp:~mvo/aptdaemon/use-apt-auth.conf
Merge into: lp:aptdaemon
Diff against target: 112 lines (+61/-12)
2 files modified
aptdaemon/worker.py (+36/-12)
tests/test_worker.py (+25/-0)
To merge this branch: bzr merge lp:~mvo/aptdaemon/use-apt-auth.conf
Reviewer Review Type Date Requested Status
Michael Vogt Resubmit on 2012-03-08
Martin Pitt (community) 2012-03-05 Needs Fixing on 2012-03-08
Review via email: mp+95892@code.launchpad.net

Description of the Change

This branch moves all username/password data from a repository into /etc/apt/auth.conf

To post a comment you must log in.
lp:~mvo/aptdaemon/use-apt-auth.conf updated on 2012-03-06
779. By Michael Vogt on 2012-03-06

add a comment when credentials are moved

Martin Pitt (pitti) wrote :

nitpick:

> comment += " ;credentials put into /etc/apt/auth.conf"

This should be "; credentials ..."

> + res = urlsplit(uri)

Do we need to be concerned about exceptions here? or does the code already ensure that this is a valid URL? Is there any test case which runs that with an invalid URL, and one with a passwordless one?

Does netrc need any quoting if the password contains a space? I suppose that the URL is already encoded (i. e. %20), just making sure that this is handled.

58 + try:
59 + uid = gid = 0
60 + os.chown(auth_conf_path, uid, gid)
61 + os.chmod(auth_conf_path, 0640)

I think that's fine when creating the file. But I wouldn't change the permissions if it already exists; if the admin configures it to be writable for some sub-admin group we should respect that IMHO.

Seems ok to me otherwise.

review: Needs Fixing
Michael Vogt (mvo) wrote :

Thanks for your review!

I fixed the issues you mentioned in r780.

review: Resubmit
lp:~mvo/aptdaemon/use-apt-auth.conf updated on 2012-03-08
780. By Michael Vogt on 2012-03-08

fix review comments from Martin Pitt: a) typo fix b) do not chmod/chown but instead set umask c) check for exceptions in splituri()

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'aptdaemon/worker.py'
2--- aptdaemon/worker.py 2012-03-08 04:58:28 +0000
3+++ aptdaemon/worker.py 2012-03-08 19:50:25 +0000
4@@ -445,13 +445,14 @@
5 sourcesfile = os.path.join(dir, os.path.basename(sourcesfile))
6 else:
7 sourcesfile = None
8- # if there is a password in the uri, protect the file from
9- # non-admin users
10+ # if there is a password in the uri move it into the auth.conf
11 password_in_uri = re.match("(http|https|ftp)://\S+?:\S+?@\S+", uri)
12 if password_in_uri:
13- old_umask = os.umask(0027)
14- else:
15- old_umask = os.umask(0022)
16+ uri = self._update_auth_conf_and_get_passwordless_uri(uri)
17+ if not comment:
18+ comment = "credentials put into /etc/apt/auth.conf"
19+ else:
20+ comment += " ; credentials put into /etc/apt/auth.conf"
21 try:
22 sources = SourcesList()
23 entry = sources.add(src_type, uri, dist, comps, comment,
24@@ -464,15 +465,38 @@
25 raise
26 else:
27 sources.save()
28- # set to sourcesfile root.admin only if there is a password
29- if password_in_uri and sourcesfile:
30- import grp
31- try:
32- os.chown(sourcesfile, 0, grp.getgrnam("admin")[2])
33- except Exception as e:
34- logging.warn("os.chmod() failed '%s'" % e)
35+
36+ def _update_auth_conf_and_get_passwordless_uri(self, uri):
37+ """Add the credentials in uri to /etc/apt/auth.conf
38+ and return the uri passwordless
39+ """
40+ from urlparse import urlsplit, urlunsplit
41+ try:
42+ res = urlsplit(uri)
43+ except ValueError as e:
44+ logging.warn("failed to urlsplit '%s'" % uri)
45+ return uri
46+ # split into bits and clean netloc
47+ scheme = res.scheme
48+ netloc = res.netloc.replace("%s:%s@" % (res.username, res.password), "")
49+ path = res.path
50+ query = res.query
51+ fragment = res.fragment
52+ # write auth.conf with tight default permissions
53+ old_umask = os.umask(0027)
54+ try:
55+ auth_conf_path = apt.apt_pkg.config.FindFile("Dir::etc::netrc")
56+ auth_conf = open(auth_conf_path, "a")
57+ auth_conf.write("""machine %s
58+login %s
59+password %s\n\n""" % (netloc+path, res.username, res.password))
60+ auth_conf.close()
61+ except OSError as e:
62+ logging.warn("writing auth.conf: '%s'" % e)
63 finally:
64 os.umask(old_umask)
65+ # return uri without user/pass
66+ return urlunsplit((scheme, netloc, path, query, fragment))
67
68 def add_vendor_key_from_keyserver(self, trans, keyid, keyserver):
69 """Add the signing key from the given (keyid, keyserver) to the
70
71=== modified file 'tests/test_worker.py'
72--- tests/test_worker.py 2012-01-23 10:32:24 +0000
73+++ tests/test_worker.py 2012-03-08 19:50:25 +0000
74@@ -25,6 +25,7 @@
75 import glob
76 import os
77 import shutil
78+import stat
79 import sys
80 import unittest
81
82@@ -409,6 +410,30 @@
83 self.assertEqual(license_key, open(verify_path).read(),
84 "Content of license key doesn't match")
85
86+ def test_use_apt_auth_conf(self):
87+ from mock import Mock
88+ source_file_name = "private_source.list"
89+ self.worker.add_repository(
90+ Mock(), "deb", "https://user:pass@host.example.com/path",
91+ "natty", ["main"], "comment", source_file_name)
92+ # check source file
93+ source_file = os.path.join(
94+ self.chroot.path, "etc", "apt", "sources.list.d", source_file_name)
95+ sources_file_content = open(source_file).read()
96+ #print sources_file_content
97+ self.assertFalse("user:pass" in open(source_file).read())
98+ # check auth file
99+ auth_file = os.path.join(
100+ self.chroot.path, "etc", "apt", "auth.conf")
101+ auth_content = open(auth_file).read()
102+ #print auth_content
103+ self.assertTrue("login user" in auth_content)
104+ self.assertTrue("password pass" in auth_content)
105+ self.assertTrue("machine host.example.com/path" in auth_content)
106+ buf=os.stat(auth_file)
107+ self.assertEqual(stat.S_IMODE(buf.st_mode), 0640)
108+
109+
110
111 if __name__ == "__main__":
112 unittest.main()

Subscribers

People subscribed via source and target branches

to status/vote changes: