Developing for Splunk Enterprise

Modifying ACL/Saved Search permissions through REST API using Python

erichar7
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

Flynt
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

kiran_p
Explorer
0 Karma

Flynt
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

Flynt
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

Federica_92
Communicator

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

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

thank you

0 Karma

Flynt
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

erichar7
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

martin_mueller
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

erichar7
Explorer

This is the content of my request via urllib2:

print request.get_full_url()
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

erichar7
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

martin_mueller
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

erichar7
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

martin_mueller
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

martin_mueller
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

erichar7
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

martin_mueller
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
Register for .conf21 Now! Go Vegas or Go Virtual!

How will you .conf21? You decide! Go in-person in Las Vegas, 10/18-10/21, or go online with .conf21 Virtual, 10/19-10/20.