bengler / checkpoint

Centralized identity store and authentication broker for web applications. It supports a number of authentication mechanisms and is provided via a http-interface.
MIT License
31 stars 2 forks source link

Configuration error or bug with sessions/transferring? #39

Closed prognostikos closed 11 years ago

prognostikos commented 11 years ago

I'm running into an issue and I'm not sure if it's because I made a configuration mistake or if it is an actual bug.

I have an application at staging.example.com. It uses rack-proxy to replace the hostname with checkpoint.example.com for requests that start with /api/checkpoint as shown below:

class CheckpointProxy < Rack::Proxy
  def rewrite_env(env)
    env['HTTP_X_PROXIED_FOR']     = env['HTTP_HOST']
    env['HTTP_X_FORWARDED_PROTO'] = 'https' if env['SERVER_PORT'] == 443

    env['HTTP_HOST'] = 'checkpoint.example.com'
    env
  end
end

I eventually also want to use this checkpoint instance to work with *.example.dev and www.example.com.

I have a realm configured to authenticate with Facebook, and the website url in the facebook configuration is checkpoint.example.com. The domains example.dev, staging.example.com, www.example.com, and checkpoint.example.com are added to the realm, and the primary domain is set to be checkpoint.example.com.

If I make a request from staging.example.com to /api/checkpoint/v1/login/facebook?redirect_to=https://staging.example.com/login/succeeded I see the messages below in my logs. (I have much more information about the but it is hard to anonymize - I can provide a private gist on request).

What I expect is that checkpoint handles the authentication and transfers me back to staging.example.com. I can see that the Account and Identity are updated with the correct information -- it seems to be dying in the transfer phase.

It seems to me that the redirect_to parameter is not being properly stored in the session and checkpoint is blowing up when it sends nil to URI.parse. Again I'm not sure if it is due to my configuration or if it's an actual bug.

2012-12-14T08:30:25+00:00 app[web.1]: D, [2012-12-14T08:30:25.885506 #45] DEBUG -- :   Identity Load (12.1ms)  SELECT "identities".* FROM "identities" WHERE "identities"."id" IN (15)
2012-12-14T08:30:25+00:00 app[web.1]: URI::InvalidURIError - bad URI(is not URI?): :
2012-12-14T08:30:25+00:00 app[web.1]:   /usr/local/lib/ruby/1.9.1/uri/common.rb:156:in `split'
2012-12-14T08:30:25+00:00 app[web.1]:   /usr/local/lib/ruby/1.9.1/uri/common.rb:174:in `parse'
2012-12-14T08:30:25+00:00 app[web.1]:   /usr/local/lib/ruby/1.9.1/uri/common.rb:628:in `parse'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/api/v1.rb:190:in `transfer'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/api/v1/auth.rb:157:in `block in <class:CheckpointV1>'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:1212:in `call'
2012-12-14T08:30:25+00:00 heroku[router]: at=info method=GET path=/api/checkpoint/v1/auth/facebook/callback?code=[FB_CALLBACK] host=checkpoint.example.com fwd=90.184.60.199 dyno=web.1 queue=0 wait=0ms connect=6ms service=1326ms status=500 bytes=30
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:1212:in `block in compile!'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in `[]'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in `block (3 levels) in route!'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:801:in `route_eval'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in `block (2 levels) in route!'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:822:in `block in process_route'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:820:in `catch'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:820:in `process_route'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:784:in `block in route!'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:783:in `each'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:783:in `route!'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:886:in `dispatch!'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `block in call!'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `block in invoke'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `catch'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `invoke'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:705:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-protection-4a771b640d70/lib/rack/protection/xss_header.rb:27:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-protection-4a771b640d70/lib/rack/protection/path_traversal.rb:16:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-protection-4a771b640d70/lib/rack/protection/json_csrf.rb:17:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-protection-4a771b640d70/lib/rack/protection/base.rb:47:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-protection-4a771b640d70/lib/rack/protection/xss_header.rb:27:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-ea7ed1aeb8e6/lib/rack/nulllogger.rb:9:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-ea7ed1aeb8e6/lib/rack/head.rb:9:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:1334:in `block in call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:1416:in `synchronize'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:1334:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/pebbles-cors-d51dc16e96bb/lib/pebbles-cors.rb:30:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/omniauth-1.0.3/lib/omniauth/strategy.rb:168:in `call!'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/omniauth-1.0.3/lib/omniauth/strategy.rb:148:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/omniauth-1.0.3/lib/omniauth/strategy.rb:368:in `call_app!'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/omniauth-1.0.3/lib/omniauth/strategy.rb:332:in `callback_phase'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/omniauth-oauth2-1.0.2/lib/omniauth/strategies/oauth2.rb:65:in `callback_phase'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/omniauth-1.0.3/lib/omniauth/strategy.rb:204:in `callback_call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/omniauth-1.0.3/lib/omniauth/strategy.rb:166:in `call!'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/omniauth-1.0.3/lib/omniauth/strategy.rb:148:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/omniauth-1.0.3/lib/omniauth/builder.rb:42:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-ea7ed1aeb8e6/lib/rack/session/abstract/id.rb:214:in `context'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-ea7ed1aeb8e6/lib/rack/session/abstract/id.rb:209:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-ea7ed1aeb8e6/lib/rack/methodoverride.rb:21:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/rack-contrib-1.1.0/lib/rack/contrib/post_body_content_type_parser.rb:36:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-ea7ed1aeb8e6/lib/rack/builder.rb:134:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-ea7ed1aeb8e6/lib/rack/urlmap.rb:64:in `block in call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-ea7ed1aeb8e6/lib/rack/urlmap.rb:49:in `each'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bundler/gems/rack-ea7ed1aeb8e6/lib/rack/urlmap.rb:49:in `call'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/unicorn-4.1.1/lib/unicorn/http_server.rb:528:in `process_client'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/unicorn-4.1.1/lib/unicorn/http_server.rb:600:in `worker_loop'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/unicorn-4.1.1/lib/unicorn/http_server.rb:485:in `spawn_missing_workers'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/unicorn-4.1.1/lib/unicorn/http_server.rb:135:in `start'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/gems/unicorn-4.1.1/bin/unicorn:121:in `<top (required)>'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bin/unicorn:19:in `load'
2012-12-14T08:30:25+00:00 app[web.1]:   /app/vendor/bundle/ruby/1.9.1/bin/unicorn:19:in `<main>'
atombender commented 11 years ago

Could the problem be your proxying? If it changes the host name when proxying, the transfer stuff might blow up, since it's intended to support copying sessions across domains.

prognostikos commented 11 years ago

@alexstaubo I don't know how else I can proxy from the main application to checkpoint.

The hostname also seems to be changed when it's deployed using Erik's deployment documentation

I can't follow those directions exactly as I'm deploying to Heroku, but in principle I'm doing the same thing in my application, just using rack-proxy/rack-reverse-proxy instead of Nginx/HAProxy.

Perhaps checkpoint needs to explicitly use the X-Forwarded-Host header?

Right now for me the only way I can get checkpoint to work is to set the primary_domain to be the domain of the site that is using checkpoint and to configure Facebook to also call back to the site. The transfer stuff (i.e. using checkpoint.example.com as primary domain & oauth callback domain with staging.example.com and example.dev) just isn't working for me.

simen commented 11 years ago

Checkpoint does support the X-Forwarded-Host header through Rack. We use it all the time in our setup. Are you sure Rack::Proxy does? I vaguely remember we had to patch it severely a year ago when we tried to use it for a similar purpose.

prognostikos commented 11 years ago

@simen I've switched to rack-reverse-proxy at the latest commit which added support for X-Forwarded-Host and still getting the exception.

simen commented 11 years ago

It would be interesting to see a dump of the headers and the value of request.host when the request arrives at checkpoint!

prognostikos commented 11 years ago

I updated rack-reverse-proxy with a few outstanding pull requests (particularly this one) and now X-Forwarded-Host is getting sent to checkpoint on Heroku and checkpoint is working as designed for example.dev and staging.example.com.