Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added last_request_at_threshold cconfig option

  • Loading branch information...
commit 1d38644cf9ff566b38e5f1a9446006f6fb5f766d 1 parent 93a4787
@binarylogic authored
View
3  CHANGELOG.rdoc
@@ -9,7 +9,8 @@
* 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.
* 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
+* 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.
== 1.0.0 released 2008-11-05
View
11 README.rdoc
@@ -1,6 +1,6 @@
= Authlogic
-Authlogic is a clean and simple ruby authentication solution. Put simply, its the Chuck Norris of authentication solutions for rails, merb, etc.
+Authlogic is a clean, simple, and unobtrusive ruby authentication solution. Put simply, its the Chuck Norris of authentication solutions for rails, merb, etc.
The last thing we need is another authentication solution, right? That's what I thought until I tried out some of the current solutions in both rails and merb. None of them felt right. They were either too complicated, bloated, littered my application with tons of code, or were just confusing. This is not the simple / elegant ruby we all fell in love with. We need a "ruby like" authentication solution. Authlogic is my attempt to satisfy that need...
@@ -75,6 +75,7 @@ Install the gem / plugin (recommended)
$ sudo gem install authlogic
+
# config/environment.rb
config.gem :authlogic
@@ -89,14 +90,14 @@ Lets assume you are setting up a session for your User model.
Create your user_session.rb file:
# app/models/user_session.rb
- class UserSession < Authgasm::Session::Base
+ class UserSession < Authlogic::Session::Base
# configuration here, just like ActiveRecord, or in an initializer
- # See Authgasm::Session::Config::ClassMethods for more details
+ # See Authlogic::Session::Config::ClassMethods for more details
end
=== Ensure proper database fields
-The user model needs to have the following columns. The names of these columns can be changed with configuration. Better yet, Authgasm tries to guess these names by checking for the existence of common names. See Authgasm::Session::Config::ClassMethods for more details, but chances are you won't have to specify any configuration for your field names, even if they aren't the same names as below.
+The user model needs to have the following columns. The names of these columns can be changed with configuration. Better yet, Authlogic tries to guess these names by checking for the existence of common names. See Authlogic::Session::Config::ClassMethods for more details, but chances are you won't have to specify any configuration for your field names, even if they aren't the same names as below.
t.string :login, :null => false
t.string :crypted_password, :null => false
@@ -109,7 +110,7 @@ The user model needs to have the following columns. The names of these columns c
Make sure you have a model that you will be authenticating with. For this example let's say you have a User model:
class User < ActiveRecord::Base
- acts_as_authentic # for options see documentation: Authgasm::ActsAsAuthentic::ClassMethods
+ acts_as_authentic # for options see documentation: Authlogic::ActsAsAuthentic::ClassMethods
end
Done! Now go use it just like you would with any other ActiveRecord model. Either glance at the code at the beginning of this readme or check out the tutorial (see above in "helpful links") for a more detailed walk through.
View
2  Rakefile
@@ -8,7 +8,7 @@ Echoe.new 'authlogic' do |p|
p.author = "Ben Johnson of Binary Logic"
p.email = 'bjohnson@binarylogic.com'
p.project = 'authlogic'
- p.summary = "A clean and simple ruby authentication solution."
+ p.summary = "A clean, simple, and unobtrusive ruby authentication solution."
p.url = "http://github.com/binarylogic/authlogic"
p.dependencies = %w(activesupport activerecord)
p.include_rakefile = true
View
4 lib/authlogic/controller_adapters/abstract_adapter.rb
@@ -22,6 +22,10 @@ def cookies
controller.cookies
end
+ def params
+ controller.params
+ end
+
def request
controller.request
end
View
15 lib/authlogic/session/base.rb
@@ -171,7 +171,7 @@ def find_record
if send("valid_#{find_method}?")
self.new_session = false
- if record.class.column_names.include?("last_request_at")
+ if record.class.column_names.include?("last_request_at") && (record.last_request_at.blank? || last_request_at_threshold.ago >= record.last_request_at)
record.last_request_at = Time.now
record.save_without_session_maintenance(false)
end
@@ -295,6 +295,7 @@ def valid?
errors.clear
if valid_credentials?
validate
+ valid_record?
return true if errors.empty?
end
@@ -407,15 +408,17 @@ def valid_credentials?
return false
end
+ self.record = unchecked_record
+ true
+ end
+
+ def valid_record?
[:active, :approved, :confirmed].each do |required_status|
- if unchecked_record.respond_to?("#{required_status}?") && !unchecked_record.send("#{required_status}?")
- errors.add_to_base("Your account has not been marked as #{required_status}")
+ if record.respond_to?("#{required_status}?") && !record.send("#{required_status}?")
+ errors.add_to_base("Your account has not been marked as #{required_status}")
return false
end
end
-
- self.record = unchecked_record
- true
end
end
end
View
72 lib/authlogic/session/config.rb
@@ -89,6 +89,20 @@ def find_by_login_method(value = nil)
end
alias_method :find_by_login_method=, :find_by_login_method
+ # Once the user confirms their openid Authlogic tries to find the record with that openod. This is the method it called on the record's
+ # class to find the record by the openid.
+ #
+ # * <tt>Default:</tt> "find_by_#{openid_field}"
+ # * <tt>Accepts:</tt> Symbol or String
+ def find_by_openid_method(value = nil)
+ if value.nil?
+ read_inheritable_attribute(:find_by_openid_method) || find_by_openid_method("find_by_#{openid_field}")
+ else
+ write_inheritable_attribute(:find_by_openid_method, value)
+ end
+ end
+ alias_method :find_by_openid_method=, :find_by_openid_method
+
# Calling UserSession.find tries to find the user session by session, then cookie, then basic http auth. This option allows you to change the order or remove any of these.
#
# * <tt>Default:</tt> [:session, :cookie, :http_auth]
@@ -103,9 +117,25 @@ def find_with(*values)
end
alias_method :find_with=, :find_with
- # 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.
+ # 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)
+ if value.nil?
+ read_inheritable_attribute(:last_request_at_threshold) || last_request_at_threshold(0)
+ else
+ write_inheritable_attribute(:last_request_at_threshold, value)
+ end
+ end
+ alias_method :last_request_at_threshold=, :last_request_at_threshold
+
+ # 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> Guesses based on the model columns, tries login, username, and email. If none are present it defaults to login
# * <tt>Accepts:</tt> Symbol or String
@@ -118,6 +148,38 @@ def login_field(value = nil)
end
alias_method :login_field=, :login_field
+ # The name of the method you want Authlogic to create for storing the openid url. 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
+ # "openid_url" and then find users by openid this is compeltely doable. See the find_by_openid_method configuration option for
+ # more details.
+ #
+ # * <tt>Default:</tt> Guesses based on the model columns, tries openid, openid_url, identity_url.
+ # * <tt>Accepts:</tt> Symbol or String
+ def openid_field(value = nil)
+ if value.nil?
+ read_inheritable_attribute(:openid_field) || openid_field((klass.column_names.include?("openid") && :openid) || (klass.column_names.include?("openid_url") && :openid_url) || (klass.column_names.include?("identity_url") && :identity_url))
+ else
+ write_inheritable_attribute(:openid_field, value)
+ end
+ end
+ alias_method :openid_field=, :openid_field
+
+ # The name of the method you want Authlogic to create for storing the openid url. 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
+ # "openid_url" and then find users by openid this is compeltely doable. See the find_by_openid_method configuration option for
+ # more details.
+ #
+ # * <tt>Default:</tt> Guesses based on the model columns, tries openid, openid_url, identity_url.
+ # * <tt>Accepts:</tt> Symbol or String
+ def openid_file_store_path(value = nil)
+ if value.nil?
+ read_inheritable_attribute(:openid_file_store_path) || openid_file_store_path((defined?(RAILS_ROOT) && RAILS_ROOT + "/tmp/openids") || (defined?(Merb) && Merb.root + "/tmp/openids"))
+ else
+ write_inheritable_attribute(:openid_file_store_path, value)
+ end
+ end
+ alias_method :openid_file_store_path=, :openid_file_store_path
+
# Works exactly like login_field, but for the password instead.
#
# * <tt>Default:</tt> Guesses based on the model columns, tries password and pass. If none are present it defaults to password
@@ -212,6 +274,10 @@ def find_by_login_method
def find_with
self.class.find_with
end
+
+ def last_request_at_threshold
+ self.class.last_request_at_threshold
+ end
def login_field
self.class.login_field
View
73 lib/authlogic/session/openid.rb
@@ -0,0 +1,73 @@
+module Authlogic
+ module Session
+ module OpenID
+ def self.included(klass)
+ klass.alias_method_chain :create_configurable_methods!, :openid
+ klass.before_validation :valid_openid?
+ klass.attr_accessor :openid_response
+ end
+
+ # Returns true if logging in with openid. Credentials mean username and password.
+ def logging_in_with_openid?
+ login_with == :openid
+ end
+
+ def valid_openid?
+ if controller.params[:openid_complete].blank?
+ if send(openid_field).blank?
+ errors.add(openid_field, "can not be blank")
+ return false
+ end
+
+ begin
+ self.openid_response = openid_consumer.begin(send(openid_field))
+ rescue OpenID::OpenIDError => e
+ errors.add("The OpenID identifier #{send(openid_field)} could not be found: #{e}")
+ return false
+ end
+
+ sregreq = OpenID::SReg::Request.new
+ # required fields
+ #sregreq.request_fields(['email','nickname'], true)
+ # optional fields
+ #sregreq.request_fields(['dob', 'fullname'], false)
+ oidreq.add_extension(sregreq)
+ oidreq.return_to_args["openid_complete"] = 1
+ else
+ case openid_response.status
+ when OpenID::Consumer::SUCCESS
+
+ when OpenID::Consumer::CANCEL
+ errors.add_to_base("OpenID authentication was cancelled.")
+ when OpenID::Consumer::FAILURE
+ errors.add_to_base("OpenID authentication failed.")
+ when OpenID::Consumer::SETUP_NEEDED
+ errors.add_to_Base("OpenID authentication needs setup.")
+ end
+ end
+ end
+
+ private
+ def create_configurable_methods_with_openid!
+ create_configurable_methods_without_openid!
+
+ return if respond_to?(openid_field)
+
+ if openid_field
+ self.class.class_eval <<-"end_eval", __FILE__, __LINE__
+ attr_reader :#{openid_field}
+
+ def #{openid_field}=(value)
+ self.login_with = :openid
+ @#{openid_field} = value
+ end
+ end_eval
+ end
+ end
+
+ def openid_consumer
+ @openid_consumer ||= OpenID::Consumer.new(controller.session, OpenID::FilesystemStore.new(openid_file_store_path))
+ end
+ end
+ end
+end
View
0  test_libs/aes128_crypto_provider.rb → test/libs/aes128_crypto_provider.rb
File renamed without changes
View
0  test_libs/mock_controller.rb → test/libs/mock_controller.rb
File renamed without changes
View
0  test_libs/mock_cookie_jar.rb → test/libs/mock_cookie_jar.rb
File renamed without changes
View
0  test_libs/mock_request.rb → test/libs/mock_request.rb
File renamed without changes
View
0  test_libs/ordered_hash.rb → test/libs/ordered_hash.rb
File renamed without changes
View
19 test/session_tests/config_test.rb
@@ -52,6 +52,25 @@ def test_find_with
assert UserSession.find
end
+
+ def test_last_request_at_threshold
+ ben = users(:ben)
+ set_session_for(ben)
+ UserSession.last_request_at_threshold = 2.seconds
+ assert_equal 2.seconds, UserSession.last_request_at_threshold
+
+ assert UserSession.find
+ last_request_at = ben.reload.last_request_at
+ sleep(1)
+ assert UserSession.find
+ assert_equal last_request_at, ben.reload.last_request_at
+ sleep(1)
+ assert UserSession.find
+ assert_not_equal last_request_at, ben.reload.last_request_at
+
+ UserSession.last_request_at_threshold 0
+ assert_equal 0, UserSession.last_request_at_threshold
+ end
def test_login_field
UserSession.login_field = :saweet
View
8 test/test_helper.rb
@@ -4,10 +4,10 @@
require "active_record"
require 'active_record/fixtures'
require File.dirname(__FILE__) + '/../lib/authlogic' unless defined?(Authlogic)
-require File.dirname(__FILE__) + '/../test_libs/aes128_crypto_provider'
-require File.dirname(__FILE__) + '/../test_libs/mock_request'
-require File.dirname(__FILE__) + '/../test_libs/mock_cookie_jar'
-require File.dirname(__FILE__) + '/../test_libs/mock_controller'
+require File.dirname(__FILE__) + '/libs/aes128_crypto_provider'
+require File.dirname(__FILE__) + '/libs/mock_request'
+require File.dirname(__FILE__) + '/libs/mock_cookie_jar'
+require File.dirname(__FILE__) + '/libs/mock_controller'
ActiveRecord::Schema.verbose = false
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
Please sign in to comment.
Something went wrong with that request. Please try again.