I tried to use omniauth-openid
with my new rails application. It worked when I developed using HTTP. After I started to develop with HTTPS, it failed. Finally I got the coolest workaround: OmniAuth.config.full_host
and X-Forwarded-Host/Port
.
My Environment
I use Pow
for a development server. To use HTTPS with Pow
, I installed nginx
and configured like below.
server {
listen 443;
server_name *.dev *.xip.io;
ssl on;
ssl_certificate ssl/my.crt;
ssl_certificate_key ssl/my.key;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
proxy_pass http://127.0.0.1;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
}
}
For authentication, I use omniauth-openid
via omniauth-google-apps
and devise
.
config/initializers/devise.rb
config.omniauth :google_apps, store: OpenID::Store::Filesystem.new('/tmp'), domain: ENV['GOOGLE_APPS_DOMAIN']
app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token
def google_apps
…
They worked if I access to Pow
directly using HTTP.
What was the problem 1?
I guess all people using omniauth-oauth2
behind a reverse proxy encounter “Redirect uri mismatch” error. Because redirect_uri
query string parameter is like https://myapp.127.0.0.1.xip.io:80/users/auth/github
. :80
?????
And omniauth-google-apps
didn’t work neither. My browser tried to redirect to https://myapp.127.0.0.1.xip.io:80/users/auth/google_apps/callback
…
Solution
Here is a simple workaround for this.
To simplify, I configured it as a string.
OmniAuth.config.full_host = "https://myapp.127.0.0.1.xip.io"
What was the problem 2?
After that, when I accessed to https://myapp.127.0.0.1.xip.io/users/auth/google_apps
, Google said:
Error: invalid_request
Error in parsing the OpenID auth request.
The reason was a request query string parameter:
openid.realm:https://myapp.127.0.0.1.xip.io:80
:80
again… At this time, it came from rack-openid
via omniauth-openid
.
rack-openid/lib/rack/openid.rb at v1.3.1 · josh/rack-openid
oidreq.redirect_url(trust_root || realm_url(req), return_to || request_url, immediate)
At first, I applied a monkey patch to omniauth-openid
:
--- a/lib/omniauth/strategies/open_id.rb
+++ b/lib/omniauth/strategies/open_id.rb
@@ -32,6 +32,7 @@ module OmniAuth
lambda{|env| [401, {"WWW-Authenticate" => Rack::OpenID.build_header(
:identifier => identifier,
:return_to => callback_url,
+ :trust_root => full_host,
:required => options.required,
:optional => options.optional,
:method => 'post'
Then, opened.realm
looked fine, but after the callback, OmniAuth said:
Could not authenticate you from GoogleApps because "Invalid credentials".
This was because rack-openid
doesn’t pay attention to trust_root
.
rack-openid/lib/rack/openid.rb at v1.3.1 · josh/rack-openid
consumer.complete(flatten_params(req.params), req.url)
Then, I found another monkey patch for Rack::Request
.
But this is not cool. I thought that Rack::Request
must have a functionality to deal with HTTPS reverse proxy.
rack/lib/rack/request.rb at 1.5.2 · rack/rack
def port
if port = host_with_port.split(/:/)[1]
port.to_i
elsif port = @env['HTTP_X_FORWARDED_PORT']
port.to_i
elsif @env.has_key?("HTTP_X_FORWARDED_HOST")
DEFAULT_PORTS[scheme]
else
@env["SERVER_PORT"].to_i
end
end
YES!!!!!!!!!!!!!!!
Solution
I added X-Forwarded-Host
on my nginx.conf
, then it worked! Because I had already configured X-Forwarded-Proto
.
proxy_set_header X-Forwarded-Host $host;
Or X-Forwarded-Port
also worked.
proxy_set_header X-Forwarded-Port 443;
Conclusion
If you use SSL termination(nginx, Apache, LB, etc.) with your application:
- You should use SSL termination for your development environment.
- Otherwise, you will have some trouble between dev and prod…
- You should pass much information using
X-Forwarded-*
headers.- Many libraries handle these headers better than you:)