Jazz Forum Welcome to the Jazz Community Forum Connect and collaborate with IBM Engineering experts and users

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


1 vote

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.



4 answers

Permanent link
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.

1 vote

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.


Permanent link
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/

1 vote


Permanent link
William, did you succeed developing authentication code with Python?
I was trying to connect to RM catalog without success.

1 vote


Permanent link
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...


0 votes

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.

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 log in 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.

Search context
Follow this question

By Email: 

Once you sign in you will be able to subscribe for any updates here.

By RSS:

Answers
Answers and Comments
Question details

Question asked: Jul 25 '12, 10:19 p.m.

Question was seen: 9,106 times

Last updated: Apr 28 '14, 12:18 p.m.

Confirmation Cancel Confirm