Skip to content

Commit 3a61f60

Browse files
nejchJohnVillalovos
authored andcommitted
feat(groups): add LDAP link manager and deprecate old API endpoints
1 parent 0c98b2d commit 3a61f60

File tree

4 files changed

+112
-31
lines changed

4 files changed

+112
-31
lines changed

docs/gl_objects/groups.rst

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,11 +326,22 @@ LDAP group links
326326

327327
Add an LDAP group link to an existing GitLab group::
328328

329-
group.add_ldap_group_link(ldap_group_cn, gitlab.const.AccessLevel.DEVELOPER, 'ldapmain')
329+
ldap_link = group.ldap_group_links.create({
330+
'provider': 'ldapmain',
331+
'group_access': gitlab.const.AccessLevel.DEVELOPER,
332+
'cn: 'ldap_group_cn'
333+
})
334+
335+
List a group's LDAP group links:
336+
337+
group.ldap_group_links.list()
330338

331339
Remove a link::
332340

333-
group.delete_ldap_group_link(ldap_group_cn, 'ldapmain')
341+
ldap_link.delete()
342+
# or by explicitly providing the CN or filter
343+
group.ldap_group_links.delete(provider='ldapmain', cn='ldap_group_cn')
344+
group.ldap_group_links.delete(provider='ldapmain', filter='(cn=Common Name)')
334345

335346
Sync the LDAP groups::
336347

gitlab/v4/objects/groups.py

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@
55
import gitlab
66
from gitlab import cli
77
from gitlab import exceptions as exc
8-
from gitlab import types
8+
from gitlab import types, utils
99
from gitlab.base import RESTManager, RESTObject
10-
from gitlab.mixins import CRUDMixin, ListMixin, ObjectDeleteMixin, SaveMixin
10+
from gitlab.mixins import (
11+
CreateMixin,
12+
CRUDMixin,
13+
DeleteMixin,
14+
ListMixin,
15+
ObjectDeleteMixin,
16+
SaveMixin,
17+
)
1118
from gitlab.types import RequiredOptional
1219

1320
from .access_requests import GroupAccessRequestManager # noqa: F401
@@ -47,6 +54,8 @@
4754
"GroupManager",
4855
"GroupDescendantGroup",
4956
"GroupDescendantGroupManager",
57+
"GroupLDAPGroupLink",
58+
"GroupLDAPGroupLinkManager",
5059
"GroupSubgroup",
5160
"GroupSubgroupManager",
5261
]
@@ -74,6 +83,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
7483
issues_statistics: GroupIssuesStatisticsManager
7584
iterations: GroupIterationManager
7685
labels: GroupLabelManager
86+
ldap_group_links: "GroupLDAPGroupLinkManager"
7787
members: GroupMemberManager
7888
members_all: GroupMemberAllManager
7989
mergerequests: GroupMergeRequestManager
@@ -168,6 +178,13 @@ def add_ldap_group_link(
168178
GitlabAuthenticationError: If authentication is not correct
169179
GitlabCreateError: If the server cannot perform the request
170180
"""
181+
utils.warn(
182+
message=(
183+
"The add_ldap_group_link() method is deprecated and will be removed "
184+
"in a future version. Use ldap_group_links.create() instead."
185+
),
186+
category=DeprecationWarning,
187+
)
171188
path = f"/groups/{self.encoded_id}/ldap_group_links"
172189
data = {"cn": cn, "group_access": group_access, "provider": provider}
173190
self.manager.gitlab.http_post(path, post_data=data, **kwargs)
@@ -188,29 +205,19 @@ def delete_ldap_group_link(
188205
GitlabAuthenticationError: If authentication is not correct
189206
GitlabDeleteError: If the server cannot perform the request
190207
"""
208+
utils.warn(
209+
message=(
210+
"The delete_ldap_group_link() method is deprecated and will be "
211+
"removed in a future version. Use ldap_group_links.delete() instead."
212+
),
213+
category=DeprecationWarning,
214+
)
191215
path = f"/groups/{self.encoded_id}/ldap_group_links"
192216
if provider is not None:
193217
path += f"/{provider}"
194218
path += f"/{cn}"
195219
self.manager.gitlab.http_delete(path, **kwargs)
196220

197-
@cli.register_custom_action("Group")
198-
@exc.on_http_error(exc.GitlabGetError)
199-
def list_ldap_group_links(
200-
self, **kwargs: Any
201-
) -> Union[gitlab.GitlabList, List[Dict[str, Any]]]:
202-
"""List LDAP group links.
203-
204-
Args:
205-
**kwargs: Extra options to send to the server (e.g. sudo)
206-
207-
Raises:
208-
GitlabAuthenticationError: If authentication is not correct
209-
GitlabGetError: If the server cannot perform the request
210-
"""
211-
path = f"/groups/{self.encoded_id}/ldap_group_links"
212-
return self.manager.gitlab.http_list(path, **kwargs)
213-
214221
@cli.register_custom_action("Group")
215222
@exc.on_http_error(exc.GitlabCreateError)
216223
def ldap_sync(self, **kwargs: Any) -> None:
@@ -416,3 +423,44 @@ class GroupDescendantGroupManager(GroupSubgroupManager):
416423

417424
_path = "/groups/{group_id}/descendant_groups"
418425
_obj_cls: Type[GroupDescendantGroup] = GroupDescendantGroup
426+
427+
428+
class GroupLDAPGroupLink(RESTObject):
429+
_repr_attr = "provider"
430+
431+
def _get_link_attrs(self) -> Dict[str, str]:
432+
# https://docs.gitlab.com/ee/api/groups.html#add-ldap-group-link-with-cn-or-filter
433+
# https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link-with-cn-or-filter
434+
# We can tell what attribute to use based on the data returned
435+
data = {"provider": self.provider}
436+
if self.cn:
437+
data["cn"] = self.cn
438+
else:
439+
data["filter"] = self.filter
440+
441+
return data
442+
443+
def delete(self, **kwargs: Any) -> None:
444+
"""Delete the LDAP group link from the server.
445+
446+
Args:
447+
**kwargs: Extra options to send to the server (e.g. sudo)
448+
449+
Raises:
450+
GitlabAuthenticationError: If authentication is not correct
451+
GitlabDeleteError: If the server cannot perform the request
452+
"""
453+
if TYPE_CHECKING:
454+
assert isinstance(self.manager, DeleteMixin)
455+
self.manager.delete(
456+
self.encoded_id, query_data=self._get_link_attrs(), **kwargs
457+
)
458+
459+
460+
class GroupLDAPGroupLinkManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
461+
_path = "/groups/{group_id}/ldap_group_links"
462+
_obj_cls: Type[GroupLDAPGroupLink] = GroupLDAPGroupLink
463+
_from_parent_attrs = {"group_id": "id"}
464+
_create_attrs = RequiredOptional(
465+
required=("provider", "group_access"), exclusive=("cn", "filter")
466+
)

tests/functional/api/test_groups.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,37 @@ def test_group_labels(group):
139139

140140

141141
@pytest.mark.gitlab_premium
142-
@pytest.mark.xfail(reason="/ldap/groups endpoint is gone")
143-
def test_group_ldap_links(gl, group):
142+
@pytest.mark.xfail(reason="/ldap/groups endpoint not documented")
143+
def test_ldap_groups(gl):
144+
assert isinstance(gl.ldapgroups.list(), list)
145+
146+
147+
@pytest.mark.gitlab_premium
148+
def test_group_ldap_links(group):
144149
ldap_cn = "common-name"
145150
ldap_provider = "ldap-provider"
146-
assert gl.ldapgroups.list()
147151

148-
group.add_ldap_group_link(ldap_cn, 30, ldap_provider)
149-
group.ldap_sync()
150-
group.delete_ldap_group_link(ldap_cn)
152+
ldap_cn_link = group.ldap_group_links.create(
153+
{"provider": ldap_provider, "group_access": 30, "cn": ldap_cn}
154+
)
155+
ldap_filter_link = group.ldap_group_links.create(
156+
{"provider": ldap_provider, "group_access": 30, "filter": "(cn=Common Name)"}
157+
)
158+
159+
ldap_links = group.ldap_group_links.list()
160+
161+
assert ldap_cn_link.cn == ldap_links[0].cn
162+
assert ldap_filter_link.filter == ldap_links[1].filter
163+
164+
with pytest.raises(gitlab.GitlabCreateError):
165+
# todo - can we configure dummy LDAP in the container?
166+
group.ldap_sync()
167+
168+
ldap_filter_link.delete()
169+
group.ldap_group_links.delete(provider=ldap_provider, cn=ldap_cn)
170+
171+
with pytest.raises(gitlab.GitlabListError, match="No linked LDAP groups found"):
172+
group.ldap_group_links.list()
151173

152174

153175
def test_group_notification_settings(group):

tests/unit/objects/test_groups.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import responses
99

1010
import gitlab
11-
from gitlab.v4.objects import GroupDescendantGroup, GroupSubgroup
11+
from gitlab.v4.objects import GroupDescendantGroup, GroupLDAPGroupLink, GroupSubgroup
1212
from gitlab.v4.objects.projects import GroupProject, SharedProject
1313

1414
content = {"name": "name", "id": 1, "path": "path"}
@@ -283,9 +283,9 @@ def test_list_group_descendant_groups(group, resp_list_subgroups_descendant_grou
283283

284284

285285
def test_list_ldap_group_links(group, resp_list_ldap_group_links):
286-
ldap_group_links = group.list_ldap_group_links()
287-
assert isinstance(ldap_group_links, list)
288-
assert ldap_group_links[0]["provider"] == ldap_group_links_content[0]["provider"]
286+
ldap_group_links = group.ldap_group_links.list()
287+
assert isinstance(ldap_group_links[0], GroupLDAPGroupLink)
288+
assert ldap_group_links[0].provider == ldap_group_links_content[0]["provider"]
289289

290290

291291
@pytest.mark.skip("GitLab API endpoint not implemented")

0 commit comments

Comments
 (0)