If you're using Warden gem with a Sinatra app authentication there's another nice gem sinatra_warden that will save you some time glueing Warden with your application.
So, your rack stack (warden + sinatra_warden) will go something like this:
Rack::Builder.app do
use Rack::Session::Cookie
use Warden::Manager do |manager|
manager.default_strategies :password
manager.failure_app = MyApp
manager.serialize_into_session { |user| user.id }
manager.serialize_from_session { |id| User.get(id) }
end
use Rack::Flash
run MyApp
end
and everything works as expected.
Now, I often have "use Warden::Manager" inside the same app in a Sinatra extension's registered method, e.g.
def self.registered(app)
app.use Warden::Manager do |manager|
manager.default_strategies :password
manager.failure_app = app
manager.serialize_into_session { |user| user.id }
manager.serialize_from_session { |id| User.get(id) }
end
app.get '/...' do
# other stuff
end
end
Basically, Warden's failure_app and the "main" application are the same thing.
What happens at a login failure is Warden calls the failure_app with
POST /unauthenticated
which, in turn, is being handled by sinatra_warden (0.3.0) like this:
app.post '/unauthenticated/?' do status 401 env['x-rack.flash'][:error] = options.auth_error_message if defined?(Rack::Flash) options.auth_use_erb ? erb(options.auth_login_template) : haml(options.auth_login_template) end
Since we're in the same app, in my case, what happens next is Warden sees 401 response code (Unauthorized) and acts as if someone sent a wrong username/password, calling again the failure_app (which is again, "us") with POST /unauthenticated.
This goes on and on 'till (eventually) you get a "stack too deep" error.
My fix was really simple: add warden.custom_failure! to /unauthenticated block of lib/sinatra_warden/sinatra.rb (this is sinatra_warden gem)
app.post '/unauthenticated/?' do status 401 warden.custom_failure! if warden.config.failure_app == self.class env['x-rack.flash'][:error] = options.auth_error_message if defined?(Rack::Flash) options.auth_use_erb ? erb(options.auth_login_template) : haml(options.auth_login_template) end
I really needed this quick fix so I forked sinatra_warden and published my version of the gem.
UPDATE - 26 Apr
the changes are already in the official sinatra_warden gem, version 0.3.1 so, you just need to "sudo gem update sinatra_warden" or change the version requirement to ">= 0.3.1" in your Gemfile.
PS thanks Matt Ball for explaining how to setup syntax highlighting.