def login_as_root(self, domain=None, payload=None): """ This method allows to login into the management server with root permissions. In order to use this method the application should be run directly on the management server and to have super-user privileges. :param domain: [optional] name/uid/IP address of the domain you want to log into in an MDS environment :param payload: [optional] dict of additional parameters for the login command :return: APIResponse object with the relevant details from the login command. """ python_absolute_path = os.path.expandvars( "$MDS_FWDIR/Python/bin/python") api_get_port_absolute_path = os.path.expandvars( "$MDS_FWDIR/scripts/api_get_port.py") mgmt_cli_absolute_path = os.path.expandvars("$CPDIR/bin/mgmt_cli") # try to get the management server's port by running a script if not self.is_port_default(): port = self.get_port() else: try: port = compatible_loads( subprocess.check_output([ python_absolute_path, api_get_port_absolute_path, "-f", "json" ]))["external_port"] # if can't, default back to what the user wrote or the default (443) except (ValueError, subprocess.CalledProcessError): port = self.get_port() try: # This simple dict->cli format works only because the login command doesn't require # any complex parameters like objects and lists new_payload = [] if payload: for key in payload.keys(): new_payload += [key, payload[key]] if domain: new_payload += ["domain", domain] login_response = compatible_loads( subprocess.check_output([ mgmt_cli_absolute_path, "login", "-r", "true", "-f", "json", "--port", str(port) ] + new_payload)) self.sid = login_response["sid"] self.server = "127.0.0.1" self.domain = domain if self.api_version is None: self.api_version = login_response["api-server-version"] return APIResponse(login_response, success=True) except ValueError as err: raise APIClientException( "Could not load JSON from login as root command, perhaps no root privileges?\n" + str(type(err)) + " - " + str(err)) except (WindowsError, subprocess.CalledProcessError) as err: raise APIClientException("Could not login as root:\n" + str(type(err)) + " - " + str(err))
def __init__(self, json_response, success, status_code=None, err_message=""): self.status_code = status_code self.data = None if err_message: self.success = False self.error_message = err_message self.res_obj = {} else: self.success = success try: if isinstance(json_response, dict): data_dict = json_response else: data_dict = compatible_loads(json_response) except ValueError: self.data = {"errors": [{"message": str(json_response)}]} self.error_message = "APIResponse received a response which is not a valid JSON." self.res_obj = {"status_code": self.status_code, "data": self.data} else: self.data = data_dict self.res_obj = {"status_code": self.status_code, "data": self.data} if not self.success: try: self.error_message = extract_error_and_warning_messages(self.data) except KeyError: raise APIException("Unexpected error format.", json_response)
def to_obj(self): if len(self) == 1 and self[0][0] is Pairs.NO_KEY: val = self[0][1] if val in {'null', 'true', 'false'} or val[0] in '"{[': return compatible_loads(val) elif re.match(r'\d+$', val): return int(val, 10) return val pairs = Pairs() all_nums = True any_nums = False for prefix in self.prefixes(): vals = self.get(prefix) if re.match(r'\d+$', prefix): prefix = int(prefix, 10) any_nums = True else: all_nums = False pairs.add(prefix, vals.to_obj()) if not all_nums: if any_nums: raise ValueError('mixed (sub)keys: ["%s"]' % '" "'.join( str(i[0]) for i in pairs)) return collections.OrderedDict(pairs) return [i[1] for i in sorted(pairs)]
def api_call(self, command, payload=None, sid=None, wait_for_task=True, timeout=-1): """ performs a web-service API request to the management server :param command: the command is placed in the URL field :param payload: a JSON object (or a string representing a JSON object) with the command arguments :param sid: [optional]. The Check Point session-id. when omitted use self.sid. :param wait_for_task: determines the behavior when the API server responds with a "task-id". by default, the function will periodically check the status of the task and will not return until the task is completed. when wait_for_task=False, it is up to the user to call the "show-task" API and check the status of the command. :param timeout: Optional positive timeout (in seconds) before stop waiting for the task even if not completed. :return: APIResponse object :side-effects: updates the class's uid and server variables """ timeout_start = time.time() self.check_fingerprint() if payload is None: payload = {} # Convert the json payload to a string if needed if isinstance(payload, str): _data = payload elif isinstance(payload, dict): _data = json.dumps(payload, sort_keys=False) else: raise TypeError('Invalid payload type - must be dict/string') # update class members if needed. if sid is None: sid = self.sid # Set headers _headers = { "User-Agent": "python-api-wrapper", "Accept": "*/*", "Content-Type": "application/json", "Content-Length": len(_data) } # In all API calls (except for 'login') a header containing the Check Point session-id is required. if sid is not None: _headers["X-chkp-sid"] = sid # Create ssl context with no ssl verification, we do it by ourselves context = ssl.create_default_context() context.check_hostname = False context.verify_mode = ssl.CERT_NONE # create https connection if self.proxy_host and self.proxy_port: conn = HTTPSConnection(self.proxy_host, self.proxy_port, context=context) conn.set_tunnel(self.server, self.get_port()) else: conn = HTTPSConnection(self.server, self.get_port(), context=context) # Set fingerprint conn.fingerprint = self.fingerprint # Set debug level conn.set_debuglevel(self.http_debug_level) url = "/" + self.context + "/" + ( ("v" + str(self.api_version) + "/") if self.api_version else "") + command response = None try: # Send the data to the server conn.request("POST", url, _data, _headers) # Get the reply from the server response = conn.getresponse() res = APIResponse.from_http_response(response) except ValueError as err: if err.args[0] == "Fingerprint value mismatch": err_message = "Error: Fingerprint value mismatch:\n" + " Expecting : {}\n".format( err.args[1] ) + " Got: {}\n".format( err.args[2] ) + "If you trust the new fingerprint, edit the 'fingerprints.txt' file." res = APIResponse("", False, err_message=err_message) else: res = APIResponse("", False, err_message=err) except Exception as err: res = APIResponse("", False, err_message=err) finally: conn.close() if response: res.status_code = response.status # When the command is 'login' we'd like to convert the password to "****" so that it # would not appear as plaintext in the debug file. if command == "login": json_data = compatible_loads(_data) json_data["password"] = "******" _data = json.dumps(json_data) # Store the request and the reply (for debug purpose). _api_log = { "request": { "url": url, "payload": compatible_loads(_data), "headers": _headers }, "response": res.response() } self.api_calls.append(_api_log) # If we want to wait for the task to end, wait for it if wait_for_task is True and res.success and command != "show-task": if "task-id" in res.data: res = self.__wait_for_task(res.data["task-id"], timeout=(timeout - time.time() + timeout_start)) elif "tasks" in res.data: res = self.__wait_for_tasks(res.data["tasks"], timeout=(timeout - time.time() + timeout_start)) return res
def main(argv): NO_DEFAULT = object() parser = argparse.ArgumentParser(prog=argv[0]) parser.add_argument( '--format', '-f', metavar='{json|text}', nargs=1, default='text', action=Format) args_def = [ ('--debug', None, '{on|off}', 'MGMT_CLI_DEBUG'), ('--domain', '-d', 'DOMAIN', 'MGMT_CLI_DOMAIN'), ('--fingerprint', None, 'FINGERPRINT', 'MGMT_CLI_FINGERPRINT'), ('--management', '-m', 'SERVER', 'MGMT_CLI_MANAGEMENT'), ('--password', '-p', 'PASSWORD', 'MGMT_CLI_PASSWORD'), ('--port', None, 'PORT', 'MGMT_CLI_PORT'), ('--proxy', '-x', 'PROXY', 'MGMT_CLI_PROXY'), ('--root', '-r', '{true|false}', None), ('--session-id', None, 'SESSION-ID', 'MGMT_CLI_SESSION_ID'), ('--sync', None, '{true|false}', 'MGMT_CLI_SYNC'), ('--user', '-u', 'USER', 'MGMT_CLI_USER'), ('--version', '-v', 'VERSION', 'MGMT_CLI_VERSION'), ] for lname, sname, meta, env in args_def: pargs = [lname] if sname: pargs.append(sname) kwargs = {'metavar': meta} if env: kwargs['default'] = os.environ.get(env, NO_DEFAULT) else: kwargs['default'] = NO_DEFAULT parser.add_argument(*pargs, **kwargs) parser.add_argument('command', metavar='COMMAND') parser.add_argument('arg', metavar='ARG', nargs='*', action=Args) argv = preprocess_argv(argv) if argv is None: return args = parser.parse_args(args=argv[1:]) for lname, _, _, _ in args_def: attr = lname[2:].replace('-', '_') if getattr(args, attr, None) is NO_DEFAULT: delattr(args, attr) client_args = {} if getattr(args, 'debug', 'off') == 'on': log.debug = True client_args['debug_file'] = sys.stderr # dummy # FIXME: remove when save_debug_data is fixed APIClient.save_debug_data = lambda self: sys.stderr.write( 'API calls: %s\n' % json.dumps(self.api_calls, indent=2)) client_args['http_debug_level'] = 1 debug('args: %s\n' % args) if hasattr(args, 'port'): args.port = int(args.port) if hasattr(args, 'proxy'): args.proxy_host, _, port = args.proxy.partition(':') if '@' in args.proxy_host: raise Exception('proxy authentication is not implemented') if port: args.proxy_port = int(port) clargs_def = [ ('management', 'server'), ('port', None), ('fingerprint', None), ('proxy_host', None), ('proxy_port', None), ] for name, cla in clargs_def: val = getattr(args, name, None) if cla is None: cla = name if val is not None: client_args[cla] = val debug('client args: %s\n' % client_args) args.domain = getattr(args, 'domain', None) args.root = compatible_loads(getattr(args, 'root', 'false')) args.sync = compatible_loads(getattr(args, 'sync', 'true')) with APIClient(APIClientArgs(**client_args)) as client: call_args = {} if hasattr(args, 'session_id'): call_args['sid'] = args.session_id elif args.root: client.login_as_root(domain=args.domain) elif hasattr(args, 'password') and args.command != 'login': client.login(username=args.user, password=args.password, domain=args.domain) if hasattr(args, 'version'): # FIXME: remove when api_call accepts api_version client.api_version = args.version saved_stdout = sys.stdout publish_response = None try: sys.stdout = sys.stderr if args.command == 'login': for attr in ('user', 'password', 'domain'): if attr not in args.arg: val = getattr(args, attr, None) if val: args.arg[attr] = val response = client.api_call( args.command, args.arg, wait_for_task=args.sync, **call_args).as_dict() if any(args.command.startswith(p) for p in { 'set-', 'add-', 'delete-', 'get-interfaces'}): publish_response = client.api_call( 'publish', {}, wait_for_task=args.sync).as_dict() finally: sys.stdout = saved_stdout if not response.get('success'): raise Exception(json.dumps(response, indent=2)) if publish_response and not publish_response.get('success'): raise Exception(json.dumps(publish_response, indent=2)) sys.stdout.write(args.format(response.get('data')))