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)
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
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)
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)
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
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 _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
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
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
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)
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
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)