def _refresh_token(self, keychain, connected_app): if keychain: # it might be none'd and caller adds connected_app connected_app = keychain.get_service("connected_app") if connected_app is None: raise AttributeError( "No connected app or keychain was passed to refresh_oauth_token." ) client_id = self.client_id client_secret = self.client_secret if not client_id: client_id = connected_app.client_id client_secret = connected_app.client_secret sf_oauth = self.SalesforceOAuth2( client_id, client_secret, connected_app. callback_url, # Callback url isn't really used for this call auth_site=self.instance_url, ) resp = sf_oauth.refresh_token(self.refresh_token) if resp.status_code != 200: raise SalesforceCredentialsException( f"Error refreshing OAuth token: {resp.text}") return safe_json_from_response(resp)
def _load_userinfo(self): headers = {"Authorization": "Bearer " + self.access_token} response = requests.get(self.instance_url + "/services/oauth2/userinfo", headers=headers) if response != self.config.get("userinfo", {}): config_data = safe_json_from_response(response) self.config.update({"userinfo": config_data})
def __call__(self): url = self._get_redirect_url() self._launch_browser(url) self._create_httpd() print( f"Spawning HTTP server at {self.callback_url} with timeout of {self.httpd.timeout} seconds.\n" + "If you are unable to log in to Salesforce you can " + "press ctrl+c to kill the server and return to the command line.") self.httpd.handle_request() self._check_response(self.response) return safe_json_from_response(self.response)
def latest_api_version(self): if not self._latest_api_version: headers = {"Authorization": "Bearer " + self.access_token} response = requests.get(self.instance_url + "/services/data", headers=headers) try: version = safe_json_from_response(response)[-1]["version"] except (KeyError, IndexError, TypeError): raise CumulusCIException( f"Cannot decode API Version `{response.text[0:100]}``") self._latest_api_version = str(version) return self._latest_api_version
def _call_api(self, method, path, collect_pages=False, **kwargs): next_url = self.base_url + path results = [] while next_url is not None: response = self.api.request(method, next_url, **kwargs) if response.status_code == 400: raise requests.exceptions.HTTPError(response.content) response = safe_json_from_response(response) if "links" in response and collect_pages: results.extend(response["data"]) next_url = response["links"]["next"] else: return response return results
def get_pull_requests_by_commit(github, repo, commit_sha): endpoint = ( github.session.base_url + f"/repos/{repo.owner.login}/{repo.name}/commits/{commit_sha}/pulls") response = github.session.get( endpoint, headers={"Accept": "application/vnd.github.groot-preview+json"}) json_list = safe_json_from_response(response) # raises github3.exceptions.IncompleteResposne # when these are not present for json in json_list: json["body_html"] = "" json["body_text"] = "" return [ShortPullRequest(json, github) for json in json_list]
def _enqueue_test_run(self, class_ids): if isinstance(class_ids, dict): body = { "tests": [{ "classId": class_id, "testMethods": class_ids[class_id] } for class_id in class_ids] } else: body = {"classids": ",".join(class_ids)} return safe_json_from_response( self.tooling._call_salesforce( method="POST", url=self.tooling.base_url + "runTestsAsynchronous", json=body, ))
def _check_result(self, result): # anon_results is an ExecuteAnonymous Result # https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/sforce_api_calls_executeanonymous_result.htm anon_results = safe_json_from_response(result) # A result of `None` (body == "null") with a 200 status code # means that a gack occurred. if anon_results is None: raise SalesforceException( "Anonymous Apex returned the result `null`. " "This often indicates a gack occurred." ) if not anon_results["compiled"]: raise ApexCompilationException( anon_results["line"], anon_results["compileProblem"] ) if not anon_results["success"]: raise ApexException( anon_results["exceptionMessage"], anon_results["exceptionStackTrace"] )
def jwt_session(client_id, private_key, username, url=None, auth_url=None): """Complete the JWT Token Oauth flow to obtain an access token for an org. :param client_id: Client Id for the connected app :param private_key: Private key used to sign the connected app's certificate :param username: Username to authenticate as :param url: Org's instance_url """ if auth_url: aud = (SANDBOX_LOGIN_URL if auth_url.startswith(SANDBOX_LOGIN_URL) else PROD_LOGIN_URL) else: aud = PROD_LOGIN_URL if url is None: url = PROD_LOGIN_URL else: m = SANDBOX_DOMAIN_RE.match(url) if m is not None: # sandbox aud = SANDBOX_LOGIN_URL # There can be a delay in syncing scratch org credentials # between instances, so let's use the specific one for this org. instance = m.group(2) url = f"https://{instance}.salesforce.com" payload = { "alg": "RS256", "iss": client_id, "sub": username, "aud": aud, "exp": timegm(datetime.utcnow().utctimetuple()), } encoded_jwt = jwt.encode(payload, private_key, algorithm="RS256") data = { "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion": encoded_jwt, } headers = {"Content-Type": "application/x-www-form-urlencoded"} token_url = urljoin(url, "services/oauth2/token") response = requests.post(url=token_url, data=data, headers=headers) return safe_json_from_response(response)
def __call__(self): url = self._get_redirect_url() self._launch_browser(url) self._create_httpd() print( f"Spawning HTTP server at {self.callback_url} with timeout of {self.httpd.timeout} seconds.\n" + "If you are unable to log in to Salesforce you can " + "press ctrl+c to kill the server and return to the command line.") # Implement the 300 second timeout timeout_thread = HTTPDTimeout(self.httpd, self.httpd_timeout) timeout_thread.start() # use serve_forever because it is smarter about polling for Ctrl-C # on Windows. # # There are two ways it can be shutdown. # 1. Get a callback from Salesforce. # 2. Timeout self.httpd.serve_forever() # timeout thread can stop polling and just finish timeout_thread.quit() self._check_response(self.response) return safe_json_from_response(self.response)