I have researched a lot on this topic but due to some reason I am unable to perform password complexity implementation on my Ruby on Rails Web Application. I have installed the devise gem and followed Best flexible rails password security implementation and How to validate password strength with Devise in Ruby on Rails?.
My regex seems to be working when I check it online
/\A(?=.{8,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[[:^alnum:]])/x
but once I implement it inside my user.rb it just does not work.
My user.rb file:
#Active Record for Users
class User < ActiveRecord::Base
belongs_to :entity
has_and_belongs_to_many :groups, :join_table => "users_groups"
has_many :surveys, inverse_of: :user
has_many :results, inverse_of: :user
validates :password, :firstName, :email, :salt, :role, :timezone, presence: true
validates :email, :uniqueness => {:scope => :entity_id}
validates_format_of :email, :with => /.+#.+\..+/i
devise :database_authenticatable, :validatable
validate :password_complexity
#User Authentication
def self.authenticate(email="", lpassword="")
users = User.where(email: email)
results = []
users.each do |user|
if user && user.match_password(lpassword)
results.push(user)
end
end
if(results.length == 0)
return false
else
return results
end
end
#Password Check
def match_password(lpassword="")
return (BCrypt::Password.new(password).is_password?(lpassword+salt))
end
#Password Authentication
def password_complexity
if password.present? and not password.match(/\A(?=.{8,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[[:^alnum:]])/x)
errors.add :password, "must include at least one lowercase letter, one uppercase letter, and one digit"
end
end
end
What you did should work, but why not do it simply like this
validates :password, format: { with: /\A(?=.{8,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[[:^alnum:]])/, message: "must include at least one lowercase letter, one uppercase letter, and one digit" }
Related
I have three models user (author), which is incorporating devise logic:
app/models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :questions
has_many :answers
end
question:
app/models/question.rb
# Model for Question
class Question < ActiveRecord::Base
has_many :answers, dependent: :destroy
belongs_to :author, class_name: 'User', foreign_key: 'user_id'
validates :title, presence: true, length: { maximum: 100 }
validates :body, presence: true, length: { minimum: 10 }
validates :author, presence: true
end
and answer:
app/models/answer.rb
# Model for Answer
class Answer < ActiveRecord::Base
belongs_to :question
belongs_to :author, class_name: 'User', foreign_key: 'user_id'
validates :body, presence: true, length: { minimum: 10 }
validates :question_id, presence: true
validates :author, presence: true
end
and their factories:
spec/factories/users.rb
FactoryGirl.define do
sequence :email do |n|
"email-#{n}#example.com"
end
sequence :password do |n|
"testpassword#{n}"
end
factory :user, aliases: [:author] do
email
# tried sequence generator and fixed password - both have no impact on result
# password '1234567890'
# password_confirmation '1234567890'
password
end
end
spec/factories/answers.rb
FactoryGirl.define do
factory :answer do
body 'Answer Body'
author
question
end
factory :nil_answer, class: 'Answer' do
question
body nil
end
end
spec/factories/questions.rb
FactoryGirl.define do
factory :question do
title 'Question Title'
body 'Question Body'
author
factory :question_with_answers do
after(:create) do |question|
# changing create_list to create has no impact on result
# create_list(:answer, 2, question: question)
create(:answer, question: question)
end
end
end
end
test code:
spec/features/delete_answer_spec.rb
require 'rails_helper'
feature 'Delete answer', %q{
By some reason
As an authenticated user
I want to delete answer
} do
given(:question) { create(:question_with_answers) }
given(:user) { create(:user) }
given(:ans) { create(:answer) }
scenario 'Answer author password should not be nil' do
expect(question.answers.first.author.password).to_not be_nil
# question.author.password and ans.author.password return not nil
# I need password to do:
# visit new_user_session_path
# fill_in 'Email', with: user.email
# fill_in 'Password', with: user.password
# click_on 'Log in'
end
end
Can anyone explain why the following given statement:
given(:question) { create(:question_with_answers) }
creates question object that:
question.author.password #=> '1234567890'
but:
question.answers.first.author.password #=> nil
why method "create" instantiates author of question properly (field password is set), but "create_list" inside "after" callback creates author in answer with nil fields?
rails 4.2.5, ruby 2.3.0, devise 3.5.6, warden 1.2.6, factory_girls_rails 4.6.0 (4.5.0)
Devise (and most authentication libraries) encrypt the password and don't allow you to access passwords from models retrieved from the database. The password may be temporarily available through an in-memory reader method, but won't be available if you retrieve the record from the database.
If you do:
user = User.new(password: "example")
p user.password
I'm guessing you'll see "example".
But if you do:
user = User.first
p user.password
I bet you'll see nil (assuming you have user records in your database).
When you query an association proxy like question.answers.first.author, it's going to the database again to find the answer and author. That means you're using a different instance, which no longer has the password available.
I'm trying to provide a place to set a single service login for an account, yet not require that the account owner enter the service login credentials every time the rest of the record is updated.
My understanding is that the :reject_if option on accepts_nested_attributes_for is the way to have the nested hash values ignored. Yet, in Rails 4.1, I'm getting a "password can't be blank".
I've traced through the nested_attributes code and it seems to properly ignore the values, yet nothing I do to avoid the update works. I've even deleted the web_service_user_attributes hash from the params passed to update, so I'm wondering if there is something else going on.
Am I understanding :reject_if correctly for a has_one association?
Parent model code:
class Account
has_one :web_service_user
accepts_nested_attributes_for :web_service_user, :allow_destroy => true, :reject_if => :password_not_specified, :update_only => true
def password_not_specified(attributes)
attributes[:password].blank?
end
end
Child model code:
class WebServiceUser
devise :database_authenticatable
belongs_to :account
validates_uniqueness_of :username
validates_presence_of :password, if: Proc.new{|wsu| !username.blank? }
end
Controller code:
def update
respond_to do |format|
if #licensee.update(account_params)
#etc...
end
private
def account_params
params.require(:account).permit(:name, :area_of_business, :address1, :address2, :city, :state_code, :zip, :website_url, :web_service_user_attributes => [:id, :username, :password, :_destroy])
end
Ok, it appears that my primary goof was trying to validate the presence of :password. I really wanted to validate the length of the password if it existed.
class WebServiceUser
devise :database_authenticatable
belongs_to :account
validates_uniqueness_of :username
validates_length_of :password, :minimum => 14, if: Proc.new { |u| !u.password.nil? }
end
I'm trying to mix a custom User authentication mechanism based on SecurePassword with Facebook integration through omniauth-facebook gem.
my app uses Ruby 2.0.0 and Rails 4.0.0.
i tried to follow this guide omniauth and some other articles to came up with something like this for the User and Authentication Models
User model:
class User < ActiveRecord::Base
has_one :user_playlist
has_one :user_info
has_many :band_likes
has_many :song_likes
has_many :band_comments
has_many :song_comments
has_many :authorizations
#many to many relation between User and Band
#todo: make a bands_users migration
has_and_belongs_to_many :bands
has_secure_password
validates :username, presence: true, uniqueness: {case_sensitive: false}, length: {in: 8..64}, format: {with: /\A[a-zA-Z ]+\Z/, message: 'Debe poseer solo letras y espacios.'}
validates :email, presence: true, uniqueness: {case_sensitive: false}, format: {with: /#/, message: 'Dirección de correo inváilda.'}
validates :password, length: {in: 8..24}
validates :password_confirmation, length: {in: 8..24}
def self.create_from_hash!(hash)
create(:email => hash['info']['email'], :username => hash['info']['name'], :password => hash['uid'], :password_confirmation => hash['uid'] )
end
end
Authorization Model:
class Authorization < ActiveRecord::Base
belongs_to :user
validates_presence_of :user_id, :uid, :provider
validates_uniqueness_of :uid, :scope => :provider
def self.find_from_hash(hash)
find_by_provider_and_uid(hash['provider'], hash['uid'])
end
def self.create_from_hash(hash, user = nil)
user ||= User.create_from_hash!(hash)
Authorization.create(:user => user, :uid => hash['uid'], :provider => hash['provider'])
end
end
SessionsController
class SessionsController < ApplicationController
def create
auth = request.env['omniauth.auth']
unless #auth = Authorization.find_from_hash(auth)
# Create a new user or add an auth to existing user, depending on
# whether there is already a user signed in.
#auth = Authorization.create_from_hash(auth, current_user)
end
# Log the authorizing user in.
self.current_user = #auth.user
render :text => "Welcome, #{current_user.username}. <br />User saved = #{current_user.save} .<br/>User valid = #{current_user.valid?}.<br />errors= #{current_user.errors.full_messages}"
end
end
The last render was written to check about the fact that my password does not gets validated, it doesn't matter if i use hash['uid'], hash['info']['name'], or whatever.
The reason why i use this values is just because, i will figure out later how to build a random password for the oauth-ed user, but i don't want blank ones nor disable the validations.
but, no matter what value i use, always get only my name and email:
*Welcome, "My Real Name Here.
User saved = false.
User valid = false.
errors= ["Password is too short (minimum is 8 characters)", "Password confirmation is too short (minimum is 8 characters)"]*
When creating users in Rails Console got no problem, just when OAuth tries to create a User with create_from_hash.
also, if i try to assign a non existing value from hash to password fields, it adds the message that can be blank. so, it isn't blank.
and rendering hash['uid'] in controller shows that it's longer than 8.
I Must warn that i'm new to rails, so if you can, explain me with apples xD
Thanks in advance!
finally i came up with this on User model:
def self.create_from_hash!(hash)
self.where(:email => hash.info.email.to_s).first_or_create do |user|
user.email = hash.info.email
user.username = hash.info.name
user.password = hash.uid
user.password_confirmation = hash.uid
end
end
I don't know why the later doesn't work but at least this one works!
Greetings!
I'm trying to set up my application to use Sorcery. When I add authenticates_with_sorcery! to my user model, my specs start to run really slow (about one per second). Is there some kind of configuration or set up that could cause this with Sorcery?
Here's my user model:
# This model represents a user of the application, disregarding that person's use of the system. For
# instance, a user could be a job hunter, an employer, an administrator, or some other stakeholder.
class User < ActiveRecord::Base
authenticates_with_sorcery!
attr_accessible :email, :password, :password_confirmation
# validations
validates :email,
:presence => true,
:uniqueness => true,
:format => /[^#]+#[^#]+\.[^#]+/
validates :password, :presence => true, :confirmation => true
validates :password_confirmation, :presence => true
# before filters
before_save :sanitize_email
private
# Strips and removes HTML tags from the email parameter.
def sanitize_email
self.email = email.strip
# remove anything that looks like an email
self.email = email.gsub(/<[^<>]+>/, "")
end
end
and my user factory:
require 'factory_girl'
require 'ffaker'
FactoryGirl.define do
sequence :email do |n|
"email#{n}#example.com"
end
factory :user do |f|
email
password "password"
password_confirmation "password"
end
end
My first guess is slow password encryption. For instance in devise we have config.stretches configuration variable which in the test env could be set to a small number.
check What does the "stretches" of database_authenticatable of devise mean?
FactoryGirl.define do
factory :agency do
name "Example Inc"
available_items "20"
recruiter # recruiter.id
end
factory :recruiter do
email 'example#example.com'
password 'please'
password_confirmation 'please'
# required if the Devise Confirmable module is used
# confirmed_at Time.now
end
end
agency.rb
class Agency < ActiveRecord::Base
belongs_to :recruiter
validates :name, :presence => true
end
recruiter.rb
class Recruiter < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
attr_accessible :agency_attributes, :first_name
has_one :agency, :dependent => :destroy
accepts_nested_attributes_for :agency
validates :email, :presence => true
end
authentication_steps.rb
def create_user
#recruiter = FactoryGirl.create(:recruiter)
end
How can I replicate this Recruiter & Agency association using factory_girl?
I think you should remove recruiter from agency factory and add agency to requiter factory
FactoryGirl.define do
factory :agency do
name "Example Inc"
available_items "20"
factory :agency_without_recuiter do
recuiter_id = 1
end
factory :agency_with_recuiter do
recuiter
end
end
factory :recuiter do
email 'example#example.com'
password 'please'
password_confirmation 'please'
factory :recuiter_with_agency
agency
end
end
end
This should work from both sides
create(:agency).recuiter => nil
create(:agency_with_recuiter).recuiter => recuiter
create(:recuiter).agency => nil
create(:recuiter_with_agency).agency => agency
Hope it will be usefull. Good luck!
I think you have to replicate it in your test cases, not in FG itself.
before (:each) do
#recruiter = FactoryGirl.create(:recruiter)
#agency = FactoryGirl.create(:agency)
#agency.recruiter = #recruiter
end
Something like this.