Jan
26
2011

WS-Security and Python, a Blackboard Story

We have a current integration with Blackboard Vista and as we start to deploy Blackboard Learn we wanted to use this same integration with this new end point. The feed is written in Python and the Learn web services use WS-Security for authentication/authorization. I could find very little information on WS-Security and Python. We decided to go with ZSI for our web services layer in Python. After digging for a long time we found that ZSI allows a hook to a Signature Handler that signs each soap packet before its was sent! PERFECT… Now what!

This is my first WS-Security via Python so I am not sure if there is some liberty taken with this protocol by Blackboard or not. The Blackboard looks like it uses the Rampart module for Axis, so I would hope it is standard. Below is our Signature Handler that is working GREAT!

Also below is a sample of how its used for Blackboard Learn. Learn uses a sessionId in the “password” field for WS-Security. This session is then authenticated using web services calls. The info below connects the Context web services for the first time and requests a session. You can then reuse the sessionId it creates and just reuse the Signature Handler created for the other web services calls.

Complete Signature Handler

import time
import random
import hashlib
import binascii
import logging
'''
Created on Oct 27, 2010
 
@author: cdg2
'''
 
class SignatureHandler(object):
    '''
    classdocs
    '''
    OASIS_PREFIX = "http://docs.oasis-open.org/wss/2004/01/oasis-200401"
    SEC_NS = OASIS_PREFIX + "-wss-wssecurity-secext-1.0.xsd"
    UTIL_NS = OASIS_PREFIX + "-wss-wssecurity-utility-1.0.xsd"
    PASSWORD_DIGEST_TYPE = OASIS_PREFIX + "-wss-username-token-profile-1.0#PasswordDigest"
    PASSWORD_PLAIN_TYPE = OASIS_PREFIX + "-wss-username-token-profile-1.0#PasswordText"
    log=logging.getLogger("SignatureHandler")
    def __init__(self,user,password,useDigest=False):
        '''
        Constructor
        '''
        self._user=user
        self._created=time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime(time.time()))
        self._nonce=hashlib.new("sha",str(random.random())).digest()
        if(useDigest):
            self._passwordType=self.PASSWORD_DIGEST_TYPE
            digest=hashlib.new("sha",self._nonce+self._created+password).digest()
            self._password=binascii.b2a_base64(digest)[:-1]
        else:
            self._passwordType=self.PASSWORD_PLAIN_TYPE
            self._password=password
 
    def sign(self,soapWriter):
        # create element
        securityElem = soapWriter._header.createAppendElement("", "wsse:Security")
        securityElem.node.setAttribute("xmlns:wsse", self.SEC_NS)
        securityElem.node.setAttribute("SOAP-ENV:mustunderstand", "true")
 
        # create element
        timestampElem = securityElem.createAppendElement("", "wsse:Timestamp")
        timestampElem.node.setAttribute("xmlns:wsse", self.UTIL_NS)
 
        # create element
        createdElem = timestampElem.createAppendElement("", "wsse:Created")
        createdElem.node.setAttribute("xmlns:wsse", self.UTIL_NS)
 
        createdElem.createAppendTextNode(self._created)
 
        # create element
        usernameTokenElem = securityElem.createAppendElement("", "wsse:UsernameToken")
        usernameTokenElem.node.setAttribute("xmlns:wsse", self.SEC_NS)
        usernameTokenElem.node.setAttribute("xmlns:wsu", self.UTIL_NS)
 
        # create element
        usernameElem = usernameTokenElem.createAppendElement("", "wsse:Username")
        usernameElem.node.setAttribute("xmlns:wsse", self.SEC_NS)
 
        # create element
        passwordElem = usernameTokenElem.createAppendElement("", "wsse:Password")
        passwordElem.node.setAttribute("xmlns:wsse", self.SEC_NS)
        passwordElem.node.setAttribute("Type", self._passwordType)
 
        # create element
        #nonceElem = usernameTokenElem.createAppendElement("", "wsse:Nonce")
        #nonceElem.node.setAttribute("xmlns:wsse", self.SEC_NS)
 
 
 
        # put values in elements
        usernameElem.createAppendTextNode(self._user)
        passwordElem.createAppendTextNode(self._password)
        # binascii.b2a_base64 adds a newline at the end
        #nonceElem. createAppendTextNode(binascii.b2a_base64(self._nonce)[:-1])
 
        self.log.debug(soapWriter)
 
    def verify(self,soapWriter):
        self

Out of context snippet for connection

        self.baseUrl=baseUrl
        locator = Context_WSLocator()
        self.sigHandler = SignatureHandler("session","nosession",False)
        self.port=locator.getContext_WSPortType(baseUrl)
        self.port.binding.sig_handler=self.sigHandler
 
        request = getServerVersionRequest()
        response = self.port.getServerVersion(request)
 
        ret = response._return
        self.log.info("Connecting to ContextWS version: %s" % ret._version)
 
        request = initializeVersion2Request()
        response = self.port.initializeVersion2(request)
        sessionId = response._return
 
        self.sigHandler = SignatureHandler("session",sessionId,False)
        self.port.binding.sig_handler=self.sigHandler
        self.log.info("Received sessionId:%s from initializeVersion2 and set as password" %sessionId)
        self.log.info("Should be all set to use other functions!")
        self.loginTool("venderId","programId","sharedSecret")
.....
def loginTool(self,vendorId,programId,sharedSecret):
        self.log.debug("loginTool")
        request = loginToolRequest()
        request._password = sharedSecret
        request._clientVendorId = vendorId
        request._clientProgramId = programId
 
        response = self.port.loginTool(request)
        return response._return
VN:F [1.9.13_1145]
Rating: 7.8/10 (6 votes cast)
VN:F [1.9.13_1145]
Rating: +3 (from 5 votes)
WS-Security and Python, a Blackboard Story, 7.8 out of 10 based on 6 ratings
Written by GreenO in: Technobabble | Tags: , ,

No Comments »

RSS feed for comments on this post. TrackBack URL

Leave a comment

You must be logged in to post a comment.

Powered by WordPress | Aeros Theme | TheBuckmaker.com WordPress Themes