# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Avencall
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>

import unittest

from mock import Mock, patch
from hamcrest import assert_that, contains_inanyorder, equal_to, only_contains
import time

from xivo_dao.alchemy.session import Session
from xivo_dao.alchemy.user import User

from xivo_auth.plugins import backends
from xivo_auth.plugins.backends.default_acls import DEFAULT_USER_ACLS


class TestVerifyPassword(unittest.TestCase):

    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    def test_to_get_valid_session(self, session_dao_mock):
        future_time = int(time.time()) + 86400
        serialized_data = '_USR|O:8:"stdClass":2:{s:5:"login";s:4:"root";s:6:"passwd";s:9:"superpass";}_WEBI|'
        session_mock = Mock(expire=future_time, data=serialized_data)

        session_dao_mock.return_value = session_mock

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')

        result = backend.verify_password(None, None, args)

        assert_that(result, equal_to(True))
        session_dao_mock.assert_called_once_with('1234')

    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    def test_to_get_valid_session_without_login(self, session_dao_mock):
        future_time = int(time.time()) + 86400
        serialized_data = '_USR|O:8:"stdClass":2:{s:5:"notexpected";s:4:"invalidvalue";s:6:"passwd";s:9:"superpass";}_WEBI|'
        session_mock = Mock(expire=future_time, data=serialized_data)

        session_dao_mock.return_value = session_mock

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')

        result = backend.verify_password(None, None, args)

        assert_that(result, equal_to(False))
        session_dao_mock.assert_called_once_with('1234')

    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    def test_to_handle_invalid_session(self, session_dao_mock):
        future_time = int(time.time()) + 86400
        serialized_data = 'ERROR|O:8:"stdClass":2:{s:5:"login";s:4:"root";s:6:"passwd";s:9:"superpass";}_WEBI|'
        session_mock = Mock(expire=future_time, data=serialized_data)

        session_dao_mock.return_value = session_mock

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')

        result = backend.verify_password(None, None, args)

        assert_that(result, equal_to(False))
        session_dao_mock.assert_called_once_with('1234')

class TestGetIDS(unittest.TestCase):

    def setup_session(self, webi_user):
        future_time = int(time.time()) + 86400
        serialized_data = '_USR|O:8:"stdClass":2:{s:5:"login";s:%s:"%s";s:6:"passwd";s:9:"superpass";}_WEBI|' % (len(webi_user), webi_user)
        return Mock(expire=future_time, data=serialized_data)

    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    @patch('xivo_auth.plugins.backends.xivo_session.admin_dao.get_admin_id')
    def test_to_get_root_user_ids(self, admin_dao_mock, session_dao_mock):
        webi_user = 'root'
        session_dao_mock.return_value = self.setup_session(webi_user)

        admin_dao_mock.return_value = 1

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')
        result = backend.get_ids(None, args)

        assert_that(result, equal_to(('1', None)))
        session_dao_mock.assert_called_once_with('1234')
        admin_dao_mock.assert_called_once_with(webi_user)

    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    @patch('xivo_auth.plugins.backends.xivo_session.admin_dao.get_admin_id')
    def test_to_get_admin_user_ids(self, admin_dao_mock, session_dao_mock):
        webi_user = 'joe'
        session_dao_mock.return_value = self.setup_session(webi_user)

        admin_dao_mock.return_value = 2

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')
        result = backend.get_ids(None, args)

        assert_that(result, equal_to(('2', None)))
        session_dao_mock.assert_called_once_with('1234')
        admin_dao_mock.assert_called_once_with(webi_user)

class TestGetACLS(unittest.TestCase):

    def setup_session(self, webi_user):
        future_time = int(time.time()) + 86400
        serialized_data = '_USR|O:8:"stdClass":2:{s:5:"login";s:%s:"%s";s:6:"passwd";s:9:"superpass";}_WEBI|' % (len(webi_user), webi_user)
        return Mock(expire=future_time, data=serialized_data)


    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    def test_to_get_root_user_acls(self, session_dao_mock):
        session_dao_mock.return_value = self.setup_session('root')

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')
        result = backend.get_acls(None, args)

        assert_that(result, equal_to(['confd.#']))
        session_dao_mock.assert_called_once_with('1234')

    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    @patch('xivo_auth.plugins.backends.xivo_session.admin_dao.get_admin_permission')
    def test_get_void_acl_for_admin_user_without_webi_perms(self, admin_dao_getperms_mock, session_dao_mock):
        webi_user = 'foobar'
        session_dao_mock.return_value = self.setup_session(webi_user)

        no_webi_permission = ''
        admin_dao_getperms_mock.return_value = no_webi_permission

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')
        result = backend.get_acls(None, args)

        assert_that(result, equal_to([]))
        session_dao_mock.assert_called_once_with('1234')
        admin_dao_getperms_mock.assert_called_once_with(webi_user)

    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    @patch('xivo_auth.plugins.backends.xivo_session.admin_dao.get_admin_permission')
    def test_get_acl_label_for_admin_user_with_webi_labels_perms(self, admin_dao_getperms_mock, session_dao_mock):
        webi_user = 'foobar'
        session_dao_mock.return_value = self.setup_session(webi_user)

        webi_permission_with_labels = 'a:1:{s:3:"acl";a:1:{s:7:"service";a:1:{s:4:"ipbx";a:1:{s:12:"pbx_settings";a:1:{s:6:"labels";b:1;}}}}}'
        admin_dao_getperms_mock.return_value = webi_permission_with_labels

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')
        result = backend.get_acls(None, args)

        assert_that(result, equal_to(['confd.labels.#']))
        session_dao_mock.assert_called_once_with('1234')
        admin_dao_getperms_mock.assert_called_once_with(webi_user)

    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    @patch('xivo_auth.plugins.backends.xivo_session.admin_dao.get_admin_permission')
    def test_get_acl_label_for_admin_user_with_webi_users_perms(self, admin_dao_getperms_mock, session_dao_mock):
        webi_user = 'foobar'
        session_dao_mock.return_value = self.setup_session(webi_user)

        webi_permission_with_users = 'a:1:{s:3:"acl";a:1:{s:7:"service";a:1:{s:4:"ipbx";a:1:{s:12:"pbx_settings";a:1:{s:5:"users";b:1;}}}}}'
        admin_dao_getperms_mock.return_value = webi_permission_with_users

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')
        result = backend.get_acls(None, args)

        assert_that(result, equal_to(['confd.labels.read']))
        session_dao_mock.assert_called_once_with('1234')
        admin_dao_getperms_mock.assert_called_once_with(webi_user)

    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    @patch('xivo_auth.plugins.backends.xivo_session.admin_dao.get_admin_permission')
    def test_get_acl_label_for_admin_user_with_webi_users_and_labels_perms(self, admin_dao_getperms_mock, session_dao_mock):
        webi_user = 'foobar'
        session_dao_mock.return_value = self.setup_session(webi_user)

        webi_permission_with_users_and_labels = 'a:1:{s:3:"acl";a:1:{s:7:"service";a:1:{s:4:"ipbx";a:1:{s:12:"pbx_settings";a:2:{s:5:"users";b:1;s:6:"labels";b:1;}}}}}'
        admin_dao_getperms_mock.return_value = webi_permission_with_users_and_labels

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')
        result = backend.get_acls(None, args)

        assert_that(result, only_contains('confd.labels.#', 'confd.labels.read'))
        session_dao_mock.assert_called_once_with('1234')
        admin_dao_getperms_mock.assert_called_once_with(webi_user)

    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    @patch('xivo_auth.plugins.backends.xivo_session.admin_dao.get_admin_permission')
    def test_get_acl_does_not_fail_for_admin_user_with_webi_perms_not_mapped(self, admin_dao_getperms_mock, session_dao_mock):
        webi_user = 'foobar'
        session_dao_mock.return_value = self.setup_session(webi_user)

        webi_permission_not_mapped = 'a:1:{s:3:"acl";a:1:{s:7:"service";a:1:{s:4:"ipbx";a:1:{s:12:"pbx_services";a:1:{s:6:"sounds";b:1;}}}}}'
        admin_dao_getperms_mock.return_value = webi_permission_not_mapped

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')
        result = backend.get_acls(None, args)

        assert_that(result, equal_to([]))
        session_dao_mock.assert_called_once_with('1234')
        admin_dao_getperms_mock.assert_called_once_with(webi_user)

    @patch('xivo_auth.plugins.backends.xivo_session.session_dao.get_session')
    @patch('xivo_auth.plugins.backends.xivo_session.admin_dao.get_admin_permission')
    def test_get_acl_label_for_admin_user_with_webi_perms_labels_and_not_mapped(self, admin_dao_getperms_mock, session_dao_mock):
        webi_user = 'foobar'
        session_dao_mock.return_value = self.setup_session(webi_user)

        webi_permission_labels_and_not_mapped = 'a:1:{s:3:"acl";a:1:{s:7:"service";a:1:{s:4:"ipbx";a:2:{s:12:"pbx_settings";a:1:{s:6:"labels";b:1;}s:12:"pbx_services";a:1:{s:6:"sounds";b:1;}}}}}'
        admin_dao_getperms_mock.return_value = webi_permission_labels_and_not_mapped

        args = {'cookie': '1234'}

        backend = backends.XiVOSession('config')
        result = backend.get_acls(None, args)

        assert_that(result, equal_to(['confd.labels.#']))
        session_dao_mock.assert_called_once_with('1234')
        admin_dao_getperms_mock.assert_called_once_with(webi_user)
