Repository: python-gitlab/python-gitlab

Issue:
How to delete identities with the API?
## Description of the problem, including code/CLI snippet

```
user.identities = []
user.save()
```

## Expected Behavior

Identities are deleted.

## Actual Behavior

Identities are unchanged.

## Specifications

  - python-gitlab version: 2.2.0
  - API version you are using (v3/v4): v4
  - Gitlab server version (or gitlab.com): 12.9



Discussion:
I found out you can do:

```
for i in user.identities:
    gl.http_delete("/users/{}/identities/{}".format(user.get_id(), i["provider"]))
```

Would be nice to include in the API, but it works for now.
It seems like to delete an identity, you need to use a separate API endpoint:

https://docs.gitlab.com/ee/api/users.html#delete-authentication-identity-from-user

This still needs to be added to python-gitlab, I'll try to submit a PR soon. Thanks for the report and the workaround! ;)
Ok cool. Thanks for this nice project btw!

Resolving patch:
diff --git a/gitlab/v4/objects/__init__.py b/gitlab/v4/objects/__init__.py
--- a/gitlab/v4/objects/__init__.py
+++ b/gitlab/v4/objects/__init__.py
@@ -217,6 +217,17 @@ class UserStatusManager(GetWithoutIdMixin, RESTManager):
     _from_parent_attrs = {"user_id": "id"}
 
 
+class UserIdentityProviderManager(DeleteMixin, RESTManager):
+    """Manager for user identities.
+
+    This manager does not actually manage objects but enables
+    functionality for deletion of user identities by provider.
+    """
+
+    _path = "/users/%(user_id)s/identities"
+    _from_parent_attrs = {"user_id": "id"}
+
+
 class UserImpersonationToken(ObjectDeleteMixin, RESTObject):
     pass
 
@@ -320,6 +331,7 @@ class User(SaveMixin, ObjectDeleteMixin, RESTObject):
         ("emails", "UserEmailManager"),
         ("events", "UserEventManager"),
         ("gpgkeys", "UserGPGKeyManager"),
+        ("identityproviders", "UserIdentityProviderManager"),
         ("impersonationtokens", "UserImpersonationTokenManager"),
         ("keys", "UserKeyManager"),
         ("memberships", "UserMembershipManager"),


Test patch:
diff --git a/gitlab/tests/objects/test_users.py b/gitlab/tests/objects/test_users.py
--- a/gitlab/tests/objects/test_users.py
+++ b/gitlab/tests/objects/test_users.py
@@ -95,6 +95,19 @@ def resp_get_user_status():
         yield rsps
 
 
+@pytest.fixture
+def resp_delete_user_identity(no_content):
+    with responses.RequestsMock() as rsps:
+        rsps.add(
+            method=responses.DELETE,
+            url="http://localhost/api/v4/users/1/identities/test_provider",
+            json=no_content,
+            content_type="application/json",
+            status=204,
+        )
+        yield rsps
+
+
 def test_get_user(gl, resp_get_user):
     user = gl.users.get(1)
     assert isinstance(user, User)
@@ -118,3 +131,7 @@ def test_user_status(user, resp_get_user_status):
 def test_user_activate_deactivate(user, resp_activate):
     user.activate()
     user.deactivate()
+
+
+def test_delete_user_identity(user, resp_delete_user_identity):
+    user.identityproviders.delete("test_provider")
diff --git a/tools/functional/api/test_users.py b/tools/functional/api/test_users.py
new file mode 100644
--- /dev/null
+++ b/tools/functional/api/test_users.py
@@ -0,0 +1,20 @@
+"""
+GitLab API:
+https://docs.gitlab.com/ee/api/users.html
+https://docs.gitlab.com/ee/api/users.html#delete-authentication-identity-from-user
+"""
+
+
+def test_user_identities(gl, user):
+    provider = "test_provider"
+
+    user.provider = provider
+    user.extern_uid = "1"
+    user.save()
+
+    assert provider in [item["provider"] for item in user.identities]
+
+    user.identityproviders.delete(provider)
+    user = gl.users.get(user.id)
+
+    assert provider not in [item["provider"] for item in user.identities]