googleauth 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,108 @@
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 'faraday'
36
+ require 'googleauth/compute_engine'
37
+ require 'spec_helper'
38
+
39
+ describe Google::Auth::GCECredentials do
40
+ MD_URI = '/computeMetadata/v1/instance/service-accounts/default/token'
41
+ GCECredentials = Google::Auth::GCECredentials
42
+
43
+ before(:example) do
44
+ @client = GCECredentials.new
45
+ end
46
+
47
+ def make_auth_stubs(access_token: '')
48
+ Faraday::Adapter::Test::Stubs.new do |stub|
49
+ stub.get(MD_URI) do |env|
50
+ headers = env[:request_headers]
51
+ expect(headers['Metadata-Flavor']).to eq('Google')
52
+ build_json_response(
53
+ 'access_token' => access_token,
54
+ 'token_type' => 'Bearer',
55
+ 'expires_in' => 3600)
56
+ end
57
+ end
58
+ end
59
+
60
+ it_behaves_like 'apply/apply! are OK'
61
+
62
+ describe '#on_gce?' do
63
+ it 'should be true when Metadata-Flavor is Google' do
64
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
65
+ stub.get('/') do |_env|
66
+ [200,
67
+ { 'Metadata-Flavor' => 'Google' },
68
+ '']
69
+ end
70
+ end
71
+ c = Faraday.new do |b|
72
+ b.adapter(:test, stubs)
73
+ end
74
+ expect(GCECredentials.on_gce?(connection: c)).to eq(true)
75
+ stubs.verify_stubbed_calls
76
+ end
77
+
78
+ it 'should be false when Metadata-Flavor is not Google' do
79
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
80
+ stub.get('/') do |_env|
81
+ [200,
82
+ { 'Metadata-Flavor' => 'NotGoogle' },
83
+ '']
84
+ end
85
+ end
86
+ c = Faraday.new do |b|
87
+ b.adapter(:test, stubs)
88
+ end
89
+ expect(GCECredentials.on_gce?(connection: c)).to eq(false)
90
+ stubs.verify_stubbed_calls
91
+ end
92
+
93
+ it 'should be false if the response is not 200' do
94
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
95
+ stub.get('/') do |_env|
96
+ [404,
97
+ { 'Metadata-Flavor' => 'Google' },
98
+ '']
99
+ end
100
+ end
101
+ c = Faraday.new do |b|
102
+ b.adapter(:test, stubs)
103
+ end
104
+ expect(GCECredentials.on_gce?(connection: c)).to eq(false)
105
+ stubs.verify_stubbed_calls
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,134 @@
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 'faraday'
35
+ require 'googleauth'
36
+ require 'spec_helper'
37
+
38
+ describe '#get_application_default' do
39
+ before(:example) do
40
+ @key = OpenSSL::PKey::RSA.new(2048)
41
+ @var_name = ServiceAccountCredentials::ENV_VAR
42
+ @orig = ENV[@var_name]
43
+ @home = ENV['HOME']
44
+ @scope = 'https://www.googleapis.com/auth/userinfo.profile'
45
+ end
46
+
47
+ after(:example) do
48
+ ENV[@var_name] = @orig unless @orig.nil?
49
+ ENV['HOME'] = @home unless @home == ENV['HOME']
50
+ end
51
+
52
+ def cred_json_text
53
+ cred_json = {
54
+ private_key_id: 'a_private_key_id',
55
+ private_key: @key.to_pem,
56
+ client_email: 'app@developer.gserviceaccount.com',
57
+ client_id: 'app.apps.googleusercontent.com',
58
+ type: 'service_account'
59
+ }
60
+ MultiJson.dump(cred_json)
61
+ end
62
+
63
+ it 'fails if the GOOGLE_APPLICATION_CREDENTIALS path does not exist' do
64
+ Dir.mktmpdir do |dir|
65
+ key_path = File.join(dir, 'does-not-exist')
66
+ ENV[@var_name] = key_path
67
+ expect { Google::Auth.get_application_default(@scope) }.to raise_error
68
+ end
69
+ end
70
+
71
+ it 'succeeds if the GOOGLE_APPLICATION_CREDENTIALS file is valid' do
72
+ Dir.mktmpdir do |dir|
73
+ key_path = File.join(dir, 'my_cert_file')
74
+ FileUtils.mkdir_p(File.dirname(key_path))
75
+ File.write(key_path, cred_json_text)
76
+ ENV[@var_name] = key_path
77
+ expect(Google::Auth.get_application_default(@scope)).to_not be_nil
78
+ end
79
+ end
80
+
81
+ it 'succeeds with default file if GOOGLE_APPLICATION_CREDENTIALS is unset' do
82
+ ENV.delete(@var_name) unless ENV[@var_name].nil?
83
+ Dir.mktmpdir do |dir|
84
+ key_path = File.join(dir, '.config',
85
+ ServiceAccountCredentials::WELL_KNOWN_PATH)
86
+ FileUtils.mkdir_p(File.dirname(key_path))
87
+ File.write(key_path, cred_json_text)
88
+ ENV['HOME'] = dir
89
+ expect(Google::Auth.get_application_default(@scope)).to_not be_nil
90
+ end
91
+ end
92
+
93
+ it 'fails without default file or env if not on compute engine' do
94
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
95
+ stub.get('/') do |_env|
96
+ [404,
97
+ { 'Metadata-Flavor' => 'Google' },
98
+ '']
99
+ end
100
+ end # GCE not detected
101
+ Dir.mktmpdir do |dir|
102
+ ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var
103
+ ENV['HOME'] = dir # no config present in this tmp dir
104
+ c = Faraday.new do |b|
105
+ b.adapter(:test, stubs)
106
+ end
107
+ blk = proc do
108
+ Google::Auth.get_application_default(@scope, connection: c)
109
+ end
110
+ expect(&blk).to raise_error
111
+ end
112
+ stubs.verify_stubbed_calls
113
+ end
114
+
115
+ it 'succeeds without default file or env if on compute engine' do
116
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
117
+ stub.get('/') do |_env|
118
+ [200,
119
+ { 'Metadata-Flavor' => 'Google' },
120
+ '']
121
+ end
122
+ end # GCE detected
123
+ Dir.mktmpdir do |dir|
124
+ ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var
125
+ ENV['HOME'] = dir # no config present in this tmp dir
126
+ c = Faraday.new do |b|
127
+ b.adapter(:test, stubs)
128
+ end
129
+ expect(Google::Auth.get_application_default(@scope,
130
+ connection: c)).to_not be_nil
131
+ end
132
+ stubs.verify_stubbed_calls
133
+ end
134
+ end
@@ -0,0 +1,143 @@
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 'fileutils'
36
+ require 'googleauth/service_account'
37
+ require 'jwt'
38
+ require 'multi_json'
39
+ require 'openssl'
40
+ require 'spec_helper'
41
+ require 'tmpdir'
42
+
43
+ describe Google::Auth::ServiceAccountCredentials do
44
+ ServiceAccountCredentials = Google::Auth::ServiceAccountCredentials
45
+
46
+ before(:example) do
47
+ @key = OpenSSL::PKey::RSA.new(2048)
48
+ @client = ServiceAccountCredentials.new(
49
+ 'https://www.googleapis.com/auth/userinfo.profile',
50
+ StringIO.new(cred_json_text))
51
+ end
52
+
53
+ def make_auth_stubs(access_token: '')
54
+ Faraday::Adapter::Test::Stubs.new do |stub|
55
+ stub.post('/oauth2/v3/token') do |env|
56
+ params = Addressable::URI.form_unencode(env[:body])
57
+ _claim, _header = JWT.decode(params.assoc('assertion').last,
58
+ @key.public_key)
59
+ want = ['grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer']
60
+ expect(params.assoc('grant_type')).to eq(want)
61
+ build_access_token_json(access_token)
62
+ end
63
+ end
64
+ end
65
+
66
+ def cred_json_text
67
+ cred_json = {
68
+ private_key_id: 'a_private_key_id',
69
+ private_key: @key.to_pem,
70
+ client_email: 'app@developer.gserviceaccount.com',
71
+ client_id: 'app.apps.googleusercontent.com',
72
+ type: 'service_account'
73
+ }
74
+ MultiJson.dump(cred_json)
75
+ end
76
+
77
+ it_behaves_like 'apply/apply! are OK'
78
+
79
+ describe '#from_env' do
80
+ before(:example) do
81
+ @var_name = ServiceAccountCredentials::ENV_VAR
82
+ @orig = ENV[@var_name]
83
+ @scope = 'https://www.googleapis.com/auth/userinfo.profile'
84
+ end
85
+
86
+ after(:example) do
87
+ ENV[@var_name] = @orig unless @orig.nil?
88
+ end
89
+
90
+ it 'returns nil if the GOOGLE_APPLICATION_CREDENTIALS is unset' do
91
+ ENV.delete(@var_name) unless ENV[@var_name].nil?
92
+ expect(ServiceAccountCredentials.from_env(@scope)).to be_nil
93
+ end
94
+
95
+ it 'fails if the GOOGLE_APPLICATION_CREDENTIALS path does not exist' do
96
+ ENV.delete(@var_name) unless ENV[@var_name].nil?
97
+ expect(ServiceAccountCredentials.from_env(@scope)).to be_nil
98
+ Dir.mktmpdir do |dir|
99
+ key_path = File.join(dir, 'does-not-exist')
100
+ ENV[@var_name] = key_path
101
+ expect { sac.from_env(@scope) }.to raise_error
102
+ end
103
+ end
104
+
105
+ it 'succeeds when the GOOGLE_APPLICATION_CREDENTIALS file is valid' do
106
+ sac = ServiceAccountCredentials # shortens name
107
+ Dir.mktmpdir do |dir|
108
+ key_path = File.join(dir, 'my_cert_file')
109
+ FileUtils.mkdir_p(File.dirname(key_path))
110
+ File.write(key_path, cred_json_text)
111
+ ENV[@var_name] = key_path
112
+ expect(sac.from_env(@scope)).to_not be_nil
113
+ end
114
+ end
115
+ end
116
+
117
+ describe '#from_well_known_path' do
118
+ before(:example) do
119
+ @home = ENV['HOME']
120
+ @scope = 'https://www.googleapis.com/auth/userinfo.profile'
121
+ end
122
+
123
+ after(:example) do
124
+ ENV['HOME'] = @home unless @home == ENV['HOME']
125
+ end
126
+
127
+ it 'is nil if no file exists' do
128
+ ENV['HOME'] = File.dirname(__FILE__)
129
+ expect(ServiceAccountCredentials.from_well_known_path(@scope)).to be_nil
130
+ end
131
+
132
+ it 'successfully loads the file when it is present' do
133
+ sac = ServiceAccountCredentials # shortens name
134
+ Dir.mktmpdir do |dir|
135
+ key_path = File.join(dir, '.config', sac::WELL_KNOWN_PATH)
136
+ FileUtils.mkdir_p(File.dirname(key_path))
137
+ File.write(key_path, cred_json_text)
138
+ ENV['HOME'] = dir
139
+ expect(sac.from_well_known_path(@scope)).to_not be_nil
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,66 @@
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://accounts.google.com/o/oauth2/token',
45
+ scope: 'https://www.googleapis.com/auth/userinfo.profile',
46
+ issuer: 'app@example.com',
47
+ audience: 'https://accounts.google.com/o/oauth2/token',
48
+ signing_key: @key
49
+ )
50
+ end
51
+
52
+ def make_auth_stubs(access_token: '')
53
+ Faraday::Adapter::Test::Stubs.new do |stub|
54
+ stub.post('/o/oauth2/token') do |env|
55
+ params = Addressable::URI.form_unencode(env[:body])
56
+ _claim, _header = JWT.decode(params.assoc('assertion').last,
57
+ @key.public_key)
58
+ want = ['grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer']
59
+ expect(params.assoc('grant_type')).to eq(want)
60
+ build_access_token_json(access_token)
61
+ end
62
+ end
63
+ end
64
+
65
+ it_behaves_like 'apply/apply! are OK'
66
+ end