lib/jwt.rb in jwt-1.4.0 vs lib/jwt.rb in jwt-1.4.1

- old
+ new

@@ -2,13 +2,13 @@ # JSON Web Token implementation # # Should be up to date with the latest spec: # http://self-issued.info/docs/draft-jones-json-web-token-06.html -require "base64" -require "openssl" -require "jwt/json" +require 'base64' +require 'openssl' +require 'jwt/json' module JWT class DecodeError < StandardError; end class VerificationError < DecodeError; end class ExpiredSignature < DecodeError; end @@ -21,71 +21,71 @@ extend JWT::Json module_function def sign(algorithm, msg, key) - if ["HS256", "HS384", "HS512"].include?(algorithm) + if ['HS256', 'HS384', 'HS512'].include?(algorithm) sign_hmac(algorithm, msg, key) - elsif ["RS256", "RS384", "RS512"].include?(algorithm) + elsif ['RS256', 'RS384', 'RS512'].include?(algorithm) sign_rsa(algorithm, msg, key) else - raise NotImplementedError.new("Unsupported signing method") + raise NotImplementedError.new('Unsupported signing method') end end def sign_rsa(algorithm, msg, private_key) - private_key.sign(OpenSSL::Digest.new(algorithm.sub("RS", "sha")), msg) + private_key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg) end def verify_rsa(algorithm, public_key, signing_input, signature) - public_key.verify(OpenSSL::Digest.new(algorithm.sub("RS", "sha")), signature, signing_input) + public_key.verify(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), signature, signing_input) end def sign_hmac(algorithm, msg, key) - OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub("HS", "sha")), key, msg) + OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub('HS', 'sha')), key, msg) end def base64url_decode(str) - str += "=" * (4 - str.length.modulo(4)) - Base64.decode64(str.tr("-_", "+/")) + str += '=' * (4 - str.length.modulo(4)) + Base64.decode64(str.tr('-_', '+/')) end def base64url_encode(str) - Base64.encode64(str).tr("+/", "-_").gsub(/[\n=]/, "") + Base64.encode64(str).tr('+/', '-_').gsub(/[\n=]/, '') end - def encoded_header(algorithm="HS256", header_fields={}) - header = {"typ" => "JWT", "alg" => algorithm}.merge(header_fields) + def encoded_header(algorithm='HS256', header_fields={}) + header = {'typ' => 'JWT', 'alg' => algorithm}.merge(header_fields) base64url_encode(encode_json(header)) end def encoded_payload(payload) base64url_encode(encode_json(payload)) end def encoded_signature(signing_input, key, algorithm) - if algorithm == "none" - "" + if algorithm == 'none' + '' else signature = sign(algorithm, signing_input, key) base64url_encode(signature) end end - def encode(payload, key, algorithm="HS256", header_fields={}) - algorithm ||= "none" + def encode(payload, key, algorithm='HS256', header_fields={}) + algorithm ||= 'none' segments = [] segments << encoded_header(algorithm, header_fields) segments << encoded_payload(payload) - segments << encoded_signature(segments.join("."), key, algorithm) - segments.join(".") + segments << encoded_signature(segments.join('.'), key, algorithm) + segments.join('.') end def raw_segments(jwt, verify=true) - segments = jwt.split(".") + segments = jwt.split('.') required_num_segments = verify ? [3] : [2,3] - raise JWT::DecodeError.new("Not enough or too many segments") unless required_num_segments.include? segments.length + raise JWT::DecodeError.new('Not enough or too many segments') unless required_num_segments.include? segments.length segments end def decode_header_and_payload(header_segment, payload_segment) header = decode_json(base64url_decode(header_segment)) @@ -95,28 +95,28 @@ def decoded_segments(jwt, verify=true) header_segment, payload_segment, crypto_segment = raw_segments(jwt, verify) header, payload = decode_header_and_payload(header_segment, payload_segment) signature = base64url_decode(crypto_segment.to_s) if verify - signing_input = [header_segment, payload_segment].join(".") + signing_input = [header_segment, payload_segment].join('.') [header, payload, signature, signing_input] end def decode(jwt, key=nil, verify=true, options={}, &keyfinder) - raise JWT::DecodeError.new("Nil JSON web token") unless jwt + raise JWT::DecodeError.new('Nil JSON web token') unless jwt header, payload, signature, signing_input = decoded_segments(jwt, verify) - raise JWT::DecodeError.new("Not enough or too many segments") unless header && payload + raise JWT::DecodeError.new('Not enough or too many segments') unless header && payload default_options = { :verify_expiration => true, :verify_not_before => true, - :verify_iss => true, - :verify_iat => true, - :verify_jti => true, - :verify_aud => true, - :verify_sub => true, + :verify_iss => false, + :verify_iat => false, + :verify_jti => false, + :verify_aud => false, + :verify_sub => false, :leeway => 0 } options = default_options.merge(options) @@ -124,34 +124,34 @@ algo, key = signature_algorithm_and_key(header, key, &keyfinder) verify_signature(algo, key, signing_input, signature) end if options[:verify_expiration] && payload.include?('exp') - raise JWT::ExpiredSignature.new("Signature has expired") unless payload['exp'].to_i > (Time.now.to_i - options[:leeway]) + raise JWT::ExpiredSignature.new('Signature has expired') unless payload['exp'].to_i > (Time.now.to_i - options[:leeway]) end if options[:verify_not_before] && payload.include?('nbf') - raise JWT::ImmatureSignature.new("Signature nbf has not been reached") unless payload['nbf'].to_i < (Time.now.to_i + options[:leeway]) + raise JWT::ImmatureSignature.new('Signature nbf has not been reached') unless payload['nbf'].to_i < (Time.now.to_i + options[:leeway]) end if options[:verify_iss] && payload.include?('iss') - raise JWT::InvalidIssuerError.new("Invalid issuer") unless payload['iss'].to_s == options['iss'].to_s + raise JWT::InvalidIssuerError.new("Invalid issuer. Expected #{options['iss']}, received #{payload['iss']}") unless payload['iss'].to_s == options['iss'].to_s end if options[:verify_iat] && payload.include?('iat') - raise JWT::InvalidIatError.new("Invalid iat") unless (payload['iat'].is_a?(Integer) and payload['iat'].to_i <= Time.now.to_i) + raise JWT::InvalidIatError.new('Invalid iat') unless (payload['iat'].is_a?(Integer) and payload['iat'].to_i <= Time.now.to_i) end if options[:verify_aud] && payload.include?('aud') if payload['aud'].is_a?(Array) - raise JWT::InvalidAudError.new("Invalid audience") unless payload['aud'].include?(options['aud']) + raise JWT::InvalidAudError.new('Invalid audience') unless payload['aud'].include?(options['aud']) else - raise JWT::InvalidAudError.new("Invalid audience") unless payload['aud'].to_s == options['aud'].to_s + raise JWT::InvalidAudError.new("Invalid audience. Expected #{options['aud']}, received #{payload['aud']}") unless payload['aud'].to_s == options['aud'].to_s end end if options[:verify_sub] && payload.include?('sub') - raise JWT::InvalidSubError.new("Invalid subject") unless payload['sub'].to_s == options['sub'].to_s + raise JWT::InvalidSubError.new("Invalid subject. Expected #{options['sub']}, received #{payload['sub']}") unless payload['sub'].to_s == options['sub'].to_s end if options[:verify_jti] && payload.include?('jti') - raise JWT::InvalidJtiError.new("need iat for verify jwt id") unless payload.include?('iat') - raise JWT::InvalidJtiError.new("Not a uniq jwt id") unless options['jti'].to_s == Digest::MD5.hexdigest("#{key}:#{payload['iat']}") + raise JWT::InvalidJtiError.new('need iat for verify jwt id') unless payload.include?('iat') + raise JWT::InvalidJtiError.new('Not a uniq jwt id') unless options['jti'].to_s == Digest::MD5.hexdigest("#{key}:#{payload['iat']}") end return payload,header end @@ -162,18 +162,18 @@ [header['alg'], key] end def verify_signature(algo, key, signing_input, signature) begin - if ["HS256", "HS384", "HS512"].include?(algo) - raise JWT::VerificationError.new("Signature verification failed") unless secure_compare(signature, sign_hmac(algo, signing_input, key)) - elsif ["RS256", "RS384", "RS512"].include?(algo) - raise JWT::VerificationError.new("Signature verification failed") unless verify_rsa(algo, key, signing_input, signature) + if ['HS256', 'HS384', 'HS512'].include?(algo) + raise JWT::VerificationError.new('Signature verification failed') unless secure_compare(signature, sign_hmac(algo, signing_input, key)) + elsif ['RS256', 'RS384', 'RS512'].include?(algo) + raise JWT::VerificationError.new('Signature verification failed') unless verify_rsa(algo, key, signing_input, signature) else - raise JWT::VerificationError.new("Algorithm not supported") + raise JWT::VerificationError.new('Algorithm not supported') end rescue OpenSSL::PKey::PKeyError - raise JWT::VerificationError.new("Signature verification failed") + raise JWT::VerificationError.new('Signature verification failed') ensure OpenSSL.errors.clear end end