def test_has_home_project(self): from pillar.api.blender_cloud import home_project from pillar.api.utils.authentication import validate_token user_id = self._create_user_with_token(roles={'subscriber'}, token='token') # Test home project creation with self.app.test_request_context( headers={'Authorization': self.make_header('token')}): validate_token() self.assertFalse(home_project.has_home_project(user_id)) proj = home_project.create_home_project(user_id, write_access=True) self.assertTrue(home_project.has_home_project(user_id)) # Delete the project. resp = self.client.delete('/api/projects/%s' % proj['_id'], headers={ 'Authorization': self.make_header('token'), 'If-Match': proj['_etag'] }) self.assertEqual(204, resp.status_code, resp.data) self.assertFalse(home_project.has_home_project(user_id))
def test_create_home_project(self): from pillar.api.blender_cloud import home_project from pillar.api.utils.authentication import validate_token user_id = self._create_user_with_token(roles={'subscriber'}, token='token') # Test home project creation with self.app.test_request_context( headers={'Authorization': self.make_header('token')}): validate_token() proj = home_project.create_home_project(user_id, write_access=True) self.assertEqual('home', proj['category']) self.assertEqual({'group', 'asset', 'comment'}, set(nt['name'] for nt in proj['node_types'])) endpoint = url_for('blender_cloud.home_project.home_project') db_proj = self.app.data.driver.db['projects'].find_one(proj['_id']) # Test availability at end-point resp = self.client.get(endpoint) # While we're still AB-testing, unauthenticated users should get a 404. # When that's over, it should result in a 403. self.assertEqual(403, resp.status_code) resp = self.client.get( endpoint, headers={'Authorization': self.make_header('token')}) self.assertEqual(200, resp.status_code) json_proj = json.loads(resp.data) self.assertEqual(ObjectId(json_proj['_id']), proj['_id']) self.assertEqual(json_proj['_etag'], db_proj['_etag'])
def test_multiple_users_with_home_project(self): from pillar.api.blender_cloud import home_project from pillar.api.utils.authentication import validate_token uid1 = self._create_user_with_token(roles={'subscriber'}, token='token1', user_id=24 * 'a') uid2 = self._create_user_with_token(roles={'subscriber'}, token='token2', user_id=24 * 'b') # Create home projects with self.app.test_request_context(headers={'Authorization': self.make_header('token1')}): validate_token() proj1 = home_project.create_home_project(uid1, write_access=True) db_proj1 = self.app.data.driver.db['projects'].find_one(proj1['_id']) with self.app.test_request_context(headers={'Authorization': self.make_header('token2')}): validate_token() proj2 = home_project.create_home_project(uid2, write_access=True) db_proj2 = self.app.data.driver.db['projects'].find_one(proj2['_id']) # Test availability at end-point resp1 = self.client.get('/api/bcloud/home-project', headers={'Authorization': self.make_header('token1')}) resp2 = self.client.get('/api/bcloud/home-project', headers={'Authorization': self.make_header('token2')}) self.assertEqual(200, resp1.status_code) self.assertEqual(200, resp2.status_code) json_proj1 = json.loads(resp1.data) json_proj2 = json.loads(resp2.data) self.assertEqual(ObjectId(json_proj1['_id']), proj1['_id']) self.assertEqual(ObjectId(json_proj2['_id']), proj2['_id']) self.assertEqual(json_proj1['_etag'], db_proj1['_etag']) self.assertEqual(json_proj2['_etag'], db_proj2['_etag']) self.assertNotEqual(db_proj1['_etag'], db_proj2['_etag']) self.assertNotEqual(db_proj1['_id'], db_proj2['_id'])
def test_revoking_subscriber_role(self): from pillar.api.blender_cloud import home_project from pillar.api.utils.authentication import validate_token self.user_id = self.create_user(roles=set('subscriber')) self.create_valid_auth_token(self.user_id, 'token') with self.app.test_request_context(headers={'Authorization': self.make_header('token')}): validate_token() home_proj = home_project.create_home_project(self.user_id, write_access=True) changed = home_project.user_changed_role(None, {'_id': self.user_id, 'roles': []}) self.assertTrue(changed) # The home project should NOT be writable, so we should NOT be able to create a node. self.create_test_node(home_proj['_id'], 403)
def test_validate_token__unknown_but_valid_token(self): """Test validating of valid token, unknown to us but known to Blender ID.""" from pillar.api.utils import authentication as auth self.mock_blenderid_validate_happy() with self.app.test_request_context( headers={'Authorization': self.make_header('knowntoken')}): self.assertTrue(auth.validate_token())
def test_validate_token__force_not_logged_in(self): from pillar.api.utils import authentication as auth from pillar.auth import UserClass, current_user with self.app.test_request_context(): from flask import g g.current_user = UserClass('12345') self.assertTrue(g.current_user.is_authenticated) self.assertFalse(auth.validate_token(force=True)) self.assertFalse(g.current_user.is_authenticated)
def test_validate_token__force_logged_in(self): from pillar.api.utils import authentication as auth from pillar.auth import UserClass self.mock_blenderid_validate_happy() with self.app.test_request_context( headers={'Authorization': self.make_header('knowntoken')}): from flask import g g.current_user = UserClass('12345') self.assertTrue(g.current_user.is_authenticated) self.assertTrue(auth.validate_token(force=True)) self.assertTrue(g.current_user.is_authenticated)
def test_authenticate_with_scst(self): # Make sure there is a user and SCST. db_user = self._common_user_test(201) # Make a call that's authenticated with the SCST from pillar.api.utils import authentication as auth subclient_id = self.app.config['BLENDER_ID_SUBCLIENT_ID'] auth_header = self.make_header(TEST_SUBCLIENT_TOKEN, subclient_id) with self.app.test_request_context(headers={'Authorization': auth_header}): self.assertTrue(auth.validate_token()) self.assertIsNotNone(g.current_user) self.assertEqual(db_user['_id'], g.current_user.user_id)
def test_find_token(self): """Test finding of various tokens.""" from pillar.api.utils import authentication as auth user_id = self.create_user() now = datetime.datetime.now(tz_util.utc) future = now + datetime.timedelta(days=1) past = now - datetime.timedelta(days=1) subclient = self.app.config['BLENDER_ID_SUBCLIENT_ID'] with self.app.test_request_context(): auth.store_token(user_id, 'nonexpired-main', future, None) auth.store_token(user_id, 'nonexpired-sub', future, subclient) token3 = auth.store_token(user_id, 'expired-sub', past, subclient) with self.app.test_request_context( headers={'Authorization': self.make_header('nonexpired-main') }): self.assertTrue(auth.validate_token()) with self.app.test_request_context(headers={ 'Authorization': self.make_header('nonexpired-main', subclient) }): self.assertFalse(auth.validate_token()) with self.app.test_request_context( headers={'Authorization': self.make_header('nonexpired-sub')}): self.assertFalse(auth.validate_token()) with self.app.test_request_context(headers={ 'Authorization': self.make_header('nonexpired-sub', subclient) }): self.assertTrue(auth.validate_token()) with self.app.test_request_context( headers={ 'Authorization': self.make_header('expired-sub', subclient) }): self.assertFalse(auth.validate_token()) self.mock_blenderid_validate_happy() with self.app.test_request_context( headers={ 'Authorization': self.make_header('expired-sub', subclient) }): self.assertTrue(auth.validate_token()) # We now should be able to find a new token for this user. found_token = auth.find_token('expired-sub', subclient) self.assertIsNotNone(found_token) self.assertNotEqual(token3['_id'], found_token['_id'])
def create_home_project(user_id, write_access): """Creates a home project for the given user. :param user_id: the user ID of the owner :param write_access: whether the user has full write access to the home project. :type write_access: bool :returns: the project :rtype: dict """ log.info('Creating home project for user %s', user_id) overrides = { 'category': 'home', 'url': 'home', 'summary': HOME_PROJECT_SUMMARY, 'description': HOME_PROJECT_DESCRIPTION } # Maybe the user has a deleted home project. proj_coll = current_app.data.driver.db['projects'] deleted_proj = proj_coll.find_one({ 'user': user_id, 'category': 'home', '_deleted': True }) if deleted_proj: log.info('User %s has a deleted project %s, restoring', user_id, deleted_proj['_id']) project = deleted_proj else: log.debug('User %s does not have a deleted project', user_id) project = proj_utils.create_new_project(project_name='Home', user_id=ObjectId(user_id), overrides=overrides) # Re-validate the authentication token, so that the put_internal call sees the # new group created for the project. authentication.validate_token(force=True) # There are a few things in the on_insert_projects hook we need to adjust. # Ensure that the project is private, even for admins. project['permissions']['world'] = [] # Set up the correct node types. No need to set permissions for them, # as the inherited project permissions are fine. from pillar.api.node_types.group import node_type_group from pillar.api.node_types.asset import node_type_asset # from pillar.api.node_types.text import node_type_text from pillar.api.node_types.comment import node_type_comment # For non-subscribers: take away write access from the admin group, # and grant it to certain node types. project['permissions']['groups'][0]['methods'] = home_project_permissions( write_access) # Everybody should be able to comment on anything in this project. # This allows people to comment on shared images and see comments. node_type_comment = assign_permissions(node_type_comment, subscriber_methods=['GET', 'POST'], world_methods=['GET']) project['node_types'] = [ node_type_group, node_type_asset, # node_type_text, node_type_comment, ] result, _, _, status = current_app.put_internal( 'projects', utils.remove_private_keys(project), _id=project['_id']) if status != 200: log.error('Unable to update home project %s for user %s: %s', project['_id'], user_id, result) raise wz_exceptions.InternalServerError( 'Unable to update home project') project.update(result) # Create the Blender Sync node, with explicit write permissions on the node itself. create_blender_sync_node(project['_id'], project['permissions']['groups'][0]['group'], user_id) return project
def test_validate_token__not_logged_in(self): from pillar.api.utils import authentication as auth with self.app.test_request_context(): self.assertFalse(auth.validate_token())