Rails 3.0
Authlogic 2.1.6
Using username (not email) for authentication.
Authlogic requires username to be at least 3 characters.
How does one convince Authologic to allow a 2 character username?
Thanks for your help.
You can override the authlogic default username length by adding the following code to models/user.rb
class User < ActiveRecord::Base
acts_as_authentic do |c|
c.merge_validates_length_of_login_field_options :within => 4..100
end
#....
end
This assumes your user model is called User
Related
In the Ruby on Rails has_secure_token gem/feature, it creates a unique token upon record creation and stores it in the database as plain text. If I am using that token to grant users access to an API, is there a security risk in storing that token as plain text in the database?
I was hoping there would be a way to encrypt the token column when the has_secure_token method commits the token to the database, similar to how bcrypt encrypts passwords into a database.
I have tried using gems such as attr_encrypted to store a hashed value of the token, but it seems to be incompatible with has_secure_token. Here is how my model is currently set up:
class User < ApplicationRecord
has_secure_token :token
# attr_encrypted :token, key: :encrypt_token, attribute: 'token'
# def encrypt_token
# SecureRandom.random_bytes(32)
# end
end
The commented code is attr_encrypted code that has proven to be incompatible. If someone knew if there was a way to safely encrypt a column in the database, while also using has_secure_token, I would greatly appreciate it!
Let me know if any more information is needed or this is confusing. Thanks in advance!
Rails 6 ActiveModel::SecurePassword#has_secure_password accepts an attribute name argument and will use BCrypt to set the value of a corresponding #{attribute}_digest column. The default attribute name is password and the model must have an accessor for a #{attribute}_digest attribute.
A simplified example with both a password and an api_token:
rails generate model User password_digest:string api_token_digest:string
Rails 6
class User < ApplicationRecord
has_secure_password #create a `password` attribute
has_secure_password :api_token, validations: false
before_create do
self.reset_token = SecureRandom.urlsafe_base64
end
end
Prior to Rails 6 you can directly invoke BCrypt to encrypt the token.
require 'bcrypt'
class User < ApplicationRecord
has_secure_password #create a `password` attribute
before_create do
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
self.api_token = SecureRandom.urlsafe_base64
self.api_token_digest = BCrypt::Password.create(api_token, cost: cost)
end
end
I've setup Devise (on Rails 3) to use Basecamp-style subdomain authentication. Under this model, a user could be registered twice under different subdomains with the same email address.
For example:
class User < ActiveRecord::Base
belongs_to :account
end
class Account < ActiveRecord::Base
# subdomain attribute stored here
end
User 1 registered on company1.myapp.com with email address bob#acme.com
User 2 registered on company2.myapp.com with email address bob#acme.com
(Both user account are controlled by the same human, but belong to different subdomains.)
Logging in works fine, but the standard Password Reset only looks up by email address, so you can only ever reset the password for User 1. What I'd like to do is take into account the request subdomain, so a password reset from company2.myapp.com/password/new would reset the password for User 2.
The Devise looks up the user using a find_first method, which I don't think accepts joins, so I can't include a :account => {:subodmain => 'comapny2'} condition.
I can reimplement send_reset_password_instructions to manually look up the user record, but it feels hacky and I'll need to do it for send_confirmation_instructions, too.
Is there a better way?
It looks like this may be configurable with devise_for in the routes file.
From my reading of the source (and I haven't actually tried this), you can add a reset_password_keys option. These should include the subdomain. This is passed to find_or_initialize_with_errors from send_reset_password_instructions in lib/devise/models/recoverable.rb. In find_or_initialize_with_errors it's only these keys which are used to find the resource.
You'll probably also want to override Devise::PasswordsController#new template to include the user's subdomain when they submit the reset password request.
UPDATE: to address the fact that the subdomain is stored on Account and User belongs_to :account you can probably use Rails' delegate method.
We experienced this same issue. Mike Mazur's answer worked, but for one difference:
We put :reset_password_keys => [:email, :subdomain] in the call to the devise method in our Users model.
I recently implement this behaviour in a Rails 4 App.
…/config/initializers/devise.rb
(…)
# ==> Configuration for :recoverable
#
# Defines which key will be used when recovering the password for an account
config.reset_password_keys = [:email, :subdomain]
(…)
…/app/views/devise/passwords/new.html.erb
(…)
<%= f.input :subdomain, required: true %>
(…)
…/app/controllers/users/passwords_controller.rb
class Users::PasswordsController < Devise::PasswordsController
def resource_params
params.require(:user).permit(:email, :subdomain, ...)
end
private :resource_params
end
When a user registers on my app they have to confirm their email, powered by Devise + Rails 3.
The email address defines the user's permissions so I don't want the user to be able to change it once registered. so removed :email from the users.rb attr_accessible which worked for a logged in user, but now user's can't register.
What's the right way to handle this? So users can't update their email but can register with their email using devise.
Thanks
This is the perfect case for a custom validator. Since Rails3, they are much easier to do than before.
class ImmutableValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << "cannot be changed after creation" if record.send("#{attribute}_changed?") && !record.new_record?
end
end
class User < ActiveRecord::Base
validates :email, :immutable => true
end
attr_readonly :email
That solved the problem easily.
https://groups.google.com/forum/#!topic/plataformatec-devise/skCarCHr0p8
I would personally leave the attr_accessible for :email and just remove the email field from the edit view. Also, you will want to strip out any email param from the params hash in the update action.
I'm using Authlogic to manage my user sessions. I'm using the LDAP add-on, so I have the following in my users model
acts_as_authentic do |c|
c.validate_password_field = false
end
The problem is that recently I found out that there will be some users inside the application that won't be part of the LDAP (and can't be added!). So I would need to validate SOME passwords against the database and the others against the LDAP.
The users whose password will be validated against the database will have an specific attribute that will tell me that that password will be validated in my database.
How can I manage that? Is it possible that the validate_password_field receives a "variable"? That way I could create some method that will return true/false depending on where the password validation will be done?
Thanks!
Nicolás Hock Isaza
You should be able to do this:
acts_as_authentic do |u|
u.validate_password_field = true
authentic_options = {:unless => Proc.new{|c| c.ldap}}
u.merge_validates_confirmation_of_password_field_options(authentic_options)
u.merge_validates_length_of_password_confirmation_field_options(authentic_options)
u.merge_validates_length_of_password_field_options(authentic_options)
end
If you were writing the validation yourself (not using authlogic) you would want to do something like this in the validation:
validates_presence_of :password, :unless => Proc.new{|u| u.ldap }
Since authlogic provides the 3 helper methods to add options to the end of the validates methods, you can use this to turn off validations when using LDAP.
You should be able to do an unless in your validation.
acts_as_authentic do |c|
c.validate_password_field = false if c.ldap
end
Or even (as your model field is a boolean) :
acts_as_authentic do |c|
c.validate_password_field = c.ldap
end
I use Authlogic for authentication in my Rails project.
It provide default validation for email and login field.
But, I want to allow email to be null for join because my service is for mobile and it is difficult to insert email field in mobile device.
How can I skip email validation with Authlogic in Rails?
class User < ActiveRecord::Base
acts_as_authentic do |c|
c.validate_email_field = false
end
end
I was digging for this one for awhile - extending on what jaehyun said - say you want to skip email validation in Authlogic on a conditional basis
acts_as_authentic do |c|
c.merge_validates_length_of_email_field_options({:unless => Proc.new { |user| user.has_no_email? }})
c.merge_validates_format_of_email_field_options({:unless => Proc.new { |user| user.has_no_email? }})
end