@param header [String] an Authorization header @return [Hash<String, String>] parsed authorization parameters @raise [OAuthenticator::ParseError] if the header is not well-formed and cannot be parsed @raise [OAuthenticator::DuplicatedParameters] if the header contains multiple instances of the same param
def parse_authorization(header)
header = header.to_s
scanner = StringScanner.new(header)
auth_parse_error = proc { |message| raise ParseError.new(message, {'Authorization' => [message]}) }
scanner.scan(/OAuth\s*/i) || auth_parse_error.call("Authorization scheme is not OAuth - received: #{header}")
attributes = {}
while scanner.scan(/(\w+)="([^"]*)"\s*(,?)\s*/)
key = scanner[1]
value = scanner[2]
comma_follows = !scanner[3].empty?
if !comma_follows && !scanner.eos?
auth_parse_error.call("Could not parse Authorization header: #{header}\naround or after character #{scanner.pos}: #{scanner.rest}")
end
(attributes[unescape(key)] ||= []) << unescape(value)
end
unless scanner.eos?
auth_parse_error.call("Could not parse Authorization header: #{header}\naround or after character #{scanner.pos}: #{scanner.rest}")
end
duplicates = attributes.reject { |k,v| v.size <= 1 }
if duplicates.any?
errors = duplicates.map do |k,vs|
{k => ["Received multiple instances of Authorization parameter #{k}. Received values were: #{vs.inspect}"]}
end.inject({}, &:update)
raise DuplicatedParameters.new("Received duplicate parameters: #{duplicates.keys.inspect}", errors)
end
return attributes.map { |k,v| {k => v.first} }.inject({}, &:update)
end