OmniAuth dynamic client options site within the strategy - ruby-on-rails

I have a rails app set up as an OAuth2 provider (using Doorkeeper). The app uses a different subdomain per user account (or an entirely different domain through a cname record)
i.e.
user1.myrailsapp.com
user2.myrailsapp.com
www.mycustomdomain.com
On the provider side, everything is working as expected.
I also have a second app that is a client making use of the first app's exposed API. I have a version of the client working but only with a hard coded site url in the OmniAuth strategy.
The question is, how can I dynamically set the strategy url on a per request basis.

For anyone interested, the solution is in the use of dynamic providers: https://github.com/intridea/omniauth/wiki/Dynamic-Providers
Rails.application.config.middleware.use OmniAuth::Builder do
provider :mystrategy, ENV["OAUTH_ID"], ENV["OAUTH_SECRET"],
:setup => lambda{|env|
env['omniauth.strategy'].options[:client_options].site = env['rack.session']['oauth_site']
}
end

One option is don't do it that way.
I have a similar app and ran into the same issue. However after thinking about it for a moment I realised that I didn't want to send them to a strategy provider URL on the user account's subdomain because the request wasn't yet fully authenticated (it hasn't been processed by the rails app yet).
Also for the first time a user logs in the user account subdomain hadn't yet been set up, so it would have been impossible to route there.
So instead, I have the strategy callback URL set to the main website. After the signin request is processed, session set up and everything, then I redirect the client onto their user subdomain. Takes out a whole load of pain.

Related

Linkedin OAuth2.0 : How to configure OAuth 2.0 Redirect URL with a wildcard subdomain url for a multi tenant application

I am trying to configure a LinkedIn application for a multi tenant site. I will have 20+ tenants using the same application and the number is going to increase every time.
As per Linkedin API documentation (https://developer.linkedin.com/docs/oauth2) we need to ensure following points
We strongly recommend using HTTPS whenever possible
URLs must be
absolute (e.g. "https://example.com/auth/callback", not
"/auth/callback")
URL arguments are ignored (i.e.
https://example.com/?id=1 is the same as https://example.com/)
URLs
cannot include #'s (i.e.
"https://example.com/auth/callback#linkedin" is invalid)
Can i configure redirect url as https://*.mysite.com/auth/linkedin/callback instead of specifying url of each tenant separately.
You cannot do a subdomain based wild card mapping as the IP should know the RP.
You can change the logic after you get the authorization callback, so you set the cookie and then you will have to redirect the user back to the tenant URL instead of the base URL.
Anyway, after successful authorization, you will be redirecting the user to an action, just figure out the subdomaina and the construct the URL and do the redirection
HTH
EDIT
Since the use of the URL or other approaches seem to be a hack, can you please try to have a facade like application (or Gateway like one) that has a URL that is registered in linkedin and then on receiving the response, it can use a state or other factor to redirect to the tenant URL. This can use a 302 and it will be invisible unless the user is on a very slow network. This approach does not require any hack like approach.
Here state can be a function that takes a tenant info and generates a dynamic hash that is stored for tracking and redirection.

Sharing session across rails apps on different subdomains

I am trying to implement a single-sign-on solution for multiple rails (v3.2) apps hosted at different subdomains of example.com
One app serves as an identity provider, uses devise for auth, and sits at users.example.com
The other apps rely on the identity provider for authentication, use devise+omniauth, with domains of [app1.example.com, app2.example.com, and example.com].
This blog entry inspired much of my implementation: http://blog.joshsoftware.com/2010/12/16/multiple-applications-with-devise-omniauth-and-single-sign-on/
I have it working fine, but the problem remains that the sessions are not shared so after I log in on the identity provider, I still have to make a call from each of the other apps to authenticate and I need this to be seemless to the user.
I tried using the same secret token at secret_token.rb, same session key at session_store.rb and :domain => :all (also tried '.example.com' and 'example.com' as values). Still no luck.
Doing the above, I see in a session.inspect that after login on the identity provider the session variable "warden.user.user.key" is populated. When I immediately go to the app on app1.example.com, the session.inspect shows the same session_id and _csrf_token but the "warden.user.user.key" variable is now missing.
I feel like I am missing something silly.. Any ideas what that may be?
I think there is another SO question about getting a single cookie to work across subdomains that would answer yours:
https://stackoverflow.com/a/10403338/2573896
Also, I can imagine that using a memcached cluster with dalli and memcached as your session store would work as well:
http://awesomerails.wordpress.com/2011/08/23/rails-3-memcached-session-store/
For the purpose of your application, the first solution makes more sense though.

Rails, Devise, and multiple domains

Let's say I have an application that's going to be accessed from completely different domains that all point at the same server*:
example.com, example.net, foobar.com, ...
I have a Devise based authentication system that's worked fine before. However, the goal is now to add HTTPS to the sign in system. The problem is, as it turns out, there is no way to host more than one HTTPS website on the same IP address**. To resolve this problem, I set up the login pages to always POST to https://secure.example.com. As far as I can tell, this is working fine. Devise seems to have no qualm with it. However, the tricky part is that the user now needs to be redirected to foobar.com, which also needs to understand that the user is logged in. I pass the site to return to in a hidden parameter in the login form, and the redirection works fine. I still have no way to inform foobar.com that the user is now logged in.
I've managed to set it up so that, upon being returned to foobar.com, it copies the user's session cookie for secure.example.com into a new cookie for foobar.com. This part is working fine. However, in the Rails console, the web requests for secure.example.com and foobar.com - with the same cookie sent for each - produce two completely different sessions and therefore, it's no wonder Devise acts like the user was never logged in to foobar.com
Does anyone know why this wouldn't work - why two identical web requests (only the domain of the request URI was different - I tried it in Firebug, too) would produce two completely different sessions in a Rails 3 app with different, yet consistent, session ids? More to the point, does anyone know how to MAKE this work?
* assume, for the purposes of this exercise, that this is unavoidable and the sites cannot be hosted all under different subdomains, and that the number of domains required is too great to get a separate IP address for each.
** unless they're subdomains and you have an *.example.com cert, but that's beside the point.
If you're already using Devise, I suggest you try using token authenticatable. You can generate a token for the user in question, redirect them with the token to sign in, and then quickly expire the token after they have signed in.
You could also try rolling your own OAuth provider with doorkeeper.

Omniauth: How to set authentication provider details at runtime

I have a rails app that is accessible from 2 domains. Facebook requires me to register a facebook app for each of these domains and gives me credentials for each. With Omniauth I can only specify one set of credentials that is set on application startup. However, I would need to supply FB with different credentials depending on the host of the request.
There are 2 problems here:
How can I change the Omniauth credentials for facebook at runtime?
How can I intercept the call to facebook, check the domain and set the credentials accordingly? A before filter will not work, as Omniauth uses Rack Middleware.
Any suggestions are highly appreciated!
Copying the answer from the comments in order to remove this question from the "Unanswered" filter:
I solved this myself now. The problem was that the fb strategy calls
back to fb a second time to get an access token. In that second call
the wrong credentials were used (the ones set in the initializer). So
I had to patch the OAuth2 strategy so that it calls through to the
rails app again, to set the runtime credentials for that second call.
In the call back, which normally only handles the response form
Omniauth, I set the credentials and return a 404 unless
request.env["omniauth.auth"] is present. That works fine but has some
side effects for apps without dynamic providers.
The problem is now, that even if an application doesn't want to set the credentials at runtime, it has to add a condition to the callback like if request.env["omniauth.auth"] to avoid the callback code being executed when it is called the first time. The solution is probably to add a parameter to the Omniauth builder like :dynamic_provider and only call through to the app if it is set.
~ answer per Nico
This question is fairly old but still relevant. Nowdays it is also possible to set provider details dynamically during OmniAuth's Setup Phase.
For example:
Rails.application.config.middleware.use do
provider :example,
setup: ->(env) do
env['omniauth.strategy'].options[:foo] = env['rack.session']['foo']
env['omniauth.strategy'].options[:client_options][:site] = Something.dynamic('param')
end
end
Source: https://github.com/omniauth/omniauth/wiki/Dynamic-Providers

How do I let a user sign in from a different domain on Authlogic?

[This is slightly different than a previous question about having multiple domains share the same cookie. It seemed like there wasn't an easy way to do that.]
I have a application at application.com. A customer has app.customer.com pointed at my site on Heroku, and I have everything set up so that it renders a specific version of app correctly. The issue is that I want a user at app.customer.com to be able to login. I believe authlogic is now setting the cookie on application.com, so while it verifies the credentials, no session on customer.com is ever created.
Since cookies cannot be shared across domains, you probably need to save an identifier in a database and also pass it through the url so when the client browser hits the new domain, it sends the token for the new domain session to see and match.
It should be a long cryptographically safe token, like a UUID to keep it from being guessed by attackers.
I'm not sure how the authlogic piece fits in though.

Resources