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 +4 -4
- data/README.rdoc +1 -1
- data/authlogic.gemspec +1 -1
- data/lib/authlogic/acts_as_authentic/email.rb +1 -1
- data/lib/authlogic/acts_as_authentic/login.rb +13 -12
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +1 -1
- data/lib/authlogic/controller_adapters/rack_adapter.rb +63 -0
- data/lib/authlogic/crypto_providers/bcrypt.rb +20 -18
- data/lib/authlogic/crypto_providers/scrypt.rb +2 -6
- data/lib/authlogic/session/active_record_trickery.rb +5 -15
- data/lib/authlogic/session/magic_columns.rb +10 -10
- data/lib/authlogic/session/session.rb +2 -2
- data/lib/authlogic/test_case/mock_request.rb +4 -4
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 565581e21dba66d898a0aab8b407f73338a21b31
|
4
|
+
data.tar.gz: c9ba53aa14afd2a419f003791181f49fbacaa230
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa27f90194dfe0df4e786238be81a7c0479fc0c8d5ddcff0612e23240ba17143efaa6f4a2aaa93bb9f61a87369e22ef811e048fbc99b0cd0fc4a12dee4082325
|
7
|
+
data.tar.gz: 5e55ec2fd8877e5800ca3b860273e5088423e0924fc94bdd5669d144e48444e55fe2e433808c18d513265e5838ec44eb47c06a8783cc7751c1835aa197ff73af
|
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Authlogic
|
2
2
|
|
3
|
-
**
|
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
|
|
data/authlogic.gemspec
CHANGED
@@ -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 =>
|
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
|
-
#
|
94
|
-
# manner that they handle that. If you are using the login field
|
95
|
-
# validates_uniqueness_of_login_field_options
|
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
|
-
#
|
98
|
+
# "LOWER(#{quoted_table_name}.#{login_field}) = LOWER(#{login})"
|
98
99
|
#
|
99
|
-
# If you don't specify this it
|
100
|
+
# If you don't specify this it just uses a regular case-sensitive search (with the binary modifier if necessary):
|
100
101
|
#
|
101
|
-
#
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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 =
|
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
|
-
#
|
30
|
-
# BCrypt (cost = 10):
|
31
|
-
# BCrypt (cost =
|
32
|
-
# Sha512:
|
33
|
-
# Sha1:
|
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
|
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
|
-
|
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
|
-
|
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
|
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.
|
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
|
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.
|
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-
|
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
|