Access JIRA from python - python

I am trying to access jira from python at my work place and the basic operation I intend to do is to fetch/create/update jira issues. I looked at the template code online and am trying to use that, but no luck. I have already installed jira api using pip.
pip install jira
#!/usr/bin/python
from jira import JIRA
options = {'server' : 'https://jira.mycompany.com/rest/api/2'}
jira = JIRA(options)
projects = jira.projects()
print (projects)
And this is its output:
Traceback (most recent call last):
File "JiraTest.py", line 7, in <module>
jira = JIRA(options)
File "C:\Anaconda3\lib\site-packages\jira\client.py", line 317, in __init__
si = self.server_info()
File "C:\Anaconda3\lib\site-packages\jira\client.py", line 1771, in server_info
j = self._get_json('serverInfo')
File "C:\Anaconda3\lib\site-packages\jira\client.py", line 2172, in _get_json
r = self._session.get(url, params=params)
File "C:\Anaconda3\lib\site-packages\jira\resilientsession.py", line 150, in get
return self.__verb('GET', url, **kwargs)
File "C:\Anaconda3\lib\site-packages\jira\resilientsession.py", line 146, in __verb
raise_on_error(response, verb=verb, **kwargs)
File "C:\Anaconda3\lib\site-packages\jira\resilientsession.py", line 56, in raise_on_error
r.status_code, error, r.url, request=request, response=r, **kwargs)
jira.exceptions.JIRAError: JiraError HTTP 404 url:https://jira.mycompany.com/rest/api/2/rest/api/2/serverInfo
response headers = {'Date': 'Sat, 29 Jul 2017 22:42:31 GMT', 'Content-Length': '0', 'Server': 'Apache-Coyote/1.1'}
response text =
`
I know I am doing something wrong here and hence this are the things I want to ask:
How to determine jira server at your work place.
Do the jira administrator need to enable rest api calls or something else from admin login? Is there a way to determine if it is disabled from our code?
Is there anything else I have to install apart from just installing jira through pip.
How to deal with login credentials. I am sure there is a better way than specifying username/password in your .py file. Can someone point me on where to find that info.
Thanks.

I'm not sure what version of the jira-python client you're using but to instantiate a JIRA object, you don't pass the server inside the "options" parameter (and you definitely don't put the path to the REST api). According to the docs:
class jira.JIRA(server=None, options=None, basic_auth=None, oauth=None, jwt=None, kerberos=False, validate=False, get_server_info=True, async=False, logging=True, max_retries=3, proxies=None, timeout=None)
So your instantiation should look like:
from jira.client import JIRA
jira = JIRA('https://jira.mycompany.com')
If you need to auth, then it would be:
jira = JIRA('https://jira.mycompany.com', basic_auth=(username, password))

The server URL should not contain the REST endpoint, this is added automatically by python-jira.
If you check the error you're getting, you'll see that the rest path is listed twice, this is why you're getting the 404.
So, changing your code to:
#!/usr/bin/python
from jira import JIRA
options = {'server' : 'https://jira.mycompany.com'}
jira = JIRA(options)
projects = jira.projects()
print (projects)
should do the trick.
Please let me know if there are other problems.

To confirm you have the right JIRA server, browse to the root URL https://jira.mycompany.com and ensure you can see the login screen and log in (this confirms your username and password work too).
Access to the JIRA REST API must be enabled before you can use it. To test it, try communicating with it using curl, e.g.:
curl -u "username:password" -X GET -H "Content-Type: application/json" https://jira.mycompany.com/rest/api/2/issue/KEY-666
As long as Python can communicate with servers using GET and POST, you shouldn't need anything else.
For username and password I just have the script ask at the command line with an instruction that doesn't show the password. I use node.js but I am sure Python has something similar. Or keep them in a separate file the script reads in, but make sure you never check the file in!

Related

Postman API request in Python

I am trying to web-scrape data from https://www.mcmaster.com. They have provided me with a .pfx file and a passphrase. When making a GET request on Postman using their .json file, I input my website login/password and upload the .pfx certificate with its passphrase and everything works fine. Now I am trying to do this same thing but in Python, but am a bit unsure.
Here is my current Python code, I am unsure where I would put the website email/password login and how to successfully do a GET request.
import requests_pkcs12
from requests_pkcs12 import get
r = get('https://api.mcmaster.com/v1/login', pkcs12_filename='Schallert.pfx', pkcs12_password='mcmasterAPI#1901')
response = requests_pkcs12.get(r)
print(response.text)
Here is how I have it setup in Postman (Website email/pw login)
.PFX Certificate page
Postman has a built in feature where it will convert requests into code. You can do it like so:
On the far right click the Code Snippet Button (</>)
Once you are on that page, there is two available python options
Then all you need to do is copy the code into a Python file and add all your customizations (Should be already optimized)
One thing I’ll warn you about though is the URL. Postman doesn’t add
http:// or https:// to the URL, which means Python will throw a No
Scheme Supplied error.
Available Packages for Auto Conversion:
Requests
http.client
Meaning you will have to use a different package instead of requests_pkcs12
After a quick web search, it looks like you need to create a temporary certificate as a .pem file, which is then passed to the request.
from contextlib import contextmanager
from pathlib import Path
from tempfile import NamedTemporaryFile
import requests
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
from cryptography.hazmat.primitives.serialization.pkcs12 import load_key_and_certificates
#contextmanager
def pfx_to_pem(pfx_path, pfx_password):
pfx = Path(pfx_path).read_bytes()
private_key, main_cert, add_certs = load_key_and_certificates(pfx, pfx_password.encode('utf-8'), None)
with NamedTemporaryFile(suffix='.pem') as t_pem:
with open(t_pem.name, 'wb') as pem_file:
pem_file.write(private_key.private_bytes(Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()))
pem_file.write(main_cert.public_bytes(Encoding.PEM))
for ca in add_certs:
pem_file.write(ca.public_bytes(Encoding.PEM))
yield t_pem.name
with pfx_to_pem('your pfx file path', 'your passphrase') as cert:
requests.get(url, cert=cert, data=payload)
The package requests_pkcs12 is a wrapper written above the requests package. So, all the parameters that accept requests will accept by the requests_pkcs12.
Here is the source code proof for that. https://github.com/m-click/requests_pkcs12/blob/master/requests_pkcs12.py#L156
Also, from your screenshots, I understood that you are using POST not GET.
import json
from requests_pkcs12 import post
url = "https://api.mcmaster.com/v1/login"
payload = {'Username': 'yourusername',
'Password': 'yourpassword'}
resp = post(url, pkcs12_filename='Schallert.pfx', pkcs12_password='mcmasterAPI#1901', data=json.dumps(payload))
print(resp)
Footnote: I hope the password mcmasterAPI#1901 it's a fake one. if not please don't share any credentials in the platform.

I am trying to send a request to OVH'S API, but when trying to do this i get an error

I am trying to send a request to OVH's API using their python API wrapper to check if my IP address is in mitigation, when trying to do this I get the following error:
result = client.get(f'/ip/{quote(ipblock)}/mitigation/{ipOnMitigation}', _need_auth=False)
File "/usr/local/lib/python3.8/dist-packages/ovh/client.py", line 347, in get
return self.call('GET', _target, None, _need_auth)
File "/usr/local/lib/python3.8/dist-packages/ovh/client.py", line 442, in call
raise ResourceNotFoundError(json_result.get('message'),
ovh.exceptions.ResourceNotFoundError: Got an invalid (or empty) URL
Here is my code
import json
import ovh
from urllib.parse import quote
client = ovh.Client(
endpoint='ovh-ca',
application_key='xxxxxxx',
application_secret='xxxxxxx',
consumer_key='xxxxxxxxx'
)
ipblock = "xxxx/28"
ipOnMitigation = "xxx/32"
result = client.get(f'/ip/{quote(ipblock)}/mitigation/{ipOnMitigation}', _need_auth=False)
# Pretty print
print(json.dumps(result))
Maybe the endpoint needs to look like a path (ie /ovh-ca)?
Edit: the exception indicates that something is wrong with the request. If it’s not the endpoint, it must be some other parameter your passing to the client (or not passing). I see you have a app key/secret pair. Does this endpoint require a consumer secret (to build a request signature for instance) also?

Django REST authentication from desktop app

I have been trying to use the Django-REST authentication to validate the user name /password given in a desktop app.
On the server side, I have installed the following DJANGO-REST-FRAMEWORK-JWT package found here:
https://github.com/GetBlimp/django-rest-framework-jwt
I have gone through the example and when I run the following on the command line get a token as a response:
curl -X POST -d "username=luca&password=letmein123" http://localhost:8000/api-token-auth/
And I get:
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InBhbmthaiIsInVzZXJfaWQiOjIsImVtYWlsIjoiIiwiZXhwIjoxNDc5MTE5NzQ2fQ.RA085m-YSnGFheykCCxSVxI_9rW9AC9kEaOkUB5Gm0A"}
I tried something like:
import requests
resp = requests.post('http://127.0.0.1:8000/api-token-auth/', data={}, auth=('luca', 'letmein123'))
However, this always returns response code 400 with Bad request
My question is how can I do that from my desktop python app. I basically want to call the same API with the username and passord and be able to process the response and access protected APIs.
The auth parameter of requests.request is by default meant for Basic/Digest/Custom HTTP Auth, analogous to the -u, --user <user:password> parameter of curl.
You could define your own custom Authentication class to achieve the desired result, but the basic way to achieve the same result as your original curl request is:
resp = requests.post(
'http://localhost:8000/api-token-auth/',
data={"username": "luca", "password": "letmein123"})
The data dictionary can alternatively be supplied as json by using the json parameter if you prefer (the request would be different, but also supported by Django REST framework JWT).
You can then use the token (extracted with token = resp.json()['token']) to access the restricted urls as following:
requests.post(
'http://localhost:8000/some-personal-function/',
json={"foo": 42},
headers={'Authorization': 'JWT ' + token})
By the way looking at response.text might help finding the reason, which would, in the case of your 400 response, contain the following:
'{"username":["This field is required."],"password":["This field is required."]}'

Redirect to OAuth URL with headers

I'm trying to write a Python 3.5 Flask application that redirects a user to an OAuth URL, for authentication / authorization. As part of that redirection, I have to include the Authorization header. The built-in redirect() method in Flask doesn't seem to support adding HTTP headers.
What's the proper way of handling this in such an application?
You will need to build your own response object to add headers. You can check out the docs here: http://docs.python-requests.org/en/master/api/#requests.Response
A simple example for your use case would be something like:
response = Response(headers={'Authorization': 'whatever'},
is_redirect=True,
url="https://your-redirected-url.com")
return response
Edit: Further info
Also, I would check out https://github.com/lepture/flask-oauthlib if you are interested in using a library. It has support for oAuth1 and oAuth2 and it is relatively easy to setup with a standard Flask app.
Edit: Another way of doing it
This morning I remembered a simpler way to do this. You can call the redirect function and it will return a flask Response object. Then you are able to set the headers on that newly created object.
response = redirect('https://url')
response.headers = {'authorization': 'whatever'}
return response

ServiceNow - How to use SOAP to download reports

I need to automate download of reports from serviceNow.
I've been able to automate it using python and selenium and win32com by following method.
https://test.service-now.com/sys_report_template.do?CSV&jvar_report_id=92a....7aa
And using selenium to access serviceNow as well as modify firefox default download option to dump the file to a folder on windows machine.
However, Since all of this may be ported to a linux server , we would like to port it to SOAP or CURL.
I came across serviceNow libraries for python here.
I tried it out and following code is working if I set login , password and instance-name as listed at the site using following from ServiceNow.py
class Change(Base):
__table__ = 'change_request.do'
and following within clientside script as listed on site.
# Fetch changes updated on the last 5 minutes
changes = chg.last_updated(minutes=5)
#print changes client side script.
for eachline in changes:
print eachline
However, When I replace URL with sys_report_template.do, I am getting error
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\SOAPpy\Parser.py", line 1080, in _parseSOAP
parser.parse(inpsrc)
File "C:\Python27\Lib\xml\sax\expatreader.py", line 107, in parse
xmlreader.IncrementalParser.parse(self, source)
File "C:\Python27\Lib\xml\sax\xmlreader.py", line 125, in parse
self.close()
File "C:\Python27\Lib\xml\sax\expatreader.py", line 220, in close
self.feed("", isFinal = 1)
File "C:\Python27\Lib\xml\sax\expatreader.py", line 214, in feed
self._err_handler.fatalError(exc)
File "C:\Python27\Lib\xml\sax\handler.py", line 38, in fatalError
raise exception
SAXParseException: <unknown>:1:0: no element found
Here is relevent code
from servicenow import ServiceNow
from servicenow import Connection
from servicenow.drivers import SOAP
# For SOAP connection
conn = SOAP.Auth(username='abc', password='def', instance='test')
rpt = ServiceNow.Base(conn)
rpt.__table__ = "sys_report_template.do?CSV"
#jvar_report_id replaced with .... to protect confidentiality
report = rpt.fetch_one({'jvar_report_id': '92a6760a......aas'})
for eachline in report:
print eachline
So, my question is , what can be done to make this work?
I looked on web for resources and help, but didn't find any.
Any help is appreciated.
After much research I was able to use following method to get report in csv format from servicenow. I thought I will post over here in case anyone else runs into similar issue.
import requests
import json
# Set the request parameters
url= 'https://myinstance.service-now.com/sys_report_template.do?CSV&jvar_report_id=929xxxxxxxxxxxxxxxxxxxx0c755'
user = 'my_username'
pwd = 'my_password'
# Set proper headers
headers = {"Accept":"application/json"}
# Do the HTTP request
response = requests.get(url, auth=(user, pwd), headers=headers )
response.raise_for_status()
print response.text
response.text now has report in csv format.
I need to next figure out, how to parse the response object to extract csv data in correct format.
Once done, I will post over here. But for now this answers my question.
I tried this and its working as expected.
`import requests
import json
url= 'https://myinstance.service-now.com/sys_report_template.do?CSV&jvar_report_id=929xxxxxxxxxxxxxxxxxxxx0c755'
user = 'my_username'
pwd = 'my_password'
response = requests.get(url, auth=(user, pwd), headers=headers )
file_name = "abc.csv"
with open(file_name, 'wb') as out_file:
out_file.write(response.content)
del response`

Categories