Splunk Dev

How to get HTTP header value in custom python web service?

twesthead
Path Finder

Hi,

This is another question about custom python controllers and endpoints.

  • I have programmed a custom endpoint available at: http://localhost:8080/en-US/custom/my_app/my_script/test
  • I make an ajax request from a browser inserting an Authorization header.
  • I am trying to read the value of this header in my python controller, but it doesn't appear.
  • I have tried using cherrypy headers, but although I get plenty of HTTP headers, I can't see the one I want: Authorization.

Any hints on why I get some headers but not that one?

I have my endpoint script in appserver/controllers:

 #my_script.py
 import splunk.appserver.mrsparkle.controllers as controllers
 from splunk.appserver.mrsparkle.lib.decorators import expose_page
 import cherrypy

 class Controller(controllers.BaseController):
     @expose_page(must_login=False, methods=['GET']) 
     def test(self, **kwargs) :
         return cherrypy.request.headers.output()

This is my ajax request:

$.ajax({
    type: "GET",
    crossDomain:true,
    url: "http://localhost:8080/en-US/custom/my_app/my_script/test",
    headers: {
        "Authorization" : "whatever"
    },
    success: function (response){
        console.log(response);
    }
});

This is what I get as a response:

[('Te', 'chunked'),  
('Accept-Encoding', 'gzip'),
('Host', 'localhost:8080'), 
('Accept', '*/*'), 
('X-Splunkd', 'Z/sOmesTrINg/A=='), 
('Remote-Addr', '127.0.0.1'), 
('Referer', 'https://server-of-origin/page.html'), 
('Accept-Language', 'en-US,en;q=0.8'), 
('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'), 
('Origin', 'https://server-of-origin')]

What I am expecting is to see another tuple like: ('Authorization','whatever')

0 Karma

jkat54
SplunkTrust
SplunkTrust

In your custom rest handler use this:

sessionKey=self.getSessionKey()

Here's a full example:

look for "#prompt user to restart splunk web"

### SCRIPT NAME: webSSL_rest.py


import splunk.admin as admin
import os, sys, requests, errno, ConfigParser
import splunk.mining.dcutils as dcu

logger = dcu.getLogger()

class webSSL(admin.MConfigHandler):
  CONF_FILE = 'webSSL'

  def setup(self):
    if self.requestedAction in (admin.ACTION_CREATE,admin.ACTION_EDIT):
      self.supportedArgs.addReqArg("certname")
      self.supportedArgs.addReqArg("cert")
      self.supportedArgs.addReqArg("key")

  def handleEdit(self, confInfo):
    if not 'certname' in self.callerArgs.data.keys() and self.callerArgs['certname']:
       raise admin.ArgValidationException, "A certname must be provided"
    if not 'cert' in self.callerArgs.data.keys() and self.callerArgs['cert']:
       raise admin.ArgValidationException, "A cert must be provided"   
    if not 'key' in self.callerArgs.data.keys() and self.callerArgs['key']:
       raise admin.ArgValidationException, "A key must be provided"   

    #handle long cert pasted in small field remove header and footer and break spaces into new rows
    certname = self.callerArgs['certname'][0]
    cert = self.callerArgs['cert'][0].replace('-----BEGIN CERTIFICATE-----','').replace('-----END CERTIFICATE-----','').replace(" ","\n")
    key = self.callerArgs['key'][0].replace('-----BEGIN RSA PRIVATE KEY-----','').replace('-----END RSA PRIVATE KEY-----','').replace(" ","\n")

    #set paths for cert & key
    scriptDir = sys.path[0]

    #scriptDir = C:\Program Files\Splunk\bin
    certPath = os.path.join(scriptDir,'..','etc','myauth',certname+'.pem')
    keyPath = os.path.join(scriptDir,'..','etc','myauth',certname+'.key')
    webConfPath = os.path.join(scriptDir,'..','etc','system','local','web.conf')

    #handle myauth/cert folder missing
    if not os.path.exists(os.path.dirname(certPath)):
     try:
      os.makedirs(os.path.dirname(certPath))
     except OSError as exc: 
      if exc.errno != errno.EEXIST:
       raise

    #write cert & key adding header & footer back
    with open(certPath,"w") as f:
     f.write("-----BEGIN CERTIFICATE-----" + cert + "-----END CERTIFICATE-----")    
    with open(keyPath,"w") as f:
     f.write("-----BEGIN RSA PRIVATE KEY-----" + key + "-----END RSA PRIVATE KEY-----")

    #modify & write web.conf
    try:
     config = ConfigParser.RawConfigParser()
     config.optionxform = str
     config.read(webConfPath)
     if not config.has_section("settings"):
      config.add_section("settings")
     config.set("settings","enableSplunkWebSSL",True)
     config.set("settings","caCertPath",certPath)
     config.set("settings","privKeyPath",keyPath)
     with open(webConfPath,"wb") as confFile:
      config.write(confFile)
    except Exception as e:
     logging.error(e)

    #prompt user to restart splunk web
    sessionKey=self.getSessionKey()
    headers = {'Authorization':''}
    headers['Authorization'] = 'Splunk ' + sessionKey  
    data = {'name':'restart_link','value':'Splunk must be restarted for changes to take effect.  [[/manager/search/control| Click here to restart from the Manager.]]','severity':'warn'}
    r = requests.post("https://localhost:8089/services/messages/new", headers=headers, data=data, verify=False)
    data = {'name':'restart_reason','value':'A user triggered the create action on app ssl_installer, and the following objects required a restart: ssl configuration','severity':'warn'}
    r = requests.post("https://localhost:8089/services/messages/new", headers=headers, data=data, verify=False)
    pass

  def handleList(self, confInfo):
   confDict = self.readConf(self.CONF_FILE)
   if None != confDict:
    for stanza, settings in confDict.items():
     for key, val in settings.items():
      if val is None:
       confInfo[stanza].append(key, "")
      else:
       confInfo[stanza].append(key, val)


  def handleReload(self, confInfo):
    pass

admin.init(webSSL, admin.CONTEXT_NONE)
0 Karma

jkat54
SplunkTrust
SplunkTrust

@twesthead, any luck with the example?

0 Karma

twesthead
Path Finder

Sorry about the delay and thanks for the detailed example.
I believe your example shows the implementation of a rest handler defined in restmap.conf.
I am using a python controller/endpoint defined in web.conf and appserver/controllers.
Therefore, my main class is not splunk.admin.MConfigHandler but splunk.appserver.mrsparkle.controllers.BaseController.

I feel like I haven't provided enough information on my general goal.
The background to this question is in this other question.

Since that unanswered question, I decided to authenticate and authorize users myself:
1. I have created an auth/login custom controller that takes (admin, password) and returns a sessionKey. (using splunklib.client module)
2. All my other web services take the sessionKey as a parameter and check if it is valid to authorize the request.
3. I find it ugly to pass the sessionKey as a param and I would like to pass it in an header that looks appropriate.

0 Karma

jkat54
SplunkTrust
SplunkTrust

Yeah that's what I meant. But then you've got to hard code a user/pass etc.

Using a Splunk search command however, you can pass the auth token with the correct commands.conf settings. I don't know if that's an option for you or not. You know... Somehow I do this with my rest endpoints because I trigger a restart message after the user clicks save on setup.xml. Let me get back to you...

0 Karma

jkat54
SplunkTrust
SplunkTrust

The auth header is protected to my knowledge. I was never able to get it with these methods you mention. I was able to get one by authenticating against Splunk programmatically though. And I was also able to pass the header through to custom Splunk commands.

0 Karma

twesthead
Path Finder

Hi, thanks for your comment. Can you tell me more about "authenticating against Splunk programmatically" and "passing a header through to custom Splunk commands"?
Do you mean by using username and password through the management port on endpoint 'auth/login'?

0 Karma
Get Updates on the Splunk Community!

What's new in Splunk Cloud Platform 9.1.2312?

Hi Splunky people! We are excited to share the newest updates in Splunk Cloud Platform 9.1.2312! Analysts can ...

What’s New in Splunk Security Essentials 3.8.0?

Splunk Security Essentials (SSE) is an app that can amplify the power of your existing Splunk Cloud Platform, ...

Let’s Get You Certified – Vegas-Style at .conf24

Are you ready to level up your Splunk game? Then, let’s get you certified live at .conf24 – our annual user ...