jomz-google-api-client 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. data/CHANGELOG.md +144 -0
  2. data/CONTRIBUTING.md +32 -0
  3. data/Gemfile +41 -0
  4. data/LICENSE +202 -0
  5. data/README.md +192 -0
  6. data/Rakefile +46 -0
  7. data/lib/cacerts.pem +2183 -0
  8. data/lib/compat/multi_json.rb +16 -0
  9. data/lib/google/api_client.rb +672 -0
  10. data/lib/google/api_client/auth/compute_service_account.rb +28 -0
  11. data/lib/google/api_client/auth/file_storage.rb +87 -0
  12. data/lib/google/api_client/auth/installed_app.rb +122 -0
  13. data/lib/google/api_client/auth/jwt_asserter.rb +126 -0
  14. data/lib/google/api_client/auth/key_utils.rb +93 -0
  15. data/lib/google/api_client/auth/pkcs12.rb +41 -0
  16. data/lib/google/api_client/batch.rb +323 -0
  17. data/lib/google/api_client/client_secrets.rb +176 -0
  18. data/lib/google/api_client/discovery.rb +19 -0
  19. data/lib/google/api_client/discovery/api.rb +300 -0
  20. data/lib/google/api_client/discovery/media.rb +77 -0
  21. data/lib/google/api_client/discovery/method.rb +363 -0
  22. data/lib/google/api_client/discovery/resource.rb +156 -0
  23. data/lib/google/api_client/discovery/schema.rb +121 -0
  24. data/lib/google/api_client/environment.rb +42 -0
  25. data/lib/google/api_client/errors.rb +60 -0
  26. data/lib/google/api_client/gzip.rb +28 -0
  27. data/lib/google/api_client/logging.rb +32 -0
  28. data/lib/google/api_client/media.rb +259 -0
  29. data/lib/google/api_client/railtie.rb +16 -0
  30. data/lib/google/api_client/reference.rb +27 -0
  31. data/lib/google/api_client/request.rb +351 -0
  32. data/lib/google/api_client/result.rb +253 -0
  33. data/lib/google/api_client/service.rb +233 -0
  34. data/lib/google/api_client/service/batch.rb +103 -0
  35. data/lib/google/api_client/service/request.rb +144 -0
  36. data/lib/google/api_client/service/resource.rb +40 -0
  37. data/lib/google/api_client/service/result.rb +162 -0
  38. data/lib/google/api_client/service/simple_file_store.rb +151 -0
  39. data/lib/google/api_client/service/stub_generator.rb +59 -0
  40. data/lib/google/api_client/service_account.rb +18 -0
  41. data/lib/google/api_client/version.rb +31 -0
  42. data/lib/google/inflection.rb +28 -0
  43. data/spec/fixtures/files/privatekey.p12 +0 -0
  44. data/spec/fixtures/files/sample.txt +33 -0
  45. data/spec/fixtures/files/secret.pem +19 -0
  46. data/spec/google/api_client/batch_spec.rb +249 -0
  47. data/spec/google/api_client/discovery_spec.rb +652 -0
  48. data/spec/google/api_client/gzip_spec.rb +86 -0
  49. data/spec/google/api_client/media_spec.rb +179 -0
  50. data/spec/google/api_client/request_spec.rb +30 -0
  51. data/spec/google/api_client/result_spec.rb +203 -0
  52. data/spec/google/api_client/service_account_spec.rb +164 -0
  53. data/spec/google/api_client/service_spec.rb +586 -0
  54. data/spec/google/api_client/simple_file_store_spec.rb +137 -0
  55. data/spec/google/api_client_spec.rb +253 -0
  56. data/spec/spec_helper.rb +56 -0
  57. data/tasks/gem.rake +97 -0
  58. data/tasks/git.rake +45 -0
  59. data/tasks/metrics.rake +22 -0
  60. data/tasks/spec.rake +57 -0
  61. data/tasks/wiki.rake +82 -0
  62. data/tasks/yard.rake +29 -0
  63. metadata +309 -0
@@ -0,0 +1,28 @@
1
+ # Copyright 2013 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'faraday'
16
+ require 'signet/oauth_2/client'
17
+
18
+ module Google
19
+ class APIClient
20
+ class ComputeServiceAccount < Signet::OAuth2::Client
21
+ def fetch_access_token(options={})
22
+ connection = options[:connection] || Faraday.default_connection
23
+ response = connection.get 'http://metadata/computeMetadata/v1beta1/instance/service-accounts/default/token'
24
+ Signet::OAuth2.parse_json_credentials(response.body)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,87 @@
1
+ # Copyright 2013 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'json'
16
+ require 'signet/oauth_2/client'
17
+
18
+ module Google
19
+ class APIClient
20
+ ##
21
+ # Represents cached OAuth 2 tokens stored on local disk in a
22
+ # JSON serialized file. Meant to resemble the serialized format
23
+ # http://google-api-python-client.googlecode.com/hg/docs/epy/oauth2client.file.Storage-class.html
24
+ #
25
+ class FileStorage
26
+ # @return [String] Path to the credentials file.
27
+ attr_accessor :path
28
+
29
+ # @return [Signet::OAuth2::Client] Path to the credentials file.
30
+ attr_reader :authorization
31
+
32
+ ##
33
+ # Initializes the FileStorage object.
34
+ #
35
+ # @param [String] path
36
+ # Path to the credentials file.
37
+ def initialize(path)
38
+ @path = path
39
+ self.load_credentials
40
+ end
41
+
42
+ ##
43
+ # Attempt to read in credentials from the specified file.
44
+ def load_credentials
45
+ if File.exist? self.path
46
+ File.open(self.path, 'r') do |file|
47
+ cached_credentials = JSON.load(file)
48
+ @authorization = Signet::OAuth2::Client.new(cached_credentials)
49
+ @authorization.issued_at = Time.at(cached_credentials['issued_at'])
50
+ if @authorization.expired?
51
+ @authorization.fetch_access_token!
52
+ self.write_credentials
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ ##
59
+ # Write the credentials to the specified file.
60
+ #
61
+ # @param [Signet::OAuth2::Client] authorization
62
+ # Optional authorization instance. If not provided, the authorization
63
+ # already associated with this instance will be written.
64
+ def write_credentials(authorization=nil)
65
+ @authorization = authorization unless authorization.nil?
66
+
67
+ unless @authorization.refresh_token.nil?
68
+ hash = {}
69
+ %w'access_token
70
+ authorization_uri
71
+ client_id
72
+ client_secret
73
+ expires_in
74
+ refresh_token
75
+ token_credential_uri'.each do |var|
76
+ hash[var] = @authorization.instance_variable_get("@#{var}")
77
+ end
78
+ hash['issued_at'] = @authorization.issued_at.to_i
79
+
80
+ File.open(self.path, 'w', 0600) do |file|
81
+ file.write(hash.to_json)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,122 @@
1
+ # Copyright 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'webrick'
16
+ require 'launchy'
17
+
18
+ module Google
19
+ class APIClient
20
+
21
+ # Small helper for the sample apps for performing OAuth 2.0 flows from the command
22
+ # line or in any other installed app environment.
23
+ #
24
+ # @example
25
+ #
26
+ # client = Google::APIClient.new
27
+ # flow = Google::APIClient::InstalledAppFlow.new(
28
+ # :client_id => '691380668085.apps.googleusercontent.com',
29
+ # :client_secret => '...,
30
+ # :scope => 'https://www.googleapis.com/auth/drive'
31
+ # )
32
+ # client.authorization = flow.authorize
33
+ #
34
+ class InstalledAppFlow
35
+
36
+ RESPONSE_BODY = <<-HTML
37
+ <html>
38
+ <head>
39
+ <script>
40
+ function closeWindow() {
41
+ window.open('', '_self', '');
42
+ window.close();
43
+ }
44
+ setTimeout(closeWindow, 10);
45
+ </script>
46
+ </head>
47
+ <body>You may close this window.</body>
48
+ </html>
49
+ HTML
50
+
51
+ ##
52
+ # Configure the flow
53
+ #
54
+ # @param [Hash] options The configuration parameters for the client.
55
+ # @option options [Fixnum] :port
56
+ # Port to run the embedded server on. Defaults to 9292
57
+ # @option options [String] :client_id
58
+ # A unique identifier issued to the client to identify itself to the
59
+ # authorization server.
60
+ # @option options [String] :client_secret
61
+ # A shared symmetric secret issued by the authorization server,
62
+ # which is used to authenticate the client.
63
+ # @option options [String] :scope
64
+ # The scope of the access request, expressed either as an Array
65
+ # or as a space-delimited String.
66
+ #
67
+ # @see Signet::OAuth2::Client
68
+ def initialize(options)
69
+ @port = options[:port] || 9292
70
+ @authorization = Signet::OAuth2::Client.new({
71
+ :authorization_uri => 'https://accounts.google.com/o/oauth2/auth',
72
+ :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
73
+ :redirect_uri => "http://localhost:#{@port}/"}.update(options)
74
+ )
75
+ end
76
+
77
+ ##
78
+ # Request authorization. Opens a browser and waits for response.
79
+ #
80
+ # @param [Google::APIClient::FileStorage] storage
81
+ # Optional object that responds to :write_credentials, used to serialize
82
+ # the OAuth 2 credentials after completing the flow.
83
+ #
84
+ # @return [Signet::OAuth2::Client]
85
+ # Authorization instance, nil if user cancelled.
86
+ def authorize(storage=nil)
87
+ auth = @authorization
88
+
89
+ server = WEBrick::HTTPServer.new(
90
+ :Port => @port,
91
+ :BindAddress =>"localhost",
92
+ :Logger => WEBrick::Log.new(STDOUT, 0),
93
+ :AccessLog => []
94
+ )
95
+ trap("INT") { server.shutdown }
96
+
97
+ server.mount_proc '/' do |req, res|
98
+ auth.code = req.query['code']
99
+ if auth.code
100
+ auth.fetch_access_token!
101
+ end
102
+ res.status = WEBrick::HTTPStatus::RC_ACCEPTED
103
+ res.body = RESPONSE_BODY
104
+ server.stop
105
+ end
106
+
107
+ Launchy.open(auth.authorization_uri.to_s)
108
+ server.start
109
+ if @authorization.access_token
110
+ if storage.respond_to?(:write_credentials)
111
+ storage.write_credentials(@authorization)
112
+ end
113
+ return @authorization
114
+ else
115
+ return nil
116
+ end
117
+ end
118
+ end
119
+
120
+ end
121
+ end
122
+
@@ -0,0 +1,126 @@
1
+ # Copyright 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'jwt'
16
+ require 'signet/oauth_2/client'
17
+ require 'delegate'
18
+
19
+ module Google
20
+ class APIClient
21
+ ##
22
+ # Generates access tokens using the JWT assertion profile. Requires a
23
+ # service account & access to the private key.
24
+ #
25
+ # @example Using Signet
26
+ #
27
+ # key = Google::APIClient::KeyUtils.load_from_pkcs12('client.p12', 'notasecret')
28
+ # client.authorization = Signet::OAuth2::Client.new(
29
+ # :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
30
+ # :audience => 'https://accounts.google.com/o/oauth2/token',
31
+ # :scope => 'https://www.googleapis.com/auth/prediction',
32
+ # :issuer => '123456-abcdef@developer.gserviceaccount.com',
33
+ # :signing_key => key)
34
+ # client.authorization.fetch_access_token!
35
+ # client.execute(...)
36
+ #
37
+ # @deprecated
38
+ # Service accounts are now supported directly in Signet
39
+ # @see https://developers.google.com/accounts/docs/OAuth2ServiceAccount
40
+ class JWTAsserter
41
+ # @return [String] ID/email of the issuing party
42
+ attr_accessor :issuer
43
+ # @return [Fixnum] How long, in seconds, the assertion is valid for
44
+ attr_accessor :expiry
45
+ # @return [Fixnum] Seconds to expand the issued at/expiry window to account for clock skew
46
+ attr_accessor :skew
47
+ # @return [String] Scopes to authorize
48
+ attr_reader :scope
49
+ # @return [String,OpenSSL::PKey] key for signing assertions
50
+ attr_writer :key
51
+ # @return [String] Algorithm used for signing
52
+ attr_accessor :algorithm
53
+
54
+ ##
55
+ # Initializes the asserter for a service account.
56
+ #
57
+ # @param [String] issuer
58
+ # Name/ID of the client issuing the assertion
59
+ # @param [String, Array] scope
60
+ # Scopes to authorize. May be a space delimited string or array of strings
61
+ # @param [String,OpenSSL::PKey] key
62
+ # Key for signing assertions
63
+ # @param [String] algorithm
64
+ # Algorithm to use, either 'RS256' for RSA with SHA-256
65
+ # or 'HS256' for HMAC with SHA-256
66
+ def initialize(issuer, scope, key, algorithm = "RS256")
67
+ self.issuer = issuer
68
+ self.scope = scope
69
+ self.expiry = 60 # 1 min default
70
+ self.skew = 60
71
+ self.key = key
72
+ self.algorithm = algorithm
73
+ end
74
+
75
+ ##
76
+ # Set the scopes to authorize
77
+ #
78
+ # @param [String, Array] new_scope
79
+ # Scopes to authorize. May be a space delimited string or array of strings
80
+ def scope=(new_scope)
81
+ case new_scope
82
+ when Array
83
+ @scope = new_scope.join(' ')
84
+ when String
85
+ @scope = new_scope
86
+ when nil
87
+ @scope = ''
88
+ else
89
+ raise TypeError, "Expected Array or String, got #{new_scope.class}"
90
+ end
91
+ end
92
+
93
+ ##
94
+ # Request a new access token.
95
+ #
96
+ # @param [String] person
97
+ # Email address of a user, if requesting a token to act on their behalf
98
+ # @param [Hash] options
99
+ # Pass through to Signet::OAuth2::Client.fetch_access_token
100
+ # @return [Signet::OAuth2::Client] Access token
101
+ #
102
+ # @see Signet::OAuth2::Client.fetch_access_token!
103
+ def authorize(person = nil, options={})
104
+ authorization = self.to_authorization(person)
105
+ authorization.fetch_access_token!(options)
106
+ return authorization
107
+ end
108
+
109
+ ##
110
+ # Builds a Signet OAuth2 client
111
+ #
112
+ # @return [Signet::OAuth2::Client] Access token
113
+ def to_authorization(person = nil)
114
+ return Signet::OAuth2::Client.new(
115
+ :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
116
+ :audience => 'https://accounts.google.com/o/oauth2/token',
117
+ :scope => self.scope,
118
+ :issuer => @issuer,
119
+ :signing_key => @key,
120
+ :signing_algorithm => @algorithm,
121
+ :person => person
122
+ )
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,93 @@
1
+ # Copyright 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Google
16
+ class APIClient
17
+ ##
18
+ # Helper for loading keys from the PKCS12 files downloaded when
19
+ # setting up service accounts at the APIs Console.
20
+ #
21
+ module KeyUtils
22
+ ##
23
+ # Loads a key from PKCS12 file, assuming a single private key
24
+ # is present.
25
+ #
26
+ # @param [String] keyfile
27
+ # Path of the PKCS12 file to load. If not a path to an actual file,
28
+ # assumes the string is the content of the file itself.
29
+ # @param [String] passphrase
30
+ # Passphrase for unlocking the private key
31
+ #
32
+ # @return [OpenSSL::PKey] The private key for signing assertions.
33
+ def self.load_from_pkcs12(keyfile, passphrase)
34
+ load_key(keyfile, passphrase) do |content, passphrase|
35
+ OpenSSL::PKCS12.new(content, passphrase).key
36
+ end
37
+ end
38
+
39
+
40
+ ##
41
+ # Loads a key from a PEM file.
42
+ #
43
+ # @param [String] keyfile
44
+ # Path of the PEM file to load. If not a path to an actual file,
45
+ # assumes the string is the content of the file itself.
46
+ # @param [String] passphrase
47
+ # Passphrase for unlocking the private key
48
+ #
49
+ # @return [OpenSSL::PKey] The private key for signing assertions.
50
+ #
51
+ def self.load_from_pem(keyfile, passphrase)
52
+ load_key(keyfile, passphrase) do | content, passphrase|
53
+ OpenSSL::PKey::RSA.new(content, passphrase)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ ##
60
+ # Helper for loading keys from file or memory. Accepts a block
61
+ # to handle the specific file format.
62
+ #
63
+ # @param [String] keyfile
64
+ # Path of thefile to load. If not a path to an actual file,
65
+ # assumes the string is the content of the file itself.
66
+ # @param [String] passphrase
67
+ # Passphrase for unlocking the private key
68
+ #
69
+ # @yield [String, String]
70
+ # Key file & passphrase to extract key from
71
+ # @yieldparam [String] keyfile
72
+ # Contents of the file
73
+ # @yieldparam [String] passphrase
74
+ # Passphrase to unlock key
75
+ # @yieldreturn [OpenSSL::PKey]
76
+ # Private key
77
+ #
78
+ # @return [OpenSSL::PKey] The private key for signing assertions.
79
+ def self.load_key(keyfile, passphrase, &block)
80
+ begin
81
+ begin
82
+ content = File.open(keyfile, 'rb') { |io| io.read }
83
+ rescue
84
+ content = keyfile
85
+ end
86
+ block.call(content, passphrase)
87
+ rescue OpenSSL::OpenSSLError
88
+ raise ArgumentError.new("Invalid keyfile or passphrase")
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end