-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #160 from lsst-ts/tickets/LOVE-118
LDAP Implementation
- Loading branch information
Showing
5 changed files
with
280 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,14 +3,55 @@ | |
import json | ||
from django.test import TestCase | ||
from django.urls import reverse | ||
from django.contrib.auth.models import User, Permission | ||
from django.contrib.auth.models import User, Permission, Group | ||
from freezegun import freeze_time | ||
from rest_framework.test import APIClient | ||
from rest_framework import status | ||
from api.models import ConfigFile, Token | ||
from django.conf import settings | ||
from django.core.files.base import ContentFile | ||
from unittest.mock import patch | ||
from manager import utils | ||
import ldap | ||
|
||
LDAP_USERNAME = "ldap_user" | ||
LDAP_USERNAME_NON_COMMANDS = "ldap_user_non_commands" | ||
LDAP_USERNAME_EXISTENT = "ldap_user_existent" | ||
LDAP_SEARCH_RESPONSE = [ | ||
[ | ||
None, | ||
{"memberUid": [bytes(LDAP_USERNAME, encoding="utf-8"), b"user2", b"user3"]}, | ||
], | ||
] | ||
|
||
|
||
class MockLDAPUser: | ||
_username = LDAP_USERNAME | ||
|
||
def authenticate(self, password): | ||
aux_user = User.objects.filter(username=self._username).first() | ||
if aux_user is None: | ||
ldap_user = User.objects.create_user( | ||
username=self._username, | ||
password=password, | ||
email=f"{self._username}@user.cl", | ||
first_name="First", | ||
last_name="Last", | ||
) | ||
return ldap_user | ||
return aux_user | ||
|
||
|
||
class MockLDAPUserCommands(MockLDAPUser): | ||
_username = LDAP_USERNAME | ||
|
||
|
||
class MockLDAPUserNonCommands(MockLDAPUser): | ||
_username = LDAP_USERNAME_NON_COMMANDS | ||
|
||
|
||
class MockLDAPUserExistent(MockLDAPUser): | ||
_username = LDAP_USERNAME_EXISTENT | ||
|
||
|
||
class AuthApiTestCase(TestCase): | ||
|
@@ -42,8 +83,20 @@ def setUp(self): | |
first_name="First2", | ||
last_name="Last2", | ||
) | ||
self.user_ldap = User.objects.create_user( | ||
username=LDAP_USERNAME_EXISTENT, | ||
password="password", | ||
email="[email protected]", | ||
first_name="First LDAP", | ||
last_name="Last LDAP", | ||
) | ||
self.user.user_permissions.add(Permission.objects.get(name="Execute Commands")) | ||
self.user2.user_permissions.add(Permission.objects.get(name="Execute Commands")) | ||
|
||
cmd_group = Group.objects.create(name="cmd") | ||
cmd_group.permissions.add(Permission.objects.get(name="Execute Commands")) | ||
cmd_group.user_set.add(self.user_ldap) | ||
|
||
self.login_url = reverse("login") | ||
self.validate_token_url = reverse("validate-token") | ||
self.validate_token_no_config_url = reverse( | ||
|
@@ -110,6 +163,91 @@ def test_user_login(self): | |
"The config was not requested", | ||
) | ||
|
||
@patch("django_auth_ldap.backend._LDAPUser", return_value=MockLDAPUserCommands()) | ||
@patch("ldap.initialize", return_value=ldap.ldapobject.LDAPObject("ldap://test/")) | ||
@patch("ldap.ldapobject.LDAPObject.search_s", return_value=LDAP_SEARCH_RESPONSE) | ||
def test_ldap_nonexistent_cmd_user_login( | ||
self, mockLDAPObject, mockLDAPInitialize, mockLDAPUser | ||
): | ||
# Arrange: | ||
data = {"username": LDAP_USERNAME, "password": "password"} | ||
total_users_before = User.objects.count() | ||
|
||
# Act: | ||
with self.settings( | ||
AUTHENTICATION_BACKENDS=[ | ||
"api.views.IPABackend1", | ||
"django.contrib.auth.backends.ModelBackend", | ||
] | ||
): | ||
response = self.client.post(self.login_url, data, format="json") | ||
user = User.objects.filter(username=LDAP_USERNAME).first() | ||
user_group = user.groups.filter(name="cmd").first() | ||
|
||
total_users_after = User.objects.count() | ||
|
||
# Assert: | ||
self.assertEqual(response.status_code, status.HTTP_200_OK) | ||
self.assertEqual(total_users_before + 1, total_users_after) | ||
self.assertEqual(user_group.name, "cmd") | ||
|
||
@patch("django_auth_ldap.backend._LDAPUser", return_value=MockLDAPUserExistent()) | ||
@patch("ldap.initialize", return_value=ldap.ldapobject.LDAPObject("ldap://test/")) | ||
@patch("ldap.ldapobject.LDAPObject.search_s", return_value=LDAP_SEARCH_RESPONSE) | ||
def test_ldap_existent_cmd_user_login( | ||
self, mockLDAPObject, mockLDAPInitialize, mockLDAPUser | ||
): | ||
# Arrange: | ||
data = {"username": LDAP_USERNAME_EXISTENT, "password": "password"} | ||
total_users_before = User.objects.count() | ||
|
||
# Act: | ||
with self.settings( | ||
AUTHENTICATION_BACKENDS=[ | ||
"api.views.IPABackend1", | ||
"django.contrib.auth.backends.ModelBackend", | ||
] | ||
): | ||
response = self.client.post(self.login_url, data, format="json") | ||
user = User.objects.filter(username=LDAP_USERNAME_EXISTENT).first() | ||
user_group = user.groups.filter(name="cmd").first() | ||
|
||
total_users_after = User.objects.count() | ||
|
||
# Assert: | ||
self.assertEqual(response.status_code, status.HTTP_200_OK) | ||
self.assertEqual(total_users_before, total_users_after) | ||
self.assertEqual(user_group.name, "cmd") | ||
|
||
@patch("django_auth_ldap.backend._LDAPUser", return_value=MockLDAPUserNonCommands()) | ||
@patch("ldap.initialize", return_value=ldap.ldapobject.LDAPObject("ldap://test/")) | ||
@patch( | ||
"ldap.ldapobject.LDAPObject.search_s", return_value=LDAP_SEARCH_RESPONSE, | ||
) | ||
def test_ldap_nonexistent_non_cmd_user_login( | ||
self, mockLDAPObject, mockLDAPInitialize, mockLDAPUserNonCmd | ||
): | ||
# Arrange: | ||
data = {"username": LDAP_USERNAME_NON_COMMANDS, "password": "password"} | ||
total_users_before = User.objects.count() | ||
|
||
# Act: | ||
with self.settings( | ||
AUTHENTICATION_BACKENDS=[ | ||
"api.views.IPABackend1", | ||
"django.contrib.auth.backends.ModelBackend", | ||
] | ||
): | ||
response = self.client.post(self.login_url, data, format="json") | ||
user = User.objects.filter(username=LDAP_USERNAME_NON_COMMANDS).first() | ||
|
||
total_users_after = User.objects.count() | ||
|
||
# Assert: | ||
self.assertEqual(response.status_code, status.HTTP_200_OK) | ||
self.assertEqual(total_users_before + 1, total_users_after) | ||
self.assertEqual(user.groups.count(), 0) | ||
|
||
def test_user_login_failed(self): | ||
"""Test that a user cannot request a token if the credentials are invalid.""" | ||
# Arrange: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters