How to Oauth authenticate using python for RM REST api?
Does anyone have a working python example that shows a simple client authenticating to RM server to access protected resource, like RMCatalog?
I have tried doing this using oauth2 library and rolling my own oauth dance, but I seem to be missing a header. When I post credentials to the server, a new cookie is returned, and the process goes back to starting point it seems. Also, I have compared my code with java example in OSLC tutorial, and seems consistent, except that in python I have to handle cookies myself. But looking at headers from http trace on browser login, it seems that I'm doing that consistently too. A working python example to study would be very helpful! Thanks |
4 answers
This will do a form login as per https://jazz.net/wiki/bin/view/Main/JFSCoreSecurity#Implementation
[code] # http://stackoverflow.com/questions/301924/python-urllib-urllib2-httplib-confusion import urllib import urllib2 class HttpBot: """an HttpBot represents one browser session, with cookies.""" def __init__(self): cookie_handler= urllib2.HTTPCookieProcessor() redirect_handler= urllib2.HTTPRedirectHandler() self._opener = urllib2.build_opener(redirect_handler, cookie_handler) def GET(self, url): return self._opener.open(url).read() def POST(self, url, parameters): return self._opener.open(url, urllib.urlencode(parameters)).read() if __name__ == "__main__": bot = HttpBot() ignored_html = bot.POST('https://myserver.com:9443/jts//authenticated/identity', {}) ignored_html = bot.POST('https://myserver.com:9443/jts/authenticated/j_security_check?j_username=jdoe&j_password=s3cret', {}) print bot.GET('https://myserver.com:9443/rm/discovery/RMCatalog') [code] You need to 1.) RetrieveRequestToken 2.) FormLogin 3.) AuthenticateRequestToken (use the cookies from FormLogin) 4.) RetrieveAccessToken 5.) Do some work (use the cookies from 2&3) edit: Bleeping useless post editor. Comments Step 4 in the log above actually does a form login successfully; after doing this, I can access protected resources from jts with no problem. But RM (Oauth) authentication still fails. Also, if I corrupt the credentials the value for response header x-com-ibm-team-repository-web-auth-msg is "authfailed"; But, I have had some success using oauth2 library; I will post my test code shortly. |
Here is sample python code using oauth2 library. This works, but has the following drawback:
1. needs to know the consumer_key & _secret. So need to handle this if I want the same code to work on multiple jts environments. 2. handling the form login independently of oauth2 module seems wrong, even though it's working. This should be something that is handled by the library, but I've not seen how to do that (but will continue researching it): Working example: def main(): #from jts/admin Consumers page; any valid key/secret will work #would like to implement something that does not require knowing consumer key and secret, like shown in java example consumer_key = 'key' consumer_secret = 'secret' user = 'user@ibm.com' pw = 'secret' REQUEST_TOKEN_URL = 'https://myserver.ibm.com/jts/oauth-request-token' AUTHORIZE_URL = 'https://myserver.ibm.com/jts/oauth-authorize' ACCESS_TOKEN_URL = 'https://myserver.ibm.com/jts/oauth-access-token' PROTECTED_RESOURCE_URL = 'https://myserver.ibm.com/rm/discovery/RMCatalog' RM_RESOURCE_URL = 'https://myserver.ibm.com/rm/publish/resources?projectName=Test+Configuration+Requirements' consumer = oauth.Consumer(consumer_key, consumer_secret) client = oauth.Client(consumer) #step 1: get token resp, content = client.request(REQUEST_TOKEN_URL, "POST") if resp['status'] != '200': raise Exception("Invalid response %s." % resp['status']) request_token = dict(urlparse.parse_qsl(content)) auth_url_with_token='%s?oauth_token=%s' % (AUTHORIZE_URL, request_token['oauth_token']) #step 2: authenticate to jts server cookie = formLoginToServer('jts', user, pw) #debug: prove form login was successful by getting some jts protected resource page, _ = getResourceFromServer(cookie, 'https://myserver.ibm.com/jts/users?query=foaf:nick=%22billowen@us.ibm.com%22') print page #step 3: get authorize url using token from step 1 page, _ = getResourceFromServer(cookie, auth_url_with_token ) #create a new client object that contains our request token and secret token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret']) client = oauth.Client(consumer, token) #step 4: post the access token url resp, content = client.request(ACCESS_TOKEN_URL, "POST") access_token = dict(urlparse.parse_qsl(content)) print "Access Token:" print " - oauth_token = %s" % access_token['oauth_token'] print " - oauth_token_secret = %s" % access_token['oauth_token_secret'] print "You may now access protected resources using the access tokens above." #now create a new client using access_token & access_token_secret token = oauth.Token(access_token['oauth_token'],access_token['oauth_token_secret']) client = oauth.Client(consumer, token) #with that we can get protected resources like RMCatalog print 'now get RMCatalog at ', PROTECTED_RESOURCE_URL response = client.request(PROTECTED_RESOURCE_URL) #output the RMCatalog rdf print 'response is ' g = Graph() g.parse(data=response[1], format='xml') g.serialize() #prove that we can also get the set of requirements defined for a project print 'now get some requirements data' response = client.request(RM_RESOURCE_URL) rDom = ET.fromstring( response[1] ) f = open('/tmp/rm_data.xml', 'w') f.write(ET.tostring( rDom ) ) f.close() print 'Data saved into /tmp/rm_data.xml' if __name__ == '__main__': main() Helpful Links: http://developer.linkedin.com/documents/getting-oauth-token-python http://parand.com/say/index.php/2010/06/13/using-python-oauth2-to-access-oauth-protected-resources/ |
William, did you succeed developing authentication code with Python?
I was trying to connect to RM catalog without success.
|
Below is the log from my log from code that implements Oauth steps directly (mimicking what I see from browser trace, and also from java test program).
I am using RRC v4.0. I was using RRC 3.0.1.1 previously, and was able to authenticate using slightly simplified steps, but seemed like RRC was giving access tokens at the wrong spot. That changed in releases after 3.0.1.1 and I am not able to authenticate since. Here is the log from a test program: start... -------------------------------------------------------------------------------- OLOGIN STEP 1: get protected url: https://myserver.ibm.com/rm/discovery/RMCatalog Request headers: Response headers: content-length: 352 set-cookie: jfs-oauth-access-token0=; expires=Thu, 01-Jan-70 00:00:00 GMT; path=/rm, jfs-oauth-access_token-secret0=; expires=Thu, 01-Jan-70 00:00:00 GMT; path=/rm, jfs-request-token-26923537973f4b09a74bf518a25b0620="JQYlfePc8ISyOB8D+ByJKOJma9W7LmrjcfWb0A1VSec="; Version=1; expires=Thu, 26-Jul-12 19:34:25 GMT; path=/rm server: Apache-Coyote/1.1 x-jazz-web-oauth-url: https://myserver.ibm.com/jts/oauth-authorize?oauth_token=26923537973f4b09a74bf518a25b0620 connection: close date: Thu, 26 Jul 2012 19:29:25 GMT content-type: text/html www-authenticate: OAuth realm=https://myserver.ibm.com/jts/oauth-authorize HTTP Response Code: 401 OLOGIN STEP 1. next url: https://myserver.ibm.com/jts/oauth-authorize?oauth_token=26923537973f4b09a74bf518a25b0620 -------------------------------------------------------------------------------- OLOGIN Step 2: get redirect url: https://myserver.ibm.com/jts/oauth-authorize?oauth_token=26923537973f4b09a74bf518a25b0620 Request headers: Host: myserver.ibm.com Response headers: x-com-ibm-team-repository-web-auth-msg: authrequired content-length: 0 set-cookie: JSESSIONID=D773DF4B0FDF018FDABD54E34100DC5C; Path=/jts/; Secure; HttpOnly expires: Wed, 31 Dec 1969 17:00:00 MST server: Apache-Coyote/1.1 connection: close location: https://myserver.ibm.com/jts/authenticated/identity?redirectPath=%2Fjts%2Foauth-authorize%3Foauth_token%3D26923537973f4b09a74bf518a25b0620 cache-control: private date: Thu, 26 Jul 2012 19:29:25 GMT HTTP Response Code: 302 OLOGIN STEP 2. next url: https://myserver.ibm.com/jts/authenticated/identity?redirectPath=%2Fjts%2Foauth-authorize%3Foauth_token%3D26923537973f4b09a74bf518a25b0620 -------------------------------------------------------------------------------- OLOGIN Step 3: get redirect url: https://myserver.ibm.com/jts/authenticated/identity?redirectPath=%2Fjts%2Foauth-authorize%3Foauth_token%3D26923537973f4b09a74bf518a25b0620 Request headers: Cookie: JSESSIONID=D773DF4B0FDF018FDABD54E34100DC5C; Path=/jts/; Secure; HttpOnly Response headers: x-com-ibm-team-repository-web-auth-msg: authrequired content-length: 2870 set-cookie: JazzFormAuth=Form; Path=/jts expires: Wed, 31 Dec 1969 17:00:00 MST server: Apache-Coyote/1.1 connection: close cache-control: private date: Thu, 26 Jul 2012 19:29:25 GMT content-type: text/html;charset=UTF-8 HTTP Response Code: 200 -------------------------------------------------------------------------------- OLOGIN Step 4: post authdata url: https://myserver.ibm.com/jts/j_security_check Request headers: Content-type: application/x-www-form-urlencoded;charset=UTF-8 Cookie: JSESSIONID=D773DF4B0FDF018FDABD54E34100DC5C; Path=/jts/; Secure; HttpOnly JazzFormAuth=Form; Response headers: x-com-ibm-team-repository-web-auth-msg: authrequired content-length: 0 set-cookie: JSESSIONID=7E49C694DF6A68192F613CFC75F38F6D; Path=/jts/; Secure; HttpOnly NOTE: step 4 should not return a new jesessionid at this point - trouble ahead expires: Wed, 31 Dec 1969 17:00:00 MST server: Apache-Coyote/1.1 connection: close location: https://myserver.ibm.com/jts/authenticated/identity?redirectPath=%2Fjts%2Foauth-authorize%3Foauth_token%3D26923537973f4b09a74bf518a25b0620 cache-control: private date: Thu, 26 Jul 2012 19:29:25 GMT HTTP Response Code: 302 OLOGIN STEP 4. next url: https://myserver.ibm.com/jts/authenticated/identity?redirectPath=%2Fjts%2Foauth-authorize%3Foauth_token%3D26923537973f4b09a74bf518a25b0620 -------------------------------------------------------------------------------- OLOGIN Step 5: get redirect url: https://myserver.ibm.com/jts/authenticated/identity?redirectPath=%2Fjts%2Foauth-authorize%3Foauth_token%3D26923537973f4b09a74bf518a25b0620 Request headers: Cookie: JSESSIONID=D773DF4B0FDF018FDABD54E34100DC5C; Path=/jts/; Secure; HttpOnly JazzFormAuth=Form; Response headers: x-com-ibm-team-repository-web-auth-msg: authrequired content-length: 2870 set-cookie: JSESSIONID=5F1F40880A2E9D079A0D46E15C47122D; Path=/jts/; Secure; HttpOnly, JazzFormAuth=Form; Path=/jts expires: Wed, 31 Dec 1969 17:00:00 MST server: Apache-Coyote/1.1 connection: close cache-control: private date: Thu, 26 Jul 2012 19:29:26 GMT content-type: text/html;charset=UTF-8 NOTE: step 5 should return with cookie jsessionid & jsessionidsso - it does not so stop - we are not authenticated stopping... Comments "Response headers: x-com-ibm-team-repository-web-auth-msg: authrequired" You're getting authrequired which means your Form Based Login is failing. https://jazz.net/wiki/bin/view/Main/JFSCoreSecurity#Implementation Therefore the client should always check for the presence of the x-com-ibm-team-repository-web-auth-msg HTTP response header, if the value of this is authrequired then the client must use the form-based login process described below ... The details of the Jazz Foundation user authentication follows the J2EE form-based authentication specification, as shown below. At this time the URL for the form is not present in the rot services document, this may change in future versions of the Foundation.
|
Your answer
Dashboards and work items are no longer publicly available, so some links may be invalid. We now provide similar information through other means. Learn more here.
Comments
Hi William, I don't have a python example, but I can try helping with the authentication logic. How far did you get with the authentication logic? Besides the cookie, what headers are you getting back? Also, what version of RRC are you using?
This may (or may not) help: https://jazz.net/wiki/bin/view/Main/JFSCoreSecurity#Application_Authentication The 'Implementation' section has the details.
What OAuth library are you using?
Hi Joseph, I am trying two approaches: The first approach is using oauth2 from here: http://pypi.python.org/pypi/oauth2/.
The second approach is using urllib2 calls directly to implement the steps of the oauth protocol.