firejwt 0.1.0 → 0.3.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.
data/go.mod CHANGED
@@ -3,10 +3,7 @@ module github.com/bsm/firejwt
3
3
  go 1.13
4
4
 
5
5
  require (
6
- github.com/bsm/bfs v0.9.0
7
- github.com/bsm/feedx v0.9.2
6
+ github.com/bsm/ginkgo v1.16.1
7
+ github.com/bsm/gomega v1.11.0
8
8
  github.com/dgrijalva/jwt-go v3.2.0+incompatible
9
- github.com/golang/protobuf v1.3.2
10
- github.com/onsi/ginkgo v1.11.0
11
- github.com/onsi/gomega v1.8.1
12
9
  )
data/go.sum CHANGED
@@ -1,61 +1,6 @@
1
- github.com/bmatcuk/doublestar v1.1.5/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
2
- github.com/bmatcuk/doublestar v1.2.2 h1:oC24CykoSAB8zd7XgruHo33E0cHJf/WhQA/7BeXj+x0=
3
- github.com/bmatcuk/doublestar v1.2.2/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
4
- github.com/bsm/bfs v0.8.1/go.mod h1:cVv0jyqUY/jbHoG/WYPuWvOaOhW/HZ4jl7/JMlypvAE=
5
- github.com/bsm/bfs v0.9.0 h1:7sUB3a5ZzzhBlCELY+2pqCaI6MbO7F2a0jhIgHihhFs=
6
- github.com/bsm/bfs v0.9.0/go.mod h1:N3md8kQvlteRDcfc8tqw759yW98dhj+6seWEVcg4CmM=
7
- github.com/bsm/feedx v0.9.2 h1:9Af+bc6vvnPpli2D3Re4spwdKxox8kKjmnmE4qPICIc=
8
- github.com/bsm/feedx v0.9.2/go.mod h1:63cqu0wUcW6RwIbhOnW27K8XluiOfdqnKFTVTroqNHI=
1
+ github.com/bsm/ginkgo v1.16.1 h1:jp1v1dbmbGZDWmnGXDTN+XK3U1fTTNja9xYa7VBI0l0=
2
+ github.com/bsm/ginkgo v1.16.1/go.mod h1:RabIZLzOCPghgHJKUqHZpqrQETA5AnF4aCSIYy5C1bk=
3
+ github.com/bsm/gomega v1.11.0 h1:wg9DVGPETNZLIbMsseneMV1a7uo/x+wsCyNXdEcifDI=
4
+ github.com/bsm/gomega v1.11.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk=
9
5
  github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
10
6
  github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
11
- github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
12
- github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
13
- github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
14
- github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
15
- github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
16
- github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
17
- github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
18
- github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
19
- github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
20
- github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
21
- github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
22
- github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
23
- github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
24
- github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
25
- github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
26
- github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
27
- github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
28
- github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
29
- github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
30
- github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
31
- github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34=
32
- github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
33
- golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
34
- golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
35
- golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
36
- golang.org/x/net v0.0.0-20191007182048-72f939374954 h1:JGZucVF/L/TotR719NbujzadOZ2AgnYlqphQGHDCKaU=
37
- golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
38
- golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
39
- golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
40
- golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
41
- golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
42
- golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
43
- golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
44
- golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
45
- golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
46
- golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
47
- golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
48
- golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
49
- golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
50
- golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
51
- gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
52
- gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
53
- gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
54
- gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
55
- gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
56
- gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
57
- gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
58
- gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
59
- gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
60
- gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
61
- gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
data/lib/firejwt.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module FireJWT
2
- autoload :KeySet, 'firejwt/key_set'
2
+ autoload :Certificates, 'firejwt/certificates'
3
3
  autoload :Validator, 'firejwt/validator'
4
4
 
5
5
  class Token < Hash
@@ -4,7 +4,7 @@ require 'uri'
4
4
  require 'openssl'
5
5
 
6
6
  module FireJWT
7
- class KeySet < Hash
7
+ class Certificates
8
8
  URL = 'https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com'.freeze
9
9
 
10
10
  attr_reader :expires_at
@@ -12,14 +12,17 @@ module FireJWT
12
12
  def initialize(url: URL)
13
13
  super()
14
14
 
15
- @url = URI(url)
15
+ @url = URI(url)
16
+ @keys = {}
17
+
16
18
  expire!
17
19
  refresh!
18
20
  end
19
21
 
20
- def get(key)
22
+ def get(kid)
21
23
  refresh! if expired?
22
- self[key]
24
+
25
+ @keys[kid]
23
26
  end
24
27
 
25
28
  def refresh!(limit = 5)
@@ -33,8 +36,11 @@ module FireJWT
33
36
  raise ArgumentError, 'Expires header not included in the response' unless resp['expires']
34
37
 
35
38
  @expires_at = Time.httpdate(resp['expires'])
36
- JSON.parse(resp.body).each do |kid, cert|
37
- store kid, OpenSSL::X509::Certificate.new(cert).public_key
39
+ @keys.clear
40
+
41
+ JSON.parse(resp.body).each do |kid, pem|
42
+ cert = OpenSSL::X509::Certificate.new(pem)
43
+ @keys.store kid, cert.public_key
38
44
  end
39
45
  end
40
46
 
@@ -3,46 +3,48 @@ require 'jwt'
3
3
  require 'net/http'
4
4
 
5
5
  module FireJWT
6
+ class InvalidAuthTimeError < JWT::DecodeError; end
7
+
8
+ # Validator validates tokens applying guidelines outlined in
9
+ # https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library.
6
10
  class Validator
7
- # @param [Hash] opts
8
- # @option opts [String] :algorithm the expected algorithm. Default: RS256.
9
- # @option opts [String] :aud verify the audience claim against the given value. Default: nil (= do not validate).
10
- # @option opts [String] :iss verify the issuer claim against the given value. Default: nil (= do not verify).
11
- # @option opts [String] :sub verify the subject claim against the given value. Default: nil (= do not verify).
12
- # @option opts [Boolean] :verify_iat verify the issued at claim. Default: false.
13
- # @option opts [Integer] :exp_leeway expiration leeway in seconds. Default: none.
14
- def initialize(**opts)
15
- @defaults = norm_opts(opts.dup)
16
- @keys = KeySet.new
11
+ # @param [String] project_id the unique identifier for your Firebase project, which can be found in the URL of that project's console.
12
+ def initialize(project_id)
13
+ project_id = project_id.to_s
14
+
15
+ @certs = Certificates.new
16
+ @opts = {
17
+ algorithms: %w[RS256].freeze,
18
+
19
+ # exp must be in the future, iat must be in the past
20
+ verify_expiration: true,
21
+ verify_iat: true,
22
+
23
+ # aud must be your Firebase project ID
24
+ verify_aud: true, aud: project_id,
25
+
26
+ # iss must be "https://securetoken.google.com/<projectId>"
27
+ verify_iss: true, iss: "https://securetoken.google.com/#{project_id}",
28
+ }
17
29
  end
18
30
 
19
31
  # @param [String] token the token string
20
- # @param [Hash] opts options
21
- # @option opts [Boolean] :allow_expired allow expired tokens. Default: false.
22
- # @option opts [String] :algorithm the expected algorithm. Default: RS256.
23
- # @option opts [String] :aud verify the audience claim against the given value. Default: nil (= do not validate).
24
- # @option opts [String] :iss verify the issuer claim against the given value. Default: nil (= do not verify).
25
- # @option opts [String] :sub verify the subject claim against the given value. Default: nil (= do not verify).
26
- # @option opts [Boolean] :verify_iat verify the issued at claim. Default: false.
27
- # @option opts [Integer] :exp_leeway expiration leeway in seconds. Default: none.
28
32
  # @return [FireJWT::Token] the token
29
33
  # @raises [JWT::DecodeError] validation errors
30
- def decode(token, allow_expired: false, **opts)
31
- opts = norm_opts(@defaults.merge(opts))
32
- payload, header = JWT.decode token, nil, !allow_expired, opts do |header|
33
- @keys.get(header['kid'])
34
+ def decode(token)
35
+ payload, header = JWT.decode token, nil, true, **@opts do |header|
36
+ @certs.get(header['kid'])
34
37
  end
35
- Token.new(payload, header)
36
- end
37
38
 
38
- private
39
+ # sub must be a non-empty string
40
+ sub = payload['sub']
41
+ raise(JWT::InvalidSubError, 'Invalid subject. Expected non-empty string') unless sub.is_a?(String) && !sub.empty?
39
42
 
40
- def norm_opts(opts)
41
- opts[:verify_aud] = !opts.key?(:aud) unless opts.key?(:verify_aud)
42
- opts[:verify_iss] = !opts.key?(:iss) unless opts.key?(:verify_iss)
43
- opts[:verify_sub] = !opts.key?(:sub) unless opts.key?(:verify_sub)
44
- opts[:algorithm] ||= 'RS256'
45
- opts
43
+ # auth_time must be in the past
44
+ aut = payload['auth_time']
45
+ raise(InvalidAuthTimeError, 'Invalid auth_time') if !aut.is_a?(Numeric) || aut.to_f > Time.now.to_f
46
+
47
+ Token.new(payload, header)
46
48
  end
47
49
  end
48
50
  end
@@ -1,28 +1,28 @@
1
1
  require 'spec_helper'
2
2
 
3
- RSpec.describe FireJWT::KeySet do
4
- let! :keys_request do
3
+ RSpec.describe FireJWT::Certificates do
4
+ let(:cert) { MockCert.new }
5
+
6
+ let! :http_request do
5
7
  stub_request(:get, described_class::URL.to_s).to_return(
6
8
  status: 200,
7
9
  headers: { expires: (Time.now + 3600).httpdate },
8
- body: MOCK_RESPONSE.to_json,
10
+ body: cert.to_json,
9
11
  )
10
12
  end
11
13
 
12
- it 'should init' do
13
- expect(subject).to include(
14
- MOCK_KID => instance_of(OpenSSL::PKey::RSA),
15
- )
14
+ it 'inits' do
16
15
  expect(subject.expires_at).to be_within(10).of(Time.now + 3600)
17
16
  expect(subject).not_to be_expired
17
+ expect(http_request).to have_been_made
18
18
  end
19
19
 
20
- it 'should retrieve keys' do
20
+ it 'retrieves keys' do
21
21
  expect(subject.get('BAD')).to be_nil
22
- expect(subject.get(MOCK_KID)).to be_instance_of(OpenSSL::PKey::RSA)
22
+ expect(subject.get(cert.kid)).to be_instance_of(OpenSSL::PKey::RSA)
23
23
  end
24
24
 
25
- it 'should check/update expiration status' do
25
+ it 'check/updates expiration status' do
26
26
  expect(subject).not_to be_expired
27
27
  subject.expire!
28
28
  expect(subject).to be_expired
@@ -1,59 +1,86 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe FireJWT::Validator do
4
- let! :keys_request do
5
- stub_request(:get, FireJWT::KeySet::URL.to_s).to_return(
4
+ subject { described_class.new(project_id) }
5
+
6
+ let! :http_request do
7
+ stub_request(:get, FireJWT::Certificates::URL.to_s).to_return(
6
8
  status: 200,
7
9
  headers: { expires: (Time.now + 3600).httpdate },
8
- body: MOCK_RESPONSE.to_json,
10
+ body: cert.to_json,
9
11
  )
10
12
  end
11
13
 
12
- let :exp_time do
13
- Time.now.to_i + 3600
14
- end
15
-
16
- let :token do
17
- payload = {
18
- sub: 'me@example.com',
19
- aud: 'you',
20
- iss: 'me',
21
- exp: exp_time,
14
+ let :payload do
15
+ now = Time.now.to_i
16
+ {
17
+ 'name' => 'Me',
18
+ 'picture' => 'https://test.host/me.jpg',
19
+ 'sub' => 'MDYwNDQwNjUtYWQ0ZC00ZDkwLThl',
20
+ 'user_id' => 'MDYwNDQwNjUtYWQ0ZC00ZDkwLThl',
21
+ 'aud' => project_id,
22
+ 'iss' => 'https://securetoken.google.com/' << project_id,
23
+ 'iat' => now - 1800,
24
+ 'exp' => now + 3600,
25
+ 'auth_time' => now,
26
+ 'email' => 'me@example.com',
27
+ 'email_verified' => true,
28
+ 'firebase' => {
29
+ 'sign_in_provider' => 'google.com',
30
+ 'identities' => {
31
+ 'google.com' => ['123123123123123123123'],
32
+ 'email' => ['me@example.com'],
33
+ },
34
+ },
22
35
  }
23
- JWT.encode payload, MOCK_RSA, 'RS256', kid: MOCK_KID
24
36
  end
25
37
 
26
- it 'should decode' do
38
+ let(:cert) { MockCert.new }
39
+ let(:project_id) { 'mock-project' }
40
+ let(:token) { JWT.encode payload, cert.pkey, 'RS256', kid: cert.kid }
41
+
42
+ it 'decodes' do
27
43
  decoded = subject.decode(token)
28
44
  expect(decoded).to be_instance_of(FireJWT::Token)
29
- expect(decoded).to eq(
30
- 'sub' => 'me@example.com',
31
- 'aud' => 'you',
32
- 'iss' => 'me',
33
- 'exp' => exp_time,
34
- )
45
+ expect(decoded).to eq(payload)
35
46
  expect(decoded.header).to eq(
36
47
  'alg' => 'RS256',
37
- 'kid' => 'e5a91d9f39fa4de254a1e89df00f05b7e248b985',
48
+ 'kid' => cert.kid,
38
49
  )
50
+ expect(http_request).to have_been_made
39
51
  end
40
52
 
41
- it 'should reject bad tokens' do
53
+ it 'rejects bad tokens' do
42
54
  expect { subject.decode('BAD') }.to raise_error(JWT::DecodeError)
43
55
  end
44
56
 
45
- it 'should verify audiences' do
46
- expect(subject.decode(token, aud: 'you')).to be_instance_of(FireJWT::Token)
47
- expect { subject.decode(token, aud: 'other') }.to raise_error(JWT::InvalidAudError)
57
+ it 'verifies exp' do
58
+ payload['exp'] = Time.now.to_i - 1
59
+ expect { subject.decode(token) }.to raise_error(JWT::ExpiredSignature)
60
+ end
61
+
62
+ it 'verifies iat' do
63
+ payload['iat'] = Time.now.to_i + 10
64
+ expect { subject.decode(token) }.to raise_error(JWT::InvalidIatError)
65
+ end
66
+
67
+ it 'verifies aud' do
68
+ payload['aud'] = 'other'
69
+ expect { subject.decode(token) }.to raise_error(JWT::InvalidAudError)
70
+ end
71
+
72
+ it 'verifies iss' do
73
+ payload['iss'] = 'other'
74
+ expect { subject.decode(token) }.to raise_error(JWT::InvalidIssuerError)
48
75
  end
49
76
 
50
- it 'should verify issuers' do
51
- expect(subject.decode(token, iss: 'me')).to be_instance_of(FireJWT::Token)
52
- expect { subject.decode(token, iss: 'other') }.to raise_error(JWT::InvalidIssuerError)
77
+ it 'verifies sub' do
78
+ payload['sub'] = ''
79
+ expect { subject.decode(token) }.to raise_error(JWT::InvalidSubError)
53
80
  end
54
81
 
55
- it 'should verify subjects' do
56
- expect(subject.decode(token, sub: 'me@example.com')).to be_instance_of(FireJWT::Token)
57
- expect { subject.decode(token, sub: 'other') }.to raise_error(JWT::InvalidSubError)
82
+ it 'verifies auth_time' do
83
+ payload['auth_time'] = Time.now.to_i + 10
84
+ expect { subject.decode(token) }.to raise_error(FireJWT::InvalidAuthTimeError)
58
85
  end
59
86
  end
data/spec/spec_helper.rb CHANGED
@@ -4,8 +4,34 @@ require 'webmock/rspec'
4
4
 
5
5
  WebMock.disable_net_connect!
6
6
 
7
- MOCK_KID = 'e5a91d9f39fa4de254a1e89df00f05b7e248b985'.freeze
8
- MOCK_RSA = OpenSSL::PKey::RSA.new File.read(File.expand_path('../testdata/priv.pem', __dir__))
9
- MOCK_RESPONSE = {
10
- MOCK_KID => File.read(File.expand_path('../testdata/cert.pem', __dir__)),
11
- }.freeze
7
+ class MockCert
8
+ attr_reader :cert, :pkey
9
+
10
+ def initialize
11
+ @pkey = OpenSSL::PKey::RSA.new 2048
12
+ @cert = OpenSSL::X509::Certificate.new
13
+ @cert.version = 2
14
+ @cert.serial = 2605014480174073526
15
+ @cert.subject = OpenSSL::X509::Name.parse('/CN=securetoken.system.gserviceaccount.com')
16
+ @cert.issuer = @cert.subject
17
+ @cert.public_key = @pkey.public_key
18
+ @cert.not_before = Time.now
19
+ @cert.not_after = @cert.not_before + 3600
20
+
21
+ exts = OpenSSL::X509::ExtensionFactory.new
22
+ exts.subject_certificate = cert
23
+ exts.issuer_certificate = cert
24
+ @cert.add_extension(exts.create_extension('basicConstraints', 'CA:FALSE', true))
25
+ @cert.add_extension(exts.create_extension('keyUsage', 'Digital Signature', true))
26
+ @cert.add_extension(exts.create_extension('extendedKeyUsage', 'TLS Web Client Authentication', true))
27
+ @cert.sign(@pkey, OpenSSL::Digest.new('SHA256'))
28
+ end
29
+
30
+ def kid
31
+ @kid ||= Digest::SHA1.hexdigest(@cert.to_der)
32
+ end
33
+
34
+ def to_json(*)
35
+ { kid => @cert }.to_json
36
+ end
37
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: firejwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Black Square Media Ltd
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-22 00:00:00.000000000 Z
11
+ date: 2021-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jwt
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rubocop
56
+ name: rubocop-bsm
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -87,30 +87,27 @@ executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
+ - ".github/workflows/test.yml"
90
91
  - ".gitignore"
91
- - ".rubocop-https---gitlab-com-bsm-misc-raw-master-rubocop-default-yml"
92
92
  - ".rubocop.yml"
93
- - ".travis.yml"
94
93
  - Gemfile
95
94
  - Gemfile.lock
96
95
  - LICENSE
97
96
  - Makefile
98
97
  - README.md
99
98
  - Rakefile
99
+ - ext_test.go
100
100
  - firejwt.gemspec
101
101
  - firejwt.go
102
102
  - firejwt_test.go
103
103
  - go.mod
104
104
  - go.sum
105
105
  - lib/firejwt.rb
106
- - lib/firejwt/key_set.rb
106
+ - lib/firejwt/certificates.rb
107
107
  - lib/firejwt/validator.rb
108
- - opt.go
109
- - spec/firejwt/key_set_spec.rb
108
+ - spec/firejwt/certificates_spec.rb
110
109
  - spec/firejwt/validator_spec.rb
111
110
  - spec/spec_helper.rb
112
- - testdata/cert.pem
113
- - testdata/priv.pem
114
111
  homepage: https://github.com/bsm/firejwt
115
112
  licenses:
116
113
  - Apache-2.0
@@ -130,11 +127,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
127
  - !ruby/object:Gem::Version
131
128
  version: '0'
132
129
  requirements: []
133
- rubygems_version: 3.1.2
130
+ rubygems_version: 3.1.4
134
131
  signing_key:
135
132
  specification_version: 4
136
133
  summary: Firebase JWT validation
137
134
  test_files:
138
- - spec/firejwt/key_set_spec.rb
135
+ - spec/firejwt/certificates_spec.rb
139
136
  - spec/firejwt/validator_spec.rb
140
137
  - spec/spec_helper.rb