Skip to content

Instantly share code, notes, and snippets.

@SoarinSen
Last active July 17, 2018 23:46
Show Gist options
  • Save SoarinSen/2f58ac9990d7204e897ae01061c943fd to your computer and use it in GitHub Desktop.
Save SoarinSen/2f58ac9990d7204e897ae01061c943fd to your computer and use it in GitHub Desktop.
Python functions to support creating or modifying an endpoint in Cisco Identify Services Engine (ISE) with an iPSK.
import requests, settings, smtplib, logging
import xml.etree.ElementTree as ElemTree
from bs4 import BeautifulSoup
class ISEAPIError(Exception):
"""
An error with the ISE API call being made.
"""
pass
class ISETools(object):
"""Collection of utilities to interface with Cisco ISE.
Args:
url: Server URL as a string.
username: ISE service account username as a string.
password: ISE service account password as a string.
"""
get_headers = {'Accept':
'application/vnd.com.cisco.ise.identity.endpoint.1.0+xml'}
put_headers = {'Content-Type':
'application/vnd.com.cisco.ise.identity.endpoint.1.0+xml'}
post_headers = {'Content-Type':
'application/vnd.com.cisco.ise.identity.endpoint.1.0+xml'}
delete_headers = {'Accept':
'application/vnd.com.cisco.ise.identity.endpoint.1.0+xml'}
def __init__(self, url, username, password):
self.url = url
self.auth = (username, password)
def get_dev_info(self):
#Current development status
return "Production"
def get_endpointid(self, mac):
"""Get the EndpointID for an endpoint MAC address.
Args:
mac: MAC address as a string.
Returns:
endpointID: Endpoint ID as a string if endpoint exists, or None
type if none exists.
responseCode: HTTP status code result of endpointID inquiry.
"""
url = self.url + "/ers/config/endpoint?filter=mac.EQ." + mac
result = requests.get(url, headers=self.get_headers, auth=self.auth)
try:
root = ElemTree.fromstring(result.text)
responseCode = str(result).split('[')[1].split(']')[0]
for child in root.iter():
if 'id' in child.attrib:
endpointid = child.attrib['id']
return endpointid, responseCode
except:
soup = BeautifulSoup(result.text, 'html.parser')
#get summary of html response
errorsummary = soup.body.h1.get_text()
#get details of html response
errordescription = (soup.body.find('p').findNext('p').get_text(
).split('Description ')[1])
#bundle error details for logging
logging.error(errorsummary + ": " + errordescription)
#raise details as exception
raise ISEAPIError(errordescription)
def put_psk(self, mac, psk, unid):
"""Update an endpoint entry with MAC address, uNID, and PSK.
Args:
mac: MAC address as a string.
psk: PSK as a string.
unid: uNID as a string.
Returns:
responseCode: HTTP status code result of attempted change.
"""
url = self.url + "/ers/config/endpoint/" + self.get_endpointid(mac)[0]
xml = """<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<ns3:endpoint name='name' id='id' description='description'
xmlns:ns2='ers.ise.cisco.com'
xmlns:ns3='identity.ers.ise.cisco.com'>
<customAttributes>
<customAttributes>
<entry>
<key>iPSK</key>
<value>psk=""" + psk + """</value>
</entry>
</customAttributes>
</customAttributes>
<groupId>""" + settings.GROUP_ID + """</groupId>
<identityStore></identityStore>
<identityStoreId></identityStoreId>
<mac>""" + mac + """</mac>
<portalUser>""" + unid + """</portalUser>
<profileId></profileId>
<ipsk>""" + psk + """</ipsk>
<staticGroupAssignment>true</staticGroupAssignment>
<staticProfileAssignment>false</staticProfileAssignment>
</ns3:endpoint>"""
result = (requests.put(url, headers=self.put_headers, data=xml,
auth=self.auth))
#perform a split to return just the response code
responseCode = str(result).split('[')[1].split(']')[0]
return responseCode
def create_psk(self, mac, psk, unid):
"""Create a new endpoint to add a PSK for a MAC address and uNID.
Args:
mac: MAC address as a string.
psk: PSK as a string.
unid: uNID as a string.
Returns:
responseCode: HTTP status code result of attempted change.
"""
url = self.url + "/ers/config/endpoint/"
xml = """<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<ns3:endpoint name='name' id='id' description='description'
xmlns:ns2='ers.ise.cisco.com'
xmlns:ns3='identity.ers.ise.cisco.com'>
<customAttributes>
<customAttributes>
<entry>
<key>iPSK</key>
<value>psk=""" + psk + """</value>
</entry>
</customAttributes>
</customAttributes>
<groupId>""" + settings.GROUP_ID + """</groupId>
<identityStore></identityStore>
<identityStoreId></identityStoreId>
<mac>""" + mac + """</mac>
<portalUser>""" + unid + """</portalUser>
<profileId></profileId>
<staticGroupAssignment>true</staticGroupAssignment>
<staticProfileAssignment>false</staticProfileAssignment>
</ns3:endpoint>"""
result = (requests.post(url, headers=self.post_headers, data=xml,
auth=self.auth))
#perform a split to return just the response code
responseCode = str(result).split('[')[1].split(']')[0]
return responseCode
def delete_endpoint(self, mac, unid):
"""Delete an enpoint. This is useful for when an iPSK needs to be
updated.
Args:
mac: MAC address as a string.
unid: uNID as a string.
Returns:
Response code as a string.
"""
endpointid = self.get_endpointid(mac)[0]
url = self.url + "/ers/config/endpoint/" + endpointid
result = (requests.delete(url, headers=self.delete_headers,
auth=self.auth))
#perform a split to return just the response code
responseCode = str(result).split('[')[1].split(']')[0]
return responseCode
def set_psk(self, mac, psk, unid):
"""Set a PSK for an endpoint, choose to edit existing endpoint or
create new one based off of return from get_endpointid().
Args:
mac: MAC address as a string.
psk: PSK as a string.
unid: uNID as a string.
Returns:
XML details of endpoint.
"""
endpointid = self.get_endpointid(mac)
if not endpointid:
return self.create_psk(mac, psk, unid)
else:
self.delete_endpoint(mac, unid)
return self.create_psk(mac, psk, unid)
def send_email(self, responseCode, unid, fname, lname, mac):
EMAIL_TO = unid + '@domain'
# email header details
message = ('Content-Type: text/plain; charset="us-ascii"\n' +
'MIME-Version: 1.0\nContent-Transfer-Encoding: 7bit\n' +
'Subject: Device registration status for: ' + mac +
'\nFrom: ' + settings.EMAIL_FROM + '\nTo: ' + EMAIL_TO +
'\n\n' + 'Dear ' + fname + ' ' + lname + ', \n\n')
#body conditional on response code
if responseCode.startswith('2'):
message += ('')
else:
message += ('')
#footer
message += ('')
sm = smtplib.SMTP(settings.SMTP_SERVER)
sm.sendmail(settings.EMAIL_FROM, EMAIL_TO, message)
sm.quit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment