jomz-google-api-client 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
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