def jwt_login(consumer_id, username, private_key, sandbox=False): endpoint = ("https://test.salesforce.com" if sandbox is True else "https://login.salesforce.com") jwt_payload = jwt.encode( { "exp": datetime.datetime.utcnow() + datetime.timedelta(seconds=30), "iss": consumer_id, "aud": endpoint, "sub": username, }, private_key, algorithm="RS256", ) result = requests.post( endpoint + "/services/oauth2/token", data={ "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion": jwt_payload, }, ) body = result.json() if result.status_code != 200: raise SalesforceAuthenticationFailed(body["error"], body["error_description"]) return simple_salesforce.Salesforce( instance_url=body["instance_url"], session_id=body["access_token"], version="46.0", )
def jwt_login(consumer_id, username, private_key, sandbox=False): global session_id, instance, sfurl endpoint = 'https://test.salesforce.com' if sandbox is True else 'https://login.salesforce.com' jwt_payload = jwt.encode( { 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=30), 'iss': consumer_id, 'aud': endpoint, 'sub': username }, private_key, algorithm='RS256' ) result = requests.post( endpoint + '/services/oauth2/token', data={ 'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion': jwt_payload } ) body = result.json() print(body) if result.status_code != 200: raise SalesforceAuthenticationFailed(body['error'], body['error_description']) # now set things properly session_id = body['access_token'] instance = body['instance_url'] sfurl = instance sf = Salesforce(instance_url=body['instance_url'], session_id=body['access_token']) return sf
def jwt_login(consumer_id, username, private_key): endpoint = 'https://login.salesforce.com' jwt_payload = jwt.encode( { 'iss': consumer_id, 'sub': username, 'aud': endpoint, 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=300) }, private_key, algorithm='RS256') # Send the request to get the TOKEN result = requests.post(endpoint + '/services/oauth2/token', data={ 'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion': jwt_payload }) body = result.json() sf = Salesforce(instance_url=body['instance_url'], session_id=body['access_token']) # Print LOGIN errors if result.status_code != 200: raise SalesforceAuthenticationFailed(body['error'], body['error_description']) return Salesforce(instance_url=body['instance_url'], session_id=body['access_token'])
def mock_salesforce_auth(is_success: bool) -> Iterator[None]: if is_success: with patch( 'simple_salesforce.api.Salesforce.__init__') as mock_sf_init: mock_sf_init.return_value = None yield else: with patch('simple_salesforce.api.Salesforce.__init__', side_effect=SalesforceAuthenticationFailed( 403, 'auth failed')) as mock_sf_init: mock_sf_init.return_value = None yield
def token_login(token_url, token_data, domain, consumer_key, headers, proxies, session=None): """Process OAuth 2.0 JWT Bearer Token Flow.""" response = (session or requests).post( token_url, token_data, headers=headers, proxies=proxies) try: json_response = response.json() except JSONDecodeError: raise SalesforceAuthenticationFailed( response.status_code, response.text ) if response.status_code != 200: except_code = json_response.get('error') except_msg = json_response.get('error_description') if except_msg == "user hasn't approved this consumer": auth_url = 'https://{domain}.salesforce.com/services/oauth2/' \ 'authorize?response_type=code&client_id=' \ '{consumer_key}&redirect_uri=<approved URI>'.format( domain=domain, consumer_key=consumer_key ) warnings.warn(""" If your connected app policy is set to "All users may self-authorize", you may need to authorize this application first. Browse to %s in order to Allow Access. Check first to ensure you have a valid <approved URI>.""" % auth_url) raise SalesforceAuthenticationFailed(except_code, except_msg) access_token = json_response.get('access_token') instance_url = json_response.get('instance_url') sf_instance = instance_url.replace( 'http://', '').replace( 'https://', '') return access_token, sf_instance
def connect(self): try: sf = Salesforce( username=Config.DEVELOPMENT_CONF['salesforce']['username'], password=Config.DEVELOPMENT_CONF['salesforce']['password'], security_token=Config.DEVELOPMENT_CONF['salesforce']['token']) except Exception as e: if self.retry != 0: self.retry -= 1 self.connect() else: raise SalesforceAuthenticationFailed( "500", 'Can`t connect to saleforce') return sf
def soap_login(soap_url, request_body, headers, proxies, session=None): """Process SOAP specific login workflow.""" response = (session or requests).post( soap_url, request_body, headers=headers, proxies=proxies) if response.status_code != 200: except_code = getUniqueElementValueFromXmlString( response.content, 'sf:exceptionCode') except_msg = getUniqueElementValueFromXmlString( response.content, 'sf:exceptionMessage') raise SalesforceAuthenticationFailed(except_code, except_msg) session_id = getUniqueElementValueFromXmlString( response.content, 'sessionId') server_url = getUniqueElementValueFromXmlString( response.content, 'serverUrl') sf_instance = (server_url .replace('http://', '') .replace('https://', '') .split('/')[0] .replace('-api', '')) return session_id, sf_instance
def convert_lead(self, lead_id: str, account_id: str, converted_lead_status: str = None, create_opp: bool = False, send_email: bool = False): sf_instance = self.client.sf_instance sf_version = self.client.sf_version session_id = self.client.session_id session = self.client.session if not converted_lead_status and not self.converted_status: converted_lead_status = self.converted_status = self.get_converted_status( ) soap_url = f'https://{sf_instance}/services/Soap/u/{sf_version}' login_soap_request_headers = { 'content-type': 'text/xml', 'charset': 'UTF-8', 'SOAPAction': 'convertLead' } login_soap_request_body = f""" <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com"> <soapenv:Header> <urn:SessionHeader> <urn:sessionId>{session_id}</urn:sessionId> </urn:SessionHeader> </soapenv:Header> <soapenv:Body> <urn:convertLead> <urn:leadConverts> <!-- Zero or more repetitions --> <urn:convertedStatus>{converted_lead_status}</urn:convertedStatus> <urn:leadId>{lead_id}</urn:leadId> <urn:accountId>{account_id}</urn:accountId> <urn:sendNotificationEmail>{send_email}</urn:sendNotificationEmail> <urn:doNotCreateOpportunity>{not create_opp}</urn:doNotCreateOpportunity> </urn:leadConverts> </urn:convertLead> </soapenv:Body> </soapenv:Envelope> """ response = session.post(soap_url, login_soap_request_body, headers=login_soap_request_headers) if response.status_code != 200: except_code = util.getUniqueElementValueFromXmlString( response.content, 'sf:exceptionCode') except_msg = util.getUniqueElementValueFromXmlString( response.content, 'sf:exceptionMessage') raise SalesforceAuthenticationFailed(except_code, except_msg) else: contact_id = util.getUniqueElementValueFromXmlString( response.content, 'contactId') success = util.getUniqueElementValueFromXmlString( response.content, 'success') status_code = util.getUniqueElementValueFromXmlString( response.content, 'statusCode') if success == 'true': logging.info( f"Lead Id {lead_id} converted to Contact Id {contact_id}") return True, contact_id else: logging.error( f"Unable to convert Lead Id {lead_id}. Status Code: {status_code}" ) return False, status_code
def SalesforceLogin( username=None, password=None, security_token=None, organizationId=None, sandbox=False, sf_version=DEFAULT_API_VERSION, proxies=None, session=None, client_id=None, custom_url=None): """Return a tuple of `(session_id, sf_instance)` where `session_id` is the session ID to use for authentication to Salesforce and `sf_instance` is the domain of the instance of Salesforce to use for the session. Arguments: * username -- the Salesforce username to use for authentication * password -- the password for the username * security_token -- the security token for the username * organizationId -- the ID of your organization NOTE: security_token an organizationId are mutually exclusive * sandbox -- True if you want to login to `test.salesforce.com`, False if you want to login to `login.salesforce.com`. * sf_version -- the version of the Salesforce API to use, for example "27.0" * proxies -- the optional map of scheme to proxy server * session -- Custom requests session, created in calling code. This enables the use of requets Session features not otherwise exposed by simple_salesforce. * client_id -- the ID of this client * custom_url -- Supports Salesforce URL customization """ if custom_url: soap_url = ('{custom_url}/services/Soap/u/{sf_version}' .format(custom_url=custom_url, sf_version=sf_version)) else: soap_url = 'https://{domain}.salesforce.com/services/Soap/u/{sf_version}' domain = 'test' if sandbox else 'login' soap_url = soap_url.format(domain=domain, sf_version=sf_version) if client_id: client_id = "{prefix}/{app_name}".format( prefix=DEFAULT_CLIENT_ID_PREFIX, app_name=client_id) else: client_id = DEFAULT_CLIENT_ID_PREFIX # pylint: disable=E0012,deprecated-method username = escape(username) password = escape(password) # Check if token authentication is used if security_token is not None: # Security Token Soap request body login_soap_request_body = """<?xml version="1.0" encoding="utf-8" ?> <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com"> <env:Header> <urn:CallOptions> <urn:client>{client_id}</urn:client> <urn:defaultNamespace>sf</urn:defaultNamespace> </urn:CallOptions> </env:Header> <env:Body> <n1:login xmlns:n1="urn:partner.soap.sforce.com"> <n1:username>{username}</n1:username> <n1:password>{password}{token}</n1:password> </n1:login> </env:Body> </env:Envelope>""".format( username=username, password=password, token=security_token, client_id=client_id) # Check if IP Filtering is used in conjunction with organizationId elif organizationId is not None: # IP Filtering Login Soap request body login_soap_request_body = """<?xml version="1.0" encoding="utf-8" ?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com"> <soapenv:Header> <urn:CallOptions> <urn:client>{client_id}</urn:client> <urn:defaultNamespace>sf</urn:defaultNamespace> </urn:CallOptions> <urn:LoginScopeHeader> <urn:organizationId>{organizationId}</urn:organizationId> </urn:LoginScopeHeader> </soapenv:Header> <soapenv:Body> <urn:login> <urn:username>{username}</urn:username> <urn:password>{password}</urn:password> </urn:login> </soapenv:Body> </soapenv:Envelope>""".format( username=username, password=password, organizationId=organizationId, client_id=client_id) elif username is not None and password is not None: # IP Filtering for non self-service users login_soap_request_body = """<?xml version="1.0" encoding="utf-8" ?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com"> <soapenv:Header> <urn:CallOptions> <urn:client>{client_id}</urn:client> <urn:defaultNamespace>sf</urn:defaultNamespace> </urn:CallOptions> </soapenv:Header> <soapenv:Body> <urn:login> <urn:username>{username}</urn:username> <urn:password>{password}</urn:password> </urn:login> </soapenv:Body> </soapenv:Envelope>""".format( username=username, password=password, client_id=client_id) else: except_code = 'INVALID AUTH' except_msg = ( 'You must submit either a security token or organizationId for ' 'authentication' ) raise SalesforceAuthenticationFailed(except_code, except_msg) login_soap_request_headers = { 'content-type': 'text/xml', 'charset': 'UTF-8', 'SOAPAction': 'login' } response = (session or requests).post( soap_url, login_soap_request_body, headers=login_soap_request_headers, proxies=proxies) if response.status_code != 200: except_code = getUniqueElementValueFromXmlString( response.content, 'sf:exceptionCode') except_msg = getUniqueElementValueFromXmlString( response.content, 'sf:exceptionMessage') raise SalesforceAuthenticationFailed(except_code, except_msg) session_id = getUniqueElementValueFromXmlString( response.content, 'sessionId') server_url = getUniqueElementValueFromXmlString( response.content, 'serverUrl') sf_instance = (server_url .replace('http://', '') .replace('https://', '') .split('/')[0] .replace('-api', '')) return session_id, sf_instance
def convert_lead( session, session_id, lead_id, sf_instance, account_id=None, lead_status="Closed Won", sandbox=False, proxies=None, sf_version="38.0", ): soap_url = "https://{sf_instance}/services/Soap/u/{sf_version}" domain = "test" if sandbox else "login" soap_url = soap_url.format(domain=domain, sf_version=sf_version, sf_instance=sf_instance) account_id_block = "" if account_id: account_id_block = "<urn:accountId>{account_id}</urn:accountId>".format( account_id=account_id) login_soap_request_body = """ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com"> <soapenv:Header> <urn:SessionHeader> <urn:sessionId>{session_id}</urn:sessionId> </urn:SessionHeader> </soapenv:Header> <soapenv:Body> <urn:convertLead> <urn:leadConverts> <!-- Zero or more repetitions --> <urn:convertedStatus>{lead_status}</urn:convertedStatus> <urn:leadId>{lead_id}</urn:leadId> {account_id_block} <urn:convertedStatus>{lead_status}</urn:convertedStatus> <urn:sendNotificationEmail>true</urn:sendNotificationEmail> <urn:doNotCreateOpportunity>true</urn:doNotCreateOpportunity> </urn:leadConverts> </urn:convertLead> </soapenv:Body> </soapenv:Envelope> """.format( lead_id=lead_id, account_id_block=account_id_block, session_id=session_id, lead_status=lead_status, ) login_soap_request_headers = { "content-type": "text/xml", "charset": "UTF-8", "SOAPAction": "convertLead", } response = session.post( soap_url, login_soap_request_body, headers=login_soap_request_headers, proxies=proxies, ) if response.status_code != 200: except_code = getUniqueElementValueFromXmlString( response.content, "sf:exceptionCode") except_msg = getUniqueElementValueFromXmlString( response.content, "sf:exceptionMessage") raise SalesforceAuthenticationFailed(except_code, except_msg) else: contact_id = getUniqueElementValueFromXmlString( response.content, "contactId") success = getUniqueElementValueFromXmlString(response.content, "success") status_code = getUniqueElementValueFromXmlString( response.content, "statusCode") if success == "true": return True, contact_id else: return False, status_code
def SalesforceLogin( username=None, password=None, security_token=None, organizationId=None, sandbox=None, sf_version=DEFAULT_API_VERSION, proxies=None, session=None, client_id=None, domain=None, consumer_key=None, privatekey_file=None): """Return a tuple of `(session_id, sf_instance)` where `session_id` is the session ID to use for authentication to Salesforce and `sf_instance` is the domain of the instance of Salesforce to use for the session. Arguments: * username -- the Salesforce username to use for authentication * password -- the password for the username * security_token -- the security token for the username * organizationId -- the ID of your organization NOTE: security_token an organizationId are mutually exclusive * sandbox -- DEPRECATED: Use domain instead. * sf_version -- the version of the Salesforce API to use, for example "27.0" * proxies -- the optional map of scheme to proxy server * session -- Custom requests session, created in calling code. This enables the use of requets Session features not otherwise exposed by simple_salesforce. * client_id -- the ID of this client * domain -- The domain to using for connecting to Salesforce. Use common domains, such as 'login' or 'test', or Salesforce My domain. If not used, will default to 'login'. * consumer_key -- the consumer key generated for the user * privatekey_file -- the path to the private key file used for signing the JWT token """ if (sandbox is not None) and (domain is not None): raise ValueError("Both 'sandbox' and 'domain' arguments were " "supplied. Either may be supplied, but not " "both.") if sandbox is not None: warnings.warn("'sandbox' argument is deprecated. Use " "'domain' instead. Overriding 'domain' " "with 'sandbox' value.", DeprecationWarning) domain = 'test' if sandbox else 'login' if domain is None: domain = 'login' soap_url = 'https://{domain}.salesforce.com/services/Soap/u/{sf_version}' if client_id: client_id = "{prefix}/{app_name}".format( prefix=DEFAULT_CLIENT_ID_PREFIX, app_name=client_id) else: client_id = DEFAULT_CLIENT_ID_PREFIX soap_url = soap_url.format(domain=domain, sf_version=sf_version) # pylint: disable=E0012,deprecated-method username = escape(username) if username else None password = escape(password) if password else None # Check if token authentication is used if security_token is not None: # Security Token Soap request body login_soap_request_body = """<?xml version="1.0" encoding="utf-8" ?> <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com"> <env:Header> <urn:CallOptions> <urn:client>{client_id}</urn:client> <urn:defaultNamespace>sf</urn:defaultNamespace> </urn:CallOptions> </env:Header> <env:Body> <n1:login xmlns:n1="urn:partner.soap.sforce.com"> <n1:username>{username}</n1:username> <n1:password>{password}{token}</n1:password> </n1:login> </env:Body> </env:Envelope>""".format( username=username, password=password, token=security_token, client_id=client_id) # Check if IP Filtering is used in conjunction with organizationId elif organizationId is not None: # IP Filtering Login Soap request body login_soap_request_body = """<?xml version="1.0" encoding="utf-8" ?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com"> <soapenv:Header> <urn:CallOptions> <urn:client>{client_id}</urn:client> <urn:defaultNamespace>sf</urn:defaultNamespace> </urn:CallOptions> <urn:LoginScopeHeader> <urn:organizationId>{organizationId}</urn:organizationId> </urn:LoginScopeHeader> </soapenv:Header> <soapenv:Body> <urn:login> <urn:username>{username}</urn:username> <urn:password>{password}</urn:password> </urn:login> </soapenv:Body> </soapenv:Envelope>""".format( username=username, password=password, organizationId=organizationId, client_id=client_id) elif username is not None and password is not None: # IP Filtering for non self-service users login_soap_request_body = """<?xml version="1.0" encoding="utf-8" ?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com"> <soapenv:Header> <urn:CallOptions> <urn:client>{client_id}</urn:client> <urn:defaultNamespace>sf</urn:defaultNamespace> </urn:CallOptions> </soapenv:Header> <soapenv:Body> <urn:login> <urn:username>{username}</urn:username> <urn:password>{password}</urn:password> </urn:login> </soapenv:Body> </soapenv:Envelope>""".format( username=username, password=password, client_id=client_id) elif username is not None and \ consumer_key is not None and \ privatekey_file is not None: header = {'alg': 'RS256'} expiration = datetime.utcnow() + timedelta(minutes=3) payload = { 'iss': consumer_key, 'sub': username, 'aud': 'https://{domain}.salesforce.com'.format(domain=domain), 'exp': '{exp:.0f}'.format( exp=time.mktime(expiration.timetuple()) + expiration.microsecond / 1e6 ) } with open(privatekey_file, 'rb') as key: assertion = jwt.encode(header, payload, key.read()) login_token_request_data = { 'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion': assertion } return token_login( 'https://{domain}.salesforce.com/services/oauth2/token'.format( domain=domain), login_token_request_data, domain, consumer_key, None, proxies, session) else: except_code = 'INVALID AUTH' except_msg = ( 'You must submit either a security token or organizationId for ' 'authentication' ) raise SalesforceAuthenticationFailed(except_code, except_msg) login_soap_request_headers = { 'content-type': 'text/xml', 'charset': 'UTF-8', 'SOAPAction': 'login' } return soap_login(soap_url, login_soap_request_body, login_soap_request_headers, proxies, session)