def __init__( self, splunkd_uri, session_key, endpoint, *args, **kwargs ): self._splunkd_uri = splunkd_uri self._session_key = session_key self._endpoint = endpoint self._args = args self._kwargs = kwargs splunkd_info = urlparse(self._splunkd_uri) self._client = SplunkRestClient( self._session_key, self._endpoint.app, scheme=splunkd_info.scheme, host=splunkd_info.hostname, port=splunkd_info.port, ) self.rest_credentials = RestCredentials( self._splunkd_uri, self._session_key, self._endpoint, ) self.PASSWORD = u'********'
def _migrate(self): internal_endpoint = self.endpoint.internal_endpoint if not (internal_endpoint.endswith('settings') or internal_endpoint.endswith('account')): return splunkd_info = urlparse(get_splunkd_uri()) self.base_app_name = util.get_base_app_name() self.conf_mgr = ConfManager( self.getSessionKey(), self.base_app_name, scheme=splunkd_info.scheme, host=splunkd_info.hostname, port=splunkd_info.port, ) self.client = SplunkRestClient( self.getSessionKey(), self.base_app_name, scheme=splunkd_info.scheme, host=splunkd_info.hostname, port=splunkd_info.port, ) self.legacy_passwords = None # migration legacy configuration in related conf files if internal_endpoint.endswith('settings'): self._migrate_conf() self._migrate_conf_customized() elif internal_endpoint.endswith('account'): self._migrate_conf_credential()
def __init__(self, splunkd_uri, session_key, schema): """ Global Config. :param splunkd_uri: :param session_key: :param schema: :type schema: GlobalConfigSchema """ self._splunkd_uri = splunkd_uri self._session_key = session_key self._schema = schema splunkd_info = urlparse(self._splunkd_uri) self._client = SplunkRestClient( self._session_key, self._schema.product, scheme=splunkd_info.scheme, host=splunkd_info.hostname, port=splunkd_info.port, ) self._configuration = Configuration(self._client, self._schema) self._inputs = Inputs(self._client, self._schema) self._configs = Configs(self._client, self._schema) self._settings = Settings(self._client, self._schema)
def get_session_key(splunk, request): uri = f'https://{splunk["host"]}:{splunk["port"]}/services/auth/login' _rest_client = SplunkRestClient(None, '-', 'nobody', "https", splunk["host"], splunk["port"]) try: response = _rest_client.http.post(uri, username=splunk["username"], password=splunk["password"], output_mode='json') except binding.HTTPError as e: raise return uri, json.loads(response.body.read())['sessionKey']
class RestHandler(object): def __init__(self, splunkd_uri, session_key, endpoint, *args, **kwargs): self._splunkd_uri = splunkd_uri self._session_key = session_key self._endpoint = endpoint self._args = args self._kwargs = kwargs splunkd_info = urlparse(self._splunkd_uri) self._client = SplunkRestClient( self._session_key, self._endpoint.app, scheme=splunkd_info.scheme, host=splunkd_info.hostname, port=splunkd_info.port, ) self.rest_credentials = RestCredentials( self._splunkd_uri, self._session_key, self._endpoint, ) self.PASSWORD = u'********' @_decode_response def get(self, name, decrypt=False): if self._endpoint.need_reload: self.reload() response = self._client.get( self.path_segment( self._endpoint.internal_endpoint, name=name, ), output_mode='json', ) return self._format_response(response, get=True, decrypt=decrypt) @_decode_response def all(self, decrypt=False, **query): if self._endpoint.need_reload: self.reload() response = self._client.get(self.path_segment( self._endpoint.internal_endpoint), output_mode='json', **query) return self._format_all_response(response, decrypt) def get_encrypted_field_names(self, name, data): return [ x.name for x in self._endpoint.model(name, data).fields if x.encrypted ] @_decode_response @_pre_request(existing=False) def create(self, name, data): data['name'] = name self.rest_credentials.encrypt_for_create(name, data) response = self._client.post(self.path_segment( self._endpoint.internal_endpoint), output_mode='json', body=data) return self._format_response(response) @_decode_response @_pre_request(existing=True) def update(self, name, data): self.rest_credentials.encrypt_for_update(name, data) response = self._client.post(self.path_segment( self._endpoint.internal_endpoint, name=name, ), output_mode='json', body=data) return self._format_response(response) @_decode_response def delete(self, name): response = self._client.delete( self.path_segment( self._endpoint.internal_endpoint, name=name, ), output_mode='json', ) # delete credentials rest_credentials = RestCredentials( self._splunkd_uri, self._session_key, self._endpoint, ) rest_credentials.delete(name) return self._flay_response(response) @_decode_response def disable(self, name): response = self._client.post( self.path_segment( self._endpoint.internal_endpoint, name=name, action='disable', ), output_mode='json', ) return self._flay_response(response) @_decode_response def enable(self, name): response = self._client.post( self.path_segment( self._endpoint.internal_endpoint, name=name, action='enable', ), output_mode='json', ) return self._flay_response(response) def reload(self): self._client.get( self.path_segment( self._endpoint.internal_endpoint, action='_reload', ), ) @classmethod def path_segment(cls, endpoint, name=None, action=None): """ Make path segment for given context in Splunk REST format: <endpoint>/<entity>/<action> :param endpoint: Splunk REST endpoint, e.g. data/inputs :param name: entity name for request, "/" will be quoted :param action: Splunk REST action, e.g. disable, enable :return: """ template = '{endpoint}{entity}{action}' entity = '' if name: # all special characters except "/" will be # url-encoded in splunklib.binding.UrlEncoded entity = '/' + name.replace('/', '%2F') path = template.format( endpoint=endpoint.strip('/'), entity=entity, action='/%s' % action if action else '', ) return path.strip('/') def _format_response(self, response, get=False, decrypt=False): body = response.body.read() try: cont = json.loads(body) except ValueError: raise RestError(500, 'Fail to load response, invalid JSON') for entry in cont['entry']: name = entry['name'] data = entry['content'] acl = entry['acl'] encrypted_field_names = self.get_encrypted_field_names(name, data) # encrypt and get clear password for get request if get: masked = self.rest_credentials.decrypt_for_get(name, data) if masked: self._client.post(self.path_segment( self._endpoint.internal_endpoint, name=name, ), body=masked) if not decrypt: # replace clear password with '********' for field_name in encrypted_field_names: if field_name in data and data[field_name]: data[field_name] = self.PASSWORD yield name, data, acl def _flay_response(self, response, decrypt=False): body = response.body.read() try: cont = json.loads(body) except ValueError: raise RestError(500, 'Fail to load response, invalid JSON') for entry in cont['entry']: name = entry['name'] data = entry['content'] acl = entry['acl'] if self._need_decrypt(name, data, decrypt): self._load_credentials(name, data) if not decrypt: self._clean_credentials(name, data) yield name, data, acl def _format_all_response(self, response, decrypt=False): body = response.body.read() try: cont = json.loads(body) except ValueError: raise RestError(500, 'Fail to load response, invalid JSON') # cont['entry']: collection list, load credentials in one request # if any(x.encrypted for x in self._endpoint.model(None, cont['entry']).fields): if self.get_encrypted_field_names(None, cont['entry']): self._encrypt_raw_credentials(cont['entry']) if not decrypt: self._clean_all_credentials(cont['entry']) for entry in cont['entry']: name = entry['name'] data = entry['content'] acl = entry['acl'] yield name, data, acl def _load_credentials(self, name, data): rest_credentials = RestCredentials(self._splunkd_uri, self._session_key, self._endpoint) masked = rest_credentials.decrypt(name, data) if masked: # passwords.conf changed self._client.post( self.path_segment( self._endpoint.internal_endpoint, name=name, ), **masked) def _encrypt_raw_credentials(self, data): rest_credentials = RestCredentials(self._splunkd_uri, self._session_key, self._endpoint) # get clear passwords for response data and get the password change list change_list = rest_credentials.decrypt_all(data) field_names = { x.name for x in self._endpoint.model(None, data).fields if x.encrypted } for model in change_list: # only updates the defined fields in schema masked = dict() for field in field_names: if field in model['content'] and model['content'][field] != '' \ and model['content'][field] != self.PASSWORD: masked[field] = self.PASSWORD if masked: self._client.post(self.path_segment( self._endpoint.internal_endpoint, name=model['name'], ), body=masked) def _need_decrypt(self, name, data, decrypt): # some encrypted-needed fields are plain text in *.conf. encrypted_field = False for field in self._endpoint.model(name, data).fields: if field.encrypted is False: # ignore non-encrypted fields continue encrypted_field = True if not data.get(field.name): # ignore un-stored/empty fields continue if data[field.name] == RestCredentials.PASSWORD: # ignore already-encrypted fields continue return True if decrypt and encrypted_field: # clear credentials is required by request and # there are some encrypted-needed fields return True return False def _clean_credentials(self, name, data): encrypted_field_names = self.get_encrypted_field_names(name, data) for field_name in encrypted_field_names: if field_name in data: del data[field_name] def _clean_all_credentials(self, data): encrypted_field_names = self.get_encrypted_field_names(None, data) for model in data: for field_name in encrypted_field_names: if field_name in model[ 'content'] and model['content'][field_name] != '': model['content'][field_name] = self.PASSWORD