1#!/usr/bin/python 2from __future__ import (absolute_import, division, print_function) 3# Copyright 2019 Fortinet, Inc. 4# 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <https://www.gnu.org/licenses/>. 17 18__metaclass__ = type 19 20ANSIBLE_METADATA = {'status': ['preview'], 21 'supported_by': 'community', 22 'metadata_version': '1.1'} 23 24DOCUMENTATION = ''' 25--- 26module: fortios_system_fsso_polling 27short_description: Configure Fortinet Single Sign On (FSSO) server in Fortinet's FortiOS and FortiGate. 28description: 29 - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the 30 user to set and modify system feature and fsso_polling category. 31 Examples include all parameters and values need to be adjusted to datasources before usage. 32 Tested with FOS v6.0.5 33version_added: "2.9" 34author: 35 - Miguel Angel Munoz (@mamunozgonzalez) 36 - Nicolas Thomas (@thomnico) 37notes: 38 - Requires fortiosapi library developed by Fortinet 39 - Run as a local_action in your playbook 40requirements: 41 - fortiosapi>=0.9.8 42options: 43 host: 44 description: 45 - FortiOS or FortiGate IP address. 46 type: str 47 required: false 48 username: 49 description: 50 - FortiOS or FortiGate username. 51 type: str 52 required: false 53 password: 54 description: 55 - FortiOS or FortiGate password. 56 type: str 57 default: "" 58 vdom: 59 description: 60 - Virtual domain, among those defined previously. A vdom is a 61 virtual instance of the FortiGate that can be configured and 62 used as a different unit. 63 type: str 64 default: root 65 https: 66 description: 67 - Indicates if the requests towards FortiGate must use HTTPS protocol. 68 type: bool 69 default: true 70 ssl_verify: 71 description: 72 - Ensures FortiGate certificate must be verified by a proper CA. 73 type: bool 74 default: true 75 system_fsso_polling: 76 description: 77 - Configure Fortinet Single Sign On (FSSO) server. 78 default: null 79 type: dict 80 suboptions: 81 auth_password: 82 description: 83 - Password to connect to FSSO Agent. 84 type: str 85 authentication: 86 description: 87 - Enable/disable FSSO Agent Authentication. 88 type: str 89 choices: 90 - enable 91 - disable 92 listening_port: 93 description: 94 - Listening port to accept clients (1 - 65535). 95 type: int 96 status: 97 description: 98 - Enable/disable FSSO Polling Mode. 99 type: str 100 choices: 101 - enable 102 - disable 103''' 104 105EXAMPLES = ''' 106- hosts: localhost 107 vars: 108 host: "192.168.122.40" 109 username: "admin" 110 password: "" 111 vdom: "root" 112 ssl_verify: "False" 113 tasks: 114 - name: Configure Fortinet Single Sign On (FSSO) server. 115 fortios_system_fsso_polling: 116 host: "{{ host }}" 117 username: "{{ username }}" 118 password: "{{ password }}" 119 vdom: "{{ vdom }}" 120 https: "False" 121 system_fsso_polling: 122 auth_password: "<your_own_value>" 123 authentication: "enable" 124 listening_port: "5" 125 status: "enable" 126''' 127 128RETURN = ''' 129build: 130 description: Build number of the fortigate image 131 returned: always 132 type: str 133 sample: '1547' 134http_method: 135 description: Last method used to provision the content into FortiGate 136 returned: always 137 type: str 138 sample: 'PUT' 139http_status: 140 description: Last result given by FortiGate on last operation applied 141 returned: always 142 type: str 143 sample: "200" 144mkey: 145 description: Master key (id) used in the last call to FortiGate 146 returned: success 147 type: str 148 sample: "id" 149name: 150 description: Name of the table used to fulfill the request 151 returned: always 152 type: str 153 sample: "urlfilter" 154path: 155 description: Path of the table used to fulfill the request 156 returned: always 157 type: str 158 sample: "webfilter" 159revision: 160 description: Internal revision number 161 returned: always 162 type: str 163 sample: "17.0.2.10658" 164serial: 165 description: Serial number of the unit 166 returned: always 167 type: str 168 sample: "FGVMEVYYQT3AB5352" 169status: 170 description: Indication of the operation's result 171 returned: always 172 type: str 173 sample: "success" 174vdom: 175 description: Virtual domain used 176 returned: always 177 type: str 178 sample: "root" 179version: 180 description: Version of the FortiGate 181 returned: always 182 type: str 183 sample: "v5.6.3" 184 185''' 186 187from ansible.module_utils.basic import AnsibleModule 188from ansible.module_utils.connection import Connection 189from ansible.module_utils.network.fortios.fortios import FortiOSHandler 190from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG 191 192 193def login(data, fos): 194 host = data['host'] 195 username = data['username'] 196 password = data['password'] 197 ssl_verify = data['ssl_verify'] 198 199 fos.debug('on') 200 if 'https' in data and not data['https']: 201 fos.https('off') 202 else: 203 fos.https('on') 204 205 fos.login(host, username, password, verify=ssl_verify) 206 207 208def filter_system_fsso_polling_data(json): 209 option_list = ['auth_password', 'authentication', 'listening_port', 210 'status'] 211 dictionary = {} 212 213 for attribute in option_list: 214 if attribute in json and json[attribute] is not None: 215 dictionary[attribute] = json[attribute] 216 217 return dictionary 218 219 220def underscore_to_hyphen(data): 221 if isinstance(data, list): 222 for elem in data: 223 elem = underscore_to_hyphen(elem) 224 elif isinstance(data, dict): 225 new_data = {} 226 for k, v in data.items(): 227 new_data[k.replace('_', '-')] = underscore_to_hyphen(v) 228 data = new_data 229 230 return data 231 232 233def system_fsso_polling(data, fos): 234 vdom = data['vdom'] 235 system_fsso_polling_data = data['system_fsso_polling'] 236 filtered_data = underscore_to_hyphen(filter_system_fsso_polling_data(system_fsso_polling_data)) 237 238 return fos.set('system', 239 'fsso-polling', 240 data=filtered_data, 241 vdom=vdom) 242 243 244def is_successful_status(status): 245 return status['status'] == "success" or \ 246 status['http_method'] == "DELETE" and status['http_status'] == 404 247 248 249def fortios_system(data, fos): 250 251 if data['system_fsso_polling']: 252 resp = system_fsso_polling(data, fos) 253 254 return not is_successful_status(resp), \ 255 resp['status'] == "success", \ 256 resp 257 258 259def main(): 260 fields = { 261 "host": {"required": False, "type": "str"}, 262 "username": {"required": False, "type": "str"}, 263 "password": {"required": False, "type": "str", "default": "", "no_log": True}, 264 "vdom": {"required": False, "type": "str", "default": "root"}, 265 "https": {"required": False, "type": "bool", "default": True}, 266 "ssl_verify": {"required": False, "type": "bool", "default": True}, 267 "system_fsso_polling": { 268 "required": False, "type": "dict", "default": None, 269 "options": { 270 "auth_password": {"required": False, "type": "str", "no_log": True}, 271 "authentication": {"required": False, "type": "str", 272 "choices": ["enable", "disable"]}, 273 "listening_port": {"required": False, "type": "int"}, 274 "status": {"required": False, "type": "str", 275 "choices": ["enable", "disable"]} 276 277 } 278 } 279 } 280 281 module = AnsibleModule(argument_spec=fields, 282 supports_check_mode=False) 283 284 # legacy_mode refers to using fortiosapi instead of HTTPAPI 285 legacy_mode = 'host' in module.params and module.params['host'] is not None and \ 286 'username' in module.params and module.params['username'] is not None and \ 287 'password' in module.params and module.params['password'] is not None 288 289 if not legacy_mode: 290 if module._socket_path: 291 connection = Connection(module._socket_path) 292 fos = FortiOSHandler(connection) 293 294 is_error, has_changed, result = fortios_system(module.params, fos) 295 else: 296 module.fail_json(**FAIL_SOCKET_MSG) 297 else: 298 try: 299 from fortiosapi import FortiOSAPI 300 except ImportError: 301 module.fail_json(msg="fortiosapi module is required") 302 303 fos = FortiOSAPI() 304 305 login(module.params, fos) 306 is_error, has_changed, result = fortios_system(module.params, fos) 307 fos.logout() 308 309 if not is_error: 310 module.exit_json(changed=has_changed, meta=result) 311 else: 312 module.fail_json(msg="Error in repo", meta=result) 313 314 315if __name__ == '__main__': 316 main() 317