Merge lp:~jimpop/mailman/security-logging into lp:mailman/2.1
- security-logging
- Merge into 2.1
Status: | Merged |
---|---|
Merged at revision: | 1768 |
Proposed branch: | lp:~jimpop/mailman/security-logging |
Merge into: | lp:mailman/2.1 |
Diff against target: |
121 lines (+37/-5) 7 files modified
Mailman/Cgi/admin.py (+5/-0) Mailman/Cgi/admindb.py (+5/-0) Mailman/Cgi/edithtml.py (+5/-0) Mailman/Cgi/options.py (+6/-4) Mailman/Cgi/private.py (+6/-0) Mailman/Cgi/roster.py (+5/-0) Mailman/Utils.py (+5/-1) |
To merge this branch: | bzr merge lp:~jimpop/mailman/security-logging |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mark Sapiro | Approve | ||
Jim Popovitch (community) | Needs Resubmitting | ||
Review via email: mp+347728@code.launchpad.net |
Commit message
Logging improvement for security related events (failed logins, etc.)
Description of the change
Jim Popovitch (jimpop) wrote : | # |
Mark Sapiro (msapiro) wrote : | # |
There are a couple of issues.
First, there is currently a log entry in mischief for an options page login failure, but only with private rosters. If we are going to be logging auth failures in a new security log, the options failure should be logged there too and unconditionally.
Second, the Changes to the owner notifications to add
text = "%s\nReason: %s" % (text, whence)
to the owner notifications for subscribe and unsubscribe are problematic. whence is not a 'Reason' and there is no i18n for 'Reason'
It would be better to just add whence as an additional replacement in the templates.
Finally, I don't see the need for this in the owner notices at all. This info is already in the subscribe log which I think is a better place for it.
- 1768. By Jim Popovitch
-
Changes based on feedback from Mark.
Jim Popovitch (jimpop) wrote : | # |
Thanks Mark,
The auth failure is now always logged to security in options.py, and the mischief log entry remains as was (logging only if private roster).
The only reason I put the whence in the owner notification emails is so that it is crystal clear to all the admins and moderators why a subscriber was added or removed, i.e. "bin/remove_
Mark Sapiro (msapiro) wrote : | # |
I added a NEWS item and fixed a few small issues.
Thanks for the contribution.
Mark Sapiro (msapiro) wrote : | # |
On 6/10/18 4:02 PM, Jim Popovitch wrote:
>
> The only reason I put the whence in the owner notification emails is so that it is crystal clear to all the admins and moderators why a subscriber was added or removed, i.e. "bin/remove_
I was confused. I forgot that whence was those things in these cases. I
was focused on its being an IP address. No that I realize what it is, I
think it's fine to add it to the notice, but making it a replacement for
the templates is the way to go.
--
Mark Sapiro <email address hidden> The highway is for gamblers,
San Francisco Bay Area, California better use your sense - B. Dylan
Jim Popovitch (jimpop) wrote : | # |
I've gone ahead and created the new branch for the whence templates. The chief problem for me at this point is making sure that the placement of $(whence) is grammatically correct in each template.
https:/
Mark Sapiro (msapiro) wrote : | # |
On 6/11/18 5:23 PM, Jim Popovitch wrote:
> I've gone ahead and created the new branch for the whence templates. The chief problem for me at this point is making sure that the placement of $(whence) is grammatically correct in each template.
>
> https:/
I understand the issue, and I wouldn't worry about it.
I'd say only do the 'en' templates and I'll post to mailman-i18n that
templates need to be updated to take advantage of this. There's no
problem if the template doesn't have %(whence)s in it.
My concerns are:
the 'en' adminsubscribea
and that doesn't seem to be provided.
There is no 'en' (or other) adminunsubscrib
--
Mark Sapiro <email address hidden> The highway is for gamblers,
San Francisco Bay Area, California better use your sense - B. Dylan
Jim Popovitch (jimpop) wrote : | # |
Thanks for pointing that out. I've re-pushed a complete new branch
with just the changes for the 2 "en" templates and MailList.py.
I left the branch as "Development" status (as opposed to Mature) for
now, and sent you a merge request.
Thanks!!
-Jim P.
Preview Diff
1 | === modified file 'Mailman/Cgi/admin.py' | |||
2 | --- Mailman/Cgi/admin.py 2017-06-21 16:59:41 +0000 | |||
3 | +++ Mailman/Cgi/admin.py 2018-06-10 23:02:31 +0000 | |||
4 | @@ -119,6 +119,11 @@ | |||
5 | 119 | if cgidata.has_key('adminpw'): | 119 | if cgidata.has_key('adminpw'): |
6 | 120 | # This is a re-authorization attempt | 120 | # This is a re-authorization attempt |
7 | 121 | msg = Bold(FontSize('+1', _('Authorization failed.'))).Format() | 121 | msg = Bold(FontSize('+1', _('Authorization failed.'))).Format() |
8 | 122 | remote = os.environ.get('HTTP_FORWARDED_FOR', | ||
9 | 123 | os.environ.get('HTTP_X_FORWARDED_FOR', | ||
10 | 124 | os.environ.get('REMOTE_ADDR', | ||
11 | 125 | 'unidentified origin'))) | ||
12 | 126 | syslog('security', 'Authorization failed (admin): list=%s: remote=%s', listname, remote) | ||
13 | 122 | else: | 127 | else: |
14 | 123 | msg = '' | 128 | msg = '' |
15 | 124 | Auth.loginpage(mlist, 'admin', msg=msg) | 129 | Auth.loginpage(mlist, 'admin', msg=msg) |
16 | 125 | 130 | ||
17 | === modified file 'Mailman/Cgi/admindb.py' | |||
18 | --- Mailman/Cgi/admindb.py 2017-06-24 21:34:48 +0000 | |||
19 | +++ Mailman/Cgi/admindb.py 2018-06-10 23:02:31 +0000 | |||
20 | @@ -159,6 +159,11 @@ | |||
21 | 159 | if cgidata.has_key('adminpw'): | 159 | if cgidata.has_key('adminpw'): |
22 | 160 | # This is a re-authorization attempt | 160 | # This is a re-authorization attempt |
23 | 161 | msg = Bold(FontSize('+1', _('Authorization failed.'))).Format() | 161 | msg = Bold(FontSize('+1', _('Authorization failed.'))).Format() |
24 | 162 | remote = os.environ.get('HTTP_FORWARDED_FOR', | ||
25 | 163 | os.environ.get('HTTP_X_FORWARDED_FOR', | ||
26 | 164 | os.environ.get('REMOTE_ADDR', | ||
27 | 165 | 'unidentified origin'))) | ||
28 | 166 | syslog('security', 'Authorization failed (admindb): list=%s: domain=%s', listname, remote) | ||
29 | 162 | else: | 167 | else: |
30 | 163 | msg = '' | 168 | msg = '' |
31 | 164 | Auth.loginpage(mlist, 'admindb', msg=msg) | 169 | Auth.loginpage(mlist, 'admindb', msg=msg) |
32 | 165 | 170 | ||
33 | === modified file 'Mailman/Cgi/edithtml.py' | |||
34 | --- Mailman/Cgi/edithtml.py 2017-06-06 05:47:05 +0000 | |||
35 | +++ Mailman/Cgi/edithtml.py 2018-06-10 23:02:31 +0000 | |||
36 | @@ -126,6 +126,11 @@ | |||
37 | 126 | if cgidata.has_key('admlogin'): | 126 | if cgidata.has_key('admlogin'): |
38 | 127 | # This is a re-authorization attempt | 127 | # This is a re-authorization attempt |
39 | 128 | msg = Bold(FontSize('+1', _('Authorization failed.'))).Format() | 128 | msg = Bold(FontSize('+1', _('Authorization failed.'))).Format() |
40 | 129 | remote = os.environ.get('HTTP_FORWARDED_FOR', | ||
41 | 130 | os.environ.get('HTTP_X_FORWARDED_FOR', | ||
42 | 131 | os.environ.get('REMOTE_ADDR', | ||
43 | 132 | 'unidentified origin'))) | ||
44 | 133 | syslog('security', 'Authorization failed (edithtml): list=%s: remote=%s', listname, remote) | ||
45 | 129 | else: | 134 | else: |
46 | 130 | msg = '' | 135 | msg = '' |
47 | 131 | Auth.loginpage(mlist, 'admin', msg=msg) | 136 | Auth.loginpage(mlist, 'admin', msg=msg) |
48 | 132 | 137 | ||
49 | === modified file 'Mailman/Cgi/options.py' | |||
50 | --- Mailman/Cgi/options.py 2018-02-04 16:41:19 +0000 | |||
51 | +++ Mailman/Cgi/options.py 2018-06-10 23:02:31 +0000 | |||
52 | @@ -288,13 +288,15 @@ | |||
53 | 288 | # message. | 288 | # message. |
54 | 289 | if cgidata.has_key('password'): | 289 | if cgidata.has_key('password'): |
55 | 290 | doc.addError(_('Authentication failed.')) | 290 | doc.addError(_('Authentication failed.')) |
56 | 291 | remote = os.environ.get('HTTP_FORWARDED_FOR', | ||
57 | 292 | os.environ.get('HTTP_X_FORWARDED_FOR', | ||
58 | 293 | os.environ.get('REMOTE_ADDR', | ||
59 | 294 | 'unidentified origin'))) | ||
60 | 295 | syslog('security', 'Authorization failed (private): user=%s | ||
61 | 296 | list=%s remote=%s', user, listname, remote) | ||
62 | 291 | # So as not to allow membership leakage, prompt for the email | 297 | # So as not to allow membership leakage, prompt for the email |
63 | 292 | # address and the password here. | 298 | # address and the password here. |
64 | 293 | if mlist.private_roster <> 0: | 299 | if mlist.private_roster <> 0: |
65 | 294 | remote = os.environ.get('HTTP_FORWARDED_FOR', | ||
66 | 295 | os.environ.get('HTTP_X_FORWARDED_FOR', | ||
67 | 296 | os.environ.get('REMOTE_ADDR', | ||
68 | 297 | 'unidentified origin'))) | ||
69 | 298 | syslog('mischief', | 300 | syslog('mischief', |
70 | 299 | 'Login failure with private rosters: %s from %s', | 301 | 'Login failure with private rosters: %s from %s', |
71 | 300 | user, remote) | 302 | user, remote) |
72 | 301 | 303 | ||
73 | === modified file 'Mailman/Cgi/private.py' | |||
74 | --- Mailman/Cgi/private.py 2017-06-06 05:47:05 +0000 | |||
75 | +++ Mailman/Cgi/private.py 2018-06-10 23:02:31 +0000 | |||
76 | @@ -142,6 +142,12 @@ | |||
77 | 142 | if cgidata.has_key('submit'): | 142 | if cgidata.has_key('submit'): |
78 | 143 | # This is a re-authorization attempt | 143 | # This is a re-authorization attempt |
79 | 144 | message = Bold(FontSize('+1', _('Authorization failed.'))).Format() | 144 | message = Bold(FontSize('+1', _('Authorization failed.'))).Format() |
80 | 145 | remote = os.environ.get('HTTP_FORWARDED_FOR', | ||
81 | 146 | os.environ.get('HTTP_X_FORWARDED_FOR', | ||
82 | 147 | os.environ.get('REMOTE_ADDR', | ||
83 | 148 | 'unidentified origin'))) | ||
84 | 149 | syslog('security', 'Authorization failed (private): user=%s list=%s | ||
85 | 150 | remote=%s', username, listname, remote) | ||
86 | 145 | # give an HTTP 401 for authentication failure | 151 | # give an HTTP 401 for authentication failure |
87 | 146 | print 'Status: 401 Unauthorized' | 152 | print 'Status: 401 Unauthorized' |
88 | 147 | # Are we processing a password reminder from the login screen? | 153 | # Are we processing a password reminder from the login screen? |
89 | 148 | 154 | ||
90 | === modified file 'Mailman/Cgi/roster.py' | |||
91 | --- Mailman/Cgi/roster.py 2017-06-06 03:48:34 +0000 | |||
92 | +++ Mailman/Cgi/roster.py 2018-06-10 23:02:31 +0000 | |||
93 | @@ -118,6 +118,11 @@ | |||
94 | 118 | error_page_doc(doc, _('%(realname)s roster authentication failed.')) | 118 | error_page_doc(doc, _('%(realname)s roster authentication failed.')) |
95 | 119 | doc.AddItem(mlist.GetMailmanFooter()) | 119 | doc.AddItem(mlist.GetMailmanFooter()) |
96 | 120 | print doc.Format() | 120 | print doc.Format() |
97 | 121 | remote = os.environ.get('HTTP_FORWARDED_FOR', | ||
98 | 122 | os.environ.get('HTTP_X_FORWARDED_FOR', | ||
99 | 123 | os.environ.get('REMOTE_ADDR', | ||
100 | 124 | 'unidentified origin'))) | ||
101 | 125 | syslog('security', 'Authorization failed (roster): list=%s: remote=%s', listname, remote) | ||
102 | 121 | return | 126 | return |
103 | 122 | 127 | ||
104 | 123 | # The document and its language | 128 | # The document and its language |
105 | 124 | 129 | ||
106 | === modified file 'Mailman/Utils.py' | |||
107 | --- Mailman/Utils.py 2018-06-05 19:14:08 +0000 | |||
108 | +++ Mailman/Utils.py 2018-06-10 23:02:31 +0000 | |||
109 | @@ -111,7 +111,11 @@ | |||
110 | 111 | # But first ensure the list name doesn't contain a path traversal | 111 | # But first ensure the list name doesn't contain a path traversal |
111 | 112 | # attack. | 112 | # attack. |
112 | 113 | if len(re.sub(mm_cfg.ACCEPTABLE_LISTNAME_CHARACTERS, '', listname)) > 0: | 113 | if len(re.sub(mm_cfg.ACCEPTABLE_LISTNAME_CHARACTERS, '', listname)) > 0: |
114 | 114 | syslog('mischief', 'Hostile listname: %s', listname) | 114 | remote = os.environ.get('HTTP_FORWARDED_FOR', |
115 | 115 | os.environ.get('HTTP_X_FORWARDED_FOR', | ||
116 | 116 | os.environ.get('REMOTE_ADDR', | ||
117 | 117 | 'unidentified origin'))) | ||
118 | 118 | syslog('mischief', 'Hostile listname: listname=%s remote=%s', listname, remote) | ||
119 | 115 | return False | 119 | return False |
120 | 116 | basepath = Site.get_listpath(listname) | 120 | basepath = Site.get_listpath(listname) |
121 | 117 | for ext in ('.pck', '.pck.last', '.db', '.db.last'): | 121 | for ext in ('.pck', '.pck.last', '.db', '.db.last'): |
Here's a patch that logs security related events (failed logins, etc).