lib/rack/simple_auth/hmac.rb in rack-simple_auth-0.1.0 vs lib/rack/simple_auth/hmac.rb in rack-simple_auth-0.1.1

- old
+ new

@@ -8,115 +8,120 @@ # @param [Hash] config [config hash where tolerance, secret, signature etc.. are set] def initialize(app, config) @app = app @signature = config['signature'] || '' @secret = config['secret'] || '' - @tolerance = config['tolerance'] || 0 # 0 if tolerance not set in config hash + @tolerance = config['tolerance'] || 1 # 0 if tolerance not set in config hash @logpath = config['logpath'] @steps = config['steps'] || 1 + valid_stepsize?(0.01) + valid_tolerance? + @config = config end # call Method for Rack Middleware/Application # @param [Hash] env [Rack Env Hash which contains headers etc..] def call(env) - request = Rack::Request.new(env) - if valid?(request) + @request = Rack::Request.new(env) + + if valid_request? @app.call(env) else response = Rack::Response.new('Unauthorized', 401, 'Content-Type' => 'text/html') response.finish end end # checks for valid HMAC Request - # @param [Rack::Request] request [current Request] # @return [boolean] ValidationStatus [If authorized returns true, else false] - def valid?(request) - hash_array = build_allowed_messages(request) + def valid_request? + if @request.env['HTTP_AUTHORIZATION'].nil? + log(allowed_messages) - if request.env['HTTP_AUTHORIZATION'].nil? - log(request, hash_array) - return false end - auth_array = request.env['HTTP_AUTHORIZATION'].split(':') - message_hash = auth_array[0] - signature = auth_array[1] - - if signature == @signature && hash_array.include?(message_hash) + if request_signature == @signature && allowed_messages.include?(request_message) true else - log(request, hash_array) + log(allowed_messages) false end end + private + + # Get request signature + def request_signature + @request.env['HTTP_AUTHORIZATION'].split(':').last + end + + # Get encrypted request message + def request_message + @request.env['HTTP_AUTHORIZATION'].split(':').first + end + # Builds Array of allowed message hashs - # @param [Rack::Request] request [current Request] # @return [Array] hash_array [allowed message hashes as array] - def build_allowed_messages(request) - hash_array = [] + def allowed_messages + messages = [] (-(@tolerance)..@tolerance).step(@steps) do |i| i = i.round(2) - hash_array << OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), @secret, message(request, i)) + messages << OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), @secret, message(i)) end - hash_array + messages end # Get Message for current Request and delay - # @param [Rack::Request] request [current Request] # @param [Fixnum] delay [delay in timestamp format] # @return [Hash] message [message which will be encrypted] - def message(request, delay = 0) + def message(delay = 0) date = Time.now.to_i + delay + date = date.to_i if delay.eql?(0.0) - if delay.eql?(0.0) - date = date.to_i - end - - case request.request_method + case @request.request_method when 'GET' - return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json + return { 'method' => @request.request_method, 'date' => date, 'data' => request_data(@config) }.to_json when 'POST' - return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json + return { 'method' => @request.request_method, 'date' => date, 'data' => request_data(@config) }.to_json when 'DELETE' - return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json + return { 'method' => @request.request_method, 'date' => date, 'data' => request_data(@config) }.to_json when 'PUT' - return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json + return { 'method' => @request.request_method, 'date' => date, 'data' => request_data(@config) }.to_json when 'PATCH' - return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json + return { 'method' => @request.request_method, 'date' => date, 'data' => request_data(@config) }.to_json end end # Get Request Data specified by Config - # @param [Rack::Request] request [current Request] # @param [Hash] config [Config Hash containing what type of info is data for each request] # @return [String|Hash] data [Data for each request] - def request_data(request, config) - if config[request.request_method] == 'path' || config[request.request_method] == 'params' - request.send(config[request.request_method].to_sym) + def request_data(config) + if config[@request.request_method] == 'path' || config[@request.request_method] == 'params' + @request.send(config[@request.request_method].to_sym) else - fail "Not a valid option #{config[request.request_method]} - Use either params or path" + fail "Not a valid option #{config[@request.request_method]} - Use either params or path" end end # Log to @logpath if request is unathorized - # @param [Rack::Request] request [current Request] - def log(request, hash_array) + # Contains: + # - allowed messages and received message + # - time when request was made + # - type of request + # - requested path + def log(hash_array) if @logpath - path = request.path - method = request.request_method + log = "#{Time.new} - #{@request.request_method} #{@request.path} - 400 Unauthorized\n" + log << "HTTP_AUTHORIZATION: #{@request.env['HTTP_AUTHORIZATION']}\n" + log << "Auth Message Config: #{@config[@request.request_method]}\n" - log = "#{Time.new} - #{method} #{path} - 400 Unauthorized - HTTP_AUTHORIZATION: #{request.env['HTTP_AUTHORIZATION']}\n" - log << "Auth Message Config: #{@config[request.request_method]}\n" - if hash_array log << "Allowed Encrypted Messages:\n" hash_array.each do |hash| log << "#{hash}\n" end @@ -128,9 +133,23 @@ f << "#{log}\n" end end end - private :log, :request_data, :message, :valid?, :build_allowed_messages + # Check if Stepsize is valid, if > min ensure stepsize is min stepsize + # @param [float] min [minimum allowed stepsize] + def valid_stepsize?(min) + if @steps < min + puts "Warning: Minimum allowed stepsize is #{min}" + @steps = min + end + end + + # Check if tolerance is valid, tolerance must be greater than stepsize + def valid_tolerance? + if @tolerance < @steps + fail "Tolerance must be greater than stepsize - Tolerance: #{@tolerance}, Stepsize: #{@steps}" + end + end end end end