splunk / splunk-sdk-python

Splunk Software Development Kit for Python
http://dev.splunk.com
Apache License 2.0
698 stars 370 forks source link

403 Forbidden for POST Requests to change owner to nobody #481

Closed nicolas-rdgs closed 1 year ago

nicolas-rdgs commented 2 years ago

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):

SDK (please complete the following information):

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?

akaila-splunk commented 2 years ago

Hi @nicolas-rdgs , Thank you for reporting this. we are planning to introduce a new feature to update an ACL properties and it'll be available on next release.

akaila-splunk commented 2 years ago

Hi @nicolas-rdgs , we have added new method to update ACL properties and it will be available in the next release.

nicolas-rdgs commented 1 year ago

Great! Thank you @akaila-splunk!

ashah-splunk commented 1 year ago

@nicolas-rdgs we have published the latest Python SDK v1.7.3 with the ACL update feature, request you to pull the latest release and let us know in case any issue persists. Thanks!