def config(isamAppliance, server, resourceUri, policies=[], policyType=None, policyCombiningAlgorithm=None, cache=None, check_mode=False, force=False): """ Configure a resource Note: Please input policies with policy names (it will be converted to id's), like so: [{'name': '<policy name>', 'type': 'policy'}, {'name': '<policyset name>', 'type': 'policyset'}, {'name': '<definition name>', 'type': 'definition'}] """ warnings = [] if force is False: ret_obj = search(isamAppliance, server, resourceUri) if force is True or ret_obj['data'] == {}: json_data = {"server": server, "resourceUri": resourceUri} if policyType is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.6.0") < 0: warnings.append( "Appliance at version: {0}, policyType: {1} is not supported. Needs 9.0.6.0 or higher. Ignoring policyType for this call." .format(isamAppliance.facts["version"], cache)) else: json_data['type'] = policyType json_data['policies'] = _convert_policy_name_to_id( isamAppliance, policies) if policyCombiningAlgorithm is not None: json_data['policyCombiningAlgorithm'] = policyCombiningAlgorithm if cache is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.3.0") < 0: warnings.append( "Appliance at version: {0}, cache: {1} is not supported. Needs 9.0.3.0 or higher. Ignoring cache for this call." .format(isamAppliance.facts["version"], cache)) else: json_data["cache"] = cache if check_mode is True: return isamAppliance.create_return_object(changed=True, warnings=warnings) else: return isamAppliance.invoke_post("Configure a resource", uri, json_data, warnings=warnings) return isamAppliance.create_return_object()
def execute(isamAppliance, operation="restart", check_mode=False, force=False): """ Execute an operation (start, stop or restart) on runtime """ warnings = [] # Reload function is new to ISAM v9.0.2.0 if operation == "reload" and tools.version_compare( isamAppliance.facts["version"], "9.0.2.0") < 0: warnings.append( "Appliance is at version {0}, reload requires atleast v9.0.2.0". format(isamAppliance.facts['version'])) return isamAppliance.create_return_object(warnings=warnings) if force is True or _check(isamAppliance, operation) is True: if check_mode is True: return isamAppliance.create_return_object(changed=True, warnings=warnings) else: return isamAppliance.invoke_put( "Executing an operation on runtime", uri, {'operation': operation}, requires_modules=requires_modules, requires_version=requires_version, warnings=warnings) return isamAppliance.create_return_object()
def update(isamAppliance, server, resourceUri, policyCombiningAlgorithm, cache=None, check_mode=False, force=False): """ Update the policy attachment combining algorithm """ warnings = [] ret_obj = get(isamAppliance, server, resourceUri) if force is True or ( ret_obj['data'] != {} and ( ret_obj['data']['policyCombiningAlgorithm'] != policyCombiningAlgorithm or ret_obj['data']['cache'] != cache)): json_data = { "policyCombiningAlgorithm": policyCombiningAlgorithm } if cache is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.3.0") < 0: warnings.append( "Appliance at version: {0}, cache: {1} is not supported. Needs 9.0.3.0 or higher. Ignoring cache for this call.".format( isamAppliance.facts["version"], cache)) else: json_data["cache"] = cache if check_mode is True: return isamAppliance.create_return_object(changed=True, warnings=warnings) else: return isamAppliance.invoke_put( "Update the policy attachment combining algorithm and cache", "{0}/{1}/properties".format(uri, ret_obj['data']['id']), json_data, warnings=warnings) return isamAppliance.create_return_object()
def add(isamAppliance, name, policy, uri, description="", dialect="urn:ibm:security:authentication:policy:1.0:schema", enabled=None, check_mode=False, force=False): """ Duplicate and create an authentication policy """ if force is True or _check(isamAppliance, name=name) is False: if check_mode is True: return isamAppliance.create_return_object(changed=True) else: warnings = [] json_data = { "name": name, "description": description, "policy": policy, "uri": uri, "dialect": dialect } if enabled is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.2.1") < 0: warnings.append( "Appliance is at version: {0}. Enabled parameter not supported unless atleast 9.0.2.1. Ignoring value.".format( isamAppliance.facts["version"])) else: json_data["enabled"] = enabled return isamAppliance.invoke_post( "Duplicate and create an authentication policy", module_uri, json_data, requires_modules=requires_modules, requires_version=requires_version, warnings=warnings) return isamAppliance.create_return_object()
def activate(isamAppliance, name, enabled=True, check_mode=False, force=False): """ Enable or disable a policy """ warnings = [] if tools.version_compare(isamAppliance.facts["version"], "9.0.2.1") < 0: warnings.append( "Appliance is at version: {0}. Enabled parameter not supported unless atleast 9.0.2.1. Ignoring value." .format(isamAppliance.facts["version"])) else: ret_obj = get(isamAppliance, name=name) if force or ret_obj['data']['enabled'] != enabled: if check_mode is True: return isamAppliance.create_return_object(changed=True, warnings=warnings) else: return update(isamAppliance, name=name, policy=ret_obj['data']['policy'], uri=ret_obj['data']['uri'], description=ret_obj['data']['description'], dialect=ret_obj['data']['dialect'], enabled=enabled) return isamAppliance.create_return_object(warnings=warnings)
def create(isamAppliance, comment='', wrp=None, isam_runtime=None, lmi=None, cluster=None, felb=None, aac_federation=None, system=None, check_mode=False, force=False): """ Creating a new support file """ json_data = {} json_data['comment'] = comment min_version = True if 'version' in isamAppliance.facts and isamAppliance.facts[ 'version'] is not None: if tools.version_compare(isamAppliance.facts['version'], requires_version) < 0: min_version = False if min_version is True: if wrp != None: json_data['wrp'] = wrp if isam_runtime != None: json_data['isam_runtime'] = isam_runtime if lmi != None: json_data['lmi'] = lmi if cluster != None: json_data['cluster'] = cluster if felb != None: json_data['felb'] = felb if aac_federation != None: json_data['aac_federation'] = aac_federation if system != None: json_data['system'] = system if force is True or _check(isamAppliance, comment=comment) is False: if check_mode is True: return isamAppliance.create_return_object(changed=True) else: return isamAppliance.invoke_post("Creating a new support file", "{0}/".format(uri), json_data, requires_modules=requires_modules, requires_version=requires_version) return isamAppliance.create_return_object()
def add(isamAppliance, instance_name, resource_server_name, method, path, policy, server_type="standard", cors_policy='', static_response_headers=[], url_aliases=[], name=None, rate_limiting_policy=None, documentation=None, check_mode=False, force=False): """ Creating a new API Access Control Resource """ instance_exist, warnings = _check_instance_exist(isamAppliance, instance_name) if force is False: if instance_exist is False: warnings.append("{0} does not exist".format(instance_name)) return isamAppliance.create_return_object(warnings=warnings) else: server_exist, warnings = _check_server_exist(isamAppliance, instance_name, resource_server_name) if server_exist is False: warnings.append("The specified resource server name does not exist") return isamAppliance.create_return_object(warnings=warnings) resource_exist, warnings = _check_resource_exist(isamAppliance, instance_name, resource_server_name, method, path) if force is True or resource_exist is False: if check_mode is True: return isamAppliance.create_return_object(changed=True) else: json_data = { 'method': method, 'policy': policy, 'server_type': server_type, 'cors_policy': cors_policy, 'static_response_headers': static_response_headers, 'url_aliases': url_aliases } if tools.version_compare(isamAppliance.facts["version"], "10.0.0") < 0: json_data['path'] = path else: json_data['path'] = "{0}{1}".format(resource_server_name, path) if name is not None: json_data['name'] = name if rate_limiting_policy is not None: json_data['rate_limiting_policy'] = rate_limiting_policy if documentation is not None: json_data['documentation'] = documentation return isamAppliance.invoke_post( "Creating a new API Access Control Resource", "{0}/{1}/server{2}/resource".format(uri, instance_name, resource_server_name), json_data, requires_modules=requires_modules, requires_version=requires_version) return isamAppliance.create_return_object(warnings=warnings)
def _check_resource_exist(isamAppliance, instance_name, resource_server_name, method, path): ret_obj = get_all(isamAppliance, instance_name, resource_server_name) warnings = ret_obj['warnings'] if tools.version_compare(isamAppliance.facts["version"], "10.0.0") < 0: path_name = path else: path_name = "{0}{1}".format(resource_server_name, path) for obj in ret_obj['data']: if obj['method'] == method and obj['path'] == path_name: return True, warnings return False, warnings
def _process_warnings(self, uri, requires_modules, requires_version, warnings=[]): # flag to indicate if processing needs to return and not continue return_call = False self.logger.debug( "Checking for minimum version: {0}.".format(requires_version)) if requires_version is not None and 'version' in self.facts and self.facts[ 'version'] is not None: if tools.version_compare(self.facts['version'], requires_version) < 0: return_call = True warnings.append( "API invoked requires minimum version: {0}, appliance is of lower version: {1}." .format(requires_version, self.facts['version'])) # Detecting modules from uri if none is provided if requires_modules is None and not requires_modules: if uri.startswith("/wga"): requires_modules = ['wga'] self.logger.debug("Detected module: {0} from uri: {1}.".format( requires_modules, uri)) elif uri.startswith("/mga"): requires_modules = ['mga'] self.logger.debug("Detected module: {0} from uri: {1}.".format( requires_modules, uri)) self.logger.debug("Checking for one of required modules: {0}.".format( requires_modules)) if requires_modules is not None and requires_modules: if 'activations' in self.facts and self.facts['activations']: # Find intersection of the two lists iactive = [ ia for ia in self.facts['activations'] if ia in requires_modules ] if not iactive: return_call = True warnings.append( "API invoked requires one of modules: {0}, appliance has these modules active: {1}." .format(requires_modules, self.facts['activations'])) else: self.logger.info( "Modules satisfying requirement: {0}".format(iactive)) else: return_call = True warnings.append( "API invoked requires module: {0}, appliance has no modules active." .format(requires_modules)) self.logger.debug("Warnings: {0}".format(warnings)) return warnings, return_call
def update(isamAppliance, instance_name, resource_server_name, method, path, policy, server_type="standard", cors_policy='', static_response_headers=[], url_aliases=[], name=None, rate_limiting_policy=None, documentation=None, check_mode=False, force=False): """ Updating an existing API Access Control Resource """ instance_exist, warnings = _check_instance_exist(isamAppliance, instance_name) if force is False: if instance_exist is False: warnings.append("{0} does not exist".format(instance_name)) return isamAppliance.create_return_object(warnings=warnings) else: server_exist, warnings = _check_server_exist(isamAppliance, instance_name, resource_server_name) if server_exist is False: warnings.append("The specified resource server name does not exist") return isamAppliance.create_return_object(warnings=warnings) else: resource_exist, warnings = _check_resource_exist(isamAppliance, instance_name, resource_server_name, method, path) if resource_exist is False: warnings.append("The specified resource does not exist") return isamAppliance.create_return_object(warnings=warnings) update_required, warnings, json_data = _check_resource_content(isamAppliance=isamAppliance, instance_name=instance_name, resource_server_name=resource_server_name, method=method, path=path, policy=policy, cors_policy=cors_policy, name=name, static_response_headers=static_response_headers, rate_limiting_policy=rate_limiting_policy, url_aliases=url_aliases, documentation=documentation) if force is True or update_required is True: if check_mode is True: return isamAppliance.create_return_object(changed=True) else: if tools.version_compare(isamAppliance.facts["version"], "10.0.0") < 0: url = "{0}/{1}/server{2}/resource/{3}{4}?server_type={5}".format(uri, instance_name, resource_server_name, method, path, server_type) else: url = "{0}/{1}/server{2}/resource/{3}{2}{4}?server_type={5}".format(uri, instance_name, resource_server_name, method, path, server_type) return isamAppliance.invoke_put( "Updating an existing API Access Control Resource", url, json_data, requires_modules=requires_modules, requires_version=requires_version) return isamAppliance.create_return_object(warnings=warnings)
def get_version(self): """ Get appliance version (versions API or active partition) When firmware are installed or partition are changed, then this value is updated """ self.facts['version'] = None import ibmsecurity.isam.base.version import ibmsecurity.isam.base.firmware try: ret_obj = ibmsecurity.isam.base.version.get(self) self.facts['version'] = ret_obj['data']['firmware_version'] if tools.version_compare(self.facts['version'], '9.0.3.0') > 0: if 'deployment_model' in ret_obj['data']: self.facts['model'] = ret_obj['data']['deployment_model'] if 'product_name' in ret_obj['data']: self.facts['product_name'] = ret_obj['data'][ 'product_name'] if 'product_description' in ret_obj['data']: self.facts['product_description'] = ret_obj['data'][ 'product_description'] if 'firmware_build' in ret_obj['data']: self.facts['firmware_build'] = ret_obj['data'][ 'firmware_build'] if 'firmware_label' in ret_obj['data']: self.facts['firmware_label'] = ret_obj['data'][ 'firmware_label'] # Be sure to let fatal error unconditionally percolate up the stack except IBMFatal: raise except IBMError: self.logger.error(traceback.print_exc()) try: ret_obj = ibmsecurity.isam.base.firmware.get(self) for partition in ret_obj['data']: if partition['active'] is True: ver = partition['firmware_version'].split(' ') self.facts['version'] = ver[-1] self.facts['model'] = "Appliance" except: self.logger.error(traceback.print_exc()) pass return
def update(isamAppliance, name, policy, uri, description="", dialect="urn:ibm:security:authentication:policy:1.0:schema", enabled=None, check_mode=False, force=False): """ Update a specified authentication policy """ warnings = [] needs_update = False json_data = { "name": name, "description": description, "policy": policy, "uri": uri, "dialect": dialect } if enabled is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.2.1") < 0: warnings.append( "Appliance is at version: {0}. Enabled parameter not supported unless atleast 9.0.2.1. Ignoring value.".format( isamAppliance.facts["version"])) else: json_data["enabled"] = enabled if force is not True: try: ret_obj = get(isamAppliance, name) id = ret_obj['data']['id'] del ret_obj['data']['id'] del ret_obj['data']['datecreated'] del ret_obj['data']['lastmodified'] del ret_obj['data']['userlastmodified'] del ret_obj['data']['predefined'] import ibmsecurity.utilities.tools exist_data = ibmsecurity.utilities.tools.json_sort(ret_obj['data']) new_data = ibmsecurity.utilities.tools.json_sort(json_data) logger.debug("Existing Data: {0}".format(exist_data)) logger.debug("Provided Data: {0}".format(new_data)) if exist_data != new_data: needs_update = True except: pass if force is True or needs_update is True: if check_mode is True: return isamAppliance.create_return_object(changed=True) else: return isamAppliance.invoke_put( "Update a specified authentication policy", "{0}/{1}".format(module_uri, id), json_data, requires_modules=requires_modules, requires_version=requires_version, warnings=warnings) return isamAppliance.create_return_object()
def get(isamAppliance, instance_name, resource_server_name, resource_name, method, server_type="standard", check_mode=False, force=False): """ Retrieve a single API Access Control Resource """ if tools.version_compare(isamAppliance.facts["version"], "10.0.0") < 0: url = "{0}/{1}/server{2}/resource/{3}{4}?server_type={5}".format(uri, instance_name, resource_server_name, method, resource_name, server_type) else: url = "{0}/{1}/server{2}/resource/{3}{2}{4}?server_type={5}".format(uri, instance_name, resource_server_name, method, resource_name, server_type) return isamAppliance.invoke_get("Retrieve a single API Access Control Resource", url, requires_modules=requires_modules, requires_version=requires_version)
def execute(isamAppliance, enabled, filter=None, interface=None, max_size=None, check_mode=False, force=False, snaplen=None): """ Execute an operation (start, stop or restart) on packet tracing """ check_value, warnings = _check(isamAppliance, enabled) json_data = {"enable": enabled} if filter is not None: json_data['filter'] = filter if interface is not None: json_data['interface'] = interface if max_size is not None: json_data['max_size'] = interface if snaplen is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.6.0") < 0: warnings.append( "Appliance at version: {}, snaplen: {1} is not supported. Needs 9.0.6.0 or higher. Ignoring snaplen for this call." .format(isamAppliance.facts["version"], snaplen)) else: json_data["snaplen"] = snaplen if force is True or check_value is False: if check_mode is True: return isamAppliance.create_return_object(changed=True, warnings=warnings) else: return isamAppliance.invoke_put( "Executing an operation on packet trace", "/isam/packet_tracing/", json_data, requires_model=requires_model, warnings=warnings) return isamAppliance.create_return_object(warnings=warnings)
def get_version(self): """ Get appliance version (versions API or active partition) When firmware are installed or partition are changed, then this value is updated """ self.facts['version'] = None import ibmsecurity.isam.base.version import ibmsecurity.isam.base.firmware try: ret_obj = ibmsecurity.isam.base.version.get(self) self.facts['version'] = ret_obj['data']['firmware_version'] if tools.version_compare(self.facts['version'], '9.0.3.0') > 0: if 'deployment_model' in ret_obj['data']: self.facts['model'] = ret_obj['data']['deployment_model'] if 'product_name' in ret_obj['data']: self.facts['product_name'] = ret_obj['data'][ 'product_name'] if 'product_description' in ret_obj['data']: self.facts['product_description'] = ret_obj['data'][ 'product_description'] if 'firmware_build' in ret_obj['data']: self.facts['firmware_build'] = ret_obj['data'][ 'firmware_build'] if 'firmware_label' in ret_obj['data']: self.facts['firmware_label'] = ret_obj['data'][ 'firmware_label'] except IBMError: try: ret_obj = ibmsecurity.isam.base.firmware.get(self) for partition in ret_obj['data']: if partition['active'] is True: ver = partition['firmware_version'].split(' ') self.facts['version'] = ver[-1] self.facts['model'] = "Appliance" except: pass return
def get(isamAppliance, reverseproxy_id, junctionname, check_mode=False, force=False): """ Retrieving the parameters for a single standard or virtual junction :param isamAppliance: :param reverseproxy_id: :param junctionname: :param check_mode: :param force: :return: """ ret_obj = isamAppliance.invoke_get( "Retrieving the parameters for a single standard or virtual junction", "{0}/{1}/junctions?junctions_id={2}".format(uri, reverseproxy_id, junctionname), requires_modules=requires_modules, requires_version=requires_version) # servers are provided as a single string, here we parse it out into a list + dict servers = [] if tools.version_compare(isamAppliance.facts["version"], "9.0.1.0") > 0: srv_separator = '#' else: srv_separator = '&' logger.debug("Server Separator being used: {0}".format(srv_separator)) srvs = ret_obj['data']['servers'].split(srv_separator) logger.debug("Servers in raw string: {0}".format( ret_obj['data']['servers'])) logger.debug("Number of servers in junction: {0}".format(len(srvs))) for srv in srvs: logger.debug("Parsing Server: {0}".format(srv)) server = {} for s in srv.split(';'): if s != '': kv = s.split('!') server[kv[0]] = kv[1] servers.append(server) ret_obj['data']['servers'] = servers return ret_obj
def export_file(isamAppliance, instance_name, resource_server_name, method, path, file_path, server_type="standard", check_mode=False, force=False): """ Exporting an existing API Access Control Resource """ if os.path.exists(file_path) is True: warn_str = "File {0} already exists".format(file_path) warnings = [warn_str] return isamAppliance.create_return_object(warnings=warnings) instance_exist, warnings = _check_instance_exist(isamAppliance, instance_name) if force is False: if instance_exist is False: warnings.append("{0} does not exist".format(instance_name)) return isamAppliance.create_return_object(warnings=warnings) else: server_exist, warnings = _check_server_exist(isamAppliance, instance_name, resource_server_name) if server_exist is False: warnings.append("The specified resource server name does not exist") return isamAppliance.create_return_object(warnings=warnings) resource_exist, warnings = _check_resource_exist(isamAppliance, instance_name, resource_server_name, method, path) if force is True or resource_exist is True: if check_mode is True: return isamAppliance.create_return_object(changed=True) else: if tools.version_compare(isamAppliance.facts["version"], "10.0.0") < 0: url = "{0}/{1}/server{2}/resource/{3}{4}?export=true&server_type={5}".format(uri, instance_name, resource_server_name, method, path, server_type) else: url = "{0}/{1}/server{2}/resource/{3}{2}{4}?export=true&server_type={5}".format(uri, instance_name, resource_server_name, method, path, server_type) return isamAppliance.invoke_get_file( "Exporting an existing API Access Control Resource", url, file_path, requires_modules=requires_modules, requires_version=requires_version) return isamAppliance.create_return_object(warnings=warnings)
def _check_resource_content(isamAppliance, instance_name, resource_server_name, method, path, policy, cors_policy, static_response_headers, url_aliases, name, rate_limiting_policy, documentation): ret_obj = get(isamAppliance, instance_name, resource_server_name, path, method) current_data = ret_obj['data'] del current_data['id'] json_data = { 'method': method, 'policy': policy, 'cors_policy': cors_policy, 'static_response_headers': static_response_headers, 'url_aliases': url_aliases } if tools.version_compare(isamAppliance.facts["version"], "10.0.0") < 0: json_data['path'] = path else: json_data['path'] = "{0}{1}".format(resource_server_name, path) if name is not None: json_data['name'] = name if rate_limiting_policy is not None: json_data['rate_limiting_policy'] = rate_limiting_policy if documentation is not None: json_data['documentation'] = documentation sorted_obj1 = tools.json_sort(json_data) logger.debug("Sorted sorted_obj1: {0}".format(sorted_obj1)) sorted_obj2 = tools.json_sort(current_data) logger.debug("Sorted sorted_obj2: {0}".format(sorted_obj2)) if sorted_obj1 != sorted_obj2: logger.info("Changes detected, update needed.") return True, ret_obj['warnings'], json_data return False, ret_obj['warnings'], json_data
def delete(isamAppliance, instance_name, resource_server_name, method, path, server_type='standard', check_mode=False, force=False): """ Delete an existing API Access Control Resource """ instance_exist, warnings = _check_instance_exist(isamAppliance, instance_name) if force is False: if instance_exist is False: warnings.append("{0} does not exist".format(instance_name)) return isamAppliance.create_return_object(warnings=warnings) else: server_exist, warnings = _check_server_exist(isamAppliance, instance_name, resource_server_name) if server_exist is False: warnings.append("The specified resource server name does not exist") return isamAppliance.create_return_object(warnings=warnings) resource_exist, warnings = _check_resource_exist(isamAppliance, instance_name, resource_server_name, method, path) if force is True or resource_exist is True: if check_mode is True: return isamAppliance.create_return_object(changed=True) else: if tools.version_compare(isamAppliance.facts["version"], "10.0.0") < 0: url = "{0}/{1}/server{2}/resource/{3}{4}?server_type={5}".format(uri, instance_name, resource_server_name, method, path, server_type) else: url = "{0}/{1}/server{2}/resource/{3}{2}{4}?server_type={5}".format(uri, instance_name, resource_server_name, method, path, server_type) return isamAppliance.invoke_delete( "Delete an existing API Access Control Resource", url, requires_modules=requires_modules, requires_version=requires_version) return isamAppliance.create_return_object(warnings=warnings)
def add(isamAppliance, reverseproxy_id, junction_point, server_hostname, junction_type, server_port, server_dn=None, stateful_junction='no', case_sensitive_url='no', windows_style_url='no', virtual_hostname=None, virtual_https_hostname=None, query_contents=None, https_port=None, http_port=None, proxy_hostname=None, proxy_port=None, sms_environment=None, vhost_label=None, server_uuid=None, priority=None, server_cn=None, check_mode=False, force=False): """ Adding a back-end server to an existing standard or virtual junctions :param isamAppliance: :param reverseproxy_id: :param junctionname: :param server_hostname: :param junction_type: :param server_port: :param virtual_hostname: :param virtual_https_hostname: :param server_dn: :param query_contents: :param stateful_junction: :param case_sensitive_url: :param windows_style_url: :param https_port: :param http_port: :param proxy_hostname: :param proxy_port: :param sms_environment: :param vhost_label: :param server_uuid: :param priority: :param server_cn: :param check_mode: :param force: :return: """ # Search for the UUID of the junctioned server if force is False: ret_obj = search(isamAppliance, reverseproxy_id, junction_point, server_hostname, server_port) if force is True or ret_obj['data'] == {}: if check_mode is True: return isamAppliance.create_return_object(changed=True) else: jct_srv_json = { "junction_point": junction_point, "junction_type": junction_type, "server_hostname": server_hostname, "server_port": server_port, "stateful_junction": stateful_junction, "case_sensitive_url": case_sensitive_url, "windows_style_url": windows_style_url, } if https_port is not None: jct_srv_json["https_port"] = https_port if http_port is not None: jct_srv_json["http_port"] = http_port if proxy_hostname is not None: jct_srv_json["proxy_hostname"] = proxy_hostname if proxy_port is not None: jct_srv_json["proxy_port"] = proxy_port if sms_environment is not None: jct_srv_json["sms_environment"] = sms_environment if vhost_label is not None: jct_srv_json["vhost_label"] = vhost_label if server_dn is not None: jct_srv_json["server_dn"] = server_dn if virtual_hostname: jct_srv_json["virtual_hostname"] = virtual_hostname if virtual_https_hostname is not None: jct_srv_json["virtual_https_hostname"] = virtual_https_hostname if query_contents is not None: jct_srv_json["query_contents"] = query_contents if server_uuid is not None and server_uuid != '': jct_srv_json["server_uuid"] = server_uuid if server_cn is not None: if tools.version_compare(isamAppliance.facts["version"], "10.0.2.0") < 0: warnings.append( "Appliance at version: {0}, server_cn: {1} is not supported. Needs 10.0.2.0 or higher. Ignoring server_cn for this call." .format(isamAppliance.facts["version"], server_cn)) server_cn = None else: jct_srv_json["server_cn"] = server_cn if priority is not None: if tools.version_compare(isamAppliance.facts["version"], "10.0.2.0") < 0: warnings.append( "Appliance at version: {0}, priority: {1} is not supported. Needs 10.0.2.0 or higher. Ignoring priority for this call." .format(isamAppliance.facts["version"], priority)) priority = None else: jct_srv_json["priority"] = priority return isamAppliance.invoke_put( "Adding a back-end server to an existing standard or virtual junctions", "{0}/{1}/junctions".format(uri, reverseproxy_id), jct_srv_json) return isamAppliance.create_return_object()
def add(isamAppliance, name, definitionName, companyName, redirectUri=None, companyUrl=None, contactPerson=None, contactType=None, email=None, phone=None, otherInfo=None, clientId=None, clientSecret=None, requirePkce=None, encryptionDb=None, encryptionCert=None, jwksUri=None, extProperties=None, check_mode=False, force=False): """ Create an API protection definition """ ret_obj = definitions.search(isamAppliance, definitionName, check_mode=check_mode, force=force) if ret_obj['data'] == {}: warnings = ret_obj["warnings"] warnings.append( "API Protection Definition {0} is not found. Cannot process client request." .format(definitionName)) return isamAppliance.create_return_object(warnings=warnings) else: definition = ret_obj['data'] ret_obj = search(isamAppliance, name=name, check_mode=check_mode, force=force) warnings = ret_obj["warnings"] if force is True or ret_obj["data"] == {}: if check_mode is True: return isamAppliance.create_return_object(changed=True, warnings=warnings) else: # Create a simple json with just the main client attributes client_json = { "name": name, "definition": definition, "companyName": companyName } # Add attributes that have been supplied... otherwise skip them. if redirectUri is not None: client_json["redirectUri"] = redirectUri if companyUrl is not None: client_json["companyUrl"] = companyUrl if contactPerson is not None: client_json["contactPerson"] = contactPerson if contactType is not None: client_json["contactType"] = contactType if email is not None: client_json["email"] = email if phone is not None: client_json["phone"] = phone if otherInfo is not None: client_json["otherInfo"] = otherInfo if clientId is not None: client_json["clientId"] = clientId if clientSecret is not None: client_json["clientSecret"] = clientSecret if requirePkce is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, requirePkce: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring requirePkce for this call." .format(isamAppliance.facts["version"], requirePkce)) else: client_json["requirePkce"] = requirePkce if encryptionDb is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, encryptionDb: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring encryptionDb for this call." .format(isamAppliance.facts["version"], encryptionDb)) else: client_json["encryptionDb"] = encryptionDb if encryptionCert is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, encryptionCert: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring encryptionCert for this call." .format(isamAppliance.facts["version"], encryptionCert)) else: client_json["encryptionCert"] = encryptionCert if jwksUri is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, jwksUri: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring jwksUri for this call." .format(isamAppliance.facts["version"], jwksUri)) else: client_json["jwksUri"] = jwksUri if extProperties is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.5.0") < 0: warnings.append( "Appliance at version: {0}, extProperties: {1} is not supported. Needs 9.0.5.0 or higher. Ignoring extProperties for this call." .format(isamAppliance.facts["version"], extProperties)) else: client_json["extProperties"] = extProperties return isamAppliance.invoke_post( "Create an API protection definition", uri, client_json, requires_modules=requires_modules, requires_version=requires_version, warnings=warnings) return isamAppliance.create_return_object(warnings=warnings)
def update(isamAppliance, name, definitionName, companyName, redirectUri=None, companyUrl=None, contactPerson=None, contactType=None, email=None, phone=None, otherInfo=None, clientId=None, clientSecret=None, requirePkce=None, encryptionDb=None, encryptionCert=None, jwksUri=None, extProperties=None, check_mode=False, force=False, new_name=None): """ Update a specified mapping rule """ ret_obj = definitions.search(isamAppliance, definitionName, check_mode=check_mode, force=force) if ret_obj['data'] == {}: warnings = ret_obj["warnings"] warnings.append( "API Protection Definition {0} is not found. Cannot process client request." .format(definitionName)) return isamAppliance.create_return_object(warnings=warnings) else: definition = ret_obj['data'] ret_obj = get(isamAppliance, name) warnings = ret_obj["warnings"] if ret_obj["data"] == {}: warnings.append("Client {0} not found, skipping update.".format(name)) return isamAppliance.create_return_object(warnings=warnings) else: id = ret_obj["data"]["id"] needs_update = False # Create a simple json with just the main client attributes json_data = {"definition": definition, "companyName": companyName} if new_name is not None: json_data['name'] = new_name else: json_data['name'] = name if force is not True: del ret_obj['data']['id'] # Add attributes that have been supplied... otherwise skip them. if redirectUri is not None: json_data["redirectUri"] = redirectUri elif 'redirectUri' in ret_obj['data']: del ret_obj['data']['redirectUri'] if companyUrl is not None: json_data["companyUrl"] = companyUrl elif 'companyUrl' in ret_obj['data']: del ret_obj['data']['companyUrl'] if contactPerson is not None: json_data["contactPerson"] = contactPerson elif 'contactPerson' in ret_obj['data']: del ret_obj['data']['contactPerson'] if contactType is not None: json_data["contactType"] = contactType elif 'contactType' in ret_obj['data']: del ret_obj['data']['contactType'] if email is not None: json_data["email"] = email elif 'email' in ret_obj['data']: del ret_obj['data']['email'] if phone is not None: json_data["phone"] = phone elif 'phone' in ret_obj['data']: del ret_obj['data']['phone'] if otherInfo is not None: json_data["otherInfo"] = otherInfo elif 'otherInfo' in ret_obj['data']: del ret_obj['data']['otherInfo'] if clientId is not None: json_data["clientId"] = clientId elif 'clientId' in ret_obj['data']: del ret_obj['data']['clientId'] if clientSecret is not None: json_data["clientSecret"] = clientSecret elif 'clientSecret' in ret_obj['data']: del ret_obj['data']['clientSecret'] if requirePkce is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, requirePkce: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring requirePkce for this call." .format(isamAppliance.facts["version"], requirePkce)) else: json_data["requirePkce"] = requirePkce elif 'requirePkce' in ret_obj['data']: del ret_obj['data']['requirePkce'] if encryptionDb is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, encryptionDb: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring encryptionDb for this call." .format(isamAppliance.facts["version"], encryptionDb)) else: json_data["encryptionDb"] = encryptionDb elif 'encryptionDb' in ret_obj['data']: del ret_obj['data']['encryptionDb'] if encryptionCert is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, encryptionCert: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring encryptionCert for this call." .format(isamAppliance.facts["version"], encryptionCert)) else: json_data["encryptionCert"] = encryptionCert elif 'encryptionCert' in ret_obj['data']: del ret_obj['data']['encryptionCert'] if jwksUri is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, jwksUri: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring jwksUri for this call." .format(isamAppliance.facts["version"], jwksUri)) else: json_data["jwksUri"] = jwksUri elif 'jwksUri' in ret_obj['data']: del ret_obj['data']['jwksUri'] if extProperties is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.5.0") < 0: warnings.append( "Appliance at version: {0}, extProperties: {1} is not supported. Needs 9.0.5.0 or higher. Ignoring extProperties for this call." .format(isamAppliance.facts["version"], extProperties)) else: json_data["extProperties"] = extProperties elif 'extProperties' in ret_obj['data']: del ret_obj['data']['extProperties'] sorted_ret_obj = tools.json_sort(ret_obj['data']) sorted_json_data = tools.json_sort(json_data) logger.debug("Sorted Existing Data:{0}".format(sorted_ret_obj)) logger.debug("Sorted Desired Data:{0}".format(sorted_json_data)) if sorted_ret_obj != sorted_json_data: needs_update = True if force is True or needs_update is True: if check_mode is True: return isamAppliance.create_return_object(changed=True, warnings=warnings) else: return isamAppliance.invoke_put("Update a specified mapping rule", "{0}/{1}".format(uri, id), json_data, requires_modules=requires_modules, requires_version=requires_version, warnings=warnings) return isamAppliance.create_return_object(warnings=warnings)
def add(isamAppliance, name, description="", accessPolicyName=None, grantTypes=["AUTHORIZATION_CODE"], tcmBehavior="NEVER_PROMPT", accessTokenLifetime=3600, accessTokenLength=20, enforceSingleUseAuthorizationGrant=False, authorizationCodeLifetime=300, authorizationCodeLength=30, issueRefreshToken=True, refreshTokenLength=40, maxAuthorizationGrantLifetime=604800, enforceSingleAccessTokenPerGrant=False, enableMultipleRefreshTokensForFaultTolerance=False, pinPolicyEnabled=False, pinLength=4, tokenCharSet="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", oidc=None, check_mode=False, force=False): """ Create an API protection definition """ if (isinstance(grantTypes, basestring)): import ast grantTypes = ast.literal_eval(grantTypes) ret_obj = search(isamAppliance, name=name, check_mode=check_mode, force=force) warnings = ret_obj["warnings"] if force is True or ret_obj["data"] == {}: if check_mode is True: return isamAppliance.create_return_object(changed=True, warnings=warnings) else: json_data = { "name": name, "description": description, "grantTypes": grantTypes, "tcmBehavior": tcmBehavior, "accessTokenLifetime": int(accessTokenLifetime), "accessTokenLength": int(accessTokenLength), "enforceSingleUseAuthorizationGrant": enforceSingleUseAuthorizationGrant, "authorizationCodeLifetime": int(authorizationCodeLifetime), "authorizationCodeLength": int(authorizationCodeLength), "issueRefreshToken": issueRefreshToken, "refreshTokenLength": int(refreshTokenLength), "maxAuthorizationGrantLifetime": int(maxAuthorizationGrantLifetime), "enforceSingleAccessTokenPerGrant": enforceSingleAccessTokenPerGrant, "enableMultipleRefreshTokensForFaultTolerance": enableMultipleRefreshTokensForFaultTolerance, "pinPolicyEnabled": pinPolicyEnabled, "pinLength": int(pinLength), "tokenCharSet": tokenCharSet } if accessPolicyName is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, access policy: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring access policy for this call.".format( isamAppliance.facts["version"], oidc)) accessPolicyName = None else: ret_obj = access_policy.search(isamAppliance, accessPolicyName, check_mode=check_mode, force=force) if ret_obj['data'] == {}: warnings = ret_obj["warnings"] warnings.append( "Access Policy {0} is not found. Cannot add definition.".format(accessPolicyName)) return isamAppliance.create_return_object(warnings=warnings) else: json_data["accessPolicyId"] = int(ret_obj['data']) if oidc is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, oidc: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring oidc for this call.".format( isamAppliance.facts["version"], oidc)) else: if 'attributeSources' in oidc: oidc['attributeSources'] = _map_oidc_attributeSources(isamAppliance, oidc['attributeSources'], check_mode, force) json_data["oidc"] = oidc if 'dynamicClients' in json_data['oidc']: if tools.version_compare(isamAppliance.facts["version"], "9.0.5.0") < 0: warnings.append( "Appliance at version: {0}, dynamicClients: {1} is not supported. Needs 9.0.5.0 or higher. Ignoring dynamicClients for this call.".format( isamAppliance.facts["version"], json_data['oidc']['dynamicClients'])) del json_data['oidc']['dynamicClients'] if 'issueSecret' in json_data['oidc']: if tools.version_compare(isamAppliance.facts["version"], "9.0.5.0") < 0: warnings.append( "Appliance at version: {0}, issueSecret: {1} is not supported. Needs 9.0.5.0 or higher. Ignoring issueSecret for this call.".format( isamAppliance.facts["version"], json_data['oidc']['issueSecret'])) del json_data['oidc']['issueSecret'] return isamAppliance.invoke_post( "Create an API protection definition", uri, json_data, requires_modules=requires_modules, requires_version=requires_version, warnings=warnings) return isamAppliance.create_return_object(warnings=warnings)
def update(isamAppliance, name, description="", accessPolicyName=None, grantTypes=["AUTHORIZATION_CODE"], tcmBehavior="NEVER_PROMPT", accessTokenLifetime=3600, accessTokenLength=20, enforceSingleUseAuthorizationGrant=False, authorizationCodeLifetime=300, authorizationCodeLength=30, issueRefreshToken=True, refreshTokenLength=40, maxAuthorizationGrantLifetime=604800, enforceSingleAccessTokenPerGrant=False, enableMultipleRefreshTokensForFaultTolerance=False, pinPolicyEnabled=False, pinLength=4, tokenCharSet="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", oidc=None, check_mode=False, force=False): """ Update a specified API protection definition """ ret_obj = get(isamAppliance, name) warnings = ret_obj["warnings"] if ret_obj["data"] == {}: warnings.append("Definiton {0} not found, skipping update.".format(name)) return isamAppliance.create_return_object(warnings=warnings) else: defn_id = ret_obj["data"]["id"] needs_update = False json_data = { "name": name, "description": description, "grantTypes": grantTypes, "tcmBehavior": tcmBehavior, "accessTokenLifetime": int(accessTokenLifetime), "accessTokenLength": int(accessTokenLength), "enforceSingleUseAuthorizationGrant": enforceSingleUseAuthorizationGrant, "authorizationCodeLifetime": int(authorizationCodeLifetime), "authorizationCodeLength": int(authorizationCodeLength), "issueRefreshToken": issueRefreshToken, "refreshTokenLength": int(refreshTokenLength), "maxAuthorizationGrantLifetime": int(maxAuthorizationGrantLifetime), "enforceSingleAccessTokenPerGrant": enforceSingleAccessTokenPerGrant, "enableMultipleRefreshTokensForFaultTolerance": enableMultipleRefreshTokensForFaultTolerance, "pinPolicyEnabled": pinPolicyEnabled, "pinLength": int(pinLength), "tokenCharSet": tokenCharSet } if accessPolicyName is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, access policy: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring access policy for this call.".format( isamAppliance.facts["version"], oidc)) accessPolicyName = None else: ret_obj = access_policy.search(isamAppliance, accessPolicyName, check_mode=check_mode, force=force) if ret_obj['data'] == {}: warnings = ret_obj["warnings"] warnings.append( "Access Policy {0} is not found. Cannot update definition.".format(accessPolicyName)) return isamAppliance.create_return_object(warnings=warnings) else: json_data["accessPolicyId"] = int(ret_obj['data']) if oidc is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, oidc: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring oidc for this call.".format( isamAppliance.facts["version"], oidc)) oidc = None else: if 'attributeSources' in oidc: oidc['attributeSources'] = _map_oidc_attributeSources(isamAppliance, oidc['attributeSources'], check_mode, force) json_data["oidc"] = oidc if force is not True: if 'datecreated' in ret_obj['data']: del ret_obj['data']['datecreated'] if 'id' in ret_obj['data']: del ret_obj['data']['id'] if 'lastmodified' in ret_obj['data']: del ret_obj['data']['lastmodified'] if 'mappingRules' in ret_obj['data']: del ret_obj['data']['mappingRules'] # Inspecting oidcConfig and remove missing or None attributes in returned object if oidc is not None and 'oidc' in ret_obj['data']: if 'enabled' in ret_obj['data']['oidc'] and ret_obj['data']['oidc']['enabled'] is None: del ret_obj['data']['oidc']['enabled'] if 'iss' in ret_obj['data']['oidc'] and ret_obj['data']['oidc']['iss'] is None: del ret_obj['data']['oidc']['iss'] if 'poc' in ret_obj['data']['oidc'] and ret_obj['data']['oidc']['poc'] is None: del ret_obj['data']['oidc']['poc'] if 'lifetime' in ret_obj['data']['oidc'] and ret_obj['data']['oidc']['lifetime'] is None: del ret_obj['data']['oidc']['lifetime'] if 'alg' in ret_obj['data']['oidc'] and ret_obj['data']['oidc']['alg'] is None: del ret_obj['data']['oidc']['alg'] if 'db' in ret_obj['data']['oidc'] and ret_obj['data']['oidc']['db'] is None: del ret_obj['data']['oidc']['db'] if 'cert' in ret_obj['data']['oidc'] and ret_obj['data']['oidc']['cert'] is None: del ret_obj['data']['oidc']['cert'] if 'attributeSources' in ret_obj['data']['oidc'] and ret_obj['data']['oidc']['attributeSources'] is None: del ret_obj['data']['oidc']['attributeSources'] # Inspecting oidcEncConfig and remove missing or None attributes in returned object if 'enc' in ret_obj['data']['oidc'] and ret_obj['data']['oidc']['enc'] is not None: if 'enabled' in ret_obj['data']['oidc']['enc'] and ret_obj['data']['oidc']['enc']['enabled'] is None: del ret_obj['data']['oidc']['enc']['enabled'] if 'alg' in ret_obj['data']['oidc']['enc'] and ret_obj['data']['oidc']['enc']['alg'] is None: del ret_obj['data']['oidc']['enc']['alg'] if 'enc' in ret_obj['data']['oidc']['enc'] and ret_obj['data']['oidc']['enc']['enc'] is None: del ret_obj['data']['oidc']['enc']['enc'] # For dynamicClients & issueSecret parameters # # If the values for dynamicClients or issueSecret are missing, then they are # considered to be of the value "false" by the appliance, this allows for old # configuration to be forward compatible, without the function of the # definition being changed by the same payload. if 'dynamicClients' in json_data['oidc']: if tools.version_compare(isamAppliance.facts["version"], "9.0.5.0") < 0: warnings.append( "Appliance at version: {0}, dynamicClients: {1} is not supported. Needs 9.0.5.0 or higher. Ignoring dynamicClients for this call.".format( isamAppliance.facts["version"], json_data['oidc']['dynamicClients'])) del json_data['oidc']['dynamicClients'] else: if tools.version_compare(isamAppliance.facts["version"], "9.0.5.0") >= 0: if 'dynamicClients' in ret_obj['data']['oidc'] and ret_obj['data']['oidc'][ 'dynamicClients'] is False: del ret_obj['data']['oidc']['dynamicClients'] if 'issueSecret' in json_data['oidc']: if tools.version_compare(isamAppliance.facts["version"], "9.0.5.0") < 0: warnings.append( "Appliance at version: {0}, issueSecret: {1} is not supported. Needs 9.0.5.0 or higher. Ignoring issueSecret for this call.".format( isamAppliance.facts["version"], json_data['oidc']['issueSecret'])) del json_data['oidc']['issueSecret'] else: if tools.version_compare(isamAppliance.facts["version"], "9.0.5.0") >= 0: if 'issueSecret' in ret_obj['data']['oidc'] and ret_obj['data']['oidc']['issueSecret'] is False: del ret_obj['data']['oidc']['issueSecret'] sorted_ret_obj = tools.json_sort(ret_obj['data']) sorted_json_data = tools.json_sort(json_data) logger.debug("Sorted Existing Data:{0}".format(sorted_ret_obj)) logger.debug("Sorted Desired Data:{0}".format(sorted_json_data)) if sorted_ret_obj != sorted_json_data: needs_update = True if force is True or needs_update is True: if check_mode is True: return isamAppliance.create_return_object(changed=True, warnings=warnings) else: return isamAppliance.invoke_put( "Update a specified API protection definition", "{0}/{1}".format(uri, defn_id), json_data, requires_modules=requires_modules, requires_version=requires_version, warnings=warnings) return isamAppliance.create_return_object(warnings=warnings)
def update( isamAppliance, name, description="", grantTypes=["AUTHORIZATION_CODE"], tcmBehavior="NEVER_PROMPT", accessTokenLifetime=3600, accessTokenLength=20, enforceSingleUseAuthorizationGrant=False, authorizationCodeLifetime=300, authorizationCodeLength=30, issueRefreshToken=True, refreshTokenLength=40, maxAuthorizationGrantLifetime=604800, enforceSingleAccessTokenPerGrant=False, enableMultipleRefreshTokensForFaultTolerance=False, pinPolicyEnabled=False, pinLength=4, tokenCharSet="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", oidc=None, check_mode=False, force=False): """ Update a specified API protection definition """ ret_obj = get(isamAppliance, name) warnings = ret_obj["warnings"] if ret_obj["data"] == {}: warnings.append( "Definiton {0} not found, skipping update.".format(name)) return isamAppliance.create_return_object(warnings=warnings) else: defn_id = ret_obj["data"]["id"] needs_update = False json_data = { "name": name, "description": description, "grantTypes": grantTypes, "tcmBehavior": tcmBehavior, "accessTokenLifetime": accessTokenLifetime, "accessTokenLength": accessTokenLength, "enforceSingleUseAuthorizationGrant": enforceSingleUseAuthorizationGrant, "authorizationCodeLifetime": authorizationCodeLifetime, "authorizationCodeLength": authorizationCodeLength, "issueRefreshToken": issueRefreshToken, "refreshTokenLength": refreshTokenLength, "maxAuthorizationGrantLifetime": maxAuthorizationGrantLifetime, "enforceSingleAccessTokenPerGrant": enforceSingleAccessTokenPerGrant, "enableMultipleRefreshTokensForFaultTolerance": enableMultipleRefreshTokensForFaultTolerance, "pinPolicyEnabled": pinPolicyEnabled, "pinLength": pinLength, "tokenCharSet": tokenCharSet } if oidc is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, oidc: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring oidc for this call." .format(isamAppliance.facts["version"], oidc)) else: json_data["oidc"] = oidc if force is not True: if 'datecreated' in ret_obj['data']: del ret_obj['data']['datecreated'] if 'id' in ret_obj['data']: del ret_obj['data']['id'] if 'lastmodified' in ret_obj['data']: del ret_obj['data']['lastmodified'] if 'mappingRules' in ret_obj['data']: del ret_obj['data']['mappingRules'] import ibmsecurity.utilities.tools if ibmsecurity.utilities.tools.json_sort( ret_obj['data']) != ibmsecurity.utilities.tools.json_sort( json_data): needs_update = True if force is True or needs_update is True: if check_mode is True: return isamAppliance.create_return_object(changed=True, warnings=warnings) else: return isamAppliance.invoke_put( "Update a specified API protection definition", "{0}/{1}".format(uri, defn_id), json_data, requires_modules=requires_modules, requires_version=requires_version, warnings=warnings) return isamAppliance.create_return_object(warnings=warnings)
def set(isamAppliance, reverseproxy_id, junction_point, server_hostname, server_port, junction_type="tcp", virtual_hostname=None, server_dn=None, query_contents=None, stateful_junction=None, case_sensitive_url=None, windows_style_url=None, https_port=None, http_port=None, proxy_hostname=None, proxy_port=None, sms_environment=None, vhost_label=None, junction_hard_limit=None, junction_soft_limit=None, basic_auth_mode=None, tfim_sso=None, remote_http_header=None, preserve_cookie=None, cookie_include_path=None, transparent_path_junction=None, mutual_auth=None, insert_session_cookies=None, request_encoding=None, enable_basic_auth=None, key_label=None, gso_resource_group=None, junction_cookie_javascript_block=None, client_ip_http=None, version_two_cookies=None, ltpa_keyfile=None, authz_rules=None, fsso_config_file=None, username=None, password=None, server_uuid=None, local_ip=None, ltpa_keyfile_password=None, delegation_support=None, scripting_support=None, insert_ltpa_cookies=None, check_mode=False, force=False, http2_junction=None, http2_proxy=None, sni_name=None): """ Setting a standard or virtual junction - compares with existing junction and replaces if changes are detected TODO: Compare all the parameters in the function - LTPA, BA are some that are not being compared """ warnings = [] add_required = False if force is False: # Check if record exists logger.debug("Check if the junction exists.") if _check(isamAppliance, reverseproxy_id, junction_point) is True: logger.debug("Junction exists. Compare junction details.") ret_obj = get(isamAppliance, reverseproxy_id=reverseproxy_id, junctionname=junction_point) server_found = False logger.debug( "See if the backend junction server matches any on the junction. Look for just one match." ) srvs = ret_obj['data']['servers'] srvs_len = len(srvs) for srv in srvs: if srv['server_hostname'] == server_hostname and str( srv['server_port']) == str(server_port): logger.debug("Matched a server - {0}.".format(srv)) server_found = True server_json = { 'server_hostname': server_hostname, 'server_port': str(server_port) } if case_sensitive_url is None: server_json['case_sensitive_url'] = 'no' else: server_json['case_sensitive_url'] = case_sensitive_url if http_port is None: server_json['http_port'] = str(server_port) else: server_json['http_port'] = str(http_port) if local_ip is None: server_json['local_ip'] = '' else: server_json['local_ip'] = local_ip if query_contents is None: server_json[ 'query_content_url'] = '/cgi-bin/query_contents' else: server_json['query_content_url'] = query_contents if server_dn is None: server_json['server_dn'] = '' else: server_json['server_dn'] = server_dn if server_uuid is not None: server_json['server_uuid'] = server_uuid else: # Server UUID gets generated if not specified if 'server_uuid' in srv: del srv['server_uuid'] if virtual_hostname is None: if 'virtual_junction_hostname' in srv: del srv['virtual_junction_hostname'] else: server_json[ 'virtual_junction_hostname'] = virtual_hostname if windows_style_url is None: server_json['windows_style_url'] = 'no' else: server_json['windows_style_url'] = windows_style_url # Delete dynamic data shown when we get junctions details if 'current_requests' in srv: del srv['current_requests'] if 'total_requests' in srv: del srv['total_requests'] if 'operation_state' in srv: del srv['operation_state'] if 'server_state' in srv: del srv['server_state'] # Not sure what this attribute is supposed to contain? if 'query_contents' in srv: del srv['query_contents'] if tools.json_sort(server_json) != tools.json_sort(srv): logger.debug( "Servers are found to be different. See following JSON for difference." ) logger.debug("New Server JSON: {0}".format( tools.json_sort(server_json))) logger.debug("Old Server JSON: {0}".format( tools.json_sort(srv))) add_required = True break if server_found is False: add_required = True elif add_required is False: exist_jct = ret_obj['data'] jct_json = { 'junction_point': junction_point, 'junction_type': junction_type.upper() } if authz_rules is None: jct_json['authz_rules'] = 'no' else: jct_json['authz_rules'] = authz_rules if basic_auth_mode is None: jct_json['basic_auth_mode'] = 'filter' else: jct_json['basic_auth_mode'] = basic_auth_mode if client_ip_http is None or client_ip_http.lower() == 'no': jct_json['client_ip_http'] = 'do not insert' elif client_ip_http.lower() == 'yes': jct_json['client_ip_http'] = 'insert' else: jct_json['client_ip_http'] = client_ip_http if cookie_include_path is None: jct_json['cookie_include_path'] = 'no' else: jct_json['cookie_include_path'] = cookie_include_path if delegation_support is None: jct_json['delegation_support'] = 'no' else: jct_json['delegation_support'] = delegation_support if fsso_config_file is None: jct_json['fsso_config_file'] = 'disabled' else: jct_json['fsso_config_file'] = fsso_config_file if insert_session_cookies is None: jct_json['insert_session_cookies'] = 'no' else: jct_json['insert_session_cookies'] = insert_session_cookies if junction_hard_limit is None: jct_json['junction_hard_limit'] = '0 - using global value' else: jct_json['junction_hard_limit'] = str(junction_hard_limit) if junction_soft_limit is None: jct_json['junction_soft_limit'] = '0 - using global value' else: jct_json['junction_soft_limit'] = str(junction_soft_limit) # We could have a comma delimited set of values - so split them into array if junction_cookie_javascript_block is not None and junction_cookie_javascript_block != '': jct_json[ 'junction_cookie_javascript_block'] = junction_cookie_javascript_block.split( ',') # Here the list is delimited by space if 'junction_cookie_javascript_block' in exist_jct and exist_jct[ 'junction_cookie_javascript_block'] is not None: exist_jct[ 'junction_cookie_javascript_block'] = exist_jct[ 'junction_cookie_javascript_block'].split(' ') if mutual_auth is None: jct_json['mutual_auth'] = 'no' else: jct_json['mutual_auth'] = mutual_auth if preserve_cookie is None: jct_json['preserve_cookie'] = 'no' else: jct_json['preserve_cookie'] = preserve_cookie if remote_http_header is None: jct_json['remote_http_header'] = 'do not insert' elif isinstance( remote_http_header, basestring) and remote_http_header.lower() == 'all': jct_json['remote_http_header'] = [ 'iv_creds', 'iv_groups', 'iv_user' ] else: jct_json['remote_http_header'] = remote_http_header # To allow for multiple header values to be sorted during compare convert retrieved data into array if exist_jct['remote_http_header'].startswith('insert - '): exist_jct['remote_http_header'] = ( exist_jct['remote_http_header'][9:]).split(' ') if request_encoding is None: jct_json['request_encoding'] = 'UTF-8, URI Encoded' else: jct_json['request_encoding'] = request_encoding if scripting_support is None: jct_json['scripting_support'] = 'no' else: jct_json['scripting_support'] = scripting_support if stateful_junction is None: jct_json['stateful_junction'] = 'no' else: jct_json['stateful_junction'] = stateful_junction if tfim_sso is None: jct_json['tfim_sso'] = 'no' else: jct_json['tfim_sso'] = tfim_sso if transparent_path_junction is None: jct_json['transparent_path_junction'] = 'no' else: jct_json[ 'transparent_path_junction'] = transparent_path_junction if http2_junction is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, http2_junction: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring http2_junction for this call." .format(isamAppliance.facts["version"], http2_junction)) http2_junction = None else: jct_json['http2_junction'] = http2_junction if http2_proxy is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, http2_proxy: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring http2_proxy for this call." .format(isamAppliance.facts["version"], http2_proxy)) http2_proxy = None else: jct_json['http2_proxy'] = http2_proxy if sni_name is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, sni_name: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring sni_name for this call." .format(isamAppliance.facts["version"], sni_name)) sni_name = None else: jct_json['sni_name'] = sni_name # TODO: Not sure of how to match following attributes! Need to revisit. # TODO: Not all function parameters are being checked - need to add! del exist_jct['boolean_rule_header'] del exist_jct['forms_based_sso'] del exist_jct['http_header_ident'] del exist_jct['session_cookie_backend_portal'] # We are already comparing server details - so remove this from this compare del exist_jct['servers'] # Delete dynamic data shown when we get junctions details del exist_jct['active_worker_threads'] if tools.json_sort(jct_json) != tools.json_sort(exist_jct): logger.debug( "Junctions are found to be different. See following JSON for difference." ) logger.debug("New Junction JSON: {0}".format( tools.json_sort(jct_json))) logger.debug("Old Junction JSON: {0}".format( tools.json_sort(exist_jct))) add_required = True if add_required is True and srvs_len > 1: warnings.append( "Junction will replaced. Existing multiple servers #{0} will be overwritten. Please re-add as needed." .format(srvs_len)) else: add_required = True if force is True or add_required is True: # Junction force add will replace the junction, no need for delete (force set to True as a result) return add( isamAppliance=isamAppliance, reverseproxy_id=reverseproxy_id, junction_point=junction_point, server_hostname=server_hostname, server_port=server_port, junction_type=junction_type, virtual_hostname=virtual_hostname, server_dn=server_dn, query_contents=query_contents, stateful_junction=stateful_junction, case_sensitive_url=case_sensitive_url, windows_style_url=windows_style_url, https_port=https_port, http_port=http_port, proxy_hostname=proxy_hostname, proxy_port=proxy_port, sms_environment=sms_environment, vhost_label=vhost_label, junction_hard_limit=junction_hard_limit, junction_soft_limit=junction_soft_limit, basic_auth_mode=basic_auth_mode, tfim_sso=tfim_sso, remote_http_header=remote_http_header, preserve_cookie=preserve_cookie, cookie_include_path=cookie_include_path, transparent_path_junction=transparent_path_junction, mutual_auth=mutual_auth, insert_session_cookies=insert_session_cookies, request_encoding=request_encoding, enable_basic_auth=enable_basic_auth, key_label=key_label, gso_resource_group=gso_resource_group, junction_cookie_javascript_block=junction_cookie_javascript_block, client_ip_http=client_ip_http, version_two_cookies=version_two_cookies, ltpa_keyfile=ltpa_keyfile, authz_rules=authz_rules, fsso_config_file=fsso_config_file, username=username, password=password, server_uuid=server_uuid, local_ip=local_ip, ltpa_keyfile_password=ltpa_keyfile_password, delegation_support=delegation_support, scripting_support=scripting_support, insert_ltpa_cookies=insert_ltpa_cookies, check_mode=check_mode, force=True, http2_junction=http2_junction, http2_proxy=http2_proxy, sni_name=sni_name, warnings=warnings) return isamAppliance.create_return_object()
def add(isamAppliance, reverseproxy_id, junction_point, server_hostname, server_port, junction_type="tcp", virtual_hostname=None, server_dn=None, query_contents=None, stateful_junction=None, case_sensitive_url=None, windows_style_url=None, https_port=None, http_port=None, proxy_hostname=None, proxy_port=None, sms_environment=None, vhost_label=None, junction_hard_limit=None, junction_soft_limit=None, basic_auth_mode=None, tfim_sso=None, remote_http_header=None, preserve_cookie=None, cookie_include_path=None, transparent_path_junction=None, mutual_auth=None, insert_session_cookies=None, request_encoding=None, enable_basic_auth=None, key_label=None, gso_resource_group=None, junction_cookie_javascript_block=None, client_ip_http=None, version_two_cookies=None, ltpa_keyfile=None, authz_rules=None, fsso_config_file=None, username=None, password=None, server_uuid=None, local_ip=None, ltpa_keyfile_password=None, delegation_support=None, scripting_support=None, insert_ltpa_cookies=None, check_mode=False, force=False, http2_junction=None, http2_proxy=None, sni_name=None, warnings=[]): """ Creating a standard or virtual junction :param isamAppliance: :param reverseproxy_id: :param junction_point: :param server_hostname: :param server_port: :param junction_type: :param virtual_hostname: :param server_dn: :param query_contents: :param stateful_junction: :param case_sensitive_url: :param windows_style_url: :param https_port: :param http_port: :param proxy_hostname: :param proxy_port: :param sms_environment: :param vhost_label: :param junction_hard_limit: :param junction_soft_limit: :param basic_auth_mode: :param tfim_sso: :param remote_http_header: :param preserve_cookie: :param cookie_include_path: :param transparent_path_junction: :param mutual_auth: :param insert_session_cookies: :param request_encoding: :param enable_basic_auth: :param key_label: :param gso_resource_group: :param junction_cookie_javascript_block: :param client_ip_http: :param version_two_cookies: :param ltpa_keyfile: :param authz_rules: :param fsso_config_file: :param username: :param password: :param server_uuid: :param local_ip: :param ltpa_keyfile_password: :param delegation_support: :param scripting_support: :param insert_ltpa_cookies: :param check_mode: :param force: :param http2_junction: :param http2_proxy: :param sni_name: :return: """ if force is True or _check(isamAppliance, reverseproxy_id, junction_point) is False: if check_mode is True: return isamAppliance.create_return_object(changed=True, warnings=warnings) else: # Create a simple json with just the main junction attributes jct_json = { "junction_point": junction_point, "junction_type": junction_type, "server_hostname": server_hostname, "server_port": server_port, "force": force } # Add attributes that have been supplied... otherwise skip them. if junction_hard_limit is not None: jct_json["junction_hard_limit"] = junction_hard_limit if junction_soft_limit is not None: jct_json["junction_soft_limit"] = junction_soft_limit if basic_auth_mode is not None: jct_json["basic_auth_mode"] = basic_auth_mode if tfim_sso is not None: jct_json["tfim_sso"] = tfim_sso if remote_http_header is not None: jct_json["remote_http_header"] = remote_http_header if stateful_junction is not None: jct_json["stateful_junction"] = stateful_junction if preserve_cookie is not None: jct_json["preserve_cookie"] = preserve_cookie if cookie_include_path is not None: jct_json["cookie_include_path"] = cookie_include_path if transparent_path_junction is not None: jct_json[ "transparent_path_junction"] = transparent_path_junction if mutual_auth is not None: jct_json["mutual_auth"] = mutual_auth if insert_ltpa_cookies is not None: jct_json["insert_ltpa_cookies"] = insert_ltpa_cookies if insert_session_cookies is not None: jct_json["insert_session_cookies"] = insert_session_cookies if request_encoding is not None: jct_json["request_encoding"] = request_encoding if enable_basic_auth is not None: jct_json["enable_basic_auth"] = enable_basic_auth if key_label is not None: jct_json["key_label"] = key_label if gso_resource_group is not None: jct_json["gso_resource_group"] = gso_resource_group if junction_cookie_javascript_block is not None and junction_cookie_javascript_block != '': jct_json[ "junction_cookie_javascript_block"] = junction_cookie_javascript_block if client_ip_http is not None: jct_json["client_ip_http"] = client_ip_http if version_two_cookies is not None: jct_json["version_two_cookies"] = version_two_cookies if ltpa_keyfile is not None: jct_json["ltpa_keyfile"] = ltpa_keyfile if authz_rules is not None: jct_json["authz_rules"] = authz_rules if fsso_config_file is not None: jct_json["fsso_config_file"] = fsso_config_file if username is not None: jct_json["username"] = username if password is not None: jct_json["password"] = password if server_uuid is not None: jct_json["server_uuid"] = server_uuid if virtual_hostname is not None: jct_json["virtual_hostname"] = virtual_hostname if server_dn is not None: jct_json["server_dn"] = server_dn if local_ip is not None: jct_json["local_ip"] = local_ip if query_contents is not None: jct_json["query_contents"] = query_contents if case_sensitive_url is not None: jct_json["case_sensitive_url"] = case_sensitive_url if windows_style_url is not None: jct_json["windows_style_url"] = windows_style_url if ltpa_keyfile_password is not None: jct_json["ltpa_keyfile_password"] = ltpa_keyfile_password if https_port is not None: jct_json["https_port"] = https_port if http_port is not None: jct_json["http_port"] = http_port if proxy_hostname is not None: jct_json["proxy_hostname"] = proxy_hostname if proxy_port is not None: jct_json["proxy_port"] = proxy_port if sms_environment is not None: jct_json["sms_environment"] = sms_environment if vhost_label is not None: jct_json["vhost_label"] = vhost_label if delegation_support is not None: jct_json["delegation_support"] = delegation_support if scripting_support is not None: jct_json["scripting_support"] = scripting_support if http2_junction is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, http2_junction: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring http2_junction for this call." .format(isamAppliance.facts["version"], http2_junction)) else: jct_json["http2_junction"] = http2_junction if http2_proxy is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, http2_proxy: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring http2_proxy for this call." .format(isamAppliance.facts["version"], http2_proxy)) else: jct_json['http2_proxy'] = http2_proxy if sni_name is not None: if tools.version_compare(isamAppliance.facts["version"], "9.0.4.0") < 0: warnings.append( "Appliance at version: {0}, sni_name: {1} is not supported. Needs 9.0.4.0 or higher. Ignoring sni_name for this call." .format(isamAppliance.facts["version"], sni_name)) else: jct_json['sni_name'] = sni_name return isamAppliance.invoke_post( "Creating a standard or virtual junction", "{0}/{1}/junctions".format(uri, reverseproxy_id), jct_json, requires_modules=requires_modules, requires_version=requires_version, warnings=warnings) return isamAppliance.create_return_object(warnings=warnings)
def _check_file(isdsAppliance, file): """ Parse the file name to see if it is already uploaded - use version and release date from pkg file name Also check to see if the firmware level is already uploaded Note: Lot depends on the name of the file. :param isdsAppliance: :param file: :return: """ import os.path # If there is an exception then simply return False # Sample filename - 8.0.1.9-ISS-ISDS_20181207-0045.pkg logger.debug("Checking provided file is ready to upload: {0}".format(file)) try: # Extract file name from path f = os.path.basename(file) fn = os.path.splitext(f) logger.debug("File name without path: {0}".format(fn[0])) # Split of file by '-' hyphen and '_' under score import re fp = re.split('-|_', fn[0]) firm_file_version = fp[0] firm_file_product = fp[2] firm_file_date = fp[3] logger.debug("PKG file details: {0}: version: {1} date: {2}".format( firm_file_product, firm_file_version, firm_file_date)) # Check if firmware level already contains the update to be uploaded or greater, check Active partition # firmware "name" of format - 8.0.1.9-ISS-ISDS_20181207-0045 import ibmsecurity.isds.firmware ret_obj = ibmsecurity.isds.firmware.get(isdsAppliance) for firm in ret_obj['data']: # Split of file by '-' hyphen and '_' under score fp = re.split('-|_', firm['name']) firm_appl_version = fp[0] firm_appl_product = fp[2] firm_appl_date = fp[3] logger.debug( "Partition details ({0}): {1}: version: {2} date: {3}".format( firm['partition'], firm_appl_product, firm_appl_version, firm_appl_date)) if firm['active'] is True: from ibmsecurity.utilities import tools if tools.version_compare(firm_appl_version, firm_file_version) >= 0: logger.info( "Active partition has version {0} which is greater or equals than install package at version {1}." .format(firm_appl_version, firm_file_version)) return True else: logger.info( "Active partition has version {0} which is smaller than install package at version {1}." .format(firm_appl_version, firm_file_version)) # Check if update uploaded - will not show up if installed though ret_obj = get(isdsAppliance) for upd in ret_obj['data']: rd = upd['release_date'] rd = rd.replace( '-', '') # turn release date into 20161102 format from 2016-11-02 if upd['version'] == fp[0] and rd == fp[ 3]: # Version of format 8.0.1.9 return True except Exception as e: logger.debug("Exception occured: {0}".format(e)) pass return False
def export(isamAppliance, reverseproxy_id, junctionname, export_dir, junction_prefix, check_mode=False, force=False): """ Retrieving the parameters for a single standard or virtual junction :param isamAppliance: :param reverseproxy_id: :param junctionname: :param export_dir: :param junction_prefix: :param check_mode: :param force: :return: """ ignoreAttrs = {'current_requests', 'operation_state', 'server_state'} serverPrefix=junction_prefix file_path = export_dir +"/"+ reverseproxy_id file_path = file_path.strip() directory = os.path.dirname(file_path) if not os.path.exists(directory): os.makedirs(directory) logger.debug("Directory doesn't exist, creating: " + file_path) ret_obj = isamAppliance.invoke_get("Retrieving the parameters for a single standard or virtual junction", "{0}/{1}/junctions?junctions_id={2}".format(uri, reverseproxy_id, junctionname), requires_modules=requires_modules, requires_version=requires_version) # servers are provided as a single string, here we parse it out into a list + dict servers = [] if tools.version_compare(isamAppliance.facts["version"], "9.0.1.0") > 0: srv_separator = '#' else: srv_separator = '&' logger.debug("Server separator being used: {0}".format(srv_separator)) srvs = ret_obj['data']['servers'].split(srv_separator) logger.debug("Servers in raw string: {0}".format(ret_obj['data']['servers'])) logger.debug("Number of servers in junction: {0}".format(len(srvs))) for srv in srvs: logger.debug("Parsing Server: {0}".format(srv)) server = {} for s in srv.split(';'): if s != '': kv = s.split('!') server[kv[0]] = kv[1] servers.append(server) ret_obj['data']['servers'] = servers #normalise Junction json junction_data = _normaliseJunction(ret_obj['data']) f = open(file_path + "/" + junctionname +".0", "w") servers = junction_data['servers'] #servers will be processed separately del junction_data['servers'] for mykey in junction_data: junction_data[mykey]=str(junction_data[mykey]).replace("unknown","") junction_data[mykey]=str(junction_data[mykey]).replace("disabled","") f.write(junction_prefix + mykey +": " + str(junction_data[mykey]) +"\n") f.close() #process additional servers, new file i=0 while i < len(servers): if i == 0: f = open(file_path + "/" + junctionname + "." + str(i), "a") #f.write(serverPrefix + "reverseproxy_id: " + reverseproxy_id +"\n") # open a new file for additional junctioned servers if i > 0: serverPrefix="add_junction_servers_" #open file for add additional servers f = open(file_path + "/" + junctionname + "." + str(i), "w") f.write("add_junction_servers: \n - server: " + servers[i]["server_hostname"]) f.write( "\n port: " + servers[i]["server_port"] +"\n") del servers[i]['server_port'] del servers[i]['server_hostname'] f.write(serverPrefix + "junction_point: " + junctionname +"\n") f.write(serverPrefix + "junction_type: " + str(junction_data["junction_type"]).lower() +"\n") f.write(serverPrefix + "reverseproxy_id: " + reverseproxy_id +"\n") for skey in servers[i]: f.write(serverPrefix + skey + ": " + servers[i][skey]+"\n") i += 1 f.close() return ret_obj