google-ads-common 0.7.2 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ChangeLog CHANGED
@@ -1,3 +1,9 @@
1
+ 0.7.3:
2
+ - Compatibility with Savon -> 1.0.0 (not backward-compatible).
3
+ - Now require HTTPI ~> 1.0.0.
4
+ - HttpClient is no longer explicitely required.
5
+ - Support for OAuth2.0 authorization method.
6
+
1
7
  0.7.2:
2
8
  - Compatibility with savon-0.9.10 (not backward-compatible).
3
9
 
data/README CHANGED
@@ -4,9 +4,6 @@ This gem is a dependency for the new generation of Ruby Google Ads client
4
4
  libraries. It contains common code shared among all of these libraries, such as
5
5
  authentication, SOAP stub generation, error handling, logging, etc.
6
6
 
7
- This is an early preview release, so a lot of things are still missing!
8
-
9
-
10
7
  = Docs for Users
11
8
 
12
9
  == 1 - Installation:
@@ -14,13 +11,12 @@ This is an early preview release, so a lot of things are still missing!
14
11
  google-ads-common is a Ruby gem. See http://docs.rubygems.org/read/book/1
15
12
 
16
13
  Install it using the gem install command.
17
- $ gem install --local google-ads-common-VERSION.gem
14
+ $ gem install google-ads-common
18
15
 
19
16
  The following gem libraries are required:
20
- - savon v0.9.9 or greater;
21
- - httpi v0.9.7 or greater;
22
- - httpclient v2.2.3 or greater;
23
- - oauth v0.4.5 or greater.
17
+ - savon
18
+ - httpi
19
+ - oauth
24
20
 
25
21
  = Docs for Developers
26
22
 
@@ -26,6 +26,7 @@ require 'ads_common/errors'
26
26
  require 'ads_common/utils'
27
27
  require 'ads_common/auth/client_login_handler'
28
28
  require 'ads_common/auth/oauth_handler'
29
+ require 'ads_common/auth/oauth2_handler'
29
30
 
30
31
  module AdsCommon
31
32
  class Api
@@ -110,12 +111,15 @@ module AdsCommon
110
111
  begin
111
112
  credentials = @credential_handler.credentials
112
113
  token = @auth_handler.get_token(credentials)
113
- rescue AdsCommon::Errors::OAuthVerificationRequired => e
114
+ rescue AdsCommon::Errors::OAuthVerificationRequired,
115
+ AdsCommon::Errors::OAuth2VerificationRequired => e
114
116
  verification_code = (block_given?) ? yield(e.oauth_url) : nil
115
117
  # Retry with verification code if one provided.
116
118
  if verification_code
117
- @credential_handler.set_credential(
118
- :oauth_verification_code, verification_code)
119
+ code_symbol =
120
+ e.kind_of?(AdsCommon::Errors::OAuthVerificationRequired) ?
121
+ :oauth_verification_code : :oauth2_verification_code
122
+ @credential_handler.set_credential(code_symbol, verification_code)
119
123
  retry
120
124
  else
121
125
  raise e
@@ -193,6 +197,13 @@ module AdsCommon
193
197
  @config,
194
198
  api_config.environment_config(environment, :oauth_scope)
195
199
  )
200
+ when :OAUTH2
201
+ environment = @config.read('service.environment',
202
+ api_config.default_environment())
203
+ AdsCommon::Auth::OAuth2Handler.new(
204
+ @config,
205
+ api_config.environment_config(environment, :oauth_scope)
206
+ )
196
207
  else
197
208
  raise AdsCommon::Errors::Error,
198
209
  "Unknown authentication method '%s'" % auth_method
@@ -0,0 +1,219 @@
1
+ # Encoding: utf-8
2
+ #
3
+ # Authors:: api.dklimkin@gmail.com (Danial Klimkin)
4
+ #
5
+ # Copyright:: Copyright 2012, Google Inc. All Rights Reserved.
6
+ #
7
+ # License:: Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
16
+ # implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+ # This module manages OAuth2.0 authentication.
21
+
22
+ require 'oauth2'
23
+
24
+ require 'ads_common/auth/base_handler'
25
+ require 'ads_common/errors'
26
+
27
+ module AdsCommon
28
+ module Auth
29
+
30
+ # Credentials class to handle OAuth2.0 authentication.
31
+ class OAuth2Handler < AdsCommon::Auth::BaseHandler
32
+ OAUTH2_CONFIG = {
33
+ :site => 'https://accounts.google.com',
34
+ :authorize_url => '/o/oauth2/auth',
35
+ :token_url => '/o/oauth2/token'
36
+ }
37
+ OAUTH2_HEADER = 'Bearer %s'
38
+ DEFAULT_CALLBACK = 'urn:ietf:wg:oauth:2.0:oob'
39
+
40
+ # Initializes the OAuthHandler2 with all the necessary details.
41
+ #
42
+ # Args:
43
+ # - config: Config object with library configuration
44
+ # - scope: OAuth authorization scope
45
+ #
46
+ def initialize(config, scope)
47
+ super(config)
48
+ @scope = scope
49
+ end
50
+
51
+ # Invalidates the stored token if the required credential has changed.
52
+ def property_changed(prop, value)
53
+ oauth2_keys = [:oauth2_client_id, :oauth2_client_secret, :oauth2_token]
54
+ if oauth2_keys.include?(prop)
55
+ @token, @client = nil, nil
56
+ end
57
+ end
58
+
59
+ def handle_error(error)
60
+ # TODO: Add support.
61
+ get_logger().error(error)
62
+ raise error
63
+ end
64
+
65
+ # Returns authorization string.
66
+ def auth_string(credentials, request = nil)
67
+ return generate_oauth2_parameters_string(credentials)
68
+ end
69
+
70
+ # Overrides base get_token method to account for the token expiration.
71
+ def get_token(credentials = nil)
72
+ refresh_token! if !@token.nil? && @token.expired?
73
+ return super(credentials)
74
+ end
75
+
76
+ # Refreshes access token from refresh token.
77
+ def refresh_token!()
78
+ return nil if @token.nil? or @token.refresh_token.nil?
79
+ @token = @token.refresh!
80
+ return @token
81
+ end
82
+
83
+ private
84
+
85
+ # Generates auth string for OAuth2.0 method of authentication.
86
+ #
87
+ # Args:
88
+ # - credentials: credentials set for authorization
89
+ #
90
+ # Returns:
91
+ # - Authentication string
92
+ #
93
+ def generate_oauth2_parameters_string(credentials)
94
+ token = get_token(credentials)
95
+ return OAUTH2_HEADER % token.token
96
+ end
97
+
98
+ # Auxiliary method to validate the credentials for token generation.
99
+ #
100
+ # Args:
101
+ # - credentials: a hash with the credentials for the account being
102
+ # accessed
103
+ #
104
+ # Raises:
105
+ # - AdsCommon::Errors::AuthError if validation fails
106
+ #
107
+ def validate_credentials(credentials)
108
+ if @scope.nil?
109
+ raise AdsCommon::Errors::AuthError, 'Scope is not specified.'
110
+ end
111
+
112
+ if credentials.nil?
113
+ raise AdsCommon::Errors::AuthError, 'No credentials supplied.'
114
+ end
115
+
116
+ if credentials[:oauth2_client_id].nil?
117
+ raise AdsCommon::Errors::AuthError,
118
+ 'Client id is not included in the credentials.'
119
+ end
120
+
121
+ if credentials[:oauth2_client_secret].nil?
122
+ raise AdsCommon::Errors::AuthError,
123
+ 'Client secret is not included in the credentials.'
124
+ end
125
+ end
126
+
127
+ # Auxiliary method to generate an authentication token for logging via
128
+ # the OAuth2.0 API.
129
+ #
130
+ # Args:
131
+ # - credentials: a hash with the credentials for the account being
132
+ # accessed
133
+ #
134
+ # Returns:
135
+ # - The auth token for the account (as an AccessToken)
136
+ #
137
+ # Raises:
138
+ # - AdsCommon::Errors::AuthError if authentication fails
139
+ # - AdsCommon::Errors::OAuthVerificationRequired if OAuth verification
140
+ # code required
141
+ #
142
+ def create_token(credentials)
143
+ validate_credentials(credentials)
144
+ @client ||= create_client(credentials)
145
+ return create_token_from_credentials(credentials, @client) ||
146
+ generate_access_token(credentials, @client)
147
+ end
148
+
149
+ def create_client(credentials)
150
+ oauth2_config = OAUTH2_CONFIG.dup()
151
+ proxy = @config.read('connection.proxy')
152
+ unless proxy.nil?
153
+ oauth2_config.merge!({:connection_opts => {:proxy => proxy}})
154
+ end
155
+ client = OAuth2::Client.new(credentials[:oauth2_client_id],
156
+ credentials[:oauth2_client_secret],
157
+ oauth2_config)
158
+ return client
159
+ end
160
+
161
+ # Creates access token based on data from credentials.
162
+ #
163
+ # Args:
164
+ # - credentials: a hash with the credentials for the account being
165
+ # accessed. Has to include :oauth2_token key with a hash value that
166
+ # represents a stored OAuth2 access token
167
+ # - client: OAuth2 client for the current configuration
168
+ #
169
+ # Returns:
170
+ # - The auth token for the account (as an AccessToken)
171
+ #
172
+ def create_token_from_credentials(credentials, client)
173
+ access_token = nil
174
+ oauth2_token_hash = credentials[:oauth2_token]
175
+ if !oauth2_token_hash.nil? && oauth2_token_hash.kind_of?(Hash)
176
+ access_token = OAuth2::AccessToken.new(
177
+ client, {:access_token => oauth2_token_hash})
178
+ end
179
+ return access_token
180
+ end
181
+
182
+ # Generates new request tokens and authorizes it to get access token.
183
+ #
184
+ # Args:
185
+ # - credentials: a hash with the credentials for the account being
186
+ # accessed
187
+ # - client: OAuth2 client for the current configuration
188
+ #
189
+ # Returns:
190
+ # - The auth token for the account (as an AccessToken)
191
+ #
192
+ def generate_access_token(credentials, client)
193
+ token = nil
194
+ begin
195
+ callback = credentials[:oauth2_callback] || DEFAULT_CALLBACK
196
+ verification_code = credentials[:oauth2_verification_code]
197
+ if verification_code.nil? || verification_code.empty?
198
+ auth_options = {
199
+ :redirect_uri => callback,
200
+ :scope => @scope,
201
+ :state => credentials[:oauth2_state],
202
+ :access_type => credentials[:oauth2_access_type],
203
+ :approval_prompt => credentials[:oauth2_approval_prompt]
204
+ }.reject {|k, v| v.nil?}
205
+ auth_url = client.auth_code.authorize_url(auth_options)
206
+ raise AdsCommon::Errors::OAuth2VerificationRequired.new(auth_url)
207
+ else
208
+ token = @client.auth_code.get_token(verification_code,
209
+ {:redirect_uri => callback})
210
+ end
211
+ rescue OAuth::Unauthorized => e
212
+ raise AdsCommon::Errors::AuthError,
213
+ 'Authorization error occured: %s' % e
214
+ end
215
+ return token
216
+ end
217
+ end
218
+ end
219
+ end
@@ -17,7 +17,7 @@
17
17
  # See the License for the specific language governing permissions and
18
18
  # limitations under the License.
19
19
  #
20
- # This module manages OAuth authentication.
20
+ # This module manages OAuth1.0a authentication.
21
21
 
22
22
  require 'oauth'
23
23
 
@@ -63,11 +63,6 @@ module AdsCommon
63
63
  raise error
64
64
  end
65
65
 
66
- # Returns OAuth-specific Consumer object.
67
- def get_oauth_consumer()
68
- return @consumer
69
- end
70
-
71
66
  # Returns authorization string.
72
67
  def auth_string(credentials, request)
73
68
  if request.nil?
@@ -257,23 +252,6 @@ module AdsCommon
257
252
  oauth_url, request_token)
258
253
  raise error
259
254
  end
260
-
261
- # Extracts key-value pairs from OAuth server response.
262
- #
263
- # Args:
264
- # - text: server response string
265
- #
266
- # Returns:
267
- # - Hash of key-value pairs
268
- #
269
- def parse_token_text(text)
270
- result = {}
271
- text.split('&').each do |line|
272
- key, value = line.split("=")
273
- result[key.to_sym] = value
274
- end
275
- return result
276
- end
277
255
  end
278
256
  end
279
257
  end
@@ -23,6 +23,8 @@
23
23
  require 'savon'
24
24
  require 'rexml/document'
25
25
 
26
+ require 'ads_common/utils'
27
+
26
28
  module AdsCommon
27
29
  module Build
28
30
  # Contains the methods that extracts WSDL data.
@@ -19,6 +19,8 @@
19
19
  #
20
20
  # Generic class to handle credentials across client libraries.
21
21
 
22
+ require 'ads_common/api_config'
23
+
22
24
  module AdsCommon
23
25
  class CredentialHandler
24
26
 
@@ -84,7 +86,7 @@ module AdsCommon
84
86
  agent_app ||= $0
85
87
  agent_data = extra_ids
86
88
  agent_data << "Common-Ruby/%s" % AdsCommon::ApiConfig::CLIENT_LIB_VERSION
87
- agent_data << "Savon/%s" % Savon::Version
89
+ agent_data << "Savon/%s" % Savon::VERSION
88
90
  ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
89
91
  agent_data << [ruby_engine, RUBY_VERSION].join('/')
90
92
  agent_data << "HTTPI/%s" % HTTPI::VERSION
@@ -39,7 +39,7 @@ module AdsCommon
39
39
  end
40
40
  end
41
41
 
42
- # Raised when OAuth access token is required.
42
+ # Raised when OAuth1.0a access token is required.
43
43
  class OAuthVerificationRequired < AuthError
44
44
  attr_reader :oauth_url, :request_token
45
45
  def initialize(oauth_url, request_token)
@@ -48,6 +48,15 @@ module AdsCommon
48
48
  end
49
49
  end
50
50
 
51
+ # Raised when OAuth2.0 access token is required.
52
+ class OAuth2VerificationRequired < AuthError
53
+ attr_reader :oauth_url
54
+ def initialize(oauth_url)
55
+ super()
56
+ @oauth_url = oauth_url
57
+ end
58
+ end
59
+
51
60
  # Raised when ClientLogin Captcha challenge occurs.
52
61
  class CaptchaRequiredError < AuthError
53
62
  attr_reader :error, :captcha_token
@@ -21,6 +21,6 @@
21
21
 
22
22
  module AdsCommon
23
23
  module ApiConfig
24
- CLIENT_LIB_VERSION = '0.7.2'
24
+ CLIENT_LIB_VERSION = '0.7.3'
25
25
  end
26
26
  end
@@ -52,4 +52,11 @@ class TestCredentialHandler < Test::Unit::TestCase
52
52
  assert_equal(42, credentials[:client_customer_id])
53
53
  assert_equal('bar', credentials[:foo])
54
54
  end
55
+
56
+ def test_generate_user_agent_simple()
57
+ result1 = @handler.generate_http_user_agent()
58
+ assert_kind_of(String, result1)
59
+ result2 = @handler.generate_soap_user_agent()
60
+ assert_kind_of(String, result2)
61
+ end
55
62
  end
metadata CHANGED
@@ -1,88 +1,97 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: google-ads-common
3
- version: !ruby/object:Gem::Version
4
- version: 0.7.2
3
+ version: !ruby/object:Gem::Version
4
+ hash: 5
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 7
9
+ - 3
10
+ version: 0.7.3
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Sergio Gomes
9
14
  - Danial Klimkin
10
15
  autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
- date: 2012-06-08 00:00:00.000000000 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
18
+
19
+ date: 2012-06-21 00:00:00 Z
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
16
22
  name: savon
17
- requirement: !ruby/object:Gem::Requirement
18
- none: false
19
- requirements:
20
- - - ~>
21
- - !ruby/object:Gem::Version
22
- version: 0.9.10
23
- type: :runtime
24
23
  prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
- requirements:
28
- - - ~>
29
- - !ruby/object:Gem::Version
30
- version: 0.9.10
31
- - !ruby/object:Gem::Dependency
32
- name: httpclient
33
- requirement: !ruby/object:Gem::Requirement
24
+ requirement: &id001 !ruby/object:Gem::Requirement
34
25
  none: false
35
- requirements:
26
+ requirements:
36
27
  - - ~>
37
- - !ruby/object:Gem::Version
38
- version: 2.2.3
28
+ - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 0
34
+ version: 1.0.0
39
35
  type: :runtime
40
- prerelease: false
41
- version_requirements: !ruby/object:Gem::Requirement
42
- none: false
43
- requirements:
44
- - - ~>
45
- - !ruby/object:Gem::Version
46
- version: 2.2.3
47
- - !ruby/object:Gem::Dependency
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
48
38
  name: httpi
49
- requirement: !ruby/object:Gem::Requirement
50
- none: false
51
- requirements:
52
- - - ~>
53
- - !ruby/object:Gem::Version
54
- version: 0.9.7
55
- type: :runtime
56
39
  prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
40
+ requirement: &id002 !ruby/object:Gem::Requirement
58
41
  none: false
59
- requirements:
42
+ requirements:
60
43
  - - ~>
61
- - !ruby/object:Gem::Version
62
- version: 0.9.7
63
- - !ruby/object:Gem::Dependency
44
+ - !ruby/object:Gem::Version
45
+ hash: 23
46
+ segments:
47
+ - 1
48
+ - 0
49
+ - 0
50
+ version: 1.0.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
64
54
  name: oauth
65
- requirement: !ruby/object:Gem::Requirement
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
66
57
  none: false
67
- requirements:
58
+ requirements:
68
59
  - - ~>
69
- - !ruby/object:Gem::Version
60
+ - !ruby/object:Gem::Version
61
+ hash: 5
62
+ segments:
63
+ - 0
64
+ - 4
65
+ - 5
70
66
  version: 0.4.5
71
67
  type: :runtime
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: oauth2
72
71
  prerelease: false
73
- version_requirements: !ruby/object:Gem::Requirement
72
+ requirement: &id004 !ruby/object:Gem::Requirement
74
73
  none: false
75
- requirements:
74
+ requirements:
76
75
  - - ~>
77
- - !ruby/object:Gem::Version
78
- version: 0.4.5
76
+ - !ruby/object:Gem::Version
77
+ hash: 1
78
+ segments:
79
+ - 0
80
+ - 7
81
+ - 1
82
+ version: 0.7.1
83
+ type: :runtime
84
+ version_requirements: *id004
79
85
  description: Essential utilities shared by all Ads Ruby client libraries
80
- email:
86
+ email:
81
87
  - api.dklimkin@gmail.com
82
88
  executables: []
89
+
83
90
  extensions: []
91
+
84
92
  extra_rdoc_files: []
85
- files:
93
+
94
+ files:
86
95
  - lib/ads_common/api.rb
87
96
  - lib/ads_common/utils.rb
88
97
  - lib/ads_common/version.rb
@@ -90,6 +99,7 @@ files:
90
99
  - lib/ads_common/savon_service.rb
91
100
  - lib/ads_common/api_config.rb
92
101
  - lib/ads_common/auth/client_login_handler.rb
102
+ - lib/ads_common/auth/oauth2_handler.rb
93
103
  - lib/ads_common/auth/oauth_handler.rb
94
104
  - lib/ads_common/auth/base_handler.rb
95
105
  - lib/ads_common/http.rb
@@ -120,29 +130,40 @@ files:
120
130
  - ChangeLog
121
131
  homepage: http://code.google.com/p/google-api-ads-ruby/
122
132
  licenses: []
133
+
123
134
  post_install_message:
124
135
  rdoc_options: []
125
- require_paths:
136
+
137
+ require_paths:
126
138
  - lib
127
- required_ruby_version: !ruby/object:Gem::Requirement
139
+ required_ruby_version: !ruby/object:Gem::Requirement
128
140
  none: false
129
- requirements:
130
- - - ! '>='
131
- - !ruby/object:Gem::Version
132
- version: '0'
133
- required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ hash: 3
145
+ segments:
146
+ - 0
147
+ version: "0"
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
149
  none: false
135
- requirements:
136
- - - ! '>='
137
- - !ruby/object:Gem::Version
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ hash: 23
154
+ segments:
155
+ - 1
156
+ - 3
157
+ - 6
138
158
  version: 1.3.6
139
159
  requirements: []
160
+
140
161
  rubyforge_project: google-ads-common
141
162
  rubygems_version: 1.8.24
142
163
  signing_key:
143
164
  specification_version: 3
144
165
  summary: Common code for Google Ads APIs
145
- test_files:
166
+ test_files:
146
167
  - test/test_savon_service.rb
147
168
  - test/test_results_extractor.rb
148
169
  - test/test_credential_handler.rb