I am currently looking for a python script which can help in creating a workitem using the XML payload. I tried RTCClient but it is of not much help for future and hence I am looking for script via Requests library from Python
I tried cURL commands and I was able to create workitem in RTC but when I try to repeat the same via Python Requests, I don't get any luck in achieving it. Below is the snippet I am using to achieve the same. During my last GET, I get HTML error as "Javascript is either disabled or not available in your Browser". I believe my authentication is not working proper via Python whereas the same works fine with cURL
Can anyone help in correcting below syntax
RTCCookieURL = 'https://clmtest:9443/jazz/authenticated/identity'
RTCGetCookie = requests.get(RTCCookieURL, verify=False)
RTCCookies=RTCGetCookie.cookies
print(RTCCookies)
RTCAuthURL = 'https://clmtest:9443/jazz/authenticated/j_security_check'
RTCHeaders = {
'Accept': 'text/xml',
'Content-Type': 'application/x-oslc-cm-change-request+xml'
}
RTCAuth = requests.get(RTCAuthURL, auth=HTTPBasicAuth('uname','pwd'), verify=False, allow_redirects=True)
print(RTCAuth.cookies)
RTCGetCatalog = requests.get('https://clmtest:9443/jazz/oslc/workitems/catalog', verify=False, cookies=RTCAuth.cookies)
print(RTCGetCatalog.content)
I guess you're trying to replicate an example I've seen somewhere using Curl to login in two steps - a GET to collect cookies then a POST (because -d data is contained in the Curl command) to do form authentication, with explicit saving cookies on the GET and applying these cookies to the subsequent command(s).
You should use a requests session because it does all the cookie handling for you.
Reference material is here, see below heading FORM challenge https://jazz.net/wiki/bin/view/Main/NativeClientAuthentication. Properly handled, when making a request which requires login the response indicates this and tells you where to go to authenticate, which is a much better plan than simply hardcoding URLs as your code does and as does the simple example below.
Notes:
One point of care you should take - authentication has a timeout configured on the app server, and doing an explicit login will only work for subsequent requests as long as that timout hasn't expired, and then you'll get a challenge which if you ignore it you will start getting 403 responses. Basically, it's better in general to not use an explicit login but to simply always try to make the actual request you want to make and check the response headers (even when the request gets a 200 as for example the whoami before logging in, see code) to look for the need to authenticate, and then do the login and finally replay the original request which wouldn't have had any effect as authentication was needed. Take the approach of handling every request like this then authentication expiry is automatically handled by reauthenticating.
This code below uses hardcoded URLs so won't work if e.g. the jts context root changes from /jts. In a more robust implementation there are few hardcoded urls - obviously your code needs to know the application's URL e.g. https://myserver.com:9443/ccm1 and then I think only minimal harcoding is needed - such as j_security_check and rootservices - every other url should be found from the rootservices (the project catalog) or from content/headers in responses.
ccm and qm do authentication themselves, but rm delegates to jts for auth - the indicators for authrequired tell you where to go so you don't need to (shouldn't) hardcode the differences.
As noted in the reference material direct login as you attempt doesn't work on Tomcat, only Liberty. Also refer to the other note about replaying the original request for Tomcat.
This code below replicates what I can remember of the Curl login sequence, works for Form login to Liberty using the Liberty user registry and that's what I've tested it against. YMMV with other auth mechanisms and this definitely won't work for Jazz Authorization Server which does different redirect for the login.
import requests
import urllib3
# Disable the InsecureRequestWarning - pointless having warnings when
# accessing temporary servers which only ever have self-signed certs
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
SERVER = "https://clmtest:9443"
JTSCookieURL = SERVER+'/ccm/authenticated/identity'
JTSAuthURL = SERVER+'/ccm/j_security_check'
JTSWHOAMI = SERVER+"/ccm/whoami"
RootServices = SERVER+'/ccm/rootservices'
USERNAME='fred'
PWD = 'fred'
# get a session - use this for *every* request to the server
s = requests.session()
# when not authenticated, whoami returns 200 with HTML :-( - but it's a good test of authentication success
GetWhoAmI = s.get(JTSWHOAMI, verify=False)
print( f"{GetWhoAmI=}" )
# whoami when authenticated returns the user id - this is always on the jts
# or when not authenticated returns html
if GetWhoAmI.content != SERVER+"/jts/users/"+USERNAME:
print( "NOT AUTHENTICATED YET!!!")
else:
raise Exception( "We are authenticated which should never happen before we login" )
#
# This works for (default) form authentication using Liberty user registry
#
# do a get to load up session with cookies
GetCookie = s.get(JTSCookieURL, verify=False)
print( f"{GetCookie=}" )
# do a post to authenticate
Auth = s.post(JTSAuthURL, data = { 'j_username': USERNAME, 'j_password': PWD}, verify=False,allow_redirects=True)
print(f"{Auth=}")
# now you can get protected resource - whoami
GetWhoAmI = s.get(JTSWHOAMI, verify=False)
print( f"{GetWhoAmI=}" )
if GetWhoAmI.text != SERVER+"/jts/users/"+USERNAME:
# print( "NOT AUTHENTICATED!!!")
raise Exception( "NOT AUTHENTICATED" )
else:
print( "HURRAY WE ARE AUTHENTICATED" )
# now you can get protected resources, starting with rootservices
GetRootServices = s.get(RootServices, verify=False)
print( f"{GetRootServices=}" )
#print(GetRootServices.content)
The curl equivalent (for windows, for other OS just remove the rem/echo lines) for /rm is something like (for https://SERVER:9443 and admin user/password myid/mypassword):
rem GET to receive the JazzFormAuth cookie
rem important to use the -L option so the authentication redirects are followed
curl -k -L -c cookies.txt "https://SERVER:9443/jts/authenticated/identity" -v
echo ******************************************************************************************
rem POST to authenticate
rem important to use the -L option so the authentication redirects are followed
curl -k -L -b cookies.txt -c cookies.txt -d "" "https://SERVER:9443/jts/j_security_check?j_username=myid&j_password=mypassword" -v
rem GET a protected resource - if fails, returns 302 (because -L isn't specified on this request, if it fails then redirect to auth isn't followed)
curl -k -b cookies.txt -c cookies.txt "https://SERVER:9443/rm/oslc_rm/catalog" -v -H "OSLC-Core-Version: 2.0" -H "Accept: application/rdf+xml"
and then for further requests always use the -b cookies.txt -c cookies.txt options to provide the session authentication. NOTE the cookies will only be valid until the authentication timeout expires - might be six hours.
This example also works for ccm (Engineering Workflow Manager, EWM, formerly RTC) as well as DOORS Next and should work for Engineering Test Manager (ETM formerly known as RQM)
Related
I have set up an API using configured with auth protected endpoints as described in this excellent tutorial
https://blog.miguelgrinberg.com/post/restful-authentication-with-flask
My end user, however, wants to authenticate by passing a JSON and then remain authenticated until the session expires.
The current method of authentication uses headers, as in the tutorial
$ curl -u miguel:python -i -X GET http://127.0.0.1:5000/api/resource
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 30
Server: Werkzeug/0.9.4 Python/2.7.3
Date: Thu, 28 Nov 2013 20:02:25 GMT
{
"data": "Hello, miguel!"
}
The users want to send the following instead
curl -L -X POST 'https://api.org/auth/?json={"client_id":"CLIENT ID","client_secret":"CLIENT SECRET","grant_type":"password"}' -H 'Content-Type: application/json'
There is clearly a way to authenticate once and remain authenticated because flask-restx endpoints display the attached image when you try to use an #auth.login_required decorated endpoint. Does anyone know what code this manual login code triggers and whether I can replicate the process by passing data received into an endpoint via JSON?
I have considered an internal redirect or curl-request but this seems unnecessarily clunky
manual login via API
The username/password prompt in your image is implemented by web browsers when the server uses the Basic Authentication method. If your client is not a web browser, then there is no user interface to request username and password, you have to implement that yourself.
Your assertion that "there is clearly a way" to authenticate and remain authenticated for the duration of the session is incorrect. The HTTP protocol is stateless, which means that every request stands on its own. You think that session authentication is possible because in some situations the data that you as a client are not providing is automatically inserted by the web browser or HTTP client. Examples:
When you log in to a website and then the website remembers who you are as you navigate from page to page, the browser is inserting a session cookie into all the requests that the client sends. The server writes information about the client in the session, so that it can recover it every time a request from the client is received.
When you use the username/password Basic Authentication solution that you referenced in your question, the browser saves the username and password that you entered, and inserts an Authorization header with them into all successive requests sent during the session. From the side of the server, every request comes with a username and a password and needs to be verified from scratch.
Finally, the JSON example that you show appears to be based on the OAuth protocol. This is a fairly extensive solution with many different flows. The one that you use in your example is the Password grant, in which the client passes username and password and receives an access token in exchange. This access token must be provided in all successive requests you make.
If your client application runs in the browser, then the two options that you have for the browser to help out with the authentication are:
Use session cookies. With Flask, this can be done with the Flask-Login extension.
Use Basic Authentication, to let the browser prompt the user for credentials, which are then automatically sent in successive requests. This is fully supported by the Flask-HTTPAuth.
I'm noticing that when requests running in parallel modify Flask's session, only some keys are recorded. This happens both with Flask's default cookie session and with Flask-Session using the Redis backend. The project is not new, but this only became noticeable once many requests were happening at the same time for the same session.
import time
from flask import Flask, session
from flask_session import Session
app = Flask(__name__)
app.secret_key = "example"
app.config["SESSION_TYPE"] = "redis"
Session(app)
#app.route("/set/<value>")
def set_value(value):
"""Simulate long running task."""
time.sleep(1)
session[value] = "done"
return "ok\n"
#app.route("/keys")
def keys():
return str(session.keys()) + "\n"
The following shell script demonstrates the issue. Notice that all the requests complete, but only one key is present in the final listing, and it's different between test runs.
#!/bin/bash
# set session
curl -c 'cookie' http://localhost:5007/keys
# run parallel
curl -b 'cookie' http://localhost:5007/set/key1 && echo "done1" &
curl -b 'cookie' http://localhost:5007/set/key2 && echo "done2" &
curl -b 'cookie' http://localhost:5007/set/key3 && echo "done3" &
wait
# get result
curl -b 'cookie' http://localhost:5007/keys
$ sh test.sh
dict_keys(['_permanent'])
ok
ok
ok
done3
done1
done2
dict_keys(['_permanent', 'key2'])
$ sh test.sh
dict_keys(['_permanent'])
ok
done3
ok
ok
done2
done1
dict_keys(['_permanent', 'key1'])
Why aren't all the keys present after the requests finish?
Cookie-based sessions are not thread safe. Any given request only sees the session cookie sent with it, and only returns the cookie with that request's modifications. This isn't specific to Flask, it's how HTTP requests work.
You issue three requests in parallel. They all read the initial cookie that only contains the _permanent key, send their requests, and get a response that sets a cookie with their specific key. Each response cookie would have the _permanent key and the key_keyN key only. Whichever request finishes last writes to the file, overwriting previous data, so you're left with its cookie only.
In practice this isn't an issue. The session isn't really meant to store data that changes rapidly between requests, that's what a database is for. Things that modify the session, such as logging in, don't happen in parallel to the same session (and are idempotent anyway).
If you're really concerned about this, use a server-side session to store the data in a database. Databases are good at synchronizing writes.
You're already using Flask-Session and Redis, but digging into the Flask-Session implementation reveals why you have this issue. Flask-Session doesn't store each session key separately, it writes a single serialized value with all the keys. So it suffers the same issue as cookie-based sessions: only what was present during that request is put back into Redis, overwriting what happened in parallel.
In this case, it will be better to write your own SessionInterface subclass to store each key individually. You would override save_session to set all keys in session and delete any that aren't present.
For now, my idea is to validate the below request by writing in decorators.py before the request is passed into the init.py including the endpoints. But Im not sure of how I can write the validation code of request with flask. Would anyone help me write this code ?
This is the http request which will be sent from curl command.
AUTH_HEADER=`echo -n ${ID}:${SECRET}|base64`
curl ${URL_HEADER}/oauth/token -X POST -H "Authorization: Basic ${AUTH_HEADER}" –d "grant_type=xxx&scope=yyy"
If you are unsure, especially when it comes to security - do not try to invent things yourself.
For Flask, there is an excellent package Flask-Security which provides:
Session based authentication
Role management
Password hashing
Basic HTTP authentication
Token based authentication
Token based account activation (optional)
Token based password recovery / resetting (optional)
User registration (optional)
Login tracking (optional)
JSON/Ajax Support
I am trying to make a HTTP Request to a JSON API like https://api.github.com using tornado.httpclient and I found that it always responses with FORBIDDEN 403.
Simplifying, I make a request using the CLI with:
$ python -m tornado.httpclient https://api.github.com
getting a tornado.httpclient.HTTPError: HTTP 403: Forbidden.
In other hand, if I try to request this URL via browser or a simple $ curl https://api.github.com, the response is 200 OK and the proper JSON file.
What is causing this? Should I set some specific Headers on the tornado.httpclient request? What's the difference with a curl request?
You have to put user agent in the request, see Github API for more details:
All API requests MUST include a valid User-Agent header. Requests with
no User-Agent header will be rejected. We request that you use your
GitHub username, or the name of your application, for the User-Agent
header value. This allows us to contact you if there are problems
It might be an issue with their robots.txt. Maybe tornado.httpclient modifies the User-Agent in a way that makes it appear to be a web crawler? I'm not that familiar with it.
I faced similar issue & problem was with configurable-http-proxy so I killed its process & restarted jupyterhub
ps aux | grep configurable-http-proxy
if there are any pid's from above command, kill them with
kill -9 <PID>
and restart ``
I am trying to put together a bash or python script to play with the facebook graph API. Using the API looks simple, but I'm having trouble setting up curl in my bash script to call authorize and access_token. Does anyone have a working example?
Update 2018-08-23
Since this still gets some views and upvotes I just want to mention that by now there seems to exist a maintained 3rd party SDK: https://github.com/mobolic/facebook-sdk
Better late than never, maybe others searching for that will find it. I got it working with Python 2.6 on a MacBook.
This requires you to have
the Python facebook module installed: https://github.com/pythonforfacebook/facebook-sdk,
an actual Facebook app set up
and the profile you want to post to must have granted proper permissions to allow all the different stuff like reading and writing.
You can read about the authentication stuff in the Facebook developer documentation. See https://developers.facebook.com/docs/authentication/ for details.
This blog post might also help with this: http://blog.theunical.com/facebook-integration/5-steps-to-publish-on-a-facebook-wall-using-php/
Here goes:
#!/usr/bin/python
# coding: utf-8
import facebook
import urllib
import urlparse
import subprocess
import warnings
# Hide deprecation warnings. The facebook module isn't that up-to-date (facebook.GraphAPIError).
warnings.filterwarnings('ignore', category=DeprecationWarning)
# Parameters of your app and the id of the profile you want to mess with.
FACEBOOK_APP_ID = 'XXXXXXXXXXXXXXX'
FACEBOOK_APP_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
FACEBOOK_PROFILE_ID = 'XXXXXX'
# Trying to get an access token. Very awkward.
oauth_args = dict(client_id = FACEBOOK_APP_ID,
client_secret = FACEBOOK_APP_SECRET,
grant_type = 'client_credentials')
oauth_curl_cmd = ['curl',
'https://graph.facebook.com/oauth/access_token?' + urllib.urlencode(oauth_args)]
oauth_response = subprocess.Popen(oauth_curl_cmd,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE).communicate()[0]
try:
oauth_access_token = urlparse.parse_qs(str(oauth_response))['access_token'][0]
except KeyError:
print('Unable to grab an access token!')
exit()
facebook_graph = facebook.GraphAPI(oauth_access_token)
# Try to post something on the wall.
try:
fb_response = facebook_graph.put_wall_post('Hello from Python', \
profile_id = FACEBOOK_PROFILE_ID)
print fb_response
except facebook.GraphAPIError as e:
print 'Something went wrong:', e.type, e.message
Error checking on getting the token might be better but you get the idea of what to do.
Here you go, as simple as it can get. Doesn’t require any 3rd-party SDK etc.
Make sure Python 'requests' module is installed
import requests
def get_fb_token(app_id, app_secret):
url = 'https://graph.facebook.com/oauth/access_token'
payload = {
'grant_type': 'client_credentials',
'client_id': app_id,
'client_secret': app_secret
}
response = requests.post(url, params=payload)
return response.json()['access_token']
Easy! Just use facebook-sdk.
import facebook
app_id = 'YOUR_APP_ID'
app_secret = 'YOUR_APP_SECRET'
graph = facebook.GraphAPI()
# exactly what you're after ;-)
access_token = graph.get_app_access_token(app_id, app_secret)
You first need to set up an application. The following will then spit out an access token given your application ID and secret:
> curl -F type=client_cred -F client_id=[...] -F client_secret=[...] https://graph.facebook.com/oauth/access_token
Since a web browser needs to be involved for the actual authorization, there is no such thing as a "standalone script" that does it all. If you're just playing with the API, or are writing a script to automate something yourself, and want a access_token for yourself that does not expire, you can grab one here: http://fbrell.com/auth/offline-access-token
There IS a way to do it, I've found it, but it's a lot of work and will require you to spoof a browser 100% (and you'll likely be breaking their terms of service)
Sorry I can't provide all the details, but the gist of it:
assuming you have a username/password for a facebook account, go curl for the oauth/authenticate... page. Extract any cookies returned in the "Set-Cookie" header and then follow any "Location" headers (compiling cookies along the way).
scrape the login form, preserving all fields, and submit it (setting the referer and content-type headers, and inserting your email/pass) same cookie collection from (1) required
same as (2) but now you're going to need to POST the approval form acquired after (2) was submitted, set the Referer header with thr URL where the form was acquired.
follow the redirects until it sends you back to your site, and get the "code" parameter out of that URL
Exchange the code for an access_token at the oauth endpoint
The main gotchas are cookie management and redirects. Basically, you MUST mimic a browser 100%. I think it's hackery but there is a way, it's just really hard!
s29 has the correct answer but leaves some steps to solve. The following script demonstrates a working script for acquiring an access token using the Facebook SDK:
__requires__ = ['facebook-sdk']
import os
import facebook
def get_app_access_token():
client = facebook.GraphAPI()
return client.get_app_access_token(
os.environ['FACEBOOK_APP_ID'],
os.environ['FACEBOOK_APP_SECRET'],
)
__name__ == '__main__' and print(get_app_access_token())
This script expects the FACEBOOK_APP_ID and FACEBOOK_APP_SECRET environment variables are set to the values for your app. Feel free to adapt that technique to load those values from a different source.
You must first install the Facebook SDK (pip install facebook-sdk; python get-token.py) or use another tool like rwt to invoke the script (rwt -- get-token.py).
Here is the Python Code. Try running some of these examples on command line, they work fine for me. See also — http://www.pythonforfacebook.com/