Example #1
0
    def test_user_authentication_success_if_user_already_exists(self):
        """
        Tests the end point of a user authenticating their ADS 2.0 credentials via
        the web app, assuming that they have previously set something before
        """
        # Stub out the user in the database
        user = Users(
            absolute_uid=10,
            twopointoh_email='*****@*****.**',
        )
        with self.app.session_scope() as session:
            session.add(user)
            session.commit()

            # 1. The user fills in their credentials
            # 2. The user submits their credentials to the end point
            url = url_for('authenticateusertwopointoh')

            with HTTMock(ads_classic_200):
                r = self.client.post(url,
                                     data=self.stub_user_data_2p0,
                                     headers={USER_ID_KEYWORD: 10})

            self.assertStatus(r, 200)

            self.assertEqual(r.json['twopointoh_email'],
                             self.stub_user_data_2p0['twopointoh_email'])
            self.assertTrue(r.json['twopointoh_authed'])

            r_user = session.query(Users).filter(
                Users.absolute_uid == 10).one()

            self.assertEqual(r_user.twopointoh_email,
                             self.stub_user_data_2p0['twopointoh_email'])
Example #2
0
    def test_user_authentication_fails_when_user_already_exists(self):
        """
        Tests the end point of a user authenticating their ADS credentials via
        the web app, assuming that they have previously set something before.
        This is the scenario in which there is a failure, the credentials remain
        the same in the database
        """
        # Stub out the user in the database
        user = Users(absolute_uid=10, twopointoh_email='*****@*****.**')
        with self.app.session_scope() as session:
            session.add(user)
            session.commit()

            # 1. The user fills in their credentials
            # 2. The user submits their credentials to the end point
            url = url_for('authenticateusertwopointoh')

            possible_failures = [
                ads_classic_fail, ads_classic_unknown_user,
                ads_classic_wrong_password
            ]
            for fail_response in possible_failures:
                with HTTMock(fail_response):
                    self.client.post(url,
                                     data=self.stub_user_data_2p0,
                                     headers={USER_ID_KEYWORD: 10})

                r_user = session.query(Users).filter(
                    Users.absolute_uid == 10).one()
                self.assertEqual(r_user.twopointoh_email, '*****@*****.**')
    def test_user_authentication_success_if_user_already_exists(self):
        """
        Tests the end point of a user authenticating their ADS credentials via
        the web app, assuming that they have previously set something before
        """
        # Stub out the user in the database
        user = Users(absolute_uid=10,
                     classic_email='*****@*****.**',
                     classic_cookie='some cookie',
                     classic_mirror='other.mirror.com')
        db.session.add(user)
        db.session.commit()

        # 1. The user fills in their credentials
        # 2. The user submits their credentials to the end point
        url = url_for('authenticateuserclassic')

        with HTTMock(ads_classic_200):
            r = self.client.post(url,
                                 data=self.stub_user_data,
                                 headers={USER_ID_KEYWORD: 10})

        self.assertStatus(r, 200)

        self.assertEqual(r.json['classic_email'],
                         self.stub_user_data['classic_email'])
        self.assertTrue(r.json['classic_authed'])

        r_user = Users.query.filter(Users.absolute_uid == 10).one()

        self.assertEqual(r_user.classic_email,
                         self.stub_user_data['classic_email'])
        self.assertEqual(r_user.classic_mirror,
                         self.stub_user_data['classic_mirror'])
        self.assertIsInstance(r_user.classic_cookie, unicode)
Example #4
0
    def test_get_libraries_end_point(self):
        """
        Test the workflow of successfully retrieving a set of ADS 2.0 libraries
        """
        # Setup S3 mock data
        TestADSTwoPointOhLibraries.helper_s3_mock_setup()

        # Expected stub data
        stub_get_libraries = {
            'libraries': [{
                'name':
                'Name',
                'description':
                'Description',
                'documents': [
                    '2015MNRAS.446.4239E', '2015A&C....10...61E',
                    '2014A&A...562A.100E', '2013A&A...556A..23E'
                ]
            }]
        }

        # 1. The user is identified via header information
        # - Generate dummy user in database
        # - Give the header the correct information
        user = Users(absolute_uid=10, twopointoh_email='*****@*****.**')
        with self.app.session_scope() as session:
            session.add(user)
            session.commit()

            url = url_for('twopointohlibraries', uid=10)
            r = self.client.get(url)

            self.assertStatus(r, 200)
            self.assertEqual(r.json['libraries'],
                             stub_get_libraries['libraries'])
Example #5
0
    def test_get_myads_end_point(self):
        """
        Test the workflow of successfully retrieving myADS settings
        """
        stub_get_myads = {
            u'pre_aut,':
            u'Henneken, Edwin\r\nKurtz, Michael J.\r\nHernquist, L.\r\nIcke, V.\r\nMellema, G.\r\nRosvall, Martin\r\nBergstrom, Carl\r\nNewman, Mark',
            u'firstname': u'Edwin',
            u'phy_t1,':
            u'bibliometrics\r\ninformetrics\r\neigenfactor\r\nrecommendation\r\n=citation\r\n"digital library"',
            u'ast_t1,':
            u'bibliometrics\r\ninformetrics\r\neigenfactor\r\nrecommendation\r\n=citation\r\n"digital library"',
            u'phy_aut,':
            u'Henneken, Edwin\r\nKurtz, Michael J.\r\nHernquist, L.\r\nIcke, V.\r\nMellema, G.\r\nRosvall, Martin\r\nBergstrom, Carl\r\nNewman, Mark',
            u'ast_aut,':
            u'Henneken, Edwin\r\nKurtz, Michael J.\r\nHernquist, L.\r\nIcke, V.\r\nMellema, G.\r\nRosvall, Martin\r\nBergstrom, Carl\r\nNewman, Mark',
            u'phy_t2,':
            u'"digital library"\r\n"search engine"\r\n"information retrieval"\r\n',
            u'email': u'*****@*****.**',
            u'pre_t1,':
            u'bibliometrics\r\ninformetrics\r\neigenfactor\r\nrecommendation\r\n=citation\r\n"digital library"',
            u'daily_t1,': u'"gamma ray bursts"',
            u'groups': [u'astro-ph', u'cs', u'gr-qc', u'math-ph'],
            u'lastname': u'Henneken',
            u'ast_t2,':
            u'"digital library"\r\n"search engine"\r\n"information retrieval"\r\n',
            u'pre_t2,':
            u'"digital library"\r\n"search engine"\r\n"information retrieval"\r\n',
            u'id': 2093057
        }

        # 1. The user is identified via header information
        # - Generate dummy user in database
        # - Give the header the correct information
        user = Users(absolute_uid=10,
                     classic_cookie='ef9df8ds',
                     classic_mirror='mirror.com',
                     classic_email='*****@*****.**')
        with self.app.session_scope() as session:
            session.add(user)
            session.commit()

            # 2. The database is checked to see if the user exists, and the cookie
            # retrieved
            #  3. The ADS Classic end point is contacted, returning a 200, and the
            # content returned
            url = url_for('classicmyads', uid=10)

            with HTTMock(ads_classic_myads_200):
                r = self.client.get(url)

            self.assertStatus(r, 200)
            self.assertEqual(r.json, stub_get_myads)
    def test_get_export_end_point_when_aws_s3_error(self, mock_resource):
        """
        Test when there is an issue loading/accessing S3 storage
        """
        mock_resource.side_effect = Exception('Custom Error')

        user = Users(absolute_uid=10, twopointoh_email='*****@*****.**')
        db.session.add(user)
        db.session.commit()

        url = url_for('exporttwopointohlibraries', export='zotero')
        r = self.client.get(url, headers={USER_ID_KEYWORD: user.absolute_uid})

        self.assertStatus(r, TWOPOINTOH_AWS_PROBLEM['code'])
        self.assertEqual(r.json['error'], TWOPOINTOH_AWS_PROBLEM['message'])
    def test_get_libraries_end_point_when_aws_s3_error(self, mock_resource):
        """
        Test when this user has not associated any ADS 2.0 (classic) account
        """
        mock_resource.side_effect = Exception('Custom Error')

        user = Users(absolute_uid=10, twopointoh_email='*****@*****.**')
        db.session.add(user)
        db.session.commit()

        url = url_for('twopointohlibraries', uid=10)
        r = self.client.get(url)

        self.assertStatus(r, TWOPOINTOH_AWS_PROBLEM['code'])
        self.assertEqual(r.json['error'], TWOPOINTOH_AWS_PROBLEM['message'])
    def test_get_libraries_end_point_when_no_user_but_is_twopointoh(self):
        """
        Test when this user does not have a Classic account, but a 2.0 account
        """
        # 1. The user is identified via header information
        # - Generate dummy user in database
        # - Give the header the correct information
        user = Users(absolute_uid=10, twopointoh_email='*****@*****.**')
        db.session.add(user)
        db.session.commit()

        url = url_for('classiclibraries', uid=10)
        r = self.client.get(url)

        self.assertStatus(r, NO_CLASSIC_ACCOUNT['code'])
        self.assertEqual(r.json['error'], NO_CLASSIC_ACCOUNT['message'])
    def test_get_libraries_end_point_when_no_user(self):
        """
        Test when this user does not have any libraries
        """
        # 1. The user is identified via header information
        # - Generate dummy user in database
        # - Give the header the correct information
        user = Users(absolute_uid=10,
                     twopointoh_email='*****@*****.**')
        db.session.add(user)
        db.session.commit()

        url = url_for('twopointohlibraries', uid=10)
        r = self.client.get(url)

        self.assertStatus(r, NO_TWOPOINTOH_LIBRARIES['code'])
        self.assertEqual(r.json['error'], NO_TWOPOINTOH_LIBRARIES['message'])
Example #10
0
    def test_get_zotero_export_successfully_when_no_keyword(self):
        """
        Test that a user can get the expected zotero export. They press a
        button, which results in a zip file being returned. Within the zip file
        is a list of files, each one is a .bib file that corresponds to a
        library that a user had.
        """
        # Stub out the user in the database
        user = Users(absolute_uid=10, twopointoh_email='*****@*****.**')
        with self.app.session_scope() as session:
            session.add(user)
            session.commit()

            # Setup S3 storage
            TestExportADSTwoPointOhLibraries.helper_s3_mock_setup()

            url = url_for('exporttwopointohlibraries', export='zotero')

            with HTTMock(export_success_no_keyword):
                r = self.client.get(
                    url, headers={USER_ID_KEYWORD: user.absolute_uid})

            self.assertStatus(r, 200)
            self.assertIn('Content-Disposition', r.headers)
            self.assertEqual(r.headers['Content-Disposition'],
                             'attachment; filename=user_zotero.zip')

            zip_file = ZipFile(BytesIO(r.get_data()))
            zip_content = {
                name: zip_file.read(name)
                for name in zip_file.namelist()
            }
            self.assertEqual(zip_content.keys(), ['Name.bib', 'Name2.bib'])

            self.assertIn(
                'keywords = {tag1, tag2}',
                zip_content['Name.bib'],
            )
            self.assertIn('notes = {note1, note2}', zip_content['Name.bib'])

            self.assertNotIn(
                'tag1',
                zip_content['Name2.bib'],
            )
            self.assertNotIn('notes =', zip_content['Name2.bib'])
    def test_get_temporary_url_on_export(self):
        """
        The user should receive a temporary url when asking for an export
        """
        # Stub out the user in the database
        user = Users(absolute_uid=10, twopointoh_email='*****@*****.**')
        db.session.add(user)
        db.session.commit()

        # Setup S3 storage
        TestExportADSTwoPointOhLibraries.helper_s3_mock_setup()

        url = url_for('exporttwopointohlibraries', export='zotero')
        r = self.client.get(url, headers={USER_ID_KEYWORD: 10})
        self.assertIn(
            'https://adsabs-mongogut.s3.amazonaws.com/cb16a523-cdba-406b-bfff-edfd428248be.zotero.zip',
            r.json['url'],
        )
    def test_get_libraries_when_ads_classic_returns_non_200(self):
        """
        Tests that the expected response is returned when ADS classic returns a
        non-200 response
        """
        user = Users(absolute_uid=10,
                     classic_cookie='ef9df8ds',
                     classic_mirror='mirror.com',
                     classic_email='*****@*****.**')
        db.session.add(user)
        db.session.commit()

        url = url_for('classiclibraries', uid=10)
        with HTTMock(ads_classic_fail):
            r = self.client.get(url, headers={USER_ID_KEYWORD: 10})

        self.assertStatus(r, CLASSIC_UNKNOWN_ERROR['code'])
        self.assertEqual(r.json['error'], CLASSIC_UNKNOWN_ERROR['message'])
    def test_get_libraries_end_point_when_no_user_but_is_classic(self):
        """
        Test when this user does not have any libraries, but has Classic account
        """
        # 1. The user is identified via header information
        # - Generate dummy user in database
        # - Give the header the correct information
        user = Users(absolute_uid=10,
                     classic_cookie='ef9df8ds',
                     classic_mirror='mirror.com',
                     classic_email='*****@*****.**')
        db.session.add(user)
        db.session.commit()

        url = url_for('twopointohlibraries', uid=10)
        r = self.client.get(url)

        self.assertStatus(r, NO_TWOPOINTOH_ACCOUNT['code'])
        self.assertEqual(r.json['error'], NO_TWOPOINTOH_ACCOUNT['message'])
    def test_get_libraries_when_ads_classic_timesout(self, mocked_get):
        """
        Test that if ADS Classic times out before finishing the request, that
        the libraries end point returns a known error
        """
        user = Users(absolute_uid=10,
                     classic_cookie='ef9df8ds',
                     classic_mirror='mirror.com',
                     classic_email='*****@*****.**')
        db.session.add(user)
        db.session.commit()

        mocked_get.side_effect = Timeout

        url = url_for('classiclibraries', uid=10)

        r = self.client.get(url)

        self.assertStatus(r, CLASSIC_TIMEOUT['code'])
        self.assertEqual(r.json['error'], CLASSIC_TIMEOUT['message'])
    def test_user_successfully_retrieves_ads_classic_settings(self):
        """
        Tests that the user successfully retrieves their settings for the ADS
        Classic service
        """
        # Stub data
        user = Users(absolute_uid=10,
                     classic_email='*****@*****.**',
                     classic_cookie='some cookie',
                     classic_mirror='mirror.com')
        db.session.add(user)
        db.session.commit()

        # Ask the end point
        url = url_for('classicuser')
        r = self.client.get(url, headers={USER_ID_KEYWORD: 10})

        # Check we get what we expected
        self.assertStatus(r, 200)
        self.assertEqual(r.json['classic_email'], user.classic_email)
        self.assertEqual(r.json['classic_mirror'], user.classic_mirror)
        self.assertEqual(r.json['twopointoh_email'], '')
Example #16
0
    def test_get_libraries_end_point(self):
        """
        Test the workflow of successfully retrieving a set of classic libraries
        """
        stub_get_libraries = {
            'libraries': [{
                'name':
                'Name',
                'description':
                'Description',
                'documents': [
                    '2015MNRAS.446.4239E', '2015A&C....10...61E',
                    '2014A&A...562A.100E', '2013A&A...556A..23E'
                ]
            }]
        }

        # 1. The user is identified via header information
        # - Generate dummy user in database
        # - Give the header the correct information
        user = Users(absolute_uid=10,
                     classic_cookie='ef9df8ds',
                     classic_mirror='mirror.com',
                     classic_email='*****@*****.**')
        with self.app.session_scope() as session:
            session.add(user)
            session.commit()

            # 2. The database is checked to see if the user exists, and the cookie
            # retrieved
            #  3. The ADS Classic end point is contacted, returning a 200, and the
            # content returned
            url = url_for('classiclibraries', uid=10)
            with HTTMock(ads_classic_libraries_200):
                r = self.client.get(url)
            self.assertStatus(r, 200)
            self.assertEqual(r.json['libraries'],
                             stub_get_libraries['libraries'])
Example #17
0
    def post(self):
        """
        HTTP POST request that receives the user's ADS 2.0 credentials, and
        then contacts the Classic system to check that what the user provided
        is indeed valid. If valid, the users ID is stored.

        Post body:
        ----------
        KEYWORD, VALUE
        twopointoh_email: <string> ADS 2.0 e-mail of the user
        twopointoh_password: <string> ADS 2.0 password of the user

        Return data (on success):
        -------------------------
        twopointoh_authed: <boolean> were they authenticated
        twopointoh_email: <string> e-mail that authenticated correctly

        HTTP Responses:
        --------------
        Succeed authentication: 200
        Bad/malformed data: 400
        User unknown/wrong password/failed authentication: 404
        ADS Classic give unknown messages: 500
        ADS Classic times out: 504

        Any other responses will be default Flask errors
        """
        post_data = get_post_data(request)

        # Collect the username, password from the request
        try:
            twopointoh_email = post_data['twopointoh_email']
            twopointoh_password = post_data['twopointoh_password']
        except KeyError:
            current_app.logger.warning(
                'User did not provide a required key: {}'.format(
                    traceback.print_exc()))
            return err(CLASSIC_DATA_MALFORMED)

        # Create the correct URL
        url = current_app.config['ADS_CLASSIC_URL'].format(
            mirror=current_app.config['ADS_TWO_POINT_OH_MIRROR'], )
        params = {
            'man_cmd': 'elogin',
            'man_email': twopointoh_email,
            'man_passwd': twopointoh_password
        }

        # Authenticate
        current_app.logger.info(
            'User "{email}" trying to authenticate"'.format(
                email=twopointoh_email))
        try:
            response = current_app.client.post(url, params=params)
        except requests.exceptions.Timeout:
            current_app.logger.warning(
                'ADS Classic end point timed out, returning to user')
            return err(CLASSIC_TIMEOUT)

        if response.status_code >= 500:
            message, status_code = err(CLASSIC_UNKNOWN_ERROR)
            message['ads_classic'] = {
                'message': response.text,
                'status_code': response.status_code
            }
            current_app.logger.warning(
                'ADS Classic has responded with an unknown error: {}'.format(
                    response.text))
            return message, status_code

        # Sanity check the response
        email = response.json()['email']
        if email != twopointoh_email:
            current_app.logger.warning(
                'User email "{}" does not match ADS return email "{}"'.format(
                    twopointoh_email, email))
            return err(CLASSIC_AUTH_FAILED)

        # Respond to the user based on whether they were successful or not
        if response.status_code == 200 \
                and response.json()['message'] == 'LOGGED_IN' \
                and int(response.json()['loggedin']):
            current_app.logger.info(
                'Authenticated successfully "{email}"'.format(
                    email=twopointoh_email))

            absolute_uid = self.helper_get_user_id()
            with current_app.session_scope() as session:
                try:
                    user = session.query(Users).filter(
                        Users.absolute_uid == absolute_uid).one()

                    current_app.logger.info('User already exists in database')
                    user.twopointoh_email = twopointoh_email
                except NoResultFound:
                    current_app.logger.info(
                        'Creating entry in database for user')
                    user = Users(absolute_uid=absolute_uid,
                                 twopointoh_email=twopointoh_email)
                    session.add(user)
                session.commit()

                current_app.logger.info(
                    'Successfully saved content for "{}" to database'.format(
                        twopointoh_email))

                return {
                    'twopointoh_email': email,
                    'twopointoh_authed': True
                }, 200
            return err(HARBOUR_SERVICE_FAIL)
        else:
            current_app.logger.warning(
                'ADS 2.0 credentials for "{email}" did not succeed"'.format(
                    email=twopointoh_email))
            return err(CLASSIC_AUTH_FAILED)
Example #18
0
    def post(self):
        """
        HTTP POST request that receives the user's ADS Classic credentials, and
        then contacts the Classic system to check that what the user provided is
        indeed valid. If valid, the users ID is stored within the myADS service
        store.

        Post body:
        ----------
        KEYWORD, VALUE
        classic_email: <string> ADS Classic e-mail of the user
        classic_password: <string> ADS Classic password of the user
        classic_mirror: <string> ADS Classic mirror this user belongs to

        Return data (on success):
        -------------------------
        classic_authed: <boolean> were they authenticated
        classic_email: <string> e-mail that authenticated correctly
        classic_mirror: <string> ADS Classic mirror this user selected

        HTTP Responses:
        --------------
        Succeed authentication: 200
        Bad/malformed data: 400
        User unknown/wrong password/failed authentication: 404
        ADS Classic give unknown messages: 500
        ADS Classic times out: 504

        Any other responses will be default Flask errors
        """
        post_data = get_post_data(request)
        with current_app.session_scope() as session:
            # Collect the username, password from the request
            try:
                classic_email = post_data['classic_email']
                classic_password = post_data['classic_password']
                classic_mirror = post_data['classic_mirror']
            except KeyError:
                current_app.logger.warning(
                    'User did not provide a required key: {}'.format(
                        traceback.print_exc()))
                return err(CLASSIC_DATA_MALFORMED)

            # Check that the mirror exists and not man-in-the-middle
            if classic_mirror not in current_app.config[
                    'ADS_CLASSIC_MIRROR_LIST']:
                current_app.logger.warning(
                    'User "{}" tried to use a mirror that does not exist: "{}"'
                    .format(classic_email, classic_mirror))
                return err(CLASSIC_BAD_MIRROR)

            # Create the correct URL
            url = current_app.config['ADS_CLASSIC_URL'].format(
                mirror=classic_mirror, )
            params = {
                'man_cmd': 'elogin',
                'man_email': classic_email,
                'man_passwd': classic_password
            }

            # Authenticate
            current_app.logger.info(
                'User "{email}" trying to authenticate at mirror "{mirror}"'.
                format(email=classic_email, mirror=classic_mirror))
            try:
                response = current_app.client.post(url, params=params)
            except requests.exceptions.Timeout:
                current_app.logger.warning(
                    'ADS Classic end point timed out, returning to user')
                return err(CLASSIC_TIMEOUT)

            if response.status_code >= 500:
                message, status_code = err(CLASSIC_UNKNOWN_ERROR)
                message['ads_classic'] = {
                    'message': response.text,
                    'status_code': response.status_code
                }
                current_app.logger.warning(
                    'ADS Classic has responded with an unknown error: {}'.
                    format(response.text))
                return message, status_code

            # Sanity check the response
            email = response.json()['email']
            if email != classic_email:
                current_app.logger.warning(
                    'User email "{}" does not match ADS return email "{}"'.
                    format(classic_email, email))
                return err(CLASSIC_AUTH_FAILED)

            # Respond to the user based on whether they were successful or not
            if response.status_code == 200 \
                    and response.json()['message'] == 'LOGGED_IN' \
                    and int(response.json()['loggedin']):
                current_app.logger.info(
                    'Authenticated successfully "{email}" at mirror "{mirror}"'
                    .format(email=classic_email, mirror=classic_mirror))

                # Save cookie in myADS
                try:
                    cookie = response.json()['cookie']
                except KeyError:
                    current_app.logger.warning(
                        'Classic returned no cookie, cannot continue: {}'.
                        format(response.json()))
                    return err(CLASSIC_NO_COOKIE)

                absolute_uid = self.helper_get_user_id()
                try:
                    user = session.query(Users).filter(
                        Users.absolute_uid == absolute_uid).one()

                    current_app.logger.info('User already exists in database')
                    user.classic_mirror = classic_mirror
                    user.classic_cookie = cookie
                    user.classic_email = classic_email
                except NoResultFound:
                    current_app.logger.info(
                        'Creating entry in database for user')
                    user = Users(absolute_uid=absolute_uid,
                                 classic_cookie=cookie,
                                 classic_email=classic_email,
                                 classic_mirror=classic_mirror)

                    session.add(user)

                session.commit()
                current_app.logger.info(
                    'Successfully saved content for "{}" to database: {{"cookie": "{}"}}'
                    .format(classic_email, '*' * len(user.classic_cookie)))

                return {
                    'classic_email': email,
                    'classic_mirror': classic_mirror,
                    'classic_authed': True
                }, 200

            else:
                current_app.logger.warning(
                    'Credentials for "{email}" did not succeed at mirror "{mirror}"'
                    .format(email=classic_email, mirror=classic_mirror))
                return err(CLASSIC_AUTH_FAILED)