Merge lp:~jimpop/mailman/security-logging into lp:mailman/2.1

Proposed by Jim Popovitch
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
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.)

To post a comment you must log in.
Revision history for this message
Jim Popovitch (jimpop) wrote :

Here's a patch that logs security related events (failed logins, etc).

Revision history for this message
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.

review: Needs Fixing
lp:~jimpop/mailman/security-logging updated
1768. By Jim Popovitch

Changes based on feedback from Mark.

Revision history for this message
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_member", "email confirmation", "web confirmation". It keeps a large mod team informed, as well as saving mods from having to ask "why was this person removed?". etc. I like the idea of integrating it in the templates, so I've removed it from this merge and I'll do a new merge request for that piece (and you can decide on that at that time).

review: Needs Resubmitting
Revision history for this message
Mark Sapiro (msapiro) wrote :

I added a NEWS item and fixed a few small issues.

Thanks for the contribution.

review: Approve
Revision history for this message
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_member", "email confirmation", "web confirmation". It keeps a large mod team informed, as well as saving mods from having to ask "why was this person removed?". etc. I like the idea of integrating it in the templates, so I've removed it from this merge and I'll do a new merge request for that piece (and you can decide on that at that time).

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

Revision history for this message
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://code.launchpad.net/~jimpop/mailman/owner-notification-whence

Revision history for this message
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://code.launchpad.net/~jimpop/mailman/owner-notification-whence

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' adminsubscribeack.txt template adds a %(method)s replacement
and that doesn't seem to be provided.

There is no 'en' (or other) adminunsubscribeack.txt template.

--
Mark Sapiro <email address hidden> The highway is for gamblers,
San Francisco Bay Area, California better use your sense - B. Dylan

Revision history for this message
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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 if cgidata.has_key('adminpw'):
6 # This is a re-authorization attempt
7 msg = Bold(FontSize('+1', _('Authorization failed.'))).Format()
8+ remote = os.environ.get('HTTP_FORWARDED_FOR',
9+ os.environ.get('HTTP_X_FORWARDED_FOR',
10+ os.environ.get('REMOTE_ADDR',
11+ 'unidentified origin')))
12+ syslog('security', 'Authorization failed (admin): list=%s: remote=%s', listname, remote)
13 else:
14 msg = ''
15 Auth.loginpage(mlist, 'admin', msg=msg)
16
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 if cgidata.has_key('adminpw'):
22 # This is a re-authorization attempt
23 msg = Bold(FontSize('+1', _('Authorization failed.'))).Format()
24+ remote = os.environ.get('HTTP_FORWARDED_FOR',
25+ os.environ.get('HTTP_X_FORWARDED_FOR',
26+ os.environ.get('REMOTE_ADDR',
27+ 'unidentified origin')))
28+ syslog('security', 'Authorization failed (admindb): list=%s: domain=%s', listname, remote)
29 else:
30 msg = ''
31 Auth.loginpage(mlist, 'admindb', msg=msg)
32
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 if cgidata.has_key('admlogin'):
38 # This is a re-authorization attempt
39 msg = Bold(FontSize('+1', _('Authorization failed.'))).Format()
40+ remote = os.environ.get('HTTP_FORWARDED_FOR',
41+ os.environ.get('HTTP_X_FORWARDED_FOR',
42+ os.environ.get('REMOTE_ADDR',
43+ 'unidentified origin')))
44+ syslog('security', 'Authorization failed (edithtml): list=%s: remote=%s', listname, remote)
45 else:
46 msg = ''
47 Auth.loginpage(mlist, 'admin', msg=msg)
48
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 # message.
54 if cgidata.has_key('password'):
55 doc.addError(_('Authentication failed.'))
56+ remote = os.environ.get('HTTP_FORWARDED_FOR',
57+ os.environ.get('HTTP_X_FORWARDED_FOR',
58+ os.environ.get('REMOTE_ADDR',
59+ 'unidentified origin')))
60+ syslog('security', 'Authorization failed (private): user=%s
61+ list=%s remote=%s', user, listname, remote)
62 # So as not to allow membership leakage, prompt for the email
63 # address and the password here.
64 if mlist.private_roster <> 0:
65- remote = os.environ.get('HTTP_FORWARDED_FOR',
66- os.environ.get('HTTP_X_FORWARDED_FOR',
67- os.environ.get('REMOTE_ADDR',
68- 'unidentified origin')))
69 syslog('mischief',
70 'Login failure with private rosters: %s from %s',
71 user, remote)
72
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 if cgidata.has_key('submit'):
78 # This is a re-authorization attempt
79 message = Bold(FontSize('+1', _('Authorization failed.'))).Format()
80+ remote = os.environ.get('HTTP_FORWARDED_FOR',
81+ os.environ.get('HTTP_X_FORWARDED_FOR',
82+ os.environ.get('REMOTE_ADDR',
83+ 'unidentified origin')))
84+ syslog('security', 'Authorization failed (private): user=%s list=%s
85+ remote=%s', username, listname, remote)
86 # give an HTTP 401 for authentication failure
87 print 'Status: 401 Unauthorized'
88 # Are we processing a password reminder from the login screen?
89
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 error_page_doc(doc, _('%(realname)s roster authentication failed.'))
95 doc.AddItem(mlist.GetMailmanFooter())
96 print doc.Format()
97+ remote = os.environ.get('HTTP_FORWARDED_FOR',
98+ os.environ.get('HTTP_X_FORWARDED_FOR',
99+ os.environ.get('REMOTE_ADDR',
100+ 'unidentified origin')))
101+ syslog('security', 'Authorization failed (roster): list=%s: remote=%s', listname, remote)
102 return
103
104 # The document and its language
105
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 # But first ensure the list name doesn't contain a path traversal
111 # attack.
112 if len(re.sub(mm_cfg.ACCEPTABLE_LISTNAME_CHARACTERS, '', listname)) > 0:
113- syslog('mischief', 'Hostile listname: %s', listname)
114+ remote = os.environ.get('HTTP_FORWARDED_FOR',
115+ os.environ.get('HTTP_X_FORWARDED_FOR',
116+ os.environ.get('REMOTE_ADDR',
117+ 'unidentified origin')))
118+ syslog('mischief', 'Hostile listname: listname=%s remote=%s', listname, remote)
119 return False
120 basepath = Site.get_listpath(listname)
121 for ext in ('.pck', '.pck.last', '.db', '.db.last'):