authlogic 3.4.0 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4fed624511b6b7a6b441cb6dd3147085b19ffb04
4
- data.tar.gz: 9b7d99ff708b9f25edb9abdae86e854f19fc47e6
3
+ metadata.gz: 565581e21dba66d898a0aab8b407f73338a21b31
4
+ data.tar.gz: c9ba53aa14afd2a419f003791181f49fbacaa230
5
5
  SHA512:
6
- metadata.gz: 53b498bb6fd6de0e49988fac47604ec34ffe5fb2beacb2520450e512133c1e7dd4cd70c91373414baa9b6cb4d4098e01921719b8a2e1e8d00ead21a3c8d8a9e8
7
- data.tar.gz: 158dcd58ebf39d0c24806178c709344f8b12e85b6ad58fbb67d0f12103343ce9c6b2ab2045f0a76aa8c8acb1e6c6057626f44191cee63522f8a263ca7080c487
6
+ metadata.gz: fa27f90194dfe0df4e786238be81a7c0479fc0c8d5ddcff0612e23240ba17143efaa6f4a2aaa93bb9f61a87369e22ef811e048fbc99b0cd0fc4a12dee4082325
7
+ data.tar.gz: 5e55ec2fd8877e5800ca3b860273e5088423e0924fc94bdd5669d144e48444e55fe2e433808c18d513265e5838ec44eb47c06a8783cc7751c1835aa197ff73af
@@ -1,6 +1,6 @@
1
1
  = Authlogic
2
2
 
3
- ** Please note the latest version is compatible with rails 3.2 only. Please see the rails2 branch for Rails 2 compatibility.
3
+ ** Authlogic plans to support rails 3 and 4 for the foreseeable future
4
4
 
5
5
  Authlogic is a clean, simple, and unobtrusive ruby authentication solution.
6
6
 
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "authlogic"
6
- s.version = "3.4.0"
6
+ s.version = "3.4.1"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Ben Johnson"]
9
9
  s.email = ["bjohnson@binarylogic.com"]
@@ -62,7 +62,7 @@ module Authlogic
62
62
  # merge options into it. Checkout the convenience function merge_validates_format_of_email_field_options to merge
63
63
  # options.</b>
64
64
  #
65
- # * <tt>Default:</tt> {:with => Authlogic::Regex.email, :message => lambda {I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}}
65
+ # * <tt>Default:</tt> {:with => Authlogic::Regex.email, :message => Proc.new {I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}}
66
66
  # * <tt>Accepts:</tt> Hash of options accepted by validates_format_of
67
67
  def validates_format_of_email_field_options(value = nil)
68
68
  rw_config(:validates_format_of_email_field_options, value, {:with => Authlogic::Regex.email, :message => Proc.new{I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}})
@@ -90,21 +90,19 @@ module Authlogic
90
90
  end
91
91
 
92
92
  # This method allows you to find a record with the given login. If you notice, with Active Record you have the
93
- # validates_uniqueness_of validation function. They give you a :case_sensitive option. I handle this in the same
94
- # manner that they handle that. If you are using the login field and set false for the :case_sensitive option in
95
- # validates_uniqueness_of_login_field_options this method will modify the query to look something like:
93
+ # UniquenessValidator class. They give you a :case_sensitive option. I handle this in the same
94
+ # manner that they handle that. If you are using the login field, set false for the :case_sensitive option in
95
+ # validates_uniqueness_of_login_field_options and the column doesn't have a case-insensitive collation,
96
+ # this method will modify the query to look something like:
96
97
  #
97
- # where("LOWER(#{quoted_table_name}.#{login_field}) = ?", login.downcase).first
98
+ # "LOWER(#{quoted_table_name}.#{login_field}) = LOWER(#{login})"
98
99
  #
99
- # If you don't specify this it calls the good old find_by_* method:
100
+ # If you don't specify this it just uses a regular case-sensitive search (with the binary modifier if necessary):
100
101
  #
101
- # find_by_login(login)
102
+ # "BINARY #{login_field} = #{login}"
102
103
  #
103
104
  # The above also applies for using email as your login, except that you need to set the :case_sensitive in
104
105
  # validates_uniqueness_of_email_field_options to false.
105
- #
106
- # The only reason I need to do the above is for Postgres and SQLite since they perform case sensitive searches with the
107
- # find_by_* methods.
108
106
  def find_by_smart_case_login_field(login)
109
107
  if login_field
110
108
  find_with_case(login_field, login, validates_uniqueness_of_login_field_options[:case_sensitive] != false)
@@ -115,11 +113,14 @@ module Authlogic
115
113
 
116
114
  private
117
115
  def find_with_case(field, value, sensitivity = true)
118
- if sensitivity
119
- send("find_by_#{field}", value)
116
+ relation = if not sensitivity
117
+ connection.case_insensitive_comparison(arel_table, field.to_s, columns_hash[field.to_s], value)
120
118
  else
121
- where("LOWER(#{quoted_table_name}.#{field}) = ?", value.mb_chars.downcase).first
119
+ value = connection.case_sensitive_modifier(value) if value
120
+ relation = arel_table[field.to_s].eq(value)
122
121
  end
122
+
123
+ where(relation).first
123
124
  end
124
125
  end
125
126
 
@@ -52,7 +52,7 @@ module Authlogic
52
52
 
53
53
  # Class level methods for the perishable token
54
54
  module ClassMethods
55
- # Use this methdo to find a record with a perishable token. This method does 2 things for you:
55
+ # Use this method to find a record with a perishable token. This method does 2 things for you:
56
56
  #
57
57
  # 1. It ignores blank tokens
58
58
  # 2. It enforces the perishable_token_valid_for configuration option.
@@ -0,0 +1,63 @@
1
+ module Authlogic
2
+ module ControllerAdapters
3
+ # Adapter for authlogic to make it function as a Rack middleware.
4
+ # First you'll have write your own Rack adapter where you have to set your cookie domain.
5
+ #
6
+ # class YourRackAdapter < Authlogic::ControllerAdapters::RackAdapter
7
+ # def cookie_domain
8
+ # 'your_cookie_domain_here.com'
9
+ # end
10
+ # end
11
+ #
12
+ # Next you need to set up a rack middleware like this:
13
+ #
14
+ # class AuthlogicMiddleware
15
+ # def initialize(app)
16
+ # @app = app
17
+ # end
18
+ #
19
+ # def call(env)
20
+ # YourRackAdapter.new(env)
21
+ # @app.call(env)
22
+ # end
23
+ # end
24
+ #
25
+ # And that is all! Now just load this middleware into rack:
26
+ #
27
+ # use AuthlogicMiddleware
28
+ #
29
+ # Authlogic will expect a User and a UserSession object to be present:
30
+ #
31
+ # class UserSession < Authlogic::Session::Base
32
+ # # Authlogic options go here
33
+ # end
34
+ #
35
+ # class User < ActiveRecord::Base
36
+ # acts_as_authentic
37
+ # end
38
+ #
39
+ class RackAdapter < AbstractAdapter
40
+
41
+ def initialize(env)
42
+ # We use the Rack::Request object as the controller object.
43
+ # For this to work, we have to add some glue.
44
+ request = Rack::Request.new(env)
45
+
46
+ request.instance_eval do
47
+ def request; self; end
48
+ def remote_ip; self.ip; end
49
+ end
50
+
51
+ super(request)
52
+ Authlogic::Session::Base.controller = self
53
+ end
54
+
55
+ # Rack Requests stores cookies with not just the value, but also with flags and expire information in the hash.
56
+ # Authlogic does not like this, so we drop everything except the cookie value
57
+ def cookies
58
+ controller.cookies.map{|key, value_hash| {key => value_hash[:value]} }.inject(:merge) || {}
59
+ end
60
+ end
61
+ end
62
+
63
+ end
@@ -1,8 +1,4 @@
1
- begin
2
- require "bcrypt"
3
- rescue LoadError
4
- "sudo gem install bcrypt-ruby"
5
- end
1
+ require "bcrypt"
6
2
 
7
3
  module Authlogic
8
4
  module CryptoProviders
@@ -21,16 +17,16 @@ module Authlogic
21
17
  #
22
18
  # Benchmark.bm(18) do |x|
23
19
  # x.report("BCrypt (cost = 10:") { 100.times { BCrypt::Password.create("mypass", :cost => 10) } }
24
- # x.report("BCrypt (cost = 2:") { 100.times { BCrypt::Password.create("mypass", :cost => 2) } }
20
+ # x.report("BCrypt (cost = 4:") { 100.times { BCrypt::Password.create("mypass", :cost => 4) } }
25
21
  # x.report("Sha512:") { 100.times { Digest::SHA512.hexdigest("mypass") } }
26
22
  # x.report("Sha1:") { 100.times { Digest::SHA1.hexdigest("mypass") } }
27
23
  # end
28
24
  #
29
- # user system total real
30
- # BCrypt (cost = 10): 10.780000 0.060000 10.840000 ( 11.100289)
31
- # BCrypt (cost = 2): 0.180000 0.000000 0.180000 ( 0.181914)
32
- # Sha512: 0.000000 0.000000 0.000000 ( 0.000829)
33
- # Sha1: 0.000000 0.000000 0.000000 ( 0.000395)
25
+ # user system total real
26
+ # BCrypt (cost = 10): 37.360000 0.020000 37.380000 ( 37.558943)
27
+ # BCrypt (cost = 4): 0.680000 0.000000 0.680000 ( 0.677460)
28
+ # Sha512: 0.000000 0.000000 0.000000 ( 0.000672)
29
+ # Sha1: 0.000000 0.000000 0.000000 ( 0.000454)
34
30
  #
35
31
  # You can play around with the cost to get that perfect balance
36
32
  # between performance and security. A default cost of 10 is the
@@ -50,24 +46,30 @@ module Authlogic
50
46
  class BCrypt
51
47
  class << self
52
48
  # 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.
53
- # Set this to whatever you want, play around with it to get that perfect balance between security and performance.
49
+ # Set this to any value >= the engine's minimum (currently 4), play around with it to get that perfect balance between security and performance.
54
50
  def cost
55
51
  @cost ||= 10
56
52
  end
57
- attr_writer :cost
58
-
53
+
54
+ def cost=(val)
55
+ if val < ::BCrypt::Engine::MIN_COST
56
+ raise ArgumentError.new("Authlogic's bcrypt cost cannot be set below the engine's min cost (#{::BCrypt::Engine::MIN_COST})")
57
+ end
58
+ @cost = val
59
+ end
60
+
59
61
  # Creates a BCrypt hash for the password passed.
60
62
  def encrypt(*tokens)
61
63
  ::BCrypt::Password.create(join_tokens(tokens), :cost => cost)
62
64
  end
63
-
65
+
64
66
  # Does the hash match the tokens? Uses the same tokens that were used to encrypt.
65
67
  def matches?(hash, *tokens)
66
68
  hash = new_from_hash(hash)
67
69
  return false if hash.blank?
68
70
  hash == join_tokens(tokens)
69
71
  end
70
-
72
+
71
73
  # This method is used as a flag to tell Authlogic to "resave" the password upon a successful login, using the new cost
72
74
  def cost_matches?(hash)
73
75
  hash = new_from_hash(hash)
@@ -77,12 +79,12 @@ module Authlogic
77
79
  hash.cost == cost
78
80
  end
79
81
  end
80
-
82
+
81
83
  private
82
84
  def join_tokens(tokens)
83
85
  tokens.flatten.join
84
86
  end
85
-
87
+
86
88
  def new_from_hash(hash)
87
89
  begin
88
90
  ::BCrypt::Password.new(hash)
@@ -1,8 +1,4 @@
1
- begin
2
- require "scrypt"
3
- rescue LoadError
4
- "sudo gem install scrypt"
5
- end
1
+ require "scrypt"
6
2
 
7
3
  module Authlogic
8
4
  module CryptoProviders
@@ -67,7 +63,7 @@ module Authlogic
67
63
  def join_tokens(tokens)
68
64
  tokens.flatten.join
69
65
  end
70
-
66
+
71
67
  def new_from_hash(hash)
72
68
  begin
73
69
  ::SCrypt::Password.new(hash)
@@ -9,7 +9,7 @@ module Authlogic
9
9
  klass.extend ClassMethods
10
10
  klass.send(:include, InstanceMethods)
11
11
  end
12
-
12
+
13
13
  module ClassMethods
14
14
  # How to name the attributes of Authlogic, works JUST LIKE ActiveRecord, but instead it uses the following
15
15
  # namespace:
@@ -20,24 +20,14 @@ module Authlogic
20
20
  options[:default] ||= attribute_key_name.to_s.humanize
21
21
  I18n.t("attributes.#{name.underscore}.#{attribute_key_name}", options)
22
22
  end
23
-
23
+
24
24
  # How to name the class, works JUST LIKE ActiveRecord, except it uses the following namespace:
25
25
  #
26
26
  # authlogic.models.user_session
27
27
  def human_name(*args)
28
28
  I18n.t("models.#{name.underscore}", {:count => 1, :default => name.humanize})
29
29
  end
30
-
31
- # For rails < 2.3, mispelled
32
- def self_and_descendents_from_active_record
33
- [self]
34
- end
35
-
36
- # For rails >= 2.3, mispelling fixed
37
- def self_and_descendants_from_active_record
38
- [self]
39
- end
40
-
30
+
41
31
  # For rails >= 3.0
42
32
  def model_name
43
33
  if defined?(::ActiveModel)
@@ -55,7 +45,7 @@ module Authlogic
55
45
  ancestors.select { |x| x.respond_to?(:model_name) }
56
46
  end
57
47
  end
58
-
48
+
59
49
  module InstanceMethods
60
50
  # Don't use this yourself, this is to just trick some of the helpers since this is the method it calls.
61
51
  def new_record?
@@ -69,7 +59,7 @@ module Authlogic
69
59
  def destroyed?
70
60
  record.nil?
71
61
  end
72
-
62
+
73
63
  def to_key
74
64
  new_record? ? nil : record.to_key
75
65
  end
@@ -8,7 +8,7 @@ module Authlogic
8
8
  # last_request_at Updates every time the user logs in, either by explicitly logging in, or logging in by cookie, session, or http auth
9
9
  # current_login_at Updates with the current time when an explicit login is made.
10
10
  # last_login_at Updates with the value of current_login_at before it is reset.
11
- # current_login_ip Updates with the request remote_ip when an explicit login is made.
11
+ # current_login_ip Updates with the request ip when an explicit login is made.
12
12
  # last_login_ip Updates with the value of current_login_ip before it is reset.
13
13
  module MagicColumns
14
14
  def self.included(klass)
@@ -21,7 +21,7 @@ module Authlogic
21
21
  before_save :set_last_request_at, :if => :set_last_request_at?
22
22
  end
23
23
  end
24
-
24
+
25
25
  # Configuration for the magic columns feature.
26
26
  module Config
27
27
  # Every time a session is found the last_request_at field for that record is updatd with the current time, if that field exists.
@@ -36,7 +36,7 @@ module Authlogic
36
36
  end
37
37
  alias_method :last_request_at_threshold=, :last_request_at_threshold
38
38
  end
39
-
39
+
40
40
  # The methods available for an Authlogic::Session::Base object that make up the magic columns feature.
41
41
  module InstanceMethods
42
42
  private
@@ -46,22 +46,22 @@ module Authlogic
46
46
  attempted_record.failed_login_count += 1
47
47
  end
48
48
  end
49
-
49
+
50
50
  def update_info
51
51
  record.login_count = (record.login_count.blank? ? 1 : record.login_count + 1) if record.respond_to?(:login_count)
52
52
  record.failed_login_count = 0 if record.respond_to?(:failed_login_count)
53
-
53
+
54
54
  if record.respond_to?(:current_login_at)
55
55
  record.last_login_at = record.current_login_at if record.respond_to?(:last_login_at)
56
56
  record.current_login_at = klass.default_timezone == :utc ? Time.now.utc : Time.now
57
57
  end
58
-
58
+
59
59
  if record.respond_to?(:current_login_ip)
60
60
  record.last_login_ip = record.current_login_ip if record.respond_to?(:last_login_ip)
61
- record.current_login_ip = controller.request.remote_ip
61
+ record.current_login_ip = controller.request.ip
62
62
  end
63
63
  end
64
-
64
+
65
65
  # This method lets authlogic know whether it should allow the last_request_at field to be updated
66
66
  # with the current time (Time.now). One thing to note here is that it also checks for the existence of a
67
67
  # last_request_update_allowed? method in your controller. This allows you to control this method pragmatically
@@ -81,11 +81,11 @@ module Authlogic
81
81
  return controller.last_request_update_allowed? if controller.responds_to_last_request_update_allowed?
82
82
  record.last_request_at.blank? || last_request_at_threshold.to_i.seconds.ago >= record.last_request_at
83
83
  end
84
-
84
+
85
85
  def set_last_request_at
86
86
  record.last_request_at = klass.default_timezone == :utc ? Time.now.utc : Time.now
87
87
  end
88
-
88
+
89
89
  def last_request_at_threshold
90
90
  self.class.last_request_at_threshold
91
91
  end
@@ -35,8 +35,8 @@ module Authlogic
35
35
  # Allow finding by persistence token, because when records are created the session is maintained in a before_save, when there is no id.
36
36
  # This is done for performance reasons and to save on queries.
37
37
  record = record_id.nil? ?
38
- search_for_record("find_by_persistence_token", persistence_token) :
39
- search_for_record("find_by_#{klass.primary_key}", record_id)
38
+ search_for_record("find_by_persistence_token", persistence_token.to_s) :
39
+ search_for_record("find_by_#{klass.primary_key}", record_id.to_s)
40
40
  self.unauthorized_record = record if record && record.persistence_token == persistence_token
41
41
  valid?
42
42
  else
@@ -2,15 +2,15 @@ module Authlogic
2
2
  module TestCase
3
3
  class MockRequest # :nodoc:
4
4
  attr_accessor :controller
5
-
5
+
6
6
  def initialize(controller)
7
7
  self.controller = controller
8
8
  end
9
-
10
- def remote_ip
9
+
10
+ def ip
11
11
  (controller && controller.respond_to?(:env) && controller.env.is_a?(Hash) && controller.env['REMOTE_ADDR']) || "1.1.1.1"
12
12
  end
13
-
13
+
14
14
  private
15
15
  def method_missing(*args, &block)
16
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authlogic
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.0
4
+ version: 3.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Johnson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-03 00:00:00.000000000 Z
11
+ date: 2014-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -169,6 +169,7 @@ files:
169
169
  - lib/authlogic/authenticates_many/association.rb
170
170
  - lib/authlogic/authenticates_many/base.rb
171
171
  - lib/authlogic/controller_adapters/abstract_adapter.rb
172
+ - lib/authlogic/controller_adapters/rack_adapter.rb
172
173
  - lib/authlogic/controller_adapters/rails_adapter.rb
173
174
  - lib/authlogic/controller_adapters/sinatra_adapter.rb
174
175
  - lib/authlogic/crypto_providers/aes256.rb