class Authlogic::Session::Base
This is the most important class in Authlogic
. You will inherit this class for your own eg. ‘UserSession`.
Ongoing consolidation of modules
¶ ↑
We are consolidating modules into this class (inlining mixins). When we are done, there will only be this one file. It will be quite large, but it will be easier to trace execution.
Once consolidation is complete, we hope to identify and extract collaborating objects. For example, there may be a “session adapter” that connects this class with the existing ‘ControllerAdapters`. Perhaps a data object or a state machine will reveal itself.
¶ ↑
Activating Authlogic
requires that you pass it an Authlogic::ControllerAdapters::AbstractAdapter
object, or a class that extends it. This is sort of like a database connection for an ORM library, Authlogic
can’t do anything until it is “connected” to a controller. If you are using a supported framework, Authlogic
takes care of this for you.
ActiveRecord Trickery
¶ ↑
Authlogic
looks like ActiveRecord, sounds like ActiveRecord, but its not ActiveRecord. That’s the goal here. This is useful for the various rails helper methods such as form_for, error_messages_for, or any method that expects an ActiveRecord object. The point is to disguise the object as an ActiveRecord object so we can take advantage of the many ActiveRecord tools.
Brute Force Protection
¶ ↑
A brute force attacks is executed by hammering a login with as many password combinations as possible, until one works. A brute force attacked is generally combated with a slow hashing algorithm such as BCrypt. You can increase the cost, which makes the hash generation slower, and ultimately increases the time it takes to execute a brute force attack. Just to put this into perspective, if a hacker was to gain access to your server and execute a brute force attack locally, meaning there is no network lag, it would probably take decades to complete. Now throw in network lag and it would take MUCH longer.
But for those that are extra paranoid and can’t get enough protection, why not stop them as soon as you realize something isn’t right? That’s what this module is all about. By default the consecutive_failed_logins_limit
configuration option is set to 50, if someone consecutively fails to login after 50 attempts their account will be suspended. This is a very liberal number and at this point it should be obvious that something is not right. If you wish to lower this number just set the configuration to a lower number:
class UserSession < Authlogic::Session::Base consecutive_failed_logins_limit 10 end
Callbacks
¶ ↑
Between these callbacks and the configuration, this is the contract between me and you to safely modify Authlogic’s behavior. I will do everything I can to make sure these do not change.
Check out the sub modules of Authlogic::Session
. They are very concise, clear, and to the point. More importantly they use the same API that you would use to extend Authlogic
. That being said, they are great examples of how to extend Authlogic
and add / modify behavior to Authlogic
. These modules could easily be pulled out into their own plugin and become an “add on” without any change.
Now to the point of this module. Just like in ActiveRecord you have before_save, before_validation, etc. You have similar callbacks with Authlogic
, see the METHODS
constant below. The order of execution is as follows:
before_persisting persist after_persisting [save record if record.has_changes_to_save?] before_validation before_validation_on_create before_validation_on_update validate after_validation_on_update after_validation_on_create after_validation [save record if record.has_changes_to_save?] before_save before_create before_update after_update after_create after_save [save record if record.has_changes_to_save?] before_destroy [save record if record.has_changes_to_save?] after_destroy
Notice the “save record if has_changes_to_save” lines above. This helps with performance. If you need to make changes to the associated record, there is no need to save the record, Authlogic
will do it for you. This allows multiple modules to modify the record and execute as few queries as possible.
WARNING: unlike ActiveRecord, these callbacks must be set up on the class level:
class UserSession < Authlogic::Session::Base before_validation :my_method validate :another_method # ..etc end
You can NOT define a “before_validation” method, this is bad practice and does not allow Authlogic
to extend properly with multiple extensions. Please ONLY use the method above.
HTTP Basic Authentication
¶ ↑
Handles all authentication that deals with basic HTTP auth. Which is authentication built into the HTTP protocol:
http://username:password@whatever.com
Also, if you are not comfortable letting users pass their raw username and password you can use a single access token, as described below.
Magic Columns
¶ ↑
Just like ActiveRecord has “magic” columns, such as: created_at and updated_at. Authlogic
has its own “magic” columns too:
-
login_count - Increased every time an explicit login is made. This will NOT increase if logging in by a session, cookie, or basic http auth
-
failed_login_count - This increases for each consecutive failed login. See the
consecutive_failed_logins_limit
option for details. -
last_request_at - Updates every time the user logs in, either by explicitly logging in, or logging in by cookie, session, or http auth
-
current_login_at - Updates with the current time when an explicit login is made.
-
last_login_at - Updates with the value of current_login_at before it is reset.
-
current_login_ip - Updates with the request ip when an explicit login is made.
-
last_login_ip - Updates with the value of current_login_ip before it is reset.
Multiple Simultaneous Sessions
¶ ↑
See ‘id`. Allows you to separate sessions with an id, ultimately letting you create multiple sessions for the same user.
Timeout
¶ ↑
Think about financial websites, if you are inactive for a certain period of time you will be asked to log back in on your next request. You can do this with Authlogic
easily, there are 2 parts to this:
-
Define the timeout threshold:
acts_as_authentic do |c| c.logged_in_timeout = 10.minutes # default is 10.minutes end
-
Enable logging out on timeouts
class UserSession < Authlogic::Session::Base logout_on_timeout true # default is false end
This will require a user to log back in if they are inactive for more than 10 minutes. In order for this feature to be used you must have a last_request_at datetime column in your table for whatever model you are authenticating with.
Params
¶ ↑
This module is responsible for authenticating the user via params, which ultimately allows the user to log in using a URL like the following:
https://www.domain.com?user_credentials=4LiXF7FiGUppIPubBPey
Notice the token in the URL, this is a single access token. A single access token is used for single access only, it is not persisted. Meaning the user provides it, Authlogic
grants them access, and that’s it. If they want access again they need to provide the token again. Authlogic
will NEVER try to persist the session after authenticating through this method.
For added security, this token is ONLY allowed for RSS and ATOM requests. You can change this with the configuration. You can also define if it is allowed dynamically by defining a single_access_allowed? method in your controller. For example:
class UsersController < ApplicationController private def single_access_allowed? action_name == "index" end
Also, by default, this token is permanent. Meaning if the user changes their password, this token will remain the same. It will only change when it is explicitly reset.
You can modify all of this behavior with the Config
sub module.
Perishable Token
¶ ↑
Maintains the perishable token, which is helpful for confirming records or authorizing records to reset their password. All that this module does is reset it after a session have been saved, just keep it changing. The more it changes, the tighter the security.
See Authlogic::ActsAsAuthentic::PerishableToken
for more information.
Scopes
¶ ↑
Authentication can be scoped, and it’s easy, you just need to define how you want to scope everything. See ‘.with_scope`.
Unauthorized Record
¶ ↑
Allows you to create session with an object. Ex:
UserSession.create(my_user_object)
Be careful with this, because Authlogic
is assuming that you have already confirmed that the user is who he says he is.
For example, this is the method used to persist the session internally. Authlogic
finds the user with the persistence token. At this point we know the user is who he says he is, so Authlogic
just creates a session with the record. This is particularly useful for 3rd party authentication methods, such as OpenID. Let that method verify the identity, once it’s verified, pass the object and create a session.
Magic States
¶ ↑
Authlogic
tries to check the state of the record before creating the session. If your record responds to the following methods and any of them return false, validation will fail:
Method name Description active? Is the record marked as active? approved? Has the record been approved? confirmed? Has the record been confirmed?
Authlogic
does nothing to define these methods for you, its up to you to define what they mean. If your object responds to these methods Authlogic
will use them, otherwise they are ignored.
What’s neat about this is that these are checked upon any type of login. When logging in explicitly, by cookie, session, or basic http auth. So if you mark a user inactive in the middle of their session they wont be logged back in next time they refresh the page. Giving you complete control.
Need Authlogic
to check your own “state”? No problem, check out the hooks section below. Add in a before_validation to do your own checking. The sky is the limit.
Validation
¶ ↑
The errors in Authlogic
work just like ActiveRecord. In fact, it uses the ‘ActiveModel::Errors` class. Use it the same way:
“‘ class UserSession
validate :check_if_awesome private def check_if_awesome if login && !login.include?("awesome") errors.add(:login, "must contain awesome") end unless attempted_record.awesome? errors.add(:base, "You must be awesome to log in") end end
end “‘
Constants
- E_AC_PARAMETERS
- E_DPR_FIND_BY_LOGIN_METHOD
- METHODS
-
Callbacks
¶ ↑
- VALID_SAME_SITE_VALUES
Attributes
Public Class Methods
Source
# File lib/authlogic/session/base.rb, line 478 def activated? !controller.nil? end
Returns true if a controller has been set and can be used properly. This MUST be set before anything can be done. Similar to how ActiveRecord won’t allow you to do anything without establishing a DB connection. In your framework environment this is done for you, but if you are using Authlogic
outside of your framework, you need to assign a controller object to Authlogic
via Authlogic::Session::Base.controller
= obj. See the controller= method for more information.
Source
# File lib/authlogic/session/base.rb, line 486 def allow_http_basic_auth(value = nil) rw_config(:allow_http_basic_auth, value, false) end
Allow users to log in via HTTP basic authentication.
-
Default:
false -
Accepts:
Boolean
Source
# File lib/authlogic/session/base.rb, line 496 def authenticate_with(klass) @klass_name = klass.name @klass = klass end
Lets you change which model to use for authentication.
-
Default:
inferred from the class name. UserSession would automatically try User -
Accepts:
an ActiveRecord class
Source
# File lib/authlogic/session/base.rb, line 535 def consecutive_failed_logins_limit(value = nil) rw_config(:consecutive_failed_logins_limit, value, 50) end
To help protect from brute force attacks you can set a limit on the allowed number of consecutive failed logins. By default this is 50, this is a very liberal number, and if someone fails to login after 50 tries it should be pretty obvious that it’s a machine trying to login in and very likely a brute force attack.
In order to enable this field your model MUST have a failed_login_count (integer) field.
If you don’t know what a brute force attack is, it’s when a machine tries to login into a system using every combination of character possible. Thus resulting in possibly millions of attempts to log into an account.
-
Default:
50 -
Accepts:
Integer, set to 0 to disable
Source
# File lib/authlogic/session/base.rb, line 503 def controller RequestStore.store[:authlogic_controller] end
The current controller object
Source
# File lib/authlogic/session/base.rb, line 515 def controller=(value) RequestStore.store[:authlogic_controller] = value end
This accepts a controller object wrapped with the Authlogic
controller adapter. The controller adapters close the gap between the different controllers in each framework. That being said, Authlogic
is expecting your object’s class to extend Authlogic::ControllerAdapters::AbstractAdapter
. See Authlogic::ControllerAdapters
for more info.
Lastly, this is thread safe.
Source
# File lib/authlogic/session/base.rb, line 566 def create(*args, &block) session = new(*args) session.save(&block) session end
A convenience method. The same as:
session = UserSession.new(*args) session.save
Instead you can do:
UserSession.create(*args)
Source
# File lib/authlogic/session/base.rb, line 574 def create!(*args) session = new(*args) session.save! session end
Same as create but calls create!, which raises an exception when validation fails.
Source
# File lib/authlogic/session/base.rb, line 588 def disable_magic_states(value = nil) rw_config(:disable_magic_states, value, false) end
Set this to true if you want to disable the checking of active?, approved?, and confirmed? on your record. This is more or less of a convenience feature, since 99% of the time if those methods exist and return false you will not want the user logging in. You could easily accomplish this same thing with a before_validation method or other callbacks.
-
Default:
false -
Accepts:
Boolean
Source
# File lib/authlogic/session/base.rb, line 598 def failed_login_ban_for(value = nil) rw_config(:failed_login_ban_for, (!value.nil? && value) || value, 2.hours.to_i) end
Once the failed logins limit has been exceed, how long do you want to ban the user? This can be a temporary or permanent ban.
-
Default:
2.hours -
Accepts:
Fixnum, set to 0 for permanent ban
Source
# File lib/authlogic/session/base.rb, line 666 def find(id = nil, priority_record = nil) session = new({ priority_record: priority_record }, id) session.priority_record = priority_record if session.persisting? session end end
This is how you persist a session. This finds the record for the current session using a variety of methods. It basically tries to “log in” the user without the user having to explicitly log in. Check out the other Authlogic::Session
modules for more information.
The best way to use this method is something like:
helper_method :current_user_session, :current_user def current_user_session return @current_user_session if defined?(@current_user_session) @current_user_session = UserSession.find end def current_user return @current_user if defined?(@current_user) @current_user = current_user_session && current_user_session.user end
Also, this method accepts a single parameter as the id, to find session that you marked with an id:
UserSession.find(:secure)
See the id method for more information on ids.
Priority Record
¶ ↑
This internal feature supports ActiveRecord’s optimistic locking feature, which is automatically enabled when a table has a ‘lock_version` column.
“‘ # api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html p1 = Person.find(1) p2 = Person.find(1) p1.first_name = “Michael” p1.save p2.first_name = “should fail” p2.save # Raises an ActiveRecord::StaleObjectError “`
Now, consider the following Authlogic
scenario:
“‘ User.log_in_after_password_change = true ben = User.find(1) UserSession.create(ben) ben.password = “newpasswd” ben.password_confirmation = “newpasswd” ben.save “`
We’ve used one of Authlogic’s session maintenance features, ‘log_in_after_password_change`. So, when we call `ben.save`, there is a `before_save` callback that logs Ben in (`UserSession.find`). Well, when we log Ben in, we update his user record, eg. `login_count`. When we’re done logging Ben in, then the normal ‘ben.save` happens. So, there were two `update` queries. If those two updates came from different User instances, we would get a `StaleObjectError`.
Our solution is to carefully pass around a single ‘User` instance, using it for all `update` queries, thus avoiding the `StaleObjectError`.
Source
# File lib/authlogic/session/base.rb, line 675 def find_by_login_method(value = nil) ::ActiveSupport::Deprecation.new.warn(E_DPR_FIND_BY_LOGIN_METHOD) record_selection_method(value) end
@deprecated in favor of record_selection_method
Source
# File lib/authlogic/session/base.rb, line 718 def generalize_credentials_error_messages(value = nil) rw_config(:generalize_credentials_error_messages, value, false) end
The text used to identify credentials (username/password) combination when a bad login attempt occurs. When you show error messages for a bad login, it’s considered good security practice to hide which field the user has entered incorrectly (the login field or the password field). For a full explanation, see www.gnucitizen.org/blog/username-enumeration-vulnerabilities/
Example of use:
class UserSession < Authlogic::Session::Base generalize_credentials_error_messages true end This would make the error message for bad logins and bad passwords look identical: Login/Password combination is not valid Alternatively you may use a custom message: class UserSession < AuthLogic::Session::Base generalize_credentials_error_messages "Your login information is invalid" end This will instead show your custom error message when the UserSession is invalid.
The downside to enabling this is that is can be too vague for a user that has a hard time remembering their username and password combinations. It also disables the ability to to highlight the field with the error when you use form_for.
If you are developing an app where security is an extreme priority (such as a financial application), then you should enable this. Otherwise, leaving this off is fine.
-
Default
false -
Accepts:
Boolean
Source
# File lib/authlogic/session/base.rb, line 731 def http_basic_auth_realm(value = nil) rw_config(:http_basic_auth_realm, value, "Application") end
HTTP authentication realm
Sets the HTTP authentication realm.
Note: This option has no effect unless request_http_basic_auth
is true
-
Default:
‘Application’ -
Accepts:
String
Source
# File lib/authlogic/session/base.rb, line 741 def httponly(value = nil) rw_config(:httponly, value, true) end
Should the cookie be set as httponly? If true, the cookie will not be accessible from javascript
-
Default:
true -
Accepts:
Boolean
Source
# File lib/authlogic/session/base.rb, line 750 def human_name(*) I18n.t("models.#{name.underscore}", count: 1, default: name.humanize) end
How to name the class, works JUST LIKE ActiveRecord, except it uses the following namespace:
authlogic.models.user_session
Source
# File lib/authlogic/session/base.rb, line 764 def klass @klass ||= klass_name ? klass_name.constantize : nil end
The name of the class that this session is authenticating with. For example, the UserSession class will authenticate with the User class unless you specify otherwise in your configuration. See authenticate_with
for information on how to change this value.
@api public
Source
# File lib/authlogic/session/base.rb, line 776 def klass_name return @klass_name if instance_variable_defined?(:@klass_name) @klass_name = name.scan(/(.*)Session/)[0]&.first end
The model name, guessed from the session class name, e.g. “User”, from “UserSession”.
TODO: This method can return nil. We should explore this. It seems likely to cause a NoMethodError later, so perhaps we should raise an error instead.
@api private
Source
# File lib/authlogic/session/base.rb, line 837 def last_request_at_threshold(value = nil) rw_config(:last_request_at_threshold, value, 0) end
Every time a session is found the last_request_at field for that record is updated with the current time, if that field exists. If you want to limit how frequent that field is updated specify the threshold here. For example, if your user is making a request every 5 seconds, and you feel this is too frequent, and feel a minute is a good threshold. Set this to 1.minute. Once a minute has passed in between requests the field will be updated.
-
Default:
0 -
Accepts:
integer representing time in seconds
Source
# File lib/authlogic/session/base.rb, line 791 def login_field(value = nil) rw_config(:login_field, value, klass.login_field || klass.email_field) end
The name of the method you want Authlogic
to create for storing the login / username. Keep in mind this is just for your Authlogic::Session
, if you want it can be something completely different than the field in your model. So if you wanted people to login with a field called “login” and then find users by email this is completely doable. See the ‘record_selection_method` configuration option for details.
-
Default:
klass.login_field || klass.email_field -
Accepts:
Symbol or String
Source
# File lib/authlogic/session/base.rb, line 823 def logout_on_timeout(value = nil) rw_config(:logout_on_timeout, value, false) end
With acts_as_authentic you get a :logged_in_timeout configuration option. If this is set, after this amount of time has passed the user will be marked as logged out. Obviously, since web based apps are on a per request basis, we have to define a time limit threshold that determines when we consider a user to be “logged out”. Meaning, if they login and then leave the website, when do mark them as logged out? I recommend just using this as a fun feature on your website or reports, giving you a ballpark number of users logged in and active. This is not meant to be a dead accurate representation of a user’s logged in state, since there is really no real way to do this with web based apps. Think about a user that logs in and doesn’t log out. There is no action that tells you that the user isn’t technically still logged in and active.
That being said, you can use that feature to require a new login if their session times out. Similar to how financial sites work. Just set this option to true and if your record returns true for stale? then they will be required to log back in.
Lastly, UserSession.find will still return an object if the session is stale, but you will not get a record. This allows you to determine if the user needs to log back in because their session went stale, or because they just aren’t logged in. Just call current_user_session.stale? as your flag.
-
Default:
false -
Accepts:
Boolean
Source
# File lib/authlogic/session/base.rb, line 1118 def initialize(*args) @id = nil self.scope = self.class.scope define_record_alias_method raise Activation::NotActivatedError unless self.class.activated? unless self.class.configured_password_methods configure_password_methods self.class.configured_password_methods = true end instance_variable_set("@#{password_field}", nil) self.credentials = args end
Constructor
¶ ↑
Source
# File lib/authlogic/session/base.rb, line 855 def params_key(value = nil) rw_config(:params_key, value, cookie_key) end
Works exactly like cookie_key
, but for params. So a user can login via params just like a cookie or a session. Your URL would look like:
http://www.domain.com?user_credentials=my_single_access_key
You can change the “user_credentials” key above with this configuration option. Keep in mind, just like cookie_key
, if you supply an id the id will be appended to the front. Check out cookie_key
for more details. Also checkout the “Single Access / Private Feeds Access” section in the README.
-
Default:
cookie_key
-
Accepts:
String
Source
# File lib/authlogic/session/base.rb, line 865 def password_field(value = nil) rw_config(:password_field, value, login_field && :password) end
Works exactly like login_field
, but for the password instead. Returns :password if a login_field
exists.
-
Default:
:password -
Accepts:
Symbol or String
Source
# File lib/authlogic/session/base.rb, line 906 def record_selection_method(value = nil) rw_config(:record_selection_method, value, "find_by_smart_case_login_field") end
Authlogic
tries to validate the credentials passed to it. One part of validation is actually finding the user and making sure it exists. What method it uses the do this is up to you.
“‘ # user_session.rb record_selection_method
:find_by_email “`
This is the recommended way to find the user by email address. The resulting query will be ‘User.find_by_email(send(login_field
))`. (`login_field` will fall back to `email_field` if there’s no ‘login` or `username` column).
In your User model you can make that method do anything you want, giving you complete control of how users are found by the UserSession.
Let’s take an example: You want to allow users to login by username or email. Set this to the name of the class method that does this in the User model. Let’s call it “find_by_username_or_email”
“‘ class User < ActiveRecord::Base
def self.find_by_username_or_email(login) find_by_username(login) || find_by_email(login) end
end “‘
Now just specify the name of this method for this configuration option and you are all set. You can do anything you want here. Maybe you allow users to have multiple logins and you want to search a has_many relationship, etc. The sky is the limit.
-
Default:
“find_by_smart_case_login_field” -
Accepts:
Symbol or String
Source
# File lib/authlogic/session/base.rb, line 937 def remember_me(value = nil) rw_config(:remember_me, value, false) end
If sessions should be remembered by default or not.
-
Default:
false -
Accepts:
Boolean
Source
# File lib/authlogic/session/base.rb, line 946 def remember_me_for(value = nil) rw_config(:remember_me_for, value, 3.months) end
The length of time until the cookie expires.
-
Default:
3.months -
Accepts:
Integer, length of time in seconds, such as 60 or 3.months
Source
# File lib/authlogic/session/base.rb, line 928 def request_http_basic_auth(value = nil) rw_config(:request_http_basic_auth, value, false) end
Whether or not to request HTTP authentication
If set to true and no HTTP authentication credentials are sent with the request, the Rails controller method authenticate_or_request_with_http_basic will be used and a ‘401 Authorization Required’ header will be sent with the response. In most cases, this will cause the classic HTTP authentication popup to appear in the users browser.
If set to false, the Rails controller method authenticate_with_http_basic is used and no 401 header is sent.
Note: This parameter has no effect unless allow_http_basic_auth
is true
-
Default:
false -
Accepts:
Boolean
Source
# File lib/authlogic/session/base.rb, line 956 def same_site(value = nil) unless VALID_SAME_SITE_VALUES.include?(value) msg = "Invalid same_site value: #{value}. Valid: #{VALID_SAME_SITE_VALUES.inspect}" raise ArgumentError, msg end rw_config(:same_site, value) end
Should the cookie be prevented from being send along with cross-site requests?
-
Default:
nil -
Accepts:
String, one of nil, ‘Lax’ or ‘Strict’
Source
# File lib/authlogic/session/base.rb, line 966 def scope RequestStore.store[:authlogic_scope] end
The current scope set, should be used in the block passed to with_scope.
Source
# File lib/authlogic/session/base.rb, line 975 def secure(value = nil) rw_config(:secure, value, true) end
Should the cookie be set as secure? If true, the cookie will only be sent over SSL connections
-
Default:
true -
Accepts:
Boolean
Source
# File lib/authlogic/session/base.rb, line 985 def session_fixation_defense(value = nil) rw_config(:session_fixation_defense, value, true) end
Should the Rack session ID be reset after authentication, to protect against Session
Fixation attacks?
-
Default:
true -
Accepts:
Boolean
Source
# File lib/authlogic/session/base.rb, line 1018 def session_key(value = nil) rw_config(:session_key, value, cookie_key) end
Works exactly like cookie_key
, but for sessions. See cookie_key
for more info.
-
Default:
cookie_key
-
Accepts:
Symbol or String
Source
# File lib/authlogic/session/base.rb, line 1032 def single_access_allowed_request_types(value = nil) rw_config( :single_access_allowed_request_types, value, ["application/rss+xml", "application/atom+xml"] ) end
Authentication is allowed via a single access token, but maybe this is something you don’t want for your application as a whole. Maybe this is something you only want for specific request types. Specify a list of allowed request types and single access authentication will only be allowed for the ones you specify.
-
Default:
[“application/rss+xml”, “application/atom+xml”] -
Accepts:
String of a request type, or :all or :any to allow single access authentication for any and all request types
Source
# File lib/authlogic/session/base.rb, line 1047 def verify_password_method(value = nil) rw_config(:verify_password_method, value, "valid_password?") end
The name of the method in your model used to verify the password. This should be an instance method. It should also be prepared to accept a raw password and a crytped password.
-
Default:
“valid_password?” defined in acts_as_authentic/password.rb -
Accepts:
Symbol or String
Source
# File lib/authlogic/session/base.rb, line 1106 def with_scope(options = {}) raise ArgumentError, "You must provide a block" unless block_given? self.scope = options result = yield self.scope = nil result end
What with_scopes focuses on is scoping the query when finding the object and the name of the cookie / session. It works very similar to ActiveRecord::Base#with_scopes. It accepts a hash with any of the following options:
-
find_options:
any options you can pass into ActiveRecord::Base.find. This is used when trying to find the record. -
id:
The id of the session, this gets merged with the real id. For information ids see the id method.
Here is how you use it:
“‘ UserSession.with_scope(find_options: User.where(account_id: 2), id: “account_2”) do
UserSession.find
end “‘
Essentially what the above does is scope the searching of the object with the sql you provided. So instead of:
“‘ User.where(“login = ’ben’”).first “‘
it would effectively be:
“‘ User.where(“login = ’ben’ and account_id = 2”).first “‘
You will also notice the :id option. This works just like the id method. It scopes your cookies. So the name of your cookie will be:
account_2_user_credentials
instead of:
user_credentials
What is also nifty about scoping with an :id is that it merges your id’s. So if you do:
UserSession.with_scope( find_options: { conditions: "account_id = 2"}, id: "account_2" ) do session = UserSession.new session.id = :secure end
The name of your cookies will be:
secure_account_2_user_credentials
Private Class Methods
Source
# File lib/authlogic/session/base.rb, line 1577 def scope=(value) RequestStore.store[:authlogic_scope] = value end
Public Instance Methods
Source
# File lib/authlogic/session/base.rb, line 1138 def attempted_record @attempted_record end
You should use this as a place holder for any records that you find during validation. The main reason for this is to allow other modules to use it if needed. Take the failed_login_count feature, it needs this in order to increase the failed login count.
Source
# File lib/authlogic/session/base.rb, line 1143 def attempted_record=(value) value = priority_record if value == priority_record # See notes in `.find` @attempted_record = value end
See attempted_record
Source
# File lib/authlogic/session/base.rb, line 1153 def being_brute_force_protected? exceeded_failed_logins_limit? && ( failed_login_ban_for <= 0 || attempted_record.respond_to?(:updated_at) && attempted_record.updated_at >= failed_login_ban_for.seconds.ago ) end
Returns true when the consecutive_failed_logins_limit
has been exceeded and is being temporarily banned. Notice the word temporary, the user will not be permanently banned unless you choose to do so with configuration. By default they will be banned for 2 hours. During that 2 hour period this method will return true.
Source
# File lib/authlogic/session/base.rb, line 1167 def credentials if authenticating_with_unauthorized_record? { unauthorized_record: "<protected>" } elsif authenticating_with_password? { login_field.to_sym => send(login_field), password_field.to_sym => "<protected>" } else {} end end
The credentials you passed to create your session, in a redacted format intended for output (debugging, logging). See credentials= for more info.
@api private
Source
# File lib/authlogic/session/base.rb, line 1208 def credentials=(value) normalized = Array.wrap(value) if normalized.first.class.name == "ActionController::Parameters" raise TypeError, E_AC_PARAMETERS end # Allows you to set the remember_me option when passing credentials. values = value.is_a?(Array) ? value : [value] case values.first when Hash if values.first.with_indifferent_access.key?(:remember_me) self.remember_me = values.first.with_indifferent_access[:remember_me] end else r = values.find { |val| val.is_a?(TrueClass) || val.is_a?(FalseClass) } self.remember_me = r unless r.nil? end # Accepts the login_field / password_field credentials combination in # hash form. # # You must pass an actual Hash, `ActionController::Parameters` is # specifically not allowed. values = Array.wrap(value) if values.first.is_a?(Hash) sliced = values .first .with_indifferent_access .slice(login_field, password_field) sliced.each do |field, val| next if val.blank? send("#{field}=", val) end end # Setting the unauthorized record if it exists in the credentials passed. values = value.is_a?(Array) ? value : [value] self.unauthorized_record = values.first if values.first.class < ::ActiveRecord::Base # Setting the id if it is passed in the credentials. values = value.is_a?(Array) ? value : [value] self.id = values.last if values.last.is_a?(Symbol) # Setting priority record if it is passed. The only way it can be passed # is through an array: # # session.credentials = [real_user_object, priority_user_object] # # See notes in `.find` values = value.is_a?(Array) ? value : [value] self.priority_record = values[1] if values[1].class < ::ActiveRecord::Base end
Set your credentials before you save your session. There are many method signatures.
“‘ # A hash of credentials is most common session.credentials = { login: “foo”, password: “bar”, remember_me
: true }
# You must pass an actual Hash, ‘ActionController::Parameters` is # specifically not allowed.
# You can pass an array of objects: session.credentials = [my_user_object, true]
# If you need to set an id (see ‘#id`) pass it last. session.credentials = [
{:login => "foo", :password => "bar", :remember_me => true}, :my_id
] session.credentials = [my_user_object, true, :my_id]
The ‘id` is something that you control yourself, it should never be set from a hash or a form.
# Finally, there’s priority_record
- {
priority_record
: my_object }, :my_id -
“‘
rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
Source
# File lib/authlogic/session/base.rb, line 1265 def destroy run_callbacks :before_destroy save_record errors.clear @record = nil run_callbacks :after_destroy true end
Clears all errors and the associated record, you should call this terminate a session, thus requiring the user to authenticate again if it is needed.
Source
# File lib/authlogic/session/base.rb, line 1279 def errors @errors ||= ::ActiveModel::Errors.new(self) end
@api public
Source
# File lib/authlogic/session/base.rb, line 1284 def httponly return @httponly if defined?(@httponly) @httponly = self.class.httponly end
If the cookie should be marked as httponly (not accessible via javascript)
Source
# File lib/authlogic/session/base.rb, line 1291 def httponly=(value) @httponly = value end
Accepts a boolean as to whether the cookie should be marked as httponly. If true, the cookie will not be accessible from javascript
Source
# File lib/authlogic/session/base.rb, line 1296 def httponly? httponly == true || httponly == "true" || httponly == "1" end
See httponly
Source
# File lib/authlogic/session/base.rb, line 1316 def id @id end
Allows you to set a unique identifier for your session, so that you can have more than 1 session at a time.
For example, you may want to have simultaneous private and public sessions. Or, a normal user session and a “secure” user session. The secure user session would be created only when they want to modify their billing information, or other sensitive information.
You can set the id during initialization (see initialize for more information), or as an attribute:
session.id = :my_id
Set your id before you save your session.
Lastly, to retrieve your session with the id, use the ‘.find` method.
Source
# File lib/authlogic/session/base.rb, line 1320 def inspect format( "#<%s: %s>", self.class.name, credentials.blank? ? "no credentials provided" : credentials.inspect ) end
Source
# File lib/authlogic/session/base.rb, line 1328 def invalid_password? invalid_password == true end
Source
# File lib/authlogic/session/base.rb, line 1334 def new_record? new_session? end
Don’t use this yourself, this is to just trick some of the helpers since this is the method it calls.
Source
# File lib/authlogic/session/base.rb, line 1340 def new_session? new_session != false end
Returns true if the session is new, meaning no action has been taken on it and a successful save has not taken place.
Source
# File lib/authlogic/session/base.rb, line 1344 def persisted? !(new_record? || destroyed?) end
Source
# File lib/authlogic/session/base.rb, line 1357 def persisting? return true unless record.nil? self.attempted_record = nil self.remember_me = cookie_credentials&.remember_me? run_callbacks :before_persisting run_callbacks :persist ensure_authentication_attempted if errors.empty? && !attempted_record.nil? self.record = attempted_record run_callbacks :after_persisting save_record self.new_session = false true else false end end
Returns boolean indicating if the session is being persisted or not, meaning the user does not have to explicitly log in in order to be logged in.
If the session has no associated record, it will try to find a record and persist the session.
This is the method that the class level method find uses to ultimately persist the session.
Source
# File lib/authlogic/session/base.rb, line 1398 def remember_me return @remember_me if defined?(@remember_me) @remember_me = self.class.remember_me end
Is the cookie going to expire after the session is over, or will it stick around?
Source
# File lib/authlogic/session/base.rb, line 1406 def remember_me=(value) @remember_me = value end
Accepts a boolean as a flag to remember the session or not. Basically to expire the cookie at the end of the session or keep it for “remember_me_until”.
Source
# File lib/authlogic/session/base.rb, line 1411 def remember_me? remember_me == true || remember_me == "true" || remember_me == "1" end
See remember_me
Source
# File lib/authlogic/session/base.rb, line 1416 def remember_me_expired? return unless remember_me? cookie_credentials.remember_me_until < ::Time.now end
Has the cookie expired due to current time being greater than remember_me_until.
Source
# File lib/authlogic/session/base.rb, line 1423 def remember_me_for return unless remember_me? self.class.remember_me_for end
How long to remember the user if remember_me
is true. This is based on the class level configuration: remember_me_for
Source
# File lib/authlogic/session/base.rb, line 1430 def remember_me_until return unless remember_me? remember_me_for.from_now end
When to expire the cookie. See remember_me_for
configuration option to change this.
Source
# File lib/authlogic/session/base.rb, line 1487 def same_site return @same_site if defined?(@same_site) @same_site = self.class.same_site(nil) end
If the cookie should be marked as SameSite with ‘Lax’ or ‘Strict’ flag.
Source
# File lib/authlogic/session/base.rb, line 1493 def same_site=(value) unless VALID_SAME_SITE_VALUES.include?(value) msg = "Invalid same_site value: #{value}. Valid: #{VALID_SAME_SITE_VALUES.inspect}" raise ArgumentError, msg end @same_site = value end
Accepts nil, ‘Lax’ or ‘Strict’ as possible flags.
Source
# File lib/authlogic/session/base.rb, line 1440 def save result = nil if valid? self.record = attempted_record run_callbacks :before_save run_callbacks(new_session? ? :before_create : :before_update) run_callbacks(new_session? ? :after_create : :after_update) run_callbacks :after_save save_record self.new_session = false result = true else result = false end yield result if block_given? result end
After you have specified all of the details for your session you can try to save it. This will run validation checks and find the associated record, if all validation passes. If validation does not pass, the save will fail and the errors will be stored in the errors object.
Source
# File lib/authlogic/session/base.rb, line 1463 def save! result = save raise Existence::SessionInvalidError, self unless result result end
Same as save but raises an exception of validation errors when validation fails
Source
# File lib/authlogic/session/base.rb, line 1375 def save_record(alternate_record = nil) r = alternate_record || record if r != priority_record if r&.has_changes_to_save? && !r.readonly? r.save_without_session_maintenance(validate: false) end end end
Source
# File lib/authlogic/session/base.rb, line 1536 def scope @scope ||= {} end
The scope of the current object
Source
# File lib/authlogic/session/base.rb, line 1470 def secure return @secure if defined?(@secure) @secure = self.class.secure end
If the cookie should be marked as secure (SSL only)
Source
# File lib/authlogic/session/base.rb, line 1477 def secure=(value) @secure = value end
Accepts a boolean as to whether the cookie should be marked as secure. If true the cookie will only ever be sent over an SSL connection.
Source
# File lib/authlogic/session/base.rb, line 1482 def secure? secure == true || secure == "true" || secure == "1" end
See secure
Source
# File lib/authlogic/session/base.rb, line 1389 def stale? if remember_me? remember_me_expired? else !stale_record.nil? || (logout_on_timeout? && record && record.logged_out?) end end
Tells you if the record is stale or not. Meaning the record has timed out. This will only return true if you set logout_on_timeout
to true in your configuration. Basically how a bank website works. If you aren’t active over a certain period of time your session becomes stale and requires you to log back in.
Source
# File lib/authlogic/session/base.rb, line 1540 def to_key new_record? ? nil : record.to_key end
Source
# File lib/authlogic/session/base.rb, line 1545 def to_model self end
For rails >= 3.0
Source
# File lib/authlogic/session/base.rb, line 1554 def valid? errors.clear self.attempted_record = nil run_the_before_validation_callbacks # Run the `validate` callbacks, eg. `validate_by_password`. # This is when `attempted_record` is set. run_callbacks(:validate) ensure_authentication_attempted if errors.empty? run_the_after_validation_callbacks end save_record(attempted_record) errors.empty? end
Determines if the information you provided for authentication is valid or not. If there is a problem with the information provided errors will be added to the errors object and this method will return false.
@api public
Private Instance Methods
Source
# File lib/authlogic/session/base.rb, line 1587 def add_general_credentials_error error_message = if self.class.generalize_credentials_error_messages.is_a? String self.class.generalize_credentials_error_messages else "#{login_field.to_s.humanize}/Password combination is not valid" end errors.add( :base, I18n.t("error_messages.general_credentials_error", default: error_message) ) end
Private instance methods
¶ ↑
Source
# File lib/authlogic/session/base.rb, line 1600 def add_invalid_password_error if generalize_credentials_error_messages? add_general_credentials_error else errors.add( password_field, I18n.t("error_messages.password_invalid", default: "is not valid") ) end end
Source
# File lib/authlogic/session/base.rb, line 1611 def add_login_not_found_error if generalize_credentials_error_messages? add_general_credentials_error else errors.add( login_field, I18n.t("error_messages.login_not_found", default: "is not valid") ) end end
Source
# File lib/authlogic/session/base.rb, line 1622 def allow_http_basic_auth? self.class.allow_http_basic_auth == true end
Source
# File lib/authlogic/session/base.rb, line 1626 def authenticating_with_password? login_field && (!send(login_field).nil? || !send("protected_#{password_field}").nil?) end
Source
# File lib/authlogic/session/base.rb, line 1640 def build_key(last_part) [id, scope[:id], last_part].compact.join("_") end
Used for things like cookie_key
, session_key
, etc. Examples:
-
user_credentials
-
ziggity_zack_user_credentials
-
ziggity_zack is an “id”
-
see persistence_token_test.rb
-
Source
# File lib/authlogic/session/base.rb, line 1644 def clear_failed_login_count if record.respond_to?(:failed_login_count) record.failed_login_count = 0 end end
Source
# File lib/authlogic/session/base.rb, line 1690 def configure_password_methods define_login_field_methods define_password_field_methods end
Source
# File lib/authlogic/session/base.rb, line 1650 def consecutive_failed_logins_limit self.class.consecutive_failed_logins_limit end
Source
# File lib/authlogic/session/base.rb, line 1654 def controller self.class.controller end
Source
# File lib/authlogic/session/base.rb, line 1702 def define_login_field_methods return unless login_field self.class.send(:attr_writer, login_field) unless respond_to?("#{login_field}=") self.class.send(:attr_reader, login_field) unless respond_to?(login_field) end
Source
# File lib/authlogic/session/base.rb, line 1709 def define_password_field_methods return unless password_field define_password_field_writer_method define_password_field_reader_methods end
@api private
Source
# File lib/authlogic/session/base.rb, line 1720 def define_password_field_reader_methods unless respond_to?(password_field) # Deliberate no-op method, see rationale above. self.class.send(:define_method, password_field) {} end self.class.class_eval( <<-EOS, __FILE__, __LINE__ + 1 private def protected_#{password_field} @#{password_field} end EOS ) end
The password should not be accessible publicly. This way forms using form_for don’t fill the password with the attempted password. To prevent this we just create this method that is private.
@api private
Source
# File lib/authlogic/session/base.rb, line 1735 def define_password_field_writer_method unless respond_to?("#{password_field}=") self.class.send(:attr_writer, password_field) end end
Source
# File lib/authlogic/session/base.rb, line 1751 def define_record_alias_method noun = klass_name.demodulize.underscore.to_sym return if respond_to?(noun) self.class.send(:alias_method, noun, :record) end
Creating an alias method for the “record” method based on the klass name, so that we can do:
session.user
instead of:
session.record
@api private
Source
# File lib/authlogic/session/base.rb, line 1761 def disable_magic_states? self.class.disable_magic_states == true end
Source
# File lib/authlogic/session/base.rb, line 1765 def enforce_timeout if stale? self.stale_record = record self.record = nil end end
Source
# File lib/authlogic/session/base.rb, line 1772 def ensure_authentication_attempted if errors.empty? && attempted_record.nil? errors.add( :base, I18n.t( "error_messages.no_authentication_details", default: "You did not provide any details for authentication." ) ) end end
Source
# File lib/authlogic/session/base.rb, line 1784 def exceeded_failed_logins_limit? !attempted_record.nil? && attempted_record.respond_to?(:failed_login_count) && consecutive_failed_logins_limit > 0 && attempted_record.failed_login_count && attempted_record.failed_login_count >= consecutive_failed_logins_limit end
Source
# File lib/authlogic/session/base.rb, line 1838 def failed_login_ban_for self.class.failed_login_ban_for end
Source
# File lib/authlogic/session/base.rb, line 1793 def find_by_login_method ::ActiveSupport::Deprecation.new.warn(E_DPR_FIND_BY_LOGIN_METHOD) self.class.record_selection_method end
@deprecated in favor of ‘self.class.record_selection_method`
Source
# File lib/authlogic/session/base.rb, line 1798 def generalize_credentials_error_messages? self.class.generalize_credentials_error_messages end
Source
# File lib/authlogic/session/base.rb, line 1828 def http_auth_login_proc proc do |login, password| if !login.blank? && !password.blank? send("#{login_field}=", login) send("#{password_field}=", password) valid? end end end
Returns a Proc to be executed by ‘ActionController::HttpAuthentication::Basic` when credentials are present in the HTTP request.
@api private @return Proc
Source
# File lib/authlogic/session/base.rb, line 1842 def increase_failed_login_count if invalid_password? && attempted_record.respond_to?(:failed_login_count) attempted_record.failed_login_count ||= 0 attempted_record.failed_login_count += 1 end end
Source
# File lib/authlogic/session/base.rb, line 1849 def increment_login_count if record.respond_to?(:login_count) record.login_count = (record.login_count.blank? ? 1 : record.login_count + 1) end end
Source
# File lib/authlogic/session/base.rb, line 1859 def klass_name self.class.klass_name end
Source
# File lib/authlogic/session/base.rb, line 1863 def last_request_at_threshold self.class.last_request_at_threshold end
Source
# File lib/authlogic/session/base.rb, line 1867 def login_field self.class.login_field end
Source
# File lib/authlogic/session/base.rb, line 1871 def logout_on_timeout? self.class.logout_on_timeout == true end
Source
# File lib/authlogic/session/base.rb, line 1875 def params_credentials controller.params[params_key] end
Source
# File lib/authlogic/session/base.rb, line 1879 def params_enabled? if !params_credentials || !klass.column_names.include?("single_access_token") return false end if controller.responds_to_single_access_allowed? return controller.single_access_allowed? end params_enabled_by_allowed_request_types? end
Source
# File lib/authlogic/session/base.rb, line 1889 def params_enabled_by_allowed_request_types? case single_access_allowed_request_types when Array single_access_allowed_request_types.include?(controller.request_content_type) || single_access_allowed_request_types.include?(:all) else %i[all any].include?(single_access_allowed_request_types) end end
Source
# File lib/authlogic/session/base.rb, line 1899 def params_key build_key(self.class.params_key) end
Source
# File lib/authlogic/session/base.rb, line 1903 def password_field self.class.password_field end
Source
# File lib/authlogic/session/base.rb, line 1930 def persist_by_http_auth login_proc = http_auth_login_proc if self.class.request_http_basic_auth controller.authenticate_or_request_with_http_basic( self.class.http_basic_auth_realm, &login_proc ) else controller.authenticate_with_http_basic(&login_proc) end false end
Source
# File lib/authlogic/session/base.rb, line 1945 def persist_by_http_auth? allow_http_basic_auth? && login_field && password_field end
Source
# File lib/authlogic/session/base.rb, line 1921 def persist_by_params return false unless params_enabled? self.unauthorized_record = search_for_record( "find_by_single_access_token", params_credentials ) self.single_access = valid? end
Source
# File lib/authlogic/session/base.rb, line 1950 def persist_by_session persistence_token, record_id = session_credentials if !persistence_token.nil? record = persist_by_session_search(persistence_token, record_id) if record && record.persistence_token == persistence_token self.unauthorized_record = record end valid? else false end end
Tries to validate the session from information in the session
Source
# File lib/authlogic/session/base.rb, line 1966 def persist_by_session_search(persistence_token, record_id) if record_id.nil? search_for_record("find_by_persistence_token", persistence_token.to_s) else search_for_record("find_by_#{klass.primary_key}", record_id.to_s) end end
Allow finding by persistence token, because when records are created the session is maintained in a before_save, when there is no id. This is done for performance reasons and to save on queries.
Source
# File lib/authlogic/session/base.rb, line 1697 def renew_session_id return unless self.class.session_fixation_defense controller.renew_session_id end
Assign a new controller-session ID, to defend against Session
Fixation. guides.rubyonrails.org/v6.0/security.html#session-fixation
Source
# File lib/authlogic/session/base.rb, line 1986 def required_magic_states_for(record) %i[active approved confirmed].select { |state| record.respond_to?("#{state}?") } end
@api private
Source
# File lib/authlogic/session/base.rb, line 1996 def reset_failed_login_count attempted_record.failed_login_count = 0 end
Source
# File lib/authlogic/session/base.rb, line 1992 def reset_failed_login_count? exceeded_failed_logins_limit? && !being_brute_force_protected? end
Source
# File lib/authlogic/session/base.rb, line 1978 def reset_perishable_token! if record.respond_to?(:reset_perishable_token) && !record.disable_perishable_token_maintenance? record.reset_perishable_token end end
Source
# File lib/authlogic/session/base.rb, line 1974 def reset_stale_state self.stale_record = nil end
Source
# File lib/authlogic/session/base.rb, line 2001 def run_the_after_validation_callbacks run_callbacks(new_session? ? :after_validation_on_create : :after_validation_on_update) run_callbacks(:after_validation) end
@api private
Source
# File lib/authlogic/session/base.rb, line 2007 def run_the_before_validation_callbacks run_callbacks(:before_validation) run_callbacks(new_session? ? :before_validation_on_create : :before_validation_on_update) end
@api private
Source
# File lib/authlogic/session/base.rb, line 2014 def search_for_record(*args) search_scope.scoping do klass.send(*args) end end
‘args` is the name of a model method, like `find_by_single_access_token` or `find_by_smart_case_login_field`.
Source
# File lib/authlogic/session/base.rb, line 2023 def search_scope if scope[:find_options].is_a?(ActiveRecord::Relation) scope[:find_options] else conditions = scope[:find_options] && scope[:find_options][:conditions] || {} klass.send(:where, conditions) end end
Returns an AR relation representing the scope of the search. The relation is either provided directly by, or defined by ‘find_options`.
Source
# File lib/authlogic/session/base.rb, line 2058 def session_compound_key "#{session_key}_#{klass.primary_key}" end
@api private @return [String] - Examples:
-
user_credentials_id
-
ziggity_zack_user_credentials_id
-
ziggity_zack is an “id”, see ‘#id`
-
see persistence_token_test.rb
-
Source
# File lib/authlogic/session/base.rb, line 2062 def session_credentials [ controller.session[session_key], controller.session[session_compound_key] ].collect { |i| i.nil? ? i : i.to_s }.compact end
Source
# File lib/authlogic/session/base.rb, line 2074 def session_key build_key(self.class.session_key) end
@return [String] - Examples:
-
user_credentials
-
ziggity_zack_user_credentials
-
ziggity_zack is an “id”, see ‘#id`
-
see persistence_token_test.rb
-
Source
# File lib/authlogic/session/base.rb, line 2033 def set_last_request_at current_time = Time.current MagicColumn::AssignsLastRequestAt .new(current_time, record, controller, last_request_at_threshold) .assign end
@api private
Source
# File lib/authlogic/session/base.rb, line 2040 def single_access? single_access == true end
Source
# File lib/authlogic/session/base.rb, line 2044 def single_access_allowed_request_types self.class.single_access_allowed_request_types end
Source
# File lib/authlogic/session/base.rb, line 2078 def update_info increment_login_count clear_failed_login_count update_login_timestamps update_login_ip_addresses end
Source
# File lib/authlogic/session/base.rb, line 2085 def update_login_ip_addresses if record.respond_to?(:current_login_ip) record.last_login_ip = record.current_login_ip if record.respond_to?(:last_login_ip) record.current_login_ip = controller.request.ip end end
Source
# File lib/authlogic/session/base.rb, line 2092 def update_login_timestamps if record.respond_to?(:current_login_at) record.last_login_at = record.current_login_at if record.respond_to?(:last_login_at) record.current_login_at = Time.current end end
Source
# File lib/authlogic/session/base.rb, line 2099 def update_session update_session_set_persistence_token update_session_set_primary_key end
Source
# File lib/authlogic/session/base.rb, line 2116 def update_session_set_persistence_token controller.session[session_key] = record && record.persistence_token end
Updates the session, setting the ‘persistence_token` of the record.
@api private
Source
# File lib/authlogic/session/base.rb, line 2108 def update_session_set_primary_key compound_key = session_compound_key controller.session[compound_key] = record && record.send(record.class.primary_key) end
Updates the session, setting the primary key (usually ‘id`) of the record.
@api private
Source
# File lib/authlogic/session/base.rb, line 2122 def validate_by_password self.invalid_password = false validate_by_password__blank_fields return if errors.count > 0 self.attempted_record = search_for_record( self.class.record_selection_method, send(login_field) ) if attempted_record.blank? add_login_not_found_error return end validate_by_password__invalid_password end
In keeping with the metaphor of ActiveRecord, verification of the password is referred to as a “validation”.
Source
# File lib/authlogic/session/base.rb, line 2137 def validate_by_password__blank_fields if send(login_field).blank? errors.add( login_field, I18n.t("error_messages.login_blank", default: "cannot be blank") ) end if send("protected_#{password_field}").blank? errors.add( password_field, I18n.t("error_messages.password_blank", default: "cannot be blank") ) end end
Source
# File lib/authlogic/session/base.rb, line 2155 def validate_by_password__invalid_password unless attempted_record.send( verify_password_method, send("protected_#{password_field}") ) self.invalid_password = true add_invalid_password_error end end
Verify the password, usually using ‘valid_password?` in `acts_as_authentic/password.rb`. If it cannot be verified, we refer to it as “invalid”.
Source
# File lib/authlogic/session/base.rb, line 2185 def validate_failed_logins # Clear all other error messages, as they are irrelevant at this point and can # only provide additional information that is not needed errors.clear duration = failed_login_ban_for == 0 ? "" : " temporarily" errors.add( :base, I18n.t( "error_messages.consecutive_failed_logins_limit_exceeded", default: format( "Consecutive failed logins limit exceeded, account has been%s disabled.", duration ) ) ) end
Source
# File lib/authlogic/session/base.rb, line 2169 def validate_magic_states return true if attempted_record.nil? required_magic_states_for(attempted_record).each do |required_status| next if attempted_record.send("#{required_status}?") errors.add( :base, I18n.t( "error_messages.not_#{required_status}", default: "Your account is not #{required_status}" ) ) return false end true end
Source
# File lib/authlogic/session/base.rb, line 2202 def verify_password_method self.class.verify_password_method end