Community Documentation

Services 3.0 Python example using XML-RPC and OAuth2

Last updated November 16, 2011. Created by teunis on November 16, 2011.
Log in to edit this page.

This code connects using two-legged OAuth to a drupal host running services-3.x, OAuth and an XMLRPC endpoint. This example uses two different ways to connect - one using xmlrpclib, one not. It could probably be easily adapted for python-oauth instead of oauth2.

# Note, am using two-legged auth here.
# needs http://drupal.org/node/1336974 for two-legged and http://drupal.org/node/1337718 if using a nonstandard port.
#
# there's a couple of approaches here.  One uses xmlrpclib, one doesn't.  Both use oauth2 - but could probably be worked with oauth
#
# services_endpoint needs to be something like (serialiazed as I've pulled it from database and there's no form yet):
#  a:1:{s:14:"services_oauth";a:3:{s:13:"oauth_context";s:n:"CONTEXT GOES HERE";s:11:"credentials";s:8:"consumer";s:13:"authorization";s:n:"DEFAULT SECURITY LEVEL GOES HERE";}}
# Don't forget to fix for 'CONTEXT GOES HERE' and 'DEFAULT SECURITY LEVEL GOES HERE' (and fix 'n' to be the right number)

import oauth2
import time
import urllib2
import xmlrpclib

host_key = 'PUT A KEY HERE'
host_secret = 'PUT A SECRET HERE'
# this is the endpoint.
host = 'https://testserver:1081/endpoint'

class OAuthTransport(xmlrpclib.SafeTransport):
    def __init__(self, host, verbose = None, use_datetime=0):
        xmlrpclib.SafeTransport.__init__(self)
        self.verbose = verbose
        self._use_datetime = use_datetime
        self.host = host

    def oauth_request(self, url, moreparams={}, body=''):
        params = {                                           
            'oauth_version': "1.0",
            'oauth_nonce': oauth2.generate_nonce(),
            'oauth_timestamp': int(time.time())
            }
        consumer = oauth2.Consumer(key=host_key,secret=host_secret)
        params['oauth_consumer_key'] = consumer.key
        params.update(moreparams)
       
        req = oauth2.Request(method='POST', url=url, parameters=params, body=body)
        signature_method = oauth2.SignatureMethod_HMAC_SHA1()
        req.sign_request(signature_method, consumer, None)
        return req

    def single_request(self, host, handler, request_body, verbose=0):
        if (verbose):
            print(host)
            print(handler)
            print(request_body)
        # the parameters call for host + handler - but they've dropped the method (eg:https)
        request = self.oauth_request(url=self.host, body=request_body)
        req = urllib2.Request(request.to_url())
        req.add_header('Content-Type', 'text/xml')
        req.add_data(request_body)
        f = urllib2.urlopen(req)
        return(self.parse_response(f))

def build_request(url, moreparams={}, body=''):
    params = {                                           
        'oauth_version': "1.0",
        'oauth_nonce': oauth2.generate_nonce(),
        'oauth_timestamp': int(time.time())
    }
    consumer = oauth2.Consumer(key=host_key,secret=host_secret)
    params['oauth_consumer_key'] = consumer.key
    params.update(moreparams)

    req = oauth2.Request(method='POST', url=url, parameters=params, body=body)
    signature_method = oauth2.SignatureMethod_HMAC_SHA1()
    req.sign_request(signature_method, consumer, None)
    return req

trans = OAuthTransport(host)
server = xmlrpclib.ServerProxy(host, transport=trans)

if (1):
    try:
        for method in server.system.listMethods():
            print method
            # it would be really nice if introspection works.  Currently it doesn't.
#            print '\n'.join(['  ' + x for x in server.system.methodHelp(method).split('\n')])
#            print
    except xmlrpclib.Fault, err:
        print "A fault occurred"
        print "Fault code: %d" % err.faultCode
        print "Fault string: %s" % err.faultString

if (1):
    req_body = '<methodCall><methodName>system.listMethods</methodName><params></params></methodCall>'
    request = build_request(url=host, moreparams={}, body=req_body)
    u = urllib2.urlopen(request.to_url(), req_body)
    print u.readlines()

# note that it returns a lot of extra information.   Suspect node.retrieve unfinished.
try:
    print server.node.retrieve(3, ['nid','title'])
except xmlrpclib.Fault, err:
    print "A fault occurred"
    print "Fault code: %d" % err.faultCode
    print "Fault string: %s" % err.faultString

req_body = '<methodCall><methodName>system.listMethods</methodName><params></params></methodCall>'
request = build_request(url=host, moreparams={}, body=req_body)
u = urllib2.urlopen(request.to_url(), req_body)
print u.readlines()

Page status

No known problems

Log in to edit this page

About this page

Drupal version
Drupal 6.x, Drupal 7.x
Audience
Programmers
Level
Intermediate
Keywords
oauth, python, services, xmlrpc

Develop for Drupal

Drupal’s online documentation is © 2000-2013 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License. Comments on documentation pages are used to improve content and then deleted.