Ruby On Rails authentication with Devise and (warden) callbacks - ruby

I have a rails app that is using Devise, with a User model, no scope.
I've also added activeadmin gem in to the app, Active Admin is a gem used for adding an admin dashboard in your application. It uses Devise for logging in users and creates a separate admin_user model for the admins.
I am allowing anonymous, non-logged in users to create shopping carts, creating a session[:cart_id]. If a user logs in I want associate the user with the cart, something like
Cart.find(session[:cart_id]).user = current_user
I was planning to use Wardens callbacks wardens callbacks to impliment this, something like so :
Warden::Manager.after_set_user :scope => :user do |user, auth, opts|
Cart.find(session[:cart_id]).user = user
end
However I get an error if I do that:
<% unless user_signed_in? %> throws an error :admin_user user is not logged in
Anyone got any ideas what is going on?
I've looked at related questions, but no help:
How to access session from Warden/Devise after_authentication callback in Rails
Where should warden callbacks be placed in a rails app?

The AdminUser model that Active Admin uses also executes this callback. So, maybe, an if can solve your problem:
Warden::Manager.after_set_user :scope => :user do |user, auth, opts|
Cart.find(session[:cart_id]).user = user if user.class == User
end

Actually it turned out the issue was solved by setting the default scope in warden,in the devise initializer file.
# Configure the default scope given to Warden. By default it's the first
# devise role declared in your routes (usually :user).
# config.default_scope = :user
Since the active admin routes were added above the devise routes for my user, the adminuser became the default user.

Related

Building an OmniAuth strategy with a custom workflow

I want to achieve the following login workflow:
user clicks on login button
user gets redirected to our authentication platform
user submits the login credentials and then gets redirected back to our
website via a pre-set callback URL
the OmniAuth strategy must decode the response (using our SDK) and
save the result in the omniauth.auth hash
Is this process easily achievable using a OmniAuth Strategy? It's not very clear to me from the documentation, and the majority of already built strategies seem to be using the OAuth workflow.
Apparently this is quite easy to do.
The OmniAuth strategy
module OmniAuth
module Strategies
class Service
include OmniAuth::Strategy
def request_phase
redirect AUTHENTICATION_URL
end
uid { #user_details.user_id }
def extra
#user_details # Return a hash with user data
end
def callback_phase
# Configure Service SDK
#user_details = Service.user_data # Make SDK call to get user details
super
end
end
end
end
The App
1) Add a login button with the authentication URL:
<%= link_to 'Login', 'auth/service' %>
2) Add a callback route
get '/auth/service/callback', to: 'sessions#create'
3) Handle the callback response in the controller
class SessionsController < ApplicationController
def create
#user = User.find_or_create_by(service_id: auth_hash.uid)
# Handle #user
end
end

Ragarding ruby on rails sessions

In my rails application, I'm using a devise gem for user sign in and sign out.
After a successful sign in, I want to store data in the user's session. How can I do this?
This may help you.
To verify if a user is signed in, use the following helper:
user_signed_in?
For the current signed-in user, this helper is available:
current_user
You can access the session for this scope:
user_session
As you mentioned need to add data to session code goes here
adding this to my config/initializers/devise.rb file
Warden::Manager.after_authentication do |user,auth,opts|
auth.raw_session['warden.user.user.email'] = user.email
auth.raw_session['warden.user.user.username'] = user.username
end

rails role based access using cancan

There is no user and roles table. I have a tabless model for users and roles. user information is set in the application controller with the values from the environmental variables, for this one I have hard coded the value. The role information comes from the service.
#Application controller setting the user object
before_filter :set_user
def set_user
#user = User.new(:id => 123)
end
I am using cancan for authorization and ability.rb doesnt see this #user or user and comes in as nil.Does ability load before the application controller? Am I missing anything in the controllers for cancan? I have load_and_authorize_resource in the controllers.
Any suggestion will be greatly helpful.
Thanks
Ramya
Add this method in your ApplicationController if you don't have it:
def current_user
#user
end

Sessions & User Authentication in Padrino

I'm very new to Padrino (I come from a PHP background), and ruby web frameworks in general, and have been trying to figure out how to implement a simple user authentication and session management system, but have not really found much documentation on the subject. I know that padrino comes with a pre-built "Admin" package that includes user login/authentication, ect, however I'd rather roll my own from scratch, rather than trying to customize their solution to fit my own needs.
So my question is, in Padrino how would I go about implementing a simple session-based authentication system for logging in users by setting session data once a user/pass combo has been validated against the database, retrieving that session data to check if the user is logged in when a request is made to protect certain pages/resources, use the session data to get the user's ID/role/ect, and then destroy that session when user logs out. As a PHP programmer I'm used to using the $_SESSION superglobal for this purpose, is there something akin to this in padrino/ruby? I noticed there is a enable :sessions in app.rb, is :sessions the pardrino equivalent?
Yup,
session[:cart] = cart_id
Cart.find(session[:cart].to_i) if session[:cart].present?
For authentication purposes you can avoid padrino-admin and builtin auth using a more more simple way:
# in app.rb
use Rack::Auth::Basic, 'Restricted Area' do |username, password|
user == 'admin' and password == 'pwd'
end
If you need to control a bit more your sessions/cookies you can use:
set :sessions,
:key => '__awesome_key',
:secret => 'awesome_password',
:expire_after => 1.year

Sinatra App with multiple users

What is the easiest way to allow for multiple users in a Sinatra web app. I've previously used an authorization class that allows for one username and password, but what if I want to allow users to sign up for a simple web app and allow them all their own login credentials?
Thank you so much!
If HTTP basic auth is sufficient I'd recommend defining two methods like this:
helpers do
def protected!
unless authorized?
response["WWW-Authenticate"] = 'Basic realm="Protected Area"'
throw(:halt, [401, "Not authorized\n"])
end
end
def authorized?
#auth ||= Rack::Auth::Basic::Request.new(request.env)
if #auth.provided? && #auth.basic? && #auth.credentials
username,password = #auth.credentials
# verify credentials are correct
end
end
end
Call protected! from any action that should be protected (or use a before block to protect everything). I leave the credential verification to you since I don't know how you're storing user account information.
The sinatra-authentication gem looks like an easy and powerful solution for adding users, authentication and permissions to sinatra apps.

Resources