I want to execute an action after user's cookie expires.
The action is session#destroy. Any idea how to do that?
This is session_store.rb
Rails.application.config.session_store(
key: '_app_session',
expire_after: ENV['SESSION_EXPIRE'].to_i.minutes
)
If you are using devise gem then you can simply authenticate user before action like this. This will check use session expired or not.
before_action :authenticate_user!
For manual to check the session is expired or not before action.
Add this line to your application controller :
before_action :expire_session
private
def expire_session
time_left = (session[:expire_after] - Time.now).to_i
unless time_left > 0
# redirect to login page
else
session[:expire_after] = Time.now + ENV['SESSION_EXPIRE'].to_i.minutes
end
end
Related
I have tried everithing starting following this guide
https://adibsaad.com/blog/setting-up-ember-cli-with-a-rails-back-end-and-token-authentication-authorization
but still it does not work. When I try to reach pages that are protected with authentication token the server give me "unauthorized 401". Here
https://github.com/francescabarbazeni87/Ember-Devise-Simple-Auth-Example-
there is my code for the server and client side. Many thanks in advance.
class ApplicationController < ActionController::Base
before_filter :authenticate_user_from_token!
# Enter the normal Devise authentication path,
# using the token authenticated user if available
#before_filter :authenticate_user! <-----you dont need this line...delete or comment it out
I want a password site wide just like Rack's Basic AUTH
/config.ru
use Rack::Auth::Basic, "Restricted Area" do |username, password|
[username, password] == ['admin', 'admin']
end
run Rails.application
But I don't want it to block paths /API and /mailgun/incoming_email with password access. Can I accomplish this in Rack? Or should I implement a scope within the routes.rb that almost all resources are behind a Rack (enter once) password?
For the record I am using Devise within the site... that's separate. I need a sitewide password before it.
[Revised Question]
Specific Routes
I would like to password protect only the root path / and /visitors with the Rack like password. I've seen something used in a Rails routes.rb file before with a lambda condition requiring the password. I'm not having luck finding that information at the moment.
My website already redirects unauthenticated Devise users to /users/sign_in. So I only needed to password protect /, /users/sign_in, and /users/sign_up. This is how I did it.
config.ru
class RootSiteAuth < Rack::Auth::Basic
def call(env)
request = Rack::Request.new(env)
if ['/', '/users/sign_in', '/users/sign_up'].include? request.path
super
else
#app.call(env)
end
end
end
use RootSiteAuth, "Restricted Area" do |username, password|
[username, password] == ['admin', 'admin']
end
run Rails.application
And it works. Every controller that has before_filter :authenticate_user! redirects to the Rack password page. After authentication we're good to go. Anything without the filter permits outside access as planned. ^_^
I have a created and API using rails 4 and at the moment I'm trying to figure out how to do the login. Since the API will be used for an iPhone app we decided to go with token authentication and Doorkeeper/OAuth2 gem.
So far I created a signin controller to take care of authenticating the user (I'm using bcrypt to hash passwords).
def create
#user = User.find_by(email: params[:username])
dbPasswordHash = BCrypt::Password.new(#user.password_digest)
if #user == nil
render json: 'noUser', status: :unprocessable_entity
else
if dbPasswordHash == params[:password]
client = OAuth2::Client.new(app_id, secret, :site => "http://localhost:3000/")
access_token = client.password.get_token(#user.email, dbPasswordHash)
render json: access_token.to_json, status: :ok, location: #user
else
render json: {status:'ERROR',status_info:'Wrong username/password'}, status: :unprocessable_entity
end
end
end
The problem I'm having with the above code is that Faraday timesout. The issue lies with the access_token call. Since a POST request was made to /signin the second one (access_token), which goes to Doorkeeper to authenticate, will have to wait until the first is done.
I'm not sure if I'm over complicating the process but what I want to achieve is for a request to be made from the front-end, the user is authenticated and token's returned to the front-end for future use.
Another approach I tried is to POST to /oauth/token with:
{
"grant_type" : "password",
"username" : "test#gmail.com",
"password" : "$2a$10$igmaaZkrSviHc.8Glm3hcuRdqzeT5YQwYaKFN9eUbpfcmCqA3PBiO",
"client_id" : "f5cbc8d91f6e007c003e17baf3f45cb83cede4313c381afa99e456f59b08e3f8",
"client_secret" : "f827f84548b33ebd8042cfbaa7aff944f5844aad7962623ed68d83963bc62bb5"
}
This approach works fine but the password is already hashed and when I try to use
dbPasswordHash = BCrypt::Password.new(params[:password])
in doorkeeper.rb I get an error about BCrypt (I did try "require 'bcrypt'").
Any suggestions would be welcomed.
I want foo.com/ to show the landing page when the user isn't logged in, and foo.com/ to show the dashboard of the user when the user is logged in, just like in Facebook.
I was going to do it the following way:
def index
if user_signed_in?
#posts = current_user.posts
render 'home/dashboard'
else
render 'home/landing'
end
end
But then quickly realized that I'd need to use before_filter :authenticate_user! in order to get current_user, so Devise will require to sign in.
Maybe there's a way to do this more cleanly using routing. Please advice.
authenticated :user do
root to: "users#index", as: :authenticated_root
end
unauthenticated do
root to: "main#index"
end
https://github.com/plataformatec/devise/issues/2393#issuecomment-17298414
I am using signed cookies to maintain my user across pages, pretty much implemented as here.
I use two methods, sign_in(account) and sign_out to manipulate my cookies, creating or destroying them as you would expect ...
module SessionsHelper
def sign_in account
cookies.signed[:auth_account] = {
:expires => 1.week.from_now,
:value => [account.id, account.hash]
}
end
def sign_out
cookies.delete(:auth_account)
end
end
However, when trying to use this method, or the authenticate method that matches it in the ApplicationController from the functional tests, I get a NoMethodError:
NoMethodError: undefined method `signed' for {}:ActiveSupport::HashWithIndifferentAccess
I realise from this and this that this is an issue with the way cookies are defined differently in the test case, but I can't get any of these solutions to work. For completeness, an example test that fails with the above error:
require 'test_helper'
class AccountsControllerTest < ActionController::TestCase
include SessionsHelper
setup do
# We need to fake authentication by manually
# assigning an account to the sign_in process
sign_in accounts(:ia)
#account = accounts(:ia)
end
test "should 403 on index if unauthenticated" do
sign_out
get :index
assert_response :forbidden
end
test "should 200 on index if authenticated" do
get :index
assert_response :success
end
end
You can't set cookies in your test with the cookies variable like you do in your controller.
The cookies variable in your tests is use for read cookies after doing requests call (get/post...) and not for writing
In order to spoof login within your tests you should set cookies via #request.cookies[:auth]
you can put the following method in your test_helper and use it in all your tests
def signin user
#request.cookies[:auth] = user.auth
end
and in your tests
test "get dashboard if logged in" do
signin #user
get :index
end