I'm trying to integrate simple OpenID authentication through Google accounts. I'm using omniauth gem and on my local development system (Win7, ruby 1.8.7-p302, rails 2.3.8, omniauth 0.1.5) everything works nice.
The problem shows it's face when I deploy it to my hosting (HostGator). The app (mongrel) starts at port 12002 and through HostGator's cPanel it's configured to be rewritten from one of subdomains:
RewriteCond %{HTTP_HOST} ^subdomain.mycompany.com$ [OR]
RewriteCond %{HTTP_HOST} ^www.subdomain.mycompany.com$
RewriteRule ^(.*)$ "http\:\/\/127\.0\.0\.1\:12002\/$1" [P,L]
When browser goes /auth/open_id it's redirected to Google for authorization but it's return_to address is subdomain.mycompany.com:12002 which of course is incorrect because Apache doesn't listen on 12002. I've managed to monkey patch OmniAuth::Strategies::OpenID and Rack::OpenID so they assemble address without port BUT now on the final stage after user access confirmation if falls into:
Routing Error
No route matches "/403.shtml" with {:method=>:get}
I guess the problem is what my site's address is encoded (some kind of hash) at other authorization request parameter to avoid
The port issue is because of the the way RACK request computes the port. Here is the patch
require 'rack/utils'
module Rack
class Request
def port
if host_with_port =~ /:(\d+)$/
$1.to_i
else
standard_port
end
end
# Returns the standard \port number for this request's protocol.
def standard_port
case protocol
when 'https://' then 443
else 80
end
end
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
def protocol
ssl? ? 'https://' : 'http://'
end
# Is this an SSL request?
def ssl?
@env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
end
end
end
This is the way rails ActionController::Request computes the port.
Hope this helps
Well...
The 403 error was because hosting security rules were so strict what Google's OpenID response (long enough to be suspicious) was rejected. Resolved by hosting support.
To resolve the problem with port number within return_to parameter (addressed by freiwillen) I've made the following (monkey path) initializer:
module OmniAuth
module Strategies
# OmniAuth strategy for connecting via OpenID. This allows for connection
# to a wide variety of sites, some of which are listed [on the OpenID website](http://openid.net/get-an-openid/).
class OpenID
protected
def callback_url
uri = URI.parse(request.url)
uri.path += '/callback'
# by KirylP: to overcome hosting subdomain forwarding to rails port
uri.port = '' if request.env.has_key? 'HTTP_X_FORWARDED_SERVER'
uri.to_s
end
end
end
end
module Rack
class OpenID
SERVER_PORT_TO_AVOID = 12002
private
def realm_url(req)
url = req.scheme + "://"
url << req.host
scheme, port = req.scheme, req.port
if scheme == "https" && port != 443 ||
scheme == "http" && port != 80
url << ":#{port}" if port != SERVER_PORT_TO_AVOID # KirylP
end
url
end
end
end
module OpenID
class Consumer
def complete(query, current_url)
message = Message.from_post_args(query)
current_url.sub!(":#{Rack::OpenID::SERVER_PORT_TO_AVOID}", '') # KirylP
mode = message.get_arg(OPENID_NS, 'mode', 'invalid')
begin
meth = method('complete_' + mode)
rescue NameError
meth = method(:complete_invalid)
end
response = meth.call(message, current_url)
cleanup_last_requested_endpoint
if [SUCCESS, CANCEL].member?(response.status)
cleanup_session
end
return response
end
end
end
I hope someone will propose more elegant solution.
In the most recent version of Omniauth (0.2.0.beta4) you can specify full_host
as a config option and set it to be evaluated at each request, or just use a fixed value.
Example (rails):
ActionController::Dispatcher.middleware.use OmniAuth::Builder do
store = Rails.env.development? ? OpenID::Store::Filesystem.new("#{Rails.root}/tmp") : nil
provider :open_id, store, :name => 'google', :identifier => 'https://www.google.com/accounts/o8/id', :scope => 'email'
if Rails.env.production?
configure do |config|
config.full_host = lambda do |env|
req = Rack::Request.new(env)
"#{req.scheme}://#{req.host}" # req.host strips port number
end
end
end
end