Developing for Splunk Enterprise

Modifying ACL/Saved Search permissions through REST API using Python

Explorer

I'm attempting to modify a saved search's permissions through the Splunk Python SDK. Unfortunately, it doesn't seem to be supported out of the box, so I'm trying to do it through the REST API. I asked a previous question (modifying saved search permissions using the python sdk) which showed me how to do it in Java, but I'm having trouble translating that solution to Python. I'm using the urllib2 module. I've had some success with this, but I'm stuck:

def modify_perms( ss ):
    service =   initSplunk()

    zen_config  =   get_config()
    url = "localhost:8089/servicesNS/%s/splenoss/saved/searches/%s/acl" % ("admin", ss)

    request =   urllib2.Request( url )        

    base64string    =   base64.encodestring("admin:changeme")

    request.add_header("Authorization", "Basic %s" % base64string)
    request.add_header("Referer", url ) 

    # Saved search access params
    jwargs  = { "sharing"       :   "app"                                        ,
                "modifiable"    :   "1"                                          ,
                "perms.read"    :   "*"                                          ,
                "perms.write"   :   ["admin" , "power"]                          ,
                #"perms"     :   {"read":["*"] , "write":["admin" , "power"]}    ,   
    }


    #response    =   urllib2.urlopen( request , **jwargs )
    response    =   urllib2.urlopen( request )
    print response.read()

If I don't try to push anything to splunk, I get a response back, which has all of the permission settings. However, once I do try to push jwargs, I get error messages about unexpected keywords. I'm assuming that I'm not passing jwargs correctly, or the way I've built jwargs isn't correct. What am I missing to get this to work in Python?

0 Karma
1 Solution

Splunk Employee
Splunk Employee

There are a few changes that would need to be made here-

First, when using urllib2 to post, you'll need to urlencode the data (https://docs.python.org/2/howto/urllib2.html#data)

Secondly, base64.encodestring appears to be appending padding in some manner, you'll need to strip that out.

Lastly, you'll have to add the content type in the header to use the urlencoded data.

Something such as the following should work -

import urllib2
import base64
import urllib


    def modify_perms( ss ):
       url = "https://localhost:8089/servicesNS/%s/search/saved/searches/%s/acl" % ("admin", ss)
       request = urllib2.Request( url )
       base64string    =   base64.encodestring("admin:changeme").strip()
       request.add_header("Authorization", "Basic %s" % base64string)
       request.add_header("Referer", url )
       request.add_header("Content-Type", "application/x-www-form-urlencoded")
       kwargs = { "sharing" : "app","owner":"nobody" }
       response = urllib2.urlopen( request ,  urllib.urlencode(kwargs))
       print response.read()


    modify_perms("test")

This is for a search named test in the search app changing the owner to "nobody" and sharing to "app".

View solution in original post

Explorer
0 Karma

Splunk Employee
Splunk Employee

There are a few changes that would need to be made here-

First, when using urllib2 to post, you'll need to urlencode the data (https://docs.python.org/2/howto/urllib2.html#data)

Secondly, base64.encodestring appears to be appending padding in some manner, you'll need to strip that out.

Lastly, you'll have to add the content type in the header to use the urlencoded data.

Something such as the following should work -

import urllib2
import base64
import urllib


    def modify_perms( ss ):
       url = "https://localhost:8089/servicesNS/%s/search/saved/searches/%s/acl" % ("admin", ss)
       request = urllib2.Request( url )
       base64string    =   base64.encodestring("admin:changeme").strip()
       request.add_header("Authorization", "Basic %s" % base64string)
       request.add_header("Referer", url )
       request.add_header("Content-Type", "application/x-www-form-urlencoded")
       kwargs = { "sharing" : "app","owner":"nobody" }
       response = urllib2.urlopen( request ,  urllib.urlencode(kwargs))
       print response.read()


    modify_perms("test")

This is for a search named test in the search app changing the owner to "nobody" and sharing to "app".

View solution in original post

Splunk Employee
Splunk Employee

By the way if you want to add multiple items (such as for permissions in the following example) use a comma delimited string format

{ "sharing" : "app","owner":"nobody","perms.write":"admin,power,user" }

0 Karma

Communicator

Can I ask if someone can explain me why you insert this part?

request.addheader("Authorization", "Basic %s" % base64string)
request.add
header("Referer", url )

thank you

0 Karma

Splunk Employee
Splunk Employee

Splunk allows for basic HTTP authentication as seen here - http://docs.splunk.com/Documentation/Splunk/latest/RESTUM/RESTusing#Supported_HTTP_methods . Also note the defining RFC for this method here - http://www.rfc-base.org/txt/rfc-1945.txt

Authentication is necessary to access certain REST endpoints in Splunk (most of them actually).

0 Karma

Explorer

I replaced my perms.write with "admin,power" and I got the same results, I keep getting those unhashable type errors or unexpected keyword errors.

As for splunk.rest, I can import that module just fine. However, when I execute the Simple Request function, it returns errors related to SPLUNK_HOME, as if that variable doesn't exist.

0 Karma

SplunkTrust
SplunkTrust

Replace the array for perms.write with "admin,power".

As for the $SPLUNK_HOME environment variable on Windows, that's probably C:\Program Files\Splunk. You can simply import splunk.rest when called from within Splunk's own Python.

0 Karma

Explorer

This is the content of my request via urllib2:

print request.getfullurl()
print request.get_method()

print request.get_data()

https://localhost:8089/servicesNS/admin/splenoss/saved/searches/test/acl
POST
{'owner': 'admin', 'perms.write': ['admin', 'power'], 'sharing': 'app', 'perms.read': '*'}

0 Karma

Explorer

Yes, I've inspected the request and it looks good. If I do not unpack jwargs with **, I will get TypeError: unhashable type when I try to open the url. If I try to build the request using **jwargs instead, it errors out before I can even try to open the url, I get an "unexpected keyword argument" on the first entry in jwargs

Since I'm running Splunk on my Windows machine, I cannot test the curl command. I also couldn't get the splunk.rest module to work correctly, I kept getting KeyError: "SPLUNK_HOME" (I'm guessing that variable doesn't exist with the Windows install)

0 Karma

SplunkTrust
SplunkTrust

Did you inspect your request to see what it actually sent as HTTP POST body? Coming from the other direction, did you use a basic client like curl to send a POST manually to validate the body you intend to send?

splunk.rest sits in $SPLUNK_HOME/Python-2.7/Lib/site-packages/splunk/rest - part of the Splunk install itself.

0 Karma

Explorer

there is no splunk.rest module, or splunklib.rest (or at least I can't find it)...what are you using here?

Also, yes I'm missing "owner" in my args, but that's not important. No matter what I put in my args, I always get back an error about unexpected keys

0 Karma

SplunkTrust
SplunkTrust

Is your perms.write array translated to "perms.write=admin,power" in the HTTP POST body?
Additionally, you seem to be missing the owner.

0 Karma

SplunkTrust
SplunkTrust

Hmm. Here's a simplified excerpt of modifying the permissions from Python I've built a while back:

import splunk.rest as rest
...
aclUrl = "/servicesNS/" + user + "/" + app + "/saved/searches/" + search + "/acl"
postArgs = {"perms.write": perms_write, "perms.read":  perms_read, "sharing": "app", "owner": entity.owner}
rest.simpleRequest(aclUrl, sessionKey=sessionKey, postargs=postArgs, method='POST', raiseAllErrors=True)

entity.owner is the owner of the search (from splunk.entity.getEntity()), and perms_write/perms_read are comma-separated strings of roles.

0 Karma

Explorer

Yes, I do get an error about unexpected keys. However, it complains no matter what I try to pass (if it's a valid key or not)

0 Karma

SplunkTrust
SplunkTrust

I'm going to guess that the REST API is complaining about an unexpected modifiable key. That's not writeable, but rather a calculated part of the response, telling the client if the permissions and sharing of the object allow the current user to modify the object. Setting that doesn't make sense, it's implicitly set of each user through the perms keys.

0 Karma