Hi,
This is another question about custom python controllers and endpoints.
http://localhost:8080/en-US/custom/my_app/my_script/test
Authorization
header.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')
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)
@twesthead, any luck with the example?
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.
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...
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.
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'?