It's all about the answers!

Ask a question

How to Oauth authenticate using python for RM REST api?


William Owen (9145) | asked Jul 25 '12, 10:19 p.m.
JAZZ DEVELOPER
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



Comments
Bas Bekker commented Jul 26 '12, 12:48 p.m. | edited Jul 26 '12, 12:55 p.m.
JAZZ DEVELOPER

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?


Joseph Reedick commented Jul 26 '12, 2:53 p.m.

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?


William Owen commented Jul 26 '12, 4:32 p.m.
JAZZ DEVELOPER

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.

4 answers



permanent link
Joseph Reedick (10847) | answered Jul 26 '12, 4:54 p.m.
edited Jul 26 '12, 4:57 p.m.
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
William Owen commented Jul 27 '12, 7:43 a.m.
JAZZ DEVELOPER

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.


permanent link
William Owen (9145) | answered Jul 27 '12, 8:18 p.m.
JAZZ DEVELOPER
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
    print "You may now access protected resources using the access tokens above."
    print
   
    #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/


permanent link
Bentsi Magidovich (2036) | answered Apr 28 '14, 12:18 p.m.
William, did you succeed developing authentication code with Python?
I was trying to connect to RM catalog without success.

permanent link
William Owen (9145) | answered Jul 26 '12, 3:53 p.m.
JAZZ DEVELOPER
edited Jul 26 '12, 3:54 p.m.
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
Joseph Reedick commented Jul 26 '12, 4:45 p.m. | edited Jul 26 '12, 4:45 p.m.

"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.

URL: https://{server-name-and-port}/jazz/j_security_check
User name: j_username
Password: j_password
Content-Type: application/x-www-form-urlencoded; charset=utf-8

Your answer


Register or to post 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.