PK!1jira_oauth_generator/access_using_jira_library.pyfrom jira import JIRA from configparser import ConfigParser import argparse import os from pathlib import Path parser = argparse.ArgumentParser() parser.add_argument("jira_environment", help = "Enter Jira Environment where you want to run this library. Options: dev/prod") args = parser.parse_args() print() print(f"Reading OAuth from {Path.home()}/.oauthconfig/.oauth_jira_config.{args.jira_environment}") config = ConfigParser() config.read(Path.home() / f".oauthconfig/.oauth_jira_config.{args.jira_environment}") jira_url = config.get("server_info", "jira_base_url") oauth_token = config.get("oauth_token_config", "oauth_token") oauth_token_secret=config.get("oauth_token_config", "oauth_token_secret") consumer_key = config.get("oauth_token_config", "consumer_key") test_issue_key = config.get("jira_oauth_generator", "test_issue_key") rsa_private_key = None # Load RSA Private Key file. with open( Path.home() /'.oauthconfig/oauth.pem', 'r') as key_cert_file: rsa_private_key = key_cert_file.read() if jira_url[-1] == '/': jira_url = jira_url[0:-1] oauth_dict = { 'access_token' : oauth_token, 'access_token_secret': oauth_token_secret, 'consumer_key': consumer_key, 'key_cert': rsa_private_key } ajira = JIRA(oauth=oauth_dict, server = jira_url) print("") print(f"Reteriving Issue: {test_issue_key}") issue = ajira.issue(test_issue_key, fields ='summary,comment') print (f"Issue:{test_issue_key}, Summary: {issue.fields.summary}") print("") print("Reteriving 1st three Jira Projects available to you:") projects = ajira.projects() keys = sorted([project.key for project in projects])[2:5] print("First 3 Projects are %s" %keys) print("")PK!߲P 5jira_oauth_generator/access_using_requests_package.py''' Sample program demnostrating how to access Jira using OAuth1 tokens and Requests library! * It reads list of projects available to user and prints name of first project * Adds comment on given Issue with test_issue_key ''' from configparser import ConfigParser import argparse import requests from requests_oauthlib import OAuth1 import os from pathlib import Path def get_jira_oauth_init_parameters(jira_env): config = ConfigParser() print() print(f"Reading OAuth from {Path.home()}/.oauthconfig/.oauth_jira_config.{jira_env}") config.read(Path.home() / f".oauthconfig/.oauth_jira_config.{jira_env}") jira_url = config.get("server_info", "jira_base_url") oauth_token = config.get("oauth_token_config", "oauth_token") oauth_token_secret=config.get("oauth_token_config", "oauth_token_secret") consumer_key = config.get("oauth_token_config", "consumer_key") test_issue_key = config.get("jira_oauth_generator", "test_issue_key") rsa_private_key = None # Load RSA Private Key file. with open( Path.home() /'.oauthconfig/oauth.pem', 'r') as key_cert_file: rsa_private_key = key_cert_file.read() oauth = OAuth1(client_key = consumer_key, rsa_key = rsa_private_key, signature_method='RSA-SHA1', resource_owner_key=oauth_token, resource_owner_secret=oauth_token_secret ) return { "oauth1_object" : oauth, "jira_url" : jira_url, "test_issue_key": test_issue_key } def get_jira_session(init_dict): session = requests.Session() session.auth = init_dict["oauth1_object"] session.headers.update({'X-Atlassian-Token': 'nocheck'}) return session def get_jira_projects(session, base_url): print("") print("Reteriving 1st Jira Project available to you:") jira_projects_url = base_url + '/rest/api/2/project' response = jira_session.get(jira_projects_url) response.raise_for_status() # Get First Project name from list of Projects reterived. print(response.json()[0]['name']) print("") def add_comment_to_issue(session, base_url, issue_key): print("") print(f"Adding comment to issue {issue_key}") try: post_data_dict = {} post_data_dict["body"] = "This is a test comment using bare REST api." post_result = session.post(f"{base_url}/rest/api/2/issue/{issue_key}/comment", json = post_data_dict) post_result.raise_for_status() print("Comment successfully added. Please verify through browser!") print("") except requests.exceptions.HTTPError as err: print (err) if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("jira_environment", help = "Enter Jira Environment where you want to run this library. Options: dev/prod") args = parser.parse_args() init_dict = get_jira_oauth_init_parameters(args.jira_environment) base_url = init_dict["jira_url"] test_issue_key = init_dict["test_issue_key"] jira_session = get_jira_session(init_dict) # Get 1st Jira Project Name get_jira_projects(jira_session, base_url) # Add comment to given issue add_comment_to_issue(jira_session, base_url, test_issue_key)PK!;^ğ&&2jira_oauth_generator/jira_oauth_token_generator.py""" * Original implementation is available here: https://bitbucket.org/atlassian_tutorial/atlassian-oauth-examples under python/app.py * Copied here as jira_oauth_token_generator.py with modifications: * Since we are not able to resolve SSL Certification problem, let's disable ssl certificate validation for each REST api call. client.disable_ssl_certificate_validation = True * Strangely first time (before you approve request in browser) when you access data_url, browser returns 200 response with content of zero bytes instead of 401 response as original code says. Hence I've commented out response code validation for this part. * Also I've refactored and removed SignatureMethod_RSA_SHA1 into it's own file. This way we can import it into any other python program! * Python 3 compatible! * Pre-Requisities: * You have generated RSA Private and Public keys and stored them into files "oauth.pem" and "oauth.pub" respectively. * config/ directory contain "starter_oauth.config" file with following details: jira_base_url= consumer_key= * """ from configparser import ConfigParser from pathlib import Path from urllib import parse import base64 import json from tlslite.utils import keyfactory import oauth2 as oauth oauth_config_dir_path = Path.home() / '.oauthconfig' starter_oauth_config_file = oauth_config_dir_path / 'starter_oauth.config' rsa_private_key_file_path = oauth_config_dir_path / 'oauth.pem' rsa_public_key_file_path = oauth_config_dir_path / 'oauth.pub' # noinspection PyShadowingNames def get_access_token_url(base_url): return base_url + '/plugins/servlet/oauth/access-token' # noinspection PyShadowingNames def get_data_url(base_url, test_jira_issue): return base_url + f'/rest/api/2/issue/{test_jira_issue}?fields=summary' def read_rsa_private_key(path): with open(file=path, mode='r') as f: return f.read() def read_rsa_public_key(path): with open(file=path, mode='r') as key_cert_file: return key_cert_file.read() # noinspection PyPep8Naming class SignatureMethod_RSA_SHA1(oauth.SignatureMethod): name = 'RSA-SHA1' # noinspection PyShadowingNames def __init__(self, rsa_private_key): self.rsa_private_key = rsa_private_key.strip() # noinspection PyShadowingNames def signing_base(self, request, consumer, token): if not hasattr(request, 'normalized_url') or request.normalized_url is None: raise ValueError("Base URL for request is not set.") sig = ( oauth.escape(request.method), oauth.escape(request.normalized_url), oauth.escape(request.get_normalized_parameters()), ) key = '%s&' % oauth.escape(consumer.secret) if token: key += oauth.escape(token.secret) raw = '&'.join(sig) return key, raw # noinspection PyShadowingNames def sign(self, request, consumer, token): """Builds the base signature string.""" key, raw = self.signing_base(request, consumer, token) privatekey = keyfactory.parsePrivateKey(self.rsa_private_key) signature = privatekey.hashAndSign(bytearray(raw, 'utf8')) return base64.b64encode(signature) def get_jira_oauth_init_parameters(): config = ConfigParser() config.optionxform = str # Read config file as case insensitive config.read(starter_oauth_config_file) jira_url = config.get("oauth_config", "jira_base_url") consumer_key = config.get("oauth_config", "consumer_key") # noinspection PyShadowingNames test_jira_issue = config.get("oauth_config", "test_jira_issue") rsa_private_key = read_rsa_private_key(path=rsa_private_key_file_path) rsa_public_key = read_rsa_public_key(path=rsa_public_key_file_path) return { "consumer_key": consumer_key, "jira_base_url": jira_url, "rsa_private_key": rsa_private_key, "rsa_public_key": rsa_public_key, "test_jira_issue": test_jira_issue } # noinspection PyShadowingNames def generate_request_token_and_auth_url(base_url, consumer_key, consumer_secret, rsa_private_key): request_token_url = base_url + '/plugins/servlet/oauth/request-token' authorize_url = base_url + '/plugins/servlet/oauth/authorize' consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret) client = oauth.Client(consumer=consumer) client.set_signature_method(SignatureMethod_RSA_SHA1(rsa_private_key=rsa_private_key)) # Step 1: Get a request token. This is a temporary token that is used for # having the user authorize an access token and to sign the request to obtain # said access token. resp, content = client.request(request_token_url, "POST") if resp['status'] != '200': raise Exception("Invalid response %s: %s" % (resp['status'], content)) # If output is in bytes. Let's convert it into String. if type(content) == bytes: content = content.decode('UTF-8') request_token = dict(parse.parse_qsl(content)) url = f"{authorize_url}?oauth_token={request_token['oauth_token']}" return consumer, request_token, url # noinspection PyShadowingNames def print_url_and_ask_for_continue(url): # Step 2: Redirect to the provider. Since this is a CLI script we do not # redirect. In a web application you would redirect the user to the URL # below. print(f"Go to the following link in your browser: {url}") # After the user has granted access to you, the consumer, the provider will # redirect you to whatever URL you have told them to redirect to. You can # usually define this in the oauth_callback argument as well. accepted = 'n' while accepted.lower() == 'n': accepted = input('Have you authorized me? (y/n) ') # noinspection PyShadowingNames def generate_access_token(rsa_private_key, consumer, request_token, access_token_url): # Step 3: Once the consumer has redirected the user back to the oauth_callback # URL you can request the access token the user has approved. You use the # request token to sign this request. After this is done you throw away the # request token and use the access token returned. You should store this # access token somewhere safe, like a database, for future use. token = oauth.Token(key=request_token['oauth_token'], secret=request_token['oauth_token_secret']) # token.set_verifier(oauth_verifier) client = oauth.Client(consumer=consumer, token=token) client.set_signature_method(SignatureMethod_RSA_SHA1(rsa_private_key=rsa_private_key)) resp, content = client.request(uri=access_token_url, method="POST") # Response is coming in bytes. Let's convert it into String. # If output is in bytes. Let's convert it into String. if type(content) == bytes: content = content.decode('UTF-8') return dict(parse.parse_qsl(qs=content)) # noinspection PyShadowingNames def check_access_token(access_token, consumer, rsa_private_key, data_url, test_jira_issue): print(f"Accessing {test_jira_issue} using generated OAuth tokens:") # Now lets try to access the same issue again with the access token. We should get a 200! token = oauth.Token(key=access_token['oauth_token'], secret=access_token['oauth_token_secret']) client = oauth.Client(consumer=consumer, token=token) client.set_signature_method(SignatureMethod_RSA_SHA1(rsa_private_key=rsa_private_key)) resp, content = client.request(uri=data_url, method="GET") if resp['status'] != '200': raise Exception("Should have access!") print("Success!") # If output is in bytes. Let's convert it into String. if type(content) == bytes: content = content.decode('UTF-8') json_content = json.loads(s=content) print(f'Issue key: {json_content["key"]}, Summary: {json_content["fields"]["summary"]} ') if __name__ == '__main__': init_dict = get_jira_oauth_init_parameters() base_url = init_dict['jira_base_url'] consumer_key = init_dict["consumer_key"] consumer_secret = init_dict["rsa_public_key"] rsa_private_key = init_dict['rsa_private_key'] test_jira_issue = init_dict['test_jira_issue'] data_url = get_data_url(base_url=base_url, test_jira_issue=test_jira_issue) consumer, request_token, url = generate_request_token_and_auth_url(base_url=base_url, consumer_key=consumer_key, consumer_secret=consumer_secret, rsa_private_key=rsa_private_key) print(f"Request Token: oauth_token={request_token['oauth_token']}, " f"oauth_token_secret={request_token['oauth_token_secret']}") print() access_token = {'oauth_problem': True} while 'oauth_problem' in access_token: print_url_and_ask_for_continue(url=url) access_token = generate_access_token(rsa_private_key=rsa_private_key, consumer=consumer, request_token=request_token, access_token_url=get_access_token_url(base_url=base_url)) print() print(f"Access Token: oauth_token={access_token['oauth_token']}, " f"oauth_token_secret={access_token['oauth_token_secret']}") print("You may now access protected resources using the access tokens above.") print() check_access_token(access_token=access_token, consumer=consumer, rsa_private_key=rsa_private_key, data_url=data_url, test_jira_issue=test_jira_issue) PK!HnHTU*jira_oauth_generator-0.1.7.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!HV7 -jira_oauth_generator-0.1.7.dist-info/METADATAXr8}W`+SeQŹbOl'QnHTJHH[Pac_K4@Ix*{I%It7r޸J,vDؕT3 M n?hQ$\z)a(f&[MD>Dy/D4r>153i$Df72ƾ~ùh}Dfdž`qTB7WXG`Yk-R`K)zl4\eKѳSF\s%[U6S<3GN+Q|p;[HmhՇ stx=Sw"N[Z&#~І+A 8B[OV B[OSk9PbU$ :[e cBRrvV![uRerIZvدJh;W= 'U/'(Z?C0J UJyZ/FQhKAdj^0YODl8e7'u,p@opaa kwKa+Ќ3-AFeC%slgi\rЙ7 ]Duyþ S䌧{Qa{;nc%8y))xNӥTY@/Y,݊H#hC&5W1-g%6sL-XZ(ߗ4HqrbB[P.s&KXCQM:`8abb` W*`R0uaNѱ5 n$%L EPR*^@)׀& mʘtXA.߷Fg9Z2DiYaZn餪RLh*jhD::3p$3sB3~RD>{ޫw[@c1='Awu~vr2ЏP\{hF;`S\٣BQ;LRmѴxsiR s>9ɛl'HW>{W%ŐaQH0Xű9Oہ.{rj>dG`=OQ̰k1)_2MC[i5isp(vIXeBښ &15 L 5lIAP %D\#x> ʼbEp:5yh$NqфGctŐp66A»gE1>A%@wC*?& #%⺎2قħ*Vz  e3!CÍaf72 $}XlYu!6WB]^U&8Z VU *D@c-'6'FJ~x:9q 4;iaޕ(ZT1IѬe$dWng[݄k1FMVK37xQ>Sݲoq1,j Ӵv47INU3e+Px(NߜFˏAr_~m~.Zg$Ӎ~`\#DȏկDIFQMeUn(Qܮ7r7o@IͣWncSj7)D,Env+7Vo[gP&>l"橓8 ֭PMoڝfZG?ix>z5Uz\*^hx1ִ)qg|Ӧj;t1X }Zegbd(wm[%>irpqr6jۋ{?W&jvd1̩e9pJئx)dp?xQ:)`ބػJ\d8mmok\bjr&B/ Az(o/e_̻9~9g84b>U\;BK1wN0,^V]m Y;fG!|h\N J`/`(/PK!1jira_oauth_generator/access_using_jira_library.pyPK!߲P 5jira_oauth_generator/access_using_requests_package.pyPK!;^ğ&&2jira_oauth_generator/jira_oauth_token_generator.pyPK!HnHTU*:jira_oauth_generator-0.1.7.dist-info/WHEELPK!HV7 -z;jira_oauth_generator-0.1.7.dist-info/METADATAPK!HEqN8+Djira_oauth_generator-0.1.7.dist-info/RECORDPK.F