google-id-tokenz 1.2.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 (4) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +46 -0
  3. data/lib/google-id-token.rb +164 -0
  4. metadata +130 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4c8d036fbff7aa58d162239a1c377dcecee06f74
4
+ data.tar.gz: 652a2c203876170dc81485608259a8bf3f4aa03c
5
+ SHA512:
6
+ metadata.gz: 65584666085ec799e249f2d1bed0cde6507c4fefeafbe65ed64e8ba21623af3bdee873b98b7fff19bb14b09d95a8bbfd6be04690f4e7281e7372ce2046f3b912
7
+ data.tar.gz: ec89ae8d5cd861e3ce9037748c0f4ae76557813074336634667696fe3f729202d4b4920472b6001e4fe550ffedd0a89d86577fc9c2fe1c6eb89166ad5734468a
data/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # GoogleIDToken
2
+
3
+ This code is from [@timbray](https://github.com/timbray)'s awesome [google-id-token](https://code.google.com/p/google-id-token/) codebase, with one minor tweak to handle a new token format (array vs hash).
4
+
5
+ Tim gives a great overview of id tokens here http://www.tbray.org/ongoing/When/201x/2013/04/04/ID-Tokens.
6
+
7
+ GoogleIDToken currently provides a single useful class "Validator", which provides a single method "#check", which parses and validates an ID Token allegedly generated by Google auth servers.
8
+
9
+ ## Examples
10
+
11
+ [android](http://android-developers.blogspot.in/2013/01/verifying-back-end-calls-from-android.html)
12
+
13
+ [android cross client auth](https://developers.google.com/accounts/docs/CrossClientAuth)
14
+
15
+ Creating a new validator takes a single optional hash argument. If the hash has an entry for :x509_key, that value is taken to be a key as created by OpenSSL::X509::Certificate.new, and the token is validated using that key. If there is no such entry, the keys are fetched from the Google certs endpoint https://www.googleapis.com/oauth2/v1/certs.
16
+
17
+ ## Installation
18
+
19
+ ```
20
+ gem install google-id-token
21
+ ```
22
+
23
+ ## Examples
24
+
25
+ ```
26
+ validator = GoogleIDToken::Validator.new
27
+ jwt = validator.check(token, required_audience, required_client_id)
28
+ if jwt
29
+ email = jwt['email']
30
+ else
31
+ report "Cannot validate: #{validator.problem}"
32
+ end
33
+ ```
34
+
35
+
36
+ ```
37
+ cert = OpenSSL::X509::Certificate.new(File.read('my-cert.pem'))
38
+ validator = GoogleIDToken::Validator.new(:x509_cert => cert)
39
+ jwt = validator.check(token, required_audience, required_client_id)
40
+ if jwt
41
+ email = jwt['email']
42
+ else
43
+ report "Cannot validate: #{validator.problem}"
44
+ end
45
+ ```
46
+
@@ -0,0 +1,164 @@
1
+ # encoding: utf-8
2
+ # Copyright 2012 Google Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ ##
17
+ # Validates strings alleged to be ID Tokens issued by Google; if validation
18
+ # succeeds, returns the decoded ID Token as a hash.
19
+ # It's a good idea to keep an instance of this class around for a long time,
20
+ # because it caches the keys, performs validation statically, and only
21
+ # refreshes from Google when required (typically once per day)
22
+ #
23
+ # @author Tim Bray, adapted from code by Bob Aman
24
+
25
+ require 'multi_json'
26
+ require 'jwt'
27
+ require 'openssl'
28
+ require 'net/http'
29
+
30
+ module GoogleIDToken
31
+ class Validator
32
+
33
+ GOOGLE_CERTS_URI = 'https://www.googleapis.com/oauth2/v1/certs'
34
+
35
+ # @!attribute [r] problem
36
+ # Reason for failure, if #check returns nil
37
+ attr_reader :problem
38
+
39
+ def initialize(keyopts = {})
40
+ if keyopts[:x509_cert]
41
+ @certs_mode = :literal
42
+ @certs = { :_ => keyopts[:x509_cert] }
43
+ # elsif keyopts[:jwk_uri] # TODO
44
+ # @certs_mode = :jwk
45
+ # @certs = {}
46
+ else
47
+ @certs_mode = :old_skool
48
+ @certs = {}
49
+ end
50
+
51
+ end
52
+
53
+ ##
54
+ # If it validates, returns a hash with the JWT fields from the ID Token.
55
+ # You have to provide an "aud" value, which must match the
56
+ # token's field with that name, and will similarly check cid if provided.
57
+ #
58
+ # If something fails, returns nil; #problem returns error text
59
+ #
60
+ # @param [String] token
61
+ # The string form of the token
62
+ # @param [String] aud
63
+ # The required audience value
64
+ # @param [String] cid
65
+ # The optional client-id ("azp" field) value
66
+ #
67
+ # @return [Hash] The decoded ID token, or null
68
+ def check(token, aud, cid = nil)
69
+ case check_cached_certs(token, aud, cid)
70
+ when :valid
71
+ @token
72
+ when :problem
73
+ nil
74
+ else
75
+ # no certs worked, might've expired, refresh
76
+ if refresh_certs
77
+ @problem = 'Unable to retrieve Google public keys'
78
+ nil
79
+ else
80
+ case check_cached_certs(token, aud, cid)
81
+ when :valid
82
+ @token
83
+ when :problem
84
+ nil
85
+ else
86
+ @problem = 'Token not verified as issued by Google'
87
+ nil
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ # tries to validate the token against each cached cert.
96
+ # Returns :valid (sets @token) or :problem (sets @problem) or
97
+ # nil, which means none of the certs validated.
98
+ def check_cached_certs(token, aud, cid)
99
+ @problem = @token = nil
100
+
101
+ # find first public key that validates this token
102
+ @certs.detect do |key, cert|
103
+ begin
104
+ public_key = cert.public_key
105
+ @token = JWT.decode(token, public_key, !!public_key)
106
+
107
+ @token = @token.first if @token.is_a?(Array)
108
+
109
+ # in Feb 2013, the 'cid' claim became the 'azp' claim per changes
110
+ # in the OIDC draft. At some future point we can go all-azp, but
111
+ # this should keep everything running for a while
112
+ if @token['azp']
113
+ @token['cid'] = @token['azp']
114
+ elsif @token['cid']
115
+ @token['azp'] = @token['cid']
116
+ end
117
+ rescue JWT::DecodeError
118
+ nil # go on, try the next cert
119
+ end
120
+ end
121
+
122
+ if @token
123
+ if !(@token.has_key?('aud') && (@token['aud'] == aud))
124
+ @problem = 'Token audience mismatch'
125
+ elsif cid && !(@token.has_key?('cid') && (@token['cid'] == cid))
126
+ @problem = 'Token client-id mismatch'
127
+ end
128
+ @problem ? :problem : :valid
129
+ else
130
+ nil
131
+ end
132
+ end
133
+
134
+ # returns true if there was a problem
135
+ def refresh_certs
136
+ case @certs_mode
137
+ when :literal
138
+ return # no-op
139
+ when :old_skool
140
+ old_skool_refresh_certs
141
+ # when :jwk # TODO
142
+ # jwk_refresh_certs
143
+ end
144
+ end
145
+
146
+ def old_skool_refresh_certs
147
+ uri = URI(GOOGLE_CERTS_URI)
148
+ get = Net::HTTP::Get.new uri.request_uri
149
+ http = Net::HTTP.new(uri.host, uri.port)
150
+ http.use_ssl = true
151
+ res = http.request(get)
152
+
153
+ if res.kind_of?(Net::HTTPSuccess)
154
+ new_certs = Hash[MultiJson.load(res.body).map do |key, cert|
155
+ [key, OpenSSL::X509::Certificate.new(cert)]
156
+ end]
157
+ @certs.merge! new_certs
158
+ false
159
+ else
160
+ true
161
+ end
162
+ end
163
+ end
164
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: google-id-tokenz
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Tim Bray
8
+ - Bob Aman
9
+ - Nathan Tsoi
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2014-08-10 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: multi_json
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '0'
29
+ - !ruby/object:Gem::Dependency
30
+ name: jwt
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ - !ruby/object:Gem::Dependency
44
+ name: fakeweb
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ - !ruby/object:Gem::Dependency
58
+ name: rake
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ - !ruby/object:Gem::Dependency
72
+ name: rspec
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ - !ruby/object:Gem::Dependency
86
+ name: openssl
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ type: :development
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ description: Google ID Token utilities; currently just a parser/checker
100
+ email: nathan@vertile.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - README.md
106
+ - lib/google-id-token.rb
107
+ homepage: https://github.com/nathantsoi/google-id-tokenz
108
+ licenses: []
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.2.2
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Google ID Token utilities
130
+ test_files: []