diff --git a/lib/jwt/algos/none.rb b/lib/jwt/algos/none.rb new file mode 100644 index 00000000..1085ae35 --- /dev/null +++ b/lib/jwt/algos/none.rb @@ -0,0 +1,21 @@ +module JWT + module Algos + module None + # Unsecured JWT + module_function + + SUPPORTED = %w[none].freeze + + def sign(to_sign) + raise EncodeError, 'Signing key not supported for Unsecured JWT' if to_sign.key + '' + end + + def verify(to_verify) + raise VerificationError, 'Signing key not supported for Unsecured JWT' if to_verify.public_key + raise VerificationError, 'Signature should be empty for Unsecured JWT' unless to_verify.signature == '' + true + end + end + end +end diff --git a/lib/jwt/decode.rb b/lib/jwt/decode.rb index c44f755f..89495f42 100644 --- a/lib/jwt/decode.rb +++ b/lib/jwt/decode.rb @@ -13,7 +13,7 @@ def initialize(jwt, key, verify, options, &keyfinder) @jwt = jwt @key = key @options = options - @segments = jwt.split('.') + @segments = jwt.split('.', -1) @verify = verify @signature = '' @keyfinder = keyfinder @@ -66,7 +66,6 @@ def verify_claims def validate_segment_count! return if segment_length == 3 - return if !@verify && segment_length == 2 # If no verifying required, the signature is not needed raise(JWT::DecodeError, 'Not enough or too many segments') end diff --git a/lib/jwt/encode.rb b/lib/jwt/encode.rb index 35ddba79..fa42f516 100644 --- a/lib/jwt/encode.rb +++ b/lib/jwt/encode.rb @@ -52,8 +52,6 @@ def encode_payload end def encode_signature - return '' if @algorithm == ALG_NONE - JWT::Base64.url_encode(JWT::Signature.sign(@algorithm, encoded_header_and_payload, @key)) end diff --git a/lib/jwt/signature.rb b/lib/jwt/signature.rb index bd933201..ca01e712 100644 --- a/lib/jwt/signature.rb +++ b/lib/jwt/signature.rb @@ -7,6 +7,7 @@ require 'jwt/algos/ecdsa' require 'jwt/algos/rsa' require 'jwt/algos/ps' +require 'jwt/algos/none' require 'jwt/algos/unsupported' begin require 'rbnacl' @@ -25,6 +26,7 @@ module Signature Algos::Rsa, Algos::Eddsa, Algos::Ps, + Algos::None, Algos::Unsupported ].freeze ToSign = Struct.new(:algorithm, :msg, :key) diff --git a/spec/jwt_spec.rb b/spec/jwt_spec.rb index 0fd5e64b..6472b79d 100644 --- a/spec/jwt_spec.rb +++ b/spec/jwt_spec.rb @@ -44,6 +44,7 @@ context 'alg: NONE' do let(:alg) { 'none' } + let(:sig) { 'kWOVtIOpWcG7JnyJG0qOkTDbOy636XrrQhMm_8JrRQ8' } it 'should generate a valid token' do token = JWT.encode payload, nil, alg @@ -51,12 +52,37 @@ expect(token).to eq data['NONE'] end + it 'with key should raise JWT::EncodeError' do + expect do + JWT.encode payload, data[:secret], alg + end.to raise_error JWT::EncodeError, 'Signing key not supported for Unsecured JWT' + end + it 'should decode a valid token' do jwt_payload, header = JWT.decode data['NONE'], nil, false expect(header['alg']).to eq alg expect(jwt_payload).to eq payload end + + it 'should decode and verify a valid token' do + jwt_payload, header = JWT.decode data['NONE'], nil, true, algorithm: alg + + expect(header['alg']).to eq alg + expect(jwt_payload).to eq payload + end + + it 'with signature should raise JWT::VerificationError' do + expect do + JWT.decode data['NONE'] + sig, nil, true, algorithm: alg + end.to raise_error JWT::VerificationError, 'Signature should be empty for Unsecured JWT' + end + + it 'with key should raise JWT::VerificationError' do + expect do + JWT.decode data['NONE'], data[:secret], true, algorithm: alg + end.to raise_error JWT::VerificationError, 'Signing key not supported for Unsecured JWT' + end end context 'payload validation' do @@ -358,12 +384,6 @@ end end - context 'a token with two segments but does not require verifying' do - it 'raises something else than "Not enough or too many segments"' do - expect { JWT.decode('ThisIsNotAValidJWTToken.second', nil, false) }.to raise_error(JWT::DecodeError, 'Invalid segment encoding') - end - end - context 'Base64' do it 'urlsafe replace + / with - _' do allow(Base64).to receive(:encode64) { 'string+with/non+url-safe/characters_' }