Esempio n. 1
0
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()
Esempio n. 2
0
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()
Esempio n. 3
0
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
Esempio n. 4
0
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)
Esempio n. 5
0
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()
Esempio n. 6
0
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