Description
Describe the bug
I don't know if it's really a bug, but the client send a bad request to Splunk because there is a conflict key argument.
The client returns a 403 Forbidden error when I try to change the owner of a saved search via the "POST" method of SavedSearch object/entity.
Splunk (please complete the following information):
- Version: 8.2.2.1
- OS: Debian 11
- Deployment: single-instance
SDK (please complete the following information):
- Version: 1.7.1
- Language Runtime Version: Python 3.9.2
- OS: Debian 11
To Reproduce
import splunklib.client as client
service = client.connect(host=, port=, username=, password=, owner="admin", app="search", sharing="app")
saved_search = service.saved_searches["Test savedsearch"]
saved_search.post("acl", owner="nobody", app="search", sharing="app")
# Traceback
---------------------------------------------------------------------------
HTTPError Traceback (most recent call last)
/home/user/splunk_update_rules.ipynb Cell 2 in <cell line: 2>()
1 a = service.saved_searches["Test savedsearch"]
----> 2 a.post("acl", owner="nobody", app="search", sharing="app")
File ~/.local/lib/python3.9/site-packages/splunklib/client.py:1038, in Entity.post(self, path_segment, owner, app, sharing, **query)
1036 def post(self, path_segment="", owner=None, app=None, sharing=None, **query):
1037 owner, app, sharing = self._proper_namespace(owner, app, sharing)
-> 1038 return super(Entity, self).post(path_segment, owner=owner, app=app, sharing=sharing, **query)
File ~/.local/lib/python3.9/site-packages/splunklib/client.py:846, in Endpoint.post(self, path_segment, owner, app, sharing, **query)
844 else:
845 path = self.service._abspath(self.path + path_segment, owner=owner, app=app, sharing=sharing)
--> 846 return self.service.post(path, owner=owner, app=app, sharing=sharing, **query)
File ~/.local/lib/python3.9/site-packages/splunklib/binding.py:288, in _authentication.<locals>.wrapper(self, *args, **kwargs)
285 return request_fun(self, *args, **kwargs)
286 try:
287 # Issue the request
--> 288 return request_fun(self, *args, **kwargs)
289 except HTTPError as he:
290 if he.status == 401 and self.autologin:
291 # Authentication failed. Try logging in, and then
292 # rerunning the request. If either step fails, throw
293 # an AuthenticationError and give up.
File ~/.local/lib/python3.9/site-packages/splunklib/binding.py:69, in _log_duration.<locals>.new_f(*args, **kwargs)
66 @wraps(f)
67 def new_f(*args, **kwargs):
68 start_time = datetime.now()
---> 69 val = f(*args, **kwargs)
70 end_time = datetime.now()
71 logging.debug("Operation took %s", end_time-start_time)
File ~/.local/lib/python3.9/site-packages/splunklib/binding.py:762, in Context.post(self, path_segment, owner, app, sharing, headers, **query)
760 logging.debug("POST request to %s (body: %s)", path, repr(query))
761 all_headers = headers + self.additional_headers + self._auth_headers
--> 762 response = self.http.post(path, all_headers, **query)
763 return response
File ~/.local/lib/python3.9/site-packages/splunklib/binding.py:1240, in HttpLib.post(self, url, headers, **kwargs)
1234 body = _encode(**kwargs).encode('utf-8')
1235 message = {
1236 'method': "POST",
1237 'headers': headers,
1238 'body': body
1239 }
-> 1240 return self.request(url, message)
File ~/.local/lib/python3.9/site-packages/splunklib/binding.py:1260, in HttpLib.request(self, url, message, **kwargs)
1258 response = record(response)
1259 if 400 <= response.status:
-> 1260 raise HTTPError(response)
1262 # Update the cookie with any HTTP request
1263 # Initially, assume list of 2-tuples
1264 key_value_tuples = response.headers
HTTPError: HTTP 403 Forbidden -- You do not have permission to share objects at the system level
After some investigation, this following line is the root cause:
return super(Entity, self).post(path_segment, owner=owner, app=app, sharing=sharing, **query)
Because "**query" replace the values of owner, app and sharing arguments, so query become empty and kwargs in HttpLib.post too.
I have the same behavior when I do:
% curl -sku admin:xxx -d output_mode=json 'https://localhost:8089/servicesNS/nobody/soc_rules/saved/searches/Test%20savedsearch/acl' | jq
{
"messages": [
{
"type": "ERROR",
"text": "You do not have permission to share objects at the system level"
}
]
}
I discovered the "body" argument/key from binding.py (line: 1221) that parse correctly the POST data, so when I do the following request, it works:
saved_search.post("acl", body={"owner":"nobody", "app": "search", "sharing": "app"})
{'status': 200,
'reason': 'OK',
'headers': [('Date', 'Wed, 24 Aug 2022 15:09:42 GMT'),
......
}
It is the correct way to do that or it is a unwanted behavior?