google-ads-common 0.6.4 → 0.7.0

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.
@@ -1,6 +1,6 @@
1
1
  # Encoding: utf-8
2
2
  #
3
- # Authors:: api.sgomes@gmail.com (Sérgio Gomes)
3
+ # Authors:: api.dklimkin@gmail.com (Danial Klimkin)
4
4
  #
5
5
  # Copyright:: Copyright 2010, Google Inc. All Rights Reserved.
6
6
  #
@@ -24,10 +24,10 @@
24
24
  module AdsCommon
25
25
  module Auth
26
26
  class BaseHandler
27
+
27
28
  # Default initializer.
28
29
  def initialize(config)
29
30
  @config = config
30
- @logger = @config.read('library.logger')
31
31
  @token = nil
32
32
  end
33
33
 
@@ -44,18 +44,6 @@ module AdsCommon
44
44
  raise error
45
45
  end
46
46
 
47
- # This method returns the set of fields to be included in the header.
48
- # The generic method simply returns everything passed to it.
49
- def header_list(credentials)
50
- return credentials.keys.dup()
51
- end
52
-
53
- # This method returns the key value pairs to be included in the header.
54
- # The generic method simply returns everything passed to it.
55
- def headers(credentials)
56
- return credentials.dup()
57
- end
58
-
59
47
  # Returns authorization token of some kind. Attempts to create a new one
60
48
  # if the token has not yet been created and credentials present.
61
49
  def get_token(credentials = nil)
@@ -63,15 +51,17 @@ module AdsCommon
63
51
  return @token
64
52
  end
65
53
 
66
- # Creates authorization token. Needs to be overridden.
67
- def create_token(credentials)
68
- raise NotImplementedError, 'create_token not overridden.'
69
- end
70
-
71
54
  # Returns authorization string. Needs to be overridden.
72
55
  def auth_string(credentials, request)
73
56
  raise NotImplementedError, 'auth_string not overridden.'
74
57
  end
58
+
59
+ private
60
+
61
+ # Creates authorization token. Needs to be overridden.
62
+ def create_token(credentials)
63
+ raise NotImplementedError, 'create_token not overridden.'
64
+ end
75
65
  end
76
66
  end
77
67
  end
@@ -33,53 +33,38 @@ module AdsCommon
33
33
  class ClientLoginHandler < AdsCommon::Auth::BaseHandler
34
34
  ACCOUNT_TYPE = 'GOOGLE'
35
35
  AUTH_PATH = '/accounts/ClientLogin'
36
+ AUTH_PREFIX = 'GoogleLogin auth='
36
37
  CAPTCHA_PATH = '/accounts/'
37
- IGNORED_FIELDS = [:email, :password, :auth_token]
38
38
 
39
39
  # Initializes the ClientLoginHandler with all the necessary details.
40
- def initialize(config, server, service_name)
40
+ def initialize(config, auth_server, service_name)
41
41
  super(config)
42
- @server = server
42
+ @server = auth_server
43
43
  @service_name = service_name
44
44
  end
45
45
 
46
46
  # Invalidates the stored token if the email, password or provided auth
47
47
  # token have changed.
48
48
  def property_changed(prop, value)
49
- if [:auth_token, :email, :password].include?(prop)
49
+ if [:email, :password].include?(prop)
50
50
  @token = nil
51
51
  end
52
+ if :auth_token.eql?(prop)
53
+ @token = create_token_from_string(value)
54
+ end
52
55
  end
53
56
 
54
57
  # Handle specific ClientLogin errors.
55
58
  def handle_error(error)
56
59
  # TODO: Add support for automatically regenerating auth tokens when they
57
60
  # expire.
61
+ get_logger().error(error)
58
62
  raise error
59
63
  end
60
64
 
61
- # Returns all of the fields that this auth handler will fill.
62
- def header_list(credentials)
63
- result = credentials.keys.map.reject do |field|
64
- IGNORED_FIELDS.include?(field)
65
- end
66
- result << :authToken
67
- return result
68
- end
69
-
70
- # Returns all of the credentials received from the CredentialHandler,
71
- # except for ignored fields.
72
- def headers(credentials)
73
- result = credentials.reject do |field, value|
74
- IGNORED_FIELDS.include?(field)
75
- end
76
- result[:authToken] = get_token(credentials)
77
- return result
78
- end
79
-
80
65
  # Returns authorization string.
81
66
  def auth_string(credentials, request)
82
- return ("GoogleLogin auth=%s" % get_token(credentials))
67
+ return [AUTH_PREFIX, get_token(credentials)].join
83
68
  end
84
69
 
85
70
  private
@@ -95,18 +80,23 @@ module AdsCommon
95
80
  #
96
81
  def validate_credentials(credentials)
97
82
  if credentials.nil?
98
- raise AdsCommon::Errors::AuthError,
99
- 'No credentials supplied.'
100
- end
101
-
102
- if credentials[:email].nil?
103
- raise AdsCommon::Errors::AuthError,
104
- 'Email address not included in credentials.'
83
+ raise AdsCommon::Errors::AuthError, 'No credentials supplied.'
105
84
  end
106
85
 
107
- if credentials[:password].nil?
108
- raise AdsCommon::Errors::AuthError,
109
- 'Password not included in credentials.'
86
+ if credentials[:auth_token].nil?
87
+ if credentials[:email].nil?
88
+ raise AdsCommon::Errors::AuthError,
89
+ 'Email address not included in credentials.'
90
+ end
91
+ if credentials[:password].nil?
92
+ raise AdsCommon::Errors::AuthError,
93
+ 'Password not included in credentials.'
94
+ end
95
+ else
96
+ if credentials[:email] and credentials[:password]
97
+ get_logger().warn('Both auth_token and login credentials present' +
98
+ ', preferring auth_token.')
99
+ end
110
100
  end
111
101
  end
112
102
 
@@ -118,35 +108,44 @@ module AdsCommon
118
108
  # accessed
119
109
  #
120
110
  # Returns:
121
- # - The auth token for the account (as a string)
111
+ # - The auth token for the account
122
112
  #
123
113
  # Raises:
124
114
  # - AdsCommon::Errors::AuthError if authentication fails
125
115
  #
126
116
  def create_token(credentials)
127
- token = @config.read('authentication.auth_token') ||
117
+ token = credentials.include?(:auth_token) ?
118
+ create_token_from_string(credentials[:auth_token]) :
128
119
  generate_token(credentials)
129
120
  return token
130
121
  end
131
122
 
132
- # Generates new client login token based on credentials.
133
- def generate_token(credentials)
134
- validate_credentials(credentials)
123
+ # Creates token for provided auth string. Trivial for this handler.
124
+ def create_token_from_string(token_string)
125
+ return token_string
126
+ end
135
127
 
128
+ # Prepares POST data for ClientLogin request.
129
+ def get_login_data(credentials)
136
130
  email = CGI.escape(credentials[:email])
137
131
  password = CGI.escape(credentials[:password])
138
-
139
- url = @server + AUTH_PATH
140
-
132
+ service_name = @service_name
141
133
  data = "accountType=%s&Email=%s&Passwd=%s&service=%s" %
142
- [ACCOUNT_TYPE, email, password, @service_name]
143
-
134
+ [ACCOUNT_TYPE, email, password, service_name]
144
135
  if credentials[:logintoken] and credentials[:logincaptcha]
145
136
  data += "&logintoken=%s&logincaptcha=%s" %
146
137
  [CGI.escape(credentials[:logintoken]),
147
138
  CGI.escape(credentials[:logincaptcha])]
148
139
  end
140
+ return data
141
+ end
142
+
143
+ # Generates new client login token based on credentials.
144
+ def generate_token(credentials)
145
+ validate_credentials(credentials)
149
146
 
147
+ url = @server + AUTH_PATH
148
+ data = get_login_data(credentials)
150
149
  headers = {'Content-Type' => 'application/x-www-form-urlencoded'}
151
150
 
152
151
  response = AdsCommon::Http.post_response(url, data, @config, headers)
@@ -29,17 +29,11 @@ module AdsCommon
29
29
 
30
30
  # Credentials class to handle OAuth authentication.
31
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
- :oauth_token_secret, :oauth_token
36
- ]
37
-
38
32
  OAUTH_CONFIG = {
39
- :site => "https://www.google.com",
40
- :request_token_path => "/accounts/OAuthGetRequestToken",
41
- :access_token_path => "/accounts/OAuthGetAccessToken",
42
- :authorize_path => "/accounts/OAuthAuthorizeToken"
33
+ :site => 'https://www.google.com',
34
+ :request_token_path => '/accounts/OAuthGetRequestToken',
35
+ :access_token_path => '/accounts/OAuthGetAccessToken',
36
+ :authorize_path => '/accounts/OAuthAuthorizeToken'
43
37
  }
44
38
 
45
39
  DEFAULT_CALLBACK = 'oob'
@@ -56,42 +50,17 @@ module AdsCommon
56
50
  @scope = scope
57
51
  end
58
52
 
59
- def handle_error(error)
60
- # TODO: Add support.
61
- raise error
62
- end
63
-
64
- # Returns all of the fields that this auth handler will fill.
65
- #
66
- # Args:
67
- # - credentials: request credentials
68
- #
69
- # Returns:
70
- # - array with header names
71
- #
72
- def header_list(credentials)
73
- result = credentials.keys.map.reject do |field|
74
- IGNORED_FIELDS.include?(field)
53
+ # Invalidates the stored token if the required credential has changed.
54
+ def property_changed(prop, value)
55
+ if [:oauth_consumer_key, :oauth_consumer_secret].include?(prop)
56
+ @consumer, @token, @request_token = nil, nil, nil
75
57
  end
76
- result << :access_token
77
- return result
78
58
  end
79
59
 
80
- # Returns all of the credentials received from the CredentialHandler,
81
- # except for ignored fields.
82
- #
83
- # Args:
84
- # - credentials: request credentials
85
- #
86
- # Returns:
87
- # - hash with header names and values
88
- #
89
- def headers(credentials)
90
- result = credentials.reject do |field, value|
91
- IGNORED_FIELDS.include?(field)
92
- end
93
- result[:access_token] = get_token(credentials)
94
- return result
60
+ def handle_error(error)
61
+ # TODO: Add support.
62
+ get_logger().error(error)
63
+ raise error
95
64
  end
96
65
 
97
66
  # Returns OAuth-specific Consumer object.
@@ -108,6 +77,8 @@ module AdsCommon
108
77
  return generate_oauth_parameters_string(credentials, request)
109
78
  end
110
79
 
80
+ private
81
+
111
82
  # Generates auth string for OAuth method of authentication.
112
83
  #
113
84
  # Args:
@@ -118,10 +89,11 @@ module AdsCommon
118
89
  # - Authentication string
119
90
  #
120
91
  def generate_oauth_parameters_string(credentials, request)
92
+ # get_token() ensures @consumer is initialized.
93
+ token = get_token(credentials)
121
94
  oauth_params = {
122
- # get_token() ensures @consumer is initialized.
123
- :token => get_token(credentials),
124
- :consumer => @consumer
95
+ :consumer => @consumer,
96
+ :token => token
125
97
  }
126
98
  oauth_helper = OAuth::Client::Helper.new(request, oauth_params)
127
99
  return oauth_helper.header
@@ -139,6 +111,10 @@ module AdsCommon
139
111
  # - AdsCommon::Errors::AuthError if validation fails
140
112
  #
141
113
  def validate_credentials(credentials)
114
+ if @scope.nil?
115
+ raise AdsCommon::Errors::AuthError, 'Scope is not specified.'
116
+ end
117
+
142
118
  if credentials.nil?
143
119
  raise AdsCommon::Errors::AuthError, 'No credentials supplied.'
144
120
  end
@@ -152,6 +128,8 @@ module AdsCommon
152
128
  raise AdsCommon::Errors::AuthError,
153
129
  'Consumer secret not included in credentials.'
154
130
  end
131
+
132
+ # TODO: add checks for both methods.
155
133
  end
156
134
 
157
135
  # Auxiliary method to generate an authentication token for logging via
@@ -171,15 +149,19 @@ module AdsCommon
171
149
  #
172
150
  def create_token(credentials)
173
151
  validate_credentials(credentials)
174
- if @consumer.nil?
175
- oauth_config = OAUTH_CONFIG.merge({:scope => @scope})
176
- proxy = @config.read('connection.proxy')
177
- oauth_config[:proxy] = proxy if !proxy.nil?
178
- @consumer = OAuth::Consumer.new(credentials[:oauth_consumer_key],
179
- credentials[:oauth_consumer_secret], oauth_config)
180
- end
181
- return create_token_from_credentials(credentials) ||
182
- generate_access_token(credentials)
152
+ @consumer ||= create_consumer(credentials)
153
+ return create_token_from_credentials(credentials, @consumer) ||
154
+ generate_access_token(credentials, @consumer)
155
+ end
156
+
157
+ def create_consumer(credentials)
158
+ oauth_config = OAUTH_CONFIG.merge({:scope => @scope})
159
+ proxy = @config.read('connection.proxy')
160
+ oauth_config[:proxy] = proxy unless proxy.nil?
161
+ return OAuth::Consumer.new(
162
+ credentials[:oauth_consumer_key],
163
+ credentials[:oauth_consumer_secret],
164
+ oauth_config)
183
165
  end
184
166
 
185
167
  # Creates access token based on data from credentials.
@@ -187,30 +169,31 @@ module AdsCommon
187
169
  # Args:
188
170
  # - credentials: a hash with the credentials for the account being
189
171
  # accessed
172
+ # - consumer: OAuth consumer for the current configuration
190
173
  #
191
174
  # Returns:
192
175
  # - The auth token for the account (as an AccessToken)
193
176
  #
194
- def create_token_from_credentials(credentials)
195
- access_token = nil
196
-
177
+ def create_token_from_credentials(credentials, consumer)
197
178
  token = credentials[:oauth_token]
198
- if !token.nil? and !token.empty?
199
- method = credentials[:oauth_method] || DEFAULT_METHOD
200
- access_token = case method
201
- when 'RSA-SHA1'
202
- OAuth::AccessToken.from_hash(@consumer, {:oauth_token => token})
203
- when 'HMAC-SHA1'
204
- token_secret = credentials[:oauth_token_secret]
205
- if token_secret.nil? or token_secret.empty?
206
- @logger.warn(("The 'token' specified for method %s but " +
207
- "'token secret' is not available, ignoring token") % method)
208
- nil
209
- else
210
- OAuth::AccessToken.from_hash(@consumer, {
211
- :oauth_token => token, :oauth_token_secret => token_secret})
212
- end
213
- end
179
+ if token.nil? or token.empty?
180
+ return nil
181
+ end
182
+
183
+ method = credentials[:oauth_method] || DEFAULT_METHOD
184
+ access_token = case method
185
+ when 'RSA-SHA1'
186
+ OAuth::AccessToken.from_hash(consumer, {:oauth_token => token})
187
+ when 'HMAC-SHA1'
188
+ token_secret = credentials[:oauth_token_secret]
189
+ if token_secret.nil? or token_secret.empty?
190
+ get_logger().warn(("The 'token' specified for method %s but " +
191
+ "'token secret' is not available, ignoring token") % method)
192
+ nil
193
+ else
194
+ OAuth::AccessToken.from_hash(consumer, {
195
+ :oauth_token => token, :oauth_token_secret => token_secret})
196
+ end
214
197
  end
215
198
  return access_token
216
199
  end
@@ -220,18 +203,21 @@ module AdsCommon
220
203
  # Args:
221
204
  # - credentials: a hash with the credentials for the account being
222
205
  # accessed
206
+ # - consumer: OAuth consumer for the current configuration
223
207
  #
224
208
  # Returns:
225
209
  # - The auth token for the account (as an AccessToken)
226
210
  #
227
- def generate_access_token(credentials)
211
+ def generate_access_token(credentials, consumer)
228
212
  token = nil
229
213
  callback = credentials[:oauth_callback] || DEFAULT_CALLBACK
230
214
  begin
231
215
  if @request_token.nil?
232
216
  @request_token = credentials[:oauth_request_token] ||
233
- @consumer.get_request_token({:oauth_callback => callback},
234
- {:scope => @scope})
217
+ consumer.get_request_token(
218
+ {:oauth_callback => callback},
219
+ {:scope => @scope}
220
+ )
235
221
  end
236
222
  verification_code = credentials[:oauth_verification_code]
237
223
  if verification_code.nil? || verification_code.empty?
@@ -41,13 +41,10 @@ module AdsCommon
41
41
  # - api_name an API name to generate for
42
42
  # - version a version of the service
43
43
  # - service_name a service name to generate stubs for
44
- # - extensions an optional list of extensions to include
45
44
  #
46
- def initialize(wsdl_url, code_path, api_name, version, service_name,
47
- extensions = [])
45
+ def initialize(wsdl_url, code_path, api_name, version, service_name)
48
46
  @wsdl_url = wsdl_url
49
47
  @code_path = code_path
50
- @extensions = extensions
51
48
  @generator_args = {
52
49
  :api_name => api_name,
53
50
  :version => version,
@@ -112,7 +109,6 @@ module AdsCommon
112
109
  wrapper_file = create_new_file(file_name)
113
110
  generator = SavonServiceGenerator.new(@generator_args)
114
111
  generator.add_actions(wsdl.soap_actions.dup)
115
- generator.add_extensions(@extensions)
116
112
  wrapper_file.write(generator.generate_code())
117
113
  wrapper_file.close
118
114
  end