module Rack module OAuth2 class AccessToken class MAC < AccessToken attr_required :mac_key, :mac_algorithm attr_optional :issued_at, :ext attr_reader :nonce, :body_hash, :signature def initialize(attributes = {}) super(attributes) @issued_at ||= Time.now.utc end def token_response super.merge( :mac_key => mac_key, :mac_algorithm => mac_algorithm ) end def verify!(request) if request.body_hash.present? BodyHash.new( :raw_body => request.body.read, :algorithm => self.mac_algorithm ).verify!(request.body_hash) end Signature.new( :secret => self.mac_key, :algorithm => self.mac_algorithm, :nonce => request.nonce, :method => request.request_method, :request_uri => request.fullpath, :host => request.host, :port => request.port, :body_hash => request.body_hash, :ext => request.ext ).verify!(request.signature) rescue Verifier::VerificationFailed => e request.invalid_token! e.message end def authenticate(request) @nonce = generate_nonce if request.contenttype == 'application/x-www-form-urlencoded' @body_hash = BodyHash.new( :raw_body => request.body, :algorithm => self.mac_algorithm ).calculate end @signature = Signature.new( :secret => self.mac_key, :algorithm => self.mac_algorithm, :nonce => self.nonce, :method => request.header.request_method, :request_uri => request.header.create_query_uri, :host => request.header.request_uri.host, :port => request.header.request_uri.port, :body_hash => self.body_hash, :ext => self.ext ).calculate request.header['Authorization'] = authorization_header end private def authorization_header header = "MAC" header << " id=\"#{access_token}\"," header << " nonce=\"#{nonce}\"," header << " bodyhash=\"#{body_hash}\"," if body_hash.present? header << " ext=\"#{ext}\"," if ext.present? header << " mac=\"#{signature}\"" end def generate_nonce [ (Time.now.utc - @issued_at).to_i, ActiveSupport::SecureRandom.hex ].join(':') end end end end end require 'rack/oauth2/access_token/mac/verifier' require 'rack/oauth2/access_token/mac/body_hash' require 'rack/oauth2/access_token/mac/signature'