comparison test/test_mailgw.py @ 4781:6e9b9743de89

Implementation for: http://issues.roundup-tracker.org/issue2550731 Add mechanism for the detectors to be able to tell the source of the data changes. Support for tx_Source property on database handle. Can be used by detectors to find out the source of a change in an auditor to block changes arriving by unauthenticated mechanisms (e.g. plain email where headers can be faked). The property db.tx_Source has the following values: * None - Default value set to None. May be valid if it's a script that is created by the user. Otherwise it's an error and indicates that some code path is not properly setting the tx_Source property. * "cli" - this string value is set when using roundup-admin and supplied scripts. * "web" - this string value is set when using any web based technique: html interface, xmlrpc .... * "email" - this string value is set when using an unauthenticated email based technique. * "email-sig-openpgp" - this string value is set when email with a valid pgp signature is used. (*NOTE* the testing for this mode is incomplete. If you have a pgp infrastructure you should test and verify that this is properly set.) This also includes some (possibly incomplete) tests cases for the modes above and an example of using ts_Source in the customization.txt document.
author John Rouillard <rouilj@ieee.org>
date Tue, 23 Apr 2013 23:06:09 -0400
parents 782737d1a2d7
children a850f8bae536
comparison
equal deleted inserted replaced
4774:3adff0fb0207 4781:6e9b9743de89
127 res.append('- %s'%l1[i]) 127 res.append('- %s'%l1[i])
128 res.append('+ %s'%l2[j]) 128 res.append('+ %s'%l2[j])
129 129
130 return res 130 return res
131 131
132 from roundup.hyperdb import String
133
132 class MailgwTestAbstractBase(unittest.TestCase, DiffHelper): 134 class MailgwTestAbstractBase(unittest.TestCase, DiffHelper):
133 count = 0 135 count = 0
134 schema = 'classic' 136 schema = 'classic'
135 def setUp(self): 137 def setUp(self):
136 self.old_translate_ = mailgw._ 138 self.old_translate_ = mailgw._
137 roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext 139 roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext
138 self.__class__.count = self.__class__.count + 1 140 self.__class__.count = self.__class__.count + 1
139 141
140 # and open the database / "instance" 142 # and open the database / "instance"
141 self.db = memorydb.create('admin') 143 self.db = memorydb.create('admin')
144
145 self.db.issue.addprop(tx_Source=String())
146 self.db.msg.addprop(tx_Source=String())
147 self.db.post_init()
148
149 self.db.tx_Source = "email"
150
142 self.instance = Tracker() 151 self.instance = Tracker()
143 self.instance.db = self.db 152 self.instance.db = self.db
144 self.instance.config = self.db.config 153 self.instance.config = self.db.config
145 self.instance.MailGW = MailGW 154 self.instance.MailGW = MailGW
146 155
204 Subject: [issue] Testing... 213 Subject: [issue] Testing...
205 214
206 ''') 215 ''')
207 assert not os.path.exists(SENDMAILDEBUG) 216 assert not os.path.exists(SENDMAILDEBUG)
208 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...') 217 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
218 self.assertEqual(self.db.issue.get(nodeid, 'tx_Source'), 'email')
209 219
210 220
211 class MailgwTestCase(MailgwTestAbstractBase): 221 class MailgwTestCase(MailgwTestAbstractBase):
212 222
213 def testMessageWithFromInIt(self): 223 def testMessageWithFromInIt(self):
318 nodeid = self._handle_mail(self.newmsg) 328 nodeid = self._handle_mail(self.newmsg)
319 assert not os.path.exists(SENDMAILDEBUG) 329 assert not os.path.exists(SENDMAILDEBUG)
320 l = self.db.issue.get(nodeid, 'nosy') 330 l = self.db.issue.get(nodeid, 'nosy')
321 l.sort() 331 l.sort()
322 self.assertEqual(l, [self.chef_id, self.richard_id]) 332 self.assertEqual(l, [self.chef_id, self.richard_id])
333
334 # check that the message has the right source code
335 l = self.db.msg.get('1', 'tx_Source')
336 self.assertEqual(l, 'email')
337
323 return nodeid 338 return nodeid
324 339
325 def testNewIssue(self): 340 def testNewIssue(self):
326 self.doNewIssue() 341 self.doNewIssue()
327 342
411 assignedto: richard 426 assignedto: richard
412 messages: 1 427 messages: 1
413 nosy: Chef, mary, richard 428 nosy: Chef, mary, richard
414 status: unread 429 status: unread
415 title: Testing... 430 title: Testing...
431 tx_Source: email
416 432
417 _______________________________________________________________________ 433 _______________________________________________________________________
418 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> 434 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
419 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> 435 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
420 _______________________________________________________________________ 436 _______________________________________________________________________
453 assignedto: richard 469 assignedto: richard
454 messages: 1 470 messages: 1
455 nosy: Chef, mary, richard 471 nosy: Chef, mary, richard
456 status: unread 472 status: unread
457 title: Testing... 473 title: Testing...
474 tx_Source: email
458 475
459 _______________________________________________________________________ 476 _______________________________________________________________________
460 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> 477 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
461 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> 478 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
462 _______________________________________________________________________ 479 _______________________________________________________________________
497 assignedto: richard 514 assignedto: richard
498 messages: 1 515 messages: 1
499 nosy: Chef, mary, richard 516 nosy: Chef, mary, richard
500 status: unread 517 status: unread
501 title: Testing... 518 title: Testing...
519 tx_Source: email
502 520
503 _______________________________________________________________________ 521 _______________________________________________________________________
504 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> 522 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
505 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> 523 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
506 _______________________________________________________________________ 524 _______________________________________________________________________
1193 X-Roundup-Name: Roundup issue tracker 1211 X-Roundup-Name: Roundup issue tracker
1194 X-Roundup-Loop: hello 1212 X-Roundup-Loop: hello
1195 X-Roundup-Issue-Status: chatting 1213 X-Roundup-Issue-Status: chatting
1196 Content-Transfer-Encoding: quoted-printable 1214 Content-Transfer-Encoding: quoted-printable
1197 1215
1198
1199 richard <richard@test.test> added the comment: 1216 richard <richard@test.test> added the comment:
1200 1217
1201 This is a followup 1218 This is a followup
1202 1219
1203 ---------- 1220 ----------
1227 ''') 1244 ''')
1228 l = self.db.issue.get('1', 'nosy') 1245 l = self.db.issue.get('1', 'nosy')
1229 l.sort() 1246 l.sort()
1230 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id, 1247 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1231 self.john_id]) 1248 self.john_id])
1249
1250 # check that the message has the right tx_Source
1251 l = self.db.msg.get('2', 'tx_Source')
1252 self.assertEqual(l, 'email')
1232 1253
1233 self.compareMessages(self._get_mail(), 1254 self.compareMessages(self._get_mail(),
1234 '''FROM: roundup-admin@your.tracker.email.domain.example 1255 '''FROM: roundup-admin@your.tracker.email.domain.example
1235 TO: chef@bork.bork.bork, john@test.test, mary@test.test 1256 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1236 Content-Type: text/plain; charset="utf-8" 1257 Content-Type: text/plain; charset="utf-8"
1245 X-Roundup-Name: Roundup issue tracker 1266 X-Roundup-Name: Roundup issue tracker
1246 X-Roundup-Loop: hello 1267 X-Roundup-Loop: hello
1247 X-Roundup-Issue-Status: chatting 1268 X-Roundup-Issue-Status: chatting
1248 Content-Transfer-Encoding: quoted-printable 1269 Content-Transfer-Encoding: quoted-printable
1249 1270
1250
1251 richard <richard@test.test> added the comment: 1271 richard <richard@test.test> added the comment:
1252 1272
1253 This is a followup 1273 This is a followup
1254 1274
1255 ---------- 1275 ----------
1263 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1> 1283 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1264 _______________________________________________________________________ 1284 _______________________________________________________________________
1265 ''') 1285 ''')
1266 1286
1267 def testNosyGeneration(self): 1287 def testNosyGeneration(self):
1288 self.db.tx_Source = "email"
1268 self.db.issue.create(title='test') 1289 self.db.issue.create(title='test')
1269 1290
1270 # create a nosy message 1291 # create a nosy message
1271 msg = self.db.msg.create(content='This is a test', 1292 msg = self.db.msg.create(content='This is a test',
1272 author=self.richard_id, messageid='<dummy_test_message_id>') 1293 author=self.richard_id, messageid='<dummy_test_message_id>')
1273 self.db.journaltag = 'richard' 1294 self.db.journaltag = 'richard'
1274 l = self.db.issue.create(title='test', messages=[msg], 1295 l = self.db.issue.create(title='test', messages=[msg],
1275 nosy=[self.chef_id, self.mary_id, self.john_id]) 1296 nosy=[self.chef_id, self.mary_id, self.john_id])
1297
1298
1299 # check that message has right tx_Source
1300 self.assertEqual(self.db.msg.get('1', 'tx_Source'), 'email')
1276 1301
1277 self.compareMessages(self._get_mail(), 1302 self.compareMessages(self._get_mail(),
1278 '''FROM: roundup-admin@your.tracker.email.domain.example 1303 '''FROM: roundup-admin@your.tracker.email.domain.example
1279 TO: chef@bork.bork.bork, john@test.test, mary@test.test 1304 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1280 Content-Type: text/plain; charset="utf-8" 1305 Content-Type: text/plain; charset="utf-8"
1298 ---------- 1323 ----------
1299 messages: 1 1324 messages: 1
1300 nosy: Chef, john, mary, richard 1325 nosy: Chef, john, mary, richard
1301 status: unread 1326 status: unread
1302 title: test 1327 title: test
1328 tx_Source: email
1303 1329
1304 _______________________________________________________________________ 1330 _______________________________________________________________________
1305 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example> 1331 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1306 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2> 1332 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
1307 _______________________________________________________________________ 1333 _______________________________________________________________________
1371 Message-Id: <followup_dummy_id> 1397 Message-Id: <followup_dummy_id>
1372 Subject: Re: Testing... [assignedto=mary; nosy=+john] 1398 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1373 1399
1374 This is a followup 1400 This is a followup
1375 ''') 1401 ''')
1402
1403 l = self.db.msg.get('2', 'tx_Source')
1404 self.assertEqual(l, 'email')
1405
1376 self.compareMessages(self._get_mail(), 1406 self.compareMessages(self._get_mail(),
1377 '''FROM: roundup-admin@your.tracker.email.domain.example 1407 '''FROM: roundup-admin@your.tracker.email.domain.example
1378 TO: chef@bork.bork.bork, john@test.test, mary@test.test 1408 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1379 Content-Type: text/plain; charset="utf-8" 1409 Content-Type: text/plain; charset="utf-8"
1380 Subject: [issue1] Testing... 1410 Subject: [issue1] Testing...
3388 def testPGPSignedMessage(self): 3418 def testPGPSignedMessage(self):
3389 nodeid = self._handle_mail(self.signed_msg) 3419 nodeid = self._handle_mail(self.signed_msg)
3390 m = self.db.issue.get(nodeid, 'messages')[0] 3420 m = self.db.issue.get(nodeid, 'messages')[0]
3391 self.assertEqual(self.db.msg.get(m, 'content'), 3421 self.assertEqual(self.db.msg.get(m, 'content'),
3392 'This is a pgp signed message.') 3422 'This is a pgp signed message.')
3423 # check that the message has the right source code
3424 l = self.db.msg.get(m, 'tx_Source')
3425 self.assertEqual(l, 'email-sig-openpgp')
3426
3393 3427
3394 def testPGPSignedMessageFail(self): 3428 def testPGPSignedMessageFail(self):
3395 # require both, signing and encryption 3429 # require both, signing and encryption
3396 self.instance.config['PGP_REQUIRE_INCOMING'] = 'both' 3430 self.instance.config['PGP_REQUIRE_INCOMING'] = 'both'
3397 self.assertRaises(MailUsageError, self._handle_mail, self.signed_msg) 3431 self.assertRaises(MailUsageError, self._handle_mail, self.signed_msg)
3439 self.instance.config['PGP_REQUIRE_INCOMING'] = 'encrypted' 3473 self.instance.config['PGP_REQUIRE_INCOMING'] = 'encrypted'
3440 nodeid = self._handle_mail (self.encrypted_msg) 3474 nodeid = self._handle_mail (self.encrypted_msg)
3441 m = self.db.issue.get(nodeid, 'messages')[0] 3475 m = self.db.issue.get(nodeid, 'messages')[0]
3442 self.assertEqual(self.db.msg.get(m, 'content'), 3476 self.assertEqual(self.db.msg.get(m, 'content'),
3443 'This is the text to be encrypted') 3477 'This is the text to be encrypted')
3478 # check that the message has the right source code
3479 l = self.db.msg.get(m, 'tx_Source')
3480 self.assertEqual(l, 'email')
3444 3481
3445 def testPGPEncryptedUnsignedMessageFromNonPGPUser(self): 3482 def testPGPEncryptedUnsignedMessageFromNonPGPUser(self):
3446 msg = self.encrypted_msg.replace('John Doe <john@test.test>', 3483 msg = self.encrypted_msg.replace('John Doe <john@test.test>',
3447 '"Contrary, Mary" <mary@test.test>') 3484 '"Contrary, Mary" <mary@test.test>')
3448 nodeid = self._handle_mail (msg) 3485 nodeid = self._handle_mail (msg)
3449 m = self.db.issue.get(nodeid, 'messages')[0] 3486 m = self.db.issue.get(nodeid, 'messages')[0]
3450 self.assertEqual(self.db.msg.get(m, 'content'), 3487 self.assertEqual(self.db.msg.get(m, 'content'),
3451 'This is the text to be encrypted') 3488 'This is the text to be encrypted')
3452 self.assertEqual(self.db.msg.get(m, 'author'), self.mary_id) 3489 self.assertEqual(self.db.msg.get(m, 'author'), self.mary_id)
3490 # check that the message has the right source code
3491 l = self.db.msg.get(m, 'tx_Source')
3492 self.assertEqual(l, 'email')
3493
3453 3494
3454 # check that a bounce-message that is triggered *after* 3495 # check that a bounce-message that is triggered *after*
3455 # decrypting is properly encrypted: 3496 # decrypting is properly encrypted:
3456 def testPGPEncryptedUnsignedMessageCheckBounce(self): 3497 def testPGPEncryptedUnsignedMessageCheckBounce(self):
3457 # allow non-signed msg 3498 # allow non-signed msg
3531 --ReaqsoxgOBHFXBhH-- 3572 --ReaqsoxgOBHFXBhH--
3532 ''') 3573 ''')
3533 m = self.db.issue.get(nodeid, 'messages')[0] 3574 m = self.db.issue.get(nodeid, 'messages')[0]
3534 self.assertEqual(self.db.msg.get(m, 'content'), 3575 self.assertEqual(self.db.msg.get(m, 'content'),
3535 'This is the text of a signed and encrypted email.') 3576 'This is the text of a signed and encrypted email.')
3536 3577 # check that the message has the right source code
3578 l = self.db.msg.get(m, 'tx_Source')
3579 self.assertEqual(l, 'email-sig-openpgp')
3537 3580
3538 def test_suite(): 3581 def test_suite():
3539 suite = unittest.TestSuite() 3582 suite = unittest.TestSuite()
3540 suite.addTest(unittest.makeSuite(MailgwTestCase)) 3583 suite.addTest(unittest.makeSuite(MailgwTestCase))
3541 if pyme is not None: 3584 if pyme is not None:

Roundup Issue Tracker: http://roundup-tracker.org/