/** * ─────────────────────────────────────────────────────────────────────────────────────────────────┐ * This class is handle user authentication process. * Aurthenticate user and update its refresh token into the Config custom settings. * Shopify API Documentation: https://shopify.dev/docs/admin-api/rest/reference * Create Shopify Store: https://www.shopify.com/signup?itcat=identity&itterm=create-new-store * Shopify API Release 2020: https://www.shopify.in/partners/blog/shopify-api-release-january-2020 * What is Person Account in Salesforce ? https://help.salesforce.com/articleView?id=account_person.htm&type=5 * ────────────────────────────────────────────────────────────────────────────────────────────────── * @author Sumit * ────────────────────────────────────────────────────────────────────────────────────────────────── */ public with sharing class AuthenticateInternally { String clientIdProduction; String clientSecretproduction; String salesforceUrl = system.url.getOrgDomainUrl().toexternalform(); public Boolean inProgress{get;set;} public Boolean error{get;set;} public String customerInstanceUrl ; public String customerDomainURL; public String ReturnViewmode; public pagereference authenticateInternallyController(){ String isLwcApp; list listofConfiguration = new list(); //String conquery = 'Select '+CheckAccessibility.isAccessible('id,name,HIC_ShopifySync__ClientId__c,HIC_ShopifySync__ClientSecret__c','HIC_ShopifySync__Configuration__c')+' from HIC_ShopifySync__Configuration__c where '+CheckAccessibility.isAccessible('name','HIC_ShopifySync__Configuration__c')+' = \'Default\' LIMIT 1'; //listofConfiguration = database.query(conquery); listofConfiguration = [select id,name,HIC_ShopifySync__ClientId__c,HIC_ShopifySync__ClientSecret__c from HIC_ShopifySync__Configuration__c limit 1]; if(listofConfiguration.isEmpty()) return null; clientIdProduction = listofConfiguration[0].HIC_ShopifySync__ClientId__c; clientSecretproduction = listofConfiguration[0].HIC_ShopifySync__ClientSecret__c; system.debug('authenticateInternallyControllerCalled-params--'+apexpages.currentpage().getparameters()); if(apexpages.currentpage().getparameters().containsKey('code') && apexpages.currentpage().getparameters().containsKey('state')){ system.debug('authenticateInternallyControllerEntered'); inProgress = true; error = false; // PKCE: strip the embedded code_verifier from state before the legacy // suffix-parsing logic runs (verifier is recovered separately below for token exchange). String rawStateParam = apexpages.currentpage().getparameters().get('state'); String returnCustomerUrl = PkceUtil.extractOriginalState(rawStateParam); if(returnCustomerUrl.containsIgnoreCase('islwcapp')){ isLwcApp = 'true'; returnCustomerUrl = returnCustomerUrl.replace('islwcapp', ''); } string urlLoginhint = apexpages.currentpage().getparameters().get('login_hint'); System.debug('in login_hint' + urlLoginhint); String viewmode = returnCustomerUrl.substring(returnCustomerUrl.length() - 7,returnCustomerUrl.length()); system.debug('viewmode' + viewmode); if(viewmode.containsIgnoreCase('Theme3')){ ReturnViewmode = 'Theme3'; }else if(viewmode.containsIgnoreCase('Theme4d')){ ReturnViewmode = 'Theme4d'; } String toCheck = returnCustomerUrl.substring(returnCustomerUrl.length() - 13,returnCustomerUrl.length()); If(toCheck.contains('login')){ if(ReturnViewmode == 'Theme3'){ customerInstanceUrl = returnCustomerUrl.substring(0, returnCustomerUrl.length() - 11); } if( ReturnViewmode == 'Theme4d'){ customerInstanceUrl = returnCustomerUrl.substring(0, returnCustomerUrl.length() - 12); } }else{ if(ReturnViewmode == 'Theme3'){ customerInstanceUrl = returnCustomerUrl.substring(0, returnCustomerUrl.length() - 10); } if( ReturnViewmode == 'Theme4d'){ customerInstanceUrl = returnCustomerUrl.substring(0, returnCustomerUrl.length() - 11); } } // PKCE: recover the code_verifier that was packed into state at /authorize time // by salesforceAuthenticationController.authenticate() in the customer org. String codeVerifier = PkceUtil.extractVerifier(rawStateParam); HttpRequest req = new HttpRequest(); req.setMethod('POST'); //if(returnCustomerUrl.containsIgnoreCase('test')){ if(toCheck.containsIgnoreCase('login')){ req.setEndpoint('https://login.salesforce.com/services/oauth2/token'); }else{ req.setEndpoint('https://test.salesforce.com/services/oauth2/token'); } String tokenBody = 'grant_type=authorization_code' + '&client_secret=' + clientSecretproduction + '&client_id='+ clientIdProduction + '&redirect_uri=https://hicshopifymadeeasy-dev-ed.my.salesforce-sites.com/thankYouPageSuccessfulAuthentication' + '&code=' + apexpages.currentpage().getparameters().get('code'); if(String.isNotBlank(codeVerifier)){ tokenBody += '&code_verifier=' + codeVerifier; } req.setBody(tokenBody); req.setTimeout(120000); Http http = new Http(); HTTPResponse res; if(!Test.isRunningTest()){ res = http.send(req); System.debug('BODY: '+res.getBody()); System.debug('STATUS:'+res.getStatus()); System.debug('STATUS_CODE:'+res.getStatusCode()); } list customSettingRecord = new list(); //String query = 'Select '+CheckAccessibility.isAccessible('name,HIC_ShopifySync__Client_Id__c, HIC_ShopifySync__Client_Secret__c, HIC_ShopifySync__Password__c, HIC_ShopifySync__Salesforce_Url__c, HIC_ShopifySync__UserName__c ', 'HIC_ShopifySync__Internal_Callout__c')+ ' from HIC_ShopifySync__Internal_Callout__c LIMIT 1'; //customSettingRecord = database.query(query); customSettingRecord = [select name,HIC_ShopifySync__Client_Id__c, HIC_ShopifySync__Client_Secret__c, HIC_ShopifySync__Password__c, HIC_ShopifySync__Salesforce_Url__c, HIC_ShopifySync__UserName__c from HIC_ShopifySync__Internal_Callout__c limit 1]; string packageOrdAccessToken = oauthLogin(customSettingRecord[0].HIC_ShopifySync__Salesforce_Url__c,customSettingRecord[0].HIC_ShopifySync__Client_Id__c,customSettingRecord[0].HIC_ShopifySync__Client_Secret__c,customSettingRecord[0].HIC_ShopifySync__UserName__c,customSettingRecord[0].HIC_ShopifySync__Password__c); system.debug('packageOrdAccessToken++++++++'+packageOrdAccessToken); if( packageOrdAccessToken != null){ System.debug('customerInstanceUrl--> '+customerInstanceUrl); createRemoteSiteSettings(packageOrdAccessToken,customerInstanceUrl); Map responseBody = (Map) JSON.deserializeUntyped(res.getBody()); System.debug('Refreshtoken++++'+ responseBody.get('refresh_token')); // NOTE: string.valueOf(null) returns the literal 'null', which used to be concatenated // straight into the JSON body below and stored as if it were a real token. A stored // 'null' defeats every blank check in the package (the keep-alive probe and // ShopifyController.refreshTokenCheck both accept it), so the org reports connected while // every refresh fails. Keep these genuinely null; the body builder omits them. String refershToken = responseBody.get('refresh_token') == null ? null : string.valueOf(responseBody.get('refresh_token')); String accessToken = responseBody.get('access_token') == null ? null : string.valueOf(responseBody.get('access_token')); customerDomainURL = String.valueof(responseBody.get('instance_url')); if (customerDomainURL != null) createRemoteSiteSettings(packageOrdAccessToken, customerDomainURL); System.debug('Org Refresh Token++'+refershToken ); System.debug('Org accessToken Token++'+accessToken ); /* HttpRequest toInsertRefreshToken = new HttpRequest(); toInsertRefreshToken.setHeader('X-HTTP-Method-Override','PATCH'); toInsertRefreshToken.setMethod('POST'); toInsertRefreshToken.setHeader('Authorization','Bearer '+ accessToken); toInsertRefreshToken.setHeader('Content-Type','application/json'); toInsertRefreshToken.setEndpoint(customerInstanceUrl+'/services/data/v36.0/sobjects/HIC_ShopifySync__Configuration__c/Name/Default?_HttpMethod=PATCH'); toInsertRefreshToken.setEndpoint(customerInstanceUrl+'/services/apexrest/HIC_ShopifySync/UpdateRefreshToken'); string refreshTokenBody = '{ "HIC_ShopifySync__Refresh_Token__c" : " '+refershToken+' " } '; toInsertRefreshToken.setBody(refreshTokenBody); Http insertRefreshToken = new Http(); if(!Test.isRunningTest()){ HTTPResponse resResult = insertRefreshToken.send(toInsertRefreshToken); System.debug('BODY1: '+resResult.getBody()); System.debug('STATUS1:'+resResult.getStatus()); System.debug('STATUS_CODE1:'+resResult.getStatusCode()); if(resResult.getStatusCode() == 204 || resResult.getStatusCode() == 302){ pagereference successPage = new pagereference('https://hicshopifymadeeasy-dev-ed.my.salesforce-sites.com/thankYouPageSuccessfulAuthentication?authenticationSuccess=true'); return successPage; }else{ pagereference errorPage = new pagereference('https://hicshopifymadeeasy-dev-ed.my.salesforce-sites.com/thankYouPageSuccessfulAuthentication?authenticationSuccess=false'); return errorPage; } }*/ if(!Test.isRunningTest()){ Http insertRefreshToken = new Http(); HttpRequest httpReq = new HttpRequest(); httpReq.setEndpoint(customerInstanceUrl+'/services/apexrest/HIC_ShopifySync/AuthenticateAllApexClass?objectname=UpdateRefreshToken&DMLType=Update'); httpReq.setMethod( 'POST' ); httpReq.setHeader( 'Content-Type', 'application/json' ); httpReq.setHeader( 'Accept', 'application/json' ); httpReq.setHeader( 'Authorization', 'Bearer ' + accessToken ); // Built with JSON.serialize so a null token is omitted rather than becoming the // string "null", and so any character in a token is escaped correctly. Map tokenPayload = new Map(); if (String.isNotBlank(refershToken)) tokenPayload.put('HIC_ShopifySync__Refresh_Token__c', refershToken); if (String.isNotBlank(accessToken)) tokenPayload.put('HIC_ShopifySync__Access_Token__c', accessToken); String body = JSON.serialize(tokenPayload); httpReq.setBody( body ); HttpResponse restoken = insertRefreshToken.send( httpReq ); System.debug('BODY1: '+restoken.getBody()); System.debug('STATUS1:'+restoken.getStatus()); System.debug('STATUS_CODE1:'+restoken.getStatusCode()); Boolean redirect = false; if(restoken.getStatusCode() >=300 && restoken.getStatusCode() <= 307 && restoken.getStatusCode() != 306) { String locforstart = restoken.getHeader('Location'); if(locforstart != null && locforstart != ''){ createRemoteSiteSettings(packageOrdAccessToken,locforstart.removeEndIgnoreCase('/services/apexrest/HIC_ShopifySync/AuthenticateAllApexClass?objectname=UpdateRefreshToken&DMLType=Update')); } do { redirect = false; // reset the value each time String loc = restoken.getHeader('Location'); // get location of the redirect if(loc == null) { redirect = false; continue; } req = new HttpRequest(); req.setEndpoint(loc); req.setMethod('POST'); req.setHeader( 'Content-Type', 'application/json' ); req.setHeader( 'Accept', 'application/json' ); req.setHeader( 'Authorization', 'Bearer ' + accessToken ); req.setBody( body ); req.setTimeout(120000); restoken = insertRefreshToken.send(req); if(restoken.getStatusCode() != 500) { // 500 = fail if(restoken.getStatusCode() >=300 && restoken.getStatusCode() <= 307 && restoken.getStatusCode() != 306) { redirect= true; } // I do special handling here with cookies // if you need to bring a session cookie over to the // redirected page, this is the place to grab that info } } while (redirect && Limits.getCallouts() != Limits.getLimitCallouts()); } system.debug('StatusCode: '+ restoken.getStatus() ); if(restoken.getStatusCode() == 200 || restoken.getStatusCode() == 204 ){ System.debug('@@@ Does LWC Contains true ::: '+isLwcApp); if(String.isNotBlank(isLwcApp) && isLwcApp.containsIgnoreCase('true')){ System.debug('@@@ inside LWC true ::: '); pagereference successPage = new pagereference('https://hicshopifymadeeasy-dev-ed.my.salesforce-sites.com/thankYouPageSuccessfulAuthentication?authenticationSuccess=true&customerInstanceUrl='+customerInstanceUrl+'&viewmode='+ReturnViewmode+'&islwcapp=true'); return successPage; } pagereference successPage = new pagereference('https://hicshopifymadeeasy-dev-ed.my.salesforce-sites.com/thankYouPageSuccessfulAuthentication?authenticationSuccess=true&customerInstanceUrl='+customerInstanceUrl+'&viewmode='+ReturnViewmode); return successPage; }else{ if(String.isNotBlank(isLwcApp) && isLwcApp.containsIgnoreCase('true')){ System.debug('@@@ inside LWC true ::: '); pagereference errorPage = new pagereference('https://hicshopifymadeeasy-dev-ed.my.salesforce-sites.com/thankYouPageSuccessfulAuthentication?authenticationSuccess=false&customerInstanceUrl='+customerInstanceUrl+'&viewmode='+ReturnViewmode+'&islwcapp=true'); return errorPage; } pagereference errorPage = new pagereference('https://hicshopifymadeeasy-dev-ed.my.salesforce-sites.com/thankYouPageSuccessfulAuthentication?authenticationSuccess=false&customerInstanceUrl='+customerInstanceUrl+'&viewmode='+ReturnViewmode); return errorPage; } } } } system.debug('customerUrl--'+customerInstanceUrl); if(apexpages.currentpage().getparameters().containsKey('authenticationSuccess') && apexpages.currentpage().getparameters().get('authenticationSuccess') != null && apexpages.currentpage().getparameters().get('authenticationSuccess') == 'true' ){ inProgress = false; // error = true; }else if(apexpages.currentpage().getparameters().containsKey('authenticationSuccess') && apexpages.currentpage().getparameters().get('authenticationSuccess') != null && apexpages.currentpage().getparameters().get('authenticationSuccess') == 'false' ){ inProgress = null; error = true; } return null; } public static boolean CheckingRemotesiteExistence(String SFdomainUrl ,string Sessionid){ boolean exist = false; // String SFdomainUrl = URL.getOrgDomainUrl().toExternalForm(); String OrgURl = URL.getOrgDomainUrl().toExternalForm(); try{ HttpRequest req = new HttpRequest(); req.setHeader('Authorization', 'Bearer ' + Sessionid); //Get user Session ID req.setHeader('Content-Type', 'application/json'); String query='select+id,+EndpointUrl+from+Remotesitesetting+where+EndpointUrl=+\''+SFdomainUrl+'\''; req.setEndpoint(OrgURl+'/services/data/v58.0/tooling/query/?q='+query); req.setMethod('GET'); req.setTimeout(120000); Http h = new Http(); HttpResponse response; String RemotesitesettingResponse; if(!Test.isRunningTest()){ response = h.send(req); RemotesitesettingResponse = response.getBody().trim(); }else{ RemotesitesettingResponse = '{"size":1,"totalSize":1,"done":true,"queryLocator":null,"entityTypeName":"Certificate","records":[{"attributes":{"type":"Certificate","url":"/services/data/v58.0/tooling/sobjects/Certificate/0P12v000006b5K9CAI"},"Id":"0P12v000006b5K9CAI","DeveloperName":"Shopify"}]}'; } System.debug('response---- '+ RemotesitesettingResponse); if(RemotesitesettingResponse == null || RemotesitesettingResponse =='') return false; Map mapofRemoteSitesettings = (Map) JSON.deserializeUntyped(RemotesitesettingResponse); if(!mapofRemoteSitesettings.isempty() && mapofRemoteSitesettings != null && mapofRemoteSitesettings.containskey('size')){ if(Integer.valueof(mapofRemoteSitesettings.get('size')) > 0){ exist = true; } } return exist; }Catch(Exception e){ System.debug('Exception---- '+ e + 'at line number '+ e.getLineNumber()); return exist; } } public static void createRemoteSiteSettings(String accessToken, String instanceURl){ system.debug('createRemoteSiteSettings+++++'+accessToken) ; if(CheckingRemotesiteExistence(instanceURl,accessToken)) return; MetadataServiceNew.MetadataPort service = createService(accessToken); MetadataServiceNew.RemoteSiteSetting remoteSiteSettings = new MetadataServiceNew.RemoteSiteSetting(); remoteSiteSettings.fullName = 'App'+DateTime.now().getTime(); remoteSiteSettings.url = instanceURl; remoteSiteSettings.description='Client Remote Site '+instanceURl; remoteSiteSettings.isActive=true; remoteSiteSettings.disableProtocolSecurity=false; /* MetadataServiceNew.RemoteSiteSetting remoteSiteSettingsWithoutVf = new MetadataServiceNew.RemoteSiteSetting(); remoteSiteSettingsWithoutVf.fullName = 'AppMain'+DateTime.now().getTime(); remoteSiteSettingsWithoutVf.url = instanceURl.remove('visualforce.'); remoteSiteSettingsWithoutVf.description='Client Remote Site '+instanceURl; remoteSiteSettingsWithoutVf.isActive=true; remoteSiteSettingsWithoutVf.disableProtocolSecurity=false; system.debug('url without vf '+instanceURl.remove('visualforce.')); system.debug('remoteSiteSettingsWithoutVf--'+remoteSiteSettingsWithoutVf);*/ MetadataServiceNew.AsyncResult[] results = service.create(new List { remoteSiteSettings }); // MetadataServiceNew.AsyncResult[] resultsVF = service.create(new List { remoteSiteSettingsWithoutVf }); system.debug('results meta size '+results.size()); system.debug('results meta '+results); system.debug('string.ValueOf(results[0].Id)'+string.ValueOf(results[0].Id)); MetadataServiceNew.AsyncResult[] checkResults = service.checkStatus(new List {string.ValueOf(results[0].Id)}); system.debug('checkResults meta size '+checkResults.size()); system.debug('checkResults meta '+checkResults); system.debug('chk' + checkResults ); } public static MetadataServiceNew.MetadataPort createService(String accessToken){ system.debug('createService+++++'+accessToken) ; MetadataServiceNew.MetadataPort service = new MetadataServiceNew.MetadataPort(); service.SessionHeader = new MetadataServiceNew.SessionHeader_element(); service.SessionHeader.sessionId = accessToken; return service; } public static string oauthLogin(String loginUri, String clientId, String clientSecret, String username, String password) { HttpRequest req = new HttpRequest(); req.setMethod('POST'); req.setEndpoint(loginUri+'/services/oauth2/token'); req.setBody('grant_type=password' + '&client_id=' + clientId + '&client_secret=' + clientSecret + '&username=' + EncodingUtil.urlEncode(username, 'UTF-8') + '&password=' + EncodingUtil.urlEncode(password, 'UTF-8')); req.setTimeout(120000); System.debug('BODY:req '+req.getBody()); Http http = new Http(); if(!Test.isRunningTest()){ HTTPResponse res = http.send(req); System.debug('BODY: '+res.getBody()); System.debug('STATUS:'+res.getStatus()); System.debug('STATUS_CODE:'+res.getStatusCode()); readToken body = (readToken)JSON.deserialize(res.getBody(), readToken.class); System.debug('Token:'+body.access_token); return body.access_token; }else{ return null; } } public PageReference dosubmit(){ string UserCustomDomain; String ViewMode; String isLwcApp; if(apexpages.currentpage().getparameters().containsKey('customerInstanceUrl') && apexpages.currentpage().getparameters().get('customerInstanceUrl') != null && apexpages.currentpage().getparameters().get('customerInstanceUrl') != '' ){ UserCustomDomain = apexpages.currentpage().getparameters().get('customerInstanceUrl'); } if(apexpages.currentpage().getparameters().containsKey('islwcapp') && apexpages.currentpage().getparameters().get('islwcapp') != null && apexpages.currentpage().getparameters().get('islwcapp') != '' ){ isLwcApp = apexpages.currentpage().getparameters().get('islwcapp'); } if(apexpages.currentpage().getparameters().containsKey('viewmode') && apexpages.currentpage().getparameters().get('viewmode') != null && apexpages.currentpage().getparameters().get('viewmode') != '' ){ ViewMode = apexpages.currentpage().getparameters().get('viewmode'); } String sfUrl=URL.getOrgDomainUrl().getHost(); String myURL; //= UserCustomDomain + '/lightning/n/HIC_ShopifySync__Salesforce_Shopify_Sync_Settings'; if(ViewMode == 'Theme3') { myURL = 'apex/SfdcShopifySyncSettings?'; } else if(ViewMode == 'Theme4d' && String.isNotBlank(isLwcApp) && isLwcApp.containsIgnoreCase('true')) { myURL = 'lightning/n/HIC_ShopifySync__SME_Settings'; } else if(ViewMode == 'Theme4d' && isLwcApp == null){ // else if(ViewMode == 'Theme4d'){ myURL = 'lightning/n/HIC_ShopifySync__Salesforce_Shopify_Sync_Settings'; }else{ myURL = 'lightning/n/HIC_ShopifySync__Salesforce_Shopify_Sync_Settings'; } PageReference pr = new PageReference(UserCustomDomain +'/'+myURL); // google is blocked here // PageReference pr = new PageReference('https://hicshopifymadeeasy-dev-ed.my.salesforce.com/apex/SfdcShopifySyncSettings?'); // google is blocked here pr.setRedirect(true); return pr; } public class readToken{ public string access_token{get;set;} public string instance_url{get;set;} } }