def test_permissions_revoke_all_iam_permissions(clean_db, monkeypatch): """ Smoke test that Permissions.revoke_all_iam_permissions calls revoke_download_access the right arguments. """ gcloud_client = mock_gcloud_client(monkeypatch) user = Users(email="*****@*****.**") user.insert() trial = TrialMetadata(trial_id=TRIAL_ID, metadata_json=METADATA) trial.insert() upload_types = ["wes_bam", "ihc", "rna_fastq", "plasma"] for upload_type in upload_types: Permissions( granted_to_user=user.id, trial_id=trial.trial_id, upload_type=upload_type, granted_by_user=user.id, ).insert() Permissions.revoke_all_iam_permissions() gcloud_client.revoke_download_access.assert_has_calls( [call(user.email, trial.trial_id, upload_type) for upload_type in upload_types] ) # not called on admins or nci biobank users gcloud_client.revoke_download_access.reset_mock() for role in [CIDCRole.ADMIN.value, CIDCRole.NCI_BIOBANK_USER.value]: user.role = role user.update() Permissions.revoke_all_iam_permissions() gcloud_client.revoke_download_access.assert_not_called()
def test_permissions_delete(clean_db, monkeypatch, caplog): gcloud_client = mock_gcloud_client(monkeypatch) user = Users(email="*****@*****.**") user.insert() trial = TrialMetadata(trial_id=TRIAL_ID, metadata_json=METADATA) trial.insert() perm = Permissions( granted_to_user=user.id, trial_id=trial.trial_id, upload_type="wes_bam", granted_by_user=user.id, ) perm.insert() # Deleting a record by a user doesn't exist leads to an error gcloud_client.reset_mocks() with pytest.raises(NoResultFound, match="no user with id"): perm.delete(deleted_by=999999) # Deletion of an existing permission leads to no error gcloud_client.reset_mocks() with caplog.at_level(logging.DEBUG): perm.delete(deleted_by=user.id) gcloud_client.revoke_download_access.assert_called_once() gcloud_client.grant_download_access.assert_not_called() assert any( log_record.message.strip() == f"admin-action: {user.email} removed from {user.email} the permission wes_bam on {trial.trial_id}" for log_record in caplog.records ) # Deleting an already-deleted record is idempotent gcloud_client.reset_mocks() perm.delete(deleted_by=user) gcloud_client.revoke_download_access.assert_called_once() gcloud_client.grant_download_access.assert_not_called() # Deleting a record whose user doesn't exist leads to an error gcloud_client.reset_mocks() with pytest.raises(NoResultFound, match="no user with id"): Permissions(granted_to_user=999999).delete(deleted_by=user) gcloud_client.revoke_download_access.assert_not_called() gcloud_client.grant_download_access.assert_not_called() # If revoking a permission from a "network-viewer", no GCS IAM actions are taken gcloud_client.revoke_download_access.reset_mock() user.role = CIDCRole.NETWORK_VIEWER.value user.update() perm = Permissions( granted_to_user=user.id, trial_id=trial.trial_id, upload_type="ihc", granted_by_user=user.id, ) perm.insert() perm.delete(deleted_by=user) gcloud_client.revoke_download_access.assert_not_called()
def setup_users(cidc_api, monkeypatch, registered=True) -> Tuple[int, int]: """ Insert two users into the database. If `registered=False`, don't register the first user. """ current_user = Users(id=1, email="*****@*****.**") other_user = Users(id=2, email="*****@*****.**") mock_current_user(current_user, monkeypatch) with cidc_api.app_context(): if registered: current_user.role = CIDCRole.CIMAC_USER.value current_user.approval_date = datetime.now() current_user.insert() other_user.insert() return current_user.id, other_user.id
def test_permissions_grant_iam_permissions(clean_db, monkeypatch): """ Smoke test that Permissions.grant_iam_permissions calls grant_download_access with the right arguments. """ refresh_intake_access = MagicMock() monkeypatch.setattr( "cidc_api.models.models.refresh_intake_access", refresh_intake_access ) gcloud_client = mock_gcloud_client(monkeypatch) user = Users(email="*****@*****.**", role=CIDCRole.NETWORK_VIEWER.value) user.insert() trial = TrialMetadata(trial_id=TRIAL_ID, metadata_json=METADATA) trial.insert() upload_types = ["wes_bam", "ihc", "rna_fastq", "plasma"] for upload_type in upload_types: Permissions( granted_to_user=user.id, trial_id=trial.trial_id, upload_type=upload_type, granted_by_user=user.id, ).insert() # IAM permissions not granted to network viewers Permissions.grant_iam_permissions(user=user) gcloud_client.grant_download_access.assert_not_called() # IAM permissions should be granted for any other role user.role = CIDCRole.CIMAC_USER.value Permissions.grant_iam_permissions(user=user) for upload_type in upload_types: assert ( call(user.email, trial.trial_id, upload_type) in gcloud_client.grant_download_access.call_args_list ) refresh_intake_access.assert_called_once_with(user.email)
def test_permissions_insert(clean_db, monkeypatch, caplog): gcloud_client = mock_gcloud_client(monkeypatch) user = Users(email="*****@*****.**") user.insert() trial = TrialMetadata(trial_id=TRIAL_ID, metadata_json=METADATA) trial.insert() _insert = MagicMock() monkeypatch.setattr(CommonColumns, "insert", _insert) # if upload_type is invalid with pytest.raises(ValueError, match="invalid upload type"): Permissions(upload_type="foo", granted_to_user=user.id, trial_id=trial.trial_id) # if don't give granted_by_user perm = Permissions( granted_to_user=user.id, trial_id=trial.trial_id, upload_type="wes_bam" ) with pytest.raises(IntegrityError, match="`granted_by_user` user must be given"): perm.insert() _insert.assert_not_called() # if give bad granted_by_user _insert.reset_mock() perm = Permissions( granted_to_user=user.id, trial_id=trial.trial_id, upload_type="wes_bam", granted_by_user=999999, ) with pytest.raises(IntegrityError, match="`granted_by_user` user must exist"): perm.insert() _insert.assert_not_called() # if give bad granted_to_user _insert.reset_mock() perm = Permissions( granted_to_user=999999, trial_id=trial.trial_id, upload_type="wes_bam", granted_by_user=user.id, ) with pytest.raises(IntegrityError, match="`granted_to_user` user must exist"): perm.insert() _insert.assert_not_called() # This one will work _insert.reset_mock() perm = Permissions( granted_to_user=user.id, trial_id=trial.trial_id, upload_type="wes_bam", granted_by_user=user.id, ) with caplog.at_level(logging.DEBUG): perm.insert() _insert.assert_called_once() assert any( log_record.message.strip() == f"admin-action: {user.email} gave {user.email} the permission wes_bam on {trial.trial_id}" for log_record in caplog.records ) gcloud_client.grant_download_access.assert_called_once() # If granting a permission to a "network-viewer", no GCS IAM actions are taken _insert.reset_mock() gcloud_client.grant_download_access.reset_mock() user.role = CIDCRole.NETWORK_VIEWER.value user.update() perm = Permissions( granted_to_user=user.id, trial_id=trial.trial_id, upload_type="ihc", granted_by_user=user.id, ) perm.insert() _insert.assert_called_once() gcloud_client.grant_download_access.assert_not_called()
def test_authorize(cidc_api, clean_db): """Check that authorization works as expected.""" user = Users(**PAYLOAD) with cidc_api.app_context(): # Unregistered user should not be authorized to do anything to any resource except "users" with pytest.raises(Unauthorized, match="not registered"): auth.authorize(user, [], "some-resource", "some-http-method") # We can't track accesses for users who aren't registered assert user._accessed is None # Unregistered user should not be able to GET users with pytest.raises(Unauthorized, match="not registered"): auth.authorize(user, [], "users", "GET") assert user._accessed is None # Unregistered user should not be able to GET self with pytest.raises(Unauthorized, match="not registered"): auth.authorize(user, [], "self", "GET") assert user._accessed is None # Unregistered user should be able to POST users assert auth.authorize(user, [], "self", "POST") # Add the user to the db but don't approve yet user.insert() # Unapproved user isn't authorized to do anything with pytest.raises(Unauthorized, match="pending approval"): auth.authorize(user, [], "self", "POST") # Check that we tracked this user's last access assert user._accessed.date() == date.today() _accessed = user._accessed # Ensure unapproved user can access their own data assert auth.authorize(user, [], "self", "GET") # Give the user a role but don't approve them user.role = CIDCRole.CIMAC_USER.value user.update() # Unapproved user *with an authorized role* still shouldn't be authorized with pytest.raises(Unauthorized, match="pending approval"): auth.authorize(user, [CIDCRole.CIMAC_USER.value], "self", "POST") # Approve the user user.approval_date = datetime.now() user.update() # If user doesn't have required role, they should not be authorized. with pytest.raises(Unauthorized, match="not authorized to access"): auth.authorize(user, [CIDCRole.ADMIN.value], "some-resource", "some-http-method") # If user has an allowed role, they should be authorized assert auth.authorize(user, [CIDCRole.CIMAC_USER.value], "some-resource", "some-http-method") # If the resource has no role restrictions, they should be authorized assert auth.authorize(user, [], "some-resource", "some-http-method") # Disable user user.disabled = True user.update() # If user has an allowed role but is disabled, they should be unauthorized with pytest.raises(Unauthorized, match="disabled"): auth.authorize(user, [CIDCRole.CIMAC_USER.value], "some-resource", "some-http-method") # Ensure unapproved user can access their own data assert auth.authorize(user, [], "self", "GET") # If the resource has no role restrictions, they should be still unauthorized with pytest.raises(Unauthorized, match="disabled"): auth.authorize(user, [], "some-resource", "some-http-method") # Check that user's last access wasn't updated by all activity, # since it occurred on the same day as previous accesses assert user._accessed == _accessed