예제 #1
0
def test_user_tries_deleting_his_profile_but_it_fails_partially(
    user_gql_client, service_1, service_2, mocker
):
    """Test an edge case where dry runs passes for all connected services, but the
    proper service connection delete fails for a single connected service. All other
    connected services should still get deleted.
    """

    def mock_delete_gdpr_data(self, api_token, dry_run=False):
        if self.service.name == service_2.name and not dry_run:
            raise requests.HTTPError("Such big fail! :(")

    mocker.patch.object(
        ServiceConnection,
        "delete_gdpr_data",
        autospec=True,
        side_effect=mock_delete_gdpr_data,
    )
    mocker.patch.object(
        TunnistamoTokenExchange, "fetch_api_tokens", return_value=GDPR_API_TOKENS
    )
    profile = ProfileFactory(user=user_gql_client.user)
    ServiceConnectionFactory(profile=profile, service=service_1)
    ServiceConnectionFactory(profile=profile, service=service_2)

    executed = user_gql_client.execute(DELETE_MY_PROFILE_MUTATION)

    expected_data = {"deleteMyProfile": None}

    assert ServiceConnection.objects.count() == 1
    assert ServiceConnection.objects.first().service == service_2
    assert dict(executed["data"]) == expected_data
    assert_match_error_code(executed, CONNECTED_SERVICE_DELETION_FAILED_ERROR)
예제 #2
0
def test_user_deletion_from_keycloak(
    user_gql_client, mocker, kc_delete_user_response_code, keycloak_setup
):
    user = user_gql_client.user
    profile = ProfileFactory(user=user)

    def kc_delete_user_response(*args, **kwargs):
        response = requests.Response()
        response.status_code = kc_delete_user_response_code
        response.raise_for_status()

    mocked_keycloak_delete_user = mocker.patch.object(
        KeycloakAdminClient, "delete_user", side_effect=kc_delete_user_response
    )

    executed = user_gql_client.execute(DELETE_MY_PROFILE_MUTATION)

    if kc_delete_user_response_code in [204, 404]:
        assert executed["data"] == {"deleteMyProfile": {"clientMutationId": None}}
        assert "errors" not in executed
    else:
        assert Profile.objects.filter(pk=profile.pk).exists()
        assert executed["data"]["deleteMyProfile"] is None
        assert_match_error_code(executed, "CONNECTED_SERVICE_DELETION_FAILED_ERROR")

    mocked_keycloak_delete_user.assert_called_once_with(user.uuid)
def test_anon_user_can_not_claim_claimable_profile(anon_user_gql_client):
    profile = ProfileWithPrimaryEmailFactory(
        user=None, first_name="John", last_name="Doe"
    )
    claim_token = ClaimTokenFactory(profile=profile)

    t = Template(
        """
        mutation {
            claimProfile(
                input: {
                    token: "${claimToken}"
                }
            ) {
                profile {
                    id
                }
            }
        }
        """
    )
    query = t.substitute(claimToken=claim_token.token)

    executed = anon_user_gql_client.execute(query)
    assert_match_error_code(executed, "PERMISSION_DENIED_ERROR")
예제 #4
0
def test_normal_user_can_query_his_own_profile(user_gql_client, service,
                                               with_service,
                                               with_serviceconnection):
    profile = ProfileFactory(user=user_gql_client.user)
    if with_serviceconnection:
        ServiceConnectionFactory(profile=profile, service=service)

    query = """
        {
            myProfile {
                firstName
                lastName
            }
        }
    """
    expected_data = {
        "myProfile": {
            "firstName": profile.first_name,
            "lastName": profile.last_name
        }
    }
    executed = user_gql_client.execute(
        query, service=service if with_service else None)

    if with_service and with_serviceconnection:
        assert executed["data"] == expected_data
    elif not with_service:
        assert_match_error_code(executed, "SERVICE_NOT_IDENTIFIED_ERROR")
        assert executed["data"]["myProfile"] is None
    else:
        assert_match_error_code(executed, "PERMISSION_DENIED_ERROR")
        assert executed["data"]["myProfile"] is None
예제 #5
0
def test_user_can_delete_his_profile(
    user_gql_client,
    profile_service,
    service_1,
    requests_mock,
    mocker,
    with_serviceconnection,
):
    """Deletion is allowed when GDPR URL is set, and service returns a successful status."""
    profile = ProfileFactory(user=user_gql_client.user)
    ServiceConnectionFactory(profile=profile, service=profile_service)

    if with_serviceconnection:
        requests_mock.delete(
            f"{service_1.gdpr_url}{profile.pk}", json={}, status_code=204
        )
        ServiceConnectionFactory(profile=profile, service=service_1)
        mocker.patch.object(
            TunnistamoTokenExchange, "fetch_api_tokens", return_value=GDPR_API_TOKENS
        )

    executed = user_gql_client.execute(DELETE_MY_PROFILE_MUTATION, service=service_1)

    if with_serviceconnection:
        expected_data = {"deleteMyProfile": {"clientMutationId": None}}
        assert executed["data"] == expected_data

        with pytest.raises(Profile.DoesNotExist):
            profile.refresh_from_db()
        with pytest.raises(User.DoesNotExist):
            user_gql_client.user.refresh_from_db()
    else:
        assert_match_error_code(executed, "PERMISSION_DENIED_ERROR")
        assert executed["data"]["deleteMyProfile"] is None
        assert Profile.objects.filter(pk=profile.pk).exists()
def test_giving_non_existing_service_client_id_results_in_object_does_not_exist_error(
    user_gql_client, ):
    input_data = service_input_data(uuid.uuid1(), "not_existing")

    executed = execute_mutation(input_data, user_gql_client)

    assert_match_error_code(executed, "OBJECT_DOES_NOT_EXIST_ERROR")
def test_staff_user_can_resolve_address_entity(
    user_gql_client, group, service, with_serviceconnection
):
    address, variables = _create_address_and_variables(with_serviceconnection, service)
    user = user_gql_client.user
    user.groups.add(group)
    assign_perm("can_view_profiles", group, service)

    expected_data = {
        "_entities": [
            {
                "id": address._global_id,
                "address": address.address,
                "postalCode": address.postal_code,
            }
        ]
    }
    executed = user_gql_client.execute(
        ENTITY_QUERY, variables=variables, service=service,
    )

    if with_serviceconnection:
        assert executed["data"] == expected_data
    else:
        assert_match_error_code(executed, "PERMISSION_DENIED_ERROR")
        assert executed["data"]["_entities"] is None
    def test_giving_too_long_name_field_causes_a_validation_error(
            self, field_name, user_gql_client):
        profile_input = {field_name: "x" * 256}

        executed = self._execute_query(user_gql_client, profile_input)

        assert_match_error_code(executed, "VALIDATION_ERROR")
def test_owner_can_resolve_address_entity(
    user_gql_client, service, with_service, with_serviceconnection
):
    address, variables = _create_address_and_variables(
        with_serviceconnection, service, user=user_gql_client.user
    )
    expected_data = {
        "_entities": [
            {
                "id": address._global_id,
                "address": address.address,
                "postalCode": address.postal_code,
            }
        ]
    }

    executed = user_gql_client.execute(
        ENTITY_QUERY, variables=variables, service=service if with_service else None,
    )

    if with_service and with_serviceconnection:
        assert executed["data"] == expected_data
    elif not with_service:
        assert_match_error_code(executed, "SERVICE_NOT_IDENTIFIED_ERROR")
        assert executed["data"]["_entities"] is None
    else:
        assert_match_error_code(executed, "PERMISSION_DENIED_ERROR")
        assert executed["data"]["_entities"] is None
    def test_normal_user_can_create_temporary_read_access_token_for_profile(
            self, user_gql_client, service, with_serviceconnection):
        profile = ProfileFactory(user=user_gql_client.user)
        if with_serviceconnection:
            ServiceConnectionFactory(profile=profile, service=service)

        executed = user_gql_client.execute(self.query, service=service)

        if with_serviceconnection:
            token_data = executed["data"][
                "createMyProfileTemporaryReadAccessToken"][
                    "temporaryReadAccessToken"]

            # Check that an UUID can be parsed from the token
            uuid.UUID(token_data["token"])

            actual_expiration_time = datetime.fromisoformat(
                token_data["expiresAt"])
            expected_expiration_time = timezone.now() + timedelta(days=2)
            assert_almost_equal(actual_expiration_time,
                                expected_expiration_time, timedelta(seconds=1))
        else:
            assert_match_error_code(executed, "PERMISSION_DENIED_ERROR")
            assert executed["data"][
                "createMyProfileTemporaryReadAccessToken"] is None
예제 #11
0
def test_staff_user_needs_required_permission_to_access_verified_personal_information(
    has_needed_permission,
    amr_claim_value,
    settings,
    user_gql_client,
    profile_with_verified_personal_information,
    group,
    service,
):
    settings.VERIFIED_PERSONAL_INFORMATION_ACCESS_AMR_LIST = [
        "authmethod1",
        "authmethod2",
    ]

    ServiceConnectionFactory(
        profile=profile_with_verified_personal_information, service=service)

    user = user_gql_client.user
    user.groups.add(group)
    assign_perm("can_view_profiles", group, service)
    if has_needed_permission:
        assign_perm("can_view_verified_personal_information", group, service)

    t = Template("""
            {
                profile(id: "${id}") {
                    verifiedPersonalInformation {
                        firstName
                    }
                }
            }
        """)
    query = t.substitute(id=relay.Node.to_global_id(
        ProfileNode._meta.name, profile_with_verified_personal_information.id))

    token_payload = {"loa": "substantial", "amr": amr_claim_value}
    executed = user_gql_client.execute(query,
                                       auth_token_payload=token_payload,
                                       service=service)

    if (has_needed_permission and amr_claim_value
            in settings.VERIFIED_PERSONAL_INFORMATION_ACCESS_AMR_LIST):
        assert "errors" not in executed
        assert executed["data"] == {
            "profile": {
                "verifiedPersonalInformation": {
                    "firstName":
                    profile_with_verified_personal_information.
                    verified_personal_information.first_name
                }
            }
        }
    else:
        assert_match_error_code(executed, "PERMISSION_DENIED_ERROR")
        assert executed["data"] == {
            "profile": {
                "verifiedPersonalInformation": None
            }
        }
    def test_adding_address_with_invalid_country_code_value_causes_a_validation_error(
            self, country_code, user_gql_client, address_data):
        address_data["country_code"] = country_code
        new_address = to_graphql_object(address_data)
        profile_input = {"addAddresses": [new_address]}

        executed = self._execute_query(user_gql_client, profile_input)

        assert_match_error_code(executed, "VALIDATION_ERROR")
    def test_adding_address_with_too_long_field_causes_a_validation_error(
            self, field_name, user_gql_client, address_data):
        address_data[field_name] = "x" * 130
        new_address = to_graphql_object(address_data)
        profile_input = {"addAddresses": [new_address]}

        executed = self._execute_query(user_gql_client, profile_input)

        assert_match_error_code(executed, "VALIDATION_ERROR")
def test_deny_invalid_primary_email_address(test_email, user_gql_client):
    user_id = uuid.uuid1()

    input_data = primary_email_input_data(user_id, test_email)

    executed = execute_mutation(input_data, user_gql_client)

    assert_match_error_code(executed, "VALIDATION_ERROR")
    assert executed["data"]["prof"] is None
예제 #15
0
def test_user_gets_error_when_deleting_non_existent_profile(user_gql_client):
    profile = ProfileFactory(user=user_gql_client.user)
    profile.delete()

    executed = user_gql_client.execute(DELETE_MY_PROFILE_MUTATION)

    expected_data = {"deleteMyProfile": None}
    assert dict(executed["data"]) == expected_data
    assert_match_error_code(executed, PROFILE_DOES_NOT_EXIST_ERROR)
def test_anonymous_user_can_not_resolve_profile_entity(
    anon_user_gql_client, service, with_service, with_serviceconnection
):
    profile, variables = _create_profile_and_variables(with_serviceconnection, service)
    executed = anon_user_gql_client.execute(
        ENTITY_QUERY, variables=variables, service=service if with_service else None,
    )

    assert_match_error_code(executed, "PERMISSION_DENIED_ERROR")
    assert executed["data"]["_entities"] is None
    def test_giving_invalid_ssn_causes_a_validation_error(
            self, user_gql_client):
        profile_input = {
            "sensitivedata": {
                "ssn": "101010X1234"
            },
        }

        executed = self._execute_query(user_gql_client, profile_input)

        assert_match_error_code(executed, "VALIDATION_ERROR")
예제 #18
0
    def test_too_low_level_of_assurance_denies_access(self, loa,
                                                      user_gql_client):
        profile = ProfileFactory(user=user_gql_client.user)
        VerifiedPersonalInformationFactory(profile=profile)

        executed = self._execute_query(user_gql_client, loa)

        assert_match_error_code(executed, "PERMISSION_DENIED_ERROR")

        assert executed["data"]["myProfile"][
            "verifiedPersonalInformation"] is None
def test_can_not_delete_primary_email(user_gql_client):
    profile = ProfileWithPrimaryEmailFactory(user=user_gql_client.user)
    email = profile.emails.first()

    email_deletes = [to_global_id(type="EmailNode", id=email.id)]
    executed = user_gql_client.execute(
        EMAILS_MUTATION,
        variables={"profileInput": {
            "removeEmails": email_deletes
        }})
    assert_match_error_code(executed, "PROFILE_MUST_HAVE_PRIMARY_EMAIL")
def test_using_non_existing_token_produces_an_object_does_not_exist_error(
    user_gql_client,
):
    non_existing_token = "e5d47102-a29b-441d-adbc-c6e4e762ffe1"

    variables = {
        "token": non_existing_token,
    }
    executed = user_gql_client.execute(CLAIM_PROFILE_MUTATION, variables=variables)

    assert_match_error_code(executed, "OBJECT_DOES_NOT_EXIST_ERROR")
예제 #21
0
def test_api_tokens_missing(user_gql_client, service_1, query_or_delete, mocker):
    """Missing API token for a service connection that has the query/delete scope set, should be an error."""
    mocker.patch.object(TunnistamoTokenExchange, "fetch_api_tokens", return_value={})
    profile = ProfileFactory(user=user_gql_client.user)
    ServiceConnectionFactory(profile=profile, service=service_1)

    if query_or_delete == "query":
        executed = user_gql_client.execute(DOWNLOAD_MY_PROFILE_MUTATION)
    else:
        executed = user_gql_client.execute(DELETE_MY_PROFILE_MUTATION)

    assert_match_error_code(executed, MISSING_GDPR_API_TOKEN_ERROR)
    def test_adding_invalid_email_address_causes_an_invalid_email_format_error(
            self, invalid_email, email_data, user_gql_client):
        profile_input = {
            "addEmails": [{
                "email": invalid_email,
                "emailType": email_data["email_type"]
            }],
        }

        executed = self._execute_query(user_gql_client, profile_input)

        assert_match_error_code(executed, "INVALID_EMAIL_FORMAT")
    def test_adding_phone_with_empty_phone_number_causes_a_validation_error(
            self, user_gql_client, phone_data):
        profile_input = {
            "addPhones": [{
                "phone": "",
                "phoneType": phone_data["phone_type"]
            }],
        }

        executed = self._execute_query(user_gql_client, profile_input)

        assert_match_error_code(executed, "VALIDATION_ERROR")
def test_can_not_delete_primary_email(user_gql_client):
    profile = ProfileFactory(user=None)
    email = EmailFactory(profile=profile, primary=True)
    claim_token = ClaimTokenFactory(profile=profile)

    email_deletes = [to_global_id(type="EmailNode", id=email.id)]
    executed = user_gql_client.execute(
        CLAIM_PROFILE_MUTATION,
        variables={
            "token": str(claim_token.token),
            "profileInput": {"removeEmails": email_deletes},
        },
    )
    assert_match_error_code(executed, "PROFILE_MUST_HAVE_PRIMARY_EMAIL")
def test_can_not_change_primary_email_to_non_primary(user_gql_client):
    profile = ProfileWithPrimaryEmailFactory(user=user_gql_client.user)
    email = profile.emails.first()

    email_updates = [{
        "id": to_global_id(type="EmailNode", id=email.id),
        "primary": False
    }]
    executed = user_gql_client.execute(
        EMAILS_MUTATION,
        variables={"profileInput": {
            "updateEmails": email_updates
        }})
    assert_match_error_code(executed, "PROFILE_MUST_HAVE_PRIMARY_EMAIL")
def test_non_owner_user_can_not_resolve_address_entity(
    user_gql_client, service, with_service, with_serviceconnection
):
    address, variables = _create_address_and_variables(with_serviceconnection, service)
    executed = user_gql_client.execute(
        ENTITY_QUERY, variables=variables, service=service if with_service else None,
    )

    if not with_service:
        assert_match_error_code(executed, "SERVICE_NOT_IDENTIFIED_ERROR")
        assert executed["data"]["_entities"] is None
    else:
        assert_match_error_code(executed, "PERMISSION_DENIED_ERROR")
        assert executed["data"]["_entities"] is None
예제 #27
0
def test_not_specifying_requesters_service_results_in_permission_denied_error(
    user_gql_client, ):
    query = """
        {
            profiles {
                edges {
                    node {
                        firstName
                    }
                }
            }
        }
    """
    executed = user_gql_client.execute(query)
    assert_match_error_code(executed, "PERMISSION_DENIED_ERROR")
    def test_updating_to_invalid_email_address_causes_an_invalid_email_format_error(
            self, invalid_email, user_gql_client):
        profile = self._get_profile(user_gql_client.user)
        email = EmailFactory(profile=profile, primary=False)

        profile_input = {
            "updateEmails": [{
                "id": to_global_id(type="EmailNode", id=email.id),
                "email": invalid_email,
            }],
        }

        executed = self._execute_query(user_gql_client, profile_input)

        assert_match_error_code(executed, "INVALID_EMAIL_FORMAT")
    def test_updating_phone_number_with_empty_phone_number_causes_a_validation_error(
            self, user_gql_client, empty_string_value):
        profile = self._get_profile(user_gql_client.user)
        phone = PhoneFactory(profile=profile)

        profile_input = {
            "updatePhones": [{
                "id": to_global_id(type="PhoneNode", id=phone.id),
                "phone": empty_string_value,
            }],
        }

        executed = self._execute_query(user_gql_client, profile_input)

        assert_match_error_code(executed, "VALIDATION_ERROR")
def test_can_not_change_primary_email_to_non_primary(user_gql_client):
    profile = ProfileFactory(user=None)
    email = EmailFactory(profile=profile, primary=True)
    claim_token = ClaimTokenFactory(profile=profile)

    variables = {
        "token": str(claim_token.token),
        "profileInput": {
            "updateEmails": [
                {"id": to_global_id(type="EmailNode", id=email.id), "primary": False}
            ],
        },
    }

    executed = user_gql_client.execute(CLAIM_PROFILE_MUTATION, variables=variables)
    assert_match_error_code(executed, "PROFILE_MUST_HAVE_PRIMARY_EMAIL")