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.
Files changed (30) hide show
  1. data/ChangeLog +5 -0
  2. data/README +1 -4
  3. data/Rakefile +2 -2
  4. data/lib/ads_common/api.rb +106 -16
  5. data/lib/ads_common/api_config.rb +2 -3
  6. data/lib/ads_common/auth/base_handler.rb +22 -3
  7. data/lib/ads_common/auth/client_login_handler.rb +27 -32
  8. data/lib/ads_common/auth/oauth_handler.rb +260 -0
  9. data/lib/ads_common/build/savon_abstract_generator.rb +12 -11
  10. data/lib/ads_common/build/savon_generator.rb +31 -27
  11. data/lib/ads_common/build/savon_registry.rb +46 -23
  12. data/lib/ads_common/build/savon_registry_generator.rb +23 -10
  13. data/lib/ads_common/build/savon_service_generator.rb +17 -3
  14. data/lib/ads_common/config.rb +1 -1
  15. data/lib/ads_common/credential_handler.rb +3 -7
  16. data/lib/ads_common/errors.rb +18 -6
  17. data/lib/ads_common/savon_headers/base_header_handler.rb +80 -0
  18. data/lib/ads_common/{soap4r_logger.rb → savon_headers/httpi_request_proxy.rb} +27 -20
  19. data/lib/ads_common/savon_headers/oauth_header_handler.rb +92 -0
  20. data/lib/ads_common/savon_headers/simple_header_handler.rb +17 -49
  21. data/lib/ads_common/savon_service.rb +129 -41
  22. data/test/test_savon_service.rb +9 -4
  23. metadata +39 -43
  24. data/lib/ads_common/build/rake_common.rb +0 -343
  25. data/lib/ads_common/build/soap4r_generator.rb +0 -565
  26. data/lib/ads_common/savon_headers/client_login_header_handler.rb +0 -60
  27. data/lib/ads_common/soap4r_headers/nested_header_handler.rb +0 -50
  28. data/lib/ads_common/soap4r_headers/single_header_handler.rb +0 -44
  29. data/lib/ads_common/soap4r_patches.rb +0 -210
  30. data/lib/ads_common/soap4r_response_handler.rb +0 -80
data/ChangeLog CHANGED
@@ -1,3 +1,8 @@
1
+ 0.5.0:
2
+ - Now support Savon 0.9.6.
3
+ - No longer depend on Soap4r.
4
+ - Support for OAuth authentication method.
5
+
1
6
  0.4.0:
2
7
  - Extracted soap4r specific code from main path.
3
8
  - APIs with Savon backend are now ruby1.9 - compatible.
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
- - soap4r v1.5.8 (only for soap4r-based libraries);
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', '~> 0.9.1')
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'
@@ -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
- @wrappers = Hash.new
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 create an authentication handler. Needs to be
136
- # implemented on the specific API because of the different nesting models
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
- raise NotImplementedError, 'create_auth_handler not overriden.'
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 wrapper. Needs to be implemented on
151
- # specific API level.
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. Must be a symbol.
155
- # - service: name for the intended service. Must be a symbol.
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 service.
224
+ # - a simplified wrapper generated for the driver
159
225
  #
160
226
  def prepare_wrapper(version, service)
161
- raise NotImplementedError, 'prepare_wrapper not overriden.'
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.4.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 2010, Google Inc. All Rights Reserved.
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.sgomes@gmail.com (Sérgio Gomes)
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
- @token = config.read('authentication.auth_token')
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
- case prop
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
- result << :authToken
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 email and password.
70
+ # except for ignored fields.
78
71
  def headers(credentials)
79
- @token = generate_token(credentials) if @token == nil
80
- result = {}
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 logging via
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
- if results.include?(:Error)
151
- error_message += " Error: %s." % results[:Error]
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, error_message
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