google-auth-token_validator 0.1.0 → 0.1.2
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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/README.md +4 -4
- data/google-auth_token_validator.gemspec +4 -4
- data/lib/googleauth/token_validator.rb +62 -58
- data/lib/googleauth/token_validator/version.rb +1 -1
- metadata +9 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd96722d88bd535c40980ccfe43384424fe2e22e
|
4
|
+
data.tar.gz: 93b4ca75f73ee610991963a859dd16477e7494ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 896349e1e8045836616665bd4eb91b9b3e2f99367ba882d89459f8e38516d8caefccd2b071a5886efc2476a39673957d9985f81cf59c9c000020ad902f4fb4bb
|
7
|
+
data.tar.gz: b64eca6fef334a4bf27fbf2a270a237ce1e30bfa65b58fbc2d153933885154580d4806fd9cb886a386aa99e8d8f0a0bbba60312efdd6e3295cb47f7517f6f7be
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -3,16 +3,16 @@
|
|
3
3
|
[](https://travis-ci.org/hamza/google-auth-token-validator-ruby)
|
4
4
|
[](https://coveralls.io/github/hamza/google-auth-token-validator-ruby?branch=master)
|
5
5
|
|
6
|
-
The Google Sign-In API gives OAuth2 JSON Web Tokens (JWT) as response data upon user sign-in. A necessary step for a service provider to trust such a token
|
6
|
+
The Google Sign-In API gives OAuth2 JSON Web Tokens (JWT) as response data upon user sign-in. A necessary step for a service provider to trust such a token is validatation. Accepting the token without validation would allow a malicious client to simply assert itself in your system.
|
7
7
|
|
8
|
-
Google provides libraries in several languages
|
8
|
+
Google provides [libraries in several languages](https://developers.google.com/identity/sign-in/web/backend-auth) to accomplish this, as well as an API endpoint that can outsource the task to Google's own servers (thereby introducing an additional network round trip into every authentication step), but a Ruby implementation is missing. This gem fills that gap.
|
9
9
|
|
10
10
|
## Installation
|
11
11
|
|
12
12
|
Add this line to your application's Gemfile:
|
13
13
|
|
14
14
|
```ruby
|
15
|
-
gem 'google-auth-token_validator'
|
15
|
+
gem 'google-auth-token_validator'
|
16
16
|
```
|
17
17
|
|
18
18
|
And then execute:
|
@@ -61,7 +61,7 @@ Use the [Google Cloud Console](https://console.cloud.google.com) to set up an OA
|
|
61
61
|
|
62
62
|
## Contributing
|
63
63
|
|
64
|
-
Bug reports and pull requests are welcome on [the repo](https://github.com/hamza/
|
64
|
+
Bug reports and pull requests are welcome on [the repo](https://github.com/hamza/google-auth-token-validator-ruby/issues).
|
65
65
|
|
66
66
|
## License
|
67
67
|
|
@@ -14,11 +14,11 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.summary = "Ruby gem to validate signed JSON Web Tokens from Google's sign-in API"
|
15
15
|
spec.description = <<-DESC
|
16
16
|
The Google Sign-In API gives OAuth2 JSON Web Tokens (JWT) as response data upon user sign-in.
|
17
|
-
A necessary step for a service provider to trust such a token
|
18
|
-
|
19
|
-
|
17
|
+
A necessary step for a service provider to trust such a token is validatation. Accepting the
|
18
|
+
token without validation would allow a malicious client to simply assert itself in your system.
|
19
|
+
\n\n
|
20
20
|
|
21
|
-
Google provides libraries in several languages (https://goo.gl/jkzS18) to
|
21
|
+
Google provides libraries in several languages (https://goo.gl/jkzS18) to accomplish this,
|
22
22
|
as well as an API endpoint that can outsource the task to Google's own servers (thereby
|
23
23
|
introducing an additional network round trip into every authentication step), but a Ruby
|
24
24
|
implementation is missing. This gem fills that gap.
|
@@ -3,85 +3,89 @@ require "json"
|
|
3
3
|
require "base64"
|
4
4
|
require "openssl"
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
module Google
|
7
|
+
module Auth
|
8
|
+
class TokenValidator
|
9
|
+
GOOGLE_SIGNON_CERTS_URL = "https://www.googleapis.com/oauth2/v1/certs".freeze
|
10
|
+
ISSUERS = %w(accounts.google.com https://accounts.google.com).freeze
|
11
|
+
CLOCK_SKEW_SECONDS = 300 # five minutes
|
12
|
+
MAX_TOKEN_LIFETIME_SECONDS = 86400 # one day
|
11
13
|
|
12
|
-
|
14
|
+
attr_reader :signed, :signature, :envelope, :payload, :client_id
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
+
def initialize jwt, client_id
|
17
|
+
segments = jwt.split(".")
|
16
18
|
|
17
|
-
|
19
|
+
fail Error, "Wrong number of segments in token: #{jwt}" unless segments.size.eql? 3
|
18
20
|
|
19
|
-
|
21
|
+
@client_id = client_id
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
+
@signed = "#{segments[0]}.#{segments[1]}"
|
24
|
+
@signature = segments[2]
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
26
|
+
@envelope = JSON.parse Base64.decode64(segments[0])
|
27
|
+
@payload = JSON.parse Base64.decode64(segments[1])
|
28
|
+
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
def validate max_expiry = MAX_TOKEN_LIFETIME_SECONDS
|
31
|
+
unless [@signed, @signature, @envelope, @payload].all?
|
32
|
+
fail Error, "Validator was not properly initialized"
|
33
|
+
end
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
35
|
+
unless self.class._certs.keys.include? @envelope["kid"]
|
36
|
+
fail Error, "No matching Google cert found for envelope: #{@envelope}"
|
37
|
+
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
pem = self.class._certs[envelope["kid"]]
|
40
|
+
cert = OpenSSL::X509::Certificate.new pem
|
41
|
+
digest = OpenSSL::Digest::SHA256.new
|
40
42
|
|
41
|
-
|
43
|
+
verified = cert.public_key.verify(digest, Base64.urlsafe_decode64(@signature), @signed)
|
42
44
|
|
43
|
-
|
45
|
+
fail Error, "Token signature invalid" unless verified
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
+
fail Error, "No issue time in token" if @payload["iat"].to_s.empty?
|
48
|
+
fail Error, "No expiration time in token" if @payload["exp"].to_s.empty?
|
47
49
|
|
48
|
-
|
49
|
-
|
50
|
-
|
50
|
+
now = Time.now.to_i
|
51
|
+
earliest = @payload["iat"] - CLOCK_SKEW_SECONDS
|
52
|
+
latest = @payload["exp"] + CLOCK_SKEW_SECONDS
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
54
|
+
fail Error, "Expiration time too far in future" if @payload["exp"] >= Time.now.to_i + max_expiry
|
55
|
+
fail Error, "Token used too early" if now < earliest
|
56
|
+
fail Error, "Token used too late" if now > latest
|
55
57
|
|
56
|
-
|
57
|
-
|
58
|
-
|
58
|
+
unless ISSUERS.include? @payload["iss"]
|
59
|
+
fail Error, "Invalid issuer. Expected one of #{ISSUERS}, but got #{@payload["iss"]}"
|
60
|
+
end
|
59
61
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
if @client_id.is_a? Array
|
63
|
+
aud_verified = @client_id.include?(@payload["aud"])
|
64
|
+
elsif @client_id.is_a? String
|
65
|
+
aud_verified = @payload["aud"] == @client_id
|
66
|
+
else
|
67
|
+
fail Error, "Invalid client id(s)"
|
68
|
+
end
|
67
69
|
|
68
|
-
|
69
|
-
|
70
|
-
|
70
|
+
unless aud_verified
|
71
|
+
fail Error, "Wrong recipient - payload audience doesn't match required audience"
|
72
|
+
end
|
71
73
|
|
72
|
-
|
73
|
-
|
74
|
+
return true
|
75
|
+
end
|
74
76
|
|
75
|
-
|
76
|
-
|
77
|
+
class << self
|
78
|
+
attr_accessor :_cached_certs
|
77
79
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
80
|
+
def _certs
|
81
|
+
@_cached_certs ||= begin
|
82
|
+
uri = URI(GOOGLE_SIGNON_CERTS_URL)
|
83
|
+
JSON.parse Net::HTTP.get(uri)
|
84
|
+
end
|
85
|
+
end
|
82
86
|
end
|
87
|
+
|
88
|
+
class Error < StandardError; end
|
83
89
|
end
|
84
90
|
end
|
85
|
-
|
86
|
-
class Error < StandardError; end
|
87
91
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: google-auth-token_validator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hamza Tayeb
|
@@ -94,16 +94,14 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '2.2'
|
97
|
-
description:
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
introducing an additional network round trip into every authentication step), but a Ruby
|
106
|
-
implementation is missing. This gem fills that gap.
|
97
|
+
description: " The Google Sign-In API gives OAuth2 JSON Web Tokens (JWT) as response
|
98
|
+
data upon user sign-in.\n A necessary step for a service provider to trust such
|
99
|
+
a token is validatation. Accepting the\n token without validation would allow
|
100
|
+
a malicious client to simply assert itself in your system.\n \n\n\n\n Google
|
101
|
+
provides libraries in several languages (https://goo.gl/jkzS18) to accomplish this,\n
|
102
|
+
\ as well as an API endpoint that can outsource the task to Google's own servers
|
103
|
+
(thereby\n introducing an additional network round trip into every authentication
|
104
|
+
step), but a Ruby\n implementation is missing. This gem fills that gap.\n"
|
107
105
|
email:
|
108
106
|
- hamza.tayeb@gmail.com
|
109
107
|
executables: []
|