signet 0.5.0 → 0.5.1

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.
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