google-id-token 1.0.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.
Files changed (3) hide show
  1. data/README.rdoc +17 -0
  2. data/lib/google-id-token.rb +132 -0
  3. metadata +128 -0
@@ -0,0 +1,17 @@
1
+ = GoogleIDToken
2
+
3
+ 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.
4
+
5
+ === Installation
6
+
7
+ gem install google-id-token
8
+
9
+ === Examples
10
+
11
+ validator = GoogleIDToken::Validator.new
12
+ jwt = validator.validate(token, required_audience, required_client_id)
13
+ if jwt
14
+ email = jwt['email']
15
+ else
16
+ report "Cannot validate: #{validator.problem}"
17
+ end
@@ -0,0 +1,132 @@
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
40
+ @certs = {}
41
+ end
42
+
43
+ ##
44
+ # If it validates, returns a hash with the JWT fields from the ID Token.
45
+ # You have to provide an "aud" value, which must match the
46
+ # token's field with that name, and will similarly check cid if provided.
47
+ #
48
+ # If something fails, returns nil; #problem returns error text
49
+ #
50
+ # @param [String] token
51
+ # The string form of the token
52
+ # @param [String] aud
53
+ # The required audience value
54
+ # @param [String] cid
55
+ # The optional client-id value
56
+ #
57
+ # @return [Hash] The decoded ID token, or null
58
+ def check(token, aud, cid = nil)
59
+ case check_cached_certs(token, aud, cid)
60
+ when :valid
61
+ @token
62
+ when :problem
63
+ nil
64
+ else
65
+ # no certs worked, might've expired, refresh
66
+ if refresh_certs
67
+ @problem = 'Unable to retrieve Google public keys'
68
+ nil
69
+ else
70
+ case check_cached_certs(token, aud, cid)
71
+ when :valid
72
+ @token
73
+ when :problem
74
+ nil
75
+ else
76
+ @problem = 'Token not verified as issued by Google'
77
+ nil
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ # tries to validate the token against each cached cert.
86
+ # Returns :valid (sets @token) or :problem (sets @problem) or
87
+ # nil, which means none of the certs validated.
88
+ def check_cached_certs(token, aud, cid)
89
+ @problem = @token = nil
90
+
91
+ # find first public key that validates this token
92
+ @certs.detect do |key, cert|
93
+ begin
94
+ public_key = cert.public_key
95
+ @token = JWT.decode(token, public_key, !!public_key)
96
+ rescue JWT::DecodeError
97
+ nil # go on, try the next cert
98
+ end
99
+ end
100
+
101
+ if @token
102
+ if !(@token.has_key?('aud') && (@token['aud'] == aud))
103
+ @problem = 'Token audience mismatch'
104
+ elsif cid && !(@token.has_key?('cid') && (@token['cid'] == cid))
105
+ @problem = 'Token client-id mismatch'
106
+ end
107
+ @problem ? :problem : :valid
108
+ else
109
+ nil
110
+ end
111
+ end
112
+
113
+ # returns true if there was a problem
114
+ def refresh_certs
115
+ uri = URI(GOOGLE_CERTS_URI)
116
+ get = Net::HTTP::Get.new uri.request_uri
117
+ res = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => true) do |http|
118
+ http.request(get)
119
+ end
120
+
121
+ if res.kind_of?(Net::HTTPSuccess)
122
+ new_certs = Hash[MultiJson.load(res.body).map do |key, cert|
123
+ [key, OpenSSL::X509::Certificate.new(cert)]
124
+ end]
125
+ @certs.merge! new_certs
126
+ false
127
+ else
128
+ true
129
+ end
130
+ end
131
+ end
132
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: google-id-token
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tim Bray
9
+ - Bob Aman
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-12-06 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: multi_json
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: jwt
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: fakeweb
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: rake
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ - !ruby/object:Gem::Dependency
80
+ name: rspec
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ description: Google ID Token utilities; currently just a parser/checker
96
+ email: tbray@textuality.com
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - lib/google-id-token.rb
102
+ - README.rdoc
103
+ homepage: https://code.google.com/p/google-id-token/
104
+ licenses: []
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 1.8.21
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Google ID Token utilities
127
+ test_files: []
128
+ has_rdoc: