devise gem way to auth for a notification api - ruby-on-rails

My app is using the devise gem for authentication. I have this video conversion service that can emit notification to a url of my choice, presumably so that the app knows the conversion is complete, basically, the notification is the same as someone clicking a button that says "conversion complete" but done programmatically.
I have created in the routes.rb file a route to this action which will mark a video as being successfully converted
#routes.rb
match "video/set_complete", "videos#set_complete"
#videos controller
def set_complete
video = Video.find_by_conv_job_id(params[:encoding_id])
video.set_complete
end
That api call from that video conversion service naturally carries a few other params to further identify the video. But I don't think it's that relevant.
Now here's the question, by the way, thanks for reading my post, I am forever indebted to you--- I mean, simply put, I can't just let anyone access that dns.com/videos/set_complete, that's why it is using Devise to authenticate, but I don't want to use user:pass#dns.com/videos/set_complete, what do I know, I just feel that the user/pass is in plain sight in a plain http (not s) request is quite dangerous. So I thought, well, assuming that the requests always come from a certain ip or domain name, can I make devise always authenticate these ip's requests without doing any embedded user/pass or the use of single access token?
Thanks again!

You can do something like this in your videos controller:
before_filter :check_ip, :only => [:set_complete]
def check_ip
if request.remote_ip != '[ip address]'
authenticate_user!
end
end
This will let signed in users make that request unless they come from whatever IP address you've specified. If you want to ONLY allow requests to this action from that IP, change authenticate_user! to something like:
sign_out_and_redirect
However, since they don't care about the response, someone could just spoof the correct IP and be able to set things complete. I don't know how much you care about that though, and this is probably still sufficient for what you're doing.

Related

Rails 5 Geolocation with Clearance

I'm currently using Clearance for authentication. As part of the login process I want to ensure that I have a location for the user (stored in the session).
My question is how to do this in the context of clearance? Ideally I only want to perform the lookup on login (to save network traffic / API calls). If I can't locate a user then I'll deny login.
I was thinking of using a guard but I don't seem to have access to request.ip or session which is a bit of a deal breaker. I was also trying to avoid redirecting to a URL that only does the geolocation and then redirects again.
Anybody have ideas on a nice model on how to make this work? Thanks!
Sign in guards are mostly intended for processes that will prevent or allow sign in. I don't think they are a good fit here. For this use case, I would suggest overriding sign_in, which is generally mixed in to ApplicationController
def sign_in(user, &block)
super
if signed_in?
UserGeocoder.call(current_user)
end
end

Easy access control to Rails app?

I need to control access to my whole Ruby on Rails app, allowing only some selected users to see it while it's under development.
I'm not looking into a full authentication system, but something much simpler, where I can add an email address to a restricted-users list, send an email to it and let that user see the app, rejecting any other user.
I have tried to use the WWWhisper add-on in Heroku (the app is hosted there) as it's just what I would need, but it doesn't seem to be available outside of the US.
I think I will have to build it myself, but, before, I wanted to make sure that there isn't a simpler solution already available. Any ideas? Thanks in advance.
If your access requirement is "having got an invitation email" then i think your simplest option is to have something like this
#in application.rb
before_filter :require_invite
protected
def require_invite
session[:invite_token] ||= params[:invite_token]
unless session[:invite_token] == "<SOME SECRET KEY STRING>"
redirect_to external_home_path and return
end
end
end
where external_home_path is some holding page for people who haven't got an invite, which says "Sorry you need an invite token blah blah". You'll need to add this to the controller which handles the external home page, to avoid a circular redirect.
skip_before_filter :require_invite, :only => [:external_home]
Then you just need to send people an invite with a link like
http://example.com?invite_token=<SOME SECRET KEY STRING>
Obviously this isn't very secure but it's as secure as the "have i seen the email" criterion.
When you go live you can take this before_filter out.

Allowing rails api to return json

I'm lost here- don't even really know what questions to ask.
I built an api as described here : http://railscasts.com/episodes/350-rest-api-versioning?view=asciicast
It's on a site that requires login.
I can access the api through the browser when I am logged in, no problem. Here are my routes:
## API
namespace :api do
namespace :v1 do
resources :users, :sessions
end
end
What I've been asked to do is to make it so that an outside party can request the json with a Api key and optional query parameters and userId
I've tried to curl the site (https) and get redirected to a logout, even with username and password.
My boss suggested a public form on the root url that accepts the userId, apikey and params, and can be curled and will return the data via the parameters posted from curl.
I have no idea how to do this, or even to allow the data to be called without loggin in. I looked at this other screen cast http://railscasts.com/episodes/353-oauth-with-doorkeeper (it's a paid version) but his interactions are allowing another rails app to interact with his original app.
Basically, where should I look for information on how to accomplish this? Any other suggestions, or more information that I could give to make my question more clear?
Thank you for your time.
More RailsCasts! Ryan Bates has you covered in http://railscasts.com/episodes/352-securing-an-api?view=asciicast
So to boil it down:
you need to determine if the clients calling your API need to identify themselves, or if they also need to authenticate somehow
you need to determine if the users of the client (that's calling your API) need to authenticate with your system -- that is, are there "users"?
Some APIs allow callers to pass an API Key as part of the query; others require a more sophisticated process of authenticating, typically OAuth, which is a little trickier.
Some APIs provide user-specific information, in which case you'll need a way to make sure the user can log in, change their password, recall a forgotten password and so on. There's a good RailsCast for that, too (or you can use the Devise gem, although I wouldn't recommend it if you're mainly implementing an API -- not Devise's strong suit).
I am guessing you know this part, but all curl does is simulate the HTTP requests your clients will be making to your API, and (with the --include option) can show you the information about the response returned -- headers, cookies, and so on.
Google "rails api authentication" for more.

Specify Cookie Domain in Authlogic When Session Is Created

Is it possible to set the cookie domain to something other than the current domain when a session is created with Authlogic?
When a new account is created from our signup domain, I'd like to redirect the user to their subdomain account and log the user in.
Current controller:
def create
#account = Account.new(params[:account])
if #account.save
#user_session = #account.user_sessions.create(#account.users.first)
# I'd like the cookie domain to be [#account.subdomain, APP_CONFIG[:domain]].join(".")
redirect_to admin_root_url(:host => [#account.subdomain, APP_CONFIG[:domain]].join("."))
else
render 'new'
end
end
If you do:
config.action_controller.session[:domain] = '.YOURDOMAIN.COM'
in your production.rb file, that will allow you to have everyone logged in on all subdomains of your subdomain. If you then add a filter (or whatever, but I use a filter so I know that works) that checks that someone is actually using the right domain before you show controller stuff, it works pretty well.
As an example, you could store the appropriate subdomain for the session as a session variable and give people link options to their specific things if they were on your main domain or looking at a page on someone else's subdomain.
This seems to be the general pattern for doing this sort of thing -- if you set a cookie specific to the subdomain otherwise you won't be able to tell when they've logged in to the main site. I also have a 'users_domain?' helper that ends up getting called occasionally in views when I do this.
If you don't want to have those sorts of common web design patterns, wesgarrion's single use -> session creation on subdomain is also a way to go. I just thought I'd mention this as a design / interaction / code issue.
If you want to log them in on the subdomain, you can use Authlogic's single use token.
Check out the Params module for an example on logging in with the single use token.
Naturally, your action will log them in and create their session (on the subdomain) so they don't have to re-authenticate for the next request.
There are options to set the domain for the cookie in process_cgi() and session(), but I don't see a way to set those per-request in Authlogic. The authlogic mailing list is pretty responsive, though, and this seems like a pretty standard use-case that someone there would have tried and figured out. And uh, I saw your note on the google group, so never mind that.
If you have an application with multiple subdomains and don't want session cookies to be shared among them, or worse - have a top-level .domain session cookie with the same session_key floating around alongside your subdomain session cookie (Rails will keep one and toss the other - I believe simply based on the order in the request header) - you can use the dispatcher hooks to force the session cookie to subdomains.
Include the hook in ActionController from an extension.
base.send :after_dispatch, :force_session_cookies_to_subdomains
Set the domain this in your after_ dispatch hook.
#env['rack.session.options'] = #env['rack.session.options'].merge(:domain => 'my_sub_domain' end)
For us, we look at the #env[HTTP_HOST] to determine what [my_sub_domain] should be.
With this approach, the user's login must occur at the subdomain for the browser to accept the subdomain'ed cookie (unless using a pattern like the Authlogic Params to propagate to the next request against the subdomain).
Note: The browser will reject the subdomain'ed cookie when the request comes from the higher level domain. For us, this isn't a bad thing - it results in the same outcome that we require, that a top level session cookie doesn't get created and later sent to subdomains.
Another approach to a similar end might be to force a cookie to not be set when not from a subdomain. Not spending much time on it, the way I was able to accomplish this was -
request.env["rack.session"] = ActionController::Session::AbstractStore::SessionHash.new(self, request.env)
in an after filter in ApplicationController.

How to create password protected RSS feed in rails

Creating RSS feed in rails is easy. I need a simple way to password protect the RSS feed. I am thinking http basic authentication.
I googled but could not find any article about creating password protected RSS.
I have this in my ApplicationController
def xml_authorize
if request.format == Mime::XML
authenticate_or_request_with_http_basic do |username, password|
username == 'foo' && password == 'bar'
end
end
end
Then I just apply a before_filter :xml_authorize to the actions that I want to password protect for XML requests only, but still want to serve normally with html.
Here's where I got the inspiration from.
Just use whatever auth system you use on your regular controllers. If the user is logged, and session is alive he will be able to download the feed.
How is HTTP authentication any different on RSS feeds than other controller actions? (This is not necessarily a rhetorical question - is it actually different?)
Have you tried just using the Rails HTTP Basic Authentication methods?
Feeds are meant to be fetched in regular intervals without user interaction.
RSS-Feeds can be consumed by something different than a browser. For example,
I have a phone where I can create a widget for the start screen from a rss-feed-link. Great function. Unfortunately authentication does not work for this widget.
And there is no user interface to put in username and password. So the authentication need to be part of the url, with all the bad security implications...
On the other hand you don't need a session to answer a feed-request.
So the solution is a create a special key for the user, and store it in the user table.
Then use it when you display the link to the rss-feed. In the feed-method, you use this key to retrieve the user, but you don't create a session. This way, even when a hacker somehow got a valid key, the hacker can only view the rss-feed, but not access the rest of your application.
If you already use some library for authentication, there may already some solution implemented for this. In Authlogic, is is the class SingleAccessToken, and you need to add a column 'single_access_token' of type string to your user table. Then authlogic creates some cryptic key when are saving the user record. You than add this key as the GET-Parameter 'user_credentials' to the url of the private rss-feed
Like knoopx said, If you use an authentication system like authlogic you should be able to specify the authentication type in the controller. You can then specify http basic authenication. Then you can, if you choose, include the authentication in the URL for the RSS Feed.
e.g:
http://username:password#example.com/rss
(sorry to break the URI up like that, but I don't have enough reputation points to post multiple links :( )

Resources