google-id-tokenz 1.2.1

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