I have an application where users can log in to their firms subdomain.
I use devise. And this code redirects the user form the root domain to the subdomain.
def after_sign_in_path_for(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
subdomain_name = current_user.firm.subdomain
if current_subdomain.nil?
# logout of root domain and login by token to subdomain
token = Devise.friendly_token
current_user.loginable_token = token
current_user.save
sign_out(current_user)
flash[:notice] = nil
home_path = valid_user_url(token, :subdomain => subdomain_name)
return home_path
else
if subdomain_name != current_subdomain.name
# user not part of current_subdomain
sign_out(current_user)
flash[:notice] = nil
flash[:alert] = "Sorry, invalid user or password for subdomain"
end
end
super
end
It works super in chrome, firefox, opera and safari, but it does not work in IE9. I do not get any error messages. Form the log i see that the user gets sigend in and when the user get redirected to the home page he/she is unauthorized. Has anyone an idea on what is going on? Form the log.
Processing by SessionsController#create as HTML
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"JaffZi9f+Uyovuya8wR2u7LjG9w/3wdUDqTqONt/kFM=",
"user"=>{"email
"=>"andreas#lizz.no", "password"=>"[FILTERED]", "remember_me"=>"0"},
"commit"=>"Sign in"}
User Load (0.0ms) SELECT "users".* FROM "users" WHERE
"users"."email" = ''whatever#atlatis.at' LIMIT 1
(0.0ms) begin transaction
(1.0ms) UPDATE "users" SET
"last_sign_in_at" = '2012-03-02 20:46:06.658370',
"current_sign_in_at" = '2012-03-
02 20:56:29.481286', "sign_in_count" = 41,
"updated_at" = '2012-03-02 20:56:29.482286' WHERE "users"."id" = 1
[paperclip] Saving attachments.
(62.0ms) commit transaction
Firm Load (0.0ms) SELECT "firms".* FROM "firms" WHERE "firms"."id" = 1 LIMIT 1
Firm Load (0.0ms) SELECT "firms".* FROM "firms" WHERE "firms"."subdomain" = 'den' LIMIT 1
CACHE (0.0ms) SELECT "firms".* FROM "firms" WHERE "firms"."subdomain" = 'den' LIMIT 1
Redirected to http://den.lvh.me:3000/
Completed 302 Found in 182ms (ActiveRecord: 0.0ms)
Started GET "/" for 127.0.0.1 at 2012-03-02 21:56:29 +0100
Processing by PrivateController#statistics as HTML
Firm Load (0.0ms) SELECT "firms".* FROM "firms" WHERE "firms"."subdomain" = 'den' LIMIT 1
Completed 401 Unauthorized in 2ms
Started GET "/users/sign_in" for 127.0.0.1 at 2012-03-02 21:56:29 +0100
Processing by SessionsController#new as HTML
Rendered devise/_links.erb (2.0ms)
Rendered devise/sessions/new.html.erb within layouts/registration (13.0ms)
Completed 200 OK in 27ms (Views: 26.0ms | ActiveRecord: 0.0ms)
If you are going across subdomain it may be better to simply change your session cookie to be cross-domain.
Editing the session-store.rb file in initializers does this.
Babyreveal::Application.config.session_store :cookie_store,
key: '_babyreveal_session',
:domain => ".mybabyreveal.com"
Notice the . prefix on the domain attribtue. This allows this cookie to be accessible across subdomains and the application should maintain it's session across subdomains. May not be 100% what you are looking for but it should get you going in the right direction.
Related
I have a small inherited rails project that uses devise to authenticate.
Recently it has started making an incorrect query to the database if the user enters an invalid password, as set out below. Previously it works as expected. I must have changed something, but I do not know what.
With a VALID password
When the user logs in with a VALID password, the console log shows similar to this
Started POST "/users/sign_in" for 192.168.2.30 at 2015-07-13 08:13:39 -0400
Processing by Users::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"A_Long_Authenticity_Token_Goes_Here", "user"=>{"email"=>"m.mouse#disney.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["email", "m.mouse#disney.com"]]
(0.3ms) BEGIN
SQL (0.6ms) UPDATE "users" SET "last_sign_in_at" = $1, "current_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "users"."id" = $5 [["last_sign_in_at", "2015-07-10 21:17:12.592611"], ["current_sign_in_at", "2015-07-13 12:13:39.359997"], ["sign_in_count", 1000], ["updated_at", "2015-07-13 12:13:39.363621"], ["id", 22]]
(17.6ms) COMMIT
and the system carries on as normal.
With an INvalid password
When the user attempts to log in with an INVALID password, the console log shows similar to this
Started POST "/users/sign_in" for 192.168.2.30 at 2015-07-13 07:44:55 -0400
Processing by Users::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"A_Long_Authenticity_Token_Goes_Here", "user"=>{"email"=>"m.mouse#disney.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}
User Load (53.0ms) SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["email", "m.mouse#disney.com"]]
Completed 401 Unauthorized in 288ms (ActiveRecord: 53.4ms)
Processing by Users::SessionsController#new as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"A_Long_Authenticity_Token_Goes_Here", "user"=>{"email"=>"m.mouse#disney.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}
User Load (2.2ms) SELECT "users".* FROM "users" WHERE "email"."email" = 'm.mouse#disney.com' AND "email"."password" = 'ThisIsAnInvalidPassword' AND "email"."remember_me" = '0' ORDER BY "users"."id" ASC LIMIT 1
PG::UndefinedTable: ERROR: missing FROM-clause entry for table "email"
LINE 1: SELECT "users".* FROM "users" WHERE "email"."email" = 'm.mou....
: SELECT "users".* FROM "users" WHERE "email"."email" = 'm.mouse#disney.com' AND "email"."password" = 'ThisIsAnInvalidPassword' AND "email"."remember_me" = '0' ORDER BY "users"."id" ASC LIMIT 1
Completed 500 Internal Server Error in 19ms (ActiveRecord: 3.3ms)
<< Output standard rails error page >>
So far as I understand this, the system tries to read the user table as expected, but no row is found. Devise munges this into a 401 Unauthorized response. The system is then attempting to redirect back to the login page somehow using Users::SessionsController#new
The system then tries a completely new query trying to look up the user using a half formatted query. The query tries to include a table called email that does not exist in the database; the query syntax is not correct either.
Database: postgres
Rails: 2.1.2
Devise gem: 3.5.1 according to bundle show
There is no Users::SessionsController#create def, so presumably using the underlying devise version
There is a Users::SessionsController#new as follows
def new
if (Rails.env.development? || Rails.env.test?) && params[:user]
user = User.where(email: params[:user]).first
sign_in :user, user
redirect_to dashboard_home_path
else
super
end
end
The environment is development
Nothing appears to be being written to the sessions table whether the login is successful or not.
Where does that second malformed query even come from, and why does devise try to use/call Users::SessionsController#new after an invalid login attempt anyway?
Thanks in advance
I think my sessions and such are screwing up because of the code I recently added in to ensure proper protocol (https on some pages, and http on others). I'm not sure though. But I keep seeing Filter chain halted as :ensure_proper_protocol rendered or redirected in my log.
the `:ensure_proper_protocol method is referring to a method I have in my application controller:
class ApplicationController < ActionController::Base
CONTROLLERS_THAT_REQUIRE_SSL = ['check_out', 'users', 'sessions', 'registrations', 'addresses', 'catalog_requests', 'wine_club/orders']
def ensure_proper_protocol
unless Rails.env.development? || Rails.env.test?
if request.format == "text/html" && request.protocol["https"] && !CONTROLLERS_THAT_REQUIRE_SSL.include?(params[:controller])
redirect_to "http://" + request.host + request.path
end
end
end
And for the controllers in CONTROLLERS_THAT_REQUIRE_SSL, I add force_ssl like so:
class CheckOutController < ApplicationController
force_ssl
...
However, I'm wondering if the switch in protocols is screwing my sessions up. Are my session issues and this error related? How do I fix the "filter chain halted" error?
The session issues I'm having is with Devise and authentication. I have a before filter to :authenticate_user! and although I manage to log in, it doesn't seem to stay logged in. The problem is that there are no error messages. It just logs out for some reason, and I'm pretty sure that it's because of the redirect because I have a before filter in my application controller to see if the user is signed in, and it uses the devise helper method user_signed_in? to see if the user is signed in. Take a look at my log:
Cache read: https://mysite-rc-preview.mysite.com/users/sign_in?
Started POST "/users/sign_in" for 69.193.194.58 at 2013-09-04 12:09:38 -0400
Processing by SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"bSYhk5t7VPBUTGkQuVyix8cb7Et7yojPE5m0V/g+do8=", "user"=>{"email"=>"emai#mysite.com", "password"=>"[FILTERED]"}, "commit"=>"Log in"}
inside setup_cart. current_cart_id is 55005260
55005260
request.session_options[:id] = eecb979b4d7db5bfd28a3684ef7288d3
User Load (2.9ms) SELECT "users".* FROM "users" WHERE "users"."email" = 'emai#mysite.com' LIMIT 1
(1.9ms) BEGIN
(2.2ms) UPDATE "users" SET "last_sign_in_at" = '2013-09-04 16:07:44.987529', "current_sign_in_at" = '2013-09-04 16:09:39.171144', "sign_in_count" = 34, "updated_at" = '2013-09-04 16:09:39.174358' WHERE "users"."id" = 350492
(10.6ms) COMMIT
begining get_or_create_cart session[:current_cart_id] is 55005260
Cart Load (2.3ms) SELECT "carts".* FROM "carts" WHERE "carts"."user_id" = 350492 AND "carts"."id" = 55005260 LIMIT 1
Cart Load (2.2ms) SELECT "carts".* FROM "carts" WHERE "carts"."user_id" = 350492
end of get_or_create_cart session[:current_cart_id] is 54993421
SeoContent Load (2.2ms) SELECT "seo_contents".* FROM "seo_contents" WHERE "seo_contents"."for_section" = 'default' LIMIT 1
There's no session[:cvv] variable
Cart Load (2.2ms) SELECT "carts".* FROM "carts" WHERE "carts"."web_cart_session" = 'eecb979b4d7db5bfd28a3684ef7288d3'
Cart Load (2.4ms) SELECT "carts".* FROM "carts" WHERE "carts"."user_id" = 350492 AND "carts"."name" = 'My Cart' LIMIT 1
CartItem Load (2.2ms) SELECT "cart_items".* FROM "cart_items" WHERE "cart_items"."cart_id" = 55005260 ORDER BY created_at
(1.9ms) BEGIN
SQL (2.4ms) DELETE FROM "carts" WHERE "carts"."id" = $1 [["id", 55005260]]
(6.5ms) COMMIT
Redirected to https://mysite-rc-preview.mysite.com/
Completed 302 Found in 408ms (ActiveRecord: 42.0ms)
Cache read: https://mysite-rc-preview.mysite.com/?
Started GET "/" for 69.193.194.58 at 2013-09-04 12:09:39 -0400
Processing by SiteController#index as HTML
Redirected to http://mysite-rc-preview.mysite.com/
Filter chain halted as :ensure_proper_protocol rendered or redirected
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)
Cache read: http://mysite-rc-preview.mysite.com/?
Started GET "/" for 69.193.194.58 at 2013-09-04 12:09:39 -0400
Processing by SiteController#index as HTML
inside setup_cart. current_cart_id is 54993421
54993421
request.session_options[:id] = 4bec2bbc42e8213be89aaf6431b41535
inside not user_signed_in? clause of setup_cart
It redirects me to the homepage after log in, which is okay, but after that it redirects from http:// ... / to https:// ... / , which causes the user to not be signed in anymore. Could this be because my sessions aren't being stored in the database as I configured them to be? I do have this line in my config/initializers/session_store.rb:
mysite::Application.config.session_store :active_record_store
I have this route that let me build custom url for users like
/thisismyname, and it works fine. But when I look at the log there is
something I don't like...
When I hit /gregory this is what is happenning:
1. Going to public_profile#public # Good
2. hitting /assets and trying to find a user with asset token # Not good
I thought my constraints would avoid this but it doesn't seem like it...
class PublicProfileConstraint
def self.matches?(request)
!['assets', 'admin'].include?(request.session[:token])
end
end
get "/:token" => "profiles#public", :as => :public_profile,
:constraints => PublicProfileConstraint
Here is the log:
Started GET "/gregory" for 127.0.0.1 at 2012-03-05 12:44:43 -0800
Processing by ProfilesController#public as HTML
Parameters: {"token"=>"gregory"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE
"users"."id" = ? LIMIT 1 [["id", 1]]
User Load (0.3ms) SELECT "users".* FROM "users" WHERE
"users"."token" = 'gregorymarcilhacy' LIMIT 1
Rendered profiles/_modal.haml (0.1ms)
....
Rendered profiles/show.haml within layouts/application (154.7ms)
Completed 200 OK in 431ms (Views: 174.0ms | ActiveRecord: 5.5ms)
... Redering js files ...
# I DONT WANT THIS
Started GET "/assets/" for 127.0.0.1 at 2012-03-05 12:44:45 -0800
Served asset - 404 Not Found (10ms)
Processing by ProfilesController#public as */*
Parameters: {"token"=>"assets"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE
"users"."id" = ? LIMIT 1 [["id", 1]]
User Load (0.3ms) SELECT "users".* FROM "users" WHERE
"users"."token" = 'assets' LIMIT 1
Redirected to http://localhost:3000/
Completed 302 Found in 312ms
... Rendering images ...
# AND I DONT WANT THIS
Started GET "/" for 127.0.0.1 at 2012-03-05 12:44:45 -0800
Processing by LandingController#landing as */*
User Load (0.3ms) SELECT "users".* FROM "users" WHERE
"users"."id" = ? LIMIT 1 [["id", 1]]
Rendered landing/landing.haml within layouts/landing (0.8ms)
Completed 200 OK in 288ms (Views: 23.5ms | ActiveRecord: 2.2ms)
You are searching request.session for the token, but this will always fail as that's the session store rather than the request parameters. You probably want the equivalent of params[:token] in the constraint class. The request object documentation indicates that request.path_parameters[:token] might contain the value you are looking for.
I have a destroy method within a notecards controller that I am calling from a users page to delete a notecard. In the first example below.. the redirect is passing the notecard ID resulting in a page not found, while the second the user ID is being passed correctly finding the user page.. can someone help me understand why?
Redirects to user passing id of notecard
def destroy
#note = Notecard.find_by_id(params[:id])
delete_note(#note)
redirect_to user_path(#current_user)
end
Redirects to user passing id of user
def destroy
#note = current_user.notecards.find_by_id(params[:id])
delete_note(#note)
redirect_to user_path(#current_user)
end
Update:
Thanks for the responses. The code is here: https://github.com/incorvia/plumnotes/.. The authentication is in the sessions helper and the sessions controller. As for the log:
With Notecard.find_by_id(params[:id])
Started DELETE "/notecards/177" for 127.0.0.1 at 2011-10-15 11:53:38 -0400
Processing by NotecardsController#destroy as HTML
Parameters: {"authenticity_token"=>"WctbONb/qAO+hesHZ6Yw5zU19eCPNGeILIhxnW9Pi1Y=", "id"=>"177"}
Notecard Load (0.3ms) SELECT `notecards`.* FROM `notecards` WHERE `notecards`.`id` = 177 LIMIT 1
SQL (0.8ms) DELETE FROM `notecards` WHERE `notecards`.`id` = 177
Redirected to http://localhost:3000/users/177
Completed 302 Found in 12ms
Started GET "/users/177" for 127.0.0.1 at 2011-10-15 11:53:39 -0400
Processing by UsersController#show as HTML
Parameters: {"id"=>"177"}
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 9 LIMIT 1
User Load (0.6ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 177 LIMIT 1
Completed 404 Not Found in 14ms
ActiveRecord::RecordNotFound (Couldn't find User with id=177):
app/controllers/users_controller.rb:11:in `show'
Rendered /Users/Kevin/.rvm/gems/ruby-1.9.2-p290#notes/gems/actionpack-3.1.0/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.4ms)
Rendered /Users/Kevin/.rvm/gems/ruby-1.9.2-p290#notes/gems/actionpack-3.1.0/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.0ms)
Rendered /Users/Kevin/.rvm/gems/ruby-1.9.2-p290#notes/gems/actionpack-3.1.0/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (4.6ms)
With current_user.notecards.find_by_id(params[:id])
Started DELETE "/notecards/179" for 127.0.0.1 at 2011-10-15 11:56:18 -0400
Processing by NotecardsController#destroy as HTML
Parameters: {"authenticity_token"=>"WctbONb/qAO+hesHZ6Yw5zU19eCPNGeILIhxnW9Pi1Y=", "id"=>"179"}
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 9 LIMIT 1
Notecard Load (0.6ms) SELECT `notecards`.* FROM `notecards` WHERE `notecards`.`user_id` = 9 AND `notecards`.`id` = 179 LIMIT 1
SQL (0.9ms) DELETE FROM `notecards` WHERE `notecards`.`id` = 179
Redirected to http://localhost:3000/users/9
Completed 302 Found in 95ms
Started GET "/users/9" for 127.0.0.1 at 2011-10-15 11:56:18 -0400
Processing by UsersController#show as HTML
Parameters: {"id"=>"9"}
Hard to guess what is defined to local var #current_user and where it occurs.
If you really interested, why, - probably more piece of code could be helpful.
Sometimes, keep it simple could be quite an interesting idea (:
redirect_to user_path( current_user.id )
It seems that #current_user wasn't actually being defined for the #Notcard controller unless the current_user method was called. That's why that the current_user.notecards... worked
It also seems that with user_path(#current_user) .. if #current_user isn't defined then it just takes the id from the params.. which happens to be the notecard id and not a user id...
The solution to fixing it was to either user current_user.notecards.. or add a before_filter for the controller that authorizes users and defines the #current_user instance variable :-)
This is my route:
scope ":username" do
resources :feedbacks
end
So when I go to mydomain.com/test/feedbacks/10 it shows the correct feedback with id=10 that belongs to username=test.
But, if I go to mydomain.com/test2/feedbacks/10 it shows me the same feedback with id=10, which does NOT belong to username=test2.
How do I restrict this from happening?
I am using the Vanity gem to give me the username in the URL, this is what that route looks like:
controller :vanities do
match ':vname' => :show, :via => :get, :constraints => {:vname => /[A-Za-z0-9\-\+\#]+/}
end
Edit 1:
That is to say, for clarity's sake, when I go to mydomain.com/test/feedbacks/10 and /test2/feedbacks/10, it shows me the same view for the same record (in which case, the latter version would be wrong because it should be telling me that no such record exists, but it's not. It is just displaying the correct record for test/feedbacks/10).
Edit 2:
Here are the logs of both requests:
The right request
Started GET "/test-3/feedbacks/7" for 127.0.0.1 at 2011-09-14 02:48:15 -0500
Processing by FeedbacksController#show as HTML
Parameters: {"username"=>"test-3", "id"=>"7"}
Feedback Load (0.5ms) SELECT "feedbacks".* FROM "feedbacks" WHERE "feedbacks"."id" = ? LIMIT 1 [["id", "7"]]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
Rendered feedbacks/show.html.erb within layouts/application (36.2ms)
Completed 200 OK in 188ms (Views: 184.3ms | ActiveRecord: 1.8ms)
The wrong request
Started GET "/test2/feedbacks/7" for 127.0.0.1 at 2011-09-14 02:48:28 -0500
Processing by FeedbacksController#show as HTML
Parameters: {"username"=>"test2", "id"=>"7"}
Feedback Load (0.1ms) SELECT "feedbacks".* FROM "feedbacks" WHERE "feedbacks"."id" = ? LIMIT 1 [["id", "7"]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
Rendered feedbacks/show.html.erb within layouts/application (37.6ms)
Completed 200 OK in 50ms (Views: 47.5ms | ActiveRecord: 1.2ms)
Your show action should look something like
def show
#user = User.find_by_username(params[:username])
if #user == current_user
...
render "show"
else
flash[:alert] = "Record doesn't exist"
redirect_to root_path
end
end
I took the liberty of adding in #Benoit's suggestion.