Admin access filter - yii

I have been having this weird experience with my Yii app. I created an account 'admin' and this admin created an additional admin account called 'sample'. Now sample, is successfully created and added to the authassignment table as an admin. Here is proof that user 204 is an admin.
Checkuser access also proves to be true that the sample account is an admin. But somehow, accessing the admin functions of a certain controller returns error 403 when logged in as sample but the other admin account admin, user 0 access it fine. Here's the access rule of the controller.
public function accessRules()
{
return array(
array('allow', // allow all users to perform 'index' and 'view' actions
'actions'=>array('index','view','update'),
'users'=>array('*'),
),
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','delete','dynamicUnitName'),
'users'=>array('admin'),
),
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions'=>array('create','update'),
'users'=>array('#'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
What is wrong with my app and why is it acting this way?

You should use roles instead of users. users holds the names of users. For more information look at the Yii page on access control
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','delete','dynamicUnitName'),
'roles' => array("admin"),
),

Change
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','delete','dynamicUnitName'),
'users'=>array('admin'),
),
To
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','delete','dynamicUnitName'),
'expression' => 'Yii::app()->user->role == "admin"',
),

Related

Skip email confirmation when creating a new user using Devise

I have a user registration page and will send the information to couple of admin users that one new user registered in the site.
Now, I created the seed data with list of users (200+). So, It'll send the 200+ email to the respective admin users. Hence, I want to stop send the mail confirmation to admin users when creating new user.
For Devise, add user.skip_confirmation! before saving.
user = User.new(
:email => 'person#example.com',
:password => 'password1',
:password_confirmation => 'password1'
)
user.skip_confirmation!
user.save!
Cite: https://github.com/plataformatec/devise/pull/2296
Another option is to do something like
user = User.new.tap do |u|
u.email = 'email#server.com'
u.password = 'hackme!'
u.password_confirmation = 'hackme!'
u.skip_confirmation!
u.save!
end
In that way, you instantiate the object, skip the confirmation and save it in one step and return it to the user variable.
It's just another way to do the same in one step.

Login to other user's account with Devise+Active Admin+Switch User

I'm trying to implement switch_user gem in my existing rails 3.0.9 application.
There are two models on my application, they are
User - for my customer accounts and it has_one Account
AdminUser - This was created by ActiveAdmin
I have already enabled devise authentication for Users and ActiveAdmin also working pretty much well with AdminUser. Now from my Active Admin interface I'd like to select the Accounts and login to those account just like the account owner does. Switch user is working fine but the problem is anyone can simply login to the user accounts now if they know the urls.
http://localhost:3000/switch_user?scope_identifier=user_1
All I need is allow only an AdminUser (i.e if there is an ActiveAdmin session) to access the User's accounts.
This is how my /config/initializers/switch_user.rb looks like
SwitchUser.setup do |config|
config.controller_guard = lambda { |current_user, request| current_admin_user.nil?}
config.redirect_path = lambda { |request, params| "/dashboard" }
end
But I get this error
NameError in SwitchUserController#set_current_user
undefined local variable or method `current_admin_user' for main:Object
Is there anyway I can access the active admin session?
Code for /config/initializers/active_admin.rb
ActiveAdmin.setup do |config|
config.site_title = "MyAppName"
config.authentication_method = :authenticate_admin_user!
config.current_user_method = :current_admin_user
end
btw in my application controller I haven't created any methods for authenticate_admin_user , current_admin_user active admin works fine without them.
You need modify local config/initializers/switch_user.rb:
config.controller_guard = lambda { |current_user, request, original_user, controller|
controller.admin_user_signed_in?
}
Original lambda has 2 arguments.
Just append more (up to 4) and use it.
Don't forget restart rails server :)
OK I think I found a solution to secure the switch_user. All I did is moving the routes inside the admin_users scope
ActiveAdmin.routes(self)
devise_for :admin_users, ActiveAdmin::Devise.config do
match '/admin/switch_user', :controller => 'switch_user', :action => 'set_current_user'
end

Yii: How to authenticate using two different tables

Does anyone know how to do separate login forms and authenticate on two different tables?
I can't go with one table and different roles... client requested to do separate tables...
I've got user login system based on Yii framework login system. But now I have to do separate for admin user (administration module).
The way I solved this issue was to create two identical copies of this plugin from the Yii Framework library:
http://www.yiiframework.com/extension/yii-user/
Then I refactored it and called it "Customer" and changed the config so that it used a different table etc.
In the configuration options for Yii, I also included these options to keep the sessions separate (config/main.php):
'components' => array(
...
'user' => array(
// enable cookie-based authentication
'allowAutoLogin' => true,
'loginUrl' => array('/user/login'),
'class' => 'RWebUser', // added - possibly uses the Rights user manager
),
'customer' => array(
// enable cookie-based authentication
'allowAutoLogin' => true,
'loginUrl' => array('/customer/login'),
'stateKeyPrefix' => 'customer',
),
'customerUser' => array(
'class' => 'CWebUser',
'stateKeyPrefix' => 'customer',
'loginUrl' => array('/customer/login'),
),
You could add a property to your UserIdentity component called, for example, role. Then change the authenticate() method of UserIdentity so that it fetches from the account table corresponding to role. Now you need to make sure that UserIdentity->role is set before invoking UserIdentity->authenticate(). If you are following the yiic webapp template then this would be in SiteController. Two very easy ways (among others):
Have two different login pages, one for normal users and one for admins and each has its own URL. Implement it with two views and two login action methods in SiteController, each sets up UserIdentity->role appropriately before invoking UserIdentity->authenticate(). This approach duplicates code and you'll be able to see how to sort that out once it's working.
Use one login page with a form element (checkbox perhaps) that an admin user selects. This form's action method UserIdentity->role according to form state.

CanCan and Devise, restricting login based on Role

I've just finished setting up Devise on a single application, using a single User model with two scopes, so I can have an /admin/login as well as a regular /users/login path. This works pretty well, my config/routes.rb file looks like this:
devise_for :users,
:path_names => { :sign_in => 'login', :sign_out => 'logout' }
devise_for :admins,
:class_name => 'User',
:skip => [:passwords, :registrations, :confirmations, :sessions],
:controllers => { :sessions => 'admin/sessions' } do
get 'admin/login' => 'admin/sessions#new', :as => :new_admin_session
post 'admin/login' => 'admin/sessions#create', :as => :admin_session
delete 'admin/logout' => 'admin/sessions#destroy', :as => :destroy_admin_session
end
This works pretty fine and dandy, I can log in to each side of the application without affecting the other. That is, the session names are separate and logging into one does not log you into the other.
Now, I've set up CanCan with my Roles model, and an Ability model, and have these defined in my database and working.
Question is, I want to be able to fill out the form on admin/login, and receive an error message because my Role doesn't allow me to log into that area. How can I accomplish this?
I am a bit confused by your question. If you are filling out the form on admin/login, then presumably you have not logged in yet?
If that's the case, then there is no current_user or current_admin and therefore nothing is passed to CanCan yet.
I have a similar set-up in my app and maintain different accounts on each side of the app. My user account is different than my admin account. If I forget and try to login to the admin side using my regular user account, I simply receive an unknown user/password error from Devise.

How to create the first (Admin) user (CanCan and Devise)?

I made authentication in my Rails 3 app fallowed by Tony's tutorial
I don't want public registrations on my app, just to create new users with Admin account, but I can't create Admin account manually, because in table Users there is encrypted password and salt that must to be generated, and I don't know how :|
You can do it from the rails console. From the command line goto the directory of your rails application and type rails console. Then enter the following code to create a user:
user=User.create!(:email=>'test#test.com',:username=>'test',:password=>'password')
This will create a user object (assuming your devise resource is called User). Now you can use the user object that you just created to set admin privileges.
I am current something like this (your details may be different) in my seeds.rb file to create my admin user for Devise.
User.new({ :email => 'admin#example.com', :password => 'password', :password_confirmation => 'password'}).save
You can execute it using rake db:seed in the terminal window.
In addition, if you are using confirmable and want to skip the requirement for a confirmation email when creating new accounts you can do something like this:
newuser = User.new({ :email => 'admin#example.com',
:password => 'password',
:password_confirmation => 'password'})
newuser.skip_confirmation!
newuser.save
This is useful if the accounts you are creating are for trusted users or if you are creating test accounts.