googleauth 0.4.2 → 0.5.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.
@@ -0,0 +1,140 @@
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
+ require 'fakefs/safe'
36
+ require 'googleauth'
37
+
38
+ describe Google::Auth::ClientId do
39
+ shared_examples 'it has a valid config' do
40
+ it 'should include a valid id' do
41
+ expect(client_id.id).to eql 'abc@example.com'
42
+ end
43
+
44
+ it 'should include a valid secret' do
45
+ expect(client_id.secret).to eql 'notasecret'
46
+ end
47
+ end
48
+
49
+ shared_examples 'it can successfully load client_id' do
50
+ context 'loaded from hash' do
51
+ let(:client_id) { Google::Auth::ClientId.from_hash(config) }
52
+
53
+ it_behaves_like 'it has a valid config'
54
+ end
55
+
56
+ context 'loaded from file' do
57
+ file_path = '/client_secrets.json'
58
+
59
+ let(:client_id) do
60
+ FakeFS do
61
+ content = MultiJson.dump(config)
62
+ File.write(file_path, content)
63
+ Google::Auth::ClientId.from_file(file_path)
64
+ end
65
+ end
66
+
67
+ it_behaves_like 'it has a valid config'
68
+ end
69
+ end
70
+
71
+ describe 'with web config' do
72
+ let(:config) do
73
+ {
74
+ 'web' => {
75
+ 'client_id' => 'abc@example.com',
76
+ 'client_secret' => 'notasecret'
77
+ }
78
+ }
79
+ end
80
+ it_behaves_like 'it can successfully load client_id'
81
+ end
82
+
83
+ describe 'with installed app config' do
84
+ let(:config) do
85
+ {
86
+ 'installed' => {
87
+ 'client_id' => 'abc@example.com',
88
+ 'client_secret' => 'notasecret'
89
+ }
90
+ }
91
+ end
92
+ it_behaves_like 'it can successfully load client_id'
93
+ end
94
+
95
+ context 'with missing top level property' do
96
+ let(:config) do
97
+ {
98
+ 'notvalid' => {
99
+ 'client_id' => 'abc@example.com',
100
+ 'client_secret' => 'notasecret'
101
+ }
102
+ }
103
+ end
104
+
105
+ it 'should raise error' do
106
+ expect { Google::Auth::ClientId.from_hash(config) }.to raise_error(
107
+ /Expected top level property/)
108
+ end
109
+ end
110
+
111
+ context 'with missing client id' do
112
+ let(:config) do
113
+ {
114
+ 'web' => {
115
+ 'client_secret' => 'notasecret'
116
+ }
117
+ }
118
+ end
119
+
120
+ it 'should raise error' do
121
+ expect { Google::Auth::ClientId.from_hash(config) }.to raise_error(
122
+ /Client id can not be nil/)
123
+ end
124
+ end
125
+
126
+ context 'with missing client secret' do
127
+ let(:config) do
128
+ {
129
+ 'web' => {
130
+ 'client_id' => 'abc@example.com'
131
+ }
132
+ }
133
+ end
134
+
135
+ it 'should raise error' do
136
+ expect { Google::Auth::ClientId.from_hash(config) }.to raise_error(
137
+ /Client secret can not be nil/)
138
+ end
139
+ end
140
+ end
@@ -37,7 +37,7 @@ require 'googleauth/compute_engine'
37
37
  require 'spec_helper'
38
38
 
39
39
  describe Google::Auth::GCECredentials do
40
- MD_URI = '/computeMetadata/v1/instance/service-accounts/default/token'
40
+ MD_URI = 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token'
41
41
  GCECredentials = Google::Auth::GCECredentials
42
42
 
43
43
  before(:example) do
@@ -46,16 +46,14 @@ describe Google::Auth::GCECredentials do
46
46
 
47
47
  def make_auth_stubs(opts = {})
48
48
  access_token = opts[:access_token] || ''
49
- Faraday::Adapter::Test::Stubs.new do |stub|
50
- stub.get(MD_URI) do |env|
51
- headers = env[:request_headers]
52
- expect(headers['Metadata-Flavor']).to eq('Google')
53
- build_json_response(
54
- 'access_token' => access_token,
55
- 'token_type' => 'Bearer',
56
- 'expires_in' => 3600)
57
- end
58
- end
49
+ body = MultiJson.dump('access_token' => access_token,
50
+ 'token_type' => 'Bearer',
51
+ 'expires_in' => 3600)
52
+ stub_request(:get, MD_URI)
53
+ .with(headers: { 'Metadata-Flavor' => 'Google' })
54
+ .to_return(body: body,
55
+ status: 200,
56
+ headers: { 'Content-Type' => 'application/json' })
59
57
  end
60
58
 
61
59
  it_behaves_like 'apply/apply! are OK'
@@ -63,83 +61,48 @@ describe Google::Auth::GCECredentials do
63
61
  context 'metadata is unavailable' do
64
62
  describe '#fetch_access_token' do
65
63
  it 'should fail if the metadata request returns a 404' do
66
- stubs = Faraday::Adapter::Test::Stubs.new do |stub|
67
- stub.get(MD_URI) do |_env|
68
- [404,
69
- { 'Metadata-Flavor' => 'Google' },
70
- '']
71
- end
72
- end
73
- c = Faraday.new do |b|
74
- b.adapter(:test, stubs)
75
- end
76
- blk = proc { @client.fetch_access_token!(connection: c) }
64
+ stub = stub_request(:get, MD_URI)
65
+ .to_return(status: 404,
66
+ headers: { 'Metadata-Flavor' => 'Google' })
67
+ blk = proc { @client.fetch_access_token! }
77
68
  expect(&blk).to raise_error Signet::AuthorizationError
78
- stubs.verify_stubbed_calls
69
+ expect(stub).to have_been_requested
79
70
  end
80
71
 
81
72
  it 'should fail if the metadata request returns an unexpected code' do
82
- stubs = Faraday::Adapter::Test::Stubs.new do |stub|
83
- stub.get(MD_URI) do |_env|
84
- [503,
85
- { 'Metadata-Flavor' => 'Google' },
86
- '']
87
- end
88
- end
89
- c = Faraday.new do |b|
90
- b.adapter(:test, stubs)
91
- end
92
- blk = proc { @client.fetch_access_token!(connection: c) }
73
+ stub = stub_request(:get, MD_URI)
74
+ .to_return(status: 503,
75
+ headers: { 'Metadata-Flavor' => 'Google' })
76
+ blk = proc { @client.fetch_access_token! }
93
77
  expect(&blk).to raise_error Signet::AuthorizationError
94
- stubs.verify_stubbed_calls
78
+ expect(stub).to have_been_requested
95
79
  end
96
80
  end
97
81
  end
98
82
 
99
83
  describe '#on_gce?' do
100
84
  it 'should be true when Metadata-Flavor is Google' do
101
- stubs = Faraday::Adapter::Test::Stubs.new do |stub|
102
- stub.get('/') do |_env|
103
- [200,
104
- { 'Metadata-Flavor' => 'Google' },
105
- '']
106
- end
107
- end
108
- c = Faraday.new do |b|
109
- b.adapter(:test, stubs)
110
- end
111
- expect(GCECredentials.on_gce?(connection: c)).to eq(true)
112
- stubs.verify_stubbed_calls
85
+ stub = stub_request(:get, 'http://169.254.169.254')
86
+ .to_return(status: 200,
87
+ headers: { 'Metadata-Flavor' => 'Google' })
88
+ expect(GCECredentials.on_gce?({}, true)).to eq(true)
89
+ expect(stub).to have_been_requested
113
90
  end
114
91
 
115
92
  it 'should be false when Metadata-Flavor is not Google' do
116
- stubs = Faraday::Adapter::Test::Stubs.new do |stub|
117
- stub.get('/') do |_env|
118
- [200,
119
- { 'Metadata-Flavor' => 'NotGoogle' },
120
- '']
121
- end
122
- end
123
- c = Faraday.new do |b|
124
- b.adapter(:test, stubs)
125
- end
126
- expect(GCECredentials.on_gce?(connection: c)).to eq(false)
127
- stubs.verify_stubbed_calls
93
+ stub = stub_request(:get, 'http://169.254.169.254')
94
+ .to_return(status: 200,
95
+ headers: { 'Metadata-Flavor' => 'NotGoogle' })
96
+ expect(GCECredentials.on_gce?({}, true)).to eq(false)
97
+ expect(stub).to have_been_requested
128
98
  end
129
99
 
130
100
  it 'should be false if the response is not 200' do
131
- stubs = Faraday::Adapter::Test::Stubs.new do |stub|
132
- stub.get('/') do |_env|
133
- [404,
134
- { 'Metadata-Flavor' => 'Google' },
135
- '']
136
- end
137
- end
138
- c = Faraday.new do |b|
139
- b.adapter(:test, stubs)
140
- end
141
- expect(GCECredentials.on_gce?(connection: c)).to eq(false)
142
- stubs.verify_stubbed_calls
101
+ stub = stub_request(:get, 'http://169.254.169.254')
102
+ .to_return(status: 404,
103
+ headers: { 'Metadata-Flavor' => 'NotGoogle' })
104
+ expect(GCECredentials.on_gce?({}, true)).to eq(false)
105
+ expect(stub).to have_been_requested
143
106
  end
144
107
  end
145
108
  end
@@ -37,6 +37,9 @@ require 'googleauth'
37
37
  require 'spec_helper'
38
38
 
39
39
  describe '#get_application_default' do
40
+ # Pass unique options each time to bypass memoization
41
+ let(:options) { |example| { dememoize: example } }
42
+
40
43
  before(:example) do
41
44
  @key = OpenSSL::PKey::RSA.new(2048)
42
45
  @var_name = ENV_VAR
@@ -59,31 +62,24 @@ describe '#get_application_default' do
59
62
  Dir.mktmpdir do |dir|
60
63
  key_path = File.join(dir, 'does-not-exist')
61
64
  ENV[@var_name] = key_path
62
- expect { Google::Auth.get_application_default(@scope) }
65
+ expect { Google::Auth.get_application_default(@scope, options) }
63
66
  .to raise_error RuntimeError
64
67
  end
65
68
  end
66
69
 
67
70
  it 'fails without default file or env if not on compute engine' do
68
- stubs = Faraday::Adapter::Test::Stubs.new do |stub|
69
- stub.get('/') do |_env|
70
- [404,
71
- { 'Metadata-Flavor' => 'Google' },
72
- '']
73
- end
74
- end # GCE not detected
71
+ stub = stub_request(:get, 'http://169.254.169.254')
72
+ .to_return(status: 404,
73
+ headers: { 'Metadata-Flavor' => 'NotGoogle' })
75
74
  Dir.mktmpdir do |dir|
76
75
  ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var
77
76
  ENV['HOME'] = dir # no config present in this tmp dir
78
- c = Faraday.new do |b|
79
- b.adapter(:test, stubs)
80
- end
81
77
  blk = proc do
82
- Google::Auth.get_application_default(@scope, connection: c)
78
+ Google::Auth.get_application_default(@scope, options)
83
79
  end
84
80
  expect(&blk).to raise_error RuntimeError
85
81
  end
86
- stubs.verify_stubbed_calls
82
+ expect(stub).to have_been_requested
87
83
  end
88
84
  end
89
85
 
@@ -94,7 +90,8 @@ describe '#get_application_default' do
94
90
  FileUtils.mkdir_p(File.dirname(key_path))
95
91
  File.write(key_path, cred_json_text)
96
92
  ENV[@var_name] = key_path
97
- expect(Google::Auth.get_application_default(@scope)).to_not be_nil
93
+ expect(Google::Auth.get_application_default(@scope, options))
94
+ .to_not be_nil
98
95
  end
99
96
  end
100
97
 
@@ -105,7 +102,8 @@ describe '#get_application_default' do
105
102
  FileUtils.mkdir_p(File.dirname(key_path))
106
103
  File.write(key_path, cred_json_text)
107
104
  ENV['HOME'] = dir
108
- expect(Google::Auth.get_application_default(@scope)).to_not be_nil
105
+ expect(Google::Auth.get_application_default(@scope, options))
106
+ .to_not be_nil
109
107
  end
110
108
  end
111
109
 
@@ -116,30 +114,21 @@ describe '#get_application_default' do
116
114
  FileUtils.mkdir_p(File.dirname(key_path))
117
115
  File.write(key_path, cred_json_text)
118
116
  ENV['HOME'] = dir
119
- expect(Google::Auth.get_application_default).to_not be_nil
117
+ expect(Google::Auth.get_application_default(nil, options)).to_not be_nil
120
118
  end
121
119
  end
122
120
 
123
121
  it 'succeeds without default file or env if on compute engine' do
124
- stubs = Faraday::Adapter::Test::Stubs.new do |stub|
125
- stub.get('/') do |_env|
126
- [200,
127
- { 'Metadata-Flavor' => 'Google' },
128
- '']
129
- end
130
- end # GCE detected
122
+ stub = stub_request(:get, 'http://169.254.169.254')
123
+ .to_return(status: 200,
124
+ headers: { 'Metadata-Flavor' => 'Google' })
131
125
  Dir.mktmpdir do |dir|
132
126
  ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var
133
127
  ENV['HOME'] = dir # no config present in this tmp dir
134
- c = Faraday.new do |b|
135
- b.adapter(:test, stubs)
136
- end
137
- creds = Google::Auth.get_application_default(
138
- @scope,
139
- connection: c)
128
+ creds = Google::Auth.get_application_default(@scope, options)
140
129
  expect(creds).to_not be_nil
141
130
  end
142
- stubs.verify_stubbed_calls
131
+ expect(stub).to have_been_requested
143
132
  end
144
133
 
145
134
  it 'succeeds with system default file' do
@@ -148,7 +137,8 @@ describe '#get_application_default' do
148
137
  key_path = File.join('/etc/google/auth/', CREDENTIALS_FILE_NAME)
149
138
  FileUtils.mkdir_p(File.dirname(key_path))
150
139
  File.write(key_path, cred_json_text)
151
- expect(Google::Auth.get_application_default(@scope)).to_not be_nil
140
+ expect(Google::Auth.get_application_default(@scope, options))
141
+ .to_not be_nil
152
142
  File.delete(key_path)
153
143
  end
154
144
  end
@@ -161,7 +151,8 @@ describe '#get_application_default' do
161
151
  ENV[CLIENT_SECRET_VAR] = cred_json[:client_secret]
162
152
  ENV[REFRESH_TOKEN_VAR] = cred_json[:refresh_token]
163
153
  ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
164
- expect(Google::Auth.get_application_default(@scope)).to_not be_nil
154
+ expect(Google::Auth.get_application_default(@scope, options))
155
+ .to_not be_nil
165
156
  end
166
157
  end
167
158
 
@@ -225,7 +216,7 @@ describe '#get_application_default' do
225
216
  File.write(key_path, cred_json_text)
226
217
  ENV[@var_name] = key_path
227
218
  blk = proc do
228
- Google::Auth.get_application_default(@scope)
219
+ Google::Auth.get_application_default(@scope, options)
229
220
  end
230
221
  expect(&blk).to raise_error RuntimeError
231
222
  end
@@ -239,7 +230,7 @@ describe '#get_application_default' do
239
230
  File.write(key_path, cred_json_text)
240
231
  ENV['HOME'] = dir
241
232
  blk = proc do
242
- Google::Auth.get_application_default(@scope)
233
+ Google::Auth.get_application_default(@scope, options)
243
234
  end
244
235
  expect(&blk).to raise_error RuntimeError
245
236
  end
@@ -249,7 +240,7 @@ describe '#get_application_default' do
249
240
  ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
250
241
  ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
251
242
  blk = proc do
252
- Google::Auth.get_application_default(@scope)
243
+ Google::Auth.get_application_default(@scope, options)
253
244
  end
254
245
  expect(&blk).to raise_error RuntimeError
255
246
  end
@@ -0,0 +1,75 @@
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/scope_util'
35
+
36
+ describe Google::Auth::ScopeUtil do
37
+ shared_examples 'normalizes scopes' do
38
+ let(:normalized) { Google::Auth::ScopeUtil.normalize(source) }
39
+
40
+ it 'normalizes the email scope' do
41
+ expect(normalized).to include(
42
+ 'https://www.googleapis.com/auth/userinfo.email')
43
+ expect(normalized).to_not include 'email'
44
+ end
45
+
46
+ it 'normalizes the profile scope' do
47
+ expect(normalized).to include(
48
+ 'https://www.googleapis.com/auth/userinfo.profile')
49
+ expect(normalized).to_not include 'profile'
50
+ end
51
+
52
+ it 'normalizes the openid scope' do
53
+ expect(normalized).to include 'https://www.googleapis.com/auth/plus.me'
54
+ expect(normalized).to_not include 'openid'
55
+ end
56
+
57
+ it 'leaves other other scopes as-is' do
58
+ expect(normalized).to include 'https://www.googleapis.com/auth/drive'
59
+ end
60
+ end
61
+
62
+ context 'with scope as string' do
63
+ let(:source) do
64
+ 'email profile openid https://www.googleapis.com/auth/drive'
65
+ end
66
+ it_behaves_like 'normalizes scopes'
67
+ end
68
+
69
+ context 'with scope as Array' do
70
+ let(:source) do
71
+ %w(email profile openid https://www.googleapis.com/auth/drive)
72
+ end
73
+ it_behaves_like 'normalizes scopes'
74
+ end
75
+ end