def ensure_not_weakly_authenticated(signed_msg, context,
                                    error_template='not-signed.txt'):
    """Make sure that the current principal is not weakly authenticated.

    NB: While handling an email, the authentication state is stored partly in
    properties of the message object, and partly in the current security
    principal.  As a consequence this function will only work correctly if the
    message has just been passed through authenticateEmail -- you can't give
    it an arbitrary message object.
    """
    cur_principal = get_current_principal()
    # The security machinery doesn't know about
    # IWeaklyAuthenticatedPrincipal yet, so do a manual
    # check. Later we can rely on the security machinery to
    # cause Unauthorized errors.
    if IWeaklyAuthenticatedPrincipal.providedBy(cur_principal):
        if signed_msg.signature is None:
            error_message = get_error_message(
                NOT_SIGNED_TEMPLATE, None, context=context)
        else:
            import_url = canonical_url(
                getUtility(ILaunchBag).user) + '/+editpgpkeys'
            error_message = get_error_message(
                NO_KEY_TEMPLATE, None, import_url=import_url, context=context)
        raise IncomingEmailError(error_message)
Exemple #2
0
 def test_clearsigned_message(self):
     # The test keys belong to Sample Person.
     sender = getUtility(IPersonSet).getByEmail('*****@*****.**')
     msg = self._get_clearsigned_for_person(sender)
     principle = authenticateEmail(msg)
     self.assertIsNot(None, msg.signature)
     self.assertEqual(sender, principle.person)
     self.assertFalse(IWeaklyAuthenticatedPrincipal.providedBy(principle))
Exemple #3
0
 def test_detached_signature_message(self):
     # Test a detached correct signature.
     sender = getUtility(IPersonSet).getByEmail('*****@*****.**')
     msg = self._get_detached_message_for_person(sender)
     principle = authenticateEmail(msg)
     self.assertIsNot(None, msg.signature)
     self.assertEqual(sender, principle.person)
     self.assertFalse(IWeaklyAuthenticatedPrincipal.providedBy(principle))
 def test_require_strong_email_authentication_and_signed(self):
     sender = getUtility(IPersonSet).getByEmail('*****@*****.**')
     sender.require_strong_email_authentication = True
     msg = self._get_clearsigned_for_person(sender)
     principal = authenticateEmail(msg)
     self.assertIsNot(None, msg.signature)
     self.assertEqual(sender, principal.person)
     self.assertFalse(IWeaklyAuthenticatedPrincipal.providedBy(principal))
Exemple #5
0
 def test_clearsigned_message_wrong_sender(self):
     # If the message is signed, but the key doesn't belong to the sender,
     # the principle is set to the sender, but weakly authenticated.
     sender = self.factory.makePerson()
     msg = self._get_clearsigned_for_person(sender)
     principle = authenticateEmail(msg)
     self.assertIsNot(None, msg.signature)
     self.assertEqual(sender, principle.person)
     self.assertTrue(IWeaklyAuthenticatedPrincipal.providedBy(principle))
 def test_clearsigned_message(self):
     # The test keys belong to Sample Person.
     sender = getUtility(IPersonSet).getByEmail('*****@*****.**')
     msg = self._get_clearsigned_for_person(sender)
     principle = authenticateEmail(msg)
     self.assertIsNot(None, msg.signature)
     self.assertEqual(sender, principle.person)
     self.assertFalse(
         IWeaklyAuthenticatedPrincipal.providedBy(principle))
 def test_detached_signature_message(self):
     # Test a detached correct signature.
     sender = getUtility(IPersonSet).getByEmail('*****@*****.**')
     msg = self._get_detached_message_for_person(sender)
     principle = authenticateEmail(msg)
     self.assertIsNot(None, msg.signature)
     self.assertEqual(sender, principle.person)
     self.assertFalse(
         IWeaklyAuthenticatedPrincipal.providedBy(principle))
 def test_clearsigned_message_wrong_sender(self):
     # If the message is signed, but the key doesn't belong to the sender,
     # the principle is set to the sender, but weakly authenticated.
     sender = self.factory.makePerson()
     msg = self._get_clearsigned_for_person(sender)
     principle = authenticateEmail(msg)
     self.assertIsNot(None, msg.signature)
     self.assertEqual(sender, principle.person)
     self.assertTrue(
         IWeaklyAuthenticatedPrincipal.providedBy(principle))
Exemple #9
0
 def test_trailing_whitespace(self):
     # Trailing whitespace should be ignored when verifying a message's
     # signature.
     sender = getUtility(IPersonSet).getByEmail('*****@*****.**')
     body = ('A message with trailing spaces.   \n'
             'And tabs\t\t\n'
             'Also mixed. \t ')
     msg = self._get_clearsigned_for_person(sender, body)
     principle = authenticateEmail(msg)
     self.assertIsNot(None, msg.signature)
     self.assertEqual(sender, principle.person)
     self.assertFalse(IWeaklyAuthenticatedPrincipal.providedBy(principle))
Exemple #10
0
 def test_unsigned_message(self):
     # An unsigned message will not have a signature nor signed content,
     # and generates a weakly authenticated principle.
     sender = self.factory.makePerson()
     email_message = self.factory.makeEmailMessage(sender=sender)
     msg = signed_message_from_string(email_message.as_string())
     self.assertIs(None, msg.signedContent)
     self.assertIs(None, msg.signature)
     principle = authenticateEmail(msg)
     self.assertEqual(sender, principle.person)
     self.assertTrue(IWeaklyAuthenticatedPrincipal.providedBy(principle))
     self.assertIs(None, msg.signature)
Exemple #11
0
def authenticateEmail(mail, signature_timestamp_checker=None):
    """Authenticates an email by verifying the PGP signature.

    The mail is expected to be an ISignedMessage.

    If this completes, it will set the current security principal to be the
    message sender.

    :param signature_timestamp_checker: This callable is
        passed the message signature timestamp, and it can raise an exception
        if it dislikes it (for example as a replay attack.)  This parameter is
        intended for use in tests.  If None, ensure_sane_signature_timestamp
        is used.
    """

    log = logging.getLogger('process-mail')
    authutil = getUtility(IPlacelessAuthUtility)

    principal, dkim_trusted_address = _getPrincipalByDkim(mail)
    if dkim_trusted_address is None:
        from_addr = parseaddr(mail['From'])[1]
        try:
            principal = authutil.getPrincipalByLogin(from_addr)
        except TypeError:
            # The email isn't valid, so don't authenticate
            principal = None

    if principal is None:
        setupInteraction(authutil.unauthenticatedPrincipal())
        return None

    person = IPerson(principal, None)
    if person.account_status != AccountStatus.ACTIVE:
        raise InactiveAccount("Mail from a user with an inactive account.")

    if dkim_trusted_address:
        log.debug('accepting dkim strongly authenticated mail')
        setupInteraction(principal, dkim_trusted_address)
    else:
        log.debug("attempt gpg authentication for %r" % person)
        principal = _gpgAuthenticateEmail(mail, principal, person,
                                          signature_timestamp_checker)

    if (IWeaklyAuthenticatedPrincipal.providedBy(principal)
            and person.require_strong_email_authentication):
        import_url = canonical_url(getUtility(ILaunchBag).user,
                                   view_name='+editpgpkeys')
        error_message = get_error_message('person-requires-signature.txt',
                                          import_url=import_url)
        raise IncomingEmailError(error_message)

    return principal
 def test_unsigned_message(self):
     # An unsigned message will not have a signature nor signed content,
     # and generates a weakly authenticated principle.
     sender = self.factory.makePerson()
     email_message = self.factory.makeEmailMessage(sender=sender)
     msg = signed_message_from_string(email_message.as_string())
     self.assertIs(None, msg.signedContent)
     self.assertIs(None, msg.signature)
     principle = authenticateEmail(msg)
     self.assertEqual(sender, principle.person)
     self.assertTrue(
         IWeaklyAuthenticatedPrincipal.providedBy(principle))
     self.assertIs(None, msg.signature)
 def test_trailing_whitespace(self):
     # Trailing whitespace should be ignored when verifying a message's
     # signature.
     sender = getUtility(IPersonSet).getByEmail('*****@*****.**')
     body = (
         'A message with trailing spaces.   \n'
         'And tabs\t\t\n'
         'Also mixed. \t ')
     msg = self._get_clearsigned_for_person(sender, body)
     principle = authenticateEmail(msg)
     self.assertIsNot(None, msg.signature)
     self.assertEqual(sender, principle.person)
     self.assertFalse(
         IWeaklyAuthenticatedPrincipal.providedBy(principle))
 def assertWeaklyAuthenticated(self, principal, signed_message):
     if not IWeaklyAuthenticatedPrincipal.providedBy(principal):
         self.fail('expected weak authentication; got strong:\n'
             + self.get_dkim_log() + '\n\n' + signed_message)