omniORB Interceptors in Python
omniORB's interceptors provide a very general mechanism to include meta-information at key event points. One very common technique uses interceptors to couple authentication information to a request. This little tutorial tries to present a very simple-minded version of this. The basis for this tutorial is Example 2 (section 2.5) from the omniORBpy version 2 User's Guide. The relevant bits should be easily relocated into other code.
the client
#!/usr/bin/env python (-)
import thread, omniORB # new
from omniORB import interceptors # new
import sys
from omniORB import CORBA
import Example
# new code begins here
_names = {}
def registerName(name):
global _names
_names[thread.get_ident()] = name
def _insertUser(op, srvctx):
u = _names.get(thread.get_ident(), "none")
cargo = omniORB.cdrMarshal(CORBA._tc_string, u)
srvctx.append((0x52434301, cargo))
interceptors.addClientSendRequest(_insertUser)
user = sys.argv[2]
registerName(user)
# new code ends here
orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
ior = sys.argv[1]
obj = orb.string_to_object(ior)
eo = obj._narrow(Example.Echo)
if eo is None:
print "Object reference is not an Example::Echo"
sys.exit(1)
message = "Hello from Python"
result = eo.echoString(message)
print "I said '%s'. The object said '%s'." % (message, result)
We import two new modules for the various pieces we need. We need the base omniORB module for the cdrMarshal function, and we need the interceptors module.
The second block of new code starts with a very simple registry of user names hashed by thread id: certainly overkill for this simple example, but in a real system, probably only pragmatic.
The function that follows is what gets called when the interceptor is run. The first argument is the operation name, the second argument is a Python list containing all current service contexts. Our function extracts the appropriate user name for the current thread, then marshals that into raw bytes using omniORB's cdrMarshal function. Since we expect our user name to be a string, we marshal this as a string, but other typecodes are available in the CORBA module. We put this cooked payload in a tuple with the service context id. The id number here is lifted from Bill Noon's ucanSecure.cc module, posted to the omniORB mailing list Feb 27 2003. (I'm not sure whether there's anything special about the number you pick, but this one works for me.)
Outside the _insertUser function, we register _insertUser to be invoked when the client sends a request, then we take a user name from the command line and register it for this thread.
Now when we make the request a few lines later, our _insertUser function is invoked, and it stuffs the username into the headers of the request. All we need is a server that can find it there....
the server
#!/usr/bin/env python (-)
import sys
import omniORB # this is new
from omniORB import interceptors # this is new
from omniORB import CORBA, PortableServer
import Example, Example__POA
class Echo_i (Example__POA.Echo):
def echoString(self, mesg):
print "echoString() called with message:", mesg
return mesg
# new code begins here
def _retrieveUser(op, contexts):
for k, v in contexts:
if k == 0x52434301:
u = omniORB.cdrUnmarshal(CORBA._tc_string, v)
print "Request on behalf of %s" % u
break
interceptors.addServerReceiveRequest(_retrieveUser)
# new code ends here
orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
poa = orb.resolve_initial_references("RootPOA")
ei = Echo_i()
eo = ei._this()
print orb.object_to_string(eo)
poaManager = poa._get_the_POAManager()
poaManager.activate()
orb.run()
The server is even simpler, because all we're doing is printing out the username when we handle a request. In the server we also import a couple of the same modules, and we define a _retrieveUser function. The arguments to this function will be the name of the operation requested, and a sequence of tuples. Each tuple contains the service context id and the payload. We iterate through the list until we find a context id matching the one we used in our client. On finding it, we unmarshal the result and print it out.
This simple example doesn't do much in the way of solving real-world problems, but hopefully the distance between this and a real-world solution isn't too great.
