示例#1
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
示例#2
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)
                        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
def test_auth_handler_dispatch():
    assert isinstance(handler_from_provider("custom"), GenericAuthHandler)
    assert isinstance(handler_from_provider("fastmail"), GenericAuthHandler)
    assert isinstance(handler_from_provider("aol"), GenericAuthHandler)
    assert isinstance(handler_from_provider("yahoo"), GenericAuthHandler)
    assert isinstance(handler_from_provider("gmail"), GmailAuthHandler)
    assert isinstance(handler_from_provider("outlook"), OutlookAuthHandler)

    with pytest.raises(NotSupportedError):
        handler_from_provider("NOTAREALMAILPROVIDER")
def test_auth_handler_dispatch():
    assert isinstance(handler_from_provider('custom'), GenericAuthHandler)
    assert isinstance(handler_from_provider('fastmail'), GenericAuthHandler)
    assert isinstance(handler_from_provider('aol'), GenericAuthHandler)
    assert isinstance(handler_from_provider('yahoo'), GenericAuthHandler)
    assert isinstance(handler_from_provider('gmail'), GmailAuthHandler)
    assert isinstance(handler_from_provider('outlook'), OutlookAuthHandler)

    with pytest.raises(NotSupportedError):
        handler_from_provider('NOTAREALMAILPROVIDER')
def test_auth_handler_dispatch():
    assert isinstance(handler_from_provider('custom'), GenericAuthHandler)
    assert isinstance(handler_from_provider('fastmail'), GenericAuthHandler)
    assert isinstance(handler_from_provider('aol'), GenericAuthHandler)
    assert isinstance(handler_from_provider('yahoo'), GenericAuthHandler)
    assert isinstance(handler_from_provider('gmail'), GmailAuthHandler)
    assert isinstance(handler_from_provider('outlook'), OutlookAuthHandler)

    with pytest.raises(NotSupportedError):
        handler_from_provider('NOTAREALMAILPROVIDER')
示例#6
0
def confim_oauth_user():
    response = {}
    encoder = APIEncoder()
    data = request.get_json(force=True)
    email_address = data.get('email_address')
    token = data.get('token')
    target = data.get('target', 0)

    if not email_address:
        response['error'] = 'Missing key - "email_address"!'
        return encoder.jsonify(response)
    if not token:
        response['error'] = 'Missing key - "token"!'
        return encoder.jsonify(response)

    shard_id = target << 48

    with session_scope(shard_id) as db_session:
        account = db_session.query(Account).filter_by(
            email_address=email_address).first()
        if account is None:
            response['error'] = 'Don\'t have this account!'
            return encoder.jsonify(response)
        auth_info = {}
        provider = provider_from_address(email_address)
        auth_info['provider'] = provider
        auth_handler = handler_from_provider(provider)
        try:
            auth_response = auth_handler._get_authenticated_user(token)
            auth_response['contacts'] = True
            auth_response['events'] = True
            auth_info.update(auth_response)
        except OAuthError:
            response['error'] = "Invalid authorization code, try again..."
            return encoder.jsonify(response)
        account = auth_handler.update_account(account, auth_info)
        try:
            if auth_handler.verify_account(account):
                db_session.add(account)
                db_session.commit()
                response['data'] = 'OK. Authenticated account for {}'.format(
                    email_address)
        except NotSupportedError as e:
            response['error'] = str(e)
            return encoder.jsonify(response)
    return encoder.jsonify(response)
示例#7
0
def create_account(db_session, email, password):
    provider = provider_from_address(email)
    auth_handler = handler_from_provider(provider)
    # Special-case Gmail and Outlook, because we need to provide an oauth token
    # and not merely a password.
    response = {'email': email}
    if provider == 'gmail':
        code = google_auth(email, password)
        response = auth_handler._get_authenticated_user(code)
    elif provider == 'outlook':
        code = outlook_auth(email, password)
        response = auth_handler._get_authenticated_user(code)
    else:
        response = {"email": email, "password": password}

    account = auth_handler.create_account(email, response)
    auth_handler.verify_account(account)
    account.throttled = False
    account.sync_host = platform.node()
    db_session.add(account)
    db_session.commit()
    return account
示例#8
0
def main(email_address, reauth, target, provider):
    """ Auth an email account. """
    preflight()

    maybe_enable_rollbar()

    shard_id = target << 48

    with session_scope(shard_id) as db_session:
        account = (db_session.query(Account).filter_by(
            email_address=email_address).first())
        if account is not None and not reauth:
            sys.exit("Already have this account!")

        if not provider:
            provider = provider_from_address(email_address)

            # Resolve unknown providers into either custom IMAP or EAS.
            if provider == "unknown":
                is_imap = raw_input(
                    "IMAP account? [Y/n] ").strip().lower() != "n"
                provider = "custom" if is_imap else "eas"

        auth_handler = handler_from_provider(provider)
        account_data = auth_handler.interactive_auth(email_address)

        if reauth:
            account = auth_handler.update_account(account, account_data)
        else:
            account = auth_handler.create_account(account_data)

        try:
            if auth_handler.verify_account(account):
                db_session.add(account)
                db_session.commit()
        except NotSupportedError as e:
            sys.exit(str(e))

    print("OK. Authenticated account for {}".format(email_address))
示例#9
0
 def auth_handler(self):
     from inbox.auth.base import handler_from_provider
     return handler_from_provider(self.provider)
示例#10
0
 def auth_handler(self):
     from inbox.auth.base import handler_from_provider
     return handler_from_provider(self.provider)
示例#11
0
def add_new_user():
    response = {}
    encoder = APIEncoder()

    data = request.get_json(force=True)
    email_address = data.get('email_address')
    password = data.get('password')
    auth_details = data.get('auth_details')
    reauth = data.get('reauth')
    target = data.get('target', 0)

    if not email_address:
        response['error'] = 'Missing key - "email_address"!'
        return encoder.jsonify(response)

    shard_id = target << 48

    with session_scope(shard_id) as db_session:
        account = db_session.query(Account).filter_by(
            email_address=email_address).first()
        if account is not None and not reauth:
            response['error'] = 'Already have this account!'
            return encoder.jsonify(response)

        auth_info = {}
        provider = provider_from_address(email_address)
        if 'gmail' in provider:
            auth_handler = handler_from_provider(provider)
            response['oauth_url'] = auth_handler.get_oauth_url(email_address)
            response['links'] = {'confirm_url': request.url + '/confirm_oauth'}
            namespace = Namespace()
            account = GmailAccount(namespace=namespace)
            account.sync_should_run = False
            account.refresh_token = '_placeholder_'
            account.email_address = email_address
        else:
            if not password:
                response['error'] = 'Missing key - "password"!'
                return encoder.jsonify(response)
            auth_info['email'] = email_address
            auth_info['password'] = password
            if provider != 'unknown':
                auth_handler = handler_from_provider(provider)
                auth_info['provider'] = provider
                try:
                    if reauth:
                        account = auth_handler.update_account(
                            account, auth_info)
                    else:
                        account = auth_handler.create_account(
                            email_address, auth_info)
                except Exception as e:
                    response['error'] = e.msg
            else:
                auth_info['provider'] = 'custom'
                auth_handler = handler_from_provider('custom')
                if not auth_details:
                    auth_info.update(
                        try_fill_config_data(email_address, password))
                else:
                    auth_info.update(auth_details)
                try:
                    if reauth:
                        account = auth_handler.update_account(
                            account, auth_info)
                    else:
                        account = auth_handler.create_account(
                            email_address, auth_info)
                except Exception as e:
                    response['error'] = str(e)
            try:
                auth_handler.verify_account(account)
                response['data'] = 'OK. Authenticated account for {}'.format(
                    email_address)
            except Exception as e:
                response['error'] = str(e)
        db_session.add(account)
        db_session.commit()
    return encoder.jsonify(response)
def test_auth_handler_dispatch():
    assert isinstance(handler_from_provider("custom"), GenericAuthHandler)
    assert isinstance(handler_from_provider("gmail"), GoogleAuthHandler)

    with pytest.raises(NotSupportedError):
        handler_from_provider("NOTAREALMAILPROVIDER")
示例#13
0
def create_account():
    g.parser.add_argument('email',
                          required=True,
                          type=bounded_str,
                          location='form')
    g.parser.add_argument('smtp_host',
                          required=True,
                          type=bounded_str,
                          location='form')
    g.parser.add_argument('smtp_port', type=int, location='form')
    g.parser.add_argument('smtp_username',
                          required=True,
                          type=bounded_str,
                          location='form')
    g.parser.add_argument('smtp_password',
                          required=True,
                          type=bounded_str,
                          location='form')
    g.parser.add_argument('imap_host',
                          required=True,
                          type=bounded_str,
                          location='form')
    g.parser.add_argument('imap_port', type=int, location='form')
    g.parser.add_argument('imap_username',
                          required=True,
                          type=bounded_str,
                          location='form')
    g.parser.add_argument('imap_password',
                          required=True,
                          type=bounded_str,
                          location='form')
    g.parser.add_argument('ssl_required',
                          required=True,
                          type=bool,
                          location='form')
    args = strict_parse_args(g.parser, request.args)

    target = find_account_shard(args['email'])
    if target is None:
        target = config.get('NEW_ACCOUNTS_DEFAULT_SHARD', 0) << 48

    with session_scope(target) as db_session:
        account = db_session.query(Account).filter_by(
            email_address=args['email']).first()

        provider_auth_info = dict(provider='custom',
                                  email=args['email'],
                                  imap_server_host=args['imap_host'],
                                  imap_server_port=(args.get('imap_port')
                                                    or DEFAULT_IMAP_SSL_PORT),
                                  imap_username=args['imap_username'],
                                  imap_password=args['imap_password'],
                                  smtp_server_host=args['smtp_host'],
                                  smtp_server_port=(args.get('smtp_port')
                                                    or DEFAULT_SMTP_SSL_PORT),
                                  smtp_username=args['smtp_username'],
                                  smtp_password=args['smtp_password'],
                                  ssl_required=args['ssl_required'])

        auth_handler = handler_from_provider(provider_auth_info['provider'])

        if account is None:
            account = auth_handler.create_account(args['email'],
                                                  provider_auth_info)
        else:
            account = account.auth_handler.update_account(
                account, provider_auth_info)

        try:
            resp = None

            if auth_handler.verify_account(account):
                db_session.add(account)
                db_session.commit()
                resp = simplejson.dumps({
                    'account_id':
                    account.public_id,
                    'namespace_id':
                    account.namespace.public_id
                })
                return make_response((resp, 201, {
                    'Content-Type': 'application/json'
                }))
            else:
                resp = simplejson.dumps({
                    'message': 'Account verification failed',
                    'type': 'api_error'
                })
                return make_response((resp, 422, {
                    'Content-Type': 'application/json'
                }))
        except ValidationError as e:
            return unprocessable_entity_response(e.message.message)
        except gaierror as error:
            if error[1] == 'Name or service not known':
                return unprocessable_entity_response(error[1])
            else:
                raise error
        except NotSupportedError as e:
            resp = simplejson.dumps({
                'message': str(e),
                'type': 'custom_api_error'
            })
            return make_response((resp, 400, {
                'Content-Type': 'application/json'
            }))
示例#14
0
def auth_callback():
    g.parser.add_argument('authorization_code',
                          type=bounded_str,
                          location='args',
                          required=True)
    g.parser.add_argument('email',
                          required=True,
                          type=bounded_str,
                          location='args')
    args = strict_parse_args(g.parser, request.args)

    target = find_account_shard(args['email'])
    if target is None:
        target = config.get('NEW_ACCOUNTS_DEFAULT_SHARD', 0) << 48

    with session_scope(target) as db_session:
        account = db_session.query(Account).filter_by(
            email_address=args['email']).first()

        updating_account = False
        if account is not None:
            updating_account = True

        auth_handler = handler_from_provider('gmail')

        request_args = {
            'client_id': GmailAuthHandler.OAUTH_CLIENT_ID,
            'client_secret': GmailAuthHandler.OAUTH_CLIENT_SECRET,
            'redirect_uri': GmailAuthHandler.OAUTH_REDIRECT_URI,
            'code': args['authorization_code'],
            'grant_type': 'authorization_code'
        }

        headers = {
            'Content-type': 'application/x-www-form-urlencoded',
            'Accept': 'text/plain'
        }

        data = urllib.urlencode(request_args)
        resp_dict = requests.post(auth_handler.OAUTH_ACCESS_TOKEN_URL,
                                  data=data,
                                  headers=headers).json()

        if u'error' in resp_dict:
            raise APIException('Internal error: ' + str(resp_dict['error']))

        access_token = resp_dict['access_token']
        validation_dict = auth_handler.validate_token(access_token)
        userinfo_dict = auth_handler._get_user_info(access_token)

        if userinfo_dict['email'].lower() != args['email'].lower():
            raise InputError('Email mismatch')

        resp_dict.update(validation_dict)
        resp_dict.update(userinfo_dict)
        resp_dict['contacts'] = True
        resp_dict['events'] = True

        auth_info = {'provider': 'gmail'}
        auth_info.update(resp_dict)

        if updating_account:
            account.auth_handler.update_account(account, auth_info)
        else:
            account = auth_handler.create_account(args['email'], auth_info)

        try:
            if auth_handler.verify_account(account):
                db_session.add(account)
                db_session.commit()
        except NotSupportedError:
            raise APIException('Internal error: ' + str(resp_dict['error']))

        resp = simplejson.dumps({
            'account_id': account.public_id,
            'namespace_id': account.namespace.public_id
        })

        return make_response((resp, 201, {'Content-Type': 'application/json'}))