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:
and everything works as expected.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
Now, I often have "use Warden::Manager" inside the same app in a Sinatra extension's registered method, e.g.
Basically, Warden's failure_app and the "main" application are the same thing.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
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:
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.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
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)
I really needed this quick fix so I forked sinatra_warden and published my version of the 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
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.
Thanks, there aren't enough good examples or explanations out there of warden/sinatra-warden, that bit about the main app and the failure app being the same was an nice piece of insight to pass on.
ReplyDelete