googleauth 0.17.0 → 0.17.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/CHANGELOG.md +6 -0
  4. data/lib/googleauth/version.rb +1 -1
  5. metadata +14 -88
  6. data/.github/CODEOWNERS +0 -7
  7. data/.github/CONTRIBUTING.md +0 -74
  8. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -36
  9. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -21
  10. data/.github/ISSUE_TEMPLATE/support_request.md +0 -7
  11. data/.github/renovate.json +0 -6
  12. data/.github/sync-repo-settings.yaml +0 -18
  13. data/.github/workflows/ci.yml +0 -55
  14. data/.github/workflows/release-please.yml +0 -39
  15. data/.gitignore +0 -39
  16. data/.kokoro/populate-secrets.sh +0 -76
  17. data/.kokoro/release.cfg +0 -52
  18. data/.kokoro/release.sh +0 -18
  19. data/.kokoro/trampoline_v2.sh +0 -489
  20. data/.repo-metadata.json +0 -5
  21. data/.rspec +0 -2
  22. data/.rubocop.yml +0 -17
  23. data/.toys/.toys.rb +0 -45
  24. data/.toys/ci.rb +0 -43
  25. data/.toys/kokoro/.toys.rb +0 -66
  26. data/.toys/kokoro/publish-docs.rb +0 -67
  27. data/.toys/kokoro/publish-gem.rb +0 -53
  28. data/.toys/linkinator.rb +0 -43
  29. data/.trampolinerc +0 -48
  30. data/Gemfile +0 -25
  31. data/googleauth.gemspec +0 -39
  32. data/integration/helper.rb +0 -31
  33. data/integration/id_tokens/key_source_test.rb +0 -74
  34. data/spec/googleauth/apply_auth_examples.rb +0 -171
  35. data/spec/googleauth/client_id_spec.rb +0 -160
  36. data/spec/googleauth/compute_engine_spec.rb +0 -178
  37. data/spec/googleauth/credentials_spec.rb +0 -600
  38. data/spec/googleauth/get_application_default_spec.rb +0 -286
  39. data/spec/googleauth/iam_spec.rb +0 -80
  40. data/spec/googleauth/scope_util_spec.rb +0 -77
  41. data/spec/googleauth/service_account_spec.rb +0 -511
  42. data/spec/googleauth/signet_spec.rb +0 -142
  43. data/spec/googleauth/stores/file_token_store_spec.rb +0 -57
  44. data/spec/googleauth/stores/redis_token_store_spec.rb +0 -50
  45. data/spec/googleauth/stores/store_examples.rb +0 -58
  46. data/spec/googleauth/user_authorizer_spec.rb +0 -343
  47. data/spec/googleauth/user_refresh_spec.rb +0 -359
  48. data/spec/googleauth/web_user_authorizer_spec.rb +0 -172
  49. data/spec/spec_helper.rb +0 -92
  50. data/test/helper.rb +0 -33
  51. data/test/id_tokens/key_sources_test.rb +0 -240
  52. data/test/id_tokens/verifier_test.rb +0 -269
@@ -1,142 +0,0 @@
1
- # Copyright 2015, Google Inc.
2
- # All rights reserved.
3
- #
4
- # Redistribution and use in source and binary forms, with or without
5
- # modification, are permitted provided that the following conditions are
6
- # met:
7
- #
8
- # * Redistributions of source code must retain the above copyright
9
- # notice, this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above
11
- # copyright notice, this list of conditions and the following disclaimer
12
- # in the documentation and/or other materials provided with the
13
- # distribution.
14
- # * Neither the name of Google Inc. nor the names of its
15
- # contributors may be used to endorse or promote products derived from
16
- # this software without specific prior written permission.
17
- #
18
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
-
30
- spec_dir = File.expand_path File.join(File.dirname(__FILE__))
31
- $LOAD_PATH.unshift spec_dir
32
- $LOAD_PATH.uniq!
33
-
34
- require "apply_auth_examples"
35
- require "googleauth/signet"
36
- require "jwt"
37
- require "openssl"
38
- require "spec_helper"
39
-
40
- describe Signet::OAuth2::Client do
41
- before :example do
42
- @key = OpenSSL::PKey::RSA.new 2048
43
- @client = Signet::OAuth2::Client.new(
44
- token_credential_uri: "https://oauth2.googleapis.com/token",
45
- scope: "https://www.googleapis.com/auth/userinfo.profile",
46
- issuer: "app@example.com",
47
- audience: "https://oauth2.googleapis.com/token",
48
- signing_key: @key
49
- )
50
- @id_client = Signet::OAuth2::Client.new(
51
- token_credential_uri: "https://oauth2.googleapis.com/token",
52
- target_audience: "https://pubsub.googleapis.com/",
53
- issuer: "app@example.com",
54
- audience: "https://oauth2.googleapis.com/token",
55
- signing_key: @key
56
- )
57
- end
58
-
59
- def make_auth_stubs opts
60
- body_fields = { "token_type" => "Bearer", "expires_in" => 3600 }
61
- body_fields["access_token"] = opts[:access_token] if opts[:access_token]
62
- body_fields["id_token"] = opts[:id_token] if opts[:id_token]
63
- body = MultiJson.dump body_fields
64
- blk = proc do |request|
65
- params = Addressable::URI.form_unencode request.body
66
- claim, _header = JWT.decode(params.assoc("assertion").last,
67
- @key.public_key, true,
68
- algorithm: "RS256")
69
- !opts[:id_token] || claim["target_audience"] == "https://pubsub.googleapis.com/"
70
- end
71
- with_params = { body: hash_including(
72
- "grant_type" => "urn:ietf:params:oauth:grant-type:jwt-bearer"
73
- ) }
74
- with_params[:headers] = { "User-Agent" => opts[:user_agent] } if opts[:user_agent]
75
- stub_request(:post, "https://oauth2.googleapis.com/token")
76
- .with(with_params, &blk)
77
- .to_return(body: body,
78
- status: 200,
79
- headers: { "Content-Type" => "application/json" })
80
- end
81
-
82
- it_behaves_like "apply/apply! are OK"
83
-
84
- describe "#configure_connection" do
85
- it "honors default_connection" do
86
- token = "1/abcdef1234567890"
87
- stub = make_auth_stubs access_token: token, user_agent: "RubyRocks/1.0"
88
- conn = Faraday.new headers: { "User-Agent" => "RubyRocks/1.0" }
89
- @client.configure_connection default_connection: conn
90
- md = { foo: "bar" }
91
- @client.apply! md
92
- want = { foo: "bar", authorization: "Bearer #{token}" }
93
- expect(md).to eq(want)
94
- expect(stub).to have_been_requested
95
- end
96
-
97
- it "honors connection_builder" do
98
- token = "1/abcdef1234567890"
99
- stub = make_auth_stubs access_token: token, user_agent: "RubyRocks/2.0"
100
- connection_builder = proc do
101
- Faraday.new headers: { "User-Agent" => "RubyRocks/2.0" }
102
- end
103
- @client.configure_connection connection_builder: connection_builder
104
- md = { foo: "bar" }
105
- @client.apply! md
106
- want = { foo: "bar", authorization: "Bearer #{token}" }
107
- expect(md).to eq(want)
108
- expect(stub).to have_been_requested
109
- end
110
- end
111
-
112
- describe "#fetch_access_token!" do
113
- it "retries when orig_fetch_access_token! raises Signet::RemoteServerError" do
114
- mocked_responses = [:raise, :raise, "success"]
115
- allow(@client).to receive(:orig_fetch_access_token!).exactly(3).times do
116
- response = mocked_responses.shift
117
- response == :raise ? raise(Signet::RemoteServerError) : response
118
- end
119
- expect(@client.fetch_access_token!).to eq("success")
120
- end
121
-
122
- it "raises when the max retry count is exceeded" do
123
- mocked_responses = [:raise, :raise, :raise, :raise, :raise, :raise, "success"]
124
- allow(@client).to receive(:orig_fetch_access_token!).exactly(6).times do
125
- response = mocked_responses.shift
126
- response == :raise ? raise(Signet::RemoteServerError) : response
127
- end
128
- expect { @client.fetch_access_token! }.to raise_error Signet::AuthorizationError
129
- end
130
-
131
- it "does not retry and raises right away if it encounters a Signet::AuthorizationError" do
132
- allow(@client).to receive(:orig_fetch_access_token!).at_most(:once)
133
- .and_raise(Signet::AuthorizationError.new("Some Message"))
134
- expect { @client.fetch_access_token! }.to raise_error Signet::AuthorizationError
135
- end
136
-
137
- it "does not retry and raises right away if it encounters a Signet::ParseError" do
138
- allow(@client).to receive(:orig_fetch_access_token!).at_most(:once).and_raise(Signet::ParseError)
139
- expect { @client.fetch_access_token! }.to raise_error Signet::ParseError
140
- end
141
- end
142
- end
@@ -1,57 +0,0 @@
1
- # Copyright 2015, Google Inc.
2
- # All rights reserved.
3
- #
4
- # Redistribution and use in source and binary forms, with or without
5
- # modification, are permitted provided that the following conditions are
6
- # met:
7
- #
8
- # * Redistributions of source code must retain the above copyright
9
- # notice, this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above
11
- # copyright notice, this list of conditions and the following disclaimer
12
- # in the documentation and/or other materials provided with the
13
- # distribution.
14
- # * Neither the name of Google Inc. nor the names of its
15
- # contributors may be used to endorse or promote products derived from
16
- # this software without specific prior written permission.
17
- #
18
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
-
30
- spec_dir = File.expand_path File.join(File.dirname(__FILE__))
31
- $LOAD_PATH.unshift spec_dir
32
- $LOAD_PATH.uniq!
33
-
34
- require "googleauth"
35
- require "googleauth/stores/file_token_store"
36
- require "spec_helper"
37
- require "fakefs/safe"
38
- require "fakefs/spec_helpers"
39
- require "googleauth/stores/store_examples"
40
-
41
- module FakeFS
42
- class File
43
- # FakeFS doesn't implement. And since we don't need to actually lock,
44
- # just stub out...
45
- def flock *; end
46
- end
47
- end
48
-
49
- describe Google::Auth::Stores::FileTokenStore do
50
- include FakeFS::SpecHelpers
51
-
52
- let :store do
53
- Google::Auth::Stores::FileTokenStore.new file: "/tokens.yaml"
54
- end
55
-
56
- it_behaves_like "token store"
57
- end
@@ -1,50 +0,0 @@
1
- # Copyright 2015, Google Inc.
2
- # All rights reserved.
3
- #
4
- # Redistribution and use in source and binary forms, with or without
5
- # modification, are permitted provided that the following conditions are
6
- # met:
7
- #
8
- # * Redistributions of source code must retain the above copyright
9
- # notice, this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above
11
- # copyright notice, this list of conditions and the following disclaimer
12
- # in the documentation and/or other materials provided with the
13
- # distribution.
14
- # * Neither the name of Google Inc. nor the names of its
15
- # contributors may be used to endorse or promote products derived from
16
- # this software without specific prior written permission.
17
- #
18
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
-
30
- spec_dir = File.expand_path File.join(File.dirname(__FILE__))
31
- $LOAD_PATH.unshift spec_dir
32
- $LOAD_PATH.uniq!
33
-
34
- require "googleauth"
35
- require "googleauth/stores/redis_token_store"
36
- require "spec_helper"
37
- require "fakeredis/rspec"
38
- require "googleauth/stores/store_examples"
39
-
40
- describe Google::Auth::Stores::RedisTokenStore do
41
- let :redis do
42
- Redis.new
43
- end
44
-
45
- let :store do
46
- Google::Auth::Stores::RedisTokenStore.new redis: redis
47
- end
48
-
49
- it_behaves_like "token store"
50
- end
@@ -1,58 +0,0 @@
1
- # Copyright 2015, Google Inc.
2
- # All rights reserved.
3
- #
4
- # Redistribution and use in source and binary forms, with or without
5
- # modification, are permitted provided that the following conditions are
6
- # met:
7
- #
8
- # * Redistributions of source code must retain the above copyright
9
- # notice, this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above
11
- # copyright notice, this list of conditions and the following disclaimer
12
- # in the documentation and/or other materials provided with the
13
- # distribution.
14
- # * Neither the name of Google Inc. nor the names of its
15
- # contributors may be used to endorse or promote products derived from
16
- # this software without specific prior written permission.
17
- #
18
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
-
30
- spec_dir = File.expand_path File.join(File.dirname(__FILE__))
31
- $LOAD_PATH.unshift spec_dir
32
- $LOAD_PATH.uniq!
33
-
34
- require "spec_helper"
35
-
36
- shared_examples "token store" do
37
- before :each do
38
- store.store "default", "test"
39
- end
40
-
41
- it "should return a stored value" do
42
- expect(store.load("default")).to eq "test"
43
- end
44
-
45
- it "should return nil for missing tokens" do
46
- expect(store.load("notavalidkey")).to be_nil
47
- end
48
-
49
- it "should return nil for deleted tokens" do
50
- store.delete "default"
51
- expect(store.load("default")).to be_nil
52
- end
53
-
54
- it "should save overwrite values on store" do
55
- store.store "default", "test2"
56
- expect(store.load("default")).to eq "test2"
57
- end
58
- end
@@ -1,343 +0,0 @@
1
- # Copyright 2015, Google Inc.
2
- # All rights reserved.
3
- #
4
- # Redistribution and use in source and binary forms, with or without
5
- # modification, are permitted provided that the following conditions are
6
- # met:
7
- #
8
- # * Redistributions of source code must retain the above copyright
9
- # notice, this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above
11
- # copyright notice, this list of conditions and the following disclaimer
12
- # in the documentation and/or other materials provided with the
13
- # distribution.
14
- # * Neither the name of Google Inc. nor the names of its
15
- # contributors may be used to endorse or promote products derived from
16
- # this software without specific prior written permission.
17
- #
18
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
-
30
- spec_dir = File.expand_path File.join(File.dirname(__FILE__))
31
- $LOAD_PATH.unshift spec_dir
32
- $LOAD_PATH.uniq!
33
-
34
- require "googleauth"
35
- require "googleauth/user_authorizer"
36
- require "uri"
37
- require "multi_json"
38
- require "spec_helper"
39
-
40
- describe Google::Auth::UserAuthorizer do
41
- include TestHelpers
42
-
43
- let(:client_id) { Google::Auth::ClientId.new "testclient", "notasecret" }
44
- let(:scope) { %w[email profile] }
45
- let(:token_store) { DummyTokenStore.new }
46
- let(:callback_uri) { "https://www.example.com/oauth/callback" }
47
- let :authorizer do
48
- Google::Auth::UserAuthorizer.new(client_id,
49
- scope,
50
- token_store,
51
- callback_uri)
52
- end
53
-
54
- shared_examples "valid authorization url" do
55
- it "should have a valid base URI" do
56
- expect(uri).to match %r{https://accounts.google.com/o/oauth2/auth}
57
- end
58
-
59
- it "should request offline access" do
60
- expect(URI(uri).query).to match(/access_type=offline/)
61
- end
62
-
63
- it "should request response type code" do
64
- expect(URI(uri).query).to match(/response_type=code/)
65
- end
66
-
67
- it "should force approval" do
68
- expect(URI(uri).query).to match(/approval_prompt=force/)
69
- end
70
-
71
- it "should include granted scopes" do
72
- expect(URI(uri).query).to match(/include_granted_scopes=true/)
73
- end
74
-
75
- it "should include the correct client id" do
76
- expect(URI(uri).query).to match(/client_id=testclient/)
77
- end
78
-
79
- it "should not include a client secret" do
80
- expect(URI(uri).query).to_not match(/client_secret/)
81
- end
82
-
83
- it "should include the redirect_uri" do
84
- expect(URI(uri).query).to match(
85
- %r{redirect_uri=https://www.example.com/oauth/callback}
86
- )
87
- end
88
-
89
- it "should include the scope" do
90
- expect(URI(uri).query).to match(/scope=email%20profile/)
91
- end
92
- end
93
-
94
- context "when generating authorization URLs and callback_uri is 'postmessage'" do
95
- let(:callback_uri) { "postmessage" }
96
- let :authorizer do
97
- Google::Auth::UserAuthorizer.new(client_id,
98
- scope,
99
- token_store,
100
- callback_uri)
101
- end
102
- let :uri do
103
- authorizer.get_authorization_url login_hint: "user1", state: "mystate"
104
- end
105
-
106
- it "should include the redirect_uri 'postmessage'" do
107
- expect(URI(uri).query).to match(
108
- %r{redirect_uri=postmessage}
109
- )
110
- end
111
- end
112
-
113
- context "when generating authorization URLs with user ID & state" do
114
- let :uri do
115
- authorizer.get_authorization_url login_hint: "user1", state: "mystate"
116
- end
117
-
118
- it_behaves_like "valid authorization url"
119
-
120
- it "includes a login hint" do
121
- expect(URI(uri).query).to match(/login_hint=user1/)
122
- end
123
-
124
- it "includes the app state" do
125
- expect(URI(uri).query).to match(/state=mystate/)
126
- end
127
- end
128
-
129
- context "when generating authorization URLs with user ID and no state" do
130
- let(:uri) { authorizer.get_authorization_url login_hint: "user1" }
131
-
132
- it_behaves_like "valid authorization url"
133
-
134
- it "includes a login hint" do
135
- expect(URI(uri).query).to match(/login_hint=user1/)
136
- end
137
-
138
- it "does not include the state parameter" do
139
- expect(URI(uri).query).to_not match(/state/)
140
- end
141
- end
142
-
143
- context "when generating authorization URLs with no user ID and no state" do
144
- let(:uri) { authorizer.get_authorization_url }
145
-
146
- it_behaves_like "valid authorization url"
147
-
148
- it "does not include the login hint parameter" do
149
- expect(URI(uri).query).to_not match(/login_hint/)
150
- end
151
-
152
- it "does not include the state parameter" do
153
- expect(URI(uri).query).to_not match(/state/)
154
- end
155
- end
156
-
157
- context "when retrieving tokens" do
158
- let :token_json do
159
- MultiJson.dump(
160
- access_token: "accesstoken",
161
- refresh_token: "refreshtoken",
162
- expiration_time_millis: 1_441_234_742_000
163
- )
164
- end
165
-
166
- context "with a valid user id" do
167
- let :credentials do
168
- token_store.store "user1", token_json
169
- authorizer.get_credentials "user1"
170
- end
171
-
172
- it "should return an instance of UserRefreshCredentials" do
173
- expect(credentials).to be_instance_of(
174
- Google::Auth::UserRefreshCredentials
175
- )
176
- end
177
-
178
- it "should return credentials with a valid refresh token" do
179
- expect(credentials.refresh_token).to eq "refreshtoken"
180
- end
181
-
182
- it "should return credentials with a valid access token" do
183
- expect(credentials.access_token).to eq "accesstoken"
184
- end
185
-
186
- it "should return credentials with a valid client ID" do
187
- expect(credentials.client_id).to eq "testclient"
188
- end
189
-
190
- it "should return credentials with a valid client secret" do
191
- expect(credentials.client_secret).to eq "notasecret"
192
- end
193
-
194
- it "should return credentials with a valid scope" do
195
- expect(credentials.scope).to eq %w[email profile]
196
- end
197
-
198
- it "should return credentials with a valid expiration time" do
199
- expect(credentials.expires_at).to eq Time.at(1_441_234_742)
200
- end
201
- end
202
-
203
- context "with an invalid user id" do
204
- it "should return nil" do
205
- expect(authorizer.get_credentials("notauser")).to be_nil
206
- end
207
- end
208
- end
209
-
210
- context "when saving tokens" do
211
- let(:expiry) { Time.now.to_i }
212
- let :credentials do
213
- Google::Auth::UserRefreshCredentials.new(
214
- client_id: client_id.id,
215
- client_secret: client_id.secret,
216
- scope: scope,
217
- refresh_token: "refreshtoken",
218
- access_token: "accesstoken",
219
- expires_at: expiry
220
- )
221
- end
222
-
223
- let :token_json do
224
- authorizer.store_credentials "user1", credentials
225
- token_store.load "user1"
226
- end
227
-
228
- it "should persist in the token store" do
229
- expect(token_json).to_not be_nil
230
- end
231
-
232
- it "should persist the refresh token" do
233
- expect(MultiJson.load(token_json)["refresh_token"]).to eq "refreshtoken"
234
- end
235
-
236
- it "should persist the access token" do
237
- expect(MultiJson.load(token_json)["access_token"]).to eq "accesstoken"
238
- end
239
-
240
- it "should persist the client id" do
241
- expect(MultiJson.load(token_json)["client_id"]).to eq "testclient"
242
- end
243
-
244
- it "should persist the scope" do
245
- expect(MultiJson.load(token_json)["scope"]).to include("email", "profile")
246
- end
247
-
248
- it "should persist the expiry as milliseconds" do
249
- expected_expiry = expiry * 1000
250
- expect(MultiJson.load(token_json)["expiration_time_millis"]).to eql(
251
- expected_expiry
252
- )
253
- end
254
- end
255
-
256
- context "with valid authorization code" do
257
- let :token_json do
258
- MultiJson.dump("access_token" => "1/abc123",
259
- "token_type" => "Bearer",
260
- "expires_in" => 3600)
261
- end
262
-
263
- before :example do
264
- stub_request(:post, "https://oauth2.googleapis.com/token")
265
- .to_return(body: token_json, status: 200, headers: {
266
- "Content-Type" => "application/json"
267
- })
268
- end
269
-
270
- it "should exchange a code for credentials" do
271
- credentials = authorizer.get_credentials_from_code(
272
- user_id: "user1", code: "code"
273
- )
274
- expect(credentials.access_token).to eq "1/abc123"
275
- expect(credentials.redirect_uri.to_s).to eq "https://www.example.com/oauth/callback"
276
- end
277
-
278
- it "should not store credentials when get only requested" do
279
- authorizer.get_credentials_from_code user_id: "user1", code: "code"
280
- expect(token_store.load("user1")).to be_nil
281
- end
282
-
283
- it "should store credentials when requested" do
284
- authorizer.get_and_store_credentials_from_code(
285
- user_id: "user1", code: "code"
286
- )
287
- expect(token_store.load("user1")).to_not be_nil
288
- end
289
- end
290
-
291
- context "with invalid authorization code" do
292
- before :example do
293
- stub_request(:post, "https://oauth2.googleapis.com/token")
294
- .to_return(status: 400)
295
- end
296
-
297
- it "should raise an authorization error" do
298
- expect do
299
- authorizer.get_credentials_from_code user_id: "user1", code: "badcode"
300
- end.to raise_error Signet::AuthorizationError
301
- end
302
-
303
- it "should not store credentials when exchange fails" do
304
- expect do
305
- authorizer.get_credentials_from_code user_id: "user1", code: "badcode"
306
- end.to raise_error Signet::AuthorizationError
307
- expect(token_store.load("user1")).to be_nil
308
- end
309
- end
310
-
311
- context "when reovking authorization" do
312
- let :token_json do
313
- MultiJson.dump(
314
- access_token: "accesstoken",
315
- refresh_token: "refreshtoken",
316
- expiration_time_millis: 1_441_234_742_000
317
- )
318
- end
319
-
320
- before :example do
321
- token_store.store "user1", token_json
322
- stub_request(:post, "https://oauth2.googleapis.com/revoke")
323
- .with(body: hash_including("token" => "refreshtoken"))
324
- .to_return(status: 200)
325
- end
326
-
327
- it "should revoke the grant" do
328
- authorizer.revoke_authorization "user1"
329
- expect(a_request(
330
- :post, "https://oauth2.googleapis.com/revoke"
331
- ).with(body: hash_including("token" => "refreshtoken")))
332
- .to have_been_made
333
- end
334
-
335
- it "should remove the token from storage" do
336
- authorizer.revoke_authorization "user1"
337
- expect(token_store.load("user1")).to be_nil
338
- end
339
- end
340
-
341
- # TODO: - Test that tokens are monitored
342
- # TODO - Test scope enforcement (auth if upgrade required)
343
- end