Search code examples
rubysqliteauthenticationracksqlite3-ruby

SQLite3 and Rack Basic Auth cannot use username as execution parameter


Consider the following code snippet:

require "sqlite3"

db = SQLite3::Database.new "my.db"
p db.execute("select * from user where name = ?", ["my_user_name"])

This will outut the entry in the database where the user's name is "my_user_name". This works as intended.

Now consider this code snippet (config.ru):

require "rack/auth/basic"
require "sqlite3"

use Rack::Auth::Basic, "my authentication" do |username, password|
  p username
  p db.execute("select * from user where name = ?", [username])
end

run do |env|
  [200, {}, []]
end

When I send a request to this server:

curl -X POST -v -ujomy:abc123 localhost:9292 -d ''

I see the following output in the terminal where I started the server (using rackup):

"my_user_name"
[]

So I now do not get a result back from my sql query.

When I insert this line before the db.execute statement:

username = "my_user_name"

Now I actually get a result back.

Replacing username with username.to_s also does not work.

So it seems that using the username variable provided by Rack does not work with sqlite? How is this even possible as username.class is String? The username.size is equal to "my_user_name".size too.


Solution

  • This is an encoding issue. In this block username and password are encoded as "ASCII-8BIT".

    use Rack::Auth::Basic, "my authentication" do |username, password|
      p username
      p db.execute("select * from user where name = ?", [username])
    end
    

    To resolve this you can change the encoding using String#force_encoding like so:

    use Rack::Auth::Basic, "my authentication" do |username, password|
      p username
      p db.execute("select * from user where name = ?", [username.force_encoding('UTF-8')])
    end