jwt 1.5.2 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +13 -5
  2. data/.codeclimate.yml +20 -0
  3. data/.gitignore +6 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +2 -0
  6. data/.travis.yml +13 -0
  7. data/Gemfile +4 -0
  8. data/README.md +29 -11
  9. data/Rakefile +1 -18
  10. data/lib/jwt.rb +19 -75
  11. data/lib/jwt/decode.rb +56 -0
  12. data/lib/jwt/error.rb +12 -0
  13. data/lib/jwt/json.rb +9 -25
  14. data/lib/jwt/verify.rb +98 -0
  15. data/lib/jwt/version.rb +23 -0
  16. data/ruby-jwt.gemspec +29 -0
  17. data/spec/fixtures/certs/ec256-private.pem +8 -0
  18. data/spec/fixtures/certs/ec256-public.pem +4 -0
  19. data/spec/fixtures/certs/ec256-wrong-private.pem +8 -0
  20. data/spec/fixtures/certs/ec256-wrong-public.pem +4 -0
  21. data/spec/fixtures/certs/ec384-private.pem +9 -0
  22. data/spec/fixtures/certs/ec384-public.pem +5 -0
  23. data/spec/fixtures/certs/ec384-wrong-private.pem +9 -0
  24. data/spec/fixtures/certs/ec384-wrong-public.pem +5 -0
  25. data/spec/fixtures/certs/ec512-private.pem +10 -0
  26. data/spec/fixtures/certs/ec512-public.pem +6 -0
  27. data/spec/fixtures/certs/ec512-wrong-private.pem +10 -0
  28. data/spec/fixtures/certs/ec512-wrong-public.pem +6 -0
  29. data/spec/fixtures/certs/rsa-1024-private.pem +15 -0
  30. data/spec/fixtures/certs/rsa-1024-public.pem +6 -0
  31. data/spec/fixtures/certs/rsa-2048-private.pem +27 -0
  32. data/spec/fixtures/certs/rsa-2048-public.pem +9 -0
  33. data/spec/fixtures/certs/rsa-2048-wrong-private.pem +27 -0
  34. data/spec/fixtures/certs/rsa-2048-wrong-public.pem +9 -0
  35. data/spec/fixtures/certs/rsa-4096-private.pem +51 -0
  36. data/spec/fixtures/certs/rsa-4096-public.pem +14 -0
  37. data/spec/jwt/verify_spec.rb +175 -0
  38. data/spec/jwt_spec.rb +1 -181
  39. data/spec/spec_helper.rb +2 -3
  40. metadata +145 -28
  41. data/jwt.gemspec +0 -34
@@ -0,0 +1,98 @@
1
+ require 'jwt/error'
2
+
3
+ module JWT
4
+ # JWT verify methods
5
+ class Verify
6
+ class << self
7
+ %w[verify_aud verify_expiration verify_iat verify_iss verify_jti verify_not_before verify_sub].each do |method_name|
8
+ define_method method_name do |payload, options|
9
+ new(payload, options).send(method_name)
10
+ end
11
+ end
12
+ end
13
+
14
+ def initialize(payload, options)
15
+ @payload = payload
16
+ @options = options
17
+ end
18
+
19
+ def verify_aud
20
+ return unless (options_aud = extract_option(:aud))
21
+
22
+ if @payload['aud'].is_a?(Array)
23
+ fail(
24
+ JWT::InvalidAudError,
25
+ 'Invalid audience'
26
+ ) unless @payload['aud'].include?(options_aud.to_s)
27
+ else
28
+ fail(
29
+ JWT::InvalidAudError,
30
+ "Invalid audience. Expected #{options_aud}, received #{@payload['aud'] || '<none>'}"
31
+ ) unless @payload['aud'].to_s == options_aud.to_s
32
+ end
33
+ end
34
+
35
+ def verify_expiration
36
+ return unless @payload.include?('exp')
37
+
38
+ if @payload['exp'].to_i < (Time.now.to_i - leeway)
39
+ fail(JWT::ExpiredSignature, 'Signature has expired')
40
+ end
41
+ end
42
+
43
+ def verify_iat
44
+ return unless @payload.include?('iat')
45
+
46
+ if !(@payload['iat'].is_a?(Numeric)) || @payload['iat'].to_f > (Time.now.to_f + leeway)
47
+ fail(JWT::InvalidIatError, 'Invalid iat')
48
+ end
49
+ end
50
+
51
+ def verify_iss
52
+ return unless (options_iss = extract_option(:iss))
53
+
54
+ if @payload['iss'].to_s != options_iss.to_s
55
+ fail(
56
+ JWT::InvalidIssuerError,
57
+ "Invalid issuer. Expected #{options_iss}, received #{@payload['iss'] || '<none>'}"
58
+ )
59
+ end
60
+ end
61
+
62
+ def verify_jti
63
+ options_verify_jti = extract_option(:verify_jti)
64
+ if options_verify_jti.respond_to?(:call)
65
+ fail(JWT::InvalidJtiError, 'Invalid jti') unless options_verify_jti.call(@payload['jti'])
66
+ else
67
+ fail(JWT::InvalidJtiError, 'Missing jti') if @payload['jti'].to_s.strip.empty?
68
+ end
69
+ end
70
+
71
+ def verify_not_before
72
+ return unless @payload.include?('nbf')
73
+
74
+ if @payload['nbf'].to_i > (Time.now.to_i + leeway)
75
+ fail(JWT::ImmatureSignature, 'Signature nbf has not been reached')
76
+ end
77
+ end
78
+
79
+ def verify_sub
80
+ return unless (options_sub = extract_option(:sub))
81
+
82
+ fail(
83
+ JWT::InvalidSubError,
84
+ "Invalid subject. Expected #{options_sub}, received #{@payload['sub'] || '<none>'}"
85
+ ) unless @payload['sub'].to_s == options_sub.to_s
86
+ end
87
+
88
+ private
89
+
90
+ def extract_option(key)
91
+ @options.values_at(key.to_sym, key.to_s).compact.first
92
+ end
93
+
94
+ def leeway
95
+ extract_option :leeway
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ # Moments version builder module
4
+ module JWT
5
+ def self.gem_version
6
+ Gem::Version.new VERSION::STRING
7
+ end
8
+
9
+ # Moments version builder module
10
+ module VERSION
11
+ # major version
12
+ MAJOR = 1
13
+ # minor version
14
+ MINOR = 5
15
+ # tiny version
16
+ TINY = 4
17
+ # alpha, beta, etc. tag
18
+ PRE = nil
19
+
20
+ # Build version string
21
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'jwt/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'jwt'
7
+ spec.version = JWT.gem_version
8
+ spec.authors = [
9
+ 'Jeff Lindsay',
10
+ 'Tim Rudat'
11
+ ]
12
+ spec.email = 'timrudat@gmail.com'
13
+ spec.summary = 'JSON Web Token implementation in Ruby'
14
+ spec.description = 'A pure ruby implementation of the RFC 7519 OAuth JSON Web Token (JWT) standard.'
15
+ spec.homepage = 'http://github.com/jwt/ruby-jwt'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = %w(lib)
22
+
23
+ spec.add_development_dependency 'bundler'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'rspec'
26
+ spec.add_development_dependency 'simplecov'
27
+ spec.add_development_dependency 'simplecov-json'
28
+ spec.add_development_dependency 'codeclimate-test-reporter'
29
+ end
@@ -0,0 +1,8 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BggqhkjOPQMBBw==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MHcCAQEEIJmVse5uPfj6B4TcXrUAvf9/8pJh+KrKKYLNcmOnp/vPoAoGCCqGSM49
6
+ AwEHoUQDQgAEAr+WbDE5VtIDGhtYMxvEc6cMsDBc/DX1wuhIMu8dQzOLSt0tpqK9
7
+ MVfXbVfrKdayVFgoWzs8MilcYq0QIhKx/w==
8
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,4 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAr+WbDE5VtIDGhtYMxvEc6cMsDBc
3
+ /DX1wuhIMu8dQzOLSt0tpqK9MVfXbVfrKdayVFgoWzs8MilcYq0QIhKx/w==
4
+ -----END PUBLIC KEY-----
@@ -0,0 +1,8 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BgUrgQQACg==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MHQCAQEEICfA4AaomONdmPTzeyrx5U/jugYXTERyb5U3ETTv7Hx7oAcGBSuBBAAK
6
+ oUQDQgAEPmuXZT3jpJnEMVPOW6RMsmxeGLOCE1PN6fwvUwOsxv7YnyoQ5/bpo64n
7
+ +Jp4slSl1aUNoCBF2oz9bS0iyBo3jg==
8
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,4 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEPmuXZT3jpJnEMVPOW6RMsmxeGLOCE1PN
3
+ 6fwvUwOsxv7YnyoQ5/bpo64n+Jp4slSl1aUNoCBF2oz9bS0iyBo3jg==
4
+ -----END PUBLIC KEY-----
@@ -0,0 +1,9 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BgUrgQQAIg==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MIGkAgEBBDDxOljqUKw9YNhkluSJIBAYO1YXcNtS+vckd5hpTZ5toxsOlwbmyrnU
6
+ Tn+D5Xma1m2gBwYFK4EEACKhZANiAASQwYTiRvXu1hMHceSosMs/8uf50sJI3jvK
7
+ kdSkvuRAPxSzhtrUvCQDnVsThFq4aOdZZY1qh2ErJGtzmrx+pEsJvJnvfOTG3NGU
8
+ KRalek+LQfVqAUSvDMKlxdkz2e67tso=
9
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,5 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkMGE4kb17tYTB3HkqLDLP/Ln+dLCSN47
3
+ ypHUpL7kQD8Us4ba1LwkA51bE4RauGjnWWWNaodhKyRrc5q8fqRLCbyZ73zkxtzR
4
+ lCkWpXpPi0H1agFErwzCpcXZM9nuu7bK
5
+ -----END PUBLIC KEY-----
@@ -0,0 +1,9 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BgUrgQQAIg==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MIGkAgEBBDAfZW47dSKnC5JkSVOk1ERxCIi/IJ1p1WBnVGx4hnrNHy+dxtaZJaF+
6
+ YLInFQ/QbYegBwYFK4EEACKhZANiAAQwXkx4BFBGLXbzl5yVrfxK7er8hSi38iDE
7
+ K2+7cdrR137Wn5JUnL4WTwXTzkyUgfBOL3sHNozwfgU03GD/EOUEKqzsIJiz2cbP
8
+ bFALd4hS+8T4szDLVC9Jl1W6k0CAtmM=
9
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,5 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEMF5MeARQRi1285ecla38Su3q/IUot/Ig
3
+ xCtvu3Ha0dd+1p+SVJy+Fk8F085MlIHwTi97BzaM8H4FNNxg/xDlBCqs7CCYs9nG
4
+ z2xQC3eIUvvE+LMwy1QvSZdVupNAgLZj
5
+ -----END PUBLIC KEY-----
@@ -0,0 +1,10 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BgUrgQQAIw==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MIHcAgEBBEIB0/+ffxEj7j62xvGaB5pvzk888e412ESO/EK/K0QlS9dSF8+Rj1rG
6
+ zqpRB8fvDnoe8xdmkW/W5GKzojMyv7YQYumgBwYFK4EEACOhgYkDgYYABAEw74Yw
7
+ aTbPY6TtWmxx6LJDzCX2nKWCPnKdZcEH9Ncu8g5RjRBRq2yacja3OoS6nA2YeDng
8
+ reBJxZr376P6Ns6XcQFWDA6K/MCTrEBCsPxXZNxd8KR9vMGWhgNtWRrcKzwJfQkr
9
+ suyehZkbbYyFnAWyARKHZuV7VUXmeEmRS/f93MPqVA==
10
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,6 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBMO+GMGk2z2Ok7VpsceiyQ8wl9pyl
3
+ gj5ynWXBB/TXLvIOUY0QUatsmnI2tzqEupwNmHg54K3gScWa9++j+jbOl3EBVgwO
4
+ ivzAk6xAQrD8V2TcXfCkfbzBloYDbVka3Cs8CX0JK7LsnoWZG22MhZwFsgESh2bl
5
+ e1VF5nhJkUv3/dzD6lQ=
6
+ -----END PUBLIC KEY-----
@@ -0,0 +1,10 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BgUrgQQAIw==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MIHbAgEBBEG/KbA2oCbiCT6L3V8XSz2WKBy0XhGvIFbl/ZkXIXnkYt+1B7wViSVo
6
+ KCHuMFsi6xU/5nE1EuDG2UsQJmKeAMkIOKAHBgUrgQQAI6GBiQOBhgAEAG0TFWe5
7
+ cZ5DZIyfuysrCoQySTNxd+aT8sPIxsx7mW6YBTsuO6rEgxyegd2Auy4xtikxpzKv
8
+ soMXR02999Aaus2jAAt/wxrhhr41BDP4MV0b6Zngb72hna0pcGqit5OyU8AbOJUZ
9
+ +rdyowRGsOY+aPbOyVhdNcsEdxYC8GdIyCQLBC1H
10
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,6 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAbRMVZ7lxnkNkjJ+7KysKhDJJM3F3
3
+ 5pPyw8jGzHuZbpgFOy47qsSDHJ6B3YC7LjG2KTGnMq+ygxdHTb330Bq6zaMAC3/D
4
+ GuGGvjUEM/gxXRvpmeBvvaGdrSlwaqK3k7JTwBs4lRn6t3KjBEaw5j5o9s7JWF01
5
+ ywR3FgLwZ0jIJAsELUc=
6
+ -----END PUBLIC KEY-----
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICXgIBAAKBgQDO/ahgFDvniFoQ1dm+MdnkBi+Ts5W9AtQNgw4ZHIdPnqEzSgW7
3
+ 0opKEu8hnlLqsIyU2BC2op/xOanipdbXObuFlA6bth1cYRI+YJlR3BbPGOIL6YbJ
4
+ ud9m0gIsBlCDLm4e/E45ZS+emudISP7/SF7zxvxZlnr1z7HTm7nIIVBvuQIDAQAB
5
+ AoGBAMzFQAccvU6GI6O4C5sOsiHUxMh3xtCftaxQVGgfQvVPVuXoeteep1Q0ewFl
6
+ IV4vnkO5pH8pTtVTWG9x5KIy6QCql4qvr2jkOm4mo9uogrpNklvBl2lN4Lxubj0N
7
+ mGRXaM3hckZl8+JT6uzfBfjy+pd8AOigJGPQCOZn4gmANW7pAkEA82Nh4wpj6ZRU
8
+ NBiBq3ONZuH4xJm59MI2FWRJsGUFUYdSaFwyKKim52/13d8iUb7v9utWQFRatCXz
9
+ Lqw9fQyVrwJBANm3dBOVxpUPrYEQsG0q2rdP+u6U3woylxwtQgJxImZKZmmJlPr8
10
+ 9v23rhydvCe1ERPYe7EjF4RGWVPN3KLdExcCQDdzNfL3BApMS97OkoRQQC/nXbjU
11
+ 2SPlN1MqVQuGCG8pqGG0V40h11y1CkvxMS10ldEojq77SOrwFnZUsXGS82sCQQC6
12
+ XdO7QCaxSq5XIRYlHN4EtS40NLOIYy3/LK6osHel4GIyTVd+UjSLk0QzssJxqwln
13
+ V5TqWQO0cxPcLQiFUYEZAkEA2G84ilb9QXOgbNyoE1VifNk49hhodbSskLb86uwY
14
+ Vgtzq1ZsqoPBCasr4WRiXt270n+mo5dNYRlZwiUn9lH78Q==
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,6 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO/ahgFDvniFoQ1dm+MdnkBi+T
3
+ s5W9AtQNgw4ZHIdPnqEzSgW70opKEu8hnlLqsIyU2BC2op/xOanipdbXObuFlA6b
4
+ th1cYRI+YJlR3BbPGOIL6YbJud9m0gIsBlCDLm4e/E45ZS+emudISP7/SF7zxvxZ
5
+ lnr1z7HTm7nIIVBvuQIDAQAB
6
+ -----END PUBLIC KEY-----
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpAIBAAKCAQEA4GzZTLU48c4WbyvHi+QKrB71x+T0eq5hqDbQqnlYjhD1Ika7
3
+ io1iplsdJWJuyxfYbUkb2Ol0fj4koZ/GS6lgCZr4+8UHbr1qf0Eu5HZSpszs2YxY
4
+ 8U5RHnrpw67co7hlgAR9HbyNf5XIYgLV9ldHH/eazwnc3F/hgNsV0xjScVilejgo
5
+ cJ4zcsyymvW8t42lteM7bI867ZuJhGop/V+Y0HFyrMsPoQyLuCUpr6ulOfrkr7ZO
6
+ dhAIG8r1HcjOp/AUjM15vfXcbUZjkM/VloifX1YitU3upMGJ8/DpFGffMOImrn5r
7
+ 6BT494V8rRyN2qvQoAkLJpqZ0avLxwiR2lgVQQIDAQABAoIBAEH0Ozgr2fxWEInD
8
+ V/VooypKPvjr9F1JejGxSkmPN9MocKIOH3dsbZ1uEXa3ItBUxan4XlK06SNgp+tH
9
+ xULfF/Y6sQlsse59hBq50Uoa69dRShn1AP6JgZVvkduMPBNxUYL5zrs6emsQXb9Q
10
+ DglDRQfEAJ7vyxSIqQDxYcyT8uSUF70dqFe+E9B2VE3D6ccHc98k41pJrAFAUFH1
11
+ wwvDhfyYr7/Ultut9wzpZvU1meF3Vna3GOUHfxrG6wu1G+WIWHGjouzThsc1qiVI
12
+ BtMCJxuCt5fOXRbU4STbMqhB6sZHiOh6J/dZU6JwRYt+IS8FB6kCNFSEWZWQledJ
13
+ XqtYSQECgYEA9nmnFTRj3fTBq9zMXfCRujkSy6X2bOb39ftNXzHFuc+I6xmv/3Bs
14
+ P9tDdjueP/SnCb7i/9hXkpEIcxjrjiqgcvD2ym1hE4q+odMzRAXYMdnmzI34SVZE
15
+ U5hYJcYsXNKrTTleba7QgqdORmyJ9FwqLO40udvmrZMY223XDwgRkOkCgYEA6RkO
16
+ 5wjjrWWp/G1YN3KXZTS1m2/eGrUThohXKAfAjbWWiouNLW2msXrxEWsPRL6xKiHu
17
+ X9cwZwzi3MstAgk+bphUGUVUkGKNDjWHJA25tDYjbPtkd6xbL4eCHsKpNL3HNYr9
18
+ N0CIvgn7qjaHRBem0iK7T6keY4axaSVddEwYapkCgYEA13K5qaB1F4Smcpt8DTWH
19
+ vPe8xUUaZlFzOJLmLCsuwmB2N8Ppg2j7RspcaxJsH021YaB5ftjWm+ipMSr8ZPY/
20
+ 8JlPsNzxuYpTXtNmAbT2KYVm6THEch61dTk6/DIBf1YrpUJbl5by7vJeStL/uBmE
21
+ SGgksL5XIyzs0opuLdaIvFkCgYAyBLWE8AxjFfCvAQuwAj/ocLITo6KmWnrRIIqL
22
+ RXaVMgUWv7FQsTnW1cnK8g05tC2yG8vZ9wQk6Mf5lwOWb0NdWgSZ0528ydj41pWk
23
+ L+nMeN2LMjqxz2NVxJ8wWJcUgTCxFZ0WcRumo9/D+6V1ABpE9zz4cBLcSnfhVypB
24
+ nV6T6QKBgQCSZNCQ9HPxjAgYcsqc5sjNwuN1GHQZSav3Tye3k6zHENe1lsteT9K8
25
+ xciGIuhybKZBvB4yImIIHCtnH+AS+mHAGqHarjNDMfvjOq0dMibPx4+bkIiHdBIH
26
+ Xz+j5kmntvFiUnzr0Z/Tcqo+r8FvyCo1YWgwqGP8XoFrswD7gy7cZw==
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,9 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4GzZTLU48c4WbyvHi+QK
3
+ rB71x+T0eq5hqDbQqnlYjhD1Ika7io1iplsdJWJuyxfYbUkb2Ol0fj4koZ/GS6lg
4
+ CZr4+8UHbr1qf0Eu5HZSpszs2YxY8U5RHnrpw67co7hlgAR9HbyNf5XIYgLV9ldH
5
+ H/eazwnc3F/hgNsV0xjScVilejgocJ4zcsyymvW8t42lteM7bI867ZuJhGop/V+Y
6
+ 0HFyrMsPoQyLuCUpr6ulOfrkr7ZOdhAIG8r1HcjOp/AUjM15vfXcbUZjkM/Vloif
7
+ X1YitU3upMGJ8/DpFGffMOImrn5r6BT494V8rRyN2qvQoAkLJpqZ0avLxwiR2lgV
8
+ QQIDAQAB
9
+ -----END PUBLIC KEY-----
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpAIBAAKCAQEAzHAVGaW9j4l3/b4ngcjjoIoIcnsQEWOMqErb5VhLZMGIq1gE
3
+ O5qxPDAwooKsNotzcAOB3ZyLn7p5D+dmOrNUYkYWgYITNGeSifrnVqQugd5Fh1L8
4
+ K7zOGltUo2UtjbN4uJ56tzxBMZp2wejs2/Qu0eu0xZK3To+YkDcWOk92rmNgmUSQ
5
+ C/kNyIOj+yBvOo3wTk6HvbhoIarCgJ6Lay1v/hMLyQLzwRY/Qfty1FTIDyTv2dch
6
+ 47FsfkZ1KAL+MbUnHuCBPzGxRjXa8Iy9Z7YGxrYasUt1b0um64bscxoIiCu8yLL8
7
+ jlg01Rwrjr/MTwKRhwXlMp8B7HTonwtaG6arJwIDAQABAoIBAGFR4dmJusl/qW1T
8
+ fj8cQLAFxaupxaZhe24J5NAyzgEy2Dqo9ariIwkB78UM66ozjEqAgOvcP+NTw5m8
9
+ kD/VapA1yTTxlO7XdzzUAhiOo80S4IphCMZRZNPLMmluGtdf3lIUr1pXBrn0TCBX
10
+ H5o9jaREzpNXGof9d6T/dEdh2J9+uE/p1xE5GSxQfaPheZzCG7636La/DcArg/UR
11
+ +TusPqp62BEmk96pE/KKJRmEeH+WnPfSh6sMpLxi3hkEU7AynpliGT6Z6xV4csBI
12
+ S/rdpkcj5DWpbnQzkwdrnL2Q+POEq/vlx5/NlezvtQPNLvQWDyY4yBCoMKGb3EbX
13
+ xrxP7MECgYEA/kwe4P0Mqk+087IyhjDBGPfcMt8gfYc9nzNfIYSWdSwuSag/hqHq
14
+ I4GwHQzUV9ix3iM6w5hin10yAzWxCYZg9hquV+lSvNNpGB76FX6oOqwuAhyQMRwv
15
+ eW+VUyfFXeJugwL5JuIaNTvwPpQVDHYtELLifie+uzJ5HC6dhg/XchcCgYEAzc5/
16
+ +IXjOlExd/mBgFk/5Y87ifA0ZOgbaJXifYgU0aNSgz1piHxU3n2p4jJ9lSdwwCl2
17
+ Fb5EN7666t20PL5QcXJ5ZdaTRLzRlYiqTWzfYHBgttbB1Jl3Ed9GsKuzRgaRqGFC
18
+ ANJSqZlKG0NZ3keRtuKdFwq+IVOnsQr9g0TZiXECgYEAqUgtCiMKCloTIGMQpSnR
19
+ cXiWWjsUmturls4Q1vQ3YHrvuVLKLyqb/dT4Uu5WcMAs765OESThCit0/pQAbVHK
20
+ PCpYwubskAzAGjGM00BEZwJ1gixXhIm5xMIWCowgI7Z3ULlq+IptXeCvtkjHlksZ
21
+ BtO+WLLGkkEwRCV38WWcSzMCgYA/Xxqgl/mD94RYAQgTUWgPc69Nph08BQyLg7ue
22
+ E8z1UGkT6FEaqc4oRGGPOSTaTK63PQ0TXOb8k0pTD7l0CtYSWMFwzkXCoLGYbeCi
23
+ vqd5tqDRLAe7QxYa9rl5pSUqptMrGeeNATZa6sya4H5Hp5oCyny8n54z/OJh7ZRq
24
+ W0TwwQKBgQDDP7ksm2pcqadaVAmODdOlaDHbaEcxp8wN7YVz0lM3UpJth96ukbj7
25
+ S39eJhXYWOn6oJQb/lN9fGOYqjg3y6IchGZDp67ATvWYvn/NY0R7mt4K4oHx5TuN
26
+ rSQlP3WmOGv8Kemw892uRfW/jZyBEHhsfS213WDttVPn9F635GdNWw==
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,9 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzHAVGaW9j4l3/b4ngcjj
3
+ oIoIcnsQEWOMqErb5VhLZMGIq1gEO5qxPDAwooKsNotzcAOB3ZyLn7p5D+dmOrNU
4
+ YkYWgYITNGeSifrnVqQugd5Fh1L8K7zOGltUo2UtjbN4uJ56tzxBMZp2wejs2/Qu
5
+ 0eu0xZK3To+YkDcWOk92rmNgmUSQC/kNyIOj+yBvOo3wTk6HvbhoIarCgJ6Lay1v
6
+ /hMLyQLzwRY/Qfty1FTIDyTv2dch47FsfkZ1KAL+MbUnHuCBPzGxRjXa8Iy9Z7YG
7
+ xrYasUt1b0um64bscxoIiCu8yLL8jlg01Rwrjr/MTwKRhwXlMp8B7HTonwtaG6ar
8
+ JwIDAQAB
9
+ -----END PUBLIC KEY-----
@@ -0,0 +1,51 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ 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
51
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,14 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqETmgWBi5rCmb7euJplA
3
+ /9xs65+bncc9Yvs5zjyycXSW82JfRuyguGm0OvA2wog24dR4N2kT/87DcGtp5JqJ
4
+ WADVFNr+2V2r6i57/OMLruRpn3p2r95dmo0COE+BxPFl7XEBT8JbH57ZtpgcB3/x
5
+ kS14nLOWFf96hrXPlXJC+VMVKVZmA8k2LRh42vT5wUf4U0Doy/p7yFNSFFa6Q8ww
6
+ e4TBy/z/f+rhFD1w8rxlYjallee/ocm7bjZCwbJGMm7orLViqWfsFX3O35PeoJ5h
7
+ /7uJ7iRwvTFERkTdwWP/0BeKBeItBR3YFc2mut+V9W+WKRkMSL6Crc+oVSx3p8aB
8
+ 7j9SZFzQiRtes4BYETpX1xl2mgIq5hvsFbLw7ESrlIodiwUMTrSIid2DQ6q80kv1
9
+ zXPr4+Id6L0sJLxPCaXnTmNtasSwyedJJYxLjwhHJwtzFAeaq18H3O791YKhjAJ6
10
+ YxK3zJ59jTE6Pkvqjq183f2PGHVRvgSN7aCmI6MBUUB5wDP2K8zX2sh40/uPDVSd
11
+ 6ei1vl3DpPk+h8iExx6AzbohfqZ+5RUUNx127L3MaQvOVC5TxV+R99gwKW++wzcV
12
+ uO3m2KqVUj+K1uYBy3KBCUMBbckpEWGbN++jcdV5oJX6fsC66nOmKlntYwCL/pRw
13
+ w+oLsbzF8J3dxeDbKNF9JDsCAwEAAQ==
14
+ -----END PUBLIC KEY-----
@@ -0,0 +1,175 @@
1
+ require 'spec_helper'
2
+ require 'jwt/verify'
3
+
4
+ module JWT
5
+ RSpec.describe Verify do
6
+ let(:base_payload) { { 'user_id' => 'some@user.tld' } }
7
+ let(:options) { { leeway: 0} }
8
+
9
+ context '.verify_aud(payload, options)' do
10
+ let(:scalar_aud) { 'ruby-jwt-audience' }
11
+ let(:array_aud) { %w(ruby-jwt-aud test-aud ruby-ruby-ruby) }
12
+ let(:scalar_payload) { base_payload.merge('aud' => scalar_aud) }
13
+ let(:array_payload) { base_payload.merge('aud' => array_aud) }
14
+
15
+ it 'must raise JWT::InvalidAudError when the singular audience does not match' do
16
+ expect do
17
+ Verify.verify_aud(scalar_payload, options.merge(aud: 'no-match'))
18
+ end.to raise_error JWT::InvalidAudError
19
+ end
20
+
21
+ it 'must raise JWT::InvalidAudError when the payload has an array and none match the supplied value' do
22
+ expect do
23
+ Verify.verify_aud(array_payload, options.merge(aud: 'no-match'))
24
+ end.to raise_error JWT::InvalidAudError
25
+ end
26
+
27
+ it 'must raise JWT::InvalidAudError when the singular audience does not match and the options aud key is a string' do
28
+ expect do
29
+ Verify.verify_aud(scalar_payload, options.merge('aud' => 'no-match'))
30
+ end.to raise_error JWT::InvalidAudError
31
+ end
32
+
33
+ it 'must allow a matching singular audience to pass' do
34
+ Verify.verify_aud(scalar_payload, options.merge(aud: scalar_aud))
35
+ end
36
+
37
+ it 'must allow a matching audence to pass when the options key is a string' do
38
+ Verify.verify_aud(scalar_payload, options.merge('aud' => scalar_aud))
39
+ end
40
+
41
+ it 'must allow an array with any value matching the one in the options' do
42
+ Verify.verify_aud(array_payload, options.merge(aud: array_aud.first))
43
+ end
44
+
45
+ it 'must allow an array with any value matching the one in the options with a string options key' do
46
+ Verify.verify_aud(array_payload, options.merge('aud' => array_aud.first))
47
+ end
48
+ end
49
+
50
+ context '.verify_expiration(payload, options)' do
51
+ let(:leeway) { 10 }
52
+ let(:payload) { base_payload.merge('exp' => (Time.now.to_i - 5)) }
53
+
54
+ it 'must raise JWT::ExpiredSignature when the token has expired' do
55
+ expect do
56
+ Verify.verify_expiration(payload, options)
57
+ end.to raise_error JWT::ExpiredSignature
58
+ end
59
+
60
+ it 'must allow some leeway in the expiration when configured' do
61
+ Verify.verify_expiration(payload, options.merge(leeway: 10))
62
+ end
63
+ end
64
+
65
+ context '.verify_iat(payload, options)' do
66
+ let(:iat) { Time.now.to_f }
67
+ let(:payload) { base_payload.merge('iat' => iat) }
68
+
69
+ it 'must allow a valid iat' do
70
+ Verify.verify_iat(payload, options)
71
+ end
72
+
73
+ it 'must allow configured leeway' do
74
+ Verify.verify_iat(payload.merge('iat' => (iat + 60)), options.merge(leeway: 70))
75
+ end
76
+
77
+ it 'must properly handle integer times' do
78
+ Verify.verify_iat(payload.merge('iat' => Time.now.to_i), options)
79
+ end
80
+
81
+ it 'must raise JWT::InvalidIatError when the iat value is not Numeric' do
82
+ expect do
83
+ Verify.verify_iat(payload.merge('iat' => 'not a number'), options)
84
+ end.to raise_error JWT::InvalidIatError
85
+ end
86
+
87
+ it 'must raise JWT::InvalidIatError when the iat value is in the future' do
88
+ expect do
89
+ Verify.verify_iat(payload.merge('iat' => (iat + 120)), options)
90
+ end.to raise_error JWT::InvalidIatError
91
+ end
92
+ end
93
+
94
+ context '.verify_iss(payload, options)' do
95
+ let(:iss) { 'ruby-jwt-gem' }
96
+ let(:payload) { base_payload.merge('iss' => iss) }
97
+
98
+ let(:invalid_token) { JWT.encode base_payload, payload[:secret] }
99
+
100
+ it 'must raise JWT::InvalidIssuerError when the configured issuer does not match the payload issuer' do
101
+ expect do
102
+ Verify.verify_iss(payload, options.merge(iss: 'mismatched-issuer'))
103
+ end.to raise_error JWT::InvalidIssuerError
104
+ end
105
+
106
+ it 'must raise JWT::InvalidIssuerError when the payload does not include an issuer' do
107
+ expect do
108
+ Verify.verify_iss(base_payload, options.merge(iss: iss))
109
+ end.to raise_error(JWT::InvalidIssuerError, /received <none>/)
110
+ end
111
+
112
+ it 'must allow a matching issuer to pass' do
113
+ Verify.verify_iss(payload, options.merge(iss: iss))
114
+ end
115
+ end
116
+
117
+ context '.verify_jti(payload, options)' do
118
+ let(:payload) { base_payload.merge('jti' => 'some-random-uuid-or-whatever') }
119
+
120
+ it 'must allow any jti when the verfy_jti key in the options is truthy but not a proc' do
121
+ Verify.verify_jti(payload, options.merge(verify_jti: true))
122
+ end
123
+
124
+ it 'must raise JWT::InvalidJtiError when the jti is missing' do
125
+ expect do
126
+ Verify.verify_jti(base_payload, options)
127
+ end.to raise_error JWT::InvalidJtiError, /missing/i
128
+ end
129
+
130
+ it 'must raise JWT::InvalidJtiError when the jti is an empty string' do
131
+ expect do
132
+ Verify.verify_jti(base_payload.merge('jti' => ' '), options)
133
+ end.to raise_error JWT::InvalidJtiError, /missing/i
134
+ end
135
+
136
+ it 'must raise JWT::InvalidJtiError when verify_jti proc returns false' do
137
+ expect do
138
+ Verify.verify_jti(payload, options.merge(verify_jti: ->(jti) { false }))
139
+ end.to raise_error JWT::InvalidJtiError, /invalid/i
140
+ end
141
+
142
+ it 'true proc should not raise JWT::InvalidJtiError' do
143
+ Verify.verify_jti(payload, options.merge(verify_jti: ->(jti) { true }))
144
+ end
145
+ end
146
+
147
+ context '.verify_not_before(payload, options)' do
148
+ let(:payload) { base_payload.merge('nbf' => (Time.now.to_i + 5)) }
149
+
150
+ it 'must raise JWT::ImmatureSignature when the nbf in the payload is in the future' do
151
+ expect do
152
+ Verify.verify_not_before(payload, options)
153
+ end.to raise_error JWT::ImmatureSignature
154
+ end
155
+
156
+ it 'must allow some leeway in the token age when configured' do
157
+ Verify.verify_not_before(payload, options.merge(leeway: 10))
158
+ end
159
+ end
160
+
161
+ context '.verify_sub(payload, options)' do
162
+ let(:sub) { 'ruby jwt subject' }
163
+
164
+ it 'must raise JWT::InvalidSubError when the subjects do not match' do
165
+ expect do
166
+ Verify.verify_sub(base_payload.merge('sub' => 'not-a-match'), options.merge(sub: sub))
167
+ end.to raise_error JWT::InvalidSubError
168
+ end
169
+
170
+ it 'must allow a matching sub' do
171
+ Verify.verify_sub(base_payload.merge('sub' => sub), options.merge(sub: sub))
172
+ end
173
+ end
174
+ end
175
+ end