Tag Archives: CUC API

{unity connection api: schedules}

Recently, I’ve had the notion to create some automation tasks for Unity Connection (9.x) using the provided API (apparently it (the api) now goes back to 7.x) that uses REST..I’ve blogged about this before even..in Resetting a User’s VM PIN. Why am I spending time creating automation you might ask? The tasks that must be performed on a week by week basis (for the next 49 weeks) includes: Create a Class of Service, Directory Handler, Schedule (and Schedule Detail of course), GDMs, 2 Call Handlers, a User Template and a partridge in a pair tree..MULTIPLIED by 4..I’ve been doing all this¬†for the past 6 weeks..all by hand..Today I’m going to briefly discuss automating the task of creating Schedules..(the actual Holiday Schedules are already configured..but and this doesn’t show you how to create a Holiday Schedule..but if you follow..then you might get the notion and/or no-how to do this ūüôā

Before moving on with this, a few disclaimers must be added..this post is really about getting you started with creating Unity Schedules in a bulk fashion..I’m not sure there is any “built-in” methods to do this within Unity itself..unless you use COBRAS (and modify the CSV file?). My other intent is to share some code that might spawn ideas on how to do other interesting things using the API..
Continue reading

{cisco unity connection rest: reseting a users vm pin}

Starting with Cisco Unity Connection 7.x?? Cisco allowed third-party applications to¬†access a REST interface¬†in order to perform configuration tasks, et al on the system without having to navigate¬†the Administrative Pages of¬†cuadmin. Today, I will leave you with the most “basic” script that makes use of this API: we will Unlock a users account and reset the users PIN.¬†This script should be extremely useful for everyone; I don’t know how many times I’ve been asked to provide something similiar. I don’t want to completely own (support) this script once it gets into your hands and I take no responsibility for any damage this might cause in your environment..but I could help streamline¬†the “UX”¬†if you were to reach out to me with very specific requests. The code I am writing for you in this post is FREE and will be available (eventually) on github with a bit of documentation..and I encourage your own¬†forks since I didn’t mind doing my own..

This script is written in Python; it would probably look equally good written in Perl, Ruby, et al (perhaps not a bulky C#/Java)..so I encourage¬†porting the code to the Language of your choice..Also, alot of you all reading this blog may be using a Windows PC; if you haven’t already done so, you will have to install python (and you also should update the Environment Variable on the system so you can type¬†python at a command prompt without being in the directory where python.exe is located);¬†you will also need the¬†requests and¬†lxml module in order to run this code; the easiest way to get those modules is to install¬†easy_install¬†which makes it that much more easier to install them (as its name implies of course); the link to get easy install: (http://simpledeveloper.com/how-to-install-easy_install/). Once you have easy_install (you can add this to that Environment Variable as well) you can type¬†easy_install lxml | easy_install requests at the command line to install the appropriate modules needed for the code I will leave you with. For mac users..you’ll already have Python and easy_install installed..type the appropriate commands above to install the necessary packages to run the code…Good luck getting everything up and running¬†(if you decide to actually use this script).

Lets look at the main() function of our program:

def main():
    global ip,user,pwd,userid
    #ip = raw_input('Enter the IP of your CUC Server. $')
    ip = '10.10.1.50'
    user = raw_input('Please enter your Admin ID. $')
    pwd = getpass('Please enter your Password. $')
    userid = raw_input('Enter the Users ID. $')
    pin = raw_input('Please enter PIN to Use. $')
    status_codes = resetpin(pin)
    if status_codes == 401:
        print 'Bad Username or Password. Please Reenter.'
        user = raw_input('Please enter your Admin ID. $')
        pwd = getpass('Please enter your Password. $')
        status_codes = resetpin(pin)
    if status_codes == 500:
        userid = raw_input('Enter the Users ID. $')
        status_codes = resetpin(pin)
    while True:
        userid = raw_input('Enter the Users ID. To quit enter q. >')
        if userid is 'q':
            break
        status_codes = resetpin(pin)
    print 'Thank you for using me! I hope it saved you precious time.'

There’s nothing great or too terribly unique¬†here..you could hardcode the IP Address (I am here), UserName, Password for your Unity Connection Credentials..you may want to be careful exposing a password in a “text” file; UserId¬†and¬†Pin represent the user you are working on.¬†After collecting information about what user account we will be reseting..the “main” function that performs the real work is called:¬†int =¬†resetpin(pin). Let’s look at the first couple of lines¬†now.

def resetpin(pin):
    headers = {'Content-type':'application/xml'}
    url = 'https://%s/vmrest/users?query=(alias is %s)' % (ip, userid)
    r1 = requests.get(url,verify=False,auth=(user,pwd))
    if r1.status_code == 401:
        return r1.status_code
    userdoc = etree.XML(r1.content)
    find = etree.XPath("//User[Alias='%s']/URI" % userid)
    try:
        objid_uri = find(userdoc)[0].text
    except IndexError:
        print 'That User Doesn\'t Exist. Please Try Again.'
        return 500

I’m thinking about breaking¬†the¬†resetpin(pin) function into into¬†3 separate functions because there are 3 big sections; above is the first section. Let’s look at the URL. When dealing with the User API within the overall API the normal call to the method is:¬†/vmrest/<function>; one cool feature of these REST calls is the fact that you can perform a query¬†using passed in values in order to get back the information on the users account needed in order to use the methods that unlock the users account and reset the users PIN:¬†objectid. If the¬†GET requests returns 401 then the userid/password we entered was incorrect (if you look back at main() you might see me checking for a 401 and if one is found the script reprompts you to enter in new information). If everything goes as planned then an XML/JSON Object is returned; an excerpt of this return is captured below:

<Users total="1">
 <User>
     <URI>/vmrest/users/2401c165-f2d1-4376-bdf1-d87ebadaa1ad</URI>
     <ObjectId>2401c165-f2d1-4376-bdf1-d87ebadaa1ad</ObjectId>
     <FirstName>Sam</FirstName>
     <LastName>Womack</LastName>
     <Alias>samwomack</Alias>
     <DisplayName>Sam Womack</DisplayName>
     <!--The rest has been removed for brevity-->
 </User>
</Users>

In order for us to get to Credential information for the users account we need to extract the ObjectId from the returned XML above..in particular from the code excerpt we are actually extracting the Text Node from the URI Tag(Element):

"//User[Alias='samwomack']/URI"

If the ObjectId¬†doesn’t exist in the return data, then we know that the user we entered doesn’t exist; when this occurs in the TRY/EXCEPT “block” we return to the main() function to reprompt for¬†userid. If everything goes well and¬†we’ve captured the users ObjectId URI we can perform the next section of code which retrieves the¬†Credential data for the particular users which indicates the Account Status for the user; below is that code and then the XML Data that is returned.

url = 'https://%s%s/credential/pin' % (ip, objid_uri)
#Check to See if Account is Locked
r2 = requests.get(url,verify=False,auth=(user,pwd))
usercred_doc = etree.XML(r2.content)
ishacked = etree.XPath("//Hacked/text()")
ishacked = ishacked(usercred_doc)[0]
if 'true' in ishacked:
    hackcount = etree.XPath("//HackCount/text()")
    hackcount = hackcount(usercred_doc)[0]
    print 'The user has %s failed login attempts.' % hackcount
    hack_doc = etree.Element('Credential')
    hack_e = etree.SubElement(hack_doc,'HackCount')
    hack_e.text = '0'
    time_e = etree.SubElement(hack_doc,'TimeHacked')
    time_e.text = ''
    hackstr = etree.tostring(hack_doc, pretty_print=True)
    print 'Unlocking the Account. Please Wait.'
    r3 = requests.put(url,headers=headers,data=hackstr,verify=False,auth=(user,pwd))
    if r3.status_code == 204:
        print 'The Account has been Unlocked Successfully.'
        print 'Now we need to Change the PIN.'
    else:
        print 'Something went wrong with your request.'
        return 1

And now what the return XML looks like from r2:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Credential>
    <URI>/vmrest/users/2401c165-f2d1-4376-bdf1-d87ebadaa1ad/credential/pin</URI>
    <UserObjectId>2401c165-f2d1-4376-bdf1-d87ebadaa1ad</UserObjectId>
    <CredentialType>4</CredentialType>
    <Credentials/>
    <IsPrimary>false</IsPrimary>
    <CantChange>false</CantChange>
    <DoesntExpire>true</DoesntExpire>
    <TimeChanged>2014-04-01 19:56:35.107</TimeChanged>
    <HackCount>7</HackCount>
    <Locked>false</Locked>
    <TimeLastHack>2014-04-01 22:00:41.279</TimeLastHack>
    <Alias>samwomack</Alias>
    <CredMustChange>false</CredMustChange>
    <CredentialPolicyObjectId>bd9808d7-71ea-4721-bcf2-7adc44d3058e</CredentialPolicyObjectId>
    <TimeHacked>2014-04-01 22:00:41.277</TimeHacked>
    <Hacked>true</Hacked>
    <ObjectId>bc461736-71c2-4708-8c03-ba18553ed17a</ObjectId>
    <EncryptionType>3</EncryptionType>
</Credential>

Before we reset the users PIN, we first need to verify the Account (which is typically <Hacked>true</Hacked>). When we find that the account is “Hacked” (the if statement), we then print how many failed login attempts..this is ‘window¬†dressing’..so isn’t essential. If the Users account isn’t locked, then we can proceed on to changing the users PIN; we could disregard¬†request2 and “unlock” the account regardless of checks..try it at your own risk. So, if the account is hacked we will construct our first¬†REST PUT¬†request (liken to a¬†SOAP REQUEST¬†as an XML document is constructed in this process). In lines 11-15 a new XML¬†document is created. In previous posts, I’ve used the DOM Standard for building XML Documents; today I introduce you to a more streamlined approach to creating the very same document (saving anywhere between 30-50% lines of code that don’t have to written). Below is what the document looks like:

<Credential>
  <HackCount>0</HackCount>
  <TimeHacked></TimeHacked>
</Credential>

Request 3 is sent with the document in tow..as it was in my previous post (written precisely the same)..and don’t forget the¬†headers which is alway in¬†dictionary (data-type) form. Really fast, I’m going to show a nice screencapture of what you can use to see the “code” working from a graphical standpoint:

UnlockAcct

As you can see with the PUT call, the returned¬†status_code is 204 so the¬†if statement in line 19 result is¬†True and you will get back a¬†printed message stating that the ‘Account was Unlocked.’ Let’s move on and finish this thing already and as it stands there are only 7 or so lines of code left..where we Send the PIN in a Prepared XML Document (in my next REST demo..I may use a JSON object..but I’m so accustomed to using XML..it just feels more natural to me).

cred_doc = etree.Element('Credential')
cred_e = etree.SubElement(cred_doc,'Credentials')
cred_e.text = pin
credstr = etree.tostring(cred_doc, pretty_print=True)
r4 = requests.put(url,headers=headers,data=credstr,verify=False,auth=(user,pwd))
if r4.status_code == 204:
    print 'You have successfully changed the PIN.'
return r4.status_code

And the XML that is sent:

<Credential>
    <Credentials>PIN</Credentials>
</Credential>

After the PIN is reset, you are Returned to the “infinite” while loop where you are prompted with a statement to enter the next userid or enter q to quit and if the user’s id is q then we have problems :). And as the code is written, if you do reset another User, you will reset that user with the same original PIN you entered. If you want to Force the caller to Change their PIN once going back in, we could do that with another REST call for Update PIN Settings, but for the sake of brevity, I will leave that off this post. If you want me to Add it as an Addendum be the First to Leave a Comment..As I haven’t received nary a one since the inception of this..As promised I leave you with the script files:¬†ucxn_scriptfiles. If you download the files, get python running on your machine with the modules installed mentioned eariler in this post, below is an output of how to run the code: the *.py file is the only file you need..put it in a Directory of your choosing..open a Terminal/CMD Prompt, navigate to that directory, enter the command as the caption below suggests (FYI, I did make an adjustment to the code, to force the user to change their PIN even after the admin gives them a new PIN..I would imagine this is customary)

python ucxn_accountreset_v01.py
#The Rest will take care of itself...

AppInAction

FYI, there is an even easier approach to this problem in the API..especially if you use LDAP accounts and passwords for mailbox users and clean up the PIN change “url”:

PUT /vmrest/user/credential/pin?newpin=<PIN>
{
    ...
    return sam;
}