1# Copyright 2019 Fortinet, Inc.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation, either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with Ansible.  If not, see <https://www.gnu.org/licenses/>.
15
16# Make coding more python3-ish
17from __future__ import (absolute_import, division, print_function)
18__metaclass__ = type
19
20import os
21import json
22import pytest
23from mock import ANY
24from ansible.module_utils.network.fortios.fortios import FortiOSHandler
25
26try:
27    from ansible.modules.network.fortios import fortios_user_tacacsplus
28except ImportError:
29    pytest.skip("Could not load required modules for testing", allow_module_level=True)
30
31
32@pytest.fixture(autouse=True)
33def connection_mock(mocker):
34    connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_user_tacacsplus.Connection')
35    return connection_class_mock
36
37
38fos_instance = FortiOSHandler(connection_mock)
39
40
41def test_user_tacacsplus_creation(mocker):
42    schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
43
44    set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
45    set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
46
47    input_data = {
48        'username': 'admin',
49        'state': 'present',
50        'user_tacacsplus': {
51            'authen_type': 'mschap',
52            'authorization': 'enable',
53            'key': 'test_value_5',
54            'name': 'default_name_6',
55            'port': '7',
56            'secondary_key': 'test_value_8',
57            'secondary_server': 'test_value_9',
58            'server': '192.168.100.10',
59            'source_ip': '84.230.14.11',
60            'tertiary_key': 'test_value_12',
61            'tertiary_server': 'test_value_13'
62        },
63        'vdom': 'root'}
64
65    is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
66
67    expected_data = {
68        'authen-type': 'mschap',
69        'authorization': 'enable',
70        'key': 'test_value_5',
71        'name': 'default_name_6',
72                'port': '7',
73                'secondary-key': 'test_value_8',
74                'secondary-server': 'test_value_9',
75                'server': '192.168.100.10',
76                'source-ip': '84.230.14.11',
77                'tertiary-key': 'test_value_12',
78                'tertiary-server': 'test_value_13'
79    }
80
81    set_method_mock.assert_called_with('user', 'tacacs+', data=expected_data, vdom='root')
82    schema_method_mock.assert_not_called()
83    assert not is_error
84    assert changed
85    assert response['status'] == 'success'
86    assert response['http_status'] == 200
87
88
89def test_user_tacacsplus_creation_fails(mocker):
90    schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
91
92    set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
93    set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
94
95    input_data = {
96        'username': 'admin',
97        'state': 'present',
98        'user_tacacsplus': {
99            'authen_type': 'mschap',
100            'authorization': 'enable',
101            'key': 'test_value_5',
102            'name': 'default_name_6',
103            'port': '7',
104            'secondary_key': 'test_value_8',
105            'secondary_server': 'test_value_9',
106            'server': '192.168.100.10',
107            'source_ip': '84.230.14.11',
108            'tertiary_key': 'test_value_12',
109            'tertiary_server': 'test_value_13'
110        },
111        'vdom': 'root'}
112
113    is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
114
115    expected_data = {
116        'authen-type': 'mschap',
117        'authorization': 'enable',
118        'key': 'test_value_5',
119        'name': 'default_name_6',
120                'port': '7',
121                'secondary-key': 'test_value_8',
122                'secondary-server': 'test_value_9',
123                'server': '192.168.100.10',
124                'source-ip': '84.230.14.11',
125                'tertiary-key': 'test_value_12',
126                'tertiary-server': 'test_value_13'
127    }
128
129    set_method_mock.assert_called_with('user', 'tacacs+', data=expected_data, vdom='root')
130    schema_method_mock.assert_not_called()
131    assert is_error
132    assert not changed
133    assert response['status'] == 'error'
134    assert response['http_status'] == 500
135
136
137def test_user_tacacsplus_removal(mocker):
138    schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
139
140    delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
141    delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
142
143    input_data = {
144        'username': 'admin',
145        'state': 'absent',
146        'user_tacacsplus': {
147            'authen_type': 'mschap',
148            'authorization': 'enable',
149            'key': 'test_value_5',
150            'name': 'default_name_6',
151            'port': '7',
152            'secondary_key': 'test_value_8',
153            'secondary_server': 'test_value_9',
154            'server': '192.168.100.10',
155            'source_ip': '84.230.14.11',
156            'tertiary_key': 'test_value_12',
157            'tertiary_server': 'test_value_13'
158        },
159        'vdom': 'root'}
160
161    is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
162
163    delete_method_mock.assert_called_with('user', 'tacacs+', mkey=ANY, vdom='root')
164    schema_method_mock.assert_not_called()
165    assert not is_error
166    assert changed
167    assert response['status'] == 'success'
168    assert response['http_status'] == 200
169
170
171def test_user_tacacsplus_deletion_fails(mocker):
172    schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
173
174    delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
175    delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
176
177    input_data = {
178        'username': 'admin',
179        'state': 'absent',
180        'user_tacacsplus': {
181            'authen_type': 'mschap',
182            'authorization': 'enable',
183            'key': 'test_value_5',
184            'name': 'default_name_6',
185            'port': '7',
186            'secondary_key': 'test_value_8',
187            'secondary_server': 'test_value_9',
188            'server': '192.168.100.10',
189            'source_ip': '84.230.14.11',
190            'tertiary_key': 'test_value_12',
191            'tertiary_server': 'test_value_13'
192        },
193        'vdom': 'root'}
194
195    is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
196
197    delete_method_mock.assert_called_with('user', 'tacacs+', mkey=ANY, vdom='root')
198    schema_method_mock.assert_not_called()
199    assert is_error
200    assert not changed
201    assert response['status'] == 'error'
202    assert response['http_status'] == 500
203
204
205def test_user_tacacsplus_idempotent(mocker):
206    schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
207
208    set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
209    set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
210
211    input_data = {
212        'username': 'admin',
213        'state': 'present',
214        'user_tacacsplus': {
215            'authen_type': 'mschap',
216            'authorization': 'enable',
217            'key': 'test_value_5',
218            'name': 'default_name_6',
219            'port': '7',
220            'secondary_key': 'test_value_8',
221            'secondary_server': 'test_value_9',
222            'server': '192.168.100.10',
223            'source_ip': '84.230.14.11',
224            'tertiary_key': 'test_value_12',
225            'tertiary_server': 'test_value_13'
226        },
227        'vdom': 'root'}
228
229    is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
230
231    expected_data = {
232        'authen-type': 'mschap',
233        'authorization': 'enable',
234        'key': 'test_value_5',
235        'name': 'default_name_6',
236                'port': '7',
237                'secondary-key': 'test_value_8',
238                'secondary-server': 'test_value_9',
239                'server': '192.168.100.10',
240                'source-ip': '84.230.14.11',
241                'tertiary-key': 'test_value_12',
242                'tertiary-server': 'test_value_13'
243    }
244
245    set_method_mock.assert_called_with('user', 'tacacs+', data=expected_data, vdom='root')
246    schema_method_mock.assert_not_called()
247    assert not is_error
248    assert not changed
249    assert response['status'] == 'error'
250    assert response['http_status'] == 404
251
252
253def test_user_tacacsplus_filter_foreign_attributes(mocker):
254    schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
255
256    set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
257    set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
258
259    input_data = {
260        'username': 'admin',
261        'state': 'present',
262        'user_tacacsplus': {
263            'random_attribute_not_valid': 'tag',
264            'authen_type': 'mschap',
265            'authorization': 'enable',
266            'key': 'test_value_5',
267            'name': 'default_name_6',
268            'port': '7',
269            'secondary_key': 'test_value_8',
270            'secondary_server': 'test_value_9',
271            'server': '192.168.100.10',
272            'source_ip': '84.230.14.11',
273            'tertiary_key': 'test_value_12',
274            'tertiary_server': 'test_value_13'
275        },
276        'vdom': 'root'}
277
278    is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
279
280    expected_data = {
281        'authen-type': 'mschap',
282        'authorization': 'enable',
283        'key': 'test_value_5',
284        'name': 'default_name_6',
285                'port': '7',
286                'secondary-key': 'test_value_8',
287                'secondary-server': 'test_value_9',
288                'server': '192.168.100.10',
289                'source-ip': '84.230.14.11',
290                'tertiary-key': 'test_value_12',
291                'tertiary-server': 'test_value_13'
292    }
293
294    set_method_mock.assert_called_with('user', 'tacacs+', data=expected_data, vdom='root')
295    schema_method_mock.assert_not_called()
296    assert not is_error
297    assert changed
298    assert response['status'] == 'success'
299    assert response['http_status'] == 200
300