From b4babd6b889eefac5f4d0f2498e5b7c6665470e4 Mon Sep 17 00:00:00 2001 From: sfdrogojan <42441166+sfdrogojan@users.noreply.github.com> Date: Tue, 21 May 2019 15:37:34 +0300 Subject: [PATCH] Added OAuth2 authentication support Added OAuth2 authentication support --- Gemfile.lock | 10 +++--- README.md | 25 ++++++++++++- lib/marketingcloudsdk/client.rb | 62 +++++++++++++++++++++++++++++--- lib/marketingcloudsdk/soap.rb | 46 +++++++++++++++--------- lib/marketingcloudsdk/version.rb | 2 +- 5 files changed, 118 insertions(+), 27 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 440a6ea..780c0e3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - sfmc-fuelsdk-ruby (1.1.0) + sfmc-fuelsdk-ruby (1.2.0) json (~> 1.8, >= 1.8.1) jwt (~> 1.0, >= 1.0.0) savon (= 2.2.0) @@ -16,6 +16,7 @@ GEM coderay (1.1.2) diff-lcs (1.3) ffi (1.9.25) + ffi (1.9.25-x64-mingw32) ffi (1.9.25-x86-mingw32) formatador (0.2.5) guard (1.8.3) @@ -39,9 +40,9 @@ GEM rb-kqueue (>= 0.2) lumberjack (1.0.13) method_source (0.9.0) - mini_portile2 (2.3.0) - nokogiri (1.8.5) - mini_portile2 (~> 2.3.0) + mini_portile2 (2.4.0) + nokogiri (1.10.1-x64-mingw32) + mini_portile2 (~> 2.4.0) nori (2.1.0) pry (0.11.3) coderay (~> 1.1.0) @@ -76,6 +77,7 @@ GEM PLATFORMS ruby + x64-mingw32 x86-mingw32 DEPENDENCIES diff --git a/README.md b/README.md index 9cac095..8bff5f6 100755 --- a/README.md +++ b/README.md @@ -6,6 +6,29 @@ ExactTarget Fuel SDK / SalesforceMarektingCloudSDK for Ruby ## Overview ## The Fuel SDK for Ruby provides easy access to ExactTarget's Fuel API Family services, including a collection of REST APIs and a SOAP API. These APIs provide access to ExactTarget functionality via common collection types such as array/hash. + +## New Features in Version 1.2.0 ## +- **OAuth2 authentication support** - [More Details](https://developer.salesforce.com/docs/atlas.en-us.mc-app-development.meta/mc-app-development/integration-considerations.htm) + + To enable OAuth2 authentication, pass ```use_oAuth2_authentication => true``` in the params argument to the Client's class constructor. + + Example of instantiating the Client class: + + ``` + myclient = MarketingCloudSDK::Client.new({ + 'client' => { + 'id' => '', + 'secret' => '', + 'request_token_url' => '', + 'soap_endpoint' => '', + 'base_api_url' => '', + 'use_oAuth2_authentication' => true, + 'account_id' => , + 'scope' => '' + } + }) + ``` + ## New Features in Version 1.1.0 ## - **Added support for your tenant's endpoints - [More Details](https://developer.salesforce.com/docs/atlas.en-us.mc-apis.meta/mc-apis/your-subdomain-tenant-specific-endpoints.htm) ** - **MarketingCloudSDK gem will be available as sfmc-fuelsdk-ruby on ruby gems. @@ -42,7 +65,7 @@ gem build marketingcloudsdk.gemspec Install the newly built gem ```ruby -gem install marketingcloudsdk-1.1.0.gem +gem install marketingcloudsdk-1.2.0.gem ``` If you have not registered your application or you need to lookup your Application Key or Application Signature values, please go to App Center at [Code@: ExactTarget's Developer Community](http://code.exacttarget.com/appcenter "Code@ App Center"). diff --git a/lib/marketingcloudsdk/client.rb b/lib/marketingcloudsdk/client.rb index 5c53675..3900764 100644 --- a/lib/marketingcloudsdk/client.rb +++ b/lib/marketingcloudsdk/client.rb @@ -78,7 +78,7 @@ def unpack raw class Client attr_accessor :debug, :access_token, :auth_token, :internal_token, :refresh_token, :id, :secret, :signature, :base_api_url, :package_name, :package_folders, :parent_folders, :auth_token_expiration, - :request_token_url, :soap_endpoint + :request_token_url, :soap_endpoint, :use_oAuth2_authentication, :account_id, :scope include MarketingCloudSDK::Soap include MarketingCloudSDK::Rest @@ -103,8 +103,11 @@ def initialize(params={}, debug=false) self.secret = client_config["secret"] self.signature = client_config["signature"] self.base_api_url = !(client_config["base_api_url"].to_s.strip.empty?) ? client_config["base_api_url"] : 'https://www.exacttargetapis.com' - self.request_token_url = !(client_config["request_token_url"].to_s.strip.empty?) ? client_config["request_token_url"] : 'https://auth.exacttargetapis.com/v1/requestToken' + self.request_token_url = client_config["request_token_url"] self.soap_endpoint = client_config["soap_endpoint"] + self.use_oAuth2_authentication = client_config["use_oAuth2_authentication"] + self.account_id = client_config["account_id"] + self.scope = client_config["scope"] end # Set a default value in case no 'client' params is sent @@ -112,20 +115,31 @@ def initialize(params={}, debug=false) self.base_api_url = 'https://www.exacttargetapis.com' end - # Leaving this for backwards compatibility - if (!self.request_token_url) - self.request_token_url = params['request_token_url'] ? params['request_token_url'] : 'https://auth.exacttargetapis.com/v1/requestToken' + if (self.request_token_url.to_s.strip.empty?) + if(use_oAuth2_authentication == true) + raise 'request_token_url (Auth TSE) is mandatory when using OAuth2 authentication' + else + self.request_token_url = 'https://auth.exacttargetapis.com/v1/requestToken' + end end self.jwt = params['jwt'] if params['jwt'] self.refresh_token = params['refresh_token'] if params['refresh_token'] self.wsdl = params["defaultwsdl"] if params["defaultwsdl"] + + self.refresh end def refresh force=false @refresh_mutex.synchronize do raise 'Require Client Id and Client Secret to refresh tokens' unless (id && secret) + + if (self.use_oAuth2_authentication == true) + self.refreshWithOAuth2(force) + return + end + #If we don't already have a token or the token expires within 5 min(300 seconds) if (self.access_token.nil? || Time.new + 300 > self.auth_token_expiration || force) then payload = Hash.new.tap do |h| @@ -154,6 +168,44 @@ def refresh force=false end end + def refreshWithOAuth2 force=false + raise 'Require Client Id and Client Secret to refresh tokens' unless (id && secret) + #If we don't already have a token or the token expires within 5 min(300 seconds) + if (self.access_token.nil? || Time.new + 300 > self.auth_token_expiration || force) then + payload = Hash.new.tap do |h| + h['client_id']= id + h['client_secret'] = secret + h['grant_type'] = 'client_credentials' + + if (not self.account_id.to_s.strip.empty?)then + h['account_id'] = account_id + end + + if (not self.scope.to_s.strip.empty?)then + h['scope'] = scope + end + end + + options = Hash.new.tap do |h| + h['data'] = payload + h['content_type'] = 'application/json' + end + + self.request_token_url += '/v2/token' + + response = post(request_token_url, options) + raise "Unable to refresh token: #{response['message']}" unless response.has_key?('access_token') + + self.access_token = response['access_token'] + self.auth_token_expiration = Time.new + response['expires_in'] + self.soap_endpoint = response['soap_instance_url'] + 'service.asmx' + self.base_api_url = response['rest_instance_url'] + return true + else + return false + end + end + def refresh! refresh true end diff --git a/lib/marketingcloudsdk/soap.rb b/lib/marketingcloudsdk/soap.rb index 7082a88..19d2bb3 100644 --- a/lib/marketingcloudsdk/soap.rb +++ b/lib/marketingcloudsdk/soap.rb @@ -121,11 +121,18 @@ module Soap include MarketingCloudSDK::Targeting def header - raise 'Require legacy token for soap header' unless internal_token - { - 'oAuth' => {'oAuthToken' => internal_token}, - :attributes! => { 'oAuth' => { 'xmlns' => 'http://exacttarget.com' }} - } + if use_oAuth2_authentication == true then + { + 'fueloauth' => {'fueloauth' => access_token}, + :attributes! => { 'fueloauth'=>{ 'xmlns' => 'http://exacttarget.com' }} + } + else + raise 'Require legacy token for soap header' unless internal_token + { + 'oAuth' => {'oAuthToken' => internal_token}, + :attributes! => { 'oAuth' => { 'xmlns' => 'http://exacttarget.com' }} + } + end end def debug @@ -138,17 +145,24 @@ def wsdl def soap_client self.refresh - @soap_client = Savon.client( - soap_header: header, - wsdl: wsdl, - endpoint: endpoint, - wsse_auth: ["*", "*"], - raise_errors: false, - log: debug, - open_timeout:180, - read_timeout: 180, - headers: {'User-Agent' => 'FuelSDK-Ruby-v' + MarketingCloudSDK::VERSION} - ) + + soap_client_options = { + soap_header: header, + wsdl: wsdl, + endpoint: endpoint, + wsse_auth: ["*", "*"], + raise_errors: false, + log: debug, + open_timeout:180, + read_timeout: 180, + headers: {'User-Agent' => 'FuelSDK-Ruby-v' + MarketingCloudSDK::VERSION} + } + + if use_oAuth2_authentication == true then + soap_client_options.delete(:wsse_auth) + end + + @soap_client = Savon.client(soap_client_options) end def soap_describe object_type diff --git a/lib/marketingcloudsdk/version.rb b/lib/marketingcloudsdk/version.rb index e55296b..3d3a1f2 100644 --- a/lib/marketingcloudsdk/version.rb +++ b/lib/marketingcloudsdk/version.rb @@ -35,5 +35,5 @@ =end module MarketingCloudSDK - VERSION = "1.1.0" + VERSION = "1.2.0" end