Use Authlogic with Typus - ruby-on-rails

I'm switching to Typus because I prefer its UI over ActiveScaffold and I love the way you can set roles for the admin section. We need that.
However, where ActiveScaffold worked flawlessly with Authlogic, Typus doesn't. I'd like to combine the two anyway, but can't seem to find out how. Typus has very basic password encryption, but I can't write a crypto_provider for it, because it depends on a very simple Sha1-encryption of the salt and the password. Authlogic doesn't support that, because it doesn't send along the actual password.
I'd hate it if we had to use two User models for the front- and backend. I don't need Authlogic to be the authentication method for Typus, but they should both at least be able to compare the password with the crypted one.
Is there anyone out there who has worked around this issue?
Thank you.

I'm not entirely happy with it, but I think I've found an answer to my own question.
I've let Typus create the AdminUser, added a user_id to it and added this method to it and I call it in a before_save:
def sync_user
self.user ||= User.find_by_email(self.email)
if user = self.user
user.email = self.email
user.password = self.password
user.password_confirmation = self.password_confirmation
user.save
end
end
This seems to do the trick for me. I'd love to do it differently, but it works for now.

Related

Send Password Reset to a Different Email - Devise

I'm using ruby on rails 5 with devise and I need to send a password reset email to a different email than the one stored in my User table. How can this be achieved?
Please note: it is pretty unrecommended way to implement things.It is not within scope of the best practices.
It is dirty and fragile.
But if you really need to achieve it no matter how dirty are the measures, this is it.
Well, the requirement to send the reset instruction to other email is already weird enough. Is it really a last resort?
Anyway,
You've not specified the Devise version but that behaviour was unlikely changed too much so lets take the current master and look how it sends emails:
https://github.com/plataformatec/devise/blob/f39c6fd92774cb66f96f546d8d5e8281542b4e78/lib/devise/mailers/helpers.rb#L31
def headers_for(action, opts)
headers = {
subject: subject_for(action),
to: resource.email,
So, the getter is somewhat hardcoded.
Though, it is possible to create a token and set it as Devise does:
https://github.com/plataformatec/devise/blob/d1948b79d3e933253baa753bd033c92171c0a7d0/lib/devise/models/recoverable.rb#L89
def set_reset_password_token
raw, enc = Devise.token_generator.generate(self.class, :reset_password_token)
self.reset_password_token = enc
self.reset_password_sent_at = Time.now.utc
save(validate: false)
raw
end
And when find in sources how Devise sends it and try to somehow replicate it but using your custom email.
I think the less evil in this case would be just implementing your own mailer for that kind of reset instructions which would use the same URL as Devise does.
Otherwise you would have too much coupling with a current version of Devise.

Decryptor for bcrypt

The title is pretty self explanatory. I'm not sure if this exists, as it would greatly compromise the security of bcrypt, but i'm using Devise in a rails app and forgot my password. However I can access the server and find the info. I can see the encrypted password and need to decrypt it.
I do not want alternate solutions to the problem, i just want a decryptor so I can get the password.
Why don't you just spin up a Rails console and re-assign your password manually?
u = User.find_by_username('myname')
u.password = u.password_confirmation = 'reset_password'
u.save
Usually something along those lines will work.

OmniAuth and Devise, how to set optional passwords

I am using OmniAuth and Devise to authenticate users. I would like users that have signed up using OmniAuth providers to be able to set an optional password (needed for API authentication) but I'm running into a wall.
If a user creates an account via OmniAuth and tries to set a password they get the following error:
BCrypt::Errors::InvalidHash in RegistrationsController#update
I believe this is because the password is blank. What's a good way around this? I've thought about generating a random password but the problem with that approach is the user needs to know the current password in order to edit settings.
Edit:
I looked at allowing the user to change settings without requiring a current password and that's what I would like to do only if the user didn't have a password initially.
An alternative is to add the following into your 'user' model class to bypass password verification if there is no password to verify, where provider is some field that is set when using external authentication.
def valid_password?(password)
!provider.nil? || super(password)
end
I assume you don't want the easy way out which would be to simply reset the password if they wanted to set it?
user.send_reset_password_instructions
This comes a bit late but it might help someone else, with Andrew's answer you can in create a password and store it in the database, but you can't login using your email and your new password, solved this by setting:
def valid_password
!provider.nil? && !encrypted_password.present? || super
end
Another alternative. You don't have to include a new field. Just catch the exception raised and return false. Here is the code.
def valid_password?(password)
begin
super(password)
rescue BCrypt::Errors::InvalidHash
return false
end
end
This should do the job.

RoR testing controllers

I use RoR 3 and i guess something changed in controller's tests.
There is no
def test_should_create_post
but
test "should create user" do
...
end
Is there any decription how is that mapping etc? Because i dont get it.
And second thing. How to program (what assertion) use to test login?
so the test "something here" style is rails way of helping us out. It is fundamentally the same as def test_as_you_want but they helped us out by taking away those nasty '_(underscores)' and wrapping the actual test wording in a string. This change came back, phew... maybe 2.3.x. that fact has to be checked but at least a year and a half ago.
Your second thing is a little more harder to answer man. What plugin are you using, or are you one of those guys who are writing their own auth system?
Either way, check out how the 'famous' auth plugins do it. from Restful Auth to Devise, basically you want test that you can:
Signup for the User account
all of your confirmation emails are sent etc..
Most of these 'cheat' or take the easy way out by passing a helper called signed_in users(:one) for instance. Assuming you are cool and using fixtures.
Basically here is what a helper method looks like if your Auth plugin/gem doesn't have one, like Clearance which didn't have it when i was first writing my tests... not sure if it has it now but it sheds light on how it should look. Notice I've commented out Restful Auth and how he/they did it:
#login user
def login_user(user = users(:one))
#Restful Auth Example
# #request.session[:user_id] = user ? users(user).id : nil
# Clearance
#controller.class_eval { attr_accessor :current_user }
#controller.current_user = user
return user
end
Actually i think i stole this from their shoulda login helper... that's probably what i did. Either way it shows you how to fake login a user.
Now when you are testing, just pass this login_user method to your test when you need a user logged in and start testing the rest of the method without worrying about them actually signing in. That is what the plugin is supposed to do and the 1000 people following it on github would scream if it didn't at least LOG that guy in.
cheers

How to search a record in RoR?

I know that I can use Query language to find the record I want. I am doing a login page, I want to find the record which match the user name and password, but I don't want to loop all the elements to find out the user I want (<% #users.each do |user| %>), wt should I do in RoR, except typing SQL.
perhaps:
User.first(:conditions => {:login => 'ted', :password => 'secret'})
# returns nil for no match and first match for a good record
# make sure there is a unique index on login
For authentication I would strongly recommend authlogic (railscast)
You can use dynamic finders to find user by user_name and password:
#user = User.find_by_user_name_and_password('scott', 'tiger')
While the other answers provided by Sam and Chandra are technically correct, both solutions implies that passwords are stored in plain text--which is a very bad idea. If somebody who shouldn't gets access to your database, they'll have a full set of usernames (and potentially email addresses), combined with all of their passwords.
Instead, consider using an algorithm to make sure your password is encrypted in the database, such as bcrypt. You'll need the bcrypt-rub gem to use it.
You should also consider leaving out the password from the query altogether. This is good practice as it provides an extra level of security; SQL injections become more difficult to perform. If users have unique usernames, just fetching the username should return the same object, after which you can check if the password is correct:
#user = User.find_by_username(params[:username])
if #user.password == params[:password]
# do something
else
# do something else
end
Ideally, you should both use bcrypt and leave out the password from the query. How to do this is described in the bcrypt-ruby readme on GitHub (the link I provided).

Resources