module Authlogic
module ORMAdapters
module ActiveRecordAdapter
module ActsAsAuthentic
# = Config
#
# Allows you to set various configuration when calling acts_as_authentic. Pass your configuration like the following:
#
# class User < ActiveRecord::Base
# acts_as_authentic :my_option => "my value"
# end
#
# === Class Methods
#
# * acts_as_authentic_config - returns a hash of the acts_as_authentic configuration, including the defaults
#
# === General Options
#
# * session_class - default: "#{name}Session",
# This is the related session class. A lot of the configuration will be based off of the configuration values of this class.
#
# * crypto_provider - default: Authlogic::CryptoProviders::Sha512,
# This is the class that provides your encryption. By default Authlogic provides its own crypto provider that uses Sha512 encrypton.
#
# * transition_from_crypto_provider - default: nil,
# This will transition your users to a new encryption algorithm. Let's say you are using Sha1 and you want to transition to Sha512. Just set the
# :crypto_provider option to Authlogic::CryptoProviders::Sha512 and then set this option to Authlogic::CryptoProviders::Sha1. Every time a user
# logs in their password will be resaved with the new algorithm and all new registrations will use the new algorithm as well.
#
# * act_like_restful_authentication - default: false,
# If you are migrating from restful_authentication you will want to set this to true, this way your users will still be able to log in and it will seems as
# if nothing has changed. If you don't do this none of your users will be able to log in. If you are starting a new project I do not recommend enabling this
# as the password encryption algorithm used in restful_authentication (Sha1) is not as secure as the one used in authlogic (Sha512). IF you REALLY want to be secure
# checkout Authlogic::CryptoProviders::BCrypt.
#
# * transition_from_restful_authentication - default: false,
# This works just like :transition_from_crypto_provider, but it makes some special exceptions so that your users will transition from restful_authentication, since
# restful_authentication does things a little different than Authlogic.
#
# * login_field - default: :login, :username, or :email, depending on which column is present, if none are present defaults to :login
# The name of the field used for logging in. Only specify if you aren't using any of the defaults.
#
# * login_field_type - default: options[:login_field] == :email ? :email : :login,
# Tells authlogic how to validation the field, what regex to use, etc. If the field name is email it will automatically use :email,
# otherwise it uses :login.
#
# * password_field - default: :password,
# This is the name of the field to set the password, *NOT* the field the encrypted password is stored. Defaults the what the configuration
#
# * crypted_password_field - default: :crypted_password, :encrypted_password, :password_hash, :pw_hash, depends on which columns are present, if none are present defaults to nil
# The name of the database field where your encrypted password is stored.
#
# * password_salt_field - default: :password_salt, :pw_salt, or :salt, depending on which column is present, defaults to :password_salt if none are present,
# This is the name of the field in your database that stores your password salt.
#
# * email_field - default: :email, depending on if it is present, if :email is not present defaults to nil
# The name of the field used to store the email address. Only specify this if you arent using this as your :login_field.
#
# * single_access_token_field - default: :single_access_token, :feed_token, or :feeds_token, depending on which column is present, if none are present defaults to nil
# This is the name of the field to login with single access, mainly used for private feed access. Only specify if the name of the field is different
# then the defaults. See the "Single Access" section in the README for more details on how single access works.
#
# * change_single_access_token_with_password - default: false,
# When a user changes their password do you want the single access token to change as well? That's what this configuration option is all about.
#
# * perishable_token_field - default: :perishable_token, :password_reset_token, :pw_reset_token, :reset_password_token, or :reset_pw_token, depending on which column is present, if none are present defaults to nil
# This is the name of the field in your database that stores your perishable token. The token you should use to confirm your users or allow a password reset. Authlogic takes care
# of maintaining this for you and making sure it changes when needed. Use this token for whatever you want, but keep in mind it is temporary, hence the term "perishable".
#
# * perishable_token_valid_for - default: 10.minutes,
# Authlogic gives you a sepcial method for finding records by the perishable token (see Authlogic::ORMAdapters::ActiveRecordAdapter::ActcsAsAuthentic::Perishability). In this method
# it checks for the age of the token. If the token is older than whatever you specify here, a record will NOT be returned. This way the tokens are perishable, thus making this system much
# more secure.
#
# * persistence_field - default: :persistence_token, :remember_token, or :cookie_tokien, depending on which column is present,
# defaults to :persistence_token if none are present,
# This is the name of the field your persistence token is stored. The persistence token is a unique token that is stored in the users cookie and
# session. This way you have complete control of when sessions expire and you don't have to change passwords to expire sessions. This also
# ensures that stale sessions can not be persisted. By stale, I mean sessions that are logged in using an outdated password.
#
# * logged_in_timeout - default: 10.minutes,
# This is a nifty feature to tell if a user is logged in or not. It's based on activity. So if the user in inactive longer than
# the value passed here they are assumed "logged out". This uses the last_request_at field, this field must be present for this option to take effect.
#
# * session_ids - default: [nil],
# The sessions that we want to automatically reset when a user is created or updated so you don't have to worry about this. Set to [] to disable.
# Should be an array of ids. See the Authlogic::Session documentation for information on ids. The order is important.
# The first id should be your main session, the session they need to log into first. This is generally nil. When you don't specify an id
# in your session you are really just inexplicitly saying you want to use the id of nil.
#
# === Validation Options
#
# * validate_fields - default: true,
# Tells Authlogic if it should validate ANY of the fields: login_field, email_field, and password_field. If set to false, no validations will be set for any of these fields.
#
# * validate_login_field - default: true,
# Tells authlogic if it should validate the :login_field. If set to false, no validations will be set for this field at all.
#
# * validate_email_field - default: true,
# Tells Authlogic if it should validate the email field. If set to false, no validations will be set for this field at all.
#
# * validate_password_field - default: :password,
# Tells authlogic if it should validate the :password_field. If set to false, no validations will be set for this field at all.
#
# * scope - default: nil,
# This scopes validations. If all of your users belong to an account you might want to scope everything to the account. Just pass :account_id
#
# * validation_options - default: {},
# Options to pass to ALL validations. These are the options ActiveRecord supplies with their validation methods, see the ActiveRecord documentation for more details.
#
# * login_field_validation_options - default: {},
# The same as :validation_options but these are only applied to validations that pertain to the :login_field
#
# * login_field_validates_length_of_options - default: :login_field_type == :email ? {:within => 6..100} : {:within => 2..100},
# These options are applied to the validates_length_of call for the :login_field
#
# * login_field_validates_format_of_options - default: :login_field_type == :email ? {:with => standard_email_regex, :message => "should look like an email address."} : {:with => standard_login_regex, :message => "should use only letters, numbers, spaces, and .-_@ please."},
# These options are applied to the validates_format_of call for the :login_field
#
# * login_field_validates_uniqueness_of_options - default: {:allow_blank => true},
# These options are applied to the validates_uniqueness_of call for the :login_field, the :allow_blank => true just prevents the error message when you have options login fields
# such as an OpenID field. The other validations will make sure the field is not actaully blank.
#
# * password_field_validation_options - default: {},
# The same as :validation_options but these are only applied to validations that pertain to the :password_field
#
# * password_field_validates_presence_of_options - default: {:on => :create},
# These options are applied to the validates_presence_of call for the :password_field
#
# * login_field_validates_confirmation_of_options - default: {},
# These options are applied to the validates_confirmation_of call for the :password_field
#
# * email_field_validation_options - default: {},
# The same as :validation_options but these are only applied to validations that pertain to the :email_field
#
# * email_field_validates_length_of_options - default: same as :login_field if :login_field_type == :email,
# These options are applied to the validates_length_of call for the :email_field
#
# * email_field_validates_format_of_options - default: same as :login_field if :login_field_type == :email,
# These options are applied to the validates_format_of call for the :email_field
#
# * email_field_validates_uniqueness_of_options - default: same as :login_field if :login_field_type == :email,
# These options are applied to the validates_uniqueness_of call for the :email_field
module Config
def first_column_to_exist(*columns_to_check) # :nodoc:
columns_to_check.each { |column_name| return column_name.to_sym if column_names.include?(column_name.to_s) }
columns_to_check.first ? columns_to_check.first.to_sym : nil
end
def acts_as_authentic_with_config(options = {})
# Stop all configuration if the DB is not set up
begin
column_names
rescue Exception
return
end
# Base configuration
options[:session_class] ||= "#{name}Session"
options[:crypto_provider] ||= CryptoProviders::Sha512
options[:login_field] ||= first_column_to_exist(:login, :username, :email)
options[:login_field_type] ||= options[:login_field] == :email ? :email : :login
options[:password_field] ||= :password
options[:crypted_password_field] ||= first_column_to_exist(:crypted_password, :encrypted_password, :password_hash, :pw_hash)
options[:password_salt_field] ||= first_column_to_exist(:password_salt, :pw_salt, :salt)
options[:email_field] = first_column_to_exist(nil, :email) unless options.key?(:email_field)
options[:email_field] = nil if options[:email_field] == options[:login_field]
options[:persistence_token_field] ||= options[:remember_token_field] || first_column_to_exist(:persistence_token, :remember_token, :cookie_token)
options[:single_access_token_field] ||= first_column_to_exist(nil, :single_access_token, :feed_token, :feeds_token)
options[:perishable_token_field] ||= options[:password_reset_token_field] || first_column_to_exist(nil, :perishable_token, :password_reset_token, :pw_reset_token, :reset_password_token, :reset_pw_token, :activation_token)
options[:perishable_token_valid_for] ||= 10.minutes
options[:perishable_token_valid_for] = options[:perishable_token_valid_for].to_i
options[:logged_in_timeout] ||= 10.minutes
options[:logged_in_timeout] = options[:logged_in_timeout].to_i
options[:session_ids] ||= [nil]
# Validation configuration
options[:validate_fields] = true unless options.key?(:validate_fields)
options[:validate_login_field] = true unless options.key?(:validate_login_field)
options[:validate_password_field] = true unless options.key?(:validate_password_field)
options[:validate_email_field] = true unless options.key?(:validate_email_field)
options[:validation_options] ||= {}
[:login, :password, :email].each do |field_name|
field_key = "#{field_name}_field_validation_options".to_sym
options[field_key] = options[:validation_options].merge(options[field_key] || {})
validation_types = field_name == :password ? [:presence, :confirmation] : [:length, :format, :uniqueness]
validation_types.each do |validation_type|
validation_key = "#{field_name}_field_validates_#{validation_type}_of_options".to_sym
options[validation_key] = options[field_key].merge(options[validation_key] || {})
end
end
if options[:scope]
options[:login_field_validates_uniqueness_of_options][:scope] ||= options[:scope]
options[:email_field_validates_uniqueness_of_options][:scope] ||= options[:scope]
end
if options[:act_like_restful_authentication] || options[:transition_from_restful_authentication]
crypto_provider_key = options[:act_like_restful_authentication] ? :crypto_provider : :transition_from_crypto_provider
options[crypto_provider_key] = CryptoProviders::Sha1
if !defined?(REST_AUTH_SITE_KEY) || REST_AUTH_SITE_KEY.nil?
class_eval("::REST_AUTH_SITE_KEY = nil") unless defined?(REST_AUTH_SITE_KEY)
options[crypto_provider_key].stretches = 1
end
end
class_eval <<-"end_eval", __FILE__, __LINE__
def self.acts_as_authentic_config
#{options.inspect}
end
end_eval
acts_as_authentic_without_config(options)
end
end
end
end
end
end
ActiveRecord::Base.class_eval do
class << self
include Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::Config
alias_method_chain :acts_as_authentic, :config
end
end