googleauth 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 296c6ddfcc4f4a1150e7bfc14e00fc37d60ba933
4
- data.tar.gz: 4e3921f83b5816e22e8509ce7a1912376322ba95
3
+ metadata.gz: ac8bcce8f139bb5d243108c0ab7273b52db59305
4
+ data.tar.gz: df908e203c1963f8194cd89d26d055cced4b5895
5
5
  SHA512:
6
- metadata.gz: cc0469ce9a49f4b41cf5be4f0682395f9616940e2eae99af294b22ea646a35a8efbd527ce865056d719cd00d5f473c6bb3c07ffe28a77c82ba8f8e1bd2ba7168
7
- data.tar.gz: b5217485091a72f408dce0fd08e6f9a5d45450f3c16783b8c5f2b8dd13fdeaf96eea90f9bc8b80ec9c10d0c1ee5925536b64f4b0cf8dc9abdd187470f825bcb0
6
+ metadata.gz: 7345453339664b2afd90a55695dfd02f075850c93ba6896193c9dccc7f8043da9762edfcf5131f9fe489dd0f6e1108cc2318f5bc2fc6e5363dd9c54cddba7b81
7
+ data.tar.gz: 0c556b84edd90bbfcd70132775acfb46c03f6bbcbb081d066d5e400e8e5f4ff60a01e059e5ad08b027eb3c58664449f5fc6bcd9450af417133c694eede138440
data/.rubocop.yml ADDED
@@ -0,0 +1 @@
1
+ inherit_from: .rubocop_todo.yml
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,15 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2015-02-25 04:34:33 -0800 using RuboCop version 0.28.0.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 1
9
+ Metrics/AbcSize:
10
+ Max: 16
11
+
12
+ # Offense count: 1
13
+ # Configuration parameters: CountComments.
14
+ Metrics/MethodLength:
15
+ Max: 11
data/.travis.yml CHANGED
@@ -6,7 +6,7 @@ rvm:
6
6
  - 1.9.3
7
7
  - rbx-2
8
8
  - jruby
9
- script: "bundle exec rake spec:all"
9
+ script: "bundle exec rake"
10
10
  before_install:
11
11
  - sudo apt-get update
12
12
  - sudo apt-get install idn
data/README.md CHANGED
@@ -36,8 +36,8 @@ $ gem install googleauth
36
36
  require 'googleauth'
37
37
 
38
38
  # Get the environment configured authorization
39
- scope = 'https://www.googleapis.com/auth/userinfo.profile'
40
- authorization = Google::Auth.get_application_default(scope)
39
+ scopes = ['https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/compute']
40
+ authorization = Google::Auth.get_application_default(scopes)
41
41
 
42
42
  # Add the the access token obtained using the authorization to a hash, e.g
43
43
  # headers.
data/googleauth.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.email = 'temiola@google.com'
11
11
  s.homepage = 'https://github.com/google/google-auth-library-ruby'
12
12
  s.summary = 'Google Auth Library for Ruby'
13
- s.license = "Apache-2.0"
13
+ s.license = 'Apache-2.0'
14
14
  s.description = <<-eos
15
15
  Allows simple authorization for accessing Google APIs.
16
16
  Provide support for Application Default Credentials, as described at
@@ -27,9 +27,9 @@ Gem::Specification.new do |s|
27
27
 
28
28
  s.add_dependency 'faraday', '~> 0.9'
29
29
  s.add_dependency 'logging', '~> 1.8'
30
- s.add_dependency 'jwt', '~> 1.2.1'
30
+ s.add_dependency 'jwt', '~> 1.3.0'
31
31
  s.add_dependency 'memoist', '~> 0.11.0'
32
- s.add_dependency 'multi_json', '1.10.1'
32
+ s.add_dependency 'multi_json', '1.11.0'
33
33
  s.add_dependency 'signet', '~> 0.6.0'
34
34
 
35
35
  s.add_development_dependency 'bundler', '~> 1.7'
data/lib/googleauth.rb CHANGED
@@ -27,8 +27,13 @@
27
27
  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
28
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
29
 
30
- require 'googleauth/service_account'
30
+ require 'multi_json'
31
+ require 'stringio'
32
+
33
+ require 'googleauth/credentials_loader'
31
34
  require 'googleauth/compute_engine'
35
+ require 'googleauth/service_account'
36
+ require 'googleauth/user_refresh'
32
37
 
33
38
  module Google
34
39
  # Module Auth provides classes that provide Google-specific authorization
@@ -40,6 +45,29 @@ https://developers.google.com/accounts/docs/application-default-credentials
40
45
  for more information
41
46
  END
42
47
 
48
+ # DefaultCredentials is used to preload the credentials file, to determine
49
+ # which type of credentials should be loaded.
50
+ class DefaultCredentials
51
+ extend CredentialsLoader
52
+
53
+ # override CredentialsLoader#make_creds to use the class determined by
54
+ # loading the json.
55
+ def self.make_creds(scope, json_key_io)
56
+ json_key, clz = determine_creds_class(json_key_io)
57
+ clz.new(scope, StringIO.new(MultiJson.dump(json_key)))
58
+ end
59
+
60
+ # Reads the input json and determines which creds class to use.
61
+ def self.determine_creds_class(json_key_io)
62
+ json_key = MultiJson.load(json_key_io.read)
63
+ fail "the json is missing the #{key} field" unless json_key.key?('type')
64
+ type = json_key['type']
65
+ return json_key, ServiceAccountCredentials if type == 'service_account'
66
+ return [json_key, UserRefreshCredentials] if type == 'authorized_user'
67
+ fail "credentials type '#{type}' is not supported"
68
+ end
69
+ end
70
+
43
71
  # Obtains the default credentials implementation to use in this
44
72
  # environment.
45
73
  #
@@ -53,9 +81,9 @@ END
53
81
  # @param scope [string|array] the scope(s) to access
54
82
  # @param options [hash] allows override of the connection being used
55
83
  def get_application_default(scope, options = {})
56
- creds = ServiceAccountCredentials.from_env(scope)
84
+ creds = DefaultCredentials.from_env(scope)
57
85
  return creds unless creds.nil?
58
- creds = ServiceAccountCredentials.from_well_known_path(scope)
86
+ creds = DefaultCredentials.from_well_known_path(scope)
59
87
  return creds unless creds.nil?
60
88
  fail NOT_FOUND_ERROR unless GCECredentials.on_gce?(options)
61
89
  GCECredentials.new
@@ -0,0 +1,93 @@
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
+ require 'memoist'
31
+ require 'rbconfig'
32
+
33
+ module Google
34
+ # Module Auth provides classes that provide Google-specific authorization
35
+ # used to access Google APIs.
36
+ module Auth
37
+ # CredentialsLoader contains the behaviour used to locate and find default
38
+ # credentials files on the file system.
39
+ module CredentialsLoader
40
+ extend Memoist
41
+ ENV_VAR = 'GOOGLE_APPLICATION_CREDENTIALS'
42
+ NOT_FOUND_ERROR =
43
+ "Unable to read the credential file specified by #{ENV_VAR}"
44
+ WELL_KNOWN_PATH = 'gcloud/application_default_credentials.json'
45
+ WELL_KNOWN_ERROR = 'Unable to read the default credential file'
46
+
47
+ # determines if the current OS is windows
48
+ def windows?
49
+ RbConfig::CONFIG['host_os'] =~ /Windows|mswin/
50
+ end
51
+ memoize :windows?
52
+
53
+ # make_creds proxies the construction of a credentials instance
54
+ #
55
+ # By default, it calls #new on the current class, but this behaviour can
56
+ # be modified, allowing different instances to be created.
57
+ def make_creds(*args)
58
+ new(*args)
59
+ end
60
+
61
+ # Creates an instance from the path specified in an environment
62
+ # variable.
63
+ #
64
+ # @param scope [string|array] the scope(s) to access
65
+ def from_env(scope)
66
+ return nil unless ENV.key?(ENV_VAR)
67
+ path = ENV[ENV_VAR]
68
+ fail 'file #{path} does not exist' unless File.exist?(path)
69
+ File.open(path) do |f|
70
+ return make_creds(scope, f)
71
+ end
72
+ rescue StandardError => e
73
+ raise "#{NOT_FOUND_ERROR}: #{e}"
74
+ end
75
+
76
+ # Creates an instance from a well known path.
77
+ #
78
+ # @param scope [string|array] the scope(s) to access
79
+ def from_well_known_path(scope)
80
+ home_var, base = windows? ? 'APPDATA' : 'HOME', WELL_KNOWN_PATH
81
+ root = ENV[home_var].nil? ? '' : ENV[home_var]
82
+ base = File.join('.config', base) unless windows?
83
+ path = File.join(root, base)
84
+ return nil unless File.exist?(path)
85
+ File.open(path) do |f|
86
+ return make_creds(scope, f)
87
+ end
88
+ rescue StandardError => e
89
+ raise "#{WELL_KNOWN_ERROR}: #{e}"
90
+ end
91
+ end
92
+ end
93
+ end
@@ -28,18 +28,8 @@
28
28
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
29
 
30
30
  require 'googleauth/signet'
31
- require 'memoist'
31
+ require 'googleauth/credentials_loader'
32
32
  require 'multi_json'
33
- require 'openssl'
34
- require 'rbconfig'
35
-
36
- # Reads the private key and client email fields from service account JSON key.
37
- def read_json_key(json_key_io)
38
- json_key = MultiJson.load(json_key_io.read)
39
- fail 'missing client_email' unless json_key.key?('client_email')
40
- fail 'missing private_key' unless json_key.key?('private_key')
41
- [json_key['private_key'], json_key['client_email']]
42
- end
43
33
 
44
34
  module Google
45
35
  # Module Auth provides classes that provide Google-specific authorization
@@ -53,52 +43,16 @@ module Google
53
43
  #
54
44
  # cf [Application Default Credentials](http://goo.gl/mkAHpZ)
55
45
  class ServiceAccountCredentials < Signet::OAuth2::Client
56
- ENV_VAR = 'GOOGLE_APPLICATION_CREDENTIALS'
57
- NOT_FOUND_ERROR =
58
- "Unable to read the credential file specified by #{ENV_VAR}"
59
46
  TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token'
60
- WELL_KNOWN_PATH = 'gcloud/application_default_credentials.json'
61
- WELL_KNOWN_ERROR = 'Unable to read the default credential file'
62
-
63
- class << self
64
- extend Memoist
65
-
66
- # determines if the current OS is windows
67
- def windows?
68
- RbConfig::CONFIG['host_os'] =~ /Windows|mswin/
69
- end
70
- memoize :windows?
71
-
72
- # Creates an instance from the path specified in an environment
73
- # variable.
74
- #
75
- # @param scope [string|array] the scope(s) to access
76
- def from_env(scope)
77
- return nil unless ENV.key?(ENV_VAR)
78
- path = ENV[ENV_VAR]
79
- fail 'file #{path} does not exist' unless File.exist?(path)
80
- File.open(path) do |f|
81
- return new(scope, f)
82
- end
83
- rescue StandardError => e
84
- raise "#{NOT_FOUND_ERROR}: #{e}"
85
- end
47
+ extend CredentialsLoader
86
48
 
87
- # Creates an instance from a well known path.
88
- #
89
- # @param scope [string|array] the scope(s) to access
90
- def from_well_known_path(scope)
91
- home_var, base = windows? ? 'APPDATA' : 'HOME', WELL_KNOWN_PATH
92
- root = ENV[home_var].nil? ? '' : ENV[home_var]
93
- base = File.join('.config', base) unless windows?
94
- path = File.join(root, base)
95
- return nil unless File.exist?(path)
96
- File.open(path) do |f|
97
- return new(scope, f)
98
- end
99
- rescue StandardError => e
100
- raise "#{WELL_KNOWN_ERROR}: #{e}"
101
- end
49
+ # Reads the private key and client email fields from the service account
50
+ # JSON key.
51
+ def self.read_json_key(json_key_io)
52
+ json_key = MultiJson.load(json_key_io.read)
53
+ fail 'missing client_email' unless json_key.key?('client_email')
54
+ fail 'missing private_key' unless json_key.key?('private_key')
55
+ [json_key['private_key'], json_key['client_email']]
102
56
  end
103
57
 
104
58
  # Initializes a ServiceAccountCredentials.
@@ -106,9 +60,9 @@ module Google
106
60
  # @param scope [string|array] the scope(s) to access
107
61
  # @param json_key_io [IO] an IO from which the JSON key can be read
108
62
  def initialize(scope, json_key_io)
109
- private_key, client_email = read_json_key(json_key_io)
63
+ private_key, client_email = self.class.read_json_key(json_key_io)
110
64
  super(token_credential_uri: TOKEN_CRED_URI,
111
- audience: TOKEN_CRED_URI, # TODO: confirm this
65
+ audience: TOKEN_CRED_URI,
112
66
  scope: scope,
113
67
  issuer: client_email,
114
68
  signing_key: OpenSSL::PKey::RSA.new(private_key))
@@ -0,0 +1,76 @@
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
+ require 'googleauth/signet'
31
+ require 'googleauth/credentials_loader'
32
+ require 'multi_json'
33
+
34
+ module Google
35
+ # Module Auth provides classes that provide Google-specific authorization
36
+ # used to access Google APIs.
37
+ module Auth
38
+ # Authenticates requests using User Refresh credentials.
39
+ #
40
+ # This class allows authorizing requests from user refresh tokens.
41
+ #
42
+ # This the end of the result of a 3LO flow. E.g, the end result of
43
+ # 'gcloud auth login' saves a file with these contents in well known
44
+ # location
45
+ #
46
+ # cf [Application Default Credentials](http://goo.gl/mkAHpZ)
47
+ class UserRefreshCredentials < Signet::OAuth2::Client
48
+ TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token'
49
+ extend CredentialsLoader
50
+
51
+ # Reads the client_id, client_secret and refresh_token fields from the
52
+ # JSON key.
53
+ def self.read_json_key(json_key_io)
54
+ json_key = MultiJson.load(json_key_io.read)
55
+ wanted = %w(client_id client_secret refresh_token)
56
+ wanted.each do |key|
57
+ fail "the json is missing the #{key} field" unless json_key.key?(key)
58
+ end
59
+ json_key
60
+ end
61
+
62
+ # Initializes a UserRefreshCredentials.
63
+ #
64
+ # @param scope [string|array] the scope(s) to access
65
+ # @param json_key_io [IO] an IO from which the JSON key can be read
66
+ def initialize(scope, json_key_io)
67
+ user_creds = self.class.read_json_key(json_key_io)
68
+ super(token_credential_uri: TOKEN_CRED_URI,
69
+ client_id: user_creds['client_id'],
70
+ client_secret: user_creds['client_secret'],
71
+ refresh_token: user_creds['refresh_token'],
72
+ scope: scope)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -31,6 +31,6 @@ module Google
31
31
  # Module Auth provides classes that provide Google-specific authorization
32
32
  # used to access Google APIs.
33
33
  module Auth
34
- VERSION = '0.1.0'
34
+ VERSION = '0.2.0'
35
35
  end
36
36
  end
@@ -44,7 +44,8 @@ describe Google::Auth::GCECredentials do
44
44
  @client = GCECredentials.new
45
45
  end
46
46
 
47
- def make_auth_stubs(access_token: '')
47
+ def make_auth_stubs(opts = {})
48
+ access_token = opts[:access_token] || ''
48
49
  Faraday::Adapter::Test::Stubs.new do |stub|
49
50
  stub.get(MD_URI) do |env|
50
51
  headers = env[:request_headers]
@@ -38,7 +38,7 @@ require 'spec_helper'
38
38
  describe '#get_application_default' do
39
39
  before(:example) do
40
40
  @key = OpenSSL::PKey::RSA.new(2048)
41
- @var_name = ServiceAccountCredentials::ENV_VAR
41
+ @var_name = CredentialsLoader::ENV_VAR
42
42
  @orig = ENV[@var_name]
43
43
  @home = ENV['HOME']
44
44
  @scope = 'https://www.googleapis.com/auth/userinfo.profile'
@@ -49,86 +49,152 @@ describe '#get_application_default' do
49
49
  ENV['HOME'] = @home unless @home == ENV['HOME']
50
50
  end
51
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
52
+ shared_examples 'it cannot load misconfigured credentials' do
53
+ it 'fails if the GOOGLE_APPLICATION_CREDENTIALS path does not exist' do
54
+ Dir.mktmpdir do |dir|
55
+ key_path = File.join(dir, 'does-not-exist')
56
+ ENV[@var_name] = key_path
57
+ expect { Google::Auth.get_application_default(@scope) }.to raise_error
58
+ end
59
+ end
62
60
 
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
61
+ it 'fails without default file or env if not on compute engine' do
62
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
63
+ stub.get('/') do |_env|
64
+ [404,
65
+ { 'Metadata-Flavor' => 'Google' },
66
+ '']
67
+ end
68
+ end # GCE not detected
69
+ Dir.mktmpdir do |dir|
70
+ ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var
71
+ ENV['HOME'] = dir # no config present in this tmp dir
72
+ c = Faraday.new do |b|
73
+ b.adapter(:test, stubs)
74
+ end
75
+ blk = proc do
76
+ Google::Auth.get_application_default(@scope, connection: c)
77
+ end
78
+ expect(&blk).to raise_error
79
+ end
80
+ stubs.verify_stubbed_calls
68
81
  end
69
82
  end
70
83
 
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
84
+ shared_examples 'it can successfully load credentials' do
85
+ it 'succeeds if the GOOGLE_APPLICATION_CREDENTIALS file is valid' do
86
+ Dir.mktmpdir do |dir|
87
+ key_path = File.join(dir, 'my_cert_file')
88
+ FileUtils.mkdir_p(File.dirname(key_path))
89
+ File.write(key_path, cred_json_text)
90
+ ENV[@var_name] = key_path
91
+ expect(Google::Auth.get_application_default(@scope)).to_not be_nil
92
+ end
93
+ end
94
+
95
+ it 'succeeds with default file without GOOGLE_APPLICATION_CREDENTIALS' do
96
+ ENV.delete(@var_name) unless ENV[@var_name].nil?
97
+ Dir.mktmpdir do |dir|
98
+ key_path = File.join(dir, '.config',
99
+ CredentialsLoader::WELL_KNOWN_PATH)
100
+ FileUtils.mkdir_p(File.dirname(key_path))
101
+ File.write(key_path, cred_json_text)
102
+ ENV['HOME'] = dir
103
+ expect(Google::Auth.get_application_default(@scope)).to_not be_nil
104
+ end
105
+ end
106
+
107
+ it 'succeeds without default file or env if on compute engine' do
108
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
109
+ stub.get('/') do |_env|
110
+ [200,
111
+ { 'Metadata-Flavor' => 'Google' },
112
+ '']
113
+ end
114
+ end # GCE detected
115
+ Dir.mktmpdir do |dir|
116
+ ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var
117
+ ENV['HOME'] = dir # no config present in this tmp dir
118
+ c = Faraday.new do |b|
119
+ b.adapter(:test, stubs)
120
+ end
121
+ creds = Google::Auth.get_application_default(
122
+ @scope,
123
+ connection: c)
124
+ expect(creds).to_not be_nil
125
+ end
126
+ stubs.verify_stubbed_calls
78
127
  end
79
128
  end
80
129
 
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
130
+ describe 'when credential type is service account' do
131
+ def cred_json_text
132
+ cred_json = {
133
+ private_key_id: 'a_private_key_id',
134
+ private_key: @key.to_pem,
135
+ client_email: 'app@developer.gserviceaccount.com',
136
+ client_id: 'app.apps.googleusercontent.com',
137
+ type: 'service_account'
138
+ }
139
+ MultiJson.dump(cred_json)
90
140
  end
141
+
142
+ it_behaves_like 'it can successfully load credentials'
143
+ it_behaves_like 'it cannot load misconfigured credentials'
91
144
  end
92
145
 
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
146
+ describe 'when credential type is authorized_user' do
147
+ def cred_json_text
148
+ cred_json = {
149
+ client_secret: 'privatekey',
150
+ refresh_token: 'refreshtoken',
151
+ client_id: 'app.apps.googleusercontent.com',
152
+ type: 'authorized_user'
153
+ }
154
+ MultiJson.dump(cred_json)
111
155
  end
112
- stubs.verify_stubbed_calls
156
+
157
+ it_behaves_like 'it can successfully load credentials'
158
+ it_behaves_like 'it cannot load misconfigured credentials'
113
159
  end
114
160
 
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
- '']
161
+ describe 'when credential type is unknown' do
162
+ def cred_json_text
163
+ cred_json = {
164
+ client_secret: 'privatekey',
165
+ refresh_token: 'refreshtoken',
166
+ client_id: 'app.apps.googleusercontent.com',
167
+ type: 'not_known_type'
168
+ }
169
+ MultiJson.dump(cred_json)
170
+ end
171
+
172
+ it 'fails if the GOOGLE_APPLICATION_CREDENTIALS file contains the creds' do
173
+ Dir.mktmpdir do |dir|
174
+ key_path = File.join(dir, 'my_cert_file')
175
+ FileUtils.mkdir_p(File.dirname(key_path))
176
+ File.write(key_path, cred_json_text)
177
+ ENV[@var_name] = key_path
178
+ blk = proc do
179
+ Google::Auth.get_application_default(@scope)
180
+ end
181
+ expect(&blk).to raise_error RuntimeError
121
182
  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)
183
+ end
184
+
185
+ it 'fails if the well known file contains the creds' do
186
+ ENV.delete(@var_name) unless ENV[@var_name].nil?
187
+ Dir.mktmpdir do |dir|
188
+ key_path = File.join(dir, '.config',
189
+ CredentialsLoader::WELL_KNOWN_PATH)
190
+ FileUtils.mkdir_p(File.dirname(key_path))
191
+ File.write(key_path, cred_json_text)
192
+ ENV['HOME'] = dir
193
+ blk = proc do
194
+ Google::Auth.get_application_default(@scope)
195
+ end
196
+ expect(&blk).to raise_error RuntimeError
128
197
  end
129
- expect(Google::Auth.get_application_default(@scope,
130
- connection: c)).to_not be_nil
131
198
  end
132
- stubs.verify_stubbed_calls
133
199
  end
134
200
  end
@@ -42,6 +42,7 @@ require 'tmpdir'
42
42
 
43
43
  describe Google::Auth::ServiceAccountCredentials do
44
44
  ServiceAccountCredentials = Google::Auth::ServiceAccountCredentials
45
+ CredentialsLoader = Google::Auth::CredentialsLoader
45
46
 
46
47
  before(:example) do
47
48
  @key = OpenSSL::PKey::RSA.new(2048)
@@ -50,7 +51,8 @@ describe Google::Auth::ServiceAccountCredentials do
50
51
  StringIO.new(cred_json_text))
51
52
  end
52
53
 
53
- def make_auth_stubs(access_token: '')
54
+ def make_auth_stubs(opts = {})
55
+ access_token = opts[:access_token] || ''
54
56
  Faraday::Adapter::Test::Stubs.new do |stub|
55
57
  stub.post('/oauth2/v3/token') do |env|
56
58
  params = Addressable::URI.form_unencode(env[:body])
@@ -78,9 +80,10 @@ describe Google::Auth::ServiceAccountCredentials do
78
80
 
79
81
  describe '#from_env' do
80
82
  before(:example) do
81
- @var_name = ServiceAccountCredentials::ENV_VAR
83
+ @var_name = CredentialsLoader::ENV_VAR
82
84
  @orig = ENV[@var_name]
83
85
  @scope = 'https://www.googleapis.com/auth/userinfo.profile'
86
+ @clz = ServiceAccountCredentials
84
87
  end
85
88
 
86
89
  after(:example) do
@@ -98,18 +101,17 @@ describe Google::Auth::ServiceAccountCredentials do
98
101
  Dir.mktmpdir do |dir|
99
102
  key_path = File.join(dir, 'does-not-exist')
100
103
  ENV[@var_name] = key_path
101
- expect { sac.from_env(@scope) }.to raise_error
104
+ expect { @clz.from_env(@scope) }.to raise_error
102
105
  end
103
106
  end
104
107
 
105
108
  it 'succeeds when the GOOGLE_APPLICATION_CREDENTIALS file is valid' do
106
- sac = ServiceAccountCredentials # shortens name
107
109
  Dir.mktmpdir do |dir|
108
110
  key_path = File.join(dir, 'my_cert_file')
109
111
  FileUtils.mkdir_p(File.dirname(key_path))
110
112
  File.write(key_path, cred_json_text)
111
113
  ENV[@var_name] = key_path
112
- expect(sac.from_env(@scope)).to_not be_nil
114
+ expect(@clz.from_env(@scope)).to_not be_nil
113
115
  end
114
116
  end
115
117
  end
@@ -118,6 +120,8 @@ describe Google::Auth::ServiceAccountCredentials do
118
120
  before(:example) do
119
121
  @home = ENV['HOME']
120
122
  @scope = 'https://www.googleapis.com/auth/userinfo.profile'
123
+ @known_path = CredentialsLoader::WELL_KNOWN_PATH
124
+ @clz = ServiceAccountCredentials
121
125
  end
122
126
 
123
127
  after(:example) do
@@ -130,13 +134,12 @@ describe Google::Auth::ServiceAccountCredentials do
130
134
  end
131
135
 
132
136
  it 'successfully loads the file when it is present' do
133
- sac = ServiceAccountCredentials # shortens name
134
137
  Dir.mktmpdir do |dir|
135
- key_path = File.join(dir, '.config', sac::WELL_KNOWN_PATH)
138
+ key_path = File.join(dir, '.config', @known_path)
136
139
  FileUtils.mkdir_p(File.dirname(key_path))
137
140
  File.write(key_path, cred_json_text)
138
141
  ENV['HOME'] = dir
139
- expect(sac.from_well_known_path(@scope)).to_not be_nil
142
+ expect(@clz.from_well_known_path(@scope)).to_not be_nil
140
143
  end
141
144
  end
142
145
  end
@@ -49,7 +49,8 @@ describe Signet::OAuth2::Client do
49
49
  )
50
50
  end
51
51
 
52
- def make_auth_stubs(access_token: '')
52
+ def make_auth_stubs(opts)
53
+ access_token = opts[:access_token] || ''
53
54
  Faraday::Adapter::Test::Stubs.new do |stub|
54
55
  stub.post('/o/oauth2/token') do |env|
55
56
  params = Addressable::URI.form_unencode(env[:body])
@@ -0,0 +1,170 @@
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/user_refresh'
37
+ require 'jwt'
38
+ require 'multi_json'
39
+ require 'openssl'
40
+ require 'spec_helper'
41
+ require 'tmpdir'
42
+
43
+ describe Google::Auth::UserRefreshCredentials do
44
+ UserRefreshCredentials = Google::Auth::UserRefreshCredentials
45
+ CredentialsLoader = Google::Auth::CredentialsLoader
46
+
47
+ before(:example) do
48
+ @key = OpenSSL::PKey::RSA.new(2048)
49
+ @client = UserRefreshCredentials.new(
50
+ 'https://www.googleapis.com/auth/userinfo.profile',
51
+ StringIO.new(cred_json_text))
52
+ end
53
+
54
+ def make_auth_stubs(opts = {})
55
+ access_token = opts[:access_token] || ''
56
+ Faraday::Adapter::Test::Stubs.new do |stub|
57
+ stub.post('/oauth2/v3/token') do |env|
58
+ params = Addressable::URI.form_unencode(env[:body])
59
+ want = %w(grant_type refresh_token)
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(missing = nil)
67
+ cred_json = {
68
+ client_secret: 'privatekey',
69
+ client_id: 'client123',
70
+ refresh_token: 'refreshtoken',
71
+ type: 'authorized_user'
72
+ }
73
+ cred_json.delete(missing.to_sym) unless missing.nil?
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 = CredentialsLoader::ENV_VAR
82
+ @orig = ENV[@var_name]
83
+ @scope = 'https://www.googleapis.com/auth/userinfo.profile'
84
+ @clz = UserRefreshCredentials
85
+ end
86
+
87
+ after(:example) do
88
+ ENV[@var_name] = @orig unless @orig.nil?
89
+ end
90
+
91
+ it 'returns nil if the GOOGLE_APPLICATION_CREDENTIALS is unset' do
92
+ ENV.delete(@var_name) unless ENV[@var_name].nil?
93
+ expect(UserRefreshCredentials.from_env(@scope)).to be_nil
94
+ end
95
+
96
+ it 'fails if the GOOGLE_APPLICATION_CREDENTIALS path does not exist' do
97
+ ENV.delete(@var_name) unless ENV[@var_name].nil?
98
+ expect(UserRefreshCredentials.from_env(@scope)).to be_nil
99
+ Dir.mktmpdir do |dir|
100
+ key_path = File.join(dir, 'does-not-exist')
101
+ ENV[@var_name] = key_path
102
+ expect { @clz.from_env(@scope) }.to raise_error
103
+ end
104
+ end
105
+
106
+ it 'fails if the GOOGLE_APPLICATION_CREDENTIALS path file is invalid' do
107
+ needed = %w(client_id client_secret refresh_token)
108
+ needed.each do |missing|
109
+ Dir.mktmpdir do |dir|
110
+ key_path = File.join(dir, 'my_cert_file')
111
+ FileUtils.mkdir_p(File.dirname(key_path))
112
+ File.write(key_path, cred_json_text(missing))
113
+ ENV[@var_name] = key_path
114
+ expect { @clz.from_env(@scope) }.to raise_error
115
+ end
116
+ end
117
+ end
118
+
119
+ it 'succeeds when the GOOGLE_APPLICATION_CREDENTIALS file is valid' do
120
+ Dir.mktmpdir do |dir|
121
+ key_path = File.join(dir, 'my_cert_file')
122
+ FileUtils.mkdir_p(File.dirname(key_path))
123
+ File.write(key_path, cred_json_text)
124
+ ENV[@var_name] = key_path
125
+ expect(@clz.from_env(@scope)).to_not be_nil
126
+ end
127
+ end
128
+ end
129
+
130
+ describe '#from_well_known_path' do
131
+ before(:example) do
132
+ @home = ENV['HOME']
133
+ @scope = 'https://www.googleapis.com/auth/userinfo.profile'
134
+ @known_path = CredentialsLoader::WELL_KNOWN_PATH
135
+ @clz = UserRefreshCredentials
136
+ end
137
+
138
+ after(:example) do
139
+ ENV['HOME'] = @home unless @home == ENV['HOME']
140
+ end
141
+
142
+ it 'is nil if no file exists' do
143
+ ENV['HOME'] = File.dirname(__FILE__)
144
+ expect(UserRefreshCredentials.from_well_known_path(@scope)).to be_nil
145
+ end
146
+
147
+ it 'fails if the file is invalid' do
148
+ needed = %w(client_id client_secret refresh_token)
149
+ needed.each do |missing|
150
+ Dir.mktmpdir do |dir|
151
+ key_path = File.join(dir, '.config', @known_path)
152
+ FileUtils.mkdir_p(File.dirname(key_path))
153
+ File.write(key_path, cred_json_text(missing))
154
+ ENV['HOME'] = dir
155
+ expect { @clz.from_env(@scope) }.to raise_error
156
+ end
157
+ end
158
+ end
159
+
160
+ it 'successfully loads the file when it is present' do
161
+ Dir.mktmpdir do |dir|
162
+ key_path = File.join(dir, '.config', @known_path)
163
+ FileUtils.mkdir_p(File.dirname(key_path))
164
+ File.write(key_path, cred_json_text)
165
+ ENV['HOME'] = dir
166
+ expect(@clz.from_well_known_path(@scope)).to_not be_nil
167
+ end
168
+ end
169
+ end
170
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: googleauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Emiola
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-25 00:00:00.000000000 Z
11
+ date: 2015-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.2.1
47
+ version: 1.3.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.2.1
54
+ version: 1.3.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: memoist
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 1.10.1
75
+ version: 1.11.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 1.10.1
82
+ version: 1.11.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: signet
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -161,6 +161,8 @@ extra_rdoc_files: []
161
161
  files:
162
162
  - ".gitignore"
163
163
  - ".rspec"
164
+ - ".rubocop.yml"
165
+ - ".rubocop_todo.yml"
164
166
  - ".travis.yml"
165
167
  - CONTRIBUTING.md
166
168
  - COPYING
@@ -170,14 +172,17 @@ files:
170
172
  - googleauth.gemspec
171
173
  - lib/googleauth.rb
172
174
  - lib/googleauth/compute_engine.rb
175
+ - lib/googleauth/credentials_loader.rb
173
176
  - lib/googleauth/service_account.rb
174
177
  - lib/googleauth/signet.rb
178
+ - lib/googleauth/user_refresh.rb
175
179
  - lib/googleauth/version.rb
176
180
  - spec/googleauth/apply_auth_examples.rb
177
181
  - spec/googleauth/compute_engine_spec.rb
178
182
  - spec/googleauth/get_application_default_spec.rb
179
183
  - spec/googleauth/service_account_spec.rb
180
184
  - spec/googleauth/signet_spec.rb
185
+ - spec/googleauth/user_refresh_spec.rb
181
186
  - spec/spec_helper.rb
182
187
  homepage: https://github.com/google/google-auth-library-ruby
183
188
  licenses:
@@ -209,4 +214,5 @@ test_files:
209
214
  - spec/googleauth/get_application_default_spec.rb
210
215
  - spec/googleauth/service_account_spec.rb
211
216
  - spec/googleauth/signet_spec.rb
217
+ - spec/googleauth/user_refresh_spec.rb
212
218
  - spec/spec_helper.rb