firejwt 0.1.0 → 0.3.1

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