added authlogic as gem. fetching fog from github due to s3 bug in gem release
This commit is contained in:
parent
4ba31d4028
commit
5a3913e936
6
Gemfile
6
Gemfile
|
@ -2,8 +2,10 @@ source 'http://rubygems.org'
|
|||
|
||||
gem 'rails'
|
||||
|
||||
gem 'authlogic'
|
||||
|
||||
gem 'mime-types', :require => 'mime/types'
|
||||
gem "carrierwave", :git => 'git://github.com/jnicklas/carrierwave.git'
|
||||
gem 'carrierwave', :git => 'git://github.com/jnicklas/carrierwave.git'
|
||||
|
||||
# -- Database
|
||||
# SQLite
|
||||
|
@ -15,7 +17,7 @@ gem 'sqlite3-ruby'
|
|||
|
||||
# -- Cloud storage
|
||||
# AWS S3 support. Can be disabled if using local file system instead of cloud storage.
|
||||
gem 'fog'
|
||||
gem 'fog', :git => 'git://github.com/geemus/fog.git'
|
||||
|
||||
# -- Photo resizing
|
||||
# MiniMagick
|
||||
|
|
87
Gemfile.lock
87
Gemfile.lock
|
@ -1,6 +1,20 @@
|
|||
GIT
|
||||
remote: git://github.com/geemus/fog.git
|
||||
revision: 72855da3d7b21d5c1ba4f25da6be4f04375c68b9
|
||||
specs:
|
||||
fog (0.7.2)
|
||||
builder
|
||||
excon (~> 0.6.1)
|
||||
formatador (>= 0.1.3)
|
||||
json
|
||||
mime-types
|
||||
net-ssh (>= 2.1.3)
|
||||
nokogiri (>= 1.4.4)
|
||||
ruby-hmac
|
||||
|
||||
GIT
|
||||
remote: git://github.com/jnicklas/carrierwave.git
|
||||
revision: 844788609b3c25b0435c42059c9db49d89ba6680
|
||||
revision: d2cb99103a4fd3a4927ea616b251809969831fbe
|
||||
specs:
|
||||
carrierwave (0.5.3)
|
||||
activesupport (~> 3.0)
|
||||
|
@ -9,12 +23,12 @@ GEM
|
|||
remote: http://rubygems.org/
|
||||
specs:
|
||||
abstract (1.0.0)
|
||||
actionmailer (3.0.6)
|
||||
actionpack (= 3.0.6)
|
||||
actionmailer (3.0.7)
|
||||
actionpack (= 3.0.7)
|
||||
mail (~> 2.2.15)
|
||||
actionpack (3.0.6)
|
||||
activemodel (= 3.0.6)
|
||||
activesupport (= 3.0.6)
|
||||
actionpack (3.0.7)
|
||||
activemodel (= 3.0.7)
|
||||
activesupport (= 3.0.7)
|
||||
builder (~> 2.1.2)
|
||||
erubis (~> 2.6.6)
|
||||
i18n (~> 0.5.0)
|
||||
|
@ -22,44 +36,38 @@ GEM
|
|||
rack-mount (~> 0.6.14)
|
||||
rack-test (~> 0.5.7)
|
||||
tzinfo (~> 0.3.23)
|
||||
activemodel (3.0.6)
|
||||
activesupport (= 3.0.6)
|
||||
activemodel (3.0.7)
|
||||
activesupport (= 3.0.7)
|
||||
builder (~> 2.1.2)
|
||||
i18n (~> 0.5.0)
|
||||
activerecord (3.0.6)
|
||||
activemodel (= 3.0.6)
|
||||
activesupport (= 3.0.6)
|
||||
activerecord (3.0.7)
|
||||
activemodel (= 3.0.7)
|
||||
activesupport (= 3.0.7)
|
||||
arel (~> 2.0.2)
|
||||
tzinfo (~> 0.3.23)
|
||||
activeresource (3.0.6)
|
||||
activemodel (= 3.0.6)
|
||||
activesupport (= 3.0.6)
|
||||
activesupport (3.0.6)
|
||||
activeresource (3.0.7)
|
||||
activemodel (= 3.0.7)
|
||||
activesupport (= 3.0.7)
|
||||
activesupport (3.0.7)
|
||||
arel (2.0.9)
|
||||
authlogic (3.0.2)
|
||||
activerecord (~> 3.0.7)
|
||||
activerecord (~> 3.0.7)
|
||||
builder (2.1.2)
|
||||
erubis (2.6.6)
|
||||
abstract (>= 1.0.0)
|
||||
excon (0.6.1)
|
||||
fog (0.7.2)
|
||||
builder
|
||||
excon (>= 0.6.1)
|
||||
formatador (>= 0.1.3)
|
||||
json
|
||||
mime-types
|
||||
net-ssh (>= 2.1.3)
|
||||
nokogiri (>= 1.4.4)
|
||||
ruby-hmac
|
||||
excon (0.6.3)
|
||||
formatador (0.1.3)
|
||||
i18n (0.5.0)
|
||||
json (1.5.1)
|
||||
mail (2.2.15)
|
||||
mail (2.2.19)
|
||||
activesupport (>= 2.3.6)
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mime-types (1.16)
|
||||
mini_exiftool (1.3.0)
|
||||
mini_magick (3.2)
|
||||
mini_magick (3.2.1)
|
||||
subexec (~> 0.0.4)
|
||||
net-ssh (2.1.4)
|
||||
nokogiri (1.4.4)
|
||||
|
@ -69,17 +77,17 @@ GEM
|
|||
rack (>= 1.0.0)
|
||||
rack-test (0.5.7)
|
||||
rack (>= 1.0)
|
||||
rails (3.0.6)
|
||||
actionmailer (= 3.0.6)
|
||||
actionpack (= 3.0.6)
|
||||
activerecord (= 3.0.6)
|
||||
activeresource (= 3.0.6)
|
||||
activesupport (= 3.0.6)
|
||||
rails (3.0.7)
|
||||
actionmailer (= 3.0.7)
|
||||
actionpack (= 3.0.7)
|
||||
activerecord (= 3.0.7)
|
||||
activeresource (= 3.0.7)
|
||||
activesupport (= 3.0.7)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.0.6)
|
||||
railties (3.0.6)
|
||||
actionpack (= 3.0.6)
|
||||
activesupport (= 3.0.6)
|
||||
railties (= 3.0.7)
|
||||
railties (3.0.7)
|
||||
actionpack (= 3.0.7)
|
||||
activesupport (= 3.0.7)
|
||||
rake (>= 0.8.7)
|
||||
thor (~> 0.14.4)
|
||||
rake (0.8.7)
|
||||
|
@ -91,14 +99,15 @@ GEM
|
|||
thor (0.14.6)
|
||||
treetop (1.4.9)
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.26)
|
||||
tzinfo (0.3.27)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
authlogic
|
||||
carrierwave!
|
||||
fog
|
||||
fog!
|
||||
mime-types
|
||||
mini_exiftool
|
||||
mini_magick
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
CarrierWave.configure do |config|
|
||||
config.s3_access_key_id = ENV['S3_KEY']
|
||||
config.s3_secret_access_key = ENV['S3_SECRET']
|
||||
config.s3_bucket = ENV['S3_BUCKET']
|
||||
#config.fog_credentials = {
|
||||
# :provider => 'AWS',
|
||||
# :aws_access_key_id => ENV['S3_KEY'],
|
||||
# :aws_secret_access_key => ENV['S3_SECRET'],
|
||||
# :region => 'us-east-1'
|
||||
#}
|
||||
#config.fog_directory = ENV['S3_BUCKET']
|
||||
config.fog_credentials = {
|
||||
:provider => 'AWS',
|
||||
:aws_access_key_id => ENV['S3_KEY'],
|
||||
:aws_secret_access_key => ENV['S3_SECRET'],
|
||||
:region => 'us-east-1'
|
||||
}
|
||||
config.fog_directory = ENV['S3_BUCKET']
|
||||
end
|
9
vendor/plugins/authlogic/.gitignore
vendored
9
vendor/plugins/authlogic/.gitignore
vendored
|
@ -1,9 +0,0 @@
|
|||
.DS_Store
|
||||
.swp
|
||||
*.log
|
||||
*.sqlite3
|
||||
pkg/*
|
||||
coverage/*
|
||||
doc/*
|
||||
benchmarks/*
|
||||
.specification
|
345
vendor/plugins/authlogic/CHANGELOG.rdoc
vendored
345
vendor/plugins/authlogic/CHANGELOG.rdoc
vendored
|
@ -1,345 +0,0 @@
|
|||
== 2.1.2
|
||||
|
||||
* Return the newly create object for the class level create method, instead of a boolean
|
||||
* Add a model_name class method for Authlogic::Session for rails 3 compatibility. Will be using ActiveModel eventually, but this should be a quick fix.
|
||||
|
||||
== 2.1.1 released 2009-7-04
|
||||
|
||||
* Use mb_chars when downcasing the login string to support international characters.
|
||||
* Check for the existence of the :remember_me key before setting remember_me off of a hash.
|
||||
* Added check to make sure Authlogic is not loaded too late, causing a NotActivated error.
|
||||
|
||||
== 2.1.0 released 2009-6-27
|
||||
|
||||
* Fixed bug when using act_like_restful_authentication and setting passwords, needed to add a 2nd parameter to tell if to check against the database or not.
|
||||
* Don't save record if they are read only.
|
||||
|
||||
== 2.0.14 released 2009-6-13
|
||||
|
||||
* Fixed issue with using brute force protection AND generalize_credentials_error_messages. Brute force protection was looking to see if there were password errors, which generalize_credentials_error_messages was obfuscating.
|
||||
* Added db_setup? method to avoid errors during rake tasks where the db might not be set up. Ex: migrations
|
||||
* Stop using errors.on(key) since that is now deprecated in Rails. Use errors[key] instead.
|
||||
* Use valid_password? for the method name to validate a password instead of valid_#{password_field}?.
|
||||
|
||||
== 2.0.13 released 2009-5-13
|
||||
|
||||
* Add authlogic/regex.rb to manifest
|
||||
|
||||
== 2.0.12 released 2009-5-13
|
||||
|
||||
* Added the ability to add a last_request_update_allowed? method in your controller to pragmatically tell Authlogic when and when not to update the last_request_at field in your database. This only takes effect if the method if present.
|
||||
* Extracted Authlogic's regular expressions into it's own module to allow easy use of them outside of Authlogic. See Authlogic::Regex for more info.
|
||||
* Made being_brute_force_protected? true for the Authlogic::Session::BruteForceProtection module.
|
||||
* Added the configuration option generalize_credentials_error_messages for the Authlogic::Session::Password module. This allows you to generalize your login / password errors messages as to not reveal was the problem was when authenticating. If enabled, when an invalid login is supplied it will use the same exact error message when an invalid password is supplied.
|
||||
* Update email regular expression to use A-Z0-9 instead of /w as to not allow for diacritical marks in an email address.
|
||||
* Changed config() convenience method to rw_config() to be more descriptive and less vague.
|
||||
|
||||
== 2.0.11 released 2009-4-25
|
||||
|
||||
* Fix bug when password is turned off and the SingleAccessToken module calls the after_password_set callback.
|
||||
* HTTP basic auth can now be toggled on or off. It also checks for the existence of a standard username and password before enabling itself.
|
||||
* Added option check_passwords_against_database for Authlogic::ActsAsAuthentic::Password to toggle between checking the password against the database value or the object value. Also added the same functionality to the instance method: valid_password?("password", true), where the second argument tells Authlogic to check the password against the database value. The default for this new feature is true.
|
||||
* Add a maintain_sessions configuration option to Authlogic::ActsAsAuthentic::SessionMaintenance as a "clearer" option to disable automatic session maintenance.
|
||||
* single_access_allowed_request_types can also be equal to :all instead of just [:all].
|
||||
* Refactor params_enabled? so that the single_access_allowed? method in controllers takes precedence.
|
||||
* Added testing comments in the README and expanded on the documentation in Authlogic::TestCase
|
||||
|
||||
== 2.0.10 released 2009-4-21
|
||||
|
||||
* Mock request is now transparent to non existent methods. Since the methods calls really have no functional value when testing authlogic.
|
||||
* Allow password confirmation to be disabled.
|
||||
* Modified login format validation to allow for the + character since emails addresses allow that as a valid character.
|
||||
* Added merge_* configuration methods for acts_as_authentic to make merging options into configuration options that default to hashes. Just a few convenience methods.
|
||||
|
||||
== 2.0.9 released 2009-4-9
|
||||
|
||||
* Fixed bug where hooks provided by the password module were called when the password module was not being used due to the fact that the password field did not exist.
|
||||
* Fixed bug where the find_with_login method was not being aliased if you were using an alternate field besides login.
|
||||
|
||||
== 2.0.8 release 2009-4-9
|
||||
|
||||
* Dont reset the @password_changed instance variable to false because its halts the callback chain, instead reset it to nil.
|
||||
|
||||
== 2.0.7 released 2009-4-9
|
||||
|
||||
* Rename TestCase::ControllerAdapter to TestCase::RailsRequestAdapter to help clarify it's usage and fix a constant typo.
|
||||
|
||||
== 2.0.6 released 2009-4-9
|
||||
|
||||
* Don't use second, use [1] instead so older rails versions don't complain.
|
||||
* Update email regular expression to be less TLD specific: (?:[A-Z]{2,4}|museum|travel)
|
||||
* Update shoulda macro for 2.0
|
||||
* validates_length_of_password_confirmation_field_options defaults to validates_confirmation_of_password_field_options
|
||||
* Use MockCookieJar in tests instead of a Hash in the MockController.
|
||||
* Cookies now store the record id as well, for faster lookup. Also to avoid the need to use sessions since sessions are lazily loaded in rails 2.3+
|
||||
* Add configuration option for Authlogic::ActsAsAuthentic: ignore_blank_passwords
|
||||
* Fix cookie_domain in rails adapter
|
||||
* Make password and login fields optional. This allows you to have an alternate authentication method as your main authentication source. Such as OpenID, LDAP, or whatever you want.
|
||||
* Reset the @password_changed instance variable after the record has been saved.
|
||||
* Add referer and user_agent to mock requests for testing purposes.
|
||||
* Add :case_sensitive => false to validates_uniqueness_of calls on the login and email fields.
|
||||
* MockRequest not tries to use controller.env['REMOTE_ADDR'] for the IP address in tests.
|
||||
* Add in custom find_with_email and find_with_login methods to perform case insensitive searches for databases that are case sensitive by default. This is only done if the :case_insensitive option for validates_uniqueness_of_login_field_options or validates_uniqueness_of_email_field_options is set to false. Which, as of this version, it is. If you are using MySQL this has been the default behavior all along. If you are using SQLite or Postgres this has NOT been the default behavior.
|
||||
* Added in exception explaining that you are using the old configuration for acts_as_authentic with an example of the new format.
|
||||
|
||||
== 2.0.5 released 2009-3-30
|
||||
|
||||
* Stub out authenticate_with_http_basic for TestCase::ControllerAdapter.
|
||||
* Added second parameter for add_acts_as_authentic module to specify the position: append or prepend.
|
||||
|
||||
== 2.0.4 released 2009-3-28
|
||||
|
||||
* Added validates_uniqueness_of_login_field_options and validates_uniqueness_of_email_field_options configuration options
|
||||
* Add in checks to make sure session_class is not nil.
|
||||
* Cleaned up TestCase some more and added functionality to log users in during functional tests.
|
||||
|
||||
== 2.0.3 released 2009-3-26
|
||||
|
||||
* Fixed error where default session class does not exist.
|
||||
* Fixed human_name for the model to use its own human name and not delegate to the associated model. Translation should be under authlogic.models.user_session (or whatever the name of your session is).
|
||||
* Fixed human_attribute_name to use Authlogic keys for translation instead of ActiveRecord: authlogic.attributes.user_session.login
|
||||
* For transitioning from restful_authentication, set the REST_AUTH_SITE_KEY to '' if it doesn't exist, instead of nil.
|
||||
* Completely rewrote Authlogic::Testing, it's now called Authlogic::TestCase. Testing Authlogic is much easier now. Please see Authlogic::TestCase for more info.
|
||||
|
||||
== 2.0.2 released 2009-3-24
|
||||
|
||||
* Reset failed_login_count if consecutive_failed_logins_limit has been exceed and the failed_login_ban_for has passed.
|
||||
* Update test helpers to use the new configuration scheme.
|
||||
* Fixed issue when logging doesn't update last_request_at, so the next persistence try would fail.
|
||||
|
||||
== 2.0.1 released 2009-3-23
|
||||
|
||||
* Validate length of password.
|
||||
* Dont save sessions with a ! during session maintenance.
|
||||
* Add self_and_descendants_from_active_record for Rails 2.3
|
||||
* Abort acts_as_authentic if there is no DB connection or table.
|
||||
|
||||
== 2.0.0 released 2009-3-23
|
||||
|
||||
* Refactored nearly all code and tests, especially acts_as_authentic. Got rid of the meta programming and rewrote to use modules and hooks. Also moved all configuration into their related modules.
|
||||
* Set up a strong API with hooks to allow you to modify behavior and most importantly, easily create "add on" modules or alternate authentication methods, etc.
|
||||
* Changed configuration method for acts_as_authentic to accept a block instead of a hash.
|
||||
* The record attribute will NEVER be set until after validation passes, similar to how ActiveRecord executes UPDATEs and CREATEs.
|
||||
* Fixed bug with session maintenance where user would log in as new user when creating another user account, typically an admin function.
|
||||
* Brute force protection is only a temporary ban by default, not a permanent one.
|
||||
* Switched to Hoe for gem management instead of Echoe.
|
||||
* Added MD5 crypto provider for legacy systems.
|
||||
* Make password salt field optional for legacy systems.
|
||||
|
||||
== 1.4.4 released 2009-3-2
|
||||
|
||||
* Moved session maintenance to a before_save, to save on queries executed and to skip an unexpected / additional save on the user object.
|
||||
* Extracted random string generation into its own class and leverages SecureRandom if it is available
|
||||
* Move cookies to a higher priority when trying to find the record to help with performance since Rails 3 lazily loads the sessions
|
||||
* Reset perishable token in a before_save instead of a before_validation
|
||||
|
||||
== 1.4.3 released 2009-2-22
|
||||
|
||||
* Fixed issue with brute force protection.
|
||||
|
||||
== 1.4.2 released 2009-2-20
|
||||
|
||||
* Cleaned up callbacks system to use hooks and execute in the proper order.
|
||||
* Added brute force protection. See the consecutive_failed_logins_limit configuration option in Authlogic::Session::Config. Also see Authlogic::Session:BruteForceProtection
|
||||
* Fixed issue with calling stale? when there is no record.
|
||||
* Simon Harris fixed the issue of using lock_version with the associated record and also optimized the library for better performance.
|
||||
* Implemented saving the record during the callback chain to execute as few queries as possible. This way modules can hook into Authlogic, modify the associated record, and not have to worry about saving the record.
|
||||
|
||||
== 1.4.1 released 2009-2-8
|
||||
|
||||
* Fixed I18n key misspelling.
|
||||
* Added I18n keys for ORM error messages.
|
||||
* Use the password_field configuration value for the alias_methods defined in acts_as_authentic/credentials.rb
|
||||
* Change shoulda macros implementation to follow the shoulda documentation
|
||||
* Rails >2.3 uses :domain for the session option instead of :session_domain. Authlogic now uses the proper key in the rails adapter.
|
||||
* Added validate_password attribute to force password validation regardless if the password is blank. This is useful for forms explicitly changing passwords.
|
||||
* The class level find method will return a session object if the session is stale. The protection is that there will be no record associated with that session. This allows you to receive an object and call the stale? method on it to determine why the user must log back in.
|
||||
* Added validate callbacks in Session::Base so you can run callbacks by calling validate :my_method, just like in AR.
|
||||
* Checked for blank persistence tokens when trying to validate passwords, this is where transitioning occurs. People transitioning from older systems never had a persistence token, which means it would be nil here.
|
||||
* Update allowed domain name extensions for email
|
||||
* Ignore default length options for validations if alternate length options are provided, since AR raises an error if 2 different length specifications are provided.
|
||||
|
||||
== 1.4.0 released 2009-1-28
|
||||
|
||||
* Added support for cookie domain, based on your frameworks session domain configuration
|
||||
* Updated test helper functions to use the persistence token config value
|
||||
* Check for UTC times when using Time.now for current_login_at and last_request_at
|
||||
* Single access now looks for a single_access_allowed? method in your controllers to determine if single access should be allowed or not. Allowing you to define exactly when single access is allowed.
|
||||
* Finding the authenticated record uses klass.primary_key instead of assuming id.
|
||||
* BREAKS BACKWARDS COMPATIBILITY: New I18n solution implemented. See Authlogic::I18n for more information.
|
||||
|
||||
== 1.3.9 released 2009-1-9
|
||||
|
||||
* Added the disable_perishable_token_maintenance option to disable the automatic resetting of the perishable_token, meaning you will have to maintain this yourself.
|
||||
* Changed shoulda macro to conform to standards so model is not required to be passed
|
||||
* Modified method definitions for the Session class to check for already defined methods, allowing you to write your own "credential" methods, and Authlogic will not overwrite your custom methods.
|
||||
* Fixed bug when passing :all to single_access_allowed_request_types
|
||||
* Added logout_on_timeout configuration option for Session::Base
|
||||
|
||||
== 1.3.8 released 2008-12-24
|
||||
|
||||
* Only change persistence token if the password is not blank
|
||||
* Normalize the last_request_at_threshold so that you can pass an integer or a date/time range.
|
||||
* Fixed bug where password length validations were not being run because the password value was not blank. It should be run if it is a new record, the password has changed, or the password is blank.
|
||||
* Added disable_magic_states option for sessions, to turn off the automatic checking of "magic states" such as active?, confirmed?, and approved?.
|
||||
|
||||
== 1.3.7 released 2008-11-30
|
||||
|
||||
* Added session generator: script/generate session UserSession
|
||||
* Added Test::Unit helpers file, see testing in the README
|
||||
|
||||
== 1.3.6 released 2008-11-30
|
||||
|
||||
* Modified validates_length_of for password so that there is a fallback validation if the passed "if statement" fails
|
||||
|
||||
== 1.3.5 released 2008-11-30
|
||||
|
||||
* :transition_from_crypto_provider for acts_as_authentic now accepts an array to transition from multiple providers. Which solves the problem of a double transition.
|
||||
* Added AES256 as a crypto_provider option, for those that want to use a reversible encryption method by supplying a key.
|
||||
* Fixed typo for using validates_format_of_options instead of validates_length_of_options
|
||||
* Fixed bug when accessing the dynamic method for accessing the session record in a namespace, since it uses class_name.underscore which replaces :: with a /
|
||||
* Added minimum length requirement of 4 for the password, and removed validates_presence_of for password since validates_length_of enforces this
|
||||
* Set before_validation to reset the persistence token if it is blank, since a password is not required for open id authentication
|
||||
|
||||
== 1.3.4 released 2008-11-24
|
||||
|
||||
* Delegate human_attribute_name to the ActiveRecord class to take advantage of the I18n feature.
|
||||
* Fixed issue with passwords from older versions of restful_authentication, the passwords end with --
|
||||
|
||||
== 1.3.3 released 2008-11-23
|
||||
|
||||
* Updated :act_like_restful_authentication for those using the older version where no site wide key is preset (REST_AUTH_SITE_KEY), Authlogic will adjust automatically based on the presence of this constant.
|
||||
* Added :transition_from_crypto_provider option for acts_as_authentic to transition your user's passwords to a new algorithm.
|
||||
* Added :transition_from_restful_authentication for acts_as_authentic to transition your users from restful_authentication to the Authlogic password system. Now you can choose to keep your passwords the same by using :act_like_restful_authentication, which will *NOT* do any transitioning, or you can use :transition_from_crypto_provider which will update your users passwords as they login or new accounts are created, while still allowing users with the old password system to log in.
|
||||
* Modified the "interface" for the crypto providers to only provide a class level encrypt and matches? method, instead of a class level encrypt and decrypt method.
|
||||
|
||||
== 1.3.2 released 2008-11-22
|
||||
|
||||
* Updated code to work better with BCrypt, using root level class now.
|
||||
|
||||
== 1.3.1 released 2008-11-22
|
||||
|
||||
* Fixed typo in acts_as_authentic config when passing the :scope option.
|
||||
* Added :act_like_restful_authentication option for acts_as_authentic
|
||||
* Added a new crypto provider: BCrypt, this is for those storing the nuclear launch codes in their apps
|
||||
|
||||
== 1.3.0 released 2008-11-21
|
||||
|
||||
* BREAKS BACKWARDS COMPATIBILITY: changed the confirm_password field to password_confirmation for acts_as_authentic, since the rails validates_confirmation_of handles creating this attribute and there is no option to change the name of this.
|
||||
* BREAKS BACKWARDS COMPATIBILITY: Cleaned up all of the validation configuration for acts_as_authentic, as well as the documentation that goes with it, you can accomplish the same things as before, but this is much more flexible and much more organized. This is mainly for those implementing i18n support. Instead of :whatever_message, its now :login_field_validates_length_of_options => {:message => "your i18n friendly message"}. As a side note, with the new i18n support in rails I would not be surprised if this is already done for you since Authlogic uses the ActiveRecord validation methods.
|
||||
* Got rid of simple delegator for the abstract controller, apparently this has performance issues.
|
||||
* Cleaned up validations to assume ActiveRecord dirty attributes are present, I think this is a safe assumption.
|
||||
|
||||
== 1.2.2 released 2008-11-20
|
||||
|
||||
* Added allow_blank_login_and_password_field and allow_blank_email_field options to acts_as_authentic, which allows you to have alternative logins, such as OpenID
|
||||
* In the session Authlogic now also stores the record id. We use this id to find the record and then check the token against the record, thus allowing for quicker database lookups, while getting the same security.
|
||||
* Skip validation for reset_perishable_token!
|
||||
* Added checks for uniqueness validations to only perform if the values have changed, this cuts down on DB queries
|
||||
* Abstract controller adapter now uses ruby's simple delegator class
|
||||
* Allow to save with a block: user_session.save { |result| }, result will either be false or self, this is useful when implementing OpenID and other methods
|
||||
|
||||
== 1.2.1 released 2008-11-19
|
||||
|
||||
* Added build method to authenticates_many association to act like AR association collections.
|
||||
* Added validation boolean configuration options for acts_as_authentic: validate_field, validate_login_field, validate_password_field, validate_email_field. This turns on and off validations for their respective fields.
|
||||
* Renamed all password_reset_token terms to perishable_token, including configuration, etc. I still allow for the old configurations so this will not break compatibility, but perishable token is a better name and can be used for account confirmation as well as a password reset token, or anything else you want.
|
||||
* Renamed all remember_token instances to persistence_token, the term "remember token" doesn't really make sense. I still allow for the old configuration, so this will not break backwards compatibility: persistence_token fits better and makes more sense.
|
||||
|
||||
== 1.2.0 released 2008-11-16
|
||||
|
||||
* Added check for database set up in acts_as_authentic to prevent errors during migrations.
|
||||
* Forced logged_in and logged_out named scopes to use seconds.
|
||||
* Hardened valid_password? method to only allow raw passwords.
|
||||
* controllers and scopes are no longer stored in class variables but in the Thread.current hash so their instances die out with the thread, which frees up memory.
|
||||
* Removed single_access_token_field and remember_token_field from Sesson::Config, they are not needed there.
|
||||
* Added password_reset_token to assist in resetting passwords.
|
||||
* Added email_field, email_field_regex, email_field_regex_failed_message configuration options to acts_as_authentic. So that you can validate emails as well as a login, instead of the either-or approach.
|
||||
* Added configuration for all validation messages for the session so that you can modify them and provide I18n support.
|
||||
|
||||
== 1.1.1 released 2008-11-13
|
||||
|
||||
* Removed ActiveRecord dependency.
|
||||
* Removed loading shoulda macros by default, moved to shoulda_macros dir.
|
||||
* Modified how params access works. Added in single_access_token_field which params now uses. See the single access section in the README. Various configuration options added as well.
|
||||
* Cleaned up acts_as_authentic configuration, added new config module to do this.
|
||||
* Cleaned up acts_as_authentic tests
|
||||
* Moved acts_as_authentic sub modules into the proper name spaces
|
||||
|
||||
== 1.1.0 released 2008-11-13
|
||||
|
||||
* Moved Rack standards into abstract_adapter for the controllers.
|
||||
* Added authenticating_with_credentials?, authenticating_with_unauthorized_record?
|
||||
* Fixed typo in abstract_adapter, black to block.
|
||||
* Cleaned up / reorganized tests.
|
||||
* Moved ActiveRecord additions to ORM Adapters name space to make way for Data Mapper.
|
||||
* Reorganized and modified acts_as_authentic to be free standing and not get info from the related session.
|
||||
* The session now gets its configuration from the model, since determining which fields are present is ORM specific.
|
||||
* Extracted session and cookie logic into their own modules for Session.
|
||||
* Moved crypto providers into their own module and added a Sha1 provider to help with the restful_authentication transition.
|
||||
* Allow the unique_token method to use the alternate crypto_provider if it is a hash algorithm, otherwise default to Sha512.
|
||||
* Added last_request_at_threshold configuration option.
|
||||
* Changed Scoped class to AuthenticatesManyAssociation, like AR has HasManyAssociation, etc.
|
||||
* Added should_be_authentic shoulda macro.
|
||||
* Removed some magic from how sessions are initialized. See the initialize documentation, this method is a little more structured now, which was required for adding in openid.
|
||||
* Added in logging via a params token, which is friendly for feed URLs. Works just like cookies and sessions when persisting the session.
|
||||
* Added the option to use session.user, instead of session.record. This is based off of what model your session is authenticating with.
|
||||
|
||||
== 1.0.0 released 2008-11-05
|
||||
|
||||
* Checked for blank login counts, if a default wasnt set in the migrations.
|
||||
* Added check for database table in acts_as_authentic to avoid errors in initial setup.
|
||||
* Completely rewrote tests to be more conventional and thorough tests, removed test_app.
|
||||
* Modified how validations work so that a validate method was added as well as callbacks for that method.
|
||||
* Extracted scope support into its own module to help organize code better.
|
||||
* Added in salt for encryption, just like hashes and removed :crypto_provider_type option for acts_as_authentic.
|
||||
* Added merb adapters.
|
||||
* Improved documentation throughout.
|
||||
|
||||
== 0.10.4 released 2008-10-31
|
||||
|
||||
* Changed configuration to use inheritable attributes
|
||||
* Cleaned up requires to be in their proper files
|
||||
* Added in scope support.
|
||||
|
||||
== 0.10.3 released 2008-10-31
|
||||
|
||||
* Instead of raising an error when extra fields are passed in credentials=, just ignore them.
|
||||
* Added remember_me config option to set the default value.
|
||||
* Only call credential methods if an argument was passed.
|
||||
* More unit tests
|
||||
* Hardened automatic session updating. Also automatically log the user in if they change their password when logged out.
|
||||
|
||||
== 0.10.2 released 2008-10-24
|
||||
|
||||
* Added in stretches to the default Sha512 encryption algorithm.
|
||||
* Use column_names instead of columns when determining if a column is present.
|
||||
* Improved validation callbacks. after_validation should only be run if valid? = true. Also clear errors before the "before_validation" callback.
|
||||
|
||||
== 0.10.1 released 2008-10-24
|
||||
|
||||
* Sessions now store the "remember token" instead of the id. This is much safer and guarantees all "sessions" that are logged in are logged in with a valid password. This way stale sessions can't be persisted.
|
||||
* Bumped security to Sha512 from Sha256.
|
||||
* Remove attr_protected call in acts_as_authentic
|
||||
* protected_password should use pasword_field configuration value
|
||||
* changed magic state "inactive" to "active"
|
||||
|
||||
== 0.10.0 released 2008-10-24
|
||||
|
||||
* Do not allow instantiation if the session has not been activated with a controller object. Just like ActiveRecord won't let you do anything without a DB connection.
|
||||
* Abstracted controller implementation to allow for rails, merb, etc adapters. So this is not confined to the rails framework.
|
||||
* Removed create and update methods and added save, like ActiveRecord.
|
||||
* after_validation should be able to change the result if it adds errors on callbacks.
|
||||
* Completed tests.
|
||||
|
||||
== 0.9.1 released 2008-10-24
|
||||
|
||||
* Changed scope to id. Makes more sense to call it an id and fits better with the ActiveRecord model.
|
||||
* Removed saving_from_session flag, apparently it is not needed.
|
||||
* Fixed updating sessions to make more sense and be stricter.
|
||||
* change last_click_at to last_request_at
|
||||
* Only run "after" callbacks if the result is successful.
|
||||
|
||||
== 0.9.0 released 2008-10-24
|
||||
|
||||
* Initial release.
|
20
vendor/plugins/authlogic/LICENSE
vendored
20
vendor/plugins/authlogic/LICENSE
vendored
|
@ -1,20 +0,0 @@
|
|||
Copyright (c) 2009 Ben Johnson of Binary Logic
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
246
vendor/plugins/authlogic/README.rdoc
vendored
246
vendor/plugins/authlogic/README.rdoc
vendored
|
@ -1,246 +0,0 @@
|
|||
= Authlogic
|
||||
|
||||
Authlogic is a clean, simple, and unobtrusive ruby authentication solution.
|
||||
|
||||
A code example can replace a thousand words...
|
||||
|
||||
Authlogic introduces a new type of model. You can have as many as you want, and name them whatever you want, just like your other models. In this example, we want to authenticate with the User model, which is inferred by the name:
|
||||
|
||||
class UserSession < Authlogic::Session::Base
|
||||
# specify configuration here, such as:
|
||||
# logout_on_timeout true
|
||||
# ...many more options in the documentation
|
||||
end
|
||||
|
||||
Log in with any of the following. Create a UserSessionsController and use it just like your other models:
|
||||
|
||||
UserSession.create(:login => "bjohnson", :password => "my password", :remember_me => true)
|
||||
session = UserSession.new(:login => "bjohnson", :password => "my password", :remember_me => true); session.save
|
||||
UserSession.create(:openid_identifier => "identifier", :remember_me => true) # requires the authlogic-oid "add on" gem
|
||||
UserSession.create(my_user_object, true) # skip authentication and log the user in directly, the true means "remember me"
|
||||
|
||||
The above handles the entire authentication process for you. It first authenticates, then it sets up the proper session values and cookies to persist the session. Just like you would if you rolled your own authentication solution.
|
||||
|
||||
You can also log out / destroy the session:
|
||||
|
||||
session.destroy
|
||||
|
||||
After a session has been created, you can persist it across requests. Thus keeping the user logged in:
|
||||
|
||||
session = UserSession.find
|
||||
|
||||
To get all of the nice authentication functionality in your model just do this:
|
||||
|
||||
class User < ActiveRecord::Base
|
||||
acts_as_authentic do |c|
|
||||
c.my_config_option = my_value
|
||||
end # the configuration block is optional
|
||||
end
|
||||
|
||||
This handles validations, etc. It is also "smart" in the sense that it if a login field is present it will use that to authenticate, if not it will look for an email field, etc. This is all configurable, but for 99% of cases that above is all you will need to do.
|
||||
|
||||
Also, sessions are automatically maintained. You can switch this on and off with configuration, but the following will automatically log a user in after a successful registration:
|
||||
|
||||
User.create(params[:user])
|
||||
|
||||
This also updates the session when the user changes his/her password.
|
||||
|
||||
Authlogic is very flexible, it has a strong public API and a plethora of hooks to allow you to modify behavior and extend it. Check out the helpful links below to dig deeper.
|
||||
|
||||
== Helpful links
|
||||
|
||||
* <b>Documentation:</b> http://rdoc.info/projects/binarylogic/authlogic
|
||||
* <b>Repository:</b> http://github.com/binarylogic/authlogic/tree/master
|
||||
* <b>Railscasts Screencast:</b> http://railscasts.com/episodes/160-authlogic
|
||||
* <b>Live example with OpenID "add on":</b> http://authlogicexample.binarylogic.com
|
||||
* <b>Live example repository with tutorial in README:</b> http://github.com/binarylogic/authlogic_example/tree/master
|
||||
* <b>Tutorial: Reset passwords with Authlogic the RESTful way:</b> http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic
|
||||
* <b>Issues:</b> http://github.com/binarylogic/authlogic/issues
|
||||
* <b>Google group:</b> http://groups.google.com/group/authlogic
|
||||
|
||||
<b>Before contacting me directly, please read:</b>
|
||||
|
||||
If you find a bug or a problem please post it in the issues section. If you need help with something, please use google groups. I check both regularly and get emails when anything happens, so that is the best place to get help. This also benefits other people in the future with the same questions / problems. Thank you.
|
||||
|
||||
== Authlogic "add ons"
|
||||
|
||||
* <b>Authlogic OpenID addon:</b> http://github.com/binarylogic/authlogic_openid
|
||||
* <b>Authlogic LDAP addon:</b> http://github.com/binarylogic/authlogic_ldap
|
||||
* <b>Authlogic Facebook Connect:</b> http://github.com/kalasjocke/authlogic_facebook_connect
|
||||
* <b>Authlogic OAuth (Twitter):</b> http://github.com/jrallison/authlogic_oauth
|
||||
* <b>Authlogic PAM:</b> http://github.com/nbudin/authlogic_pam
|
||||
|
||||
If you create one of your own, please let me know about it so I can add it to this list. Or just fork the project, add your link, and send me a pull request.
|
||||
|
||||
== Session bugs (please read if you are having issues with logging in / out)
|
||||
|
||||
Apparently there is a bug with apache / passenger for v2.1.X with sessions not working properly. This is most likely your problem if you are having trouble logging in / out. This is *not* an Authlogic issue. This can be solved by updating passener or using an alternative session store solution, such as active record store.
|
||||
|
||||
== Documentation explanation
|
||||
|
||||
You can find anything you want about Authlogic in the {documentation}[http://rdoc.info/projects/binarylogic/authlogic], all that you need to do is understand the basic design behind it.
|
||||
|
||||
That being said, there are 2 models involved during authentication. Your Authlogic model and your ActiveRecord model:
|
||||
|
||||
1. <b>Authlogic::Session</b>, your session models that extend Authlogic::Session::Base.
|
||||
2. <b>Authlogic::ActsAsAuthentic</b>, which adds in functionality to your ActiveRecord model when you call acts_as_authentic.
|
||||
|
||||
Each of the above has its various sub modules that contain common logic. The sub modules are responsible for including *everything* related to it: configuration, class methods, instance methods, etc.
|
||||
|
||||
For example, if you want to timeout users after a certain period of inactivity, you would look in <b>Authlogic::Session::Timeout</b>. To help you out, I listed the following publicly relevant modules with short descriptions. For the sake of brevity, there are more modules than listed here, the ones not listed are more for internal use, but you can easily read up on them in the {documentation}[http://rdoc.info/projects/binarylogic/authlogic].
|
||||
|
||||
=== Authlogic::ActsAsAuthentic sub modules
|
||||
|
||||
These modules are for the ActiveRecord side of things, the models that call acts_as_authentic.
|
||||
|
||||
* <b>Authlogic::ActsAsAuthentic::Base</b> - Provides the acts_as_authentic class method and includes all of the submodules.
|
||||
* <b>Authlogic::ActsAsAuthentic::Email</b> - Handles everything related to the email field.
|
||||
* <b>Authlogic::ActsAsAuthentic::LoggedInStatus</b> - Provides handy named scopes and methods for determining if the user is logged in or out.
|
||||
* <b>Authlogic::ActsAsAuthentic::Login</b> - Handles everything related to the login field.
|
||||
* <b>Authlogic::ActsAsAuthentic::MagicColumns</b> - Handles everything related to the "magic" fields: login_count, failed_login_count, last_request_at, etc.
|
||||
* <b>Authlogic::ActsAsAuthentic::Password</b> - This one is important. It handles encrypting your password, salting it, etc. It also has support for transitioning password algorithms.
|
||||
* <b>Authlogic::ActsAsAuthentic::PerishableToken</b> - Handles maintaining the perishable token field, also provides a class level method for finding record using the token.
|
||||
* <b>Authlogic::ActsAsAuthentic::PersistenceToken</b> - Handles maintaining the persistence token. This is the token stored in cookies and sessions to persist the users session.
|
||||
* <b>Authlogic::ActsAsAuthentic::RestfulAuthentication</b> - Provides configuration options to easily migrate from the restful_authentication plugin.
|
||||
* <b>Authlogic::ActsAsAuthentic::SessionMaintenance</b> - Handles automatic session maintenance. EX: a new user registers, automatically log them in. Or a user changes their password, update their session.
|
||||
* <b>Authlogic::ActsAsAuthentic::SingleAccessToken</b> - Handles maintaining the single access token.
|
||||
* <b>Authlogic::ActsAsAuthentic::ValidationsScope</b> - Allows you to scope all validations, etc. Just like the :scope option for validates_uniqueness_of
|
||||
|
||||
=== Authlogic::Session sub modules
|
||||
|
||||
These modules are for the models that extend Authlogic::Session::Base.
|
||||
|
||||
* <b>Authlogic::Session::BruteForceProtection</b> - Disables accounts after a certain number of consecutive failed logins attempted.
|
||||
* <b>Authlogic::Session::Callbacks</b> - Your tools to extend, change, or add onto Authlogic. Lets you hook in and do just about anything you want. Start here if you want to write a plugin or add-on for Authlogic
|
||||
* <b>Authlogic::Session::Cookies</b> - Authentication via cookies.
|
||||
* <b>Authlogic::Session::Existence</b> - Creating, saving, and destroying objects.
|
||||
* <b>Authlogic::Session::HttpAuth</b> - Authentication via basic HTTP authentication.
|
||||
* <b>Authlogic::Session::Id</b> - Allows sessions to be separated by an id, letting you have multiple sessions for a single user.
|
||||
* <b>Authlogic::Session::MagicColumns</b> - Maintains "magic" database columns, similar to created_at and updated_at for ActiveRecord.
|
||||
* <b>Authlogic::Session::MagicStates</b> - Automatically validates based on the records states: active?, approved?, and confirmed?. If those methods exist for the record.
|
||||
* <b>Authlogic::Session::Params</b> - Authentication via params, aka single access token.
|
||||
* <b>Authlogic::Session::Password</b> - Authentication via a traditional username and password.
|
||||
* <b>Authlogic::Session::Persistence</b> - Persisting sessions / finding sessions.
|
||||
* <b>Authlogic::Session::Session</b> - Authentication via the session, the controller session that is.
|
||||
* <b>Authlogic::Session::Timeout</b> - Automatically logging out after a certain period of inactivity.
|
||||
* <b>Authlogic::Session::UnauthorizedRecord</b> - Handles authentication by passing an ActiveRecord object directly.
|
||||
* <b>Authlogic::Session::Validation</b> - Validation / errors.
|
||||
|
||||
=== Miscellaneous modules
|
||||
|
||||
Miscellaneous modules that shared across the authentication process and are more "utility" modules and classes.
|
||||
|
||||
* <b>Authlogic::AuthenticatesMany</b> - Responsible for allowing you to scope sessions to a parent record. Similar to a has_many and belongs_to relationship. This lets you do the same thing with sessions.
|
||||
* <b>Authlogic::CryptoProviders</b> - Contains various encryption algorithms that Authlogic uses, allowing you to choose your encryption method.
|
||||
* <b>Authlogic::I18n</b> - Acts JUST LIKE the rails I18n library, and provides internationalization to Authlogic.
|
||||
* <b>Authlogic::Random</b> - A simple class to generate random tokens.
|
||||
* <b>Authlogic::Regex</b> - Contains regular expressions used in Authlogic. Such as those to validate the format of the log or email.
|
||||
* <b>Authlogic::TestCase</b> - Various helper methods for testing frameworks to help you test your code.
|
||||
* <b>Authlogic::Version</b> - A handy class for determine the version of Authlogic in a number of ways.
|
||||
|
||||
== Quick Rails example
|
||||
|
||||
What if creating sessions worked like an ORM library on the surface...
|
||||
|
||||
UserSession.create(params[:user_session])
|
||||
|
||||
What if your user sessions controller could look just like your other controllers...
|
||||
|
||||
class UserSessionsController < ApplicationController
|
||||
def new
|
||||
@user_session = UserSession.new
|
||||
end
|
||||
|
||||
def create
|
||||
@user_session = UserSession.new(params[:user_session])
|
||||
if @user_session.save
|
||||
redirect_to account_url
|
||||
else
|
||||
render :action => :new
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
current_user_session.destroy
|
||||
redirect_to new_user_session_url
|
||||
end
|
||||
end
|
||||
|
||||
As you can see, this fits nicely into the RESTful development pattern. What about the view...
|
||||
|
||||
<% form_for @user_session do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<%= f.label :login %><br />
|
||||
<%= f.text_field :login %><br />
|
||||
<br />
|
||||
<%= f.label :password %><br />
|
||||
<%= f.password_field :password %><br />
|
||||
<br />
|
||||
<%= f.submit "Login" %>
|
||||
<% end %>
|
||||
|
||||
Or how about persisting the session...
|
||||
|
||||
class ApplicationController
|
||||
helper_method :current_user_session, :current_user
|
||||
|
||||
private
|
||||
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
|
||||
end
|
||||
|
||||
== Install & Use
|
||||
|
||||
Install the gem / plugin (recommended)
|
||||
|
||||
From rubyforge:
|
||||
|
||||
$ sudo gem install authlogic
|
||||
|
||||
Or from github:
|
||||
|
||||
$ sudo gem install binarylogic-authlogic
|
||||
|
||||
Now just add the gem dependency in your projects configuration.
|
||||
|
||||
Or you can install this as a plugin:
|
||||
|
||||
script/plugin install git://github.com/binarylogic/authlogic.git
|
||||
|
||||
== Detailed Setup Tutorial
|
||||
|
||||
See the {authlogic example}[http://github.com/binarylogic/authlogic_example/tree/master] for a detailed setup tutorial. I did this because not only do you have a tutorial to go by, but you have an example app that uses the same tutorial, so you can play around with with the code. If you have problems you can compare the code to see what you are doing differently.
|
||||
|
||||
== Testing
|
||||
|
||||
I think one of the best aspects of Authlogic is testing. For one, it cuts out <b>a lot</b> of redundant tests in your applications because Authlogic is already thoroughly tested for you. It doesn't include a bunch of tests into your application, because it comes tested, just like any other library.
|
||||
|
||||
For example, think about ActiveRecord. You don't test the internals of ActiveRecord, because the creators of ActiveRecord have already tested the internals for you. It wouldn't make sense for ActiveRecord to copy it's hundreds of tests into your applications. The same concept applies to Authlogic. You only need to test code you write that is specific to your application, just like everything else in your application.
|
||||
|
||||
That being said, testing your code that uses Authlogic is easy. Since everyone uses different testing suites, I created a helpful module called Authlogic::TestCase, which is basically a set of tools for testing code using Authlogic. I explain testing Authlogic thoroughly in the {Authlogic::TestCase section of the documentation}[http://rdoc.info/rdoc/binarylogic/authlogic/blob/f2f6988d3b97e11770b00b72a7a9733df69ffa5b/Authlogic/TestCase.html]. It should answer any questions you have in regards to testing Authlogic.
|
||||
|
||||
== Tell me quickly how Authlogic works
|
||||
|
||||
Interested in how all of this all works? Think about an ActiveRecord model. A database connection must be established before you can use it. In the case of Authlogic, a controller connection must be established before you can use it. It uses that controller connection to modify cookies, the current session, login with HTTP basic, etc. It connects to the controller through a before filter that is automatically set in your controller which lets Authlogic know about the current controller object. Then Authlogic leverages that to do everything, it's a pretty simple design. Nothing crazy going on, Authlogic is just leveraging the tools your framework provides in the controller object.
|
||||
|
||||
== What sets Authlogic apart and why I created it
|
||||
|
||||
What inspired me to create Authlogic was the messiness of the current authentication solutions. Put simply, they just didn't feel right, because the logic was not organized properly. As you may know, a common misconception with the MVC design pattern is that the model "M" is only for data access logic, which is wrong. A model is a place for domain logic. This is why the RESTful design pattern and the current authentication solutions don't play nice. Authlogic solves this by placing the session maintenance logic into its own domain (aka "model"). Moving session maintenance into its own domain has its benefits:
|
||||
|
||||
1. <b>It's cleaner.</b> There are no generators in Authlogic. Authlogic provides a class that you can use, it's plain and simple ruby. More importantly, the code in your app is code you write, written the way you want, nice and clean. It's code that should be in your app and is specific to your app, not a redundant authentication pattern.
|
||||
2. <b>Easier to stay up-to-date.</b> To make my point, take a look at the commits to any other authentication solution, then look at the {commits for authlogic}[http://github.com/binarylogic/authlogic/commits/master]. How many commits could you easily start using if you already had an app using that solution? With an alternate solution, very few, if any. All of those cool new features and bug fixes are going to have be manually added or wait for your next application. Which is the main reason a generator is not suitable as an authentication solution. With Authlogic you can start using the latest code with a simple update of a gem. No generators, no mess.
|
||||
3. <b>It ties everything together on the domain level.</b> Take a new user registration for example, no reason to manually log the user in, authlogic handles this for you via callbacks. The same applies to a user changing their password. Authlogic handles maintaining the session for you.
|
||||
4. <b>No redundant tests.</b> Because Authlogic doesn't use generators, #1 also applies to tests. Authlogic is *thoroughly* tested for you. You don't go and test the internals of ActiveRecord in each of your apps do you? So why do the same for Authlogic? Your application tests should be for application specific code. Get rid of the noise and make your tests focused and concise, no reason to copy tests from app to app.
|
||||
5. <b>Framework agnostic</b>. Authlogic can be used in *any* ruby framework you want: Rails, Merb, Sinatra, Mack, your own framework, whatever. It's not tied down to Rails. It does this by abstracting itself from these framework's controllers by using a controller adapter. Thanks to {Rack}[http://rack.rubyforge.org/], there is a defined standard for controller structure, and that's what Authlogic's abstract adapter follows. So if your controller follows the rack standards, you don't need to do anything. Any place it deviates from this is solved by a simple adapter for your framework that closes these gaps. For an example, checkout the Authlogic::ControllerAdapters::MerbAdapter.
|
||||
5. <b>You are not restricted to a single session.</b> Think about Apple's me.com, where they need you to authenticate a second time before changing your billing information. Why not just create a second session for this? It works just like your initial session. Then your billing controller can require an "ultra secure" session.
|
||||
6. <b>Easily extendable.</b> One of the distinct advantages of using a library is the ability to use its API, assuming it has one. Authlogic has an *excellent* public API, meaning it can easily be extended and grow beyond the core library. Checkout the "add ons" list above to see what I mean.
|
||||
|
||||
|
||||
Copyright (c) 2009 {Ben Johnson of Binary Logic}[http://www.binarylogic.com], released under the MIT license
|
41
vendor/plugins/authlogic/Rakefile
vendored
41
vendor/plugins/authlogic/Rakefile
vendored
|
@ -1,41 +0,0 @@
|
|||
require 'rubygems'
|
||||
require 'rake'
|
||||
|
||||
begin
|
||||
require 'jeweler'
|
||||
Jeweler::Tasks.new do |gem|
|
||||
gem.name = "authlogic"
|
||||
gem.summary = "A clean, simple, and unobtrusive ruby authentication solution."
|
||||
gem.email = "bjohnson@binarylogic.com"
|
||||
gem.homepage = "http://github.com/binarylogic/authlogic"
|
||||
gem.authors = ["Ben Johnson of Binary Logic"]
|
||||
gem.add_dependency "activesupport"
|
||||
end
|
||||
Jeweler::GemcutterTasks.new
|
||||
rescue LoadError
|
||||
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
||||
end
|
||||
|
||||
require 'rake/testtask'
|
||||
Rake::TestTask.new(:test) do |test|
|
||||
test.libs << 'test'
|
||||
test.pattern = 'test/**/*_test.rb'
|
||||
test.verbose = true
|
||||
end
|
||||
|
||||
begin
|
||||
require 'rcov/rcovtask'
|
||||
Rcov::RcovTask.new do |test|
|
||||
test.libs << 'test'
|
||||
test.pattern = 'test/**/*_test.rb'
|
||||
test.verbose = true
|
||||
end
|
||||
rescue LoadError
|
||||
task :rcov do
|
||||
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
||||
end
|
||||
end
|
||||
|
||||
task :test => :check_dependencies
|
||||
|
||||
task :default => :test
|
5
vendor/plugins/authlogic/VERSION.yml
vendored
5
vendor/plugins/authlogic/VERSION.yml
vendored
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
:major: 2
|
||||
:minor: 1
|
||||
:patch: 6
|
||||
:build:
|
216
vendor/plugins/authlogic/authlogic.gemspec
vendored
216
vendor/plugins/authlogic/authlogic.gemspec
vendored
|
@ -1,216 +0,0 @@
|
|||
# Generated by jeweler
|
||||
# DO NOT EDIT THIS FILE DIRECTLY
|
||||
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = %q{authlogic}
|
||||
s.version = "2.1.6"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.authors = ["Ben Johnson of Binary Logic"]
|
||||
s.date = %q{2010-08-04}
|
||||
s.email = %q{bjohnson@binarylogic.com}
|
||||
s.extra_rdoc_files = [
|
||||
"LICENSE",
|
||||
"README.rdoc"
|
||||
]
|
||||
s.files = [
|
||||
".gitignore",
|
||||
"CHANGELOG.rdoc",
|
||||
"LICENSE",
|
||||
"README.rdoc",
|
||||
"Rakefile",
|
||||
"VERSION.yml",
|
||||
"authlogic.gemspec",
|
||||
"generators/session/session_generator.rb",
|
||||
"generators/session/templates/session.rb",
|
||||
"init.rb",
|
||||
"lib/authlogic.rb",
|
||||
"lib/authlogic/acts_as_authentic/base.rb",
|
||||
"lib/authlogic/acts_as_authentic/email.rb",
|
||||
"lib/authlogic/acts_as_authentic/logged_in_status.rb",
|
||||
"lib/authlogic/acts_as_authentic/login.rb",
|
||||
"lib/authlogic/acts_as_authentic/magic_columns.rb",
|
||||
"lib/authlogic/acts_as_authentic/password.rb",
|
||||
"lib/authlogic/acts_as_authentic/perishable_token.rb",
|
||||
"lib/authlogic/acts_as_authentic/persistence_token.rb",
|
||||
"lib/authlogic/acts_as_authentic/restful_authentication.rb",
|
||||
"lib/authlogic/acts_as_authentic/session_maintenance.rb",
|
||||
"lib/authlogic/acts_as_authentic/single_access_token.rb",
|
||||
"lib/authlogic/acts_as_authentic/validations_scope.rb",
|
||||
"lib/authlogic/authenticates_many/association.rb",
|
||||
"lib/authlogic/authenticates_many/base.rb",
|
||||
"lib/authlogic/controller_adapters/abstract_adapter.rb",
|
||||
"lib/authlogic/controller_adapters/merb_adapter.rb",
|
||||
"lib/authlogic/controller_adapters/rails_adapter.rb",
|
||||
"lib/authlogic/controller_adapters/sinatra_adapter.rb",
|
||||
"lib/authlogic/crypto_providers/aes256.rb",
|
||||
"lib/authlogic/crypto_providers/bcrypt.rb",
|
||||
"lib/authlogic/crypto_providers/md5.rb",
|
||||
"lib/authlogic/crypto_providers/sha1.rb",
|
||||
"lib/authlogic/crypto_providers/sha256.rb",
|
||||
"lib/authlogic/crypto_providers/sha512.rb",
|
||||
"lib/authlogic/crypto_providers/wordpress.rb",
|
||||
"lib/authlogic/i18n.rb",
|
||||
"lib/authlogic/i18n/translator.rb",
|
||||
"lib/authlogic/random.rb",
|
||||
"lib/authlogic/regex.rb",
|
||||
"lib/authlogic/session/activation.rb",
|
||||
"lib/authlogic/session/active_record_trickery.rb",
|
||||
"lib/authlogic/session/base.rb",
|
||||
"lib/authlogic/session/brute_force_protection.rb",
|
||||
"lib/authlogic/session/callbacks.rb",
|
||||
"lib/authlogic/session/cookies.rb",
|
||||
"lib/authlogic/session/existence.rb",
|
||||
"lib/authlogic/session/foundation.rb",
|
||||
"lib/authlogic/session/http_auth.rb",
|
||||
"lib/authlogic/session/id.rb",
|
||||
"lib/authlogic/session/klass.rb",
|
||||
"lib/authlogic/session/magic_columns.rb",
|
||||
"lib/authlogic/session/magic_states.rb",
|
||||
"lib/authlogic/session/params.rb",
|
||||
"lib/authlogic/session/password.rb",
|
||||
"lib/authlogic/session/perishable_token.rb",
|
||||
"lib/authlogic/session/persistence.rb",
|
||||
"lib/authlogic/session/priority_record.rb",
|
||||
"lib/authlogic/session/scopes.rb",
|
||||
"lib/authlogic/session/session.rb",
|
||||
"lib/authlogic/session/timeout.rb",
|
||||
"lib/authlogic/session/unauthorized_record.rb",
|
||||
"lib/authlogic/session/validation.rb",
|
||||
"lib/authlogic/test_case.rb",
|
||||
"lib/authlogic/test_case/mock_controller.rb",
|
||||
"lib/authlogic/test_case/mock_cookie_jar.rb",
|
||||
"lib/authlogic/test_case/mock_logger.rb",
|
||||
"lib/authlogic/test_case/mock_request.rb",
|
||||
"lib/authlogic/test_case/rails_request_adapter.rb",
|
||||
"rails/init.rb",
|
||||
"shoulda_macros/authlogic.rb",
|
||||
"test/acts_as_authentic_test/base_test.rb",
|
||||
"test/acts_as_authentic_test/email_test.rb",
|
||||
"test/acts_as_authentic_test/logged_in_status_test.rb",
|
||||
"test/acts_as_authentic_test/login_test.rb",
|
||||
"test/acts_as_authentic_test/magic_columns_test.rb",
|
||||
"test/acts_as_authentic_test/password_test.rb",
|
||||
"test/acts_as_authentic_test/perishable_token_test.rb",
|
||||
"test/acts_as_authentic_test/persistence_token_test.rb",
|
||||
"test/acts_as_authentic_test/restful_authentication_test.rb",
|
||||
"test/acts_as_authentic_test/session_maintenance_test.rb",
|
||||
"test/acts_as_authentic_test/single_access_test.rb",
|
||||
"test/authenticates_many_test.rb",
|
||||
"test/crypto_provider_test/aes256_test.rb",
|
||||
"test/crypto_provider_test/bcrypt_test.rb",
|
||||
"test/crypto_provider_test/sha1_test.rb",
|
||||
"test/crypto_provider_test/sha256_test.rb",
|
||||
"test/crypto_provider_test/sha512_test.rb",
|
||||
"test/fixtures/companies.yml",
|
||||
"test/fixtures/employees.yml",
|
||||
"test/fixtures/projects.yml",
|
||||
"test/fixtures/users.yml",
|
||||
"test/i18n_test.rb",
|
||||
"test/libs/affiliate.rb",
|
||||
"test/libs/company.rb",
|
||||
"test/libs/employee.rb",
|
||||
"test/libs/employee_session.rb",
|
||||
"test/libs/ldaper.rb",
|
||||
"test/libs/ordered_hash.rb",
|
||||
"test/libs/project.rb",
|
||||
"test/libs/user.rb",
|
||||
"test/libs/user_session.rb",
|
||||
"test/random_test.rb",
|
||||
"test/session_test/activation_test.rb",
|
||||
"test/session_test/active_record_trickery_test.rb",
|
||||
"test/session_test/brute_force_protection_test.rb",
|
||||
"test/session_test/callbacks_test.rb",
|
||||
"test/session_test/cookies_test.rb",
|
||||
"test/session_test/credentials_test.rb",
|
||||
"test/session_test/existence_test.rb",
|
||||
"test/session_test/http_auth_test.rb",
|
||||
"test/session_test/id_test.rb",
|
||||
"test/session_test/klass_test.rb",
|
||||
"test/session_test/magic_columns_test.rb",
|
||||
"test/session_test/magic_states_test.rb",
|
||||
"test/session_test/params_test.rb",
|
||||
"test/session_test/password_test.rb",
|
||||
"test/session_test/perishability_test.rb",
|
||||
"test/session_test/persistence_test.rb",
|
||||
"test/session_test/scopes_test.rb",
|
||||
"test/session_test/session_test.rb",
|
||||
"test/session_test/timeout_test.rb",
|
||||
"test/session_test/unauthorized_record_test.rb",
|
||||
"test/session_test/validation_test.rb",
|
||||
"test/test_helper.rb"
|
||||
]
|
||||
s.homepage = %q{http://github.com/binarylogic/authlogic}
|
||||
s.rdoc_options = ["--charset=UTF-8"]
|
||||
s.require_paths = ["lib"]
|
||||
s.rubygems_version = %q{1.3.7}
|
||||
s.summary = %q{A clean, simple, and unobtrusive ruby authentication solution.}
|
||||
s.test_files = [
|
||||
"test/acts_as_authentic_test/base_test.rb",
|
||||
"test/acts_as_authentic_test/email_test.rb",
|
||||
"test/acts_as_authentic_test/logged_in_status_test.rb",
|
||||
"test/acts_as_authentic_test/login_test.rb",
|
||||
"test/acts_as_authentic_test/magic_columns_test.rb",
|
||||
"test/acts_as_authentic_test/password_test.rb",
|
||||
"test/acts_as_authentic_test/perishable_token_test.rb",
|
||||
"test/acts_as_authentic_test/persistence_token_test.rb",
|
||||
"test/acts_as_authentic_test/restful_authentication_test.rb",
|
||||
"test/acts_as_authentic_test/session_maintenance_test.rb",
|
||||
"test/acts_as_authentic_test/single_access_test.rb",
|
||||
"test/authenticates_many_test.rb",
|
||||
"test/crypto_provider_test/aes256_test.rb",
|
||||
"test/crypto_provider_test/bcrypt_test.rb",
|
||||
"test/crypto_provider_test/sha1_test.rb",
|
||||
"test/crypto_provider_test/sha256_test.rb",
|
||||
"test/crypto_provider_test/sha512_test.rb",
|
||||
"test/i18n_test.rb",
|
||||
"test/libs/affiliate.rb",
|
||||
"test/libs/company.rb",
|
||||
"test/libs/employee.rb",
|
||||
"test/libs/employee_session.rb",
|
||||
"test/libs/ldaper.rb",
|
||||
"test/libs/ordered_hash.rb",
|
||||
"test/libs/project.rb",
|
||||
"test/libs/user.rb",
|
||||
"test/libs/user_session.rb",
|
||||
"test/random_test.rb",
|
||||
"test/session_test/activation_test.rb",
|
||||
"test/session_test/active_record_trickery_test.rb",
|
||||
"test/session_test/brute_force_protection_test.rb",
|
||||
"test/session_test/callbacks_test.rb",
|
||||
"test/session_test/cookies_test.rb",
|
||||
"test/session_test/credentials_test.rb",
|
||||
"test/session_test/existence_test.rb",
|
||||
"test/session_test/http_auth_test.rb",
|
||||
"test/session_test/id_test.rb",
|
||||
"test/session_test/klass_test.rb",
|
||||
"test/session_test/magic_columns_test.rb",
|
||||
"test/session_test/magic_states_test.rb",
|
||||
"test/session_test/params_test.rb",
|
||||
"test/session_test/password_test.rb",
|
||||
"test/session_test/perishability_test.rb",
|
||||
"test/session_test/persistence_test.rb",
|
||||
"test/session_test/scopes_test.rb",
|
||||
"test/session_test/session_test.rb",
|
||||
"test/session_test/timeout_test.rb",
|
||||
"test/session_test/unauthorized_record_test.rb",
|
||||
"test/session_test/validation_test.rb",
|
||||
"test/test_helper.rb"
|
||||
]
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
||||
s.specification_version = 3
|
||||
|
||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
||||
else
|
||||
s.add_dependency(%q<activesupport>, [">= 0"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<activesupport>, [">= 0"])
|
||||
end
|
||||
end
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
class SessionGenerator < Rails::Generator::NamedBase
|
||||
def manifest
|
||||
record do |m|
|
||||
m.class_collisions class_name
|
||||
m.directory File.join('app/models', class_path)
|
||||
m.template 'session.rb', File.join('app/models', class_path, "#{file_name}.rb")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
class <%= class_name %> < Authlogic::Session::Base
|
||||
end
|
1
vendor/plugins/authlogic/init.rb
vendored
1
vendor/plugins/authlogic/init.rb
vendored
|
@ -1 +0,0 @@
|
|||
require "authlogic"
|
64
vendor/plugins/authlogic/lib/authlogic.rb
vendored
64
vendor/plugins/authlogic/lib/authlogic.rb
vendored
|
@ -1,64 +0,0 @@
|
|||
require "active_record"
|
||||
|
||||
AUTHLOGIC_PATH = File.dirname(__FILE__) + "/authlogic/"
|
||||
|
||||
[
|
||||
"i18n",
|
||||
"random",
|
||||
"regex",
|
||||
|
||||
"controller_adapters/abstract_adapter",
|
||||
|
||||
"crypto_providers/md5",
|
||||
"crypto_providers/sha1",
|
||||
"crypto_providers/sha256",
|
||||
"crypto_providers/sha512",
|
||||
"crypto_providers/bcrypt",
|
||||
"crypto_providers/aes256",
|
||||
|
||||
"authenticates_many/base",
|
||||
"authenticates_many/association",
|
||||
|
||||
"acts_as_authentic/email",
|
||||
"acts_as_authentic/logged_in_status",
|
||||
"acts_as_authentic/login",
|
||||
"acts_as_authentic/magic_columns",
|
||||
"acts_as_authentic/password",
|
||||
"acts_as_authentic/perishable_token",
|
||||
"acts_as_authentic/persistence_token",
|
||||
"acts_as_authentic/restful_authentication",
|
||||
"acts_as_authentic/session_maintenance",
|
||||
"acts_as_authentic/single_access_token",
|
||||
"acts_as_authentic/validations_scope",
|
||||
"acts_as_authentic/base",
|
||||
|
||||
"session/activation",
|
||||
"session/active_record_trickery",
|
||||
"session/brute_force_protection",
|
||||
"session/callbacks",
|
||||
"session/cookies",
|
||||
"session/existence",
|
||||
"session/foundation",
|
||||
"session/http_auth",
|
||||
"session/id",
|
||||
"session/klass",
|
||||
"session/magic_columns",
|
||||
"session/magic_states",
|
||||
"session/params",
|
||||
"session/password",
|
||||
"session/perishable_token",
|
||||
"session/persistence",
|
||||
"session/priority_record",
|
||||
"session/scopes",
|
||||
"session/session",
|
||||
"session/timeout",
|
||||
"session/unauthorized_record",
|
||||
"session/validation",
|
||||
"session/base"
|
||||
].each do |library|
|
||||
require AUTHLOGIC_PATH + library
|
||||
end
|
||||
|
||||
require AUTHLOGIC_PATH + "controller_adapters/rails_adapter" if defined?( Rails )
|
||||
require AUTHLOGIC_PATH + "controller_adapters/merb_adapter" if defined?( Merb )
|
||||
require AUTHLOGIC_PATH + "controller_adapters/sinatra_adapter" if defined?( Sinatra )
|
|
@ -1,107 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# Provides the base functionality for acts_as_authentic
|
||||
module Base
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
end
|
||||
end
|
||||
|
||||
module Config
|
||||
# This includes a lot of helpful methods for authenticating records which The Authlogic::Session module relies on.
|
||||
# To use it just do:
|
||||
#
|
||||
# class User < ActiveRecord::Base
|
||||
# acts_as_authentic
|
||||
# end
|
||||
#
|
||||
# Configuration is easy:
|
||||
#
|
||||
# acts_as_authentic do |c|
|
||||
# c.my_configuration_option = my_value
|
||||
# end
|
||||
#
|
||||
# See the various sub modules for the configuration they provide.
|
||||
def acts_as_authentic(unsupported_options = nil, &block)
|
||||
# Stop all configuration if the DB is not set up
|
||||
return if !db_setup?
|
||||
|
||||
raise ArgumentError.new("You are using the old v1.X.X configuration method for Authlogic. Instead of " +
|
||||
"passing a hash of configuration options to acts_as_authentic, pass a block: acts_as_authentic { |c| c.my_option = my_value }") if !unsupported_options.nil?
|
||||
|
||||
yield self if block_given?
|
||||
acts_as_authentic_modules.each { |mod| include mod }
|
||||
end
|
||||
|
||||
# Since this part of Authlogic deals with another class, ActiveRecord, we can't just start including things
|
||||
# in ActiveRecord itself. A lot of these module includes need to be triggered by the acts_as_authentic method
|
||||
# call. For example, you don't want to start adding in email validations and what not into a model that has
|
||||
# nothing to do with Authlogic.
|
||||
#
|
||||
# That being said, this is your tool for extending Authlogic and "hooking" into the acts_as_authentic call.
|
||||
def add_acts_as_authentic_module(mod, action = :append)
|
||||
modules = acts_as_authentic_modules
|
||||
case action
|
||||
when :append
|
||||
modules << mod
|
||||
when :prepend
|
||||
modules = [mod] + modules
|
||||
end
|
||||
modules.uniq!
|
||||
write_inheritable_attribute(:acts_as_authentic_modules, modules)
|
||||
end
|
||||
|
||||
# This is the same as add_acts_as_authentic_module, except that it removes the module from the list.
|
||||
def remove_acts_as_authentic_module(mod)
|
||||
acts_as_authentic_modules.delete(mod)
|
||||
acts_as_authentic_modules
|
||||
end
|
||||
|
||||
private
|
||||
def acts_as_authentic_modules
|
||||
key = :acts_as_authentic_modules
|
||||
inheritable_attributes.include?(key) ? read_inheritable_attribute(key) : []
|
||||
end
|
||||
|
||||
def db_setup?
|
||||
begin
|
||||
column_names
|
||||
true
|
||||
rescue Exception
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def rw_config(key, value, default_value = nil, read_value = nil)
|
||||
if value == read_value
|
||||
inheritable_attributes.include?(key) ? read_inheritable_attribute(key) : default_value
|
||||
else
|
||||
write_inheritable_attribute(key, value)
|
||||
end
|
||||
end
|
||||
|
||||
def first_column_to_exist(*columns_to_check)
|
||||
if db_setup?
|
||||
columns_to_check.each { |column_name| return column_name.to_sym if column_names.include?(column_name.to_s) }
|
||||
end
|
||||
columns_to_check.first && columns_to_check.first.to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Base
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Email
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::LoggedInStatus
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Login
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::MagicColumns
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Password
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::PerishableToken
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::PersistenceToken
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::RestfulAuthentication
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::SessionMaintenance
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::SingleAccessToken
|
||||
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::ValidationsScope
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# Sometimes models won't have an explicit "login" or "username" field. Instead they want to use the email field.
|
||||
# In this case, authlogic provides validations to make sure the email submited is actually a valid email. Don't worry,
|
||||
# if you do have a login or username field, Authlogic will still validate your email field. One less thing you have to
|
||||
# worry about.
|
||||
module Email
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
add_acts_as_authentic_module(Methods)
|
||||
end
|
||||
end
|
||||
|
||||
# Configuration to modify how Authlogic handles the email field.
|
||||
module Config
|
||||
# The name of the field that stores email addresses.
|
||||
#
|
||||
# * <tt>Default:</tt> :email, if it exists
|
||||
# * <tt>Accepts:</tt> Symbol
|
||||
def email_field(value = nil)
|
||||
rw_config(:email_field, value, first_column_to_exist(nil, :email, :email_address))
|
||||
end
|
||||
alias_method :email_field=, :email_field
|
||||
|
||||
# Toggles validating the email field or not.
|
||||
#
|
||||
# * <tt>Default:</tt> true
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def validate_email_field(value = nil)
|
||||
rw_config(:validate_email_field, value, true)
|
||||
end
|
||||
alias_method :validate_email_field=, :validate_email_field
|
||||
|
||||
# A hash of options for the validates_length_of call for the email field. Allows you to change this however you want.
|
||||
#
|
||||
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
||||
# merge options into it. Checkout the convenience function merge_validates_length_of_email_field_options to merge
|
||||
# options.</b>
|
||||
#
|
||||
# * <tt>Default:</tt> {:within => 6..100}
|
||||
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
||||
def validates_length_of_email_field_options(value = nil)
|
||||
rw_config(:validates_length_of_email_field_options, value, {:within => 6..100})
|
||||
end
|
||||
alias_method :validates_length_of_email_field_options=, :validates_length_of_email_field_options
|
||||
|
||||
# A convenience function to merge options into the validates_length_of_email_field_options. So intead of:
|
||||
#
|
||||
# self.validates_length_of_email_field_options = validates_length_of_email_field_options.merge(:my_option => my_value)
|
||||
#
|
||||
# You can do this:
|
||||
#
|
||||
# merge_validates_length_of_email_field_options :my_option => my_value
|
||||
def merge_validates_length_of_email_field_options(options = {})
|
||||
self.validates_length_of_email_field_options = validates_length_of_email_field_options.merge(options)
|
||||
end
|
||||
|
||||
# A hash of options for the validates_format_of call for the email field. Allows you to change this however you want.
|
||||
#
|
||||
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
||||
# merge options into it. Checkout the convenience function merge_validates_format_of_email_field_options to merge
|
||||
# options.</b>
|
||||
#
|
||||
# * <tt>Default:</tt> {:with => Authlogic::Regex.email, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}
|
||||
# * <tt>Accepts:</tt> Hash of options accepted by validates_format_of
|
||||
def validates_format_of_email_field_options(value = nil)
|
||||
rw_config(:validates_format_of_email_field_options, value, {:with => Authlogic::Regex.email, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")})
|
||||
end
|
||||
alias_method :validates_format_of_email_field_options=, :validates_format_of_email_field_options
|
||||
|
||||
# See merge_validates_length_of_email_field_options. The same thing except for validates_format_of_email_field_options.
|
||||
def merge_validates_format_of_email_field_options(options = {})
|
||||
self.validates_format_of_email_field_options = validates_format_of_email_field_options.merge(options)
|
||||
end
|
||||
|
||||
# A hash of options for the validates_uniqueness_of call for the email field. Allows you to change this however you want.
|
||||
#
|
||||
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
||||
# merge options into it. Checkout the convenience function merge_validates_uniqueness_of_email_field_options to merge
|
||||
# options.</b>
|
||||
#
|
||||
# * <tt>Default:</tt> {:case_sensitive => false, :scope => validations_scope, :if => "#{email_field}_changed?".to_sym}
|
||||
# * <tt>Accepts:</tt> Hash of options accepted by validates_uniqueness_of
|
||||
def validates_uniqueness_of_email_field_options(value = nil)
|
||||
rw_config(:validates_uniqueness_of_email_field_options, value, {:case_sensitive => false, :scope => validations_scope, :if => "#{email_field}_changed?".to_sym})
|
||||
end
|
||||
alias_method :validates_uniqueness_of_email_field_options=, :validates_uniqueness_of_email_field_options
|
||||
|
||||
# See merge_validates_length_of_email_field_options. The same thing except for validates_uniqueness_of_email_field_options.
|
||||
def merge_validates_uniqueness_of_email_field_options(options = {})
|
||||
self.validates_uniqueness_of_email_field_options = validates_uniqueness_of_email_field_options.merge(options)
|
||||
end
|
||||
end
|
||||
|
||||
# All methods relating to the email field
|
||||
module Methods
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
if validate_email_field && email_field
|
||||
validates_length_of email_field, validates_length_of_email_field_options
|
||||
validates_format_of email_field, validates_format_of_email_field_options
|
||||
validates_uniqueness_of email_field, validates_uniqueness_of_email_field_options
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,60 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# Since web applications are stateless there is not sure fire way to tell if a user is logged in or not,
|
||||
# from the database perspective. The best way to do this is to provide a "timeout" based on inactivity.
|
||||
# So if that user is inactive for a certain amount of time we assume they are logged out. That's what this
|
||||
# module is all about.
|
||||
module LoggedInStatus
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
add_acts_as_authentic_module(Methods)
|
||||
end
|
||||
end
|
||||
|
||||
# All configuration for the logged in status feature set.
|
||||
module Config
|
||||
# The timeout to determine when a user is logged in or not.
|
||||
#
|
||||
# * <tt>Default:</tt> 10.minutes
|
||||
# * <tt>Accepts:</tt> Fixnum
|
||||
def logged_in_timeout(value = nil)
|
||||
rw_config(:logged_in_timeout, (!value.nil? && value.to_i) || value, 10.minutes.to_i)
|
||||
end
|
||||
alias_method :logged_in_timeout=, :logged_in_timeout
|
||||
end
|
||||
|
||||
# All methods for the logged in status feature seat.
|
||||
module Methods
|
||||
def self.included(klass)
|
||||
return if !klass.column_names.include?("last_request_at")
|
||||
|
||||
klass.class_eval do
|
||||
include InstanceMethods
|
||||
|
||||
scope :logged_in, lambda { {:conditions => ["last_request_at > ?", logged_in_timeout.seconds.ago]} }
|
||||
scope :logged_out, lambda { {:conditions => ["last_request_at is NULL or last_request_at <= ?", logged_in_timeout.seconds.ago]} }
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
# Returns true if the last_request_at > logged_in_timeout.
|
||||
def logged_in?
|
||||
raise "Can not determine the records login state because there is no last_request_at column" if !respond_to?(:last_request_at)
|
||||
!last_request_at.nil? && last_request_at > logged_in_timeout.seconds.ago
|
||||
end
|
||||
|
||||
# Opposite of logged_in?
|
||||
def logged_out?
|
||||
!logged_in?
|
||||
end
|
||||
|
||||
private
|
||||
def logged_in_timeout
|
||||
self.class.logged_in_timeout
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,141 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# Handles everything related to the login field.
|
||||
module Login
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
add_acts_as_authentic_module(Methods)
|
||||
end
|
||||
end
|
||||
|
||||
# Confguration for the login field.
|
||||
module Config
|
||||
# The name of the login field in the database.
|
||||
#
|
||||
# * <tt>Default:</tt> :login or :username, if they exist
|
||||
# * <tt>Accepts:</tt> Symbol
|
||||
def login_field(value = nil)
|
||||
rw_config(:login_field, value, first_column_to_exist(nil, :login, :username))
|
||||
end
|
||||
alias_method :login_field=, :login_field
|
||||
|
||||
# Whether or not the validate the login field
|
||||
#
|
||||
# * <tt>Default:</tt> true
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def validate_login_field(value = nil)
|
||||
rw_config(:validate_login_field, value, true)
|
||||
end
|
||||
alias_method :validate_login_field=, :validate_login_field
|
||||
|
||||
# A hash of options for the validates_length_of call for the login field. Allows you to change this however you want.
|
||||
#
|
||||
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
||||
# merge options into it. Checkout the convenience function merge_validates_length_of_login_field_options to merge
|
||||
# options.</b>
|
||||
#
|
||||
# * <tt>Default:</tt> {:within => 3..100}
|
||||
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
||||
def validates_length_of_login_field_options(value = nil)
|
||||
rw_config(:validates_length_of_login_field_options, value, {:within => 3..100})
|
||||
end
|
||||
alias_method :validates_length_of_login_field_options=, :validates_length_of_login_field_options
|
||||
|
||||
# A convenience function to merge options into the validates_length_of_login_field_options. So intead of:
|
||||
#
|
||||
# self.validates_length_of_login_field_options = validates_length_of_login_field_options.merge(:my_option => my_value)
|
||||
#
|
||||
# You can do this:
|
||||
#
|
||||
# merge_validates_length_of_login_field_options :my_option => my_value
|
||||
def merge_validates_length_of_login_field_options(options = {})
|
||||
self.validates_length_of_login_field_options = validates_length_of_login_field_options.merge(options)
|
||||
end
|
||||
|
||||
# A hash of options for the validates_format_of call for the login field. Allows you to change this however you want.
|
||||
#
|
||||
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
||||
# merge options into it. Checkout the convenience function merge_validates_format_of_login_field_options to merge
|
||||
# options.</b>
|
||||
#
|
||||
# * <tt>Default:</tt> {:with => Authlogic::Regex.login, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}
|
||||
# * <tt>Accepts:</tt> Hash of options accepted by validates_format_of
|
||||
def validates_format_of_login_field_options(value = nil)
|
||||
rw_config(:validates_format_of_login_field_options, value, {:with => Authlogic::Regex.login, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")})
|
||||
end
|
||||
alias_method :validates_format_of_login_field_options=, :validates_format_of_login_field_options
|
||||
|
||||
# See merge_validates_length_of_login_field_options. The same thing, except for validates_format_of_login_field_options
|
||||
def merge_validates_format_of_login_field_options(options = {})
|
||||
self.validates_format_of_login_field_options = validates_format_of_login_field_options.merge(options)
|
||||
end
|
||||
|
||||
# A hash of options for the validates_uniqueness_of call for the login field. Allows you to change this however you want.
|
||||
#
|
||||
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
||||
# merge options into it. Checkout the convenience function merge_validates_format_of_login_field_options to merge
|
||||
# options.</b>
|
||||
#
|
||||
# * <tt>Default:</tt> {:case_sensitive => false, :scope => validations_scope, :if => "#{login_field}_changed?".to_sym}
|
||||
# * <tt>Accepts:</tt> Hash of options accepted by validates_uniqueness_of
|
||||
def validates_uniqueness_of_login_field_options(value = nil)
|
||||
rw_config(:validates_uniqueness_of_login_field_options, value, {:case_sensitive => false, :scope => validations_scope, :if => "#{login_field}_changed?".to_sym})
|
||||
end
|
||||
alias_method :validates_uniqueness_of_login_field_options=, :validates_uniqueness_of_login_field_options
|
||||
|
||||
# See merge_validates_length_of_login_field_options. The same thing, except for validates_uniqueness_of_login_field_options
|
||||
def merge_validates_uniqueness_of_login_field_options(options = {})
|
||||
self.validates_uniqueness_of_login_field_options = validates_uniqueness_of_login_field_options.merge(options)
|
||||
end
|
||||
|
||||
# This method allows you to find a record with the given login. If you notice, with ActiveRecord you have the
|
||||
# validates_uniqueness_of validation function. They give you a :case_sensitive option. I handle this in the same
|
||||
# manner that they handle that. If you are using the login field and set false for the :case_sensitive option in
|
||||
# validates_uniqueness_of_login_field_options this method will modify the query to look something like:
|
||||
#
|
||||
# first(:conditions => ["LOWER(#{quoted_table_name}.#{login_field}) = ?", login.downcase])
|
||||
#
|
||||
# If you don't specify this it calls the good old find_by_* method:
|
||||
#
|
||||
# find_by_login(login)
|
||||
#
|
||||
# The above also applies for using email as your login, except that you need to set the :case_sensitive in
|
||||
# validates_uniqueness_of_email_field_options to false.
|
||||
#
|
||||
# The only reason I need to do the above is for Postgres and SQLite since they perform case sensitive searches with the
|
||||
# find_by_* methods.
|
||||
def find_by_smart_case_login_field(login)
|
||||
if login_field
|
||||
find_with_case(login_field, login, validates_uniqueness_of_login_field_options[:case_sensitive] != false)
|
||||
else
|
||||
find_with_case(email_field, login, validates_uniqueness_of_email_field_options[:case_sensitive] != false)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_with_case(field, value, sensitivity = true)
|
||||
if sensitivity
|
||||
send("find_by_#{field}", value)
|
||||
else
|
||||
first(:conditions => ["LOWER(#{quoted_table_name}.#{field}) = ?", value.mb_chars.downcase])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# All methods relating to the login field
|
||||
module Methods
|
||||
# Adds in various validations, modules, etc.
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
if validate_login_field && login_field
|
||||
validates_length_of login_field, validates_length_of_login_field_options
|
||||
validates_format_of login_field, validates_format_of_login_field_options
|
||||
validates_uniqueness_of login_field, validates_uniqueness_of_login_field_options
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# Magic columns are like ActiveRecord's created_at and updated_at columns. They are "magically" maintained for
|
||||
# you. Authlogic has the same thing, but these are maintained on the session side. Please see Authlogic::Session::MagicColumns
|
||||
# for more details. This module merely adds validations for the magic columns if they exist.
|
||||
module MagicColumns
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
add_acts_as_authentic_module(Methods)
|
||||
end
|
||||
end
|
||||
|
||||
# Methods relating to the magic columns
|
||||
module Methods
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
validates_numericality_of :login_count, :only_integer => :true, :greater_than_or_equal_to => 0, :allow_nil => true if column_names.include?("login_count")
|
||||
validates_numericality_of :failed_login_count, :only_integer => :true, :greater_than_or_equal_to => 0, :allow_nil => true if column_names.include?("failed_login_count")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,355 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# This module has a lot of neat functionality. It is responsible for encrypting your password, salting it, and verifying it.
|
||||
# It can also help you transition to a new encryption algorithm. See the Config sub module for configuration options.
|
||||
module Password
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
add_acts_as_authentic_module(Callbacks)
|
||||
add_acts_as_authentic_module(Methods)
|
||||
end
|
||||
end
|
||||
|
||||
# All configuration for the password aspect of acts_as_authentic.
|
||||
module Config
|
||||
# The name of the crypted_password field in the database.
|
||||
#
|
||||
# * <tt>Default:</tt> :crypted_password, :encrypted_password, :password_hash, or :pw_hash
|
||||
# * <tt>Accepts:</tt> Symbol
|
||||
def crypted_password_field(value = nil)
|
||||
rw_config(:crypted_password_field, value, first_column_to_exist(nil, :crypted_password, :encrypted_password, :password_hash, :pw_hash))
|
||||
end
|
||||
alias_method :crypted_password_field=, :crypted_password_field
|
||||
|
||||
# The name of the password_salt field in the database.
|
||||
#
|
||||
# * <tt>Default:</tt> :password_salt, :pw_salt, :salt, nil if none exist
|
||||
# * <tt>Accepts:</tt> Symbol
|
||||
def password_salt_field(value = nil)
|
||||
rw_config(:password_salt_field, value, first_column_to_exist(nil, :password_salt, :pw_salt, :salt))
|
||||
end
|
||||
alias_method :password_salt_field=, :password_salt_field
|
||||
|
||||
# Whether or not to require a password confirmation. If you don't want your users to confirm their password
|
||||
# just set this to false.
|
||||
#
|
||||
# * <tt>Default:</tt> true
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def require_password_confirmation(value = nil)
|
||||
rw_config(:require_password_confirmation, value, true)
|
||||
end
|
||||
alias_method :require_password_confirmation=, :require_password_confirmation
|
||||
|
||||
# By default passwords are required when a record is new or the crypted_password is blank, but if both of these things
|
||||
# are met a password is not required. In this case, blank passwords are ignored.
|
||||
#
|
||||
# Think about a profile page, where the user can edit all of their information, including changing their password.
|
||||
# If they do not want to change their password they just leave the fields blank. This will try to set the password to
|
||||
# a blank value, in which case is incorrect behavior. As such, Authlogic ignores this. But let's say you have a completely
|
||||
# separate page for resetting passwords, you might not want to ignore blank passwords. If this is the case for you, then
|
||||
# just set this value to false.
|
||||
#
|
||||
# * <tt>Default:</tt> true
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def ignore_blank_passwords(value = nil)
|
||||
rw_config(:ignore_blank_passwords, value, true)
|
||||
end
|
||||
alias_method :ignore_blank_passwords=, :ignore_blank_passwords
|
||||
|
||||
# When calling valid_password?("some pass") do you want to check that password against what's in that object or whats in
|
||||
# the datbase. Take this example:
|
||||
#
|
||||
# u = User.first
|
||||
# u.password = "new pass"
|
||||
# u.valid_password?("old pass")
|
||||
#
|
||||
# Should the last line above return true or false? The record hasn't been saved yet, so most would assume true.
|
||||
# Other would assume false. So I let you decide by giving you this option.
|
||||
#
|
||||
# * <tt>Default:</tt> true
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def check_passwords_against_database(value = nil)
|
||||
rw_config(:check_passwords_against_database, value, true)
|
||||
end
|
||||
alias_method :check_passwords_against_database=, :check_passwords_against_database
|
||||
|
||||
# Whether or not to validate the password field.
|
||||
#
|
||||
# * <tt>Default:</tt> true
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def validate_password_field(value = nil)
|
||||
rw_config(:validate_password_field, value, true)
|
||||
end
|
||||
alias_method :validate_password_field=, :validate_password_field
|
||||
|
||||
# A hash of options for the validates_length_of call for the password field. Allows you to change this however you want.
|
||||
#
|
||||
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
||||
# merge options into it. Checkout the convenience function merge_validates_length_of_password_field_options to merge
|
||||
# options.</b>
|
||||
#
|
||||
# * <tt>Default:</tt> {:minimum => 4, :if => :require_password?}
|
||||
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
||||
def validates_length_of_password_field_options(value = nil)
|
||||
rw_config(:validates_length_of_password_field_options, value, {:minimum => 4, :if => :require_password?})
|
||||
end
|
||||
alias_method :validates_length_of_password_field_options=, :validates_length_of_password_field_options
|
||||
|
||||
# A convenience function to merge options into the validates_length_of_login_field_options. So intead of:
|
||||
#
|
||||
# self.validates_length_of_password_field_options = validates_length_of_password_field_options.merge(:my_option => my_value)
|
||||
#
|
||||
# You can do this:
|
||||
#
|
||||
# merge_validates_length_of_password_field_options :my_option => my_value
|
||||
def merge_validates_length_of_password_field_options(options = {})
|
||||
self.validates_length_of_password_field_options = validates_length_of_password_field_options.merge(options)
|
||||
end
|
||||
|
||||
# A hash of options for the validates_confirmation_of call for the password field. Allows you to change this however you want.
|
||||
#
|
||||
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
||||
# merge options into it. Checkout the convenience function merge_validates_length_of_password_field_options to merge
|
||||
# options.</b>
|
||||
#
|
||||
# * <tt>Default:</tt> {:if => :require_password?}
|
||||
# * <tt>Accepts:</tt> Hash of options accepted by validates_confirmation_of
|
||||
def validates_confirmation_of_password_field_options(value = nil)
|
||||
rw_config(:validates_confirmation_of_password_field_options, value, {:if => :require_password?})
|
||||
end
|
||||
alias_method :validates_confirmation_of_password_field_options=, :validates_confirmation_of_password_field_options
|
||||
|
||||
# See merge_validates_length_of_password_field_options. The same thing, except for validates_confirmation_of_password_field_options
|
||||
def merge_validates_confirmation_of_password_field_options(options = {})
|
||||
self.validates_confirmation_of_password_field_options = validates_confirmation_of_password_field_options.merge(options)
|
||||
end
|
||||
|
||||
# A hash of options for the validates_length_of call for the password_confirmation field. Allows you to change this however you want.
|
||||
#
|
||||
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
||||
# merge options into it. Checkout the convenience function merge_validates_length_of_password_field_options to merge
|
||||
# options.</b>
|
||||
#
|
||||
# * <tt>Default:</tt> validates_length_of_password_field_options
|
||||
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
||||
def validates_length_of_password_confirmation_field_options(value = nil)
|
||||
rw_config(:validates_length_of_password_confirmation_field_options, value, validates_length_of_password_field_options)
|
||||
end
|
||||
alias_method :validates_length_of_password_confirmation_field_options=, :validates_length_of_password_confirmation_field_options
|
||||
|
||||
# See merge_validates_length_of_password_field_options. The same thing, except for validates_length_of_password_confirmation_field_options
|
||||
def merge_validates_length_of_password_confirmation_field_options(options = {})
|
||||
self.validates_length_of_password_confirmation_field_options = validates_length_of_password_confirmation_field_options.merge(options)
|
||||
end
|
||||
|
||||
# The class you want to use to encrypt and verify your encrypted passwords. See the Authlogic::CryptoProviders module for more info
|
||||
# on the available methods and how to create your own.
|
||||
#
|
||||
# * <tt>Default:</tt> CryptoProviders::Sha512
|
||||
# * <tt>Accepts:</tt> Class
|
||||
def crypto_provider(value = nil)
|
||||
rw_config(:crypto_provider, value, CryptoProviders::Sha512)
|
||||
end
|
||||
alias_method :crypto_provider=, :crypto_provider
|
||||
|
||||
# Let's say you originally encrypted your passwords with Sha1. Sha1 is starting to join the party with MD5 and you want to switch
|
||||
# to something stronger. No problem, just specify your new and improved algorithm with the crypt_provider option and then let
|
||||
# Authlogic know you are transitioning from Sha1 using this option. Authlogic will take care of everything, including transitioning
|
||||
# your users to the new algorithm. The next time a user logs in, they will be granted access using the old algorithm and their
|
||||
# password will be resaved with the new algorithm. All new users will obviously use the new algorithm as well.
|
||||
#
|
||||
# Lastly, if you want to transition again, you can pass an array of crypto providers. So you can transition from as many algorithms
|
||||
# as you want.
|
||||
#
|
||||
# * <tt>Default:</tt> nil
|
||||
# * <tt>Accepts:</tt> Class or Array
|
||||
def transition_from_crypto_providers(value = nil)
|
||||
rw_config(:transition_from_crypto_providers, (!value.nil? && [value].flatten.compact) || value, [])
|
||||
end
|
||||
alias_method :transition_from_crypto_providers=, :transition_from_crypto_providers
|
||||
end
|
||||
|
||||
# Callbacks / hooks to allow other modules to modify the behavior of this module.
|
||||
module Callbacks
|
||||
METHODS = [
|
||||
"before_password_set", "after_password_set",
|
||||
"before_password_verification", "after_password_verification"
|
||||
]
|
||||
|
||||
def self.included(klass)
|
||||
return if klass.crypted_password_field.nil?
|
||||
klass.define_callbacks *METHODS
|
||||
|
||||
# If Rails 3, support the new callback syntax
|
||||
if klass.send(klass.respond_to?(:singleton_class) ? :singleton_class : :metaclass).method_defined?(:set_callback)
|
||||
METHODS.each do |method|
|
||||
klass.class_eval <<-"end_eval", __FILE__, __LINE__
|
||||
def self.#{method}(*methods, &block)
|
||||
set_callback :#{method}, *methods, &block
|
||||
end
|
||||
end_eval
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
METHODS.each do |method|
|
||||
class_eval <<-"end_eval", __FILE__, __LINE__
|
||||
def #{method}
|
||||
run_callbacks(:#{method}) { |result, object| result == false }
|
||||
end
|
||||
end_eval
|
||||
end
|
||||
end
|
||||
|
||||
# The methods related to the password field.
|
||||
module Methods
|
||||
def self.included(klass)
|
||||
return if klass.crypted_password_field.nil?
|
||||
|
||||
klass.class_eval do
|
||||
include InstanceMethods
|
||||
|
||||
if validate_password_field
|
||||
validates_length_of :password, validates_length_of_password_field_options
|
||||
|
||||
if require_password_confirmation
|
||||
validates_confirmation_of :password, validates_confirmation_of_password_field_options
|
||||
validates_length_of :password_confirmation, validates_length_of_password_confirmation_field_options
|
||||
end
|
||||
end
|
||||
|
||||
after_save :reset_password_changed
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
# The password
|
||||
def password
|
||||
@password
|
||||
end
|
||||
|
||||
# This is a virtual method. Once a password is passed to it, it will create new password salt as well as encrypt
|
||||
# the password.
|
||||
def password=(pass)
|
||||
return if ignore_blank_passwords? && pass.blank?
|
||||
before_password_set
|
||||
@password = pass
|
||||
send("#{password_salt_field}=", Authlogic::Random.friendly_token) if password_salt_field
|
||||
send("#{crypted_password_field}=", crypto_provider.encrypt(*encrypt_arguments(@password, false, act_like_restful_authentication? ? :restful_authentication : nil)))
|
||||
@password_changed = true
|
||||
after_password_set
|
||||
end
|
||||
|
||||
# Accepts a raw password to determine if it is the correct password or not. Notice the second argument. That defaults to the value of
|
||||
# check_passwords_against_database. See that method for mor information, but basically it just tells Authlogic to check the password
|
||||
# against the value in the database or the value in the object.
|
||||
def valid_password?(attempted_password, check_against_database = check_passwords_against_database?)
|
||||
crypted = check_against_database && send("#{crypted_password_field}_changed?") ? send("#{crypted_password_field}_was") : send(crypted_password_field)
|
||||
return false if attempted_password.blank? || crypted.blank?
|
||||
before_password_verification
|
||||
|
||||
crypto_providers.each_with_index do |encryptor, index|
|
||||
# The arguments_type of for the transitioning from restful_authentication
|
||||
arguments_type = (act_like_restful_authentication? && index == 0) ||
|
||||
(transition_from_restful_authentication? && index > 0 && encryptor == Authlogic::CryptoProviders::Sha1) ?
|
||||
:restful_authentication : nil
|
||||
|
||||
if encryptor.matches?(crypted, *encrypt_arguments(attempted_password, check_against_database, arguments_type))
|
||||
transition_password(attempted_password) if transition_password?(index, encryptor, crypted, check_against_database)
|
||||
after_password_verification
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
# Resets the password to a random friendly token.
|
||||
def reset_password
|
||||
friendly_token = Authlogic::Random.friendly_token
|
||||
self.password = friendly_token
|
||||
self.password_confirmation = friendly_token
|
||||
end
|
||||
alias_method :randomize_password, :reset_password
|
||||
|
||||
# Resets the password to a random friendly token and then saves the record.
|
||||
def reset_password!
|
||||
reset_password
|
||||
save_without_session_maintenance(:validate => false)
|
||||
end
|
||||
alias_method :randomize_password!, :reset_password!
|
||||
|
||||
private
|
||||
def check_passwords_against_database?
|
||||
self.class.check_passwords_against_database == true
|
||||
end
|
||||
|
||||
def crypto_providers
|
||||
[crypto_provider] + transition_from_crypto_providers
|
||||
end
|
||||
|
||||
def encrypt_arguments(raw_password, check_against_database, arguments_type = nil)
|
||||
salt = nil
|
||||
salt = (check_against_database && send("#{password_salt_field}_changed?") ? send("#{password_salt_field}_was") : send(password_salt_field)) if password_salt_field
|
||||
|
||||
case arguments_type
|
||||
when :restful_authentication
|
||||
[REST_AUTH_SITE_KEY, salt, raw_password, REST_AUTH_SITE_KEY].compact
|
||||
else
|
||||
[raw_password, salt].compact
|
||||
end
|
||||
end
|
||||
|
||||
# Determines if we need to tranisiton the password.
|
||||
# If the index > 0 then we are using an "transition from" crypto provider.
|
||||
# If the encryptor has a cost and the cost it outdated.
|
||||
# If we aren't using database values
|
||||
# If we are using database values, only if the password hasnt change so we don't overwrite any changes
|
||||
def transition_password?(index, encryptor, crypted, check_against_database)
|
||||
(index > 0 || (encryptor.respond_to?(:cost_matches?) && !encryptor.cost_matches?(send(crypted_password_field)))) &&
|
||||
(!check_against_database || !send("#{crypted_password_field}_changed?"))
|
||||
end
|
||||
|
||||
def transition_password(attempted_password)
|
||||
self.password = attempted_password
|
||||
save(false)
|
||||
end
|
||||
|
||||
def require_password?
|
||||
new_record? || password_changed? || send(crypted_password_field).blank?
|
||||
end
|
||||
|
||||
def ignore_blank_passwords?
|
||||
self.class.ignore_blank_passwords == true
|
||||
end
|
||||
|
||||
def password_changed?
|
||||
@password_changed == true
|
||||
end
|
||||
|
||||
def reset_password_changed
|
||||
@password_changed = nil
|
||||
end
|
||||
|
||||
def crypted_password_field
|
||||
self.class.crypted_password_field
|
||||
end
|
||||
|
||||
def password_salt_field
|
||||
self.class.password_salt_field
|
||||
end
|
||||
|
||||
def crypto_provider
|
||||
self.class.crypto_provider
|
||||
end
|
||||
|
||||
def transition_from_crypto_providers
|
||||
self.class.transition_from_crypto_providers
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,105 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# This provides a handy token that is "perishable". Meaning the token is only good for a certain amount of time. This is perfect for
|
||||
# resetting password, confirming accounts, etc. Typically during these actions you send them this token in via their email. Once they
|
||||
# use the token and do what they need to do, that token should expire. Don't worry about maintaining this, changing it, or expiring it
|
||||
# yourself. Authlogic does all of this for you. See the sub modules for all of the tools Authlogic provides to you.
|
||||
module PerishableToken
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
add_acts_as_authentic_module(Methods)
|
||||
end
|
||||
end
|
||||
|
||||
# Change how the perishable token works.
|
||||
module Config
|
||||
# When using the find_using_perishable_token method the token can expire. If the token is expired, no
|
||||
# record will be returned. Use this option to specify how long the token is valid for.
|
||||
#
|
||||
# * <tt>Default:</tt> 10.minutes
|
||||
# * <tt>Accepts:</tt> Fixnum
|
||||
def perishable_token_valid_for(value = nil)
|
||||
rw_config(:perishable_token_valid_for, (!value.nil? && value.to_i) || value, 10.minutes.to_i)
|
||||
end
|
||||
alias_method :perishable_token_valid_for=, :perishable_token_valid_for
|
||||
|
||||
# Authlogic tries to expire and change the perishable token as much as possible, without comprising
|
||||
# it's purpose. This is for security reasons. If you want to manage it yourself, you can stop
|
||||
# Authlogic from getting your in way by setting this to true.
|
||||
#
|
||||
# * <tt>Default:</tt> false
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def disable_perishable_token_maintenance(value = nil)
|
||||
rw_config(:disable_perishable_token_maintenance, value, false)
|
||||
end
|
||||
alias_method :disable_perishable_token_maintenance=, :disable_perishable_token_maintenance
|
||||
end
|
||||
|
||||
# All methods relating to the perishable token.
|
||||
module Methods
|
||||
def self.included(klass)
|
||||
return if !klass.column_names.include?("perishable_token")
|
||||
|
||||
klass.class_eval do
|
||||
extend ClassMethods
|
||||
include InstanceMethods
|
||||
|
||||
validates_uniqueness_of :perishable_token, :if => :perishable_token_changed?
|
||||
before_save :reset_perishable_token, :unless => :disable_perishable_token_maintenance?
|
||||
end
|
||||
end
|
||||
|
||||
# Class level methods for the perishable token
|
||||
module ClassMethods
|
||||
# Use this methdo to find a record with a perishable token. This method does 2 things for you:
|
||||
#
|
||||
# 1. It ignores blank tokens
|
||||
# 2. It enforces the perishable_token_valid_for configuration option.
|
||||
#
|
||||
# If you want to use a different timeout value, just pass it as the second parameter:
|
||||
#
|
||||
# User.find_using_perishable_token(token, 1.hour)
|
||||
def find_using_perishable_token(token, age = self.perishable_token_valid_for)
|
||||
return if token.blank?
|
||||
age = age.to_i
|
||||
|
||||
conditions_sql = "perishable_token = ?"
|
||||
conditions_subs = [token]
|
||||
|
||||
if column_names.include?("updated_at") && age > 0
|
||||
conditions_sql += " and updated_at > ?"
|
||||
conditions_subs << age.seconds.ago
|
||||
end
|
||||
|
||||
find(:first, :conditions => [conditions_sql, *conditions_subs])
|
||||
end
|
||||
|
||||
# This method will raise ActiveRecord::NotFound if no record is found.
|
||||
def find_using_perishable_token!(token, age = perishable_token_valid_for)
|
||||
find_using_perishable_token(token, age) || raise(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
# Instance level methods for the perishable token.
|
||||
module InstanceMethods
|
||||
# Resets the perishable token to a random friendly token.
|
||||
def reset_perishable_token
|
||||
self.perishable_token = Random.friendly_token
|
||||
end
|
||||
|
||||
# Same as reset_perishable_token, but then saves the record afterwards.
|
||||
def reset_perishable_token!
|
||||
reset_perishable_token
|
||||
save_without_session_maintenance(:validate => false)
|
||||
end
|
||||
|
||||
# A convenience method based on the disable_perishable_token_maintenance configuration option.
|
||||
def disable_perishable_token_maintenance?
|
||||
self.class.disable_perishable_token_maintenance == true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,68 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# Maintains the persistence token, the token responsible for persisting sessions. This token
|
||||
# gets stores in the session and the cookie.
|
||||
module PersistenceToken
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
add_acts_as_authentic_module(Methods)
|
||||
end
|
||||
end
|
||||
|
||||
# Methods for the persistence token.
|
||||
module Methods
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend ClassMethods
|
||||
include InstanceMethods
|
||||
|
||||
if respond_to?(:after_password_set) && respond_to?(:after_password_verification)
|
||||
after_password_set :reset_persistence_token
|
||||
after_password_verification :reset_persistence_token!, :if => :reset_persistence_token?
|
||||
end
|
||||
|
||||
validates_presence_of :persistence_token
|
||||
validates_uniqueness_of :persistence_token, :if => :persistence_token_changed?
|
||||
|
||||
before_validation :reset_persistence_token, :if => :reset_persistence_token?
|
||||
end
|
||||
end
|
||||
|
||||
# Class level methods for the persistence token.
|
||||
module ClassMethods
|
||||
# Resets ALL persistence tokens in the database, which will require all users to reauthenticate.
|
||||
def forget_all
|
||||
# Paginate these to save on memory
|
||||
records = nil
|
||||
i = 0
|
||||
begin
|
||||
records = find(:all, :limit => 50, :offset => i)
|
||||
records.each { |record| record.forget! }
|
||||
i += 50
|
||||
end while !records.blank?
|
||||
end
|
||||
end
|
||||
|
||||
# Instance level methods for the persistence token.
|
||||
module InstanceMethods
|
||||
# Resets the persistence_token field to a random hex value.
|
||||
def reset_persistence_token
|
||||
self.persistence_token = Authlogic::Random.hex_token
|
||||
end
|
||||
|
||||
# Same as reset_persistence_token, but then saves the record.
|
||||
def reset_persistence_token!
|
||||
reset_persistence_token
|
||||
save_without_session_maintenance(:validate => false)
|
||||
end
|
||||
alias_method :forget!, :reset_persistence_token!
|
||||
|
||||
private
|
||||
def reset_persistence_token?
|
||||
persistence_token.blank?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,61 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# This module is responsible for transitioning existing applications from the restful_authentication plugin.
|
||||
module RestfulAuthentication
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
include InstanceMethods
|
||||
end
|
||||
end
|
||||
|
||||
module Config
|
||||
# Switching an existing app to Authlogic from restful_authentication? No problem, just set this true and your users won't know
|
||||
# anything changed. From your database perspective nothing will change at all. Authlogic will continue to encrypt passwords
|
||||
# just like restful_authentication, so your app won't skip a beat. Although, might consider transitioning your users to a newer
|
||||
# and stronger algorithm. Checkout the transition_from_restful_authentication option.
|
||||
#
|
||||
# * <tt>Default:</tt> false
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def act_like_restful_authentication(value = nil)
|
||||
r = rw_config(:act_like_restful_authentication, value, false)
|
||||
set_restful_authentication_config if value
|
||||
r
|
||||
end
|
||||
alias_method :act_like_restful_authentication=, :act_like_restful_authentication
|
||||
|
||||
# This works just like act_like_restful_authentication except that it will start transitioning your users to the algorithm you
|
||||
# specify with the crypto provider option. The next time they log in it will resave their password with the new algorithm
|
||||
# and any new record will use the new algorithm as well. Make sure to update your users table if you are using the default
|
||||
# migration since it will set crypted_password and salt columns to a maximum width of 40 characters which is not enough.
|
||||
def transition_from_restful_authentication(value = nil)
|
||||
r = rw_config(:transition_from_restful_authentication, value, false)
|
||||
set_restful_authentication_config if value
|
||||
r
|
||||
end
|
||||
alias_method :transition_from_restful_authentication=, :transition_from_restful_authentication
|
||||
|
||||
private
|
||||
def set_restful_authentication_config
|
||||
crypto_provider_key = act_like_restful_authentication ? :crypto_provider : :transition_from_crypto_providers
|
||||
self.send("#{crypto_provider_key}=", CryptoProviders::Sha1)
|
||||
if !defined?(::REST_AUTH_SITE_KEY) || ::REST_AUTH_SITE_KEY.nil?
|
||||
class_eval("::REST_AUTH_SITE_KEY = ''") if !defined?(::REST_AUTH_SITE_KEY)
|
||||
CryptoProviders::Sha1.stretches = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
private
|
||||
def act_like_restful_authentication?
|
||||
self.class.act_like_restful_authentication == true
|
||||
end
|
||||
|
||||
def transition_from_restful_authentication?
|
||||
self.class.transition_from_restful_authentication == true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,139 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# This is one of my favorite features that I think is pretty cool. It's things like this that make a library great
|
||||
# and let you know you are on the right track.
|
||||
#
|
||||
# Just to clear up any confusion, Authlogic stores both the record id and the persistence token in the session.
|
||||
# Why? So stale sessions can not be persisted. It stores the id so it can quickly find the record, and the
|
||||
# persistence token to ensure no sessions are stale. So if the persistence token changes, the user must log
|
||||
# back in.
|
||||
#
|
||||
# Well, the persistence token changes with the password. What happens if the user changes his own password?
|
||||
# He shouldn't have to log back in, he's the one that made the change.
|
||||
#
|
||||
# That being said, wouldn't it be nice if their session and cookie information was automatically updated?
|
||||
# Instead of cluttering up your controller with redundant session code. The same thing goes for new
|
||||
# registrations.
|
||||
#
|
||||
# That's what this module is all about. This will automatically maintain the cookie and session values as
|
||||
# records are saved.
|
||||
module SessionMaintenance
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
add_acts_as_authentic_module(Methods)
|
||||
end
|
||||
end
|
||||
|
||||
module Config
|
||||
# This is more of a convenience method. In order to turn off automatic maintenance of sessions just
|
||||
# set this to false, or you can also set the session_ids method to a blank array. Both accomplish
|
||||
# the same thing. This method is a little clearer in it's intentions though.
|
||||
#
|
||||
# * <tt>Default:</tt> true
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def maintain_sessions(value = nil)
|
||||
rw_config(:maintain_sessions, value, true)
|
||||
end
|
||||
alias_method :maintain_sessions=, :maintain_sessions
|
||||
|
||||
# As you may know, authlogic sessions can be separate by id (See Authlogic::Session::Base#id). You can
|
||||
# specify here what session ids you want auto maintained. By default it is the main session, which has
|
||||
# an id of nil.
|
||||
#
|
||||
# * <tt>Default:</tt> [nil]
|
||||
# * <tt>Accepts:</tt> Array
|
||||
def session_ids(value = nil)
|
||||
rw_config(:session_ids, value, [nil])
|
||||
end
|
||||
alias_method :session_ids=, :session_ids
|
||||
|
||||
# The name of the associated session class. This is inferred by the name of the model.
|
||||
#
|
||||
# * <tt>Default:</tt> "#{klass.name}Session".constantize
|
||||
# * <tt>Accepts:</tt> Class
|
||||
def session_class(value = nil)
|
||||
const = "#{base_class.name}Session".constantize rescue nil
|
||||
rw_config(:session_class, value, const)
|
||||
end
|
||||
alias_method :session_class=, :session_class
|
||||
end
|
||||
|
||||
module Methods
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
before_save :get_session_information, :if => :update_sessions?
|
||||
before_save :maintain_sessions, :if => :update_sessions?
|
||||
end
|
||||
end
|
||||
|
||||
# Save the record and skip session maintenance all together.
|
||||
def save_without_session_maintenance(*args)
|
||||
self.skip_session_maintenance = true
|
||||
result = save(*args)
|
||||
self.skip_session_maintenance = false
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
def skip_session_maintenance=(value)
|
||||
@skip_session_maintenance = value
|
||||
end
|
||||
|
||||
def skip_session_maintenance
|
||||
@skip_session_maintenance ||= false
|
||||
end
|
||||
|
||||
def update_sessions?
|
||||
!skip_session_maintenance && session_class && session_class.activated? && self.class.maintain_sessions == true && !session_ids.blank? && persistence_token_changed?
|
||||
end
|
||||
|
||||
def get_session_information
|
||||
# Need to determine if we are completely logged out, or logged in as another user
|
||||
@_sessions = []
|
||||
|
||||
session_ids.each do |session_id|
|
||||
session = session_class.find(session_id, self)
|
||||
@_sessions << session if session && session.record
|
||||
end
|
||||
end
|
||||
|
||||
def maintain_sessions
|
||||
if @_sessions.empty?
|
||||
create_session
|
||||
else
|
||||
update_sessions
|
||||
end
|
||||
end
|
||||
|
||||
def create_session
|
||||
# We only want to automatically login into the first session, since this is the main session. The other sessions are sessions
|
||||
# that need to be created after logging into the main session.
|
||||
session_id = session_ids.first
|
||||
session_class.create(*[self, self, session_id].compact)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
def update_sessions
|
||||
# We found sessions above, let's update them with the new info
|
||||
@_sessions.each do |stale_session|
|
||||
next if stale_session.record != self
|
||||
stale_session.unauthorized_record = self
|
||||
stale_session.save
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
def session_ids
|
||||
self.class.session_ids
|
||||
end
|
||||
|
||||
def session_class
|
||||
self.class.session_class
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,65 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# This module is responsible for maintaining the single_access token. For more information the single access token and how to use it,
|
||||
# see the Authlogic::Session::Params module.
|
||||
module SingleAccessToken
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
add_acts_as_authentic_module(Methods)
|
||||
end
|
||||
end
|
||||
|
||||
# All configuration for the single_access token aspect of acts_as_authentic.
|
||||
module Config
|
||||
# The single access token is used for authentication via URLs, such as a private feed. That being said,
|
||||
# if the user changes their password, that token probably shouldn't change. If it did, the user would have
|
||||
# to update all of their URLs. So be default this is option is disabled, if you need it, feel free to turn
|
||||
# it on.
|
||||
#
|
||||
# * <tt>Default:</tt> false
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def change_single_access_token_with_password(value = nil)
|
||||
rw_config(:change_single_access_token_with_password, value, false)
|
||||
end
|
||||
alias_method :change_single_access_token_with_password=, :change_single_access_token_with_password
|
||||
end
|
||||
|
||||
# All method, for the single_access token aspect of acts_as_authentic.
|
||||
module Methods
|
||||
def self.included(klass)
|
||||
return if !klass.column_names.include?("single_access_token")
|
||||
|
||||
klass.class_eval do
|
||||
include InstanceMethods
|
||||
validates_uniqueness_of :single_access_token, :if => :single_access_token_changed?
|
||||
before_validation :reset_single_access_token, :if => :reset_single_access_token?
|
||||
after_password_set(:reset_single_access_token, :if => :change_single_access_token_with_password?) if respond_to?(:after_password_set)
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
# Resets the single_access_token to a random friendly token.
|
||||
def reset_single_access_token
|
||||
self.single_access_token = Authlogic::Random.friendly_token
|
||||
end
|
||||
|
||||
# same as reset_single_access_token, but then saves the record.
|
||||
def reset_single_access_token!
|
||||
reset_single_access_token
|
||||
save_without_session_maintenance
|
||||
end
|
||||
|
||||
protected
|
||||
def reset_single_access_token?
|
||||
single_access_token.blank?
|
||||
end
|
||||
|
||||
def change_single_access_token_with_password?
|
||||
self.class.change_single_access_token_with_password == true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,32 +0,0 @@
|
|||
module Authlogic
|
||||
module ActsAsAuthentic
|
||||
# Allows you to scope everything to specific fields.
|
||||
# See the Config submodule for more info.
|
||||
# For information on how to scope off of a parent object see Authlogic::AuthenticatesMany
|
||||
module ValidationsScope
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
end
|
||||
end
|
||||
|
||||
# All configuration for the scope feature.
|
||||
module Config
|
||||
# Allows you to scope everything to specific field(s). Works just like validates_uniqueness_of.
|
||||
# For example, let's say a user belongs to a company, and you want to scope everything to the
|
||||
# company:
|
||||
#
|
||||
# acts_as_authentic do |c|
|
||||
# c.validations_scope = :company_id
|
||||
# end
|
||||
#
|
||||
# * <tt>Default:</tt> nil
|
||||
# * <tt>Accepts:</tt> Symbol or Array of symbols
|
||||
def validations_scope(value = nil)
|
||||
rw_config(:validations_scope, value)
|
||||
end
|
||||
alias_method :validations_scope=, :validations_scope
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,42 +0,0 @@
|
|||
module Authlogic
|
||||
module AuthenticatesMany
|
||||
# An object of this class is used as a proxy for the authenticates_many relationship. It basically allows you to "save" scope details
|
||||
# and call them on an object, which allows you to do the following:
|
||||
#
|
||||
# @account.user_sessions.new
|
||||
# @account.user_sessions.find
|
||||
# # ... etc
|
||||
#
|
||||
# You can call all of the class level methods off of an object with a saved scope, so that calling the above methods scopes the user
|
||||
# sessions down to that specific account. To implement this via ActiveRecord do something like:
|
||||
#
|
||||
# class User < ActiveRecord::Base
|
||||
# authenticates_many :user_sessions
|
||||
# end
|
||||
class Association
|
||||
attr_accessor :klass, :find_options, :id
|
||||
|
||||
def initialize(klass, find_options, id)
|
||||
self.klass = klass
|
||||
self.find_options = find_options
|
||||
self.id = id
|
||||
end
|
||||
|
||||
[:create, :create!, :find, :new].each do |method|
|
||||
class_eval <<-"end_eval", __FILE__, __LINE__
|
||||
def #{method}(*args)
|
||||
klass.with_scope(scope_options) do
|
||||
klass.#{method}(*args)
|
||||
end
|
||||
end
|
||||
end_eval
|
||||
end
|
||||
alias_method :build, :new
|
||||
|
||||
private
|
||||
def scope_options
|
||||
{:find_options => find_options, :id => id}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,55 +0,0 @@
|
|||
module Authlogic
|
||||
# This allows you to scope your authentication. For example, let's say all users belong to an account, you want to make sure only users
|
||||
# that belong to that account can actually login into that account. Simple, just do:
|
||||
#
|
||||
# class Account < ActiveRecord::Base
|
||||
# authenticates_many :user_sessions
|
||||
# end
|
||||
#
|
||||
# Now you can scope sessions just like everything else in ActiveRecord:
|
||||
#
|
||||
# @account.user_sessions.new(*args)
|
||||
# @account.user_sessions.create(*args)
|
||||
# @account.user_sessions.find(*args)
|
||||
# # ... etc
|
||||
#
|
||||
# Checkout the authenticates_many method for a list of options.
|
||||
# You may also want to checkout Authlogic::ActsAsAuthentic::Scope to scope your model.
|
||||
module AuthenticatesMany
|
||||
module Base
|
||||
# Allows you set essentially set up a relationship with your sessions. See module definition above for more details.
|
||||
#
|
||||
# === Options
|
||||
#
|
||||
# * <tt>session_class:</tt> default: "#{name}Session",
|
||||
# This is the related session class.
|
||||
#
|
||||
# * <tt>relationship_name:</tt> default: options[:session_class].klass_name.underscore.pluralize,
|
||||
# This is the name of the relationship you want to use to scope everything. For example an Account has many Users. There should be a relationship
|
||||
# called :users that you defined with a has_many. The reason we use the relationship is so you don't have to repeat yourself. The relatonship
|
||||
# could have all kinds of custom options. So instead of repeating yourself we essentially use the scope that the relationship creates.
|
||||
#
|
||||
# * <tt>find_options:</tt> default: nil,
|
||||
# By default the find options are created from the relationship you specify with :relationship_name. But if you want to override this and
|
||||
# manually specify find_options you can do it here. Specify options just as you would in ActiveRecord::Base.find.
|
||||
#
|
||||
# * <tt>scope_cookies:</tt> default: false
|
||||
# By the nature of cookies they scope theirself if you are using subdomains to access accounts. If you aren't using subdomains you need to have
|
||||
# separate cookies for each account, assuming a user is logging into mroe than one account. Authlogic can take care of this for you by
|
||||
# prefixing the name of the cookie and sessin with the model id. You just need to tell Authlogic to do this by passing this option.
|
||||
def authenticates_many(name, options = {})
|
||||
options[:session_class] ||= name.to_s.classify.constantize
|
||||
options[:relationship_name] ||= options[:session_class].klass_name.underscore.pluralize
|
||||
class_eval <<-"end_eval", __FILE__, __LINE__
|
||||
def #{name}
|
||||
find_options = #{options[:find_options].inspect} || #{options[:relationship_name]}.scope(:find)
|
||||
find_options.delete_if { |key, value| ![:conditions, :include, :joins].include?(key.to_sym) || value.nil? }
|
||||
@#{name} ||= Authlogic::AuthenticatesMany::Association.new(#{options[:session_class]}, find_options, #{options[:scope_cookies] ? "self.class.model_name.underscore + '_' + self.send(self.class.primary_key).to_s" : "nil"})
|
||||
end
|
||||
end_eval
|
||||
end
|
||||
end
|
||||
|
||||
::ActiveRecord::Base.extend(Base) if defined?(::ActiveRecord)
|
||||
end
|
||||
end
|
|
@ -1,67 +0,0 @@
|
|||
module Authlogic
|
||||
module ControllerAdapters # :nodoc:
|
||||
# Allows you to use Authlogic in any framework you want, not just rails. See the RailsAdapter or MerbAdapter
|
||||
# for an example of how to adapt Authlogic to work with your framework.
|
||||
class AbstractAdapter
|
||||
attr_accessor :controller
|
||||
|
||||
def initialize(controller)
|
||||
self.controller = controller
|
||||
end
|
||||
|
||||
def authenticate_with_http_basic(&block)
|
||||
@auth = Rack::Auth::Basic::Request.new(controller.request.env)
|
||||
if @auth.provided? and @auth.basic?
|
||||
block.call(*@auth.credentials)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def cookies
|
||||
controller.cookies
|
||||
end
|
||||
|
||||
def cookie_domain
|
||||
raise NotImplementedError.new("The cookie_domain method has not been implemented by the controller adapter")
|
||||
end
|
||||
|
||||
def params
|
||||
controller.params
|
||||
end
|
||||
|
||||
def request
|
||||
controller.request
|
||||
end
|
||||
|
||||
def request_content_type
|
||||
request.content_type
|
||||
end
|
||||
|
||||
def session
|
||||
controller.session
|
||||
end
|
||||
|
||||
def responds_to_single_access_allowed?
|
||||
controller.respond_to?(:single_access_allowed?, true)
|
||||
end
|
||||
|
||||
def single_access_allowed?
|
||||
controller.send(:single_access_allowed?)
|
||||
end
|
||||
|
||||
def responds_to_last_request_update_allowed?
|
||||
controller.respond_to?(:last_request_update_allowed?, true)
|
||||
end
|
||||
|
||||
def last_request_update_allowed?
|
||||
controller.send(:last_request_update_allowed?)
|
||||
end
|
||||
|
||||
private
|
||||
def method_missing(id, *args, &block)
|
||||
controller.send(id, *args, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
module Authlogic
|
||||
module ControllerAdapters
|
||||
# Adapts authlogic to work with merb. The point is to close the gap between what authlogic expects and what the merb controller object
|
||||
# provides. Similar to how ActiveRecord has an adapter for MySQL, PostgreSQL, SQLite, etc.
|
||||
class MerbAdapter < AbstractAdapter
|
||||
# Lets Authlogic know about the controller object via a before filter, AKA "activates" authlogic.
|
||||
module MerbImplementation
|
||||
def self.included(klass) # :nodoc:
|
||||
klass.before :activate_authlogic
|
||||
end
|
||||
|
||||
def cookie_domain
|
||||
Merb::Config[:session_cookie_domain]
|
||||
end
|
||||
|
||||
private
|
||||
def activate_authlogic
|
||||
Authlogic::Session::Base.controller = MerbAdapter.new(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# make sure we're running inside Merb
|
||||
if defined?(Merb::Plugins)
|
||||
Merb::BootLoader.before_app_loads do
|
||||
Merb::Controller.send(:include, Authlogic::ControllerAdapters::MerbAdapter::MerbImplementation)
|
||||
end
|
||||
end
|
|
@ -1,48 +0,0 @@
|
|||
module Authlogic
|
||||
module ControllerAdapters
|
||||
# Adapts authlogic to work with rails. The point is to close the gap between what authlogic expects and what the rails controller object
|
||||
# provides. Similar to how ActiveRecord has an adapter for MySQL, PostgreSQL, SQLite, etc.
|
||||
class RailsAdapter < AbstractAdapter
|
||||
class AuthlogicLoadedTooLateError < StandardError; end
|
||||
|
||||
def authenticate_with_http_basic(&block)
|
||||
controller.authenticate_with_http_basic(&block)
|
||||
end
|
||||
|
||||
def cookies
|
||||
controller.send(:cookies)
|
||||
end
|
||||
|
||||
def cookie_domain
|
||||
@cookie_domain_key ||= Rails::VERSION::STRING >= '2.3' ? :domain : :session_domain
|
||||
controller.request.session_options[@cookie_domain_key]
|
||||
end
|
||||
|
||||
def request_content_type
|
||||
request.format.to_s
|
||||
end
|
||||
|
||||
# Lets Authlogic know about the controller object via a before filter, AKA "activates" authlogic.
|
||||
module RailsImplementation
|
||||
def self.included(klass) # :nodoc:
|
||||
if defined?(::ApplicationController)
|
||||
raise AuthlogicLoadedTooLateError.new("Authlogic is trying to prepend a before_filter in ActionController::Base to active itself" +
|
||||
", the problem is that ApplicationController has already been loaded meaning the before_filter won't get copied into your" +
|
||||
" application. Generally this is due to another gem or plugin requiring your ApplicationController prematurely, such as" +
|
||||
" the resource_controller plugin. The solution is to require Authlogic before these other gems / plugins. Please require" +
|
||||
" authlogic first to get rid of this error.")
|
||||
end
|
||||
|
||||
klass.prepend_before_filter :activate_authlogic
|
||||
end
|
||||
|
||||
private
|
||||
def activate_authlogic
|
||||
Authlogic::Session::Base.controller = RailsAdapter.new(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ActionController::Base.send(:include, Authlogic::ControllerAdapters::RailsAdapter::RailsImplementation)
|
|
@ -1,61 +0,0 @@
|
|||
# Authlogic bridge for Sinatra
|
||||
module Authlogic
|
||||
module ControllerAdapters
|
||||
module SinatraAdapter
|
||||
class Cookies
|
||||
attr_reader :request, :response
|
||||
|
||||
def initialize(request, response)
|
||||
@request = request
|
||||
@response = response
|
||||
end
|
||||
|
||||
def delete(key, options = {})
|
||||
@request.cookies.delete(key)
|
||||
end
|
||||
|
||||
def []=(key, options)
|
||||
@response.set_cookie(key, options)
|
||||
end
|
||||
|
||||
def method_missing(meth, *args, &block)
|
||||
@request.cookies.send(meth, *args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
class Controller
|
||||
attr_reader :request, :response, :cookies
|
||||
|
||||
def initialize(request, response)
|
||||
@request = request
|
||||
@cookies = Cookies.new(request, response)
|
||||
end
|
||||
|
||||
def session
|
||||
env['rack.session']
|
||||
end
|
||||
|
||||
def method_missing(meth, *args, &block)
|
||||
@request.send meth, *args, &block
|
||||
end
|
||||
end
|
||||
|
||||
class Adapter < AbstractAdapter
|
||||
def cookie_domain
|
||||
env['SERVER_NAME']
|
||||
end
|
||||
|
||||
module Implementation
|
||||
def self.included(klass)
|
||||
klass.send :before do
|
||||
controller = Controller.new(request, response)
|
||||
Authlogic::Session::Base.controller = Adapter.new(controller)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Sinatra::Request.send(:include, Authlogic::ControllerAdapters::SinatraAdapter::Adapter::Implementation)
|
|
@ -1,43 +0,0 @@
|
|||
require "openssl"
|
||||
|
||||
module Authlogic
|
||||
module CryptoProviders
|
||||
# This encryption method is reversible if you have the supplied key. So in order to use this encryption method you must supply it with a key first.
|
||||
# In an initializer, or before your application initializes, you should do the following:
|
||||
#
|
||||
# Authlogic::CryptoProviders::AES256.key = "my really long and unique key, preferrably a bunch of random characters"
|
||||
#
|
||||
# My final comment is that this is a strong encryption method, but its main weakness is that its reversible. If you do not need to reverse the hash
|
||||
# then you should consider Sha512 or BCrypt instead.
|
||||
#
|
||||
# Keep your key in a safe place, some even say the key should be stored on a separate server.
|
||||
# This won't hurt performance because the only time it will try and access the key on the separate server is during initialization, which only
|
||||
# happens once. The reasoning behind this is if someone does compromise your server they won't have the key also. Basically, you don't want to
|
||||
# store the key with the lock.
|
||||
class AES256
|
||||
class << self
|
||||
attr_writer :key
|
||||
|
||||
def encrypt(*tokens)
|
||||
aes.encrypt
|
||||
aes.key = @key
|
||||
[aes.update(tokens.join) + aes.final].pack("m").chomp
|
||||
end
|
||||
|
||||
def matches?(crypted, *tokens)
|
||||
aes.decrypt
|
||||
aes.key = @key
|
||||
(aes.update(crypted.unpack("m").first) + aes.final) == tokens.join
|
||||
rescue OpenSSL::CipherError
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
def aes
|
||||
raise ArgumentError.new("You must provide a key like #{name}.key = my_key before using the #{name}") if @key.blank?
|
||||
@aes ||= OpenSSL::Cipher::Cipher.new("AES-256-ECB")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,90 +0,0 @@
|
|||
begin
|
||||
require "bcrypt"
|
||||
rescue LoadError
|
||||
"sudo gem install bcrypt-ruby"
|
||||
end
|
||||
|
||||
module Authlogic
|
||||
module CryptoProviders
|
||||
# For most apps Sha512 is plenty secure, but if you are building an app that stores nuclear launch codes you might want to consier BCrypt. This is an extremely
|
||||
# secure hashing algorithm, mainly because it is slow. A brute force attack on a BCrypt encrypted password would take much longer than a brute force attack on a
|
||||
# password encrypted with a Sha algorithm. Keep in mind you are sacrificing performance by using this, generating a password takes exponentially longer than any
|
||||
# of the Sha algorithms. I did some benchmarking to save you some time with your decision:
|
||||
#
|
||||
# require "bcrypt"
|
||||
# require "digest"
|
||||
# require "benchmark"
|
||||
#
|
||||
# Benchmark.bm(18) do |x|
|
||||
# x.report("BCrypt (cost = 10:") { 100.times { BCrypt::Password.create("mypass", :cost => 10) } }
|
||||
# x.report("BCrypt (cost = 2:") { 100.times { BCrypt::Password.create("mypass", :cost => 2) } }
|
||||
# x.report("Sha512:") { 100.times { Digest::SHA512.hexdigest("mypass") } }
|
||||
# x.report("Sha1:") { 100.times { Digest::SHA1.hexdigest("mypass") } }
|
||||
# end
|
||||
#
|
||||
# user system total real
|
||||
# BCrypt (cost = 10): 10.780000 0.060000 10.840000 ( 11.100289)
|
||||
# BCrypt (cost = 2): 0.180000 0.000000 0.180000 ( 0.181914)
|
||||
# Sha512: 0.000000 0.000000 0.000000 ( 0.000829)
|
||||
# Sha1: 0.000000 0.000000 0.000000 ( 0.000395)
|
||||
#
|
||||
# You can play around with the cost to get that perfect balance between performance and security.
|
||||
#
|
||||
# Decided BCrypt is for you? Just insall the bcrypt gem:
|
||||
#
|
||||
# gem install bcrypt-ruby
|
||||
#
|
||||
# Tell acts_as_authentic to use it:
|
||||
#
|
||||
# acts_as_authentic do |c|
|
||||
# c.crypto_provider = Authlogic::CryptoProviders::BCrypt
|
||||
# end
|
||||
#
|
||||
# You are good to go!
|
||||
class BCrypt
|
||||
class << self
|
||||
# This is the :cost option for the BCrpyt library. The higher the cost the more secure it is and the longer is take the generate a hash. By default this is 10.
|
||||
# Set this to whatever you want, play around with it to get that perfect balance between security and performance.
|
||||
def cost
|
||||
@cost ||= 10
|
||||
end
|
||||
attr_writer :cost
|
||||
|
||||
# Creates a BCrypt hash for the password passed.
|
||||
def encrypt(*tokens)
|
||||
::BCrypt::Password.create(join_tokens(tokens), :cost => cost)
|
||||
end
|
||||
|
||||
# Does the hash match the tokens? Uses the same tokens that were used to encrypt.
|
||||
def matches?(hash, *tokens)
|
||||
hash = new_from_hash(hash)
|
||||
return false if hash.blank?
|
||||
hash == join_tokens(tokens)
|
||||
end
|
||||
|
||||
# This method is used as a flag to tell Authlogic to "resave" the password upon a successful login, using the new cost
|
||||
def cost_matches?(hash)
|
||||
hash = new_from_hash(hash)
|
||||
if hash.blank?
|
||||
false
|
||||
else
|
||||
hash.cost == cost
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def join_tokens(tokens)
|
||||
tokens.flatten.join
|
||||
end
|
||||
|
||||
def new_from_hash(hash)
|
||||
begin
|
||||
::BCrypt::Password.new(hash)
|
||||
rescue ::BCrypt::Errors::InvalidHash
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
require "digest/md5"
|
||||
|
||||
module Authlogic
|
||||
module CryptoProviders
|
||||
# This class was made for the users transitioning from md5 based systems.
|
||||
# I highly discourage using this crypto provider as it superbly inferior
|
||||
# to your other options.
|
||||
#
|
||||
# Please use any other provider offered by Authlogic.
|
||||
class MD5
|
||||
class << self
|
||||
attr_accessor :join_token
|
||||
|
||||
# The number of times to loop through the encryption.
|
||||
def stretches
|
||||
@stretches ||= 1
|
||||
end
|
||||
attr_writer :stretches
|
||||
|
||||
# Turns your raw password into a MD5 hash.
|
||||
def encrypt(*tokens)
|
||||
digest = tokens.flatten.join(join_token)
|
||||
stretches.times { digest = Digest::MD5.hexdigest(digest) }
|
||||
digest
|
||||
end
|
||||
|
||||
# Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
|
||||
def matches?(crypted, *tokens)
|
||||
encrypt(*tokens) == crypted
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,35 +0,0 @@
|
|||
require "digest/sha1"
|
||||
|
||||
module Authlogic
|
||||
module CryptoProviders
|
||||
# This class was made for the users transitioning from restful_authentication. I highly discourage using this
|
||||
# crypto provider as it inferior to your other options. Please use any other provider offered by Authlogic.
|
||||
class Sha1
|
||||
class << self
|
||||
def join_token
|
||||
@join_token ||= "--"
|
||||
end
|
||||
attr_writer :join_token
|
||||
|
||||
# The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to.
|
||||
def stretches
|
||||
@stretches ||= 10
|
||||
end
|
||||
attr_writer :stretches
|
||||
|
||||
# Turns your raw password into a Sha1 hash.
|
||||
def encrypt(*tokens)
|
||||
tokens = tokens.flatten
|
||||
digest = tokens.shift
|
||||
stretches.times { digest = Digest::SHA1.hexdigest([digest, *tokens].join(join_token)) }
|
||||
digest
|
||||
end
|
||||
|
||||
# Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
|
||||
def matches?(crypted, *tokens)
|
||||
encrypt(*tokens) == crypted
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,50 +0,0 @@
|
|||
require "digest/sha2"
|
||||
|
||||
module Authlogic
|
||||
# The acts_as_authentic method has a crypto_provider option. This allows you to use any type of encryption you like.
|
||||
# Just create a class with a class level encrypt and matches? method. See example below.
|
||||
#
|
||||
# === Example
|
||||
#
|
||||
# class MyAwesomeEncryptionMethod
|
||||
# def self.encrypt(*tokens)
|
||||
# # the tokens passed will be an array of objects, what type of object is irrelevant,
|
||||
# # just do what you need to do with them and return a single encrypted string.
|
||||
# # for example, you will most likely join all of the objects into a single string and then encrypt that string
|
||||
# end
|
||||
#
|
||||
# def self.matches?(crypted, *tokens)
|
||||
# # return true if the crypted string matches the tokens.
|
||||
# # depending on your algorithm you might decrypt the string then compare it to the token, or you might
|
||||
# # encrypt the tokens and make sure it matches the crypted string, its up to you
|
||||
# end
|
||||
# end
|
||||
module CryptoProviders
|
||||
# = Sha256
|
||||
#
|
||||
# Uses the Sha256 hash algorithm to encrypt passwords.
|
||||
class Sha256
|
||||
class << self
|
||||
attr_accessor :join_token
|
||||
|
||||
# The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to.
|
||||
def stretches
|
||||
@stretches ||= 20
|
||||
end
|
||||
attr_writer :stretches
|
||||
|
||||
# Turns your raw password into a Sha256 hash.
|
||||
def encrypt(*tokens)
|
||||
digest = tokens.flatten.join(join_token)
|
||||
stretches.times { digest = Digest::SHA256.hexdigest(digest) }
|
||||
digest
|
||||
end
|
||||
|
||||
# Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
|
||||
def matches?(crypted, *tokens)
|
||||
encrypt(*tokens) == crypted
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,50 +0,0 @@
|
|||
require "digest/sha2"
|
||||
|
||||
module Authlogic
|
||||
# The acts_as_authentic method has a crypto_provider option. This allows you to use any type of encryption you like.
|
||||
# Just create a class with a class level encrypt and matches? method. See example below.
|
||||
#
|
||||
# === Example
|
||||
#
|
||||
# class MyAwesomeEncryptionMethod
|
||||
# def self.encrypt(*tokens)
|
||||
# # the tokens passed will be an array of objects, what type of object is irrelevant,
|
||||
# # just do what you need to do with them and return a single encrypted string.
|
||||
# # for example, you will most likely join all of the objects into a single string and then encrypt that string
|
||||
# end
|
||||
#
|
||||
# def self.matches?(crypted, *tokens)
|
||||
# # return true if the crypted string matches the tokens.
|
||||
# # depending on your algorithm you might decrypt the string then compare it to the token, or you might
|
||||
# # encrypt the tokens and make sure it matches the crypted string, its up to you
|
||||
# end
|
||||
# end
|
||||
module CryptoProviders
|
||||
# = Sha512
|
||||
#
|
||||
# Uses the Sha512 hash algorithm to encrypt passwords.
|
||||
class Sha512
|
||||
class << self
|
||||
attr_accessor :join_token
|
||||
|
||||
# The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to.
|
||||
def stretches
|
||||
@stretches ||= 20
|
||||
end
|
||||
attr_writer :stretches
|
||||
|
||||
# Turns your raw password into a Sha512 hash.
|
||||
def encrypt(*tokens)
|
||||
digest = tokens.flatten.join(join_token)
|
||||
stretches.times { digest = Digest::SHA512.hexdigest(digest) }
|
||||
digest
|
||||
end
|
||||
|
||||
# Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
|
||||
def matches?(crypted, *tokens)
|
||||
encrypt(*tokens) == crypted
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,43 +0,0 @@
|
|||
require 'digest/md5'
|
||||
module Authlogic
|
||||
module CryptoProviders
|
||||
class Wordpress
|
||||
class << self
|
||||
ITOA64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
def matches?(crypted, *tokens)
|
||||
stretches = 1 << ITOA64.index(crypted[3,1])
|
||||
plain, salt = *tokens
|
||||
hashed = Digest::MD5.digest(salt+plain)
|
||||
stretches.times do |i|
|
||||
hashed = Digest::MD5.digest(hashed+plain)
|
||||
end
|
||||
crypted[0,12]+encode_64(hashed, 16) == crypted
|
||||
end
|
||||
|
||||
def encode_64(input, length)
|
||||
output = ""
|
||||
i = 0
|
||||
while i < length
|
||||
value = input[i]
|
||||
i+=1
|
||||
break if value.nil?
|
||||
output += ITOA64[value & 0x3f, 1]
|
||||
value |= input[i] << 8 if i < length
|
||||
output += ITOA64[(value >> 6) & 0x3f, 1]
|
||||
|
||||
i+=1
|
||||
break if i >= length
|
||||
value |= input[i] << 16 if i < length
|
||||
output += ITOA64[(value >> 12) & 0x3f,1]
|
||||
|
||||
i+=1
|
||||
break if i >= length
|
||||
output += ITOA64[(value >> 18) & 0x3f,1]
|
||||
end
|
||||
output
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
83
vendor/plugins/authlogic/lib/authlogic/i18n.rb
vendored
83
vendor/plugins/authlogic/lib/authlogic/i18n.rb
vendored
|
@ -1,83 +0,0 @@
|
|||
require "authlogic/i18n/translator"
|
||||
|
||||
module Authlogic
|
||||
# This class allows any message in Authlogic to use internationalization. In earlier versions of Authlogic each message was translated via configuration.
|
||||
# This cluttered up the configuration and cluttered up Authlogic. So all translation has been extracted out into this class. Now all messages pass through
|
||||
# this class, making it much easier to implement in I18n library / plugin you want. Use this as a layer that sits between Authlogic and whatever I18n
|
||||
# library you want to use.
|
||||
#
|
||||
# By default this uses the rails I18n library, if it exists. If it doesnt exist it just returns the default english message. The Authlogic I18n class
|
||||
# works EXACTLY like the rails I18n class. This is because the arguments are delegated to this class.
|
||||
#
|
||||
# Here is how all messages are translated internally with Authlogic:
|
||||
#
|
||||
# Authlogic::I18n.t('error_messages.password_invalid', :default => "is invalid")
|
||||
#
|
||||
# If you use a different I18n library just replace the build-in I18n::Translator class with your own. For example:
|
||||
#
|
||||
# class MyAuthlogicI18nTranslator
|
||||
# def translate(key, options = {})
|
||||
# # you will have key which will be something like: "error_messages.password_invalid"
|
||||
# # you will also have options[:default], which will be the default english version of the message
|
||||
# # do whatever you want here with the arguments passed to you.
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# Authlogic::I18n.translator = MyAuthlogicI18nTranslator.new
|
||||
#
|
||||
# That it's! Here is a complete list of the keys that are passed. Just define these however you wish:
|
||||
#
|
||||
# authlogic:
|
||||
# error_messages:
|
||||
# login_blank: can not be blank
|
||||
# login_not_found: is not valid
|
||||
# login_invalid: should use only letters, numbers, spaces, and .-_@ please.
|
||||
# consecutive_failed_logins_limit_exceeded: Consecutive failed logins limit exceeded, account is disabled.
|
||||
# email_invalid: should look like an email address.
|
||||
# password_blank: can not be blank
|
||||
# password_invalid: is not valid
|
||||
# not_active: Your account is not active
|
||||
# not_confirmed: Your account is not confirmed
|
||||
# not_approved: Your account is not approved
|
||||
# no_authentication_details: You did not provide any details for authentication.
|
||||
# models:
|
||||
# user_session: UserSession (or whatever name you are using)
|
||||
# attributes:
|
||||
# user_session: (or whatever name you are using)
|
||||
# login: login
|
||||
# email: email
|
||||
# password: password
|
||||
# remember_me: remember me
|
||||
module I18n
|
||||
@@scope = :authlogic
|
||||
@@translator = nil
|
||||
|
||||
class << self
|
||||
# Returns the current scope. Defaults to :authlogic
|
||||
def scope
|
||||
@@scope
|
||||
end
|
||||
|
||||
# Sets the current scope. Used to set a custom scope.
|
||||
def scope=(scope)
|
||||
@@scope = scope
|
||||
end
|
||||
|
||||
# Returns the current translator. Defaults to +Translator+.
|
||||
def translator
|
||||
@@translator ||= Translator.new
|
||||
end
|
||||
|
||||
# Sets the current translator. Used to set a custom translator.
|
||||
def translator=(translator)
|
||||
@@translator = translator
|
||||
end
|
||||
|
||||
# All message translation is passed to this method. The first argument is the key for the message. The second is options, see the rails I18n library for a list of options used.
|
||||
def translate(key, options = {})
|
||||
translator.translate key, { :scope => I18n.scope }.merge(options)
|
||||
end
|
||||
alias :t :translate
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
module Authlogic
|
||||
module I18n
|
||||
class Translator
|
||||
# If the I18n gem is present, calls +I18n.translate+ passing all
|
||||
# arguments, else returns +options[:default]+.
|
||||
def translate(key, options = {})
|
||||
if defined?(::I18n)
|
||||
::I18n.translate key, options
|
||||
else
|
||||
options[:default]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
33
vendor/plugins/authlogic/lib/authlogic/random.rb
vendored
33
vendor/plugins/authlogic/lib/authlogic/random.rb
vendored
|
@ -1,33 +0,0 @@
|
|||
module Authlogic
|
||||
# Handles generating random strings. If SecureRandom is installed it will default to this and use it instead. SecureRandom comes with ActiveSupport.
|
||||
# So if you are using this in a rails app you should have this library.
|
||||
module Random
|
||||
extend self
|
||||
|
||||
SecureRandom = (defined?(::SecureRandom) && ::SecureRandom) || (defined?(::ActiveSupport::SecureRandom) && ::ActiveSupport::SecureRandom)
|
||||
|
||||
if SecureRandom
|
||||
def hex_token
|
||||
SecureRandom.hex(64)
|
||||
end
|
||||
|
||||
def friendly_token
|
||||
# use base64url as defined by RFC4648
|
||||
SecureRandom.base64(15).tr('+/=', '').strip.delete("\n")
|
||||
end
|
||||
else
|
||||
def hex_token
|
||||
Authlogic::CryptoProviders::Sha512.encrypt(Time.now.to_s + (1..10).collect{ rand.to_s }.join)
|
||||
end
|
||||
|
||||
FRIENDLY_CHARS = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
|
||||
|
||||
def friendly_token
|
||||
newpass = ""
|
||||
1.upto(20) { |i| newpass << FRIENDLY_CHARS[rand(FRIENDLY_CHARS.size-1)] }
|
||||
newpass
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
25
vendor/plugins/authlogic/lib/authlogic/regex.rb
vendored
25
vendor/plugins/authlogic/lib/authlogic/regex.rb
vendored
|
@ -1,25 +0,0 @@
|
|||
module Authlogic
|
||||
# This is a module the contains regular expressions used throughout Authlogic. The point of extracting
|
||||
# them out into their own module is to make them easily available to you for other uses. Ex:
|
||||
#
|
||||
# validates_format_of :my_email_field, :with => Authlogic::Regex.email
|
||||
module Regex
|
||||
# A general email regular expression. It allows top level domains (TLD) to be from 2 - 4 in length, any
|
||||
# TLD longer than that must be manually specified. The decisions behind this regular expression were made
|
||||
# by reading this website: http://www.regular-expressions.info/email.html, which is an excellent resource
|
||||
# for regular expressions.
|
||||
def self.email
|
||||
return @email_regex if @email_regex
|
||||
email_name_regex = '[A-Z0-9_\.%\+\-]+'
|
||||
domain_head_regex = '(?:[A-Z0-9\-]+\.)+'
|
||||
domain_tld_regex = '(?:[A-Z]{2,4}|museum|travel)'
|
||||
@email_regex = /^#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}$/i
|
||||
end
|
||||
|
||||
# A simple regular expression that only allows for letters, numbers, spaces, and .-_@. Just a standard login / username
|
||||
# regular expression.
|
||||
def self.login
|
||||
/\A\w[\w\.+\-_@ ]+$/
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,58 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# 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.
|
||||
module Activation
|
||||
class NotActivatedError < ::StandardError # :nodoc:
|
||||
def initialize(session)
|
||||
super("You must activate the Authlogic::Session::Base.controller with a controller object before creating objects")
|
||||
end
|
||||
end
|
||||
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend ClassMethods
|
||||
include InstanceMethods
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# 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.
|
||||
def activated?
|
||||
!controller.nil?
|
||||
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.
|
||||
def controller=(value)
|
||||
Thread.current[:authlogic_controller] = value
|
||||
end
|
||||
|
||||
# The current controller object
|
||||
def controller
|
||||
Thread.current[:authlogic_controller]
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
# Making sure we are activated before we start creating objects
|
||||
def initialize(*args)
|
||||
raise NotActivatedError.new(self) unless self.class.activated?
|
||||
super
|
||||
end
|
||||
|
||||
private
|
||||
def controller
|
||||
self.class.controller
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,64 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# 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.
|
||||
module ActiveRecordTrickery
|
||||
def self.included(klass)
|
||||
klass.extend ClassMethods
|
||||
klass.send(:include, InstanceMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# How to name the attributes of Authlogic, works JUST LIKE ActiveRecord, but instead it uses the following
|
||||
# namespace:
|
||||
#
|
||||
# authlogic.attributes.user_session.login
|
||||
def human_attribute_name(attribute_key_name, options = {})
|
||||
options[:count] ||= 1
|
||||
options[:default] ||= attribute_key_name.to_s.humanize
|
||||
I18n.t("attributes.#{name.underscore}.#{attribute_key_name}", options)
|
||||
end
|
||||
|
||||
# How to name the class, works JUST LIKE ActiveRecord, except it uses the following namespace:
|
||||
#
|
||||
# authlogic.models.user_session
|
||||
def human_name(*args)
|
||||
I18n.t("models.#{name.underscore}", {:count => 1, :default => name.humanize})
|
||||
end
|
||||
|
||||
# For rails < 2.3, mispelled
|
||||
def self_and_descendents_from_active_record
|
||||
[self]
|
||||
end
|
||||
|
||||
# For rails >= 2.3, mispelling fixed
|
||||
def self_and_descendants_from_active_record
|
||||
[self]
|
||||
end
|
||||
|
||||
# For rails >= 3.0
|
||||
def model_name
|
||||
if defined?(::ActiveModel)
|
||||
::ActiveModel::Name.new(self)
|
||||
else
|
||||
::ActiveSupport::ModelName.new(self.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
# Don't use this yourself, this is to just trick some of the helpers since this is the method it calls.
|
||||
def new_record?
|
||||
new_session?
|
||||
end
|
||||
|
||||
# For rails >= 3.0
|
||||
def to_model
|
||||
self
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,37 +0,0 @@
|
|||
module Authlogic
|
||||
module Session # :nodoc:
|
||||
# This is the base class Authlogic, where all modules are included. For information on functiionality see the various
|
||||
# sub modules.
|
||||
class Base
|
||||
include Foundation
|
||||
include Callbacks
|
||||
|
||||
# Included first so that the session resets itself to nil
|
||||
include Timeout
|
||||
|
||||
# Included in a specific order so they are tried in this order when persisting
|
||||
include Params
|
||||
include Cookies
|
||||
include Session
|
||||
include HttpAuth
|
||||
|
||||
# Included in a specific order so magic states gets ran after a record is found
|
||||
include Password
|
||||
include UnauthorizedRecord
|
||||
include MagicStates
|
||||
|
||||
include Activation
|
||||
include ActiveRecordTrickery
|
||||
include BruteForceProtection
|
||||
include Existence
|
||||
include Klass
|
||||
include MagicColumns
|
||||
include PerishableToken
|
||||
include Persistence
|
||||
include Scopes
|
||||
include Id
|
||||
include Validation
|
||||
include PriorityRecord
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,96 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# 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 hasing 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
|
||||
module BruteForceProtection
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
include InstanceMethods
|
||||
validate :reset_failed_login_count, :if => :reset_failed_login_count?
|
||||
validate :validate_failed_logins, :if => :being_brute_force_protected?
|
||||
end
|
||||
end
|
||||
|
||||
# Configuration for the brute force protection feature.
|
||||
module Config
|
||||
# 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.
|
||||
#
|
||||
# * <tt>Default:</tt> 50
|
||||
# * <tt>Accepts:</tt> Integer, set to 0 to disable
|
||||
def consecutive_failed_logins_limit(value = nil)
|
||||
rw_config(:consecutive_failed_logins_limit, value, 50)
|
||||
end
|
||||
alias_method :consecutive_failed_logins_limit=, :consecutive_failed_logins_limit
|
||||
|
||||
# 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.
|
||||
#
|
||||
# * <tt>Default:</tt> 2.hours
|
||||
# * <tt>Accepts:</tt> Fixnum, set to 0 for permanent ban
|
||||
def failed_login_ban_for(value = nil)
|
||||
rw_config(:failed_login_ban_for, (!value.nil? && value) || value, 2.hours.to_i)
|
||||
end
|
||||
alias_method :failed_login_ban_for=, :failed_login_ban_for
|
||||
end
|
||||
|
||||
# The methods available for an Authlogic::Session::Base object that make up the brute force protection feature.
|
||||
module InstanceMethods
|
||||
# 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.
|
||||
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
|
||||
|
||||
private
|
||||
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
|
||||
|
||||
def reset_failed_login_count?
|
||||
exceeded_failed_logins_limit? && !being_brute_force_protected?
|
||||
end
|
||||
|
||||
def reset_failed_login_count
|
||||
attempted_record.failed_login_count = 0
|
||||
end
|
||||
|
||||
def validate_failed_logins
|
||||
errors.clear # Clear all other error messages, as they are irrelevant at this point and can only provide additional information that is not needed
|
||||
errors.add(:base, I18n.t(
|
||||
'error_messages.consecutive_failed_logins_limit_exceeded',
|
||||
:default => "Consecutive failed logins limit exceeded, account has been" + (failed_login_ban_for == 0 ? "" : " temporarily") + " disabled."
|
||||
))
|
||||
end
|
||||
|
||||
def consecutive_failed_logins_limit
|
||||
self.class.consecutive_failed_logins_limit
|
||||
end
|
||||
|
||||
def failed_login_ban_for
|
||||
self.class.failed_login_ban_for
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,99 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Between these callsbacks 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.changed?]
|
||||
#
|
||||
# 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.changed?]
|
||||
#
|
||||
# before_save
|
||||
# before_create
|
||||
# before_update
|
||||
# after_update
|
||||
# after_create
|
||||
# after_save
|
||||
# [save record if record.changed?]
|
||||
#
|
||||
# before_destroy
|
||||
# [save record if record.changed?]
|
||||
# destroy
|
||||
# after_destroy
|
||||
#
|
||||
# Notice the "save record if changed?" 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.
|
||||
module Callbacks
|
||||
METHODS = [
|
||||
"before_persisting", "persist", "after_persisting",
|
||||
"before_validation", "before_validation_on_create", "before_validation_on_update", "validate",
|
||||
"after_validation_on_update", "after_validation_on_create", "after_validation",
|
||||
"before_save", "before_create", "before_update", "after_update", "after_create", "after_save",
|
||||
"before_destroy", "after_destroy"
|
||||
]
|
||||
|
||||
def self.included(base) #:nodoc:
|
||||
base.send :include, ActiveSupport::Callbacks
|
||||
base.define_callbacks *METHODS
|
||||
|
||||
# If Rails 3, support the new callback syntax
|
||||
if base.send(base.respond_to?(:singleton_class) ? :singleton_class : :metaclass).method_defined?(:set_callback)
|
||||
METHODS.each do |method|
|
||||
base.class_eval <<-"end_eval", __FILE__, __LINE__
|
||||
def self.#{method}(*methods, &block)
|
||||
set_callback :#{method}, *methods, &block
|
||||
end
|
||||
end_eval
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
METHODS.each do |method|
|
||||
class_eval <<-"end_eval", __FILE__, __LINE__
|
||||
def #{method}
|
||||
run_callbacks(:#{method}) { |result, object| result == false }
|
||||
end
|
||||
end_eval
|
||||
end
|
||||
|
||||
def persist
|
||||
run_callbacks(:persist) { |result, object| result == true }
|
||||
end
|
||||
|
||||
def save_record(alternate_record = nil)
|
||||
r = alternate_record || record
|
||||
r.save_without_session_maintenance(:validate => false) if r && r.changed? && !r.readonly?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,130 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Handles all authentication that deals with cookies, such as persisting, saving, and destroying.
|
||||
module Cookies
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
include InstanceMethods
|
||||
persist :persist_by_cookie
|
||||
after_save :save_cookie
|
||||
after_destroy :destroy_cookie
|
||||
end
|
||||
end
|
||||
|
||||
# Configuration for the cookie feature set.
|
||||
module Config
|
||||
# The name of the cookie or the key in the cookies hash. Be sure and use a unique name. If you have multiple sessions and they use the same cookie it will cause problems.
|
||||
# Also, if a id is set it will be inserted into the beginning of the string. Exmaple:
|
||||
#
|
||||
# session = UserSession.new
|
||||
# session.cookie_key => "user_credentials"
|
||||
#
|
||||
# session = UserSession.new(:super_high_secret)
|
||||
# session.cookie_key => "super_high_secret_user_credentials"
|
||||
#
|
||||
# * <tt>Default:</tt> "#{guessed_klass_name.underscore}_credentials"
|
||||
# * <tt>Accepts:</tt> String
|
||||
def cookie_key(value = nil)
|
||||
rw_config(:cookie_key, value, "#{guessed_klass_name.underscore}_credentials")
|
||||
end
|
||||
alias_method :cookie_key=, :cookie_key
|
||||
|
||||
# If sessions should be remembered by default or not.
|
||||
#
|
||||
# * <tt>Default:</tt> false
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def remember_me(value = nil)
|
||||
rw_config(:remember_me, value, false)
|
||||
end
|
||||
alias_method :remember_me=, :remember_me
|
||||
|
||||
# The length of time until the cookie expires.
|
||||
#
|
||||
# * <tt>Default:</tt> 3.months
|
||||
# * <tt>Accepts:</tt> Integer, length of time in seconds, such as 60 or 3.months
|
||||
def remember_me_for(value = :_read)
|
||||
rw_config(:remember_me_for, value, 3.months, :_read)
|
||||
end
|
||||
alias_method :remember_me_for=, :remember_me_for
|
||||
end
|
||||
|
||||
# The methods available for an Authlogic::Session::Base object that make up the cookie feature set.
|
||||
module InstanceMethods
|
||||
# Allows you to set the remember_me option when passing credentials.
|
||||
def credentials=(value)
|
||||
super
|
||||
values = value.is_a?(Array) ? value : [value]
|
||||
case values.first
|
||||
when Hash
|
||||
self.remember_me = values.first.with_indifferent_access[:remember_me] if values.first.with_indifferent_access.key?(:remember_me)
|
||||
else
|
||||
r = values.find { |value| value.is_a?(TrueClass) || value.is_a?(FalseClass) }
|
||||
self.remember_me = r if !r.nil?
|
||||
end
|
||||
end
|
||||
|
||||
# Is the cookie going to expire after the session is over, or will it stick around?
|
||||
def remember_me
|
||||
return @remember_me if defined?(@remember_me)
|
||||
@remember_me = self.class.remember_me
|
||||
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".
|
||||
def remember_me=(value)
|
||||
@remember_me = value
|
||||
end
|
||||
|
||||
# See remember_me
|
||||
def remember_me?
|
||||
remember_me == true || remember_me == "true" || remember_me == "1"
|
||||
end
|
||||
|
||||
# How long to remember the user if remember_me is true. This is based on the class level configuration: remember_me_for
|
||||
def remember_me_for
|
||||
return unless remember_me?
|
||||
self.class.remember_me_for
|
||||
end
|
||||
|
||||
# When to expire the cookie. See remember_me_for configuration option to change this.
|
||||
def remember_me_until
|
||||
return unless remember_me?
|
||||
remember_me_for.from_now
|
||||
end
|
||||
|
||||
private
|
||||
def cookie_key
|
||||
build_key(self.class.cookie_key)
|
||||
end
|
||||
|
||||
def cookie_credentials
|
||||
controller.cookies[cookie_key] && controller.cookies[cookie_key].split("::")
|
||||
end
|
||||
|
||||
# Tries to validate the session from information in the cookie
|
||||
def persist_by_cookie
|
||||
persistence_token, record_id = cookie_credentials
|
||||
if !persistence_token.nil?
|
||||
record = record_id.nil? ? search_for_record("find_by_persistence_token", persistence_token) : search_for_record("find_by_#{klass.primary_key}", record_id)
|
||||
self.unauthorized_record = record if record && record.persistence_token == persistence_token
|
||||
valid?
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def save_cookie
|
||||
controller.cookies[cookie_key] = {
|
||||
:value => "#{record.persistence_token}::#{record.send(record.class.primary_key)}",
|
||||
:expires => remember_me_until,
|
||||
:domain => controller.cookie_domain
|
||||
}
|
||||
end
|
||||
|
||||
def destroy_cookie
|
||||
controller.cookies.delete cookie_key, :domain => controller.cookie_domain
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,93 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Provides methods to create and destroy objects. Basically controls their "existence".
|
||||
module Existence
|
||||
class SessionInvalidError < ::StandardError # :nodoc:
|
||||
def initialize(session)
|
||||
super("Your session is invalid and has the following errors: #{session.errors.full_messages.to_sentence}")
|
||||
end
|
||||
end
|
||||
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend ClassMethods
|
||||
include InstanceMethods
|
||||
attr_accessor :new_session, :record
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# A convenince method. The same as:
|
||||
#
|
||||
# session = UserSession.new(*args)
|
||||
# session.save
|
||||
#
|
||||
# Instead you can do:
|
||||
#
|
||||
# UserSession.create(*args)
|
||||
def create(*args, &block)
|
||||
session = new(*args)
|
||||
session.save(&block)
|
||||
session
|
||||
end
|
||||
|
||||
# Same as create but calls create!, which raises an exception when validation fails.
|
||||
def create!(*args)
|
||||
session = new(*args)
|
||||
session.save!
|
||||
session
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
# Clears all errors and the associated record, you should call this terminate a session, thus requring
|
||||
# the user to authenticate again if it is needed.
|
||||
def destroy
|
||||
before_destroy
|
||||
save_record
|
||||
errors.clear
|
||||
@record = nil
|
||||
after_destroy
|
||||
true
|
||||
end
|
||||
|
||||
# Returns true if the session is new, meaning no action has been taken on it and a successful save
|
||||
# has not taken place.
|
||||
def new_session?
|
||||
new_session != false
|
||||
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 erorrs will be stored in the errors object.
|
||||
def save(&block)
|
||||
result = nil
|
||||
if valid?
|
||||
self.record = attempted_record
|
||||
|
||||
before_save
|
||||
new_session? ? before_create : before_update
|
||||
new_session? ? after_create : after_update
|
||||
after_save
|
||||
|
||||
save_record
|
||||
self.new_session = false
|
||||
result = true
|
||||
else
|
||||
result = false
|
||||
end
|
||||
|
||||
yield result if block_given?
|
||||
result
|
||||
end
|
||||
|
||||
# Same as save but raises an exception of validation errors when validation fails
|
||||
def save!
|
||||
result = save
|
||||
raise SessionInvalidError.new(self) unless result
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,71 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Sort of like an interface, it sets the foundation for the class, such as the required methods. This also allows
|
||||
# other modules to overwrite methods and call super on them. It's also a place to put "utility" methods used
|
||||
# throughout Authlogic.
|
||||
module Foundation
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend ClassMethods
|
||||
include InstanceMethods
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
private
|
||||
def rw_config(key, value, default_value = nil, read_value = nil)
|
||||
if value == read_value
|
||||
return read_inheritable_attribute(key) if inheritable_attributes.include?(key)
|
||||
write_inheritable_attribute(key, default_value)
|
||||
else
|
||||
write_inheritable_attribute(key, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def initialize(*args)
|
||||
self.credentials = args
|
||||
end
|
||||
|
||||
# The credentials you passed to create your session. See credentials= for more info.
|
||||
def credentials
|
||||
[]
|
||||
end
|
||||
|
||||
# Set your credentials before you save your session. You can pass a hash of credentials:
|
||||
#
|
||||
# session.credentials = {:login => "my login", :password => "my password", :remember_me => true}
|
||||
#
|
||||
# or you can pass an array of objects:
|
||||
#
|
||||
# session.credentials = [my_user_object, true]
|
||||
#
|
||||
# and if you need to set an id, just pass it last. This value need be the last item in the array you pass, since the id is something that
|
||||
# you control yourself, it should never be set from a hash or a form. Examples:
|
||||
#
|
||||
# session.credentials = [{:login => "my login", :password => "my password", :remember_me => true}, :my_id]
|
||||
# session.credentials = [my_user_object, true, :my_id]
|
||||
def credentials=(values)
|
||||
end
|
||||
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{credentials.blank? ? "no credentials provided" : credentials.inspect}>"
|
||||
end
|
||||
|
||||
def persisted?
|
||||
!(new_record? || destroyed?)
|
||||
end
|
||||
|
||||
def to_key
|
||||
new_record? ? nil : [ self.send(self.class.primary_key) ]
|
||||
end
|
||||
|
||||
private
|
||||
def build_key(last_part)
|
||||
last_part
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,58 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# 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 always use the single
|
||||
# access token. See Authlogic::Session::Params for more info.
|
||||
module HttpAuth
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
include InstanceMethods
|
||||
persist :persist_by_http_auth, :if => :persist_by_http_auth?
|
||||
end
|
||||
end
|
||||
|
||||
# Configuration for the HTTP basic auth feature of Authlogic.
|
||||
module Config
|
||||
# Do you want to allow your users to log in via HTTP basic auth?
|
||||
#
|
||||
# I recommend keeping this enabled. The only time I feel this should be disabled is if you are not comfortable
|
||||
# having your users provide their raw username and password. Whatever the reason, you can disable it here.
|
||||
#
|
||||
# * <tt>Default:</tt> true
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def allow_http_basic_auth(value = nil)
|
||||
rw_config(:allow_http_basic_auth, value, true)
|
||||
end
|
||||
alias_method :allow_http_basic_auth=, :allow_http_basic_auth
|
||||
end
|
||||
|
||||
# Instance methods for the HTTP basic auth feature of authlogic.
|
||||
module InstanceMethods
|
||||
private
|
||||
def persist_by_http_auth?
|
||||
allow_http_basic_auth? && login_field && password_field
|
||||
end
|
||||
|
||||
def persist_by_http_auth
|
||||
controller.authenticate_with_http_basic do |login, password|
|
||||
if !login.blank? && !password.blank?
|
||||
send("#{login_field}=", login)
|
||||
send("#{password_field}=", password)
|
||||
return valid?
|
||||
end
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def allow_http_basic_auth?
|
||||
self.class.allow_http_basic_auth == true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,41 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Allows you to separate sessions with an id, ultimately letting you create multiple sessions for the same user.
|
||||
module Id
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
attr_writer :id
|
||||
end
|
||||
end
|
||||
|
||||
# Setting the id if it is passed in the credentials.
|
||||
def credentials=(value)
|
||||
super
|
||||
values = value.is_a?(Array) ? value : [value]
|
||||
self.id = values.last if values.last.is_a?(Symbol)
|
||||
end
|
||||
|
||||
# Allows you to set a unique identifier for your session, so that you can have more than 1 session at a time.
|
||||
# A good example when this might be needed is when you want to have 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. Similar to me.com. This requires 2 user sessions. Just use an id for the "secure" session and you should be good.
|
||||
#
|
||||
# You can set the id during initialization (see initialize for more information), or as an attribute:
|
||||
#
|
||||
# session.id = :my_id
|
||||
#
|
||||
# Just be sure and set your id before you save your session.
|
||||
#
|
||||
# Lastly, to retrieve your session with the id check out the find class method.
|
||||
def id
|
||||
@id
|
||||
end
|
||||
|
||||
private
|
||||
# Used for things like cookie_key, session_key, etc.
|
||||
def build_key(last_part)
|
||||
[id, super].compact.join("_")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,78 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Handles authenticating via a traditional username and password.
|
||||
module Klass
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
include InstanceMethods
|
||||
|
||||
class << self
|
||||
attr_accessor :configured_klass_methods
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Config
|
||||
# Lets you change which model to use for authentication.
|
||||
#
|
||||
# * <tt>Default:</tt> inferred from the class name. UserSession would automatically try User
|
||||
# * <tt>Accepts:</tt> an ActiveRecord class
|
||||
def authenticate_with(klass)
|
||||
@klass_name = klass.name
|
||||
@klass = klass
|
||||
end
|
||||
alias_method :authenticate_with=, :authenticate_with
|
||||
|
||||
# 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.
|
||||
def klass
|
||||
@klass ||=
|
||||
if klass_name
|
||||
klass_name.constantize
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Same as klass, just returns a string instead of the actual constant.
|
||||
def klass_name
|
||||
@klass_name ||= guessed_klass_name
|
||||
end
|
||||
|
||||
# The string of the model name class guessed from the actual session class name.
|
||||
def guessed_klass_name
|
||||
guessed_name = name.scan(/(.*)Session/)[0]
|
||||
guessed_name[0] if guessed_name
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
# Creating an alias method for the "record" method based on the klass name, so that we can do:
|
||||
#
|
||||
# session.user
|
||||
#
|
||||
# instead of:
|
||||
#
|
||||
# session.record
|
||||
def initialize(*args)
|
||||
if !self.class.configured_klass_methods
|
||||
self.class.send(:alias_method, klass_name.demodulize.underscore.to_sym, :record)
|
||||
self.class.configured_klass_methods = true
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
private
|
||||
def klass
|
||||
self.class.klass
|
||||
end
|
||||
|
||||
def klass_name
|
||||
self.class.klass_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,95 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Just like ActiveRecord has "magic" columns, such as: created_at and updated_at. Authlogic has its own "magic" columns too:
|
||||
#
|
||||
# Column name Description
|
||||
# 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 Authlogic::Session::BruteForceProtection and the consecutive_failed_logins_limit config option for more 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 remote_ip when an explicit login is made.
|
||||
# last_login_ip Updates with the value of current_login_ip before it is reset.
|
||||
module MagicColumns
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
include InstanceMethods
|
||||
after_persisting :set_last_request_at, :if => :set_last_request_at?
|
||||
validate :increase_failed_login_count
|
||||
before_save :update_info
|
||||
before_save :set_last_request_at, :if => :set_last_request_at?
|
||||
end
|
||||
end
|
||||
|
||||
# Configuration for the magic columns feature.
|
||||
module Config
|
||||
# Every time a session is found the last_request_at field for that record is updatd 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 threashold. Set this to 1.minute.
|
||||
# Once a minute has passed in between requests the field will be updated.
|
||||
#
|
||||
# * <tt>Default:</tt> 0
|
||||
# * <tt>Accepts:</tt> integer representing time in seconds
|
||||
def last_request_at_threshold(value = nil)
|
||||
rw_config(:last_request_at_threshold, value, 0)
|
||||
end
|
||||
alias_method :last_request_at_threshold=, :last_request_at_threshold
|
||||
end
|
||||
|
||||
# The methods available for an Authlogic::Session::Base object that make up the magic columns feature.
|
||||
module InstanceMethods
|
||||
private
|
||||
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
|
||||
|
||||
def update_info
|
||||
record.login_count = (record.login_count.blank? ? 1 : record.login_count + 1) if record.respond_to?(:login_count)
|
||||
record.failed_login_count = 0 if record.respond_to?(:failed_login_count)
|
||||
|
||||
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 = klass.default_timezone == :utc ? Time.now.utc : Time.now
|
||||
end
|
||||
|
||||
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.remote_ip
|
||||
end
|
||||
end
|
||||
|
||||
# This method lets authlogic know whether it should allow the last_request_at field to be updated
|
||||
# with the current time (Time.now). One thing to note here is that it also checks for the existence of a
|
||||
# last_request_update_allowed? method in your controller. This allows you to control this method pragmatically
|
||||
# in your controller.
|
||||
#
|
||||
# For example, what if you had a javascript function that polled the server updating how much time is left in their
|
||||
# session before it times out. Obviously you would want to ignore this request, because then the user would never time out.
|
||||
# So you can do something like this in your controller:
|
||||
#
|
||||
# def last_request_update_allowed?
|
||||
# action_name =! "update_session_time_left"
|
||||
# end
|
||||
#
|
||||
# You can do whatever you want with that method.
|
||||
def set_last_request_at? # :doc:
|
||||
return false if !record || !klass.column_names.include?("last_request_at")
|
||||
return controller.last_request_update_allowed? if controller.responds_to_last_request_update_allowed?
|
||||
record.last_request_at.blank? || last_request_at_threshold.to_i.seconds.ago >= record.last_request_at
|
||||
end
|
||||
|
||||
def set_last_request_at
|
||||
record.last_request_at = klass.default_timezone == :utc ? Time.now.utc : Time.now
|
||||
end
|
||||
|
||||
def last_request_at_threshold
|
||||
self.class.last_request_at_threshold
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,59 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# 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 conirmed?
|
||||
#
|
||||
# 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.
|
||||
module MagicStates
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
include InstanceMethods
|
||||
validate :validate_magic_states, :unless => :disable_magic_states?
|
||||
end
|
||||
end
|
||||
|
||||
# Configuration for the magic states feature.
|
||||
module Config
|
||||
# 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.
|
||||
#
|
||||
# * <tt>Default:</tt> false
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def disable_magic_states(value = nil)
|
||||
rw_config(:disable_magic_states, value, false)
|
||||
end
|
||||
alias_method :disable_magic_states=, :disable_magic_states
|
||||
end
|
||||
|
||||
# The methods available for an Authlogic::Session::Base object that make up the magic states feature.
|
||||
module InstanceMethods
|
||||
private
|
||||
def disable_magic_states?
|
||||
self.class.disable_magic_states == true
|
||||
end
|
||||
|
||||
def validate_magic_states
|
||||
return true if attempted_record.nil?
|
||||
[:active, :approved, :confirmed].each do |required_status|
|
||||
if attempted_record.respond_to?("#{required_status}?") && !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
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,101 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# 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.
|
||||
module Params
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
include InstanceMethods
|
||||
attr_accessor :single_access
|
||||
persist :persist_by_params
|
||||
end
|
||||
end
|
||||
|
||||
# Configuration for the params / single access feature.
|
||||
module Config
|
||||
# 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.
|
||||
#
|
||||
# * <tt>Default:</tt> cookie_key
|
||||
# * <tt>Accepts:</tt> String
|
||||
def params_key(value = nil)
|
||||
rw_config(:params_key, value, cookie_key)
|
||||
end
|
||||
alias_method :params_key=, :params_key
|
||||
|
||||
# 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.
|
||||
#
|
||||
# * <tt>Default:</tt> ["application/rss+xml", "application/atom+xml"]
|
||||
# * <tt>Accepts:</tt> String of a request type, or :all or :any to allow single access authentication for any and all request types
|
||||
def single_access_allowed_request_types(value = nil)
|
||||
rw_config(:single_access_allowed_request_types, value, ["application/rss+xml", "application/atom+xml"])
|
||||
end
|
||||
alias_method :single_access_allowed_request_types=, :single_access_allowed_request_types
|
||||
end
|
||||
|
||||
# The methods available for an Authlogic::Session::Base object that make up the params / single access feature.
|
||||
module InstanceMethods
|
||||
private
|
||||
def persist_by_params
|
||||
return false if !params_enabled?
|
||||
self.unauthorized_record = search_for_record("find_by_single_access_token", params_credentials)
|
||||
self.single_access = valid?
|
||||
end
|
||||
|
||||
def params_enabled?
|
||||
return false if !params_credentials || !klass.column_names.include?("single_access_token")
|
||||
return controller.single_access_allowed? if controller.responds_to_single_access_allowed?
|
||||
|
||||
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
|
||||
[:all, :any].include?(single_access_allowed_request_types)
|
||||
end
|
||||
end
|
||||
|
||||
def params_key
|
||||
build_key(self.class.params_key)
|
||||
end
|
||||
|
||||
def single_access?
|
||||
single_access == true
|
||||
end
|
||||
|
||||
def single_access_allowed_request_types
|
||||
self.class.single_access_allowed_request_types
|
||||
end
|
||||
|
||||
def params_credentials
|
||||
controller.params[params_key]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,240 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Handles authenticating via a traditional username and password.
|
||||
module Password
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
include InstanceMethods
|
||||
validate :validate_by_password, :if => :authenticating_with_password?
|
||||
|
||||
class << self
|
||||
attr_accessor :configured_password_methods
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Password configuration
|
||||
module Config
|
||||
# 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.
|
||||
#
|
||||
# Let's say you have a UserSession that is authenticating a User. By default UserSession will call User.find_by_login(login).
|
||||
# You can change what method UserSession calls by specifying it here. Then 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.
|
||||
#
|
||||
# * <tt>Default:</tt> "find_by_smart_case_login_field"
|
||||
# * <tt>Accepts:</tt> Symbol or String
|
||||
def find_by_login_method(value = nil)
|
||||
rw_config(:find_by_login_method, value, "find_by_smart_case_login_field")
|
||||
end
|
||||
alias_method :find_by_login_method=, :find_by_login_method
|
||||
|
||||
# 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
|
||||
# http://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.
|
||||
#
|
||||
# * <tt>Default</tt> false
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def generalize_credentials_error_messages(value = nil)
|
||||
rw_config(:generalize_credentials_error_messages, value, false)
|
||||
end
|
||||
alias_method :generalize_credentials_error_messages=, :generalize_credentials_error_messages
|
||||
|
||||
# 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 compeltely doable. See the find_by_login_method configuration
|
||||
# option for more details.
|
||||
#
|
||||
# * <tt>Default:</tt> klass.login_field || klass.email_field
|
||||
# * <tt>Accepts:</tt> Symbol or String
|
||||
def login_field(value = nil)
|
||||
rw_config(:login_field, value, klass.login_field || klass.email_field)
|
||||
end
|
||||
alias_method :login_field=, :login_field
|
||||
|
||||
# Works exactly like login_field, but for the password instead. Returns :password if a login_field exists.
|
||||
#
|
||||
# * <tt>Default:</tt> :password
|
||||
# * <tt>Accepts:</tt> Symbol or String
|
||||
def password_field(value = nil)
|
||||
rw_config(:password_field, value, login_field && :password)
|
||||
end
|
||||
alias_method :password_field=, :password_field
|
||||
|
||||
# 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.
|
||||
#
|
||||
# * <tt>Default:</tt> "valid_password?"
|
||||
# * <tt>Accepts:</tt> Symbol or String
|
||||
def verify_password_method(value = nil)
|
||||
rw_config(:verify_password_method, value, "valid_password?")
|
||||
end
|
||||
alias_method :verify_password_method=, :verify_password_method
|
||||
end
|
||||
|
||||
# Password related instance methods
|
||||
module InstanceMethods
|
||||
def initialize(*args)
|
||||
if !self.class.configured_password_methods
|
||||
if login_field
|
||||
self.class.send(:attr_writer, login_field) if !respond_to?("#{login_field}=")
|
||||
self.class.send(:attr_reader, login_field) if !respond_to?(login_field)
|
||||
end
|
||||
|
||||
if password_field
|
||||
self.class.send(:attr_writer, password_field) if !respond_to?("#{password_field}=")
|
||||
self.class.send(:define_method, password_field) {} if !respond_to?(password_field)
|
||||
|
||||
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
||||
private
|
||||
# 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.
|
||||
def protected_#{password_field}
|
||||
@#{password_field}
|
||||
end
|
||||
end_eval
|
||||
end
|
||||
|
||||
self.class.configured_password_methods = true
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
# Returns the login_field / password_field credentials combination in hash form.
|
||||
def credentials
|
||||
if authenticating_with_password?
|
||||
details = {}
|
||||
details[login_field.to_sym] = send(login_field)
|
||||
details[password_field.to_sym] = "<protected>"
|
||||
details
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# Accepts the login_field / password_field credentials combination in hash form.
|
||||
def credentials=(value)
|
||||
super
|
||||
values = value.is_a?(Array) ? value : [value]
|
||||
if values.first.is_a?(Hash)
|
||||
values.first.with_indifferent_access.slice(login_field, password_field).each do |field, value|
|
||||
next if value.blank?
|
||||
send("#{field}=", value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def invalid_password?
|
||||
invalid_password == true
|
||||
end
|
||||
|
||||
private
|
||||
def authenticating_with_password?
|
||||
login_field && (!send(login_field).nil? || !send("protected_#{password_field}").nil?)
|
||||
end
|
||||
|
||||
def validate_by_password
|
||||
self.invalid_password = false
|
||||
|
||||
errors.add(login_field, I18n.t('error_messages.login_blank', :default => "cannot be blank")) if send(login_field).blank?
|
||||
errors.add(password_field, I18n.t('error_messages.password_blank', :default => "cannot be blank")) if send("protected_#{password_field}").blank?
|
||||
return if errors.count > 0
|
||||
|
||||
self.attempted_record = search_for_record(find_by_login_method, send(login_field))
|
||||
if attempted_record.blank?
|
||||
generalize_credentials_error_messages? ?
|
||||
add_general_credentials_error :
|
||||
errors.add(login_field, I18n.t('error_messages.login_not_found', :default => "is not valid"))
|
||||
return
|
||||
end
|
||||
|
||||
if !attempted_record.send(verify_password_method, send("protected_#{password_field}"))
|
||||
self.invalid_password = true
|
||||
generalize_credentials_error_messages? ?
|
||||
add_general_credentials_error :
|
||||
errors.add(password_field, I18n.t('error_messages.password_invalid', :default => "is not valid"))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
def invalid_password
|
||||
@invalid_password
|
||||
end
|
||||
|
||||
def invalid_password=(value)
|
||||
@invalid_password = value
|
||||
end
|
||||
|
||||
def find_by_login_method
|
||||
self.class.find_by_login_method
|
||||
end
|
||||
|
||||
def login_field
|
||||
self.class.login_field
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
def generalize_credentials_error_messages?
|
||||
self.class.generalize_credentials_error_messages
|
||||
end
|
||||
|
||||
def password_field
|
||||
self.class.password_field
|
||||
end
|
||||
|
||||
def verify_password_method
|
||||
self.class.verify_password_method
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,18 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# 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.
|
||||
module PerishableToken
|
||||
def self.included(klass)
|
||||
klass.after_save :reset_perishable_token!
|
||||
end
|
||||
|
||||
private
|
||||
def reset_perishable_token!
|
||||
record.reset_perishable_token if record.respond_to?(:reset_perishable_token) && !record.disable_perishable_token_maintenance?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,70 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Responsible for allowing you to persist your sessions.
|
||||
module Persistence
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend ClassMethods
|
||||
include InstanceMethods
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# 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.
|
||||
def find(id = nil, priority_record = nil)
|
||||
session = new({:priority_record => priority_record}, id)
|
||||
session.priority_record = priority_record
|
||||
if session.persisting?
|
||||
session
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
# Let's you know 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 persis
|
||||
# the session. This is the method that the class level method find uses to ultimately persist the session.
|
||||
def persisting?
|
||||
return true if !record.nil?
|
||||
self.attempted_record = nil
|
||||
before_persisting
|
||||
persist
|
||||
ensure_authentication_attempted
|
||||
if errors.empty? && !attempted_record.nil?
|
||||
self.record = attempted_record
|
||||
after_persisting
|
||||
save_record
|
||||
self.new_session = false
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# The point of this module is to avoid the StaleObjectError raised when lock_version is implemented in ActiveRecord.
|
||||
# We accomplish this by using a "priority record". Meaning this record is used if possible, it gets priority.
|
||||
# This way we don't save a record behind the scenes thus making an object being used stale.
|
||||
module PriorityRecord
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
attr_accessor :priority_record
|
||||
end
|
||||
end
|
||||
|
||||
# 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]
|
||||
def credentials=(value)
|
||||
super
|
||||
values = value.is_a?(Array) ? value : [value]
|
||||
self.priority_record = values[1] if values[1].class < ::ActiveRecord::Base
|
||||
end
|
||||
|
||||
private
|
||||
def attempted_record=(value)
|
||||
value = priority_record if value == priority_record
|
||||
super
|
||||
end
|
||||
|
||||
def save_record(alternate_record = nil)
|
||||
r = alternate_record || record
|
||||
super if r != priority_record
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,101 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Authentication can be scoped, and it's easy, you just need to define how you want to scope everything. This should help you:
|
||||
#
|
||||
# 1. Want to scope by a parent object? Ex: An account has many users. Checkout Authlogic::AuthenticatesMany
|
||||
# 2. Want to scope the validations in your model? Ex: 2 users can have the same login under different accounts. See Authlogic::ActsAsAuthentic::Scope
|
||||
module Scopes # :nodoc:
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend ClassMethods
|
||||
include InstanceMethods
|
||||
attr_writer :scope
|
||||
end
|
||||
end
|
||||
|
||||
# = Scopes
|
||||
module ClassMethods
|
||||
# The current scope set, should be used in the block passed to with_scope.
|
||||
def scope
|
||||
Thread.current[:authlogic_scope]
|
||||
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:
|
||||
#
|
||||
# * <tt>find_options:</tt> any options you can pass into ActiveRecord::Base.find. This is used when trying to find the record.
|
||||
# * <tt>id:</tt> 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 => {:conditions => "account_id = 2"}, :id => "account_2") do
|
||||
# UserSession.find
|
||||
# end
|
||||
#
|
||||
# Eseentially what the above does is scope the searching of the object with the sql you provided. So instead of:
|
||||
#
|
||||
# User.find(:first, :conditions => "login = 'ben'")
|
||||
#
|
||||
# it would be:
|
||||
#
|
||||
# User.find(:first, :conditions => "login = 'ben' and account_id = 2")
|
||||
#
|
||||
# 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
|
||||
def with_scope(options = {}, &block)
|
||||
raise ArgumentError.new("You must provide a block") unless block_given?
|
||||
self.scope = options
|
||||
result = yield
|
||||
self.scope = nil
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
def scope=(value)
|
||||
Thread.current[:authlogic_scope] = value
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
# Setting the scope if it exists upon instantiation.
|
||||
def initialize(*args)
|
||||
self.scope = self.class.scope
|
||||
super
|
||||
end
|
||||
|
||||
# The scope of the current object
|
||||
def scope
|
||||
@scope ||= {}
|
||||
end
|
||||
|
||||
private
|
||||
# Used for things like cookie_key, session_key, etc.
|
||||
def build_key(last_part)
|
||||
[scope[:id], super].compact.join("_")
|
||||
end
|
||||
|
||||
def search_for_record(*args)
|
||||
klass.send(:with_scope, :find => (scope[:find_options] || {})) do
|
||||
klass.send(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,62 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Handles all parts of authentication that deal with sessions. Such as persisting a session and saving / destroy a session.
|
||||
module Session
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
include InstanceMethods
|
||||
persist :persist_by_session
|
||||
after_save :update_session
|
||||
after_destroy :update_session
|
||||
after_persisting :update_session, :unless => :single_access?
|
||||
end
|
||||
end
|
||||
|
||||
# Configuration for the session feature.
|
||||
module Config
|
||||
# Works exactly like cookie_key, but for sessions. See cookie_key for more info.
|
||||
#
|
||||
# * <tt>Default:</tt> cookie_key
|
||||
# * <tt>Accepts:</tt> Symbol or String
|
||||
def session_key(value = nil)
|
||||
rw_config(:session_key, value, cookie_key)
|
||||
end
|
||||
alias_method :session_key=, :session_key
|
||||
end
|
||||
|
||||
# Instance methods for the session feature.
|
||||
module InstanceMethods
|
||||
private
|
||||
# Tries to validate the session from information in the session
|
||||
def persist_by_session
|
||||
persistence_token, record_id = session_credentials
|
||||
if !persistence_token.nil?
|
||||
# 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.
|
||||
record = record_id.nil? ?
|
||||
search_for_record("find_by_persistence_token", persistence_token) :
|
||||
search_for_record("find_by_#{klass.primary_key}", record_id)
|
||||
self.unauthorized_record = record if record && record.persistence_token == persistence_token
|
||||
valid?
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def session_credentials
|
||||
[controller.session[session_key], controller.session["#{session_key}_#{klass.primary_key}"]].compact
|
||||
end
|
||||
|
||||
def session_key
|
||||
build_key(self.class.session_key)
|
||||
end
|
||||
|
||||
def update_session
|
||||
controller.session[session_key] = record && record.persistence_token
|
||||
controller.session["#{session_key}_#{klass.primary_key}"] = record && record.send(record.class.primary_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,82 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# 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:
|
||||
#
|
||||
# 1. Define the timeout threshold:
|
||||
#
|
||||
# acts_as_authentic do |c|
|
||||
# c.logged_in_timeout = 10.minutes # default is 10.minutes
|
||||
# end
|
||||
#
|
||||
# 2. Enable logging out on timeouts
|
||||
#
|
||||
# class UserSession < Authlogic::Session::Base
|
||||
# logout_on_timeout true # default if 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.
|
||||
module Timeout
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend Config
|
||||
include InstanceMethods
|
||||
before_persisting :reset_stale_state
|
||||
after_persisting :enforce_timeout
|
||||
attr_accessor :stale_record
|
||||
end
|
||||
end
|
||||
|
||||
# Configuration for the timeout feature.
|
||||
module Config
|
||||
# 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 users 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 timesout. 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 a object is 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.
|
||||
#
|
||||
# * <tt>Default:</tt> false
|
||||
# * <tt>Accepts:</tt> Boolean
|
||||
def logout_on_timeout(value = nil)
|
||||
rw_config(:logout_on_timeout, value, false)
|
||||
end
|
||||
alias_method :logout_on_timeout=, :logout_on_timeout
|
||||
end
|
||||
|
||||
# Instance methods for the timeout feature.
|
||||
module InstanceMethods
|
||||
# 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.
|
||||
def stale?
|
||||
!stale_record.nil? || (logout_on_timeout? && record && record.logged_out?)
|
||||
end
|
||||
|
||||
private
|
||||
def reset_stale_state
|
||||
self.stale_record = nil
|
||||
end
|
||||
|
||||
def enforce_timeout
|
||||
if stale?
|
||||
self.stale_record = record
|
||||
self.record = nil
|
||||
end
|
||||
end
|
||||
|
||||
def logout_on_timeout?
|
||||
self.class.logout_on_timeout == true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,50 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# 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.
|
||||
module UnauthorizedRecord
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
attr_accessor :unauthorized_record
|
||||
validate :validate_by_unauthorized_record, :if => :authenticating_with_unauthorized_record?
|
||||
end
|
||||
end
|
||||
|
||||
# Returning meaningful credentials
|
||||
def credentials
|
||||
if authenticating_with_unauthorized_record?
|
||||
details = {}
|
||||
details[:unauthorized_record] = "<protected>"
|
||||
details
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# Setting the unauthorized record if it exists in the credentials passed.
|
||||
def credentials=(value)
|
||||
super
|
||||
values = value.is_a?(Array) ? value : [value]
|
||||
self.unauthorized_record = values.first if values.first.class < ::ActiveRecord::Base
|
||||
end
|
||||
|
||||
private
|
||||
def authenticating_with_unauthorized_record?
|
||||
!unauthorized_record.nil?
|
||||
end
|
||||
|
||||
def validate_by_unauthorized_record
|
||||
self.attempted_record = unauthorized_record
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,82 +0,0 @@
|
|||
module Authlogic
|
||||
module Session
|
||||
# Responsible for session validation
|
||||
module Validation
|
||||
# The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses the exact same ActiveRecord errors class. Use it the same way:
|
||||
#
|
||||
# class UserSession
|
||||
# validate :check_if_awesome
|
||||
#
|
||||
# private
|
||||
# def check_if_awesome
|
||||
# errors.add(:login, "must contain awesome") if login && !login.include?("awesome")
|
||||
# errors.add(:base, "You must be awesome to log in") unless attempted_record.awesome?
|
||||
# end
|
||||
# end
|
||||
class Errors < (defined?(::ActiveModel) ? ::ActiveModel::Errors : ::ActiveRecord::Errors)
|
||||
unless defined?(::ActiveModel)
|
||||
def [](key)
|
||||
value = super
|
||||
value.is_a?(Array) ? value : [value].compact
|
||||
end
|
||||
end
|
||||
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.
|
||||
def attempted_record
|
||||
@attempted_record
|
||||
end
|
||||
|
||||
# See attempted_record
|
||||
def attempted_record=(value)
|
||||
@attempted_record = value
|
||||
end
|
||||
|
||||
# The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses the exact same ActiveRecord errors class.
|
||||
# Use it the same way:
|
||||
#
|
||||
# === Example
|
||||
#
|
||||
# class UserSession
|
||||
# before_validation :check_if_awesome
|
||||
#
|
||||
# private
|
||||
# def check_if_awesome
|
||||
# errors.add(:login, "must contain awesome") if login && !login.include?("awesome")
|
||||
# errors.add(:base, "You must be awesome to log in") unless attempted_record.awesome?
|
||||
# end
|
||||
# end
|
||||
def errors
|
||||
@errors ||= Errors.new(self)
|
||||
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.
|
||||
def valid?
|
||||
errors.clear
|
||||
self.attempted_record = nil
|
||||
|
||||
before_validation
|
||||
new_session? ? before_validation_on_create : before_validation_on_update
|
||||
validate
|
||||
ensure_authentication_attempted
|
||||
|
||||
if errors.size == 0
|
||||
new_session? ? after_validation_on_create : after_validation_on_update
|
||||
after_validation
|
||||
end
|
||||
|
||||
save_record(attempted_record)
|
||||
errors.size == 0
|
||||
end
|
||||
|
||||
private
|
||||
def ensure_authentication_attempted
|
||||
errors.add(:base, I18n.t('error_messages.no_authentication_details', :default => "You did not provide any details for authentication.")) if errors.empty? && attempted_record.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
120
vendor/plugins/authlogic/lib/authlogic/test_case.rb
vendored
120
vendor/plugins/authlogic/lib/authlogic/test_case.rb
vendored
|
@ -1,120 +0,0 @@
|
|||
require File.dirname(__FILE__) + "/test_case/rails_request_adapter"
|
||||
require File.dirname(__FILE__) + "/test_case/mock_cookie_jar"
|
||||
require File.dirname(__FILE__) + "/test_case/mock_controller"
|
||||
require File.dirname(__FILE__) + "/test_case/mock_logger"
|
||||
require File.dirname(__FILE__) + "/test_case/mock_request"
|
||||
|
||||
module Authlogic
|
||||
# This module is a collection of methods and classes that help you easily test Authlogic. In fact,
|
||||
# I use these same tools to test the internals of Authlogic.
|
||||
#
|
||||
# === The quick and dirty
|
||||
#
|
||||
# require "authlogic/test_case" # include at the top of test_helper.rb
|
||||
# setup :activate_authlogic # run before tests are executed
|
||||
# UserSession.create(users(:whomever)) # logs a user in
|
||||
#
|
||||
# For a more detailed explanation, see below.
|
||||
#
|
||||
# === Setting up
|
||||
#
|
||||
# Authlogic comes with some simple testing tools. To get these, you need to first require Authlogic's TestCase. If
|
||||
# you are doing this in a rails app, you would require this file at the top of your test_helper.rb file:
|
||||
#
|
||||
# require "authlogic/test_case"
|
||||
#
|
||||
# If you are using Test::Unit::TestCase, the standard testing library that comes with ruby, then you can skip this next part.
|
||||
# If you are not, you need to include the Authlogic::TestCase into your testing suite as follows:
|
||||
#
|
||||
# include Authlogic::TestCase
|
||||
#
|
||||
# Now that everything is ready to go, let's move onto actually testing. Here is the basic idea behind testing:
|
||||
#
|
||||
# Authlogic requires a "connection" to your controller to activate it. In the same manner that ActiveRecord requires a connection to
|
||||
# your database. It can't do anything until it gets connnected. That being said, Authlogic will raise an
|
||||
# Authlogic::Session::Activation::NotActivatedError any time you try to instantiate an object without a "connection".
|
||||
# So before you do anything with Authlogic, you need to activate / connect Authlogic. Let's walk through how to do this in tests:
|
||||
#
|
||||
# === Fixtures / Factories
|
||||
#
|
||||
# Creating users via fixtures / factories is easy. Here's an example of a fixture:
|
||||
#
|
||||
# ben:
|
||||
# email: whatever@whatever.com
|
||||
# password_salt: <%= salt = Authlogic::Random.hex_token %>
|
||||
# crypted_password: <%= Authlogic::CryptoProviders::Sha512.encrypt("benrocks" + salt) %>
|
||||
# persistence_token: <%= Authlogic::Random.hex_token %>
|
||||
# single_access_token: <%= Authlogic::Random.friendly_token %>
|
||||
# perishable_token: <%= Authlogic::Random.friendly_token %>
|
||||
#
|
||||
# Notice the crypted_password value. Just supplement that with whatever crypto provider you are using, if you are not using the default.
|
||||
#
|
||||
# === Functional tests
|
||||
#
|
||||
# Activating Authlogic isn't a problem here, because making a request will activate Authlogic for you. The problem is
|
||||
# logging users in so they can access restricted areas. Solving this is simple, just do this:
|
||||
#
|
||||
# setup :activate_authlogic
|
||||
#
|
||||
# For those of you unfamiliar with TestUnit, the setup method bascially just executes a method before any test is ran.
|
||||
# It is essentially "setting up" your tests.
|
||||
#
|
||||
# Once you have done this, just log users in like usual:
|
||||
#
|
||||
# UserSession.create(users(:whomever))
|
||||
# # access my restricted area here
|
||||
#
|
||||
# Do this before you make your request and it will act as if that user is logged in.
|
||||
#
|
||||
# === Integration tests
|
||||
#
|
||||
# Again, just like functional tests, you don't have to do anything. As soon as you make a request, Authlogic will be
|
||||
# conntected. If you want to activate Authlogic before making a request follow the same steps described in the
|
||||
# "functional tests" section above. It works in the same manner.
|
||||
#
|
||||
# === Unit tests
|
||||
#
|
||||
# The only time you need to do any trickiness here is if you want to test Authlogic models. Maybe you added some custom
|
||||
# code or methods in your Authlogic models. Maybe you are writing a plugin or a library that extends Authlogic.
|
||||
#
|
||||
# That being said, in this environment there is no controller. So you need to use a "mock" controller. Something
|
||||
# that looks like a controller, acts like a controller, but isn't a "real" controller. You are essentially connecting
|
||||
# Authlogic to your "mock" controller, then you can test off of the mock controller to make sure everything is functioning
|
||||
# properly.
|
||||
#
|
||||
# I use a mock controller to test Authlogic myself. It's part of the Authlogic library that you can easily use. It's as simple
|
||||
# as functional and integration tests. Just do the following:
|
||||
#
|
||||
# setup :activate_authlogic
|
||||
#
|
||||
# You also get a controller method that you can test off of. For example:
|
||||
#
|
||||
# ben = users(:ben)
|
||||
# assert_nil controller.session["user_credentials"]
|
||||
# assert UserSession.create(ben)
|
||||
# assert_equal controller.session["user_credentials"], ben.persistence_token
|
||||
#
|
||||
# See how I am checking that Authlogic is interacting with the controller properly? That's the idea here.
|
||||
module TestCase
|
||||
# Activates authlogic so that you can use it in your tests. You should call this method in your test's setup. Ex:
|
||||
#
|
||||
# setup :activate_authlogic
|
||||
def activate_authlogic
|
||||
if @request && ! @request.respond_to?(:params)
|
||||
class <<@request
|
||||
alias_method :params, :parameters
|
||||
end
|
||||
end
|
||||
|
||||
Authlogic::Session::Base.controller = (@request && Authlogic::TestCase::RailsRequestAdapter.new(@request)) || controller
|
||||
end
|
||||
|
||||
# The Authlogic::TestCase::MockController object passed to Authlogic to activate it. You can access this in your test.
|
||||
# See the module description for an example.
|
||||
def controller
|
||||
@controller ||= Authlogic::TestCase::MockController.new
|
||||
end
|
||||
end
|
||||
|
||||
::Test::Unit::TestCase.send(:include, TestCase) if defined?(::Test::Unit::TestCase)
|
||||
end
|
|
@ -1,45 +0,0 @@
|
|||
module Authlogic
|
||||
module TestCase
|
||||
# Basically acts like a controller but doesn't do anything. Authlogic can interact with this, do it's thing and then you
|
||||
# can look at the controller object to see if anything changed.
|
||||
class MockController < ControllerAdapters::AbstractAdapter
|
||||
attr_accessor :http_user, :http_password
|
||||
attr_writer :request_content_type
|
||||
|
||||
def initialize
|
||||
end
|
||||
|
||||
def authenticate_with_http_basic(&block)
|
||||
yield http_user, http_password
|
||||
end
|
||||
|
||||
def cookies
|
||||
@cookies ||= MockCookieJar.new
|
||||
end
|
||||
|
||||
def cookie_domain
|
||||
nil
|
||||
end
|
||||
|
||||
def logger
|
||||
@logger ||= MockLogger.new
|
||||
end
|
||||
|
||||
def params
|
||||
@params ||= {}
|
||||
end
|
||||
|
||||
def request
|
||||
@request ||= MockRequest.new(controller)
|
||||
end
|
||||
|
||||
def request_content_type
|
||||
@request_content_type ||= "text/html"
|
||||
end
|
||||
|
||||
def session
|
||||
@session ||= {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
module Authlogic
|
||||
module TestCase
|
||||
class MockCookieJar < Hash # :nodoc:
|
||||
def [](key)
|
||||
hash = super
|
||||
hash && hash[:value]
|
||||
end
|
||||
|
||||
def delete(key, options = {})
|
||||
super(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
module Authlogic
|
||||
module TestCase
|
||||
# Simple class to replace real loggers, so that we can raise any errors being logged.
|
||||
class MockLogger
|
||||
def error(message)
|
||||
raise message
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,19 +0,0 @@
|
|||
module Authlogic
|
||||
module TestCase
|
||||
class MockRequest # :nodoc:
|
||||
attr_accessor :controller
|
||||
|
||||
def initialize(controller)
|
||||
self.controller = controller
|
||||
end
|
||||
|
||||
def remote_ip
|
||||
(controller && controller.respond_to?(:env) && controller.env.is_a?(Hash) && controller.env['REMOTE_ADDR']) || "1.1.1.1"
|
||||
end
|
||||
|
||||
private
|
||||
def method_missing(*args, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
module Authlogic
|
||||
module TestCase
|
||||
# Adapts authlogic to work with the @request object when testing. This way Authlogic can set cookies and what not before
|
||||
# a request is made, ultimately letting you log in users in functional tests.
|
||||
class RailsRequestAdapter < ControllerAdapters::AbstractAdapter
|
||||
def authenticate_with_http_basic(&block)
|
||||
end
|
||||
|
||||
def cookies
|
||||
new_cookies = MockCookieJar.new
|
||||
super.each do |key, value|
|
||||
new_cookies[key] = value[:value]
|
||||
end
|
||||
new_cookies
|
||||
end
|
||||
|
||||
def cookie_domain
|
||||
nil
|
||||
end
|
||||
|
||||
def request
|
||||
@request ||= MockRequest.new(controller)
|
||||
end
|
||||
|
||||
def request_content_type
|
||||
request.format.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,69 +0,0 @@
|
|||
# Test::Unit
|
||||
# Place this file into your test/shoulda_macros directory
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# class UserTest
|
||||
# should_have_authlogic
|
||||
# end
|
||||
#
|
||||
# Rspec
|
||||
# Place this file into your spec/support/shoulda directory
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# describe User do
|
||||
# it { should have_authlogic }
|
||||
# end
|
||||
|
||||
module Authlogic
|
||||
module Shoulda
|
||||
|
||||
module Matchers
|
||||
def have_authlogic
|
||||
HaveAuthlogic.new
|
||||
end
|
||||
alias_method :be_authentic, :have_authlogic
|
||||
|
||||
class HaveAuthlogic
|
||||
|
||||
def matches?(subject)
|
||||
subject.respond_to?(:password=) && subject.respond_to?(:valid_password?)
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Add the line 'acts_as_authentic' to your model"
|
||||
end
|
||||
|
||||
def description
|
||||
"have Authlogic"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module Macros
|
||||
include Matchers
|
||||
|
||||
def should_have_authlogic
|
||||
klass = described_type rescue model_class
|
||||
matcher = HaveAuthlogic.new
|
||||
|
||||
should matcher.description do
|
||||
assert matcher.matches?(klass.new), matcher.failure_message
|
||||
end
|
||||
end
|
||||
alias_method :should_be_authentic, :should_have_authlogic
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if defined? Spec
|
||||
Spec::Runner.configure do |config|
|
||||
config.include(Authlogic::Shoulda::Matchers)
|
||||
end
|
||||
else
|
||||
Test::Unit::TestCase.class_eval { extend Authlogic::Shoulda::Macros }
|
||||
end
|
|
@ -1,18 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module ActsAsAuthenticTest
|
||||
class BaseTest < ActiveSupport::TestCase
|
||||
def test_acts_as_authentic
|
||||
assert_nothing_raised do
|
||||
User.acts_as_authentic do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_acts_as_authentic_with_old_config
|
||||
assert_raise(ArgumentError) do
|
||||
User.acts_as_authentic({})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,101 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module ActsAsAuthenticTest
|
||||
class EmailTest < ActiveSupport::TestCase
|
||||
def test_email_field_config
|
||||
assert_equal :email, User.email_field
|
||||
assert_equal :email, Employee.email_field
|
||||
|
||||
User.email_field = :nope
|
||||
assert_equal :nope, User.email_field
|
||||
User.email_field :email
|
||||
assert_equal :email, User.email_field
|
||||
end
|
||||
|
||||
def test_validate_email_field_config
|
||||
assert User.validate_email_field
|
||||
assert Employee.validate_email_field
|
||||
|
||||
User.validate_email_field = false
|
||||
assert !User.validate_email_field
|
||||
User.validate_email_field true
|
||||
assert User.validate_email_field
|
||||
end
|
||||
|
||||
def test_validates_length_of_email_field_options_config
|
||||
assert_equal({:within => 6..100}, User.validates_length_of_email_field_options)
|
||||
assert_equal({:within => 6..100}, Employee.validates_length_of_email_field_options)
|
||||
|
||||
User.validates_length_of_email_field_options = {:yes => "no"}
|
||||
assert_equal({:yes => "no"}, User.validates_length_of_email_field_options)
|
||||
User.validates_length_of_email_field_options({:within => 6..100})
|
||||
assert_equal({:within => 6..100}, User.validates_length_of_email_field_options)
|
||||
end
|
||||
|
||||
def test_validates_format_of_email_field_options_config
|
||||
default = {:with => Authlogic::Regex.email, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}
|
||||
assert_equal default, User.validates_format_of_email_field_options
|
||||
assert_equal default, Employee.validates_format_of_email_field_options
|
||||
|
||||
User.validates_format_of_email_field_options = {:yes => "no"}
|
||||
assert_equal({:yes => "no"}, User.validates_format_of_email_field_options)
|
||||
User.validates_format_of_email_field_options default
|
||||
assert_equal default, User.validates_format_of_email_field_options
|
||||
end
|
||||
|
||||
def test_validates_uniqueness_of_email_field_options_config
|
||||
default = {:case_sensitive => false, :scope => Employee.validations_scope, :if => "#{Employee.email_field}_changed?".to_sym}
|
||||
assert_equal default, Employee.validates_uniqueness_of_email_field_options
|
||||
|
||||
Employee.validates_uniqueness_of_email_field_options = {:yes => "no"}
|
||||
assert_equal({:yes => "no"}, Employee.validates_uniqueness_of_email_field_options)
|
||||
Employee.validates_uniqueness_of_email_field_options default
|
||||
assert_equal default, Employee.validates_uniqueness_of_email_field_options
|
||||
end
|
||||
|
||||
def test_validates_length_of_email_field
|
||||
u = User.new
|
||||
u.email = "a@a.a"
|
||||
assert !u.valid?
|
||||
assert u.errors[:email].size > 0
|
||||
|
||||
u.email = "a@a.com"
|
||||
assert !u.valid?
|
||||
assert u.errors[:email].size == 0
|
||||
end
|
||||
|
||||
def test_validates_format_of_email_field
|
||||
u = User.new
|
||||
u.email = "aaaaaaaaaaaaa"
|
||||
u.valid?
|
||||
assert u.errors[:email].size > 0
|
||||
|
||||
u.email = "a@a.com"
|
||||
u.valid?
|
||||
assert u.errors[:email].size == 0
|
||||
|
||||
u.email = "damien+test1...etc..@mydomain.com"
|
||||
u.valid?
|
||||
assert u.errors[:email].size == 0
|
||||
|
||||
u.email = "dakota.dux+1@gmail.com"
|
||||
u.valid?
|
||||
assert u.errors[:email].size == 0
|
||||
end
|
||||
|
||||
def test_validates_uniqueness_of_email_field
|
||||
u = User.new
|
||||
u.email = "bjohnson@binarylogic.com"
|
||||
assert !u.valid?
|
||||
assert u.errors[:email].size > 0
|
||||
|
||||
u.email = "BJOHNSON@binarylogic.com"
|
||||
assert !u.valid?
|
||||
assert u.errors[:email].size > 0
|
||||
|
||||
u.email = "a@a.com"
|
||||
assert !u.valid?
|
||||
assert u.errors[:email].size == 0
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,36 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module ActsAsAuthenticTest
|
||||
class LoggedInStatusTest < ActiveSupport::TestCase
|
||||
def test_logged_in_timeout_config
|
||||
assert_equal 10.minutes.to_i, User.logged_in_timeout
|
||||
assert_equal 10.minutes.to_i, Employee.logged_in_timeout
|
||||
|
||||
User.logged_in_timeout = 1.hour
|
||||
assert_equal 1.hour.to_i, User.logged_in_timeout
|
||||
User.logged_in_timeout 10.minutes
|
||||
assert_equal 10.minutes.to_i, User.logged_in_timeout
|
||||
end
|
||||
|
||||
def test_named_scope_logged_in
|
||||
assert_equal 0, User.logged_in.count
|
||||
User.first.update_attribute(:last_request_at, Time.now)
|
||||
assert_equal 1, User.logged_in.count
|
||||
end
|
||||
|
||||
def test_named_scope_logged_out
|
||||
assert_equal 2, User.logged_out.count
|
||||
User.first.update_attribute(:last_request_at, Time.now)
|
||||
assert_equal 1, User.logged_out.count
|
||||
end
|
||||
|
||||
def test_logged_in_logged_out
|
||||
u = User.first
|
||||
assert !u.logged_in?
|
||||
assert u.logged_out?
|
||||
u.last_request_at = Time.now
|
||||
assert u.logged_in?
|
||||
assert !u.logged_out?
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,109 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module ActsAsAuthenticTest
|
||||
class LoginTest < ActiveSupport::TestCase
|
||||
def test_login_field_config
|
||||
assert_equal :login, User.login_field
|
||||
assert_nil Employee.login_field
|
||||
|
||||
User.login_field = :nope
|
||||
assert_equal :nope, User.login_field
|
||||
User.login_field :login
|
||||
assert_equal :login, User.login_field
|
||||
end
|
||||
|
||||
def test_validate_login_field_config
|
||||
assert User.validate_login_field
|
||||
assert Employee.validate_login_field
|
||||
|
||||
User.validate_login_field = false
|
||||
assert !User.validate_login_field
|
||||
User.validate_login_field true
|
||||
assert User.validate_login_field
|
||||
end
|
||||
|
||||
def test_validates_length_of_login_field_options_config
|
||||
assert_equal({:within => 3..100}, User.validates_length_of_login_field_options)
|
||||
assert_equal({:within => 3..100}, Employee.validates_length_of_login_field_options)
|
||||
|
||||
User.validates_length_of_login_field_options = {:yes => "no"}
|
||||
assert_equal({:yes => "no"}, User.validates_length_of_login_field_options)
|
||||
User.validates_length_of_login_field_options({:within => 3..100})
|
||||
assert_equal({:within => 3..100}, User.validates_length_of_login_field_options)
|
||||
end
|
||||
|
||||
def test_validates_format_of_login_field_options_config
|
||||
default = {:with => /\A\w[\w\.+\-_@ ]+$/, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}
|
||||
assert_equal default, User.validates_format_of_login_field_options
|
||||
assert_equal default, Employee.validates_format_of_login_field_options
|
||||
|
||||
User.validates_format_of_login_field_options = {:yes => "no"}
|
||||
assert_equal({:yes => "no"}, User.validates_format_of_login_field_options)
|
||||
User.validates_format_of_login_field_options default
|
||||
assert_equal default, User.validates_format_of_login_field_options
|
||||
end
|
||||
|
||||
def test_validates_uniqueness_of_login_field_options_config
|
||||
default = {:case_sensitive => false, :scope => User.validations_scope, :if => "#{User.login_field}_changed?".to_sym}
|
||||
assert_equal default, User.validates_uniqueness_of_login_field_options
|
||||
|
||||
User.validates_uniqueness_of_login_field_options = {:yes => "no"}
|
||||
assert_equal({:yes => "no"}, User.validates_uniqueness_of_login_field_options)
|
||||
User.validates_uniqueness_of_login_field_options default
|
||||
assert_equal default, User.validates_uniqueness_of_login_field_options
|
||||
end
|
||||
|
||||
def test_validates_length_of_login_field
|
||||
u = User.new
|
||||
u.login = "a"
|
||||
assert !u.valid?
|
||||
assert u.errors[:login].size > 0
|
||||
|
||||
u.login = "aaaaaaaaaa"
|
||||
assert !u.valid?
|
||||
assert u.errors[:login].size == 0
|
||||
end
|
||||
|
||||
def test_validates_format_of_login_field
|
||||
u = User.new
|
||||
u.login = "fdsf@^&*"
|
||||
assert !u.valid?
|
||||
assert u.errors[:login].size > 0
|
||||
|
||||
u.login = "fdsfdsfdsfdsfs"
|
||||
assert !u.valid?
|
||||
assert u.errors[:login].size == 0
|
||||
|
||||
u.login = "dakota.dux+1@gmail.com"
|
||||
assert !u.valid?
|
||||
assert u.errors[:login].size == 0
|
||||
end
|
||||
|
||||
def test_validates_uniqueness_of_login_field
|
||||
u = User.new
|
||||
u.login = "bjohnson"
|
||||
assert !u.valid?
|
||||
assert u.errors[:login].size > 0
|
||||
|
||||
u.login = "BJOHNSON"
|
||||
assert !u.valid?
|
||||
assert u.errors[:login].size > 0
|
||||
|
||||
u.login = "fdsfdsf"
|
||||
assert !u.valid?
|
||||
assert u.errors[:login].size == 0
|
||||
end
|
||||
|
||||
def test_find_by_smart_case_login_field
|
||||
ben = users(:ben)
|
||||
assert_equal ben, User.find_by_smart_case_login_field("bjohnson")
|
||||
assert_equal ben, User.find_by_smart_case_login_field("BJOHNSON")
|
||||
assert_equal ben, User.find_by_smart_case_login_field("Bjohnson")
|
||||
|
||||
drew = employees(:drew)
|
||||
assert_equal drew, Employee.find_by_smart_case_login_field("dgainor@binarylogic.com")
|
||||
assert_equal drew, Employee.find_by_smart_case_login_field("Dgainor@binarylogic.com")
|
||||
assert_equal drew, Employee.find_by_smart_case_login_field("DGAINOR@BINARYLOGIC.COM")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module ActsAsAuthenticTest
|
||||
class MagicColumnsTest < ActiveSupport::TestCase
|
||||
def test_validates_numericality_of_login_count
|
||||
u = User.new
|
||||
u.login_count = -1
|
||||
assert !u.valid?
|
||||
assert u.errors[:login_count].size > 0
|
||||
|
||||
u.login_count = 0
|
||||
assert !u.valid?
|
||||
assert u.errors[:login_count].size == 0
|
||||
end
|
||||
|
||||
def test_validates_numericality_of_failed_login_count
|
||||
u = User.new
|
||||
u.failed_login_count = -1
|
||||
assert !u.valid?
|
||||
assert u.errors[:failed_login_count].size > 0
|
||||
|
||||
u.failed_login_count = 0
|
||||
assert !u.valid?
|
||||
assert u.errors[:failed_login_count].size == 0
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,236 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module ActsAsAuthenticTest
|
||||
class PasswordTest < ActiveSupport::TestCase
|
||||
def test_crypted_password_field_config
|
||||
assert_equal :crypted_password, User.crypted_password_field
|
||||
assert_equal :crypted_password, Employee.crypted_password_field
|
||||
|
||||
User.crypted_password_field = :nope
|
||||
assert_equal :nope, User.crypted_password_field
|
||||
User.crypted_password_field :crypted_password
|
||||
assert_equal :crypted_password, User.crypted_password_field
|
||||
end
|
||||
|
||||
def test_password_salt_field_config
|
||||
assert_equal :password_salt, User.password_salt_field
|
||||
assert_equal :password_salt, Employee.password_salt_field
|
||||
|
||||
User.password_salt_field = :nope
|
||||
assert_equal :nope, User.password_salt_field
|
||||
User.password_salt_field :password_salt
|
||||
assert_equal :password_salt, User.password_salt_field
|
||||
end
|
||||
|
||||
def test_ignore_blank_passwords_config
|
||||
assert User.ignore_blank_passwords
|
||||
assert Employee.ignore_blank_passwords
|
||||
|
||||
User.ignore_blank_passwords = false
|
||||
assert !User.ignore_blank_passwords
|
||||
User.ignore_blank_passwords true
|
||||
assert User.ignore_blank_passwords
|
||||
end
|
||||
|
||||
def test_check_passwords_against_database
|
||||
assert User.check_passwords_against_database
|
||||
User.check_passwords_against_database = false
|
||||
assert !User.check_passwords_against_database
|
||||
User.check_passwords_against_database true
|
||||
assert User.check_passwords_against_database
|
||||
end
|
||||
|
||||
def test_validate_password_field_config
|
||||
assert User.validate_password_field
|
||||
assert Employee.validate_password_field
|
||||
|
||||
User.validate_password_field = false
|
||||
assert !User.validate_password_field
|
||||
User.validate_password_field true
|
||||
assert User.validate_password_field
|
||||
end
|
||||
|
||||
def test_validates_length_of_password_field_options_config
|
||||
default = {:minimum => 4, :if => :require_password?}
|
||||
assert_equal default, User.validates_length_of_password_field_options
|
||||
assert_equal default, Employee.validates_length_of_password_field_options
|
||||
|
||||
User.validates_length_of_password_field_options = {:yes => "no"}
|
||||
assert_equal({:yes => "no"}, User.validates_length_of_password_field_options)
|
||||
User.validates_length_of_password_field_options default
|
||||
assert_equal default, User.validates_length_of_password_field_options
|
||||
end
|
||||
|
||||
def test_validates_confirmation_of_password_field_options_config
|
||||
default = {:if => :require_password?}
|
||||
assert_equal default, User.validates_confirmation_of_password_field_options
|
||||
assert_equal default, Employee.validates_confirmation_of_password_field_options
|
||||
|
||||
User.validates_confirmation_of_password_field_options = {:yes => "no"}
|
||||
assert_equal({:yes => "no"}, User.validates_confirmation_of_password_field_options)
|
||||
User.validates_confirmation_of_password_field_options default
|
||||
assert_equal default, User.validates_confirmation_of_password_field_options
|
||||
end
|
||||
|
||||
def test_validates_length_of_password_confirmation_field_options_config
|
||||
default = {:minimum => 4, :if => :require_password?}
|
||||
assert_equal default, User.validates_length_of_password_confirmation_field_options
|
||||
assert_equal default, Employee.validates_length_of_password_confirmation_field_options
|
||||
|
||||
User.validates_length_of_password_confirmation_field_options = {:yes => "no"}
|
||||
assert_equal({:yes => "no"}, User.validates_length_of_password_confirmation_field_options)
|
||||
User.validates_length_of_password_confirmation_field_options default
|
||||
assert_equal default, User.validates_length_of_password_confirmation_field_options
|
||||
end
|
||||
|
||||
def test_crypto_provider_config
|
||||
assert_equal Authlogic::CryptoProviders::Sha512, User.crypto_provider
|
||||
assert_equal Authlogic::CryptoProviders::AES256, Employee.crypto_provider
|
||||
|
||||
User.crypto_provider = Authlogic::CryptoProviders::BCrypt
|
||||
assert_equal Authlogic::CryptoProviders::BCrypt, User.crypto_provider
|
||||
User.crypto_provider Authlogic::CryptoProviders::Sha512
|
||||
assert_equal Authlogic::CryptoProviders::Sha512, User.crypto_provider
|
||||
end
|
||||
|
||||
def test_transition_from_crypto_providers_config
|
||||
assert_equal [], User.transition_from_crypto_providers
|
||||
assert_equal [], Employee.transition_from_crypto_providers
|
||||
|
||||
User.transition_from_crypto_providers = [Authlogic::CryptoProviders::BCrypt]
|
||||
assert_equal [Authlogic::CryptoProviders::BCrypt], User.transition_from_crypto_providers
|
||||
User.transition_from_crypto_providers []
|
||||
assert_equal [], User.transition_from_crypto_providers
|
||||
end
|
||||
|
||||
def test_validates_length_of_password
|
||||
u = User.new
|
||||
u.password_confirmation = "test2"
|
||||
assert !u.valid?
|
||||
assert u.errors[:password].size > 0
|
||||
|
||||
u.password = "test"
|
||||
assert !u.valid?
|
||||
assert u.errors[:password_confirmation].size == 0
|
||||
end
|
||||
|
||||
def test_validates_confirmation_of_password
|
||||
u = User.new
|
||||
u.password = "test"
|
||||
u.password_confirmation = "test2"
|
||||
assert !u.valid?
|
||||
assert u.errors[:password].size > 0
|
||||
|
||||
u.password_confirmation = "test"
|
||||
assert !u.valid?
|
||||
assert u.errors[:password].size == 0
|
||||
end
|
||||
|
||||
def test_validates_length_of_password_confirmation
|
||||
u = User.new
|
||||
|
||||
u.password = "test"
|
||||
u.password_confirmation = ""
|
||||
assert !u.valid?
|
||||
assert u.errors[:password_confirmation].size > 0
|
||||
|
||||
u.password_confirmation = "test"
|
||||
assert !u.valid?
|
||||
assert u.errors[:password_confirmation].size == 0
|
||||
|
||||
ben = users(:ben)
|
||||
assert ben.valid?
|
||||
|
||||
ben.password = "newpass"
|
||||
assert !ben.valid?
|
||||
assert ben.errors[:password_confirmation].size > 0
|
||||
|
||||
ben.password_confirmation = "newpass"
|
||||
assert ben.valid?
|
||||
end
|
||||
|
||||
def test_password
|
||||
u = User.new
|
||||
old_password_salt = u.password_salt
|
||||
old_crypted_password = u.crypted_password
|
||||
u.password = "test"
|
||||
assert_not_equal old_password_salt, u.password_salt
|
||||
assert_not_equal old_crypted_password, u.crypted_password
|
||||
end
|
||||
|
||||
def test_transitioning_password
|
||||
ben = users(:ben)
|
||||
transition_password_to(Authlogic::CryptoProviders::BCrypt, ben)
|
||||
transition_password_to(Authlogic::CryptoProviders::Sha1, ben, [Authlogic::CryptoProviders::Sha512, Authlogic::CryptoProviders::BCrypt])
|
||||
transition_password_to(Authlogic::CryptoProviders::Sha512, ben, [Authlogic::CryptoProviders::Sha1, Authlogic::CryptoProviders::BCrypt])
|
||||
end
|
||||
|
||||
def test_checks_password_against_database
|
||||
ben = users(:ben)
|
||||
ben.password = "new pass"
|
||||
assert !ben.valid_password?("new pass")
|
||||
assert ben.valid_password?("benrocks")
|
||||
end
|
||||
|
||||
def test_checks_password_against_database_and_always_fails_on_new_records
|
||||
user = User.new
|
||||
user.password = "new pass"
|
||||
assert !user.valid_password?("new pass")
|
||||
end
|
||||
|
||||
def test_checks_password_against_object
|
||||
ben = users(:ben)
|
||||
ben.password = "new pass"
|
||||
assert ben.valid_password?("new pass", false)
|
||||
assert !ben.valid_password?("benrocks", false)
|
||||
end
|
||||
|
||||
def test_reset_password
|
||||
ben = users(:ben)
|
||||
old_crypted_password = ben.crypted_password
|
||||
old_password_salt = ben.password_salt
|
||||
|
||||
# soft reset
|
||||
ben.reset_password
|
||||
assert_not_equal old_crypted_password, ben.crypted_password
|
||||
assert_not_equal old_password_salt, ben.password_salt
|
||||
|
||||
# make sure it didn't go into the db
|
||||
ben.reload
|
||||
assert_equal old_crypted_password, ben.crypted_password
|
||||
assert_equal old_password_salt, ben.password_salt
|
||||
|
||||
# hard reset
|
||||
assert ben.reset_password!
|
||||
assert_not_equal old_crypted_password, ben.crypted_password
|
||||
assert_not_equal old_password_salt, ben.password_salt
|
||||
|
||||
# make sure it did go into the db
|
||||
ben.reload
|
||||
assert_not_equal old_crypted_password, ben.crypted_password
|
||||
assert_not_equal old_password_salt, ben.password_salt
|
||||
end
|
||||
|
||||
private
|
||||
def transition_password_to(crypto_provider, records, from_crypto_providers = Authlogic::CryptoProviders::Sha512)
|
||||
records = [records] unless records.is_a?(Array)
|
||||
User.acts_as_authentic do |c|
|
||||
c.crypto_provider = crypto_provider
|
||||
c.transition_from_crypto_providers = from_crypto_providers
|
||||
end
|
||||
records.each do |record|
|
||||
old_hash = record.crypted_password
|
||||
old_persistence_token = record.persistence_token
|
||||
assert record.valid_password?(password_for(record))
|
||||
assert_not_equal old_hash.to_s, record.crypted_password.to_s
|
||||
assert_not_equal old_persistence_token.to_s, record.persistence_token.to_s
|
||||
|
||||
old_hash = record.crypted_password
|
||||
old_persistence_token = record.persistence_token
|
||||
assert record.valid_password?(password_for(record))
|
||||
assert_equal old_hash.to_s, record.crypted_password.to_s
|
||||
assert_equal old_persistence_token.to_s, record.persistence_token.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,90 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module ActsAsAuthenticTest
|
||||
class PerishableTokenTest < ActiveSupport::TestCase
|
||||
def test_perishable_token_valid_for_config
|
||||
assert_equal 10.minutes.to_i, User.perishable_token_valid_for
|
||||
assert_equal 10.minutes.to_i, Employee.perishable_token_valid_for
|
||||
|
||||
User.perishable_token_valid_for = 1.hour
|
||||
assert_equal 1.hour.to_i, User.perishable_token_valid_for
|
||||
User.perishable_token_valid_for 10.minutes
|
||||
assert_equal 10.minutes.to_i, User.perishable_token_valid_for
|
||||
end
|
||||
|
||||
def test_disable_perishable_token_maintenance_config
|
||||
assert !User.disable_perishable_token_maintenance
|
||||
assert !Employee.disable_perishable_token_maintenance
|
||||
|
||||
User.disable_perishable_token_maintenance = true
|
||||
assert User.disable_perishable_token_maintenance
|
||||
User.disable_perishable_token_maintenance false
|
||||
assert !User.disable_perishable_token_maintenance
|
||||
end
|
||||
|
||||
def test_validates_uniqueness_of_perishable_token
|
||||
u = User.new
|
||||
u.perishable_token = users(:ben).perishable_token
|
||||
assert !u.valid?
|
||||
assert u.errors[:perishable_token].size > 0
|
||||
end
|
||||
|
||||
def test_before_save_reset_perishable_token
|
||||
ben = users(:ben)
|
||||
old_perishable_token = ben.perishable_token
|
||||
assert ben.save
|
||||
assert_not_equal old_perishable_token, ben.perishable_token
|
||||
end
|
||||
|
||||
def test_reset_perishable_token
|
||||
ben = users(:ben)
|
||||
old_perishable_token = ben.perishable_token
|
||||
|
||||
assert ben.reset_perishable_token
|
||||
assert_not_equal old_perishable_token, ben.perishable_token
|
||||
|
||||
ben.reload
|
||||
assert_equal old_perishable_token, ben.perishable_token
|
||||
|
||||
assert ben.reset_perishable_token!
|
||||
assert_not_equal old_perishable_token, ben.perishable_token
|
||||
|
||||
ben.reload
|
||||
assert_not_equal old_perishable_token, ben.perishable_token
|
||||
end
|
||||
|
||||
def test_find_using_perishable_token
|
||||
ben = users(:ben)
|
||||
assert_equal ben, User.find_using_perishable_token(ben.perishable_token)
|
||||
end
|
||||
|
||||
def test_find_using_perishable_token_when_perished
|
||||
ben = users(:ben)
|
||||
ActiveRecord::Base.connection.execute("UPDATE users set updated_at = '#{1.week.ago.to_s(:db)}' where id = #{ben.id}")
|
||||
assert_nil User.find_using_perishable_token(ben.perishable_token)
|
||||
end
|
||||
|
||||
def test_find_using_perishable_token_when_perished
|
||||
User.perishable_token_valid_for = 1.minute
|
||||
ben = users(:ben)
|
||||
ActiveRecord::Base.connection.execute("UPDATE users set updated_at = '#{2.minutes.ago.to_s(:db)}' where id = #{ben.id}")
|
||||
assert_nil User.find_using_perishable_token(ben.perishable_token)
|
||||
User.perishable_token_valid_for = 10.minutes
|
||||
end
|
||||
|
||||
def test_find_using_perishable_token_when_passing_threshold
|
||||
User.perishable_token_valid_for = 1.minute
|
||||
ben = users(:ben)
|
||||
ActiveRecord::Base.connection.execute("UPDATE users set updated_at = '#{10.minutes.ago.to_s(:db)}' where id = #{ben.id}")
|
||||
assert_nil User.find_using_perishable_token(ben.perishable_token, 5.minutes)
|
||||
assert_equal ben, User.find_using_perishable_token(ben.perishable_token, 20.minutes)
|
||||
User.perishable_token_valid_for = 10.minutes
|
||||
end
|
||||
|
||||
def test_find_perishable_token_with_bang
|
||||
assert_raises ActiveRecord::RecordNotFound do
|
||||
User.find_using_perishable_token!('some_bad_value')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,55 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module ActsAsAuthenticTest
|
||||
class PersistenceTokenTest < ActiveSupport::TestCase
|
||||
def test_after_password_set_reset_persistence_token
|
||||
ben = users(:ben)
|
||||
old_persistence_token = ben.persistence_token
|
||||
ben.password = "newpass"
|
||||
assert_not_equal old_persistence_token, ben.persistence_token
|
||||
end
|
||||
|
||||
def test_after_password_verification_reset_persistence_token
|
||||
ben = users(:ben)
|
||||
old_persistence_token = ben.persistence_token
|
||||
assert ben.valid_password?(password_for(ben))
|
||||
assert_equal old_persistence_token, ben.persistence_token
|
||||
|
||||
# only update it if it is nil
|
||||
assert ben.update_attribute(:persistence_token, nil)
|
||||
assert ben.valid_password?(password_for(ben))
|
||||
assert_not_equal old_persistence_token, ben.persistence_token
|
||||
end
|
||||
|
||||
def test_before_validate_reset_persistence_token
|
||||
u = User.new
|
||||
assert !u.valid?
|
||||
assert_not_nil u.persistence_token
|
||||
end
|
||||
|
||||
def test_forget_all
|
||||
http_basic_auth_for(users(:ben)) { UserSession.find }
|
||||
http_basic_auth_for(users(:zack)) { UserSession.find(:ziggity_zack) }
|
||||
assert UserSession.find
|
||||
assert UserSession.find(:ziggity_zack)
|
||||
User.forget_all
|
||||
assert !UserSession.find
|
||||
assert !UserSession.find(:ziggity_zack)
|
||||
end
|
||||
|
||||
def test_forget
|
||||
ben = users(:ben)
|
||||
zack = users(:zack)
|
||||
http_basic_auth_for(ben) { UserSession.find }
|
||||
http_basic_auth_for(zack) { UserSession.find(:ziggity_zack) }
|
||||
|
||||
assert ben.reload.logged_in?
|
||||
assert zack.reload.logged_in?
|
||||
|
||||
ben.forget!
|
||||
|
||||
assert !UserSession.find
|
||||
assert UserSession.find(:ziggity_zack)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module ActsAsAuthenticTest
|
||||
class RestfulAuthenticationTest < ActiveSupport::TestCase
|
||||
def test_act_like_restful_authentication_config
|
||||
assert !User.act_like_restful_authentication
|
||||
assert !Employee.act_like_restful_authentication
|
||||
|
||||
User.act_like_restful_authentication = true
|
||||
assert User.act_like_restful_authentication
|
||||
assert_equal Authlogic::CryptoProviders::Sha1, User.crypto_provider
|
||||
assert defined?(::REST_AUTH_SITE_KEY)
|
||||
assert_equal '', ::REST_AUTH_SITE_KEY
|
||||
assert_equal 1, Authlogic::CryptoProviders::Sha1.stretches
|
||||
|
||||
User.act_like_restful_authentication false
|
||||
assert !User.act_like_restful_authentication
|
||||
|
||||
User.crypto_provider = Authlogic::CryptoProviders::Sha512
|
||||
User.transition_from_crypto_providers = []
|
||||
end
|
||||
|
||||
def test_transition_from_restful_authentication_config
|
||||
assert !User.transition_from_restful_authentication
|
||||
assert !Employee.transition_from_restful_authentication
|
||||
|
||||
User.transition_from_restful_authentication = true
|
||||
assert User.transition_from_restful_authentication
|
||||
assert defined?(::REST_AUTH_SITE_KEY)
|
||||
assert_equal '', ::REST_AUTH_SITE_KEY
|
||||
assert_equal 1, Authlogic::CryptoProviders::Sha1.stretches
|
||||
|
||||
User.transition_from_restful_authentication false
|
||||
assert !User.transition_from_restful_authentication
|
||||
|
||||
User.crypto_provider = Authlogic::CryptoProviders::Sha512
|
||||
User.transition_from_crypto_providers = []
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,84 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module ActsAsAuthenticTest
|
||||
class SessionMaintenanceTest < ActiveSupport::TestCase
|
||||
def test_maintain_sessions_config
|
||||
assert User.maintain_sessions
|
||||
User.maintain_sessions = false
|
||||
assert !User.maintain_sessions
|
||||
User.maintain_sessions true
|
||||
assert User.maintain_sessions
|
||||
end
|
||||
|
||||
def test_login_after_create
|
||||
assert User.create(:login => "awesome", :password => "saweet", :password_confirmation => "saweet", :email => "awesome@awesome.com")
|
||||
assert UserSession.find
|
||||
end
|
||||
|
||||
def test_updating_session_with_failed_magic_state
|
||||
ben = users(:ben)
|
||||
ben.confirmed = false
|
||||
ben.password = "newpass"
|
||||
ben.password_confirmation = "newpass"
|
||||
assert ben.save
|
||||
end
|
||||
|
||||
def test_update_session_after_password_modify
|
||||
ben = users(:ben)
|
||||
UserSession.create(ben)
|
||||
old_session_key = controller.session["user_credentials"]
|
||||
old_cookie_key = controller.cookies["user_credentials"]
|
||||
ben.password = "newpass"
|
||||
ben.password_confirmation = "newpass"
|
||||
assert ben.save
|
||||
assert controller.session["user_credentials"]
|
||||
assert controller.cookies["user_credentials"]
|
||||
assert_not_equal controller.session["user_credentials"], old_session_key
|
||||
assert_not_equal controller.cookies["user_credentials"], old_cookie_key
|
||||
end
|
||||
|
||||
def test_no_session_update_after_modify
|
||||
ben = users(:ben)
|
||||
UserSession.create(ben)
|
||||
old_session_key = controller.session["user_credentials"]
|
||||
old_cookie_key = controller.cookies["user_credentials"]
|
||||
ben.first_name = "Ben"
|
||||
assert ben.save
|
||||
assert_equal controller.session["user_credentials"], old_session_key
|
||||
assert_equal controller.cookies["user_credentials"], old_cookie_key
|
||||
end
|
||||
|
||||
def test_creating_other_user
|
||||
ben = users(:ben)
|
||||
UserSession.create(ben)
|
||||
old_session_key = controller.session["user_credentials"]
|
||||
old_cookie_key = controller.cookies["user_credentials"]
|
||||
assert User.create(:login => "awesome", :password => "saweet", :password_confirmation => "saweet", :email => "awesome@saweet.com")
|
||||
assert_equal controller.session["user_credentials"], old_session_key
|
||||
assert_equal controller.cookies["user_credentials"], old_cookie_key
|
||||
end
|
||||
|
||||
def test_updating_other_user
|
||||
ben = users(:ben)
|
||||
UserSession.create(ben)
|
||||
old_session_key = controller.session["user_credentials"]
|
||||
old_cookie_key = controller.cookies["user_credentials"]
|
||||
zack = users(:zack)
|
||||
zack.password = "newpass"
|
||||
zack.password_confirmation = "newpass"
|
||||
assert zack.save
|
||||
assert_equal controller.session["user_credentials"], old_session_key
|
||||
assert_equal controller.cookies["user_credentials"], old_cookie_key
|
||||
end
|
||||
|
||||
def test_resetting_password_when_logged_out
|
||||
ben = users(:ben)
|
||||
assert !UserSession.find
|
||||
ben.password = "newpass"
|
||||
ben.password_confirmation = "newpass"
|
||||
assert ben.save
|
||||
assert UserSession.find
|
||||
assert_equal ben, UserSession.find.record
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,44 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module ActsAsAuthenticTest
|
||||
class SingleAccessTest < ActiveSupport::TestCase
|
||||
def test_change_single_access_token_with_password_config
|
||||
assert !User.change_single_access_token_with_password
|
||||
assert !Employee.change_single_access_token_with_password
|
||||
|
||||
User.change_single_access_token_with_password = true
|
||||
assert User.change_single_access_token_with_password
|
||||
User.change_single_access_token_with_password false
|
||||
assert !User.change_single_access_token_with_password
|
||||
end
|
||||
|
||||
def test_validates_uniqueness_of_single_access_token
|
||||
u = User.new
|
||||
u.single_access_token = users(:ben).single_access_token
|
||||
assert !u.valid?
|
||||
assert u.errors[:single_access_token].size > 0
|
||||
end
|
||||
|
||||
def test_before_validation_reset_single_access_token
|
||||
u = User.new
|
||||
assert !u.valid?
|
||||
assert_not_nil u.single_access_token
|
||||
end
|
||||
|
||||
def test_after_password_set_reset_single_access_token
|
||||
User.change_single_access_token_with_password = true
|
||||
|
||||
ben = users(:ben)
|
||||
old_single_access_token = ben.single_access_token
|
||||
ben.password = "new_pass"
|
||||
assert_not_equal old_single_access_token, ben.single_access_token
|
||||
|
||||
User.change_single_access_token_with_password = false
|
||||
end
|
||||
|
||||
def test_after_password_set_is_not_called
|
||||
ldaper = Ldaper.new
|
||||
assert ldaper.save
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
class AuthenticatesManyTest < ActiveSupport::TestCase
|
||||
def test_scoping
|
||||
zack = users(:zack)
|
||||
ben = users(:ben)
|
||||
binary_logic = companies(:binary_logic)
|
||||
set_session_for(zack)
|
||||
|
||||
assert !binary_logic.user_sessions.find
|
||||
|
||||
set_session_for(ben)
|
||||
|
||||
assert binary_logic.user_sessions.find
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module CryptoProviderTest
|
||||
class AES256Test < ActiveSupport::TestCase
|
||||
def test_encrypt
|
||||
assert Authlogic::CryptoProviders::AES256.encrypt("mypass")
|
||||
end
|
||||
|
||||
def test_matches
|
||||
hash = Authlogic::CryptoProviders::AES256.encrypt("mypass")
|
||||
assert Authlogic::CryptoProviders::AES256.matches?(hash, "mypass")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module CryptoProviderTest
|
||||
class BCrpytTest < ActiveSupport::TestCase
|
||||
def test_encrypt
|
||||
assert Authlogic::CryptoProviders::BCrypt.encrypt("mypass")
|
||||
end
|
||||
|
||||
def test_matches
|
||||
hash = Authlogic::CryptoProviders::BCrypt.encrypt("mypass")
|
||||
assert Authlogic::CryptoProviders::BCrypt.matches?(hash, "mypass")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,23 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module CryptoProviderTest
|
||||
class Sha1Test < ActiveSupport::TestCase
|
||||
def test_encrypt
|
||||
assert Authlogic::CryptoProviders::Sha1.encrypt("mypass")
|
||||
end
|
||||
|
||||
def test_matches
|
||||
hash = Authlogic::CryptoProviders::Sha1.encrypt("mypass")
|
||||
assert Authlogic::CryptoProviders::Sha1.matches?(hash, "mypass")
|
||||
end
|
||||
|
||||
def test_old_restful_authentication_passwords
|
||||
password = "test"
|
||||
salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd"
|
||||
digest = "00742970dc9e6319f8019fd54864d3ea740f04b1"
|
||||
Authlogic::CryptoProviders::Sha1.stretches = 1
|
||||
assert Authlogic::CryptoProviders::Sha1.matches?(digest, nil, salt, password, nil)
|
||||
Authlogic::CryptoProviders::Sha1.stretches = 10
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module CryptoProviderTest
|
||||
class Sha256Test < ActiveSupport::TestCase
|
||||
def test_encrypt
|
||||
assert Authlogic::CryptoProviders::Sha256.encrypt("mypass")
|
||||
end
|
||||
|
||||
def test_matches
|
||||
hash = Authlogic::CryptoProviders::Sha256.encrypt("mypass")
|
||||
assert Authlogic::CryptoProviders::Sha256.matches?(hash, "mypass")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
module CryptoProviderTest
|
||||
class Sha512Test < ActiveSupport::TestCase
|
||||
def test_encrypt
|
||||
assert Authlogic::CryptoProviders::Sha512.encrypt("mypass")
|
||||
end
|
||||
|
||||
def test_matches
|
||||
hash = Authlogic::CryptoProviders::Sha512.encrypt("mypass")
|
||||
assert Authlogic::CryptoProviders::Sha512.matches?(hash, "mypass")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
binary_logic:
|
||||
name: Binary Logic
|
||||
|
||||
logic_over_data:
|
||||
name: Logic Over Data
|
|
@ -1,17 +0,0 @@
|
|||
drew:
|
||||
company: binary_logic
|
||||
email: dgainor@binarylogic.com
|
||||
password_salt: <%= salt = Authlogic::Random.hex_token %>
|
||||
crypted_password: '<%= Employee.crypto_provider.encrypt("drewrocks" + salt) %>'
|
||||
persistence_token: 5273d85ed156e9dbd6a7c1438d319ef8c8d41dd24368db6c222de11346c7b11e53ee08d45ecf619b1c1dc91233d22b372482b751b066d0a6f6f9bac42eacaabf
|
||||
first_name: Drew
|
||||
last_name: Gainor
|
||||
|
||||
jennifer:
|
||||
company: logic_over_data
|
||||
email: jjohnson@logicoverdata.com
|
||||
password_salt: <%= salt = Authlogic::Random.hex_token %>
|
||||
crypted_password: '<%= Employee.crypto_provider.encrypt("jenniferocks" + salt) %>'
|
||||
persistence_token: 2be52a8f741ad00056e6f94eb6844d5316527206da7a3a5e3d0e14d19499ef9fe4c47c89b87febb59a2b41a69edfb4733b6b79302040f3de83f297c6991c75a2
|
||||
first_name: Jennifer
|
||||
last_name: Johnson
|
|
@ -1,3 +0,0 @@
|
|||
web_services:
|
||||
name: web services
|
||||
users: ben, zack
|
24
vendor/plugins/authlogic/test/fixtures/users.yml
vendored
24
vendor/plugins/authlogic/test/fixtures/users.yml
vendored
|
@ -1,24 +0,0 @@
|
|||
ben:
|
||||
company: binary_logic
|
||||
projects: web_services
|
||||
login: bjohnson
|
||||
password_salt: <%= salt = Authlogic::Random.hex_token %>
|
||||
crypted_password: <%= Authlogic::CryptoProviders::Sha512.encrypt("benrocks" + salt) %>
|
||||
persistence_token: 6cde0674657a8a313ce952df979de2830309aa4c11ca65805dd00bfdc65dbcc2f5e36718660a1d2e68c1a08c276d996763985d2f06fd3d076eb7bc4d97b1e317
|
||||
single_access_token: <%= Authlogic::Random.friendly_token %>
|
||||
perishable_token: <%= Authlogic::Random.friendly_token %>
|
||||
email: bjohnson@binarylogic.com
|
||||
first_name: Ben
|
||||
last_name: Johnson
|
||||
|
||||
zack:
|
||||
company: logic_over_data
|
||||
projects: web_services
|
||||
login: zackham
|
||||
password_salt: <%= salt = Authlogic::Random.hex_token %>
|
||||
crypted_password: <%= Authlogic::CryptoProviders::Sha512.encrypt("zackrocks" + salt) %>
|
||||
persistence_token: fd3c2d5ce09ab98e7547d21f1b3dcf9158a9a19b5d3022c0402f32ae197019fce3fdbc6614d7ee57d719bae53bb089e30edc9e5d6153e5bc3afca0ac1d320342
|
||||
single_access_token: <%= Authlogic::Random.friendly_token %>
|
||||
email: zham@ziggityzack.com
|
||||
first_name: Zack
|
||||
last_name: Ham
|
33
vendor/plugins/authlogic/test/i18n_test.rb
vendored
33
vendor/plugins/authlogic/test/i18n_test.rb
vendored
|
@ -1,33 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
class I18nTest < ActiveSupport::TestCase
|
||||
def test_uses_authlogic_as_scope_by_default
|
||||
assert_equal :authlogic, Authlogic::I18n.scope
|
||||
end
|
||||
|
||||
def test_can_set_scope
|
||||
assert_nothing_raised { Authlogic::I18n.scope = [:a, :b] }
|
||||
assert_equal [:a, :b], Authlogic::I18n.scope
|
||||
Authlogic::I18n.scope = :authlogic
|
||||
end
|
||||
|
||||
def test_uses_built_in_translator_by_default
|
||||
assert_equal Authlogic::I18n::Translator, Authlogic::I18n.translator.class
|
||||
end
|
||||
|
||||
def test_can_set_custom_translator
|
||||
old_translator = Authlogic::I18n.translator
|
||||
|
||||
assert_nothing_raised do
|
||||
Authlogic::I18n.translator = Class.new do
|
||||
def translate(key, options = {})
|
||||
"Translated: #{key}"
|
||||
end
|
||||
end.new
|
||||
end
|
||||
|
||||
assert_equal "Translated: x", Authlogic::I18n.translate(:x)
|
||||
|
||||
Authlogic::I18n.translator = old_translator
|
||||
end
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
class Affiliate < ActiveRecord::Base
|
||||
acts_as_authentic do |c|
|
||||
c.crypted_password_field = :pw_hash
|
||||
end
|
||||
|
||||
belongs_to :company
|
||||
end
|
|
@ -1,6 +0,0 @@
|
|||
class Company < ActiveRecord::Base
|
||||
authenticates_many :employee_sessions
|
||||
authenticates_many :user_sessions
|
||||
has_many :employees, :dependent => :destroy
|
||||
has_many :users, :dependent => :destroy
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
class Employee < ActiveRecord::Base
|
||||
acts_as_authentic do |c|
|
||||
c.crypto_provider Authlogic::CryptoProviders::AES256
|
||||
end
|
||||
|
||||
belongs_to :company
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
class EmployeeSession < Authlogic::Session::Base
|
||||
end
|
3
vendor/plugins/authlogic/test/libs/ldaper.rb
vendored
3
vendor/plugins/authlogic/test/libs/ldaper.rb
vendored
|
@ -1,3 +0,0 @@
|
|||
class Ldaper < ActiveRecord::Base
|
||||
acts_as_authentic
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue