google-ads-common 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +5 -0
- data/README +1 -4
- data/Rakefile +2 -2
- data/lib/ads_common/api.rb +106 -16
- data/lib/ads_common/api_config.rb +2 -3
- data/lib/ads_common/auth/base_handler.rb +22 -3
- data/lib/ads_common/auth/client_login_handler.rb +27 -32
- data/lib/ads_common/auth/oauth_handler.rb +260 -0
- data/lib/ads_common/build/savon_abstract_generator.rb +12 -11
- data/lib/ads_common/build/savon_generator.rb +31 -27
- data/lib/ads_common/build/savon_registry.rb +46 -23
- data/lib/ads_common/build/savon_registry_generator.rb +23 -10
- data/lib/ads_common/build/savon_service_generator.rb +17 -3
- data/lib/ads_common/config.rb +1 -1
- data/lib/ads_common/credential_handler.rb +3 -7
- data/lib/ads_common/errors.rb +18 -6
- data/lib/ads_common/savon_headers/base_header_handler.rb +80 -0
- data/lib/ads_common/{soap4r_logger.rb → savon_headers/httpi_request_proxy.rb} +27 -20
- data/lib/ads_common/savon_headers/oauth_header_handler.rb +92 -0
- data/lib/ads_common/savon_headers/simple_header_handler.rb +17 -49
- data/lib/ads_common/savon_service.rb +129 -41
- data/test/test_savon_service.rb +9 -4
- metadata +39 -43
- data/lib/ads_common/build/rake_common.rb +0 -343
- data/lib/ads_common/build/soap4r_generator.rb +0 -565
- data/lib/ads_common/savon_headers/client_login_header_handler.rb +0 -60
- data/lib/ads_common/soap4r_headers/nested_header_handler.rb +0 -50
- data/lib/ads_common/soap4r_headers/single_header_handler.rb +0 -44
- data/lib/ads_common/soap4r_patches.rb +0 -210
- data/lib/ads_common/soap4r_response_handler.rb +0 -80
data/ChangeLog
CHANGED
data/README
CHANGED
@@ -17,8 +17,7 @@ Install it using the gem install command.
|
|
17
17
|
$ gem install --local google-ads-common-VERSION.gem
|
18
18
|
|
19
19
|
The following gem libraries are required:
|
20
|
-
-
|
21
|
-
- savon v0.9.1 or greater (for savon-enabled libraries);
|
20
|
+
- savon v0.9.6;
|
22
21
|
- httpi v0.9.2 or greater;
|
23
22
|
- httpclient v2.1.6 or greater.
|
24
23
|
|
@@ -33,8 +32,6 @@ The following gem libraries are required:
|
|
33
32
|
build-time tasks for client libraries (not for google-ads-common).
|
34
33
|
- +savon_headers/+: Contains classes that handle header injection into savon
|
35
34
|
requests.
|
36
|
-
- +soap4r_headers/+: Contains classes that handle header injection into soap4r
|
37
|
-
requests.
|
38
35
|
- +test/+: Contains the unit tests for the library.
|
39
36
|
|
40
37
|
== 2 - Commands
|
data/Rakefile
CHANGED
@@ -47,10 +47,10 @@ spec = Gem::Specification.new do |s|
|
|
47
47
|
s.test_files = tests
|
48
48
|
s.has_rdoc = true
|
49
49
|
s.extra_rdoc_files = docs
|
50
|
-
s.add_dependency('savon', '
|
51
|
-
s.add_dependency('soap4r', '= 1.5.8')
|
50
|
+
s.add_dependency('savon', '= 0.9.6')
|
52
51
|
s.add_dependency('httpclient', '>= 2.1.6')
|
53
52
|
s.add_dependency('httpi', '~> 0.9.2')
|
53
|
+
s.add_dependency('oauth', '~> 0.4.5')
|
54
54
|
end
|
55
55
|
|
56
56
|
desc 'Default target - build'
|
data/lib/ads_common/api.rb
CHANGED
@@ -21,9 +21,10 @@
|
|
21
21
|
|
22
22
|
require 'logger'
|
23
23
|
|
24
|
+
require 'ads_common/config'
|
24
25
|
require 'ads_common/errors'
|
25
|
-
require 'ads_common/auth/base_handler'
|
26
26
|
require 'ads_common/auth/client_login_handler'
|
27
|
+
require 'ads_common/auth/oauth_handler'
|
27
28
|
|
28
29
|
module AdsCommon
|
29
30
|
class Api
|
@@ -46,17 +47,18 @@ module AdsCommon
|
|
46
47
|
create_default_logger() : provided_logger
|
47
48
|
|
48
49
|
# Check for valid environment.
|
49
|
-
env_string = config.read('service.environment')
|
50
|
+
env_string = @config.read('service.environment')
|
50
51
|
environment = (env_string.nil?) ? api_config.default_environment :
|
51
52
|
env_string.to_s.upcase.to_sym
|
52
53
|
if api_config.environments.include?(environment)
|
53
|
-
config.set('service.environment', environment)
|
54
|
+
@config.set('service.environment', environment)
|
54
55
|
else
|
55
56
|
raise AdsCommon::Errors::Error,
|
56
57
|
"Unknown or unspecified environment: \"%s\"" % env_string
|
57
58
|
end
|
58
59
|
|
59
|
-
|
60
|
+
# Service wrappers.
|
61
|
+
@wrappers = {}
|
60
62
|
end
|
61
63
|
|
62
64
|
# Sets the logger to use.
|
@@ -112,6 +114,43 @@ module AdsCommon
|
|
112
114
|
return wrapper
|
113
115
|
end
|
114
116
|
|
117
|
+
# Authorize with specified authentication method.
|
118
|
+
#
|
119
|
+
# Args:
|
120
|
+
# - parameters - hash of credentials to add to configuration
|
121
|
+
# - block - code block to handle auth login url
|
122
|
+
#
|
123
|
+
# Returns:
|
124
|
+
# - Auth token for the method
|
125
|
+
#
|
126
|
+
# Throws:
|
127
|
+
# - AdsCommon::Errors::AuthError or derived if authetication error has
|
128
|
+
# occured
|
129
|
+
#
|
130
|
+
def authorize(parameters = {}, &block)
|
131
|
+
parameters.each_pair do |key, value|
|
132
|
+
@credential_handler.set_credential(key, value)
|
133
|
+
end
|
134
|
+
@auth_handler = get_auth_handler(@config.read('service.environment'))
|
135
|
+
|
136
|
+
# Token might still be valid, if not ask for a new one.
|
137
|
+
token = @auth_handler.get_token() ||
|
138
|
+
begin
|
139
|
+
@auth_handler.get_token(@credential_handler.credentials)
|
140
|
+
rescue AdsCommon::Errors::OAuthVerificationRequired => e
|
141
|
+
verification_code = (block_given?) ? yield(e.oauth_url) : nil
|
142
|
+
# Retry with verification code if one provided.
|
143
|
+
if verification_code
|
144
|
+
@credential_handler.set_credential(
|
145
|
+
:oauth_verification_code, verification_code)
|
146
|
+
retry
|
147
|
+
else
|
148
|
+
raise e
|
149
|
+
end
|
150
|
+
end
|
151
|
+
return token
|
152
|
+
end
|
153
|
+
|
115
154
|
private
|
116
155
|
|
117
156
|
# Retrieve the SOAP header handlers to plug into the drivers. Needs to
|
@@ -132,33 +171,77 @@ module AdsCommon
|
|
132
171
|
raise NotImplementedError, 'soap_header_handlers not overriden.'
|
133
172
|
end
|
134
173
|
|
135
|
-
# Auxiliary method to
|
136
|
-
#
|
137
|
-
# used in different APIs and API versions.
|
174
|
+
# Auxiliary method to get an authentication handler. Creates a new one if
|
175
|
+
# the handler has not been initialized yet.
|
138
176
|
#
|
139
177
|
# Args:
|
140
178
|
# - environment: the current working environment (production, sandbox, etc.)
|
141
|
-
# - version: intended API version
|
179
|
+
# - version: intended API version, must be a symbol, optional
|
180
|
+
#
|
181
|
+
# Returns:
|
182
|
+
# - auth handler
|
183
|
+
#
|
184
|
+
def get_auth_handler(environment, version = nil)
|
185
|
+
@auth_handler ||= create_auth_handler(environment, version)
|
186
|
+
return @auth_handler
|
187
|
+
end
|
188
|
+
|
189
|
+
# Auxiliary method to create an authentication handler.
|
190
|
+
#
|
191
|
+
# Args:
|
192
|
+
# - environment: the current working environment (production, sandbox, etc.)
|
193
|
+
# - version: intended API version, must be a symbol, optional
|
142
194
|
#
|
143
195
|
# Returns:
|
144
196
|
# - auth handler
|
145
197
|
#
|
146
|
-
def create_auth_handler(environment, version)
|
147
|
-
|
198
|
+
def create_auth_handler(environment, version = nil)
|
199
|
+
auth_method_str = @config.read('authentication.method', 'ClientLogin')
|
200
|
+
auth_method = auth_method_str.to_s.upcase.to_sym
|
201
|
+
return case auth_method
|
202
|
+
when :CLIENTLOGIN
|
203
|
+
auth_server = api_config.auth_server(environment)
|
204
|
+
AdsCommon::Auth::ClientLoginHandler.new(config, auth_server,
|
205
|
+
api_config.headers_config[:LOGIN_SERVICE_NAME])
|
206
|
+
when :OAUTH
|
207
|
+
scope = api_config.environment_config()[environment][:oauth_scope]
|
208
|
+
AdsCommon::Auth::OAuthHandler.new(config, scope)
|
209
|
+
else
|
210
|
+
raise AdsCommon::Errors::Error,
|
211
|
+
"Unknown authentication method '%s'." % auth_method_str
|
212
|
+
end
|
148
213
|
end
|
149
214
|
|
150
|
-
# Handle loading of a single service
|
151
|
-
#
|
215
|
+
# Handle loading of a single service.
|
216
|
+
# Creates the driver, sets up handlers, declares the appropriate wrapper
|
217
|
+
# class and creates an instance of it.
|
152
218
|
#
|
153
219
|
# Args:
|
154
|
-
# - version: intended API version
|
155
|
-
# - service: name for the intended service
|
220
|
+
# - version: intended API version, must be a symbol
|
221
|
+
# - service: name for the intended service
|
156
222
|
#
|
157
223
|
# Returns:
|
158
|
-
# - a wrapper generated for the
|
224
|
+
# - a simplified wrapper generated for the driver
|
159
225
|
#
|
160
226
|
def prepare_wrapper(version, service)
|
161
|
-
|
227
|
+
environment = config.read('service.environment')
|
228
|
+
api_config.do_require(version, service)
|
229
|
+
endpoint = api_config.endpoint(environment, version, service)
|
230
|
+
interface_class_name = api_config.interface_name(version, service)
|
231
|
+
endpoint_url = endpoint.nil? ? nil : endpoint + service.to_s
|
232
|
+
wrapper = class_for_path(interface_class_name).new(self, endpoint_url)
|
233
|
+
|
234
|
+
auth_handler = get_auth_handler(environment, version)
|
235
|
+
header_list =
|
236
|
+
auth_handler.header_list(@credential_handler.credentials(version))
|
237
|
+
|
238
|
+
soap_handlers = soap_header_handlers(auth_handler, header_list,
|
239
|
+
version, wrapper.namespace)
|
240
|
+
soap_handlers.each do |handler|
|
241
|
+
wrapper.headerhandler << handler
|
242
|
+
end
|
243
|
+
|
244
|
+
return wrapper
|
162
245
|
end
|
163
246
|
|
164
247
|
# Auxiliary method to create a default Logger.
|
@@ -196,5 +279,12 @@ module AdsCommon
|
|
196
279
|
end
|
197
280
|
return result
|
198
281
|
end
|
282
|
+
|
283
|
+
# Converts complete class path into class object.
|
284
|
+
def class_for_path(path)
|
285
|
+
path.split('::').inject(Kernel) do |scope, const_name|
|
286
|
+
scope.const_get(const_name)
|
287
|
+
end
|
288
|
+
end
|
199
289
|
end
|
200
290
|
end
|
@@ -26,7 +26,7 @@ module AdsCommon
|
|
26
26
|
# Contains helper methods for loading and managing the available services.
|
27
27
|
# This module is meant to be imported into API-specific modules.
|
28
28
|
module ApiConfig
|
29
|
-
ADS_COMMON_VERSION = '0.
|
29
|
+
ADS_COMMON_VERSION = '0.5.0'
|
30
30
|
|
31
31
|
# Get the available API versions.
|
32
32
|
#
|
@@ -156,8 +156,7 @@ module AdsCommon
|
|
156
156
|
def auth_server(environment)
|
157
157
|
auth_server_url =
|
158
158
|
ENV['ADSAPI_AUTH_URL'] ||
|
159
|
-
auth_server_config[environment]
|
160
|
-
auth_server_config[default_environment()]
|
159
|
+
auth_server_config[environment]
|
161
160
|
return auth_server_url
|
162
161
|
end
|
163
162
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# Authors:: api.sgomes@gmail.com (Sérgio Gomes)
|
4
4
|
#
|
5
|
-
# Copyright:: Copyright
|
5
|
+
# Copyright:: Copyright 2011, Google Inc. All Rights Reserved.
|
6
6
|
#
|
7
7
|
# License:: Licensed under the Apache License, Version 2.0 (the "License");
|
8
8
|
# you may not use this file except in compliance with the License.
|
@@ -24,6 +24,13 @@
|
|
24
24
|
module AdsCommon
|
25
25
|
module Auth
|
26
26
|
class BaseHandler
|
27
|
+
# Default initializer.
|
28
|
+
def initialize(config)
|
29
|
+
@config = config
|
30
|
+
@logger = @config.read('library.logger')
|
31
|
+
@token = nil
|
32
|
+
end
|
33
|
+
|
27
34
|
# Callback to be used by CredentialHandlers to notify the auth handler of
|
28
35
|
# a change in one of the credentials. Useful for e.g. invalidating a
|
29
36
|
# token. The generic method does nothing.
|
@@ -40,13 +47,25 @@ module AdsCommon
|
|
40
47
|
# This method returns the set of fields to be included in the header.
|
41
48
|
# The generic method simply returns everything passed to it.
|
42
49
|
def header_list(credentials)
|
43
|
-
return credentials.keys
|
50
|
+
return credentials.keys.dup()
|
44
51
|
end
|
45
52
|
|
46
53
|
# This method returns the key value pairs to be included in the header.
|
47
54
|
# The generic method simply returns everything passed to it.
|
48
55
|
def headers(credentials)
|
49
|
-
return credentials
|
56
|
+
return credentials.dup()
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns authorization token of some kind. Attempts to create a new one
|
60
|
+
# if the token has not yet been created and credentials present.
|
61
|
+
def get_token(credentials = nil)
|
62
|
+
@token = create_token(credentials) if @token.nil? and credentials
|
63
|
+
return @token
|
64
|
+
end
|
65
|
+
|
66
|
+
# Creates authorization token. Needs to be overriden.
|
67
|
+
def create_token(credentials)
|
68
|
+
raise NotImplementedError, 'create_token not overriden.'
|
50
69
|
end
|
51
70
|
end
|
52
71
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
#
|
3
|
-
# Authors:: api.
|
4
|
-
# api.dklimkin@gmail.com (Danial Klimkin)
|
3
|
+
# Authors:: api.dklimkin@gmail.com (Danial Klimkin)
|
5
4
|
#
|
6
5
|
# Copyright:: Copyright 2011, Google Inc. All Rights Reserved.
|
7
6
|
#
|
@@ -32,15 +31,13 @@ module AdsCommon
|
|
32
31
|
|
33
32
|
# Credentials class to handle ClientLogin authentication.
|
34
33
|
class ClientLoginHandler < AdsCommon::Auth::BaseHandler
|
35
|
-
|
36
34
|
ACCOUNT_TYPE = 'GOOGLE'
|
37
35
|
AUTH_PATH = '/accounts/ClientLogin'
|
38
36
|
IGNORED_FIELDS = [:email, :password, :auth_token]
|
39
37
|
|
40
38
|
# Initializes the ClientLoginHandler with all the necessary details.
|
41
39
|
def initialize(config, server, service_name)
|
42
|
-
|
43
|
-
@config = config
|
40
|
+
super(config)
|
44
41
|
@server = server
|
45
42
|
@service_name = service_name
|
46
43
|
end
|
@@ -48,10 +45,7 @@ module AdsCommon
|
|
48
45
|
# Invalidates the stored token if the email, password or provided auth
|
49
46
|
# token have changed.
|
50
47
|
def property_changed(prop, value)
|
51
|
-
|
52
|
-
when :auth_token
|
53
|
-
@token = config.read('authentication.auth_token')
|
54
|
-
when :email, :password
|
48
|
+
if [:auth_token, :email, :password].include?(prop)
|
55
49
|
@token = nil
|
56
50
|
end
|
57
51
|
end
|
@@ -65,23 +59,20 @@ module AdsCommon
|
|
65
59
|
|
66
60
|
# Returns all of the fields that this auth handler will fill.
|
67
61
|
def header_list(credentials)
|
68
|
-
result =
|
69
|
-
|
70
|
-
credentials.each do |p, v|
|
71
|
-
result << p unless IGNORED_FIELDS.include?(p)
|
62
|
+
result = credentials.keys.map.reject do |field|
|
63
|
+
IGNORED_FIELDS.include?(field)
|
72
64
|
end
|
65
|
+
result << :authToken
|
73
66
|
return result
|
74
67
|
end
|
75
68
|
|
76
69
|
# Returns all of the credentials received from the CredentialHandler,
|
77
|
-
# except for
|
70
|
+
# except for ignored fields.
|
78
71
|
def headers(credentials)
|
79
|
-
|
80
|
-
|
81
|
-
result[:authToken] = @token
|
82
|
-
credentials.each do |p, v|
|
83
|
-
result[p] = v unless IGNORED_FIELDS.include?(p)
|
72
|
+
result = credentials.reject do |field, value|
|
73
|
+
IGNORED_FIELDS.include?(field)
|
84
74
|
end
|
75
|
+
result[:authToken] = get_token(credentials)
|
85
76
|
return result
|
86
77
|
end
|
87
78
|
|
@@ -93,9 +84,8 @@ module AdsCommon
|
|
93
84
|
# - credentials: a hash with the credentials for the account being
|
94
85
|
# accessed
|
95
86
|
#
|
96
|
-
#
|
97
87
|
# Raises:
|
98
|
-
# AdsCommon::Errors::AuthError if validation fails
|
88
|
+
# - AdsCommon::Errors::AuthError if validation fails
|
99
89
|
#
|
100
90
|
def validate_credentials(credentials)
|
101
91
|
if credentials.nil?
|
@@ -114,7 +104,7 @@ module AdsCommon
|
|
114
104
|
end
|
115
105
|
end
|
116
106
|
|
117
|
-
# Auxiliary method to generate an authentication token for
|
107
|
+
# Auxiliary method to generate an authentication token for login in via
|
118
108
|
# the ClientLogin API.
|
119
109
|
#
|
120
110
|
# Args:
|
@@ -122,11 +112,18 @@ module AdsCommon
|
|
122
112
|
# accessed
|
123
113
|
#
|
124
114
|
# Returns:
|
125
|
-
# The auth token for the account (as a string)
|
115
|
+
# - The auth token for the account (as a string)
|
126
116
|
#
|
127
117
|
# Raises:
|
128
|
-
# AdsCommon::Errors::AuthError if authentication fails
|
118
|
+
# - AdsCommon::Errors::AuthError if authentication fails
|
129
119
|
#
|
120
|
+
def create_token(credentials)
|
121
|
+
token = @config.read('authentication.auth_token') ||
|
122
|
+
generate_token(credentials)
|
123
|
+
return token
|
124
|
+
end
|
125
|
+
|
126
|
+
# Generates new client login token based on credentials.
|
130
127
|
def generate_token(credentials)
|
131
128
|
validate_credentials(credentials)
|
132
129
|
|
@@ -147,25 +144,23 @@ module AdsCommon
|
|
147
144
|
else
|
148
145
|
error_message = "Login failed for email %s: HTTP code %d." %
|
149
146
|
[credentials[:email], response.code]
|
150
|
-
|
151
|
-
|
152
|
-
else
|
153
|
-
error_message += " Raw error: %s." % response.body
|
154
|
-
end
|
147
|
+
error_str = results[:Error] || response.body
|
148
|
+
error_message += " Error: %s." % error_str if error_str
|
155
149
|
if results.include?(:Info)
|
156
150
|
error_message += " Info: %s." % results[:Info]
|
157
151
|
end
|
158
|
-
raise AdsCommon::Errors::AuthError,
|
152
|
+
raise AdsCommon::Errors::AuthError.new(error_message, error_str,
|
153
|
+
results[:Info])
|
159
154
|
end
|
160
155
|
end
|
161
156
|
|
162
157
|
# Extracts key-value pairs from ClientLogin server response.
|
163
158
|
#
|
164
159
|
# Args:
|
165
|
-
# - text: server response string
|
160
|
+
# - text: server response string
|
166
161
|
#
|
167
162
|
# Returns:
|
168
|
-
# Hash of key-value pairs
|
163
|
+
# Hash of key-value pairs
|
169
164
|
#
|
170
165
|
def parse_token_text(text)
|
171
166
|
result = {}
|
@@ -0,0 +1,260 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
# Authors:: api.dklimkin@gmail.com (Danial Klimkin)
|
4
|
+
#
|
5
|
+
# Copyright:: Copyright 2011, 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 OAuth authentication.
|
21
|
+
|
22
|
+
require 'oauth'
|
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 OAuth authentication.
|
31
|
+
class OAuthHandler < AdsCommon::Auth::BaseHandler
|
32
|
+
IGNORED_FIELDS = [
|
33
|
+
:email, :password, :auth_token,
|
34
|
+
:oauth_verification_code, :oauth_consumer_secret, :oauth_consumer_key
|
35
|
+
]
|
36
|
+
|
37
|
+
OAUTH_CONFIG = {
|
38
|
+
:site => "https://www.google.com",
|
39
|
+
:request_token_path => "/accounts/OAuthGetRequestToken",
|
40
|
+
:access_token_path => "/accounts/OAuthGetAccessToken",
|
41
|
+
:authorize_path => "/accounts/OAuthAuthorizeToken"
|
42
|
+
}
|
43
|
+
|
44
|
+
DEFAULT_CALLBACK = 'oob'
|
45
|
+
DEFAULT_METHOD = 'HMAC-SHA1'
|
46
|
+
|
47
|
+
# Initializes the OAuthHandler with all the necessary details.
|
48
|
+
#
|
49
|
+
# Args:
|
50
|
+
# - config: Config object with library configuration
|
51
|
+
# - scope: OAuth authorization scope
|
52
|
+
#
|
53
|
+
def initialize(config, scope)
|
54
|
+
super(config)
|
55
|
+
@scope = scope
|
56
|
+
end
|
57
|
+
|
58
|
+
def handle_error(error)
|
59
|
+
# TODO: Add support.
|
60
|
+
raise error
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns all of the fields that this auth handler will fill.
|
64
|
+
#
|
65
|
+
# Args:
|
66
|
+
# - credentials: request credentials
|
67
|
+
#
|
68
|
+
# Returns:
|
69
|
+
# - array with header names
|
70
|
+
#
|
71
|
+
def header_list(credentials)
|
72
|
+
result = credentials.keys.map.reject do |field|
|
73
|
+
IGNORED_FIELDS.include?(field)
|
74
|
+
end
|
75
|
+
result << :access_token
|
76
|
+
return result
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns all of the credentials received from the CredentialHandler,
|
80
|
+
# except for ignored fields.
|
81
|
+
#
|
82
|
+
# Args:
|
83
|
+
# - credentials: request credentials
|
84
|
+
#
|
85
|
+
# Returns:
|
86
|
+
# - hash with header names and values
|
87
|
+
#
|
88
|
+
def headers(credentials)
|
89
|
+
result = credentials.reject do |field, value|
|
90
|
+
IGNORED_FIELDS.include?(field)
|
91
|
+
end
|
92
|
+
result[:access_token] = get_token(credentials)
|
93
|
+
return result
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns OAuth-specific Consumer object.
|
97
|
+
def get_oauth_consumer()
|
98
|
+
return @consumer
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
# Auxiliary method to validate the credentials for token generation.
|
104
|
+
#
|
105
|
+
# Args:
|
106
|
+
# - credentials: a hash with the credentials for the account being
|
107
|
+
# accessed
|
108
|
+
#
|
109
|
+
# Raises:
|
110
|
+
# - AdsCommon::Errors::AuthError if validation fails
|
111
|
+
#
|
112
|
+
def validate_credentials(credentials)
|
113
|
+
if credentials.nil?
|
114
|
+
raise AdsCommon::Errors::AuthError, 'No credentials supplied.'
|
115
|
+
end
|
116
|
+
|
117
|
+
if credentials[:oauth_consumer_key].nil?
|
118
|
+
raise AdsCommon::Errors::AuthError,
|
119
|
+
'Consumer key not included in credentials.'
|
120
|
+
end
|
121
|
+
|
122
|
+
if credentials[:oauth_consumer_secret].nil?
|
123
|
+
raise AdsCommon::Errors::AuthError,
|
124
|
+
'Consumer secret not included in credentials.'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Auxiliary method to generate an authentication token for logging via
|
129
|
+
# the OAuth API.
|
130
|
+
#
|
131
|
+
# Args:
|
132
|
+
# - credentials: a hash with the credentials for the account being
|
133
|
+
# accessed
|
134
|
+
#
|
135
|
+
# Returns:
|
136
|
+
# - The auth token for the account (as an AccessToken)
|
137
|
+
#
|
138
|
+
# Raises:
|
139
|
+
# - AdsCommon::Errors::AuthError if authentication fails
|
140
|
+
# - AdsCommon::Errors::OAuthVerificationRequired if OAuth verification
|
141
|
+
# code required
|
142
|
+
#
|
143
|
+
def create_token(credentials)
|
144
|
+
validate_credentials(credentials)
|
145
|
+
if @consumer.nil?
|
146
|
+
oauth_config = OAUTH_CONFIG.merge({:scope => @scope})
|
147
|
+
@consumer = OAuth::Consumer.new(credentials[:oauth_consumer_key],
|
148
|
+
credentials[:oauth_consumer_secret], oauth_config)
|
149
|
+
end
|
150
|
+
return create_token_from_credentials(credentials) ||
|
151
|
+
generate_access_token(credentials)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Creates access token based on data from credentials.
|
155
|
+
#
|
156
|
+
# Args:
|
157
|
+
# - credentials: a hash with the credentials for the account being
|
158
|
+
# accessed
|
159
|
+
#
|
160
|
+
# Returns:
|
161
|
+
# - The auth token for the account (as an AccessToken)
|
162
|
+
#
|
163
|
+
def create_token_from_credentials(credentials)
|
164
|
+
access_token = nil
|
165
|
+
|
166
|
+
token = credentials[:oauth_token]
|
167
|
+
if !token.nil? and !token.empty?
|
168
|
+
method = credentials[:oauth_method] || DEFAULT_METHOD
|
169
|
+
access_token = case method
|
170
|
+
when 'RSA-SHA1'
|
171
|
+
OAuth::AccessToken.from_hash(@consumer, {:oauth_token => token})
|
172
|
+
when 'HMAC-SHA1'
|
173
|
+
token_secret = credentials[:oauth_token_secret]
|
174
|
+
if token_secret.nil? or token_secret.empty?
|
175
|
+
@logger.warn(("The 'token' specified for method %s but " +
|
176
|
+
"'token secret' is not available, ignoring token") % method)
|
177
|
+
nil
|
178
|
+
else
|
179
|
+
OAuth::AccessToken.from_hash(@consumer, {
|
180
|
+
:oauth_token => token, :oauth_token_secret => token_secret})
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
return access_token
|
185
|
+
end
|
186
|
+
|
187
|
+
# Generates new request tokens and authorizes it to get access token.
|
188
|
+
#
|
189
|
+
# Args:
|
190
|
+
# - credentials: a hash with the credentials for the account being
|
191
|
+
# accessed
|
192
|
+
#
|
193
|
+
# Returns:
|
194
|
+
# - The auth token for the account (as an AccessToken)
|
195
|
+
#
|
196
|
+
def generate_access_token(credentials)
|
197
|
+
token = nil
|
198
|
+
callback = credentials[:oauth_callback] || DEFAULT_CALLBACK
|
199
|
+
begin
|
200
|
+
if @request_token.nil?
|
201
|
+
@request_token = @consumer.get_request_token(
|
202
|
+
{:oauth_callback => callback}, {:scope => @scope})
|
203
|
+
raise_oauth_verification_error(@request_token, callback)
|
204
|
+
end
|
205
|
+
verification_code = credentials[:oauth_verification_code]
|
206
|
+
if verification_code.nil? || verification_code.empty?
|
207
|
+
raise_oauth_verification_error(@request_token, callback)
|
208
|
+
else
|
209
|
+
token = @request_token.get_access_token(
|
210
|
+
{:oauth_verifier => verification_code})
|
211
|
+
@request_token = nil
|
212
|
+
end
|
213
|
+
rescue OAuth::Unauthorized => e
|
214
|
+
if @request_token
|
215
|
+
raise_oauth_verification_error(@request_token, callback)
|
216
|
+
else
|
217
|
+
raise AdsCommon::Errors::AuthError,
|
218
|
+
"Authorization error occured: %s" % e
|
219
|
+
end
|
220
|
+
end
|
221
|
+
return token
|
222
|
+
end
|
223
|
+
|
224
|
+
# Raises a OAuthVerificationRequired error with auth URL for given
|
225
|
+
# request token.
|
226
|
+
#
|
227
|
+
# Args:
|
228
|
+
# - request_token: an initialized OAuth request token
|
229
|
+
# - callback: OAuth callback URL
|
230
|
+
#
|
231
|
+
# Returns:
|
232
|
+
# - never returns
|
233
|
+
#
|
234
|
+
# Raises:
|
235
|
+
# - AdsCommon::Errors::OAuthVerificationRequired in all cases
|
236
|
+
#
|
237
|
+
def raise_oauth_verification_error(request_token, callback)
|
238
|
+
oauth_url = request_token.authorize_url({:oauth_callback => callback})
|
239
|
+
raise AdsCommon::Errors::OAuthVerificationRequired, oauth_url
|
240
|
+
end
|
241
|
+
|
242
|
+
# Extracts key-value pairs from OAuth server response.
|
243
|
+
#
|
244
|
+
# Args:
|
245
|
+
# - text: server response string
|
246
|
+
#
|
247
|
+
# Returns:
|
248
|
+
# - Hash of key-value pairs
|
249
|
+
#
|
250
|
+
def parse_token_text(text)
|
251
|
+
result = {}
|
252
|
+
text.split('&').each do |line|
|
253
|
+
key, value = line.split("=")
|
254
|
+
result[key.to_sym] = value
|
255
|
+
end
|
256
|
+
return result
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|