signet 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a90553898c900b623be7bcd66492052606823e88
4
+ data.tar.gz: 79d812b9a1bf1c00a548b48a5434dd8a3f40cb39
5
+ SHA512:
6
+ metadata.gz: b41031268b8c1e10cea6cc132edcb85954c398927ecd7c364c401fab64930758c47a87d4ffb4b1c196f6c6e9dedd3a2cf893d939910440649f560c39555b0546
7
+ data.tar.gz: be0549ccf4f39e5d7d0a67b209884c798bfcec5bda4618a27e6e96579cec21ff54d76f08c64cf606925cf9c04015c72c678f3066b3cfa75daf60648ae8bb6c29
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ # 0.5.1
2
+
3
+ * Allow Hash objects to be used to initialize authorization URI
4
+ * Added PLAINTEXT and RSA-SHA1 signature methods to OAuth 1 support
5
+ * Added client object serialization
6
+ * The `approval_prompt` option no longer defaults to `:force`
7
+ * The `approval_prompt` and `prompt` are now mutually exclusive.
8
+
9
+ # 0.5.0
10
+
11
+ * Switched to faraday 0.9.0
12
+ * Added `expires_at` option
13
+
1
14
  # 0.4.5
2
15
 
3
16
  * Minor documentation fixes
data/Rakefile CHANGED
@@ -26,7 +26,7 @@ PKG_FILES = FileList[
26
26
  "lib/**/*", "spec/**/*", "vendor/**/*",
27
27
  "tasks/**/*", "website/**/*",
28
28
  "[A-Z]*", "Rakefile"
29
- ].exclude(/database\.yml/).exclude(/[_\.]git$/)
29
+ ].exclude(/database\.yml/).exclude(/[_\.]git$/).exclude(/Gemfile\.lock/)
30
30
 
31
31
  RCOV_ENABLED = !!(RUBY_PLATFORM != 'java' && RUBY_VERSION =~ /^1\.8/)
32
32
  if RCOV_ENABLED
@@ -0,0 +1,7 @@
1
+ require 'base64'
2
+ # Backport from ruby-1.9 to ruby-1.8
3
+ unless Base64.respond_to?(:strict_encode64)
4
+ def Base64.strict_encode64(str)
5
+ Base64.encode64(str).gsub("\n", "")
6
+ end
7
+ end
@@ -69,27 +69,27 @@ module Signet #:nodoc:
69
69
  #
70
70
  # @return [String] The credential key value.
71
71
  def self.extract_credential_key_option(credential_type, options)
72
- credential_key_symbol =
73
- ("#{credential_type}_credential_key").to_sym
74
- credential_symbol =
75
- ("#{credential_type}_credential").to_sym
76
- if options[credential_key_symbol]
77
- credential_key = options[credential_key_symbol]
78
- elsif options[credential_symbol]
72
+ # Normalize key to String to allow indifferent access.
73
+ options = options.inject({}) { |accu, (k, v)| accu[k.to_s] = v; accu }
74
+ credential_key = "#{credential_type}_credential_key"
75
+ credential = "#{credential_type}_credential"
76
+ if options[credential_key]
77
+ credential_key = options[credential_key]
78
+ elsif options[credential]
79
79
  require 'signet/oauth_1/credential'
80
- if !options[credential_symbol].respond_to?(:key)
80
+ if !options[credential].respond_to?(:key)
81
81
  raise TypeError,
82
82
  "Expected Signet::OAuth1::Credential, " +
83
- "got #{options[credential_symbol].class}."
83
+ "got #{options[credential].class}."
84
84
  end
85
- credential_key = options[credential_symbol].key
86
- elsif options[:client]
85
+ credential_key = options[credential].key
86
+ elsif options["client"]
87
87
  require 'signet/oauth_1/client'
88
- if !options[:client].kind_of?(::Signet::OAuth1::Client)
88
+ if !options["client"].kind_of?(::Signet::OAuth1::Client)
89
89
  raise TypeError,
90
- "Expected Signet::OAuth1::Client, got #{options[:client].class}."
90
+ "Expected Signet::OAuth1::Client, got #{options["client"].class}."
91
91
  end
92
- credential_key = options[:client].send(credential_key_symbol)
92
+ credential_key = options["client"].send(credential_key)
93
93
  else
94
94
  credential_key = nil
95
95
  end
@@ -111,27 +111,27 @@ module Signet #:nodoc:
111
111
  #
112
112
  # @return [String] The credential secret value.
113
113
  def self.extract_credential_secret_option(credential_type, options)
114
- credential_secret_symbol =
115
- ("#{credential_type}_credential_secret").to_sym
116
- credential_symbol =
117
- ("#{credential_type}_credential").to_sym
118
- if options[credential_secret_symbol]
119
- credential_secret = options[credential_secret_symbol]
120
- elsif options[credential_symbol]
114
+ # Normalize key to String to allow indifferent access.
115
+ options = options.inject({}) { |accu, (k, v)| accu[k.to_s] = v; accu }
116
+ credential_secret = "#{credential_type}_credential_secret"
117
+ credential = "#{credential_type}_credential"
118
+ if options[credential_secret]
119
+ credential_secret = options[credential_secret]
120
+ elsif options[credential]
121
121
  require 'signet/oauth_1/credential'
122
- if !options[credential_symbol].respond_to?(:secret)
122
+ if !options[credential].respond_to?(:secret)
123
123
  raise TypeError,
124
124
  "Expected Signet::OAuth1::Credential, " +
125
- "got #{options[credential_symbol].class}."
125
+ "got #{options[credential].class}."
126
126
  end
127
- credential_secret = options[credential_symbol].secret
128
- elsif options[:client]
127
+ credential_secret = options[credential].secret
128
+ elsif options["client"]
129
129
  require 'signet/oauth_1/client'
130
- if !options[:client].kind_of?(::Signet::OAuth1::Client)
130
+ if !options["client"].kind_of?(::Signet::OAuth1::Client)
131
131
  raise TypeError,
132
- "Expected Signet::OAuth1::Client, got #{options[:client].class}."
132
+ "Expected Signet::OAuth1::Client, got #{options["client"].class}."
133
133
  end
134
- credential_secret = options[:client].send(credential_secret_symbol)
134
+ credential_secret = options["client"].send(credential_secret)
135
135
  else
136
136
  credential_secret = nil
137
137
  end
@@ -295,6 +295,16 @@ module Signet #:nodoc:
295
295
  return Signet::OAuth1::HMACSHA1.generate_signature(
296
296
  base_string, client_credential_secret, token_credential_secret
297
297
  )
298
+ when 'RSA-SHA1'
299
+ require 'signet/oauth_1/signature_methods/rsa_sha1'
300
+ return Signet::OAuth1::RSASHA1.generate_signature(
301
+ base_string, client_credential_secret, token_credential_secret
302
+ )
303
+ when 'PLAINTEXT'
304
+ require 'signet/oauth_1/signature_methods/plaintext'
305
+ return Signet::OAuth1::PLAINTEXT.generate_signature(
306
+ base_string, client_credential_secret, token_credential_secret
307
+ )
298
308
  else
299
309
  raise NotImplementedError,
300
310
  "Unsupported signature method: #{signature_method}"
@@ -54,25 +54,62 @@ module Signet
54
54
  # :client_credential_secret => 'anonymous'
55
55
  # )
56
56
  def initialize(options={})
57
- self.temporary_credential_uri = options[:temporary_credential_uri]
58
- self.authorization_uri = options[:authorization_uri]
59
- self.token_credential_uri = options[:token_credential_uri]
57
+ self.update!(options)
58
+ end
59
+
60
+ ##
61
+ # Updates an OAuth 1.0 client.
62
+ #
63
+ # @param [Hash] options
64
+ # The configuration parameters for the client.
65
+ # - <code>:temporary_credential_uri</code> -
66
+ # The OAuth temporary credentials URI.
67
+ # - <code>:authorization_uri</code> -
68
+ # The OAuth authorization URI.
69
+ # - <code>:token_credential_uri</code> -
70
+ # The OAuth token credentials URI.
71
+ # - <code>:client_credential_key</code> -
72
+ # The OAuth client credential key.
73
+ # - <code>:client_credential_secret</code> -
74
+ # The OAuth client credential secret.
75
+ # - <code>:callback</code> - The OAuth callback. Defaults to 'oob'.
76
+ #
77
+ # @example
78
+ # client.update!(
79
+ # :temporary_credential_uri =>
80
+ # 'https://www.google.com/accounts/OAuthGetRequestToken',
81
+ # :authorization_uri =>
82
+ # 'https://www.google.com/accounts/OAuthAuthorizeToken',
83
+ # :token_credential_uri =>
84
+ # 'https://www.google.com/accounts/OAuthGetAccessToken',
85
+ # :client_credential_key => 'anonymous',
86
+ # :client_credential_secret => 'anonymous'
87
+ # )
88
+ #
89
+ # @see Signet::OAuth1::Client#initialize
90
+ def update!(options={})
91
+ # Normalize key to String to allow indifferent access.
92
+ options = options.inject({}) { |accu, (k, v)| accu[k.to_s] = v; accu }
93
+ self.temporary_credential_uri = options["temporary_credential_uri"]
94
+ self.authorization_uri = options["authorization_uri"]
95
+ self.token_credential_uri = options["token_credential_uri"]
60
96
  # Technically... this would allow you to pass in a :client key...
61
97
  # But that would be weird. Don't do that.
62
98
  self.client_credential_key =
63
- Signet::OAuth1.extract_credential_key_option(:client, options)
99
+ Signet::OAuth1.extract_credential_key_option("client", options)
64
100
  self.client_credential_secret =
65
- Signet::OAuth1.extract_credential_secret_option(:client, options)
101
+ Signet::OAuth1.extract_credential_secret_option("client", options)
66
102
  self.temporary_credential_key =
67
- Signet::OAuth1.extract_credential_key_option(:temporary, options)
103
+ Signet::OAuth1.extract_credential_key_option("temporary", options)
68
104
  self.temporary_credential_secret =
69
- Signet::OAuth1.extract_credential_secret_option(:temporary, options)
105
+ Signet::OAuth1.extract_credential_secret_option("temporary", options)
70
106
  self.token_credential_key =
71
- Signet::OAuth1.extract_credential_key_option(:token, options)
107
+ Signet::OAuth1.extract_credential_key_option("token", options)
72
108
  self.token_credential_secret =
73
- Signet::OAuth1.extract_credential_secret_option(:token, options)
74
- self.callback = options[:callback]
75
- self.two_legged = options[:two_legged] || false
109
+ Signet::OAuth1.extract_credential_secret_option("token", options)
110
+ self.callback = options["callback"]
111
+ self.two_legged = options["two_legged"] || false
112
+ return self
76
113
  end
77
114
 
78
115
  ##
@@ -127,8 +164,10 @@ module Signet
127
164
  # The authorization URI.
128
165
  def authorization_uri=(new_authorization_uri)
129
166
  if new_authorization_uri != nil
130
- new_authorization_uri =
131
- Addressable::URI.parse(new_authorization_uri)
167
+ new_authorization_uri = Addressable::URI.send(
168
+ new_authorization_uri.kind_of?(Hash) ? :new : :parse,
169
+ new_authorization_uri
170
+ )
132
171
  @authorization_uri = new_authorization_uri
133
172
  else
134
173
  @authorization_uri = nil
@@ -147,12 +186,14 @@ module Signet
147
186
  ##
148
187
  # Sets the token credential URI for this client.
149
188
  #
150
- # @param [Addressable::URI, String, #to_str] new_token_credential_uri
189
+ # @param [Addressable::URI, Hash, String, #to_str] new_token_credential_uri
151
190
  # The token credential URI.
152
191
  def token_credential_uri=(new_token_credential_uri)
153
192
  if new_token_credential_uri != nil
154
- new_token_credential_uri =
155
- Addressable::URI.parse(new_token_credential_uri)
193
+ new_token_credential_uri = Addressable::URI.send(
194
+ new_token_credential_uri.kind_of?(Hash) ? :new : :parse,
195
+ new_token_credential_uri
196
+ )
156
197
  @token_credential_uri = new_token_credential_uri
157
198
  else
158
199
  @token_credential_uri = nil
@@ -509,6 +550,28 @@ module Signet
509
550
  end
510
551
  end
511
552
 
553
+ ##
554
+ # Serialize the client object to JSON.
555
+ #
556
+ # @note A serialized client contains sensitive information. Persist or transmit with care.
557
+ #
558
+ # @return [String] A serialized JSON representation of the client.
559
+ def to_json
560
+ return MultiJson.dump({
561
+ 'temporary_credential_uri' => self.temporary_credential_uri,
562
+ 'authorization_uri' => self.authorization_uri,
563
+ 'token_credential_uri' => self.token_credential_uri,
564
+ 'callback' => self.callback,
565
+ 'two_legged' => self.two_legged,
566
+ 'client_credential_key' => self.client_credential_key,
567
+ 'client_credential_secret' => self.client_credential_secret,
568
+ 'temporary_credential_key' => self.temporary_credential_key,
569
+ 'temporary_credential_secret' => self.temporary_credential_secret,
570
+ 'token_credential_key' => self.token_credential_key,
571
+ 'token_credential_secret' => self.token_credential_secret
572
+ })
573
+ end
574
+
512
575
  ##
513
576
  # Generates a request for temporary credentials.
514
577
  #
@@ -859,7 +922,7 @@ module Signet
859
922
  :realm => nil,
860
923
  :connection => Faraday.default_connection
861
924
  }.merge(options)
862
-
925
+
863
926
  if options[:request].kind_of?(Faraday::Request)
864
927
  request = options[:request]
865
928
  else
@@ -902,16 +965,16 @@ module Signet
902
965
  req.body = body
903
966
  end
904
967
  end
905
-
968
+
906
969
  parameters = ::Signet::OAuth1.unsigned_resource_parameters(
907
970
  :client_credential_key => self.client_credential_key,
908
971
  :token_credential_key => self.token_credential_key,
909
972
  :signature_method => options[:signature_method],
910
973
  :two_legged => self.two_legged
911
974
  )
912
-
975
+
913
976
  env = request.to_env(options[:connection])
914
-
977
+
915
978
  content_type = request['Content-Type'].to_s
916
979
  content_type = content_type.split(';', 2).first if content_type.index(';')
917
980
  if request.method == :post && content_type == 'application/x-www-form-urlencoded'
@@ -923,7 +986,7 @@ module Signet
923
986
  post_parameters = Addressable::URI.form_unencode(env[:body])
924
987
  parameters = parameters.concat(post_parameters)
925
988
  end
926
-
989
+
927
990
  # No need to attach URI query parameters, the .sign_parameters
928
991
  # method takes care of that automatically.
929
992
  signature = ::Signet::OAuth1.sign_parameters(
@@ -933,7 +996,7 @@ module Signet
933
996
  self.client_credential_secret,
934
997
  self.token_credential_secret
935
998
  )
936
-
999
+
937
1000
  parameters << ['oauth_signature', signature]
938
1001
  request['Authorization'] = ::Signet::OAuth1.generate_authorization_header(
939
1002
  parameters, options[:realm])
@@ -0,0 +1,21 @@
1
+ require 'signet'
2
+
3
+ module Signet #:nodoc:
4
+ module OAuth1
5
+ module PLAINTEXT
6
+ def self.generate_signature(
7
+ base_string, client_credential_secret, token_credential_secret)
8
+ # Both the client secret and token secret must be escaped
9
+ client_credential_secret =
10
+ Signet::OAuth1.encode(client_credential_secret)
11
+ token_credential_secret =
12
+ Signet::OAuth1.encode(token_credential_secret)
13
+ # The key for the signature is just the client secret and token
14
+ # secret joined by the '&' character. If the token secret is omitted,
15
+ # the '&' must still be present.
16
+ key = [client_credential_secret, token_credential_secret].join("&")
17
+ return Signet::OAuth1.encode(key).strip
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'digest/sha1'
2
+ require 'base64'
3
+ require 'openssl'
4
+ require 'signet'
5
+ require 'compat/base64'
6
+
7
+ module Signet #:nodoc:
8
+ module OAuth1
9
+ module RSASHA1
10
+ def self.generate_signature(
11
+ base_string, client_credential_secret, token_credential_secret)
12
+
13
+ private_key = OpenSSL::PKey::RSA.new(client_credential_secret)
14
+ signature = private_key.sign(OpenSSL::Digest::SHA1.new, base_string)
15
+ #using strict_encode64 because the encode64 method adds newline characters after ever 60 chars
16
+ return Base64.strict_encode64(signature).strip
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -140,7 +140,7 @@ module Signet
140
140
  # - <code>:id_token</code> -
141
141
  # The current ID token for this client.
142
142
  # - <code>:extension_parameters</code> -
143
- # When using an extension grant type, this the set of parameters used
143
+ # When using an extension grant type, this is the set of parameters used
144
144
  # by that extension.
145
145
  #
146
146
  # @example
@@ -155,22 +155,24 @@ module Signet
155
155
  def update!(options={})
156
156
  # Normalize key to String to allow indifferent access.
157
157
  options = options.inject({}) { |accu, (k, v)| accu[k.to_s] = v; accu }
158
- self.authorization_uri = options["authorization_uri"]
159
- self.token_credential_uri = options["token_credential_uri"]
160
- self.client_id = options["client_id"]
161
- self.client_secret = options["client_secret"]
162
- self.scope = options["scope"]
163
- self.state = options["state"]
164
- self.code = options["code"]
165
- self.redirect_uri = options["redirect_uri"]
166
- self.username = options["username"]
167
- self.password = options["password"]
168
- self.issuer = options["issuer"]
169
- self.person = options["person"]
158
+ self.authorization_uri = options["authorization_uri"] if options.has_key?("authorization_uri")
159
+ self.token_credential_uri = options["token_credential_uri"] if options.has_key?("token_credential_uri")
160
+ self.client_id = options["client_id"] if options.has_key?("client_id")
161
+ self.client_secret = options["client_secret"] if options.has_key?("client_secret")
162
+ self.scope = options["scope"] if options.has_key?("scope")
163
+ self.state = options["state"] if options.has_key?("state")
164
+ self.code = options["code"] if options.has_key?("code")
165
+ self.redirect_uri = options["redirect_uri"] if options.has_key?("redirect_uri")
166
+ self.username = options["username"] if options.has_key?("username")
167
+ self.password = options["password"] if options.has_key?("password")
168
+ self.issuer = options["issuer"] if options.has_key?("issuer")
169
+ self.person = options["person"] if options.has_key?("person")
170
+ self.sub = options["sub"] if options.has_key?("sub")
170
171
  self.expiry = options["expiry"] || 60
171
- self.audience = options["audience"]
172
- self.signing_key = options["signing_key"]
172
+ self.audience = options["audience"] if options.has_key?("audience")
173
+ self.signing_key = options["signing_key"] if options.has_key?("signing_key")
173
174
  self.extension_parameters = options["extension_parameters"] || {}
175
+ self.additional_parameters = options["additional_parameters"] || {}
174
176
  self.update_token!(options)
175
177
  return self
176
178
  end
@@ -207,25 +209,16 @@ module Signet
207
209
  # Normalize key to String to allow indifferent access.
208
210
  options = options.inject({}) { |accu, (k, v)| accu[k.to_s] = v; accu }
209
211
 
210
- self.access_token = options["access_token"] if options["access_token"]
211
- self.expires_in = options["expires_in"] if options["expires_in"]
212
- self.expires_at = options["expires_at"] if options["expires_at"]
212
+ self.expires_in = options["expires_in"] if options.has_key?("expires_in")
213
+ self.expires_at = options["expires_at"] if options.has_key?("expires_at")
213
214
 
214
- # The refresh token may not be returned in a token response.
215
- # In which case, the old one should continue to be used.
216
- if options["refresh_token"]
217
- self.refresh_token = options["refresh_token"]
218
- end
219
- # The ID token may not be returned in a token response.
220
- # In which case, the old one should continue to be used.
221
- if options["id_token"]
222
- self.id_token = options["id_token"]
223
- end
224
215
  # By default, the token is issued at `Time.now` when `expires_in` is
225
216
  # set, but this can be used to supply a more precise time.
226
- if options["issued_at"]
227
- self.issued_at = options["issued_at"]
228
- end
217
+ self.issued_at = options["issued_at"] if options.has_key?("issued_at")
218
+
219
+ self.access_token = options["access_token"] if options.has_key?("access_token")
220
+ self.refresh_token = options["refresh_token"] if options.has_key?("refresh_token")
221
+ self.id_token = options["id_token"] if options.has_key?("id_token")
229
222
 
230
223
  return self
231
224
  end
@@ -244,12 +237,11 @@ module Signet
244
237
  unless options[:access_type]
245
238
  options[:access_type] = :offline
246
239
  end
247
- unless options[:approval_prompt]
248
- # This default will likely change in the future.
249
- options[:approval_prompt] = :force
250
- end
251
240
  options[:client_id] ||= self.client_id
252
241
  options[:redirect_uri] ||= self.redirect_uri
242
+ if options[:prompt] && options[:approval_prompt]
243
+ raise ArgumentError, "prompt and approval_prompt are mutually exclusive parameters"
244
+ end
253
245
  if !options[:client_id]
254
246
  raise ArgumentError, "Missing required client identifier."
255
247
  end
@@ -260,6 +252,8 @@ module Signet
260
252
  options[:scope] = self.scope.join(' ')
261
253
  end
262
254
  options[:state] = self.state unless options[:state]
255
+ options.merge!(self.additional_parameters.merge(options[:additional_parameters] || {}))
256
+ options.delete(:additional_parameters)
263
257
  uri = Addressable::URI.parse(
264
258
  ::Signet::OAuth2.generate_authorization_uri(
265
259
  @authorization_uri, options
@@ -275,12 +269,14 @@ module Signet
275
269
  ##
276
270
  # Sets the authorization URI for this client.
277
271
  #
278
- # @param [Addressable::URI, String, #to_str] new_authorization_uri
272
+ # @param [Addressable::URI, Hash, String, #to_str] new_authorization_uri
279
273
  # The authorization URI.
280
274
  def authorization_uri=(new_authorization_uri)
281
275
  if new_authorization_uri != nil
282
- new_authorization_uri =
283
- Addressable::URI.parse(new_authorization_uri)
276
+ new_authorization_uri = Addressable::URI.send(
277
+ new_authorization_uri.kind_of?(Hash) ? :new : :parse,
278
+ new_authorization_uri
279
+ )
284
280
  @authorization_uri = new_authorization_uri
285
281
  else
286
282
  @authorization_uri = nil
@@ -298,12 +294,14 @@ module Signet
298
294
  ##
299
295
  # Sets the token credential URI for this client.
300
296
  #
301
- # @param [Addressable::URI, String, #to_str] new_token_credential_uri
297
+ # @param [Addressable::URI, Hash, String, #to_str] new_token_credential_uri
302
298
  # The token credential URI.
303
299
  def token_credential_uri=(new_token_credential_uri)
304
300
  if new_token_credential_uri != nil
305
- new_token_credential_uri =
306
- Addressable::URI.parse(new_token_credential_uri)
301
+ new_token_credential_uri = Addressable::URI.send(
302
+ new_token_credential_uri.kind_of?(Hash) ? :new : :parse,
303
+ new_token_credential_uri
304
+ )
307
305
  @token_credential_uri = new_token_credential_uri
308
306
  else
309
307
  @token_credential_uri = nil
@@ -430,8 +428,8 @@ module Signet
430
428
  # The redirect URI.
431
429
  def redirect_uri=(new_redirect_uri)
432
430
  new_redirect_uri = Addressable::URI.parse(new_redirect_uri)
433
- #TODO - Better solution to allow google postmessage flow. For now, make an exception to the spec.
434
- if new_redirect_uri == nil|| new_redirect_uri.absolute? || uri_is_postmessage?(new_redirect_uri)
431
+ #TODO - Better solution to allow google postmessage flow. For now, make an exception to the spec.
432
+ if new_redirect_uri == nil|| new_redirect_uri.absolute? || uri_is_postmessage?(new_redirect_uri) || uri_is_oob?(new_redirect_uri)
435
433
  @redirect_uri = new_redirect_uri
436
434
  else
437
435
  raise ArgumentError, "Redirect URI must be an absolute URI."
@@ -532,10 +530,16 @@ module Signet
532
530
  def principal=(new_person)
533
531
  @principal = new_person
534
532
  end
535
-
533
+
536
534
  alias_method :person, :principal
537
535
  alias_method :person=, :principal=
538
-
536
+
537
+ ##
538
+ # The target "sub" when issuing assertions.
539
+ # Used in some Admin SDK APIs.
540
+ #
541
+ attr_accessor :sub
542
+
539
543
  ##
540
544
  # Returns the number of seconds assertions are valid for
541
545
  # Used only by the assertion grant type.
@@ -554,8 +558,8 @@ module Signet
554
558
  def expiry=(new_expiry)
555
559
  @expiry = new_expiry
556
560
  end
557
-
558
-
561
+
562
+
559
563
  ##
560
564
  # Returns the signing key associated with this client.
561
565
  # Used only by the assertion grant type.
@@ -574,14 +578,14 @@ module Signet
574
578
  def signing_key=(new_key)
575
579
  @signing_key = new_key
576
580
  end
577
-
581
+
578
582
  ##
579
583
  # Algorithm used for signing JWTs
580
584
  # @return [String] Signing algorithm
581
585
  def signing_algorithm
582
586
  self.signing_key.is_a?(String) ? "HS256" : "RS256"
583
587
  end
584
-
588
+
585
589
  ##
586
590
  # Returns the set of extension parameters used by the client.
587
591
  # Used only by extension access grant types.
@@ -606,6 +610,28 @@ module Signet
606
610
  end
607
611
  end
608
612
 
613
+ ##
614
+ # Returns the set of additional (non standard) parameters to be used by the client.
615
+ #
616
+ # @return [Hash] The pass through parameters.
617
+ def additional_parameters
618
+ return @additional_parameters ||= {}
619
+ end
620
+
621
+ ##
622
+ # Sets additional (non standard) parameters to be used by the client.
623
+ #
624
+ # @param [Hash] new_additional_parameters
625
+ # The parameters.
626
+ def additional_parameters=(new_additional_parameters)
627
+ if new_additional_parameters.respond_to?(:to_hash)
628
+ @additional_parameters = new_additional_parameters.to_hash
629
+ else
630
+ raise TypeError,
631
+ "Expected Hash, got #{new_additional_parameters.class}."
632
+ end
633
+ end
634
+
609
635
  ##
610
636
  # Returns the refresh token associated with this client.
611
637
  #
@@ -745,8 +771,8 @@ module Signet
745
771
  def expired?
746
772
  return self.expires_at != nil && Time.now >= self.expires_at
747
773
  end
748
-
749
-
774
+
775
+
750
776
  ##
751
777
  # Removes all credentials from the client.
752
778
  def clear_credentials!
@@ -801,7 +827,7 @@ module Signet
801
827
  end
802
828
 
803
829
  def to_jwt(options={})
804
- now = Time.new
830
+ now = Time.new
805
831
  skew = options[:skew] || 60
806
832
  assertion = {
807
833
  "iss" => self.issuer,
@@ -811,9 +837,40 @@ module Signet
811
837
  "iat" => (now - skew).to_i
812
838
  }
813
839
  assertion['prn'] = self.person unless self.person.nil?
840
+ assertion['sub'] = self.sub unless self.sub.nil?
814
841
  JWT.encode(assertion, self.signing_key, self.signing_algorithm)
815
842
  end
816
-
843
+
844
+ ##
845
+ # Serialize the client object to JSON.
846
+ #
847
+ # @note A serialized client contains sensitive information. Persist or transmit with care.
848
+ #
849
+ # @return [String] A serialized JSON representation of the client.
850
+ def to_json
851
+ return MultiJson.dump({
852
+ 'authorization_uri' => self.authorization_uri,
853
+ 'token_credential_uri' => self.token_credential_uri,
854
+ 'client_id' => self.client_id,
855
+ 'client_secret' => self.client_secret,
856
+ 'scope' => self.scope,
857
+ 'state' => self.state,
858
+ 'code' => self.code,
859
+ 'redirect_uri' => self.redirect_uri,
860
+ 'username' => self.username,
861
+ 'password' => self.password,
862
+ 'issuer' => self.issuer,
863
+ 'audience' => self.audience,
864
+ 'person' => self.person,
865
+ 'expiry' => self.expiry,
866
+ 'signing_key' => self.signing_key,
867
+ 'refresh_token' => self.refresh_token,
868
+ 'access_token' => self.access_token,
869
+ 'id_token' => self.id_token,
870
+ 'extension_parameters' => self.extension_parameters
871
+ })
872
+ end
873
+
817
874
  ##
818
875
  # Generates a request for token credentials.
819
876
  #
@@ -856,6 +913,7 @@ module Signet
856
913
  ['Cache-Control', 'no-store'],
857
914
  ['Content-Type', 'application/x-www-form-urlencoded']
858
915
  ]
916
+ parameters.merge!(self.additional_parameters.merge(options[:additional_parameters] || {}))
859
917
  return options[:connection].build_request(
860
918
  method.to_s.downcase.to_sym
861
919
  ) do |req|
@@ -907,12 +965,12 @@ module Signet
907
965
  return token_hash
908
966
  end
909
967
 
910
- ##
968
+ ##
911
969
  # Refresh the access token, if possible
912
- def refresh!
913
- self.fetch_access_token!
970
+ def refresh!(options={})
971
+ self.fetch_access_token!(options)
914
972
  end
915
-
973
+
916
974
  ##
917
975
  # Generates an authenticated request for protected resources.
918
976
  #
@@ -973,7 +1031,7 @@ module Signet
973
1031
  req.body = body
974
1032
  end
975
1033
  end
976
-
1034
+
977
1035
  request['Authorization'] = ::Signet::OAuth2.generate_bearer_authorization_header(
978
1036
  self.access_token,
979
1037
  options[:realm] ? [['realm', options[:realm]]] : nil
@@ -1042,16 +1100,23 @@ module Signet
1042
1100
  return response
1043
1101
  end
1044
1102
  end
1045
-
1103
+
1046
1104
  private
1047
-
1105
+
1048
1106
  ##
1049
1107
  # Check if URI is Google's postmessage flow (not a valid redirect_uri by spec, but allowed)
1050
1108
  # @private
1051
1109
  def uri_is_postmessage?(uri)
1052
1110
  return uri.to_s.casecmp('postmessage') == 0
1053
1111
  end
1054
-
1112
+
1113
+ ##
1114
+ # Check if the URI is a out-of-band
1115
+ # @private
1116
+ def uri_is_oob?(uri)
1117
+ return uri.to_s == 'urn:ietf:wg:oauth:2.0:oob' || uri.to_s == 'oob'
1118
+ end
1119
+
1055
1120
  end
1056
1121
  end
1057
1122
  end