Authenticate users by Customer, Login and Password with Authlogic - ruby-on-rails

I've got a typical Authlogic setup that I need to enhance to require Customer ID in addition to Login and Password.
I've read a bit about using a custom find method and another about using a global variable for accessing the additional parameter and a third referring to documentation about using scopes that doesn't seem to exist.
Seems like this should be easy, but I can't seem to find the right approach.
Anyone got a solution?

In your UserSession class, add:
find_by_login_method :find_by_customer_id_or_login
In your User class, create this customer finder:
def self.find_by_customer_id_or_login(login)
User.find_by_customer_id(login) || User.find_by_login(login)
end
This is assuming a User has both a customer_id field and a login field.

Add a customer_id column through a migration and validate_presence_of :customer_id on your model. It doesn't have anything to do with authlogic. Unless there is more that you are trying to do.

Related

Setting Pundit role for user from Devise Registrations New View / Controller

I have both Pundit and Devise setup and working correctly in my rails app. However I am unsure about how to let the user decide their role when signing up.
At the moment:
I have a URL param which is passed to the Devise new view.
In the form_for I set a hidden field called role to the value of the param.
This works.
But I am concerned that a malicious user could change this param to say "Admin" and now they are an admin.
How should I handle this? I don't want to put a restriction in the model as that will cause issues when I want to create an admin. Should I override the devise registrations controller to put a check in there?
You don't need to override Devise's RegistrationsController for what you're trying to do.
If you want admins to be able to create users that have an arbitrary role set, you could simply use your own controller. Devise still makes it easy to create a user yourself, so you'll just have to make a controller handling this. Of course, don't forget to protect it using Pundit so only admins can use this functionality.
This approach still works if you use the Confirmable module. As no confirmation e-mail will be sent on user creation, though, you'll either have to call user.confirm! after saving the model to immediately unlock the account, or manually send the confirmation e-mail using user.send_confirmation_instructions.
Edit:
This Pundit policy may or may not work for what you're trying to do. You will have to override the create action of Devise's RegistrationsController here in order to use Pundit's authorize method. For dryness' sake, you should also move the roles list elsewhere, perhaps into the model.
class UserPolicy < Struct.new(:current_user, :target_user)
def create?
registration_roles.include?(target_user.role) if current_user.nil?
end
private
def registration_roles
%w(RED BLU Spectator)
end
end
After a fair amount of googling I have an answer. First stick some validation in your model for the roles Active Record Validations Guide: See 2.6 inclusion: validator option
After this your roles are validated to ensure they are correct, you could of course have a lookup table as well. Then you have two options:
Use a conditional before_save Callback for new records. Then check if the new record has the role your protecting and if so raise an error. To catch later (in an overridden devise controller (see second option).
Override the Devise registrations controller See this SO question. And put some checks in a completely overridden create action. Use the session to store the url param passed to the new action (also needs to be completely overridden). Then if the create action fails and redirects to new you still have access to the role in the session (as the param will be cleared from the URL unless you manipulate it).
So either way you need to override the registrations controller, its just a case of how much.
I suspect there is a way to do this with just Pundit. But I have yet to be able to get it to work.

Override authlogic's email validation

I am making a login using AuthLogic, but I would like 'email' to be optional. It seems however that authlogic out of the box makes this validated for. Anyone know a workaround?
from the authlogic example rails application:
Set up your model
Make sure you have a model that you
will be authenticating with. Since we
are using the User model it should
look something like:
class User < ActiveRecord::Base
acts_as_authentic do |c|
c.my_config_option = my_value # for available options see documentation in: Authlogic::ActsAsAuthentic
end # block optional
end
One thing to note here is that this tries
to take care of all the authentication
grunt work, including validating your
login, email, password, and token
fields. You can easily disable this
with configuration. Ex:
c.validate_email_field = false. See
the Authlogic::ActsAsAuthentic sub
modules in the documentation for more
details.
Key part to note:
You can easily disable this with configuration. Ex:
c.validate_email_field = false.
Hope that helps.
Source: https://github.com/binarylogic/authlogic_example
While searching my contents ..i found out
http://rdoc.info/github/binarylogic/authlogic/master/Authlogic/ActsAsAuthentic/Email/Config#merge_validates_format_of_email_field_options-instance_method
this will surely help..

Steps to create my own authentication system, need some guidance

I want to learn how to create my own authentication system, please provide some guidance if am doing this wrong.
I will create a Module in my /lib folder /lib/auth.rb
I will require this module in my ApplicationController.
when a user enters their email + password, I will call a method that will do a lookup in the user's table for a user with the same email, I will then compare the passwords. (i'll add encryption with salt later).
If the user entered the correct credentials, I will create a row in the Sessions table, and then write the session GUID to a cookie.
Now whenever I need to check if the user is logged in, or I need the user object, I will check if the cookie exists, if it does, I will lookup the session table for a row with the same guid, if it exists, I will return the session row and then load the User object.
I realize there are many suggestions one can give, but in a nutshell does this sound like a workable solution?
Now to make this usable, I will have to make some helper methods in my ApplicationController right?
How will I access the current_user from within my views?
P.S I know of other authentication systems, I just want to learn how to create my own.
The basic logic you're following is correct. Of course you can always expand on this with features that you need. For instance, you'll need helper methods for things like "logged_in?" and "current_user". Also, you might want to add session expiry, or session retention as a "remember me" feature.
Go for it, you won't learn authentication systems better than building your own then figuring what's wrong with it.
You should really check out the authlogic gem on github.
http://github.com/binarylogic/authlogic
It also has great instructions on how to set up your users.
After Faisal said what I would say, I only give you answer to the last part of your question:
"How will I access the current_user from within my views?"
try something like this:
class User < ...
def self.current=(u)
#current = u
end
def self.current
#current
end
end
In your views (or any part of your code) you can call User.current. Your controller has to assign a validated user to User.current. Your filters can react to "if User.current.nil?" and so on.
If you want to be thread safe, you may use a thread variable instead of #current:
Thread.current[:current_user] = u

Validate password on change of certain fields in RoR

I am building a RoR 3 app, a community. It has a User model and some fields.
So when a user is updating a certain field, like his/her birthday, I want to validate that the User typed in the password that is the same in the database. This way I know that it is the right user trying to change the birthday.
So I ask you how i can create such a validator.
Also I would like to be able to specify an array of which fields the user has to validate the password to change.
This is actually pretty easy to do once you are familiar with the Rails framework.
models/User.rb
class User < ActiveRecord::Base
validate :correct_password?, :if => :check_password?
def check_password?
[birthday_changed?, other_field_changed?].any?
end
def correct_password?
# without knowing more about how you store the password
# this probably won't work with your code directly
errors.add_to_base("Must provide password") unless password?
errors.add_to_base("Incorrect password") unless password == User.find_by_id(id).password
end
end
Even though building user authentication and authorization is not hard - I would advise to use something like "AuthLogic" or "Devise" gems/plugins which will most likely cover 90% of the functionality that you need. You alsways can customize/add new functionality if needed.
Such plugins will do most of the grunt work for you: generate MVC, create database, do proper security checks, even email password recovery and such.

Authlogic-oid with ONLY OpenID

I am implementing an internal site, for which I want our company's OpenID server to be the only means of registering and logging in. To be more specific, I don't even want a normal email and password/salt to be stored for the users in this site.
I am using authlogic with the authlogic-oid plugin, but I am getting these errors whenever I try to make a new user:
undefined local variable or method `crypted_password_field' for #<User:0xb68b7c00>
I take this to mean that authlogic is trying to generate a password for this user even though there are no password fields in my database. Is there a workaround for this, or config options I can pass to acts_as_authentic to make this work?
Figured it out. In your User model, you must specify this config in the acts_as_authentic block:
class User < ActiveRecord::Base
acts_as_authentic do |c|
c.crypted_password_field = false
end
end
Looks like maybe you're trying access the crypted_password_field property somehow. If you look at the Authlogic example the documentation lists the optional fields (#3). I was able to get Authlogic and RPX up and running without password fields so I know it's possible.

Resources