cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
1518
Views
1
Helpful
0
Comments
tahanson
Cisco Employee
Cisco Employee

This tutorial shows how to make an existing Spark bot more secure.

If you are building your first bot, it is recommended you start with this tutorial.

Then come back here once it’s up and running!

If someone outside of your organization never interacted with your bot, they can’t just run a simple search to find it. However, if they know or guess the ‘email’ address of your bot, they will be able to add it to a space (formerly called room) and send it messages. The more bots that are out there, the higher the possibility of that happening! To prevent unwanted attention, there are three main ways to control access to your bot:

1. You can setup a space (formerly called room) filter when you create a webhook, which points to your bot application’s server.  If someone adds your bot to a Cisco Spark space, and the space does not fit the filter rule for any of the bot’s webhooks, the bot application server will not receive any messages from Spark.  For large enterprise bots that need access to many different spaces, that might not work out.  That’s okay— you can setup one webhook for your bot, with no filter, to receive all messages from any space to which it belongs, and use the following two methods to secure the bot.

2. Filter at the bot’s code level - JSON Payloads are sent from Cisco Spark via HTTP POST to your webserver, which is defined in your webhook (see Handling Requests from Cisco Spark).  When the JSON payload comes in, you can begin your server’s code by checking the incoming message’s data[“personId”] or data[“personEmail”], compare it to a predefined list in your code or database, and handle accordingly.  You can also make a request to Spark with data[“personId”] to check other details, like the organization, to only allow people of a specific org. 

Note: the OrgId that comes in with the webhook JSON Payload is the OrgId of the person that created the webhook.

auth_users = ['tahanson@cisco.com']

my_org_id = "Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi8xZWI2NWZkZi05NjQzLTQxN2YtOTk3NC1hZDcyY2FlMGUxMGY"

@post('/')

def index(request):

webhook = json.loads(request.body)

requester = webhook['data']['personEmail']

if requester != bot_email:

if requester in auth_users:

            print "Authorized user!"

            #Do stuff

else:

            print "Unauthorized user!"

           

#AND/OR check person's org:

person = sendSparkGET('https://api.ciscospark.com/v1/people/{0}'.format(webhook['data']['personId']))

if json.loads(person)['orgId'] == my_org_id:

            print "User is a member of Org!"

            #Do stuff

else:

            print "User it NOT a member of Org!"

return "true"

Note: Above code uses a function defined here.

3. Last, but not least, we have the webhook secret.  This should be used to prevent your bot from processing any POST request that does not come from your specific webhook.  This will block any of your other Spark webhooks, or Spark webhooks setup by other users trying to send to your bot’s webserver location.

Here is a brief tutorial on using a webhook secret in Python.

Everything together, here is a code snippet of all of these features combined:

@post('/')

def index(request):

raw = request.body

hashed = hmac.new(key, raw, hashlib.sha1)

validatedSignature = hashed.hexdigest()

print 'validatedSignature', validatedSignature

print 'X-Spark-Signature', request.headers.get('X-Spark-Signature')

returnVal = ""

if validatedSignature == request.headers.get('X-Spark-Signature'):

webhook = json.loads(raw)

print webhook['data']['id']

requester = webhook['data']['personEmail']

if requester != bot_email:

            #get person information, specifically need the person's orgId

            person = sendSparkGET('https://api.ciscospark.com/v1/people/{0}'.format(webhook['data']['personId']))

            if json.loads(person)['orgId'] == my_org_id or requester in auth_users:

                result = sendSparkGET('https://api.ciscospark.com/v1/messages/{0}'.format(webhook['data']['id']))

                result = json.loads(result)

                in_message = result.get('text', '').lower()

                in_message = in_message.replace(bot_name, '')

                #echo the message back to the same room

                sendSparkPOST("https://api.ciscospark.com/v1/messages", {"roomId": webhook['data']['roomId'], "text": in_message})

                returnVal = "success"

else:

                print "orgId does not match or person not in list of authorized users"

else:

print "Secret does not match!"

return returnVal

You can get the full, working example on Github.  You’ll just need to replace your desired orgId, bot name, and token values in the variables at the bottom of the file.  Let us know if you have any questions!

- Taylor Hanson, Customer Support Engineer II

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: