def _login(self):
     """Setup an interaction as the Launchpad Janitor."""
     auth_utility = getUtility(IPlacelessAuthUtility)
     janitor_email = self.janitor.preferredemail.email
     setupInteraction(
         auth_utility.getPrincipalByLogin(janitor_email),
         login=janitor_email)
Esempio n. 2
0
def test_traverse(url):
    """Traverse the url in the same way normal publishing occurs.

    Returns a tuple of (object, view, request) where:
      object is the last model object in the traversal chain
      view is the defined view for the object at the specified url (if
        the url didn't directly specify a view, then the view is the
        default view for the object.
      request is the request object resulting from the traversal.  This
        contains a populated traversed_objects list just as a browser
        request would from a normal call into the app servers.

    This call uses the currently logged in user, and does not start a new
    transaction.
    """
    url_parts = urlsplit(url)
    server_url = '://'.join(url_parts[0:2])
    path_info = url_parts[2]
    request, publication = get_request_and_publication(
        host=url_parts[1], extra_environment={
            'SERVER_URL': server_url,
            'PATH_INFO': path_info})

    request.setPublication(publication)
    # We avoid calling publication.beforePublication because this starts a new
    # transaction, which causes an abort of the existing transaction, and the
    # removal of any created and uncommitted objects.

    # Set the default layer.
    adapters = getGlobalSiteManager().adapters
    layer = adapters.lookup((providedBy(request),), IDefaultSkin, '')
    if layer is not None:
        layers.setAdditionalLayer(request, layer)

    principal = get_current_principal()

    if IUnauthenticatedPrincipal.providedBy(principal):
        login = None
    else:
        login = principal.person
    setupInteraction(principal, login, request)

    getUtility(IOpenLaunchBag).clear()
    app = publication.getApplication(request)
    view = request.traverse(app)
    # Find the object from the view instead on relying that it stays
    # in the traversed_objects stack. That doesn't apply to the web
    # service for example.
    try:
        obj = removeSecurityProxy(view).context
    except AttributeError:
        # But sometime the view didn't store the context...
        # Use the last traversed object in these cases.
        obj = request.traversed_objects[-2]

    restoreInteraction()

    return obj, view, request
Esempio n. 3
0
    def _login(self):
        """Setup an interaction as the bug janitor.

        The role of bug janitor is usually played by bug_watch_updater.
        """
        auth_utility = getUtility(IPlacelessAuthUtility)
        janitor_email = self.janitor.preferredemail.email
        setupInteraction(auth_utility.getPrincipalByLogin(janitor_email),
                         login=janitor_email)
Esempio n. 4
0
    def _login(self):
        """Setup an interaction as the bug janitor.

        The role of bug janitor is usually played by bug_watch_updater.
        """
        auth_utility = getUtility(IPlacelessAuthUtility)
        janitor_email = self.janitor.preferredemail.email
        setupInteraction(
            auth_utility.getPrincipalByLogin(janitor_email),
            login=janitor_email)
Esempio n. 5
0
def _gpgAuthenticateEmail(mail, principal, person,
                          signature_timestamp_checker):
    """Check GPG signature.

    :param principal: Claimed sender of the mail; to be checked against
        the actual signature.
    :returns: principal, either strongly or weakly authenticated.
    """
    log = logging.getLogger('process-mail')
    signature = mail.signature
    email_addr = parseaddr(mail['From'])[1]
    if signature is None:
        # Mark the principal so that application code can check that the
        # user was weakly authenticated.
        log.debug('message has no signature; therefore weakly authenticated')
        directlyProvides(
            principal, directlyProvidedBy(principal),
            IWeaklyAuthenticatedPrincipal)
        setupInteraction(principal, email_addr)
        return principal

    gpghandler = getUtility(IGPGHandler)
    try:
        sig = gpghandler.getVerifiedSignature(
            canonicalise_line_endings(mail.signedContent), signature)
        log.debug("got signature %r" % sig)
    except GPGVerificationError as e:
        # verifySignature failed to verify the signature.
        message = "Signature couldn't be verified: %s" % e
        log.debug(message)
        raise InvalidSignature(message)

    if signature_timestamp_checker is None:
        signature_timestamp_checker = ensure_sane_signature_timestamp
    # If this fails, we return an error to the user rather than just treating
    # it as untrusted, so they can debug or understand the problem.
    signature_timestamp_checker(
        sig.timestamp,
        'incoming mail verification')

    for gpgkey in person.gpg_keys:
        if gpgkey.fingerprint == sig.fingerprint:
            log.debug('gpg-signed message by key %r' % gpgkey.fingerprint)
            break
    else:
        # The key doesn't belong to the user. Mark the principal so that the
        # application code knows that the key used to sign the email isn't
        # associated with the authenticated user.
        log.debug('gpg-signed message but by no known key of principal')
        directlyProvides(
            principal, directlyProvidedBy(principal),
            IWeaklyAuthenticatedPrincipal)

    setupInteraction(principal, email_addr)
    return principal
Esempio n. 6
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
Esempio n. 7
0
 def _zope_response(self):
     """Get the response."""
     current_principal = None
     # End and save the current interaction, since HTTPCaller creates
     # its own interaction.
     if queryInteraction():
         current_principal = get_current_principal()
         endInteraction()
     if self._response is None:
         self._response = self.caller(self._data_to_send)
     # Restore the interaction to what it was before.
     setupInteraction(current_principal)
     return self._response
Esempio n. 8
0
 def _zope_response(self):
     """Get the response."""
     current_principal = None
     # End and save the current interaction, since HTTPCaller creates
     # its own interaction.
     if queryInteraction():
         current_principal = get_current_principal()
         endInteraction()
     if self._response is None:
         self._response = self.caller(self._data_to_send)
     # Restore the interaction to what it was before.
     setupInteraction(current_principal)
     return self._response
Esempio n. 9
0
def _gpgAuthenticateEmail(mail, principal, person,
                          signature_timestamp_checker):
    """Check GPG signature.

    :param principal: Claimed sender of the mail; to be checked against
        the actual signature.
    :returns: principal, either strongly or weakly authenticated.
    """
    log = logging.getLogger('process-mail')
    signature = mail.signature
    email_addr = parseaddr(mail['From'])[1]
    if signature is None:
        # Mark the principal so that application code can check that the
        # user was weakly authenticated.
        log.debug('message has no signature; therefore weakly authenticated')
        directlyProvides(principal, directlyProvidedBy(principal),
                         IWeaklyAuthenticatedPrincipal)
        setupInteraction(principal, email_addr)
        return principal

    gpghandler = getUtility(IGPGHandler)
    try:
        sig = gpghandler.getVerifiedSignature(
            canonicalise_line_endings(mail.signedContent), signature)
        log.debug("got signature %r" % sig)
    except GPGVerificationError as e:
        # verifySignature failed to verify the signature.
        message = "Signature couldn't be verified: %s" % e
        log.debug(message)
        raise InvalidSignature(message)

    if signature_timestamp_checker is None:
        signature_timestamp_checker = ensure_sane_signature_timestamp
    # If this fails, we return an error to the user rather than just treating
    # it as untrusted, so they can debug or understand the problem.
    signature_timestamp_checker(sig.timestamp, 'incoming mail verification')

    for gpgkey in person.gpg_keys:
        if gpgkey.fingerprint == sig.fingerprint:
            log.debug('gpg-signed message by key %r' % gpgkey.fingerprint)
            break
    else:
        # The key doesn't belong to the user. Mark the principal so that the
        # application code knows that the key used to sign the email isn't
        # associated with the authenticated user.
        log.debug('gpg-signed message but by no known key of principal')
        directlyProvides(principal, directlyProvidedBy(principal),
                         IWeaklyAuthenticatedPrincipal)

    setupInteraction(principal, email_addr)
    return principal
Esempio n. 10
0
    def interaction(self):
        """Context manager for interaction as the given user.

        If an interaction is already in progress this is a no-op,
        otherwise it sets up an interaction on entry and ends it on
        exit.
        """
        if queryInteraction() is None:
            setupInteraction(self._principal, login=self._login)
            try:
                yield
            finally:
                endInteraction()
        else:
            yield
Esempio n. 11
0
    def interaction(self):
        """Context manager for interaction as the given user.

        If an interaction is already in progress this is a no-op,
        otherwise it sets up an interaction on entry and ends it on
        exit.
        """
        if queryInteraction() is None:
            setupInteraction(self._principal, login=self._login)
            try:
                yield
            finally:
                endInteraction()
        else:
            yield
Esempio n. 12
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)
        return principal
    else:
        log.debug("attempt gpg authentication for %r" % person)
        return _gpgAuthenticateEmail(mail, principal, person,
            signature_timestamp_checker)
Esempio n. 13
0
def test_traverse(url):
    """Traverse the url in the same way normal publishing occurs.

    Returns a tuple of (object, view, request) where:
      object is the last model object in the traversal chain
      view is the defined view for the object at the specified url (if
        the url didn't directly specify a view, then the view is the
        default view for the object.
      request is the request object resulting from the traversal.  This
        contains a populated traversed_objects list just as a browser
        request would from a normal call into the app servers.

    This call uses the currently logged in user, and does not start a new
    transaction.
    """
    url_parts = urlsplit(url)
    server_url = '://'.join(url_parts[0:2])
    path_info = url_parts[2]
    request, publication = get_request_and_publication(host=url_parts[1],
                                                       extra_environment={
                                                           'SERVER_URL':
                                                           server_url,
                                                           'PATH_INFO':
                                                           path_info
                                                       })

    request.setPublication(publication)
    # We avoid calling publication.beforePublication because this starts a new
    # transaction, which causes an abort of the existing transaction, and the
    # removal of any created and uncommitted objects.

    # Set the default layer.
    adapters = getGlobalSiteManager().adapters
    layer = adapters.lookup((providedBy(request), ), IDefaultSkin, '')
    if layer is not None:
        layers.setAdditionalLayer(request, layer)

    principal = get_current_principal()

    if IUnauthenticatedPrincipal.providedBy(principal):
        login = None
    else:
        login = principal.person
    setupInteraction(principal, login, request)

    getUtility(IOpenLaunchBag).clear()
    app = publication.getApplication(request)
    view = request.traverse(app)
    # Find the object from the view instead on relying that it stays
    # in the traversed_objects stack. That doesn't apply to the web
    # service for example.
    try:
        obj = removeSecurityProxy(view).context
    except AttributeError:
        # But sometime the view didn't store the context...
        # Use the last traversed object in these cases.
        obj = request.traversed_objects[-2]

    restoreInteraction()

    return obj, view, request
Esempio n. 14
0
 def _login(self):
     """Setup an interaction as the Launchpad Janitor."""
     auth_utility = getUtility(IPlacelessAuthUtility)
     janitor_email = self.janitor.preferredemail.email
     setupInteraction(auth_utility.getPrincipalByLogin(janitor_email),
                      login=janitor_email)