import json import random from urllib.parse import parse_qs, urlsplit from urllib.parse import urlunsplit import pytest import requests from atlas_um.app import create_app from atlas_um.usm.client import USMClient class TestUSMClient: # The login callback URL registered with USM is # https://dev-um.atlas.stream/usm/login/callback REGISTERED_LOGIN_CALLBACK_PATH = "/usm/login/callback" # The logout callback URL registered with USM is # https://dev-um.atlas.stream/usm/logout/callback REGISTERED_LOGOUT_CALLBACK_PATH = "/usm/logout/callback" FAKE_USM_HOST = "usm.test" FAKE_ATLAS_UM_HOST = "atlas_um.test" FAKE_CLIENT_ID = "fake_client_id" FAKE_CLIENT_SECRET = "totally_not_secret" FAKE_AUTHORIZE_PATH = "/oauth2/openid/v1/authorize" FAKE_TOKEN_PATH = "/oauth2/openid/v1/token" FAKE_LOGOUT_PATH = "/oauth2/openid/v1/logout" FAKE_GRAPH_PATH = "/graph/v1" FAKE_USM_EXTERNAL_USER_PATH = "/ws/client/user/" FAKE_USM_UTIL_PATH = "/oauth2/util/" @pytest.fixture def app(self): # We’re using this app instance to support url_for class UrlForConfig: SERVER_NAME = self.FAKE_ATLAS_UM_HOST PREFERRED_URL_SCHEME = "https" app = create_app(UrlForConfig()) app.testing = True yield app @pytest.fixture def usm(self): return USMClient( None, self.FAKE_USM_HOST, self.FAKE_CLIENT_ID, self.FAKE_CLIENT_SECRET, self.FAKE_AUTHORIZE_PATH, self.FAKE_TOKEN_PATH, self.FAKE_LOGOUT_PATH, self.FAKE_GRAPH_PATH, self.FAKE_USM_EXTERNAL_USER_PATH, self.FAKE_USM_UTIL_PATH, ) def test_generate_state(self, usm): """Generate a random state of a given length.""" length = random.randint(1, 24) state = usm.generate_state(length) assert len(state) == length def test_generate_state_default_length(self, usm): """Generate a random state of the default length.""" state = usm.generate_state() assert len(state) == 8 def test_generate_nonce(self, usm): """Generate a random nonce of a given length.""" length = random.randint(1, 24) nonce = usm.generate_nonce(length) assert len(nonce) == length def test_generate_nonce_default_length(self, usm): """Generate a random nonce of the default length.""" nonce = usm.generate_nonce() assert len(nonce) == 8 def test_authentication_url(self, app, faker, usm): """Create an authentication URL for the given state and nonce.""" fake_nonce = faker.pystr() fake_state = faker.pystr() fake_callback = ( "https://" + self.FAKE_ATLAS_UM_HOST + self.REGISTERED_LOGIN_CALLBACK_PATH ) with app.app_context(): authentication_url = usm.authentication_url(fake_state, fake_nonce) url_parts = urlsplit(authentication_url) assert url_parts.scheme == "https" assert url_parts.netloc == self.FAKE_USM_HOST assert url_parts.path == self.FAKE_AUTHORIZE_PATH query = parse_qs(url_parts.query) assert query["response_type"] == ["code"] assert query["scope"] == ["openid email"] assert query["client_id"] == [self.FAKE_CLIENT_ID] assert query["state"] == [fake_state] assert query["redirect_uri"] == [fake_callback] assert query["nonce"] == [fake_nonce] assert url_parts.fragment == "" def test_logout_url(self, app, faker, usm, mocker): """Create a logout URL for the given state""" fake_id_token = faker.pystr() fake_state = faker.pystr() fake_callback = ( "https://" + self.FAKE_ATLAS_UM_HOST + self.REGISTERED_LOGOUT_CALLBACK_PATH ) with app.app_context(): logout_url = usm.logout_url(fake_id_token, fake_state) url_parts = urlsplit(logout_url) assert url_parts.scheme == "https" assert url_parts.netloc == self.FAKE_USM_HOST assert url_parts.path == self.FAKE_LOGOUT_PATH query = parse_qs(url_parts.query) assert query["id_token_hint"] == [fake_id_token] assert query["state"] == [fake_state] assert query["post_logout_redirect_uri"] == [fake_callback] assert url_parts.fragment == "" def test_search_users_success(self, app, faker, usm, mocker): search_term = faker.pystr() expected_data = [faker.pydict()] * faker.pyint(max_value=10) mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.json.return_value = { "success": True, "data": expected_data, } actual_result = usm.search_users(search_term) endpoint = f"{self.FAKE_GRAPH_PATH.rstrip('/')}/searchUsers" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "search_text": search_term, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_right assert expected_data == actual_result.value def test_search_users_failure_status(self, app, faker, usm, mocker): search_term = faker.pystr() expected_data = "Some error" mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.ok = False mocked_post.return_value.text = expected_data actual_result = usm.search_users(search_term) endpoint = f"{self.FAKE_GRAPH_PATH.rstrip('/')}/searchUsers" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "search_text": search_term, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_left assert expected_data == actual_result.value def test_search_users_failure_content(self, app, faker, usm, mocker): search_term = faker.pystr() expected_data = {"success": False, "message": "Some error"} mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.json.return_value = expected_data mocked_post.return_value.text = json.dumps(expected_data) actual_result = usm.search_users(search_term) endpoint = f"{self.FAKE_GRAPH_PATH.rstrip('/')}/searchUsers" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "search_text": search_term, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_left assert json.dumps(expected_data) == actual_result.value def test_get_user_success(self, app, faker, usm, mocker): email = faker.email() expected_data = faker.pydict() mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.json.return_value = { "success": True, "data": expected_data, } actual_result = usm.get_user(email) endpoint = f"{self.FAKE_GRAPH_PATH.rstrip('/')}/getUser" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "email": email, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_right assert expected_data == actual_result.value def test_get_user_failure_status(self, app, faker, usm, mocker): email = faker.email() expected_data = "Some error" mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.ok = False mocked_post.return_value.text = expected_data actual_result = usm.get_user(email) endpoint = f"{self.FAKE_GRAPH_PATH.rstrip('/')}/getUser" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "email": email, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_left assert expected_data == actual_result.value def test_get_user_failure_content(self, app, faker, usm, mocker): email = faker.email() expected_data = {"success": False, "message": "Some error"} mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.json.return_value = expected_data mocked_post.return_value.text = json.dumps(expected_data) actual_result = usm.get_user(email) endpoint = f"{self.FAKE_GRAPH_PATH.rstrip('/')}/getUser" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "email": email, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_left assert json.dumps(expected_data) == actual_result.value def test_save_user_success(self, app, faker, usm, mocker): email = faker.email() admin_email = faker.email() first_name = faker.first_name() last_name = faker.last_name() expected_data = faker.pydict() mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.json.return_value = { "success": True, "data": expected_data, } actual_result = usm.save_user( email, first_name, last_name, admin_email ) endpoint = f"{self.FAKE_USM_EXTERNAL_USER_PATH.rstrip('/')}/save" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "email": email, "firstName": first_name, "lastName": last_name, "client_admin_user_email": admin_email, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_right assert expected_data == actual_result.value def test_save_user_failure_status(self, app, faker, usm, mocker): email = faker.email() admin_email = faker.email() first_name = faker.first_name() last_name = faker.last_name() expected_data = "Some error" mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.ok = False mocked_post.return_value.text = expected_data actual_result = usm.save_user( email, first_name, last_name, admin_email ) endpoint = f"{self.FAKE_USM_EXTERNAL_USER_PATH.rstrip('/')}/save" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "email": email, "firstName": first_name, "lastName": last_name, "client_admin_user_email": admin_email, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_left assert expected_data == actual_result.value def test_save_user_failure_content(self, app, faker, usm, mocker): email = faker.email() admin_email = faker.email() first_name = faker.first_name() last_name = faker.last_name() expected_data = {"success": False, "message": "Some error"} mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.json.return_value = expected_data mocked_post.return_value.text = json.dumps(expected_data) actual_result = usm.save_user( email, first_name, last_name, admin_email ) endpoint = f"{self.FAKE_USM_EXTERNAL_USER_PATH.rstrip('/')}/save" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "email": email, "firstName": first_name, "lastName": last_name, "client_admin_user_email": admin_email, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_left assert json.dumps(expected_data) == actual_result.value def test_reset_password_success(self, app, faker, usm, mocker): email = faker.email() admin_email = faker.email() link = faker.url() expected_data = {"link": link} mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.json.return_value = { "success": True, "data": expected_data, } actual_result = usm.reset_password(email, admin_email) endpoint = ( f"{self.FAKE_USM_EXTERNAL_USER_PATH.rstrip('/')}/password-reset" ) url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "email": email, "client_admin_user_email": admin_email, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_right assert actual_result.value == link def test_reset_password_failure_status(self, app, faker, usm, mocker): email = faker.email() admin_email = faker.email() expected_data = "Some error" mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.ok = False mocked_post.return_value.text = expected_data actual_result = usm.reset_password(email, admin_email) endpoint = ( f"{self.FAKE_USM_EXTERNAL_USER_PATH.rstrip('/')}/password-reset" ) url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "email": email, "client_admin_user_email": admin_email, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_left assert expected_data == actual_result.value def test_reset_password_failure_content(self, app, faker, usm, mocker): email = faker.email() admin_email = faker.email() expected_data = {"success": False, "message": "Some error"} mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.json.return_value = expected_data mocked_post.return_value.text = json.dumps(expected_data) actual_result = usm.reset_password(email, admin_email) endpoint = ( f"{self.FAKE_USM_EXTERNAL_USER_PATH.rstrip('/')}/password-reset" ) url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, "email": email, "client_admin_user_email": admin_email, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_left assert json.dumps(expected_data) == actual_result.value def test_get_internal_domains_success(self, app, faker, usm, mocker): expected_data = ["test_1.com", "test_2.com"] mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.json.return_value = { "success": True, "data": expected_data, } actual_result = usm.get_internal_domains() endpoint = f"{self.FAKE_USM_UTIL_PATH.rstrip('/')}/findAllSonyDomains" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_right assert actual_result.value == expected_data def test_get_internal_domains_status(self, app, faker, usm, mocker): expected_data = "Some error" mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.ok = False mocked_post.return_value.text = expected_data actual_result = usm.get_internal_domains() endpoint = f"{self.FAKE_USM_UTIL_PATH.rstrip('/')}/findAllSonyDomains" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_left assert expected_data == actual_result.value def test_get_internal_domains_failure_content( self, app, faker, usm, mocker ): expected_data = {"success": False, "message": "Some error"} mocked_post = mocker.patch.object(requests, "post") mocked_post.return_value.json.return_value = expected_data mocked_post.return_value.text = json.dumps(expected_data) actual_result = usm.get_internal_domains() endpoint = f"{self.FAKE_USM_UTIL_PATH.rstrip('/')}/findAllSonyDomains" url = urlunsplit(("https", self.FAKE_USM_HOST, endpoint, None, None)) accept = { "Accept": "application/json", } payload = { "client_id": self.FAKE_CLIENT_ID, "client_secret": self.FAKE_CLIENT_SECRET, } post_expects = mocker.call(url, headers=accept, data=payload) assert mocked_post.call_args_list == [post_expects] assert actual_result.is_left assert json.dumps(expected_data) == actual_result.value