Esempio n. 1
0
    def authenticate_imap_connection(self, account, conn):
        token = token_manager.get_token(account)
        try:
            conn.oauth2_login(account.email_address, token)
        except IMAPClient.Error as exc:
            exc = _process_imap_exception(exc)

            # Raise all IMAP disabled errors except authentication_failed
            # error, which we handle differently.
            if (isinstance(exc, ImapSupportDisabledError)
                    and exc.reason != "authentication_failed"):
                raise exc

            log.error(
                "Error during IMAP XOAUTH2 login",
                account_id=account.id,
                error=exc,
            )
            if not isinstance(exc, ImapSupportDisabledError):
                raise  # Unknown IMAPClient error, reraise

            # If we got an AUTHENTICATIONFAILED response, force a token refresh
            # and try again. If IMAP auth still fails, it's likely that IMAP
            # access is disabled, so propagate that errror.
            token = token_manager.get_token(account, force_refresh=True)
            try:
                conn.oauth2_login(account.email_address, token)
            except IMAPClient.Error as exc:
                exc = _process_imap_exception(exc)
                if (not isinstance(exc, ImapSupportDisabledError)
                        or exc.reason != "authentication_failed"):
                    raise exc
                else:
                    # Instead of authentication_failed, report imap disabled
                    raise ImapSupportDisabledError("imap_disabled_for_account")
Esempio n. 2
0
    def get_items(self, sync_from_dt=None, max_results=100000):
        """
        Fetches and parses fresh contact data.

        Parameters
        ----------
        sync_from_dt: datetime, optional
            If given, fetch contacts that have been updated since this time.
            Otherwise fetch all contacts
        max_results: int, optional
            The maximum number of contact entries to fetch.

        Yields
        ------
        ..models.tables.base.Contact
            The contacts that have been updated since the last account sync.

        Raises
        ------
        ValidationError
            If no data could be fetched because of invalid credentials or
            insufficient permissions, respectively.

        """
        query = gdata.contacts.client.ContactsQuery()
        # TODO(emfree): Implement batch fetching
        # Note: The Google contacts API will only return 25 results if
        # query.max_results is not explicitly set, so have to set it to a large
        # number by default.
        query.max_results = max_results
        if sync_from_dt:
            query.updated_min = datetime.isoformat(sync_from_dt) + "Z"
        query.showdeleted = True
        while True:
            try:
                google_client = self._get_google_client()
                results = google_client.GetContacts(q=query).entry
                return [
                    self._parse_contact_result(result) for result in results
                ]
            except gdata.client.RequestError as e:
                if e.status == 503:
                    self.log.info("Ran into Google bot detection. Sleeping.",
                                  message=e)
                    gevent.sleep(5 * 60 + random.randrange(0, 60))
                else:
                    self.log.info("contact sync request failure; retrying",
                                  message=e)
                    gevent.sleep(30 + random.randrange(0, 60))
            except gdata.client.Unauthorized:
                self.log.warning(
                    "Invalid access token; refreshing and retrying")
                # Raises an OAuth error if no valid token exists
                with session_scope(self.namespace_id) as db_session:
                    account = db_session.query(GmailAccount).get(
                        self.account_id)
                    token_manager.get_token(account, force_refresh=True)
Esempio n. 3
0
    def verify_account(self, account):
        """Verifies a IMAP account by logging in."""
        try:
            access_token = token_manager.get_token(account)
            conn = self.connect_account(account.email_address, access_token,
                                        account.imap_endpoint, account.id)
            conn.logout()
        except ValidationError:
            # Access token could've expired, refresh and try again.
            access_token = token_manager.get_token(account, force_refresh=True)
            conn = self.connect_account(account.email_address, access_token,
                                        account.imap_endpoint, account.id)
            conn.logout()

        return True
Esempio n. 4
0
 def _get_google_client(self):
     """Return the Google API client."""
     # TODO(emfree) figure out a better strategy for refreshing OAuth
     # credentials as needed
     with session_scope() as db_session:
         try:
             account = db_session.query(GmailAccount).get(self.account_id)
             client_id = account.client_id or OAUTH_CLIENT_ID
             client_secret = (account.client_secret or
                              OAUTH_CLIENT_SECRET)
             access_token = token_manager.get_token(account)
             two_legged_oauth_token = gdata.gauth.OAuth2Token(
                 client_id=client_id,
                 client_secret=client_secret,
                 scope=OAUTH_SCOPE,
                 user_agent=SOURCE_APP_NAME,
                 access_token=access_token,
                 refresh_token=account.refresh_token)
             google_client = gdata.contacts.client.ContactsClient(
                 source=SOURCE_APP_NAME)
             google_client.auth_token = two_legged_oauth_token
             return google_client
         except (gdata.client.BadAuthentication, OAuthError):
             self.log.info('Invalid user credentials given')
             account.sync_state = 'invalid'
             db_session.add(account)
             db_session.commit()
             raise ValidationError
         except ConnectionError:
             self.log.error('Connection error')
             account.sync_state = 'connerror'
             db_session.add(account)
             db_session.commit()
             raise
Esempio n. 5
0
 def _get_google_client(self):
     """Return the Google API client."""
     # TODO(emfree) figure out a better strategy for refreshing OAuth
     # credentials as needed
     with session_scope() as db_session:
         try:
             account = db_session.query(GmailAccount).get(self.account_id)
             client_id = account.client_id or OAUTH_CLIENT_ID
             client_secret = (account.client_secret or OAUTH_CLIENT_SECRET)
             access_token = token_manager.get_token(account)
             two_legged_oauth_token = gdata.gauth.OAuth2Token(
                 client_id=client_id,
                 client_secret=client_secret,
                 scope=OAUTH_SCOPE,
                 user_agent=SOURCE_APP_NAME,
                 access_token=access_token,
                 refresh_token=account.refresh_token)
             google_client = gdata.contacts.client.ContactsClient(
                 source=SOURCE_APP_NAME)
             google_client.auth_token = two_legged_oauth_token
             return google_client
         except (gdata.client.BadAuthentication, OAuthError):
             self.log.info('Invalid user credentials given')
             account.sync_state = 'invalid'
             db_session.add(account)
             db_session.commit()
             raise ValidationError
         except ConnectionError:
             self.log.error('Connection error')
             account.sync_state = 'connerror'
             db_session.add(account)
             db_session.commit()
             raise
Esempio n. 6
0
 def get_token(self, account, force_refresh=False):
     if account.provider == 'gmail':
         return g_token_manager.get_token_for_email(
             account, force_refresh=force_refresh)
     else:
         return default_token_manager.get_token(account,
                                                force_refresh=force_refresh)
Esempio n. 7
0
 def get_token(self, account, force_refresh=False):
     if account.provider == 'gmail':
         return g_token_manager.get_token_for_email(
             account, force_refresh=force_refresh)
     else:
         return default_token_manager.get_token(
             account, force_refresh=force_refresh)
Esempio n. 8
0
    def __init__(self, account):
        self.account_id = account.id
        self.log = get_logger()
        self.log.bind(account_id=account.id)
        if isinstance(account, GenericAccount):
            self.smtp_username = account.smtp_username
        else:
            # Non-generic accounts have no smtp username
            self.smtp_username = account.email_address
        self.email_address = account.email_address
        self.provider_name = account.provider
        self.sender_name = account.name
        self.smtp_endpoint = account.smtp_endpoint
        self.auth_type = provider_info(self.provider_name)["auth"]

        if self.auth_type == "oauth2":
            try:
                self.auth_token = token_manager.get_token(account)
            except OAuthError:
                raise SendMailException(
                    "Could not authenticate with the SMTP server.", 403
                )
        else:
            assert self.auth_type == "password"
            if isinstance(account, GenericAccount):
                self.auth_token = account.smtp_password
            else:
                # non-generic accounts have no smtp password
                self.auth_token = account.password
Esempio n. 9
0
    def _new_connection(self):
        from inbox.auth.base import handler_from_provider

        # Ensure that connections are initialized serially, so as not to use
        # many db sessions on startup.
        with self._new_conn_lock:
            auth_handler = handler_from_provider(self.provider_name)

            for retry_count in range(MAX_TRANSIENT_ERRORS):
                try:
                    conn = auth_handler.connect_account(self.email_address,
                                                        self.credential,
                                                        self.imap_endpoint,
                                                        self.account_id)

                    # If we can connect the account, then we can set the sate
                    # to 'running' if it wasn't already
                    if self.sync_state != 'running':
                        with session_scope() as db_session:
                            query = db_session.query(ImapAccount)
                            account = query.get(self.account_id)
                            self.sync_state = account.sync_state = 'running'
                    return self.client_cls(self.account_id, self.provider_info,
                                           self.email_address, conn,
                                           readonly=self.readonly)

                except ConnectionError, e:
                    if isinstance(e, TransientConnectionError):
                        return None
                    else:
                        logger.error('Error connecting',
                                     account_id=self.account_id)
                        with session_scope() as db_session:
                            query = db_session.query(ImapAccount)
                            account = query.get(self.account_id)
                            account.sync_state = 'connerror'
                            account.update_sync_error(str(e))
                        return None
                except ValidationError, e:
                    # If we failed to validate, but the account is oauth2, we
                    # may just need to refresh the access token. Try this one
                    # time.
                    if (self.provider_info['auth'] == 'oauth2' and
                            retry_count == 0):
                        with session_scope() as db_session:
                            query = db_session.query(ImapAccount)
                            account = query.get(self.account_id)
                            self.credential = token_manager.get_token(
                                account, force_refresh=True)
                    else:
                        logger.error('Error validating',
                                     account_id=self.account_id,
                                     logstash_tag='mark_invalid')
                        with session_scope() as db_session:
                            query = db_session.query(ImapAccount)
                            account = query.get(self.account_id)
                            account.mark_invalid()
                            account.update_sync_error(str(e))
                        raise
Esempio n. 10
0
    def _new_connection(self):
        from inbox.auth import handler_from_provider

        # Ensure that connections are initialized serially, so as not to use
        # many db sessions on startup.
        with self._new_conn_lock as _:
            auth_handler = handler_from_provider(self.provider_name)

            for retry_count in range(MAX_TRANSIENT_ERRORS):
                try:
                    conn = auth_handler.connect_account(
                        self.email_address, self.credential,
                        self.imap_endpoint, self.account_id)

                    # If we can connect the account, then we can set the sate
                    # to 'running' if it wasn't already
                    if self.sync_state != 'running':
                        with session_scope() as db_session:
                            query = db_session.query(ImapAccount)
                            account = query.get(self.account_id)
                            self.sync_state = account.sync_state = 'running'
                    return self.client_cls(self.account_id,
                                           self.provider_info,
                                           self.email_address,
                                           conn,
                                           readonly=self.readonly)

                except ConnectionError, e:
                    if isinstance(e, TransientConnectionError):
                        return None
                    else:
                        logger.error('Error connecting',
                                     account_id=self.account_id)
                        with session_scope() as db_session:
                            query = db_session.query(ImapAccount)
                            account = query.get(self.account_id)
                            account.sync_state = 'connerror'
                            account.update_sync_error(str(e))
                        return None
                except ValidationError, e:
                    # If we failed to validate, but the account is oauth2, we
                    # may just need to refresh the access token. Try this one
                    # time.
                    if (self.provider_info['auth'] == 'oauth2'
                            and retry_count == 0):
                        with session_scope() as db_session:
                            query = db_session.query(ImapAccount)
                            account = query.get(self.account_id)
                            self.credential = token_manager.get_token(
                                account, force_refresh=True)
                    else:
                        logger.error('Error validating',
                                     account_id=self.account_id)
                        with session_scope() as db_session:
                            query = db_session.query(ImapAccount)
                            account = query.get(self.account_id)
                            account.sync_state = 'invalid'
                            account.update_sync_error(str(e))
                        raise
Esempio n. 11
0
    def _get_google_client(self, retry_conn_errors=True):
        """Return the Google API client."""
        # TODO(emfree) figure out a better strategy for refreshing OAuth
        # credentials as needed
        with session_scope() as db_session:
            try:
                account = db_session.query(GmailAccount).get(self.account_id)
                client_id = account.client_id or OAUTH_CLIENT_ID
                client_secret = (account.client_secret or
                                 OAUTH_CLIENT_SECRET)
                access_token = token_manager.get_token(account)
                two_legged_oauth_token = gdata.gauth.OAuth2Token(
                    client_id=client_id,
                    client_secret=client_secret,
                    scope=OAUTH_SCOPE,
                    user_agent=SOURCE_APP_NAME,
                    access_token=access_token,
                    refresh_token=account.refresh_token)
                google_client = gdata.contacts.client.ContactsClient(
                    source=SOURCE_APP_NAME)
                google_client.auth_token = two_legged_oauth_token
                return google_client
            except (gdata.client.BadAuthentication, OAuthError) as e:
                self.log.debug('Invalid user credentials given: {}'
                               .format(e), logstash_tag='mark_invalid',
                               account_id=account.id)
                account.mark_invalid()
                db_session.add(account)
                db_session.commit()

                if not retry_conn_errors:  # end of the line
                    raise ValidationError

                try:
                    token_manager.get_token(account, force_refresh=True)
                    return self._get_google_client(retry_conn_errors=False)
                except OAuthError as e:
                    raise ValidationError

            except ConnectionError:
                self.log.error('Connection error')
                account.sync_state = 'connerror'
                db_session.add(account)
                db_session.commit()
                raise
Esempio n. 12
0
    def _get_google_client(self, retry_conn_errors=True):
        """Return the Google API client."""
        # TODO(emfree) figure out a better strategy for refreshing OAuth
        # credentials as needed
        with session_scope() as db_session:
            try:
                account = db_session.query(GmailAccount).get(self.account_id)
                client_id = account.client_id or OAUTH_CLIENT_ID
                client_secret = (account.client_secret or
                                 OAUTH_CLIENT_SECRET)
                access_token = token_manager.get_token(account)
                two_legged_oauth_token = gdata.gauth.OAuth2Token(
                    client_id=client_id,
                    client_secret=client_secret,
                    scope=OAUTH_SCOPE,
                    user_agent=SOURCE_APP_NAME,
                    access_token=access_token,
                    refresh_token=account.refresh_token)
                google_client = gdata.contacts.client.ContactsClient(
                    source=SOURCE_APP_NAME)
                google_client.auth_token = two_legged_oauth_token
                return google_client
            except (gdata.client.BadAuthentication, OAuthError) as e:
                self.log.debug('Invalid user credentials given: {}'
                               .format(e))
                account.mark_invalid()
                db_session.add(account)
                db_session.commit()

                if not retry_conn_errors:  # end of the line
                    raise ValidationError

                try:
                    token_manager.get_token(account, force_refresh=True)
                    return self._get_google_client(retry_conn_errors=False)
                except OAuthError as e:
                    raise ValidationError

            except ConnectionError:
                self.log.error('Connection error')
                account.sync_state = 'connerror'
                db_session.add(account)
                db_session.commit()
                raise
Esempio n. 13
0
 def _get_google_client(self, retry_conn_errors=True):
     """Return the Google API client."""
     with session_scope(self.namespace_id) as db_session:
         account = db_session.query(GmailAccount).get(self.account_id)
         db_session.expunge(account)
     access_token = token_manager.get_token(account)
     token = gdata.gauth.AuthSubToken(access_token)
     google_client = gdata.contacts.client.ContactsClient(source=SOURCE_APP_NAME)
     google_client.auth_token = token
     return google_client
Esempio n. 14
0
    def verify_account(self, account):
        """Verifies a IMAP account by logging in."""
        try:
            access_token = token_manager.get_token(account)
            conn = self.connect_account(account.email_address,
                                        access_token,
                                        account.imap_endpoint,
                                        account.id)
            conn.logout()
        except ValidationError:
            # Access token could've expired, refresh and try again.
            access_token = token_manager.get_token(account, force_refresh=True)
            conn = self.connect_account(account.email_address,
                                        access_token,
                                        account.imap_endpoint,
                                        account.id)
            conn.logout()

        return True
Esempio n. 15
0
 def _authenticate_IMAP_connection(self, account, conn):
     host, port = account.imap_endpoint
     try:
         # Raises ValidationError if the refresh token we have is invalid.
         token = token_manager.get_token(account)
         conn.oauth2_login(account.email_address, token)
     except IMAPClient.Error as exc:
         log.error('Error during IMAP XOAUTH2 login',
                   account_id=account.id,
                   host=host,
                   port=port,
                   error=exc)
         raise
Esempio n. 16
0
 def _authenticate_IMAP_connection(self, account, conn):
     host, port = account.imap_endpoint
     try:
         # Raises ValidationError if the refresh token we have is invalid.
         token = token_manager.get_token(account)
         conn.oauth2_login(account.email_address, token)
     except IMAPClient.Error as exc:
         log.error('Error during IMAP XOAUTH2 login',
                   account_id=account.id,
                   host=host,
                   port=port,
                   error=exc)
         raise
Esempio n. 17
0
 def __init__(self, account):
     self.account_id = int(account.id)
     try:
         with session_scope(self.account_id) as db_session:
             self.account = db_session.query(Account).get(self.account_id)
             self.auth_token = token_manager.get_token(self.account)
             db_session.expunge_all()
     except OAuthError:
         raise SearchBackendException(
             "This search can't be performed because the account's "
             "credentials are out of date. Please reauthenticate and try "
             "again.",
             403,
         )
Esempio n. 18
0
 def verify_config(self, account):
     """Verifies configuration, specifically presence of 'All Mail' folder.
        Will raise an inbox.crispin.GmailSettingError if not present.
     """
     access_token = token_manager.get_token(account)
     conn = self.connect_account(account.email_address, access_token,
                                 account.imap_endpoint, account.id)
     # make a crispin client and check the folders
     client = GmailCrispinClient(account.id,
                                 provider_info('gmail'),
                                 account.email_address,
                                 conn,
                                 readonly=True)
     client.sync_folders()
     conn.logout()
     return True
Esempio n. 19
0
 def verify_config(self, account):
     """Verifies configuration, specifically presence of 'All Mail' folder.
        Will raise an inbox.crispin.GmailSettingError if not present.
     """
     access_token = token_manager.get_token(account)
     conn = self.connect_account(account.email_address,
                                 access_token,
                                 account.imap_endpoint,
                                 account.id)
     # make a crispin client and check the folders
     client = GmailCrispinClient(account.id,
                                 provider_info('gmail'),
                                 account.email_address,
                                 conn,
                                 readonly=True)
     client.sync_folders()
     conn.logout()
     return True
Esempio n. 20
0
    def _get_google_service(self):
        """Return the Google API client."""
        with session_scope() as db_session:
            try:
                account = db_session.query(GmailAccount).get(self.account_id)
                client_id = account.client_id or OAUTH_CLIENT_ID
                client_secret = (account.client_secret or
                                 OAUTH_CLIENT_SECRET)

                self.email = account.email_address

                access_token = token_manager.get_token(account)
                refresh_token = account.refresh_token

                credentials = OAuth2Credentials(
                    access_token=access_token,
                    client_id=client_id,
                    client_secret=client_secret,
                    refresh_token=refresh_token,
                    token_expiry=None,  # Value not actually needed by library.
                    token_uri=OAUTH_ACCESS_TOKEN_URL,
                    user_agent=SOURCE_APP_NAME)

                http = httplib2.Http()
                http = credentials.authorize(http)

                service = build(serviceName='calendar',
                                version='v3',
                                http=http)

                return service

            except OAuthError:
                self.log.error('Invalid user credentials given')
                account.sync_state = 'invalid'
                db_session.add(account)
                db_session.commit()
                raise ValidationError
            except ConnectionError:
                self.log.error('Connection error')
                account.sync_state = 'connerror'
                db_session.add(account)
                db_session.commit()
                raise ConnectionError
Esempio n. 21
0
    def _get_google_service(self):
        """Return the Google API client."""
        with session_scope() as db_session:
            try:
                account = db_session.query(GmailAccount).get(self.account_id)
                client_id = account.client_id or OAUTH_CLIENT_ID
                client_secret = (account.client_secret or OAUTH_CLIENT_SECRET)

                self.email = account.email_address

                access_token = token_manager.get_token(account)
                refresh_token = account.refresh_token

                credentials = OAuth2Credentials(
                    access_token=access_token,
                    client_id=client_id,
                    client_secret=client_secret,
                    refresh_token=refresh_token,
                    token_expiry=None,  # Value not actually needed by library.
                    token_uri=OAUTH_ACCESS_TOKEN_URL,
                    user_agent=SOURCE_APP_NAME)

                http = httplib2.Http()
                http = credentials.authorize(http)

                service = build(serviceName='calendar',
                                version='v3',
                                http=http)

                return service

            except OAuthError:
                self.log.error('Invalid user credentials given')
                account.sync_state = 'invalid'
                db_session.add(account)
                db_session.commit()
                raise ValidationError
            except ConnectionError:
                self.log.error('Connection error')
                account.sync_state = 'connerror'
                db_session.add(account)
                db_session.commit()
                raise ConnectionError
Esempio n. 22
0
    def __init__(self, account):
        self.account_id = account.id
        self.log = get_logger()
        self.log.bind(account_id=account.id)
        self.email_address = account.email_address
        self.provider_name = account.provider
        self.sender_name = account.name
        self.smtp_endpoint = account.smtp_endpoint
        self.auth_type = provider_info(self.provider_name,
                                       self.email_address)['auth']

        if self.auth_type == 'oauth2':
            try:
                self.auth_token = token_manager.get_token(account)
            except OAuthError:
                raise SendMailException(
                    'Could not authenticate with the SMTP server.', 403)
        else:
            assert self.auth_type == 'password'
            self.auth_token = account.password
Esempio n. 23
0
    def __init__(self, account):
        self.account_id = account.id
        self.log = get_logger()
        self.log.bind(account_id=account.id)
        self.email_address = account.email_address
        self.provider_name = account.provider
        self.sender_name = account.name
        self.smtp_endpoint = account.smtp_endpoint
        self.auth_type = provider_info(self.provider_name,
                                       self.email_address)['auth']

        if self.auth_type == 'oauth2':
            try:
                self.auth_token = token_manager.get_token(account)
            except OAuthError:
                raise SendMailException(
                    'Could not authenticate with the SMTP server.', 403)
        else:
            assert self.auth_type == 'password'
            self.auth_token = account.password
Esempio n. 24
0
    def _set_account_info(self):
        with session_scope() as db_session:
            account = db_session.query(Account).get(self.account_id)
            self.provider_name = account.provider
            self.email_address = account.email_address
            self.provider_info = account.provider_info
            self.imap_endpoint = account.imap_endpoint
            self.sync_state = account.sync_state

            if self.provider_name == 'gmail':
                self.client_cls = GmailCrispinClient
            elif getattr(account, 'supports_condstore', False):
                self.client_cls = CondStoreCrispinClient
            elif self.provider_info.get('condstore'):
                self.client_cls = CondStoreCrispinClient
            else:
                self.client_cls = CrispinClient

            # Refresh token if need be, for OAuthed accounts
            if self.provider_info['auth'] == 'oauth2':
                try:
                    self.credential = token_manager.get_token(account)
                except ValidationError as e:
                    logger.error("Error obtaining access token",
                                 account_id=self.account_id,
                                 logstash_tag='mark_invalid')
                    account.mark_invalid()
                    account.update_sync_error(str(e))
                    db_session.commit()
                    raise
                except ConnectionError as e:
                    logger.error("Error connecting",
                                 account_id=self.account_id)
                    account.sync_state = 'connerror'
                    account.update_sync_error(str(e))
                    db_session.commit()
                    raise
            else:
                self.credential = account.password
Esempio n. 25
0
def get_gmail_raw_contents(message):
    account = message.namespace.account
    auth_token = token_manager.get_token(account)

    # The Gmail API exposes the X-GM-MSGID field but encodes it
    # in hexadecimal.
    g_msgid = message.g_msgid

    if g_msgid is None:
        raise EmailDeletedException(
            "Couldn't find message on backend server. This is a permanent error."
        )

    if isinstance(g_msgid, basestring):
        g_msgid = int(g_msgid)

    hex_id = format(g_msgid, "x")
    url = "https://www.googleapis.com/gmail/v1/users/me/messages/{}?format=raw".format(
        hex_id, "x")
    r = requests.get(url, auth=OAuthRequestsWrapper(auth_token))

    if r.status_code != 200:
        log.error("Got an error when fetching raw email", r.status_code,
                  r.text)

    if r.status_code in [403, 429]:
        raise TemporaryEmailFetchException(
            "Temporary usage limit hit. Please try again.")
    if r.status_code == 404:
        raise EmailDeletedException(
            "Couldn't find message on backend server. This is a permanent error."
        )
    elif r.status_code >= 500 and r.status_code <= 599:
        raise TemporaryEmailFetchException(
            "Backend server error. Please try again in a few minutes.")

    data = r.json()
    raw = str(data["raw"])
    return base64.urlsafe_b64decode(raw + "=" * (4 - len(raw) % 4))
Esempio n. 26
0
    def _set_account_info(self):
        with session_scope() as db_session:
            account = db_session.query(Account).get(self.account_id)
            self.provider_name = account.provider
            self.email_address = account.email_address
            self.provider_info = account.provider_info
            self.imap_endpoint = account.imap_endpoint
            self.sync_state = account.sync_state

            if self.provider_name == 'gmail':
                self.client_cls = GmailCrispinClient
            elif getattr(account, 'supports_condstore', False):
                self.client_cls = CondStoreCrispinClient
            elif self.provider_info.get('condstore'):
                self.client_cls = CondStoreCrispinClient
            else:
                self.client_cls = CrispinClient

            # Refresh token if need be, for OAuthed accounts
            if self.provider_info['auth'] == 'oauth2':
                try:
                    self.credential = token_manager.get_token(account)
                except ValidationError as e:
                    logger.error("Error obtaining access token",
                                 account_id=self.account_id)
                    account.mark_invalid()
                    account.update_sync_error(str(e))
                    db_session.commit()
                    raise
                except ConnectionError as e:
                    logger.error("Error connecting",
                                 account_id=self.account_id)
                    account.sync_state = 'connerror'
                    account.update_sync_error(str(e))
                    db_session.commit()
                    raise
            else:
                self.credential = account.password
Esempio n. 27
0
    def connect_account(self, account):
        """Returns an authenticated IMAP connection for the given account.

        Raises
        ------
        ValidationError
            If fetching an access token failed because the refresh token we
            have is invalid (i.e., if the user has revoked access).
        ConnectionError
            If another error occurred when fetching an access token.
        imapclient.IMAPClient.Error, socket.error
            If errors occurred establishing the connection or logging in.
        """
        host, port = account.imap_endpoint
        try:
            conn = IMAPClient(host, port=port, use_uid=True, ssl=True)
        except (IMAPClient.Error, socket.error) as exc:
            log.error('Error instantiating IMAP connection',
                      account_id=account.id,
                      email=account.email_address,
                      imap_host=host,
                      imap_port=port,
                      error=exc)
            raise

        try:
            # Raises ValidationError if the refresh token we have is invalid.
            token = token_manager.get_token(account)
            conn.oauth2_login(account.email_address, token)
        except IMAPClient.Error as exc:
            log.error('Error during IMAP XOAUTH2 login',
                      account_id=account.id,
                      email=account.email_address,
                      host=host,
                      port=port,
                      error=exc)
            raise
        return conn
Esempio n. 28
0
    def connect_account(self, account):
        """Returns an authenticated IMAP connection for the given account.

        Raises
        ------
        ValidationError
            If fetching an access token failed because the refresh token we
            have is invalid (i.e., if the user has revoked access).
        ConnectionError
            If another error occurred when fetching an access token.
        imapclient.IMAPClient.Error, socket.error
            If errors occurred establishing the connection or logging in.
        """
        host, port = account.imap_endpoint
        try:
            conn = IMAPClient(host, port=port, use_uid=True, ssl=True)
        except (IMAPClient.Error, socket.error) as exc:
            log.error('Error instantiating IMAP connection',
                      account_id=account.id,
                      email=account.email_address,
                      imap_host=host,
                      imap_port=port,
                      error=exc)
            raise

        try:
            # Raises ValidationError if the refresh token we have is invalid.
            token = token_manager.get_token(account)
            conn.oauth2_login(account.email_address, token)
        except IMAPClient.Error as exc:
            log.error('Error during IMAP XOAUTH2 login',
                      account_id=account.id,
                      email=account.email_address,
                      host=host,
                      port=port,
                      error=exc)
            raise
        return conn
Esempio n. 29
0
    def fetch_items(self, sync_from_time=None):
        with session_scope() as db_session:
            account = db_session.query(OutlookAccount).get(self.account_id)
            access_token = token_manager.get_token(account)

            params = {'access_token': access_token}

            path = OAUTH_USER_INFO_URL + "/events"
            resp = requests.get(path, params=params)

            if resp.status_code != 200:
                try:
                    resp_data = resp.json()
                    if 'error' in resp_data and 'code' in resp_data['error']:
                        self.log.error("Error obtaining events",
                                       message=resp_data['error']['code'],
                                       provider=self.PROVIDER_NAME,
                                       account_id=self.account_id)
                    else:
                        self.log.error("Error obtaining events",
                                       provider=self.PROVIDER_NAME,
                                       message="Invalid response from server.",
                                       account_id=self.account_id)
                except ValueError:
                    self.log.error("Error obtaining events",
                                   provider=self.PROVIDER_NAME,
                                   message="Invalid response from server.",
                                   account_id=self.account_id)
                return

            response_items = resp.json()['data']
            user_id = account.o_id

        calendar_id = self.get_calendar_id('default')
        extra = {'user_id': user_id, 'stored_uids': []}
        for response_event in response_items:
            yield (calendar_id, response_event, extra)
Esempio n. 30
0
 def _get_access_token(self):
     with session_scope() as db_session:
         acc = db_session.query(Account).get(self.account_id)
         # This will raise OAuthError if OAuth access was revoked. The
         # BaseSyncMonitor loop will catch this, clean up, and exit.
         return token_manager.get_token(acc)
Esempio n. 31
0
 def _smtp_oauth2_try_refresh(self):
     with session_scope() as db_session:
         account = db_session.query(ImapAccount).get(self.account_id)
         self.auth_token = token_manager.get_token(account,
                                                   force_refresh=True)
Esempio n. 32
0
 def _smtp_oauth2_try_refresh(self):
     with session_scope() as db_session:
         account = db_session.query(ImapAccount).get(self.account_id)
         self.auth_token = token_manager.get_token(account,
                                                   force_refresh=True)
Esempio n. 33
0
 def _get_access_token(self):
     with session_scope() as db_session:
         acc = db_session.query(Account).get(self.account_id)
         # This will raise OAuthError if OAuth access was revoked. The
         # BaseSyncMonitor loop will catch this, clean up, and exit.
         return token_manager.get_token(acc)
Esempio n. 34
0
 def _get_access_token_for_push_notifications(self,
                                              account,
                                              force_refresh=False):
     if not self.push_notifications_enabled(account):
         raise OAuthError("Account not enabled for push notifications.")
     return token_manager.get_token(account, force_refresh)