authentication-logic 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/bin/console +11 -0
  3. data/bin/setup +8 -0
  4. data/lib/auth/logic/acts_as_authentic/base.rb +118 -0
  5. data/lib/auth/logic/acts_as_authentic/email.rb +32 -0
  6. data/lib/auth/logic/acts_as_authentic/logged_in_status.rb +87 -0
  7. data/lib/auth/logic/acts_as_authentic/login.rb +65 -0
  8. data/lib/auth/logic/acts_as_authentic/magic_columns.rb +40 -0
  9. data/lib/auth/logic/acts_as_authentic/password.rb +362 -0
  10. data/lib/auth/logic/acts_as_authentic/perishable_token.rb +125 -0
  11. data/lib/auth/logic/acts_as_authentic/persistence_token.rb +72 -0
  12. data/lib/auth/logic/acts_as_authentic/queries/case_sensitivity.rb +55 -0
  13. data/lib/auth/logic/acts_as_authentic/queries/find_with_case.rb +85 -0
  14. data/lib/auth/logic/acts_as_authentic/session_maintenance.rb +189 -0
  15. data/lib/auth/logic/acts_as_authentic/single_access_token.rb +85 -0
  16. data/lib/auth/logic/config.rb +41 -0
  17. data/lib/auth/logic/controller_adapters/abstract_adapter.rb +121 -0
  18. data/lib/auth/logic/controller_adapters/rack_adapter.rb +74 -0
  19. data/lib/auth/logic/controller_adapters/rails_adapter.rb +49 -0
  20. data/lib/auth/logic/controller_adapters/sinatra_adapter.rb +69 -0
  21. data/lib/auth/logic/cookie_credentials.rb +65 -0
  22. data/lib/auth/logic/crypto_providers/bcrypt.rb +116 -0
  23. data/lib/auth/logic/crypto_providers/md5/v2.rb +37 -0
  24. data/lib/auth/logic/crypto_providers/md5.rb +38 -0
  25. data/lib/auth/logic/crypto_providers/scrypt.rb +96 -0
  26. data/lib/auth/logic/crypto_providers/sha1/v2.rb +42 -0
  27. data/lib/auth/logic/crypto_providers/sha1.rb +43 -0
  28. data/lib/auth/logic/crypto_providers/sha256/v2.rb +60 -0
  29. data/lib/auth/logic/crypto_providers/sha256.rb +61 -0
  30. data/lib/auth/logic/crypto_providers/sha512/v2.rb +41 -0
  31. data/lib/auth/logic/crypto_providers/sha512.rb +40 -0
  32. data/lib/auth/logic/crypto_providers.rb +89 -0
  33. data/lib/auth/logic/errors.rb +52 -0
  34. data/lib/auth/logic/i18n/translator.rb +20 -0
  35. data/lib/auth/logic/i18n.rb +100 -0
  36. data/lib/auth/logic/random.rb +18 -0
  37. data/lib/auth/logic/session/base.rb +2205 -0
  38. data/lib/auth/logic/session/magic_column/assigns_last_request_at.rb +49 -0
  39. data/lib/auth/logic/test_case/mock_api_controller.rb +53 -0
  40. data/lib/auth/logic/test_case/mock_controller.rb +59 -0
  41. data/lib/auth/logic/test_case/mock_cookie_jar.rb +112 -0
  42. data/lib/auth/logic/test_case/mock_logger.rb +14 -0
  43. data/lib/auth/logic/test_case/mock_request.rb +36 -0
  44. data/lib/auth/logic/test_case/rails_request_adapter.rb +40 -0
  45. data/lib/auth/logic/test_case.rb +216 -0
  46. data/lib/auth/logic/version.rb +7 -0
  47. data/lib/auth/logic.rb +46 -0
  48. metadata +426 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e3ea405dd232236ede943193d4e88d29b71325cfbd49792a1172d9ffa7d61f3a
4
+ data.tar.gz: 0e4feb942a405eeca6c22b6ccfe0aa435652b8ec725945ba04a1fba309482de8
5
+ SHA512:
6
+ metadata.gz: b656538ef705d09b62b9f8ac6cf710814f549d6a0d74459076ff37be764ad2a61b518696a337d8c37670fa83d2f679eb158e2fab03550f7d06ca9a7e8e9534f9
7
+ data.tar.gz: c7780765733051e7c3317497bddce4dcf87415a029301170c54ee7c64ae001b99edb66239e28db0871b81de6a3216c9c84c87ef91935af2b4a92dfdfa1590e09
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "auth/logic"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ require "irb"
11
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authentication
4
+ module Logic
5
+ module ActsAsAuthentic
6
+ # Provides the base functionality for acts_as_authentic
7
+ module Base
8
+ def self.included(klass)
9
+ klass.class_eval do
10
+ class_attribute :acts_as_authentic_modules
11
+ self.acts_as_authentic_modules ||= []
12
+ extend Authentication::Logic::Config
13
+ extend Config
14
+ end
15
+ end
16
+
17
+ # The primary configuration of a model (often, `User`) for use with
18
+ # auth-logic. These methods become class methods of ::ActiveRecord::Base.
19
+ module Config
20
+ # This includes a lot of helpful methods for authenticating records
21
+ # which the Authentication::Logic::Session module relies on. To use it just do:
22
+ #
23
+ # class User < ApplicationRecord
24
+ # acts_as_authentic
25
+ # end
26
+ #
27
+ # Configuration is easy:
28
+ #
29
+ # acts_as_authentic do |c|
30
+ # c.my_configuration_option = my_value
31
+ # end
32
+ #
33
+ # See the various sub modules for the configuration they provide.
34
+ def acts_as_authentic
35
+ yield self if block_given?
36
+ return unless db_setup?
37
+
38
+ acts_as_authentic_modules.each { |mod| include mod }
39
+ end
40
+
41
+ # Since this part of Authentication::Logic deals with another class, ActiveRecord,
42
+ # we can't just start including things in ActiveRecord itself. A lot of
43
+ # these module includes need to be triggered by the acts_as_authentic
44
+ # method call. For example, you don't want to start adding in email
45
+ # validations and what not into a model that has nothing to do with
46
+ # Authentication::Logic.
47
+ #
48
+ # That being said, this is your tool for extending Authentication::Logic and
49
+ # "hooking" into the acts_as_authentic call.
50
+ def add_acts_as_authentic_module(mod, action = :append)
51
+ modules = acts_as_authentic_modules.clone
52
+ case action
53
+ when :append
54
+ modules << mod
55
+ when :prepend
56
+ modules = [mod] + modules
57
+ end
58
+ modules.uniq!
59
+ self.acts_as_authentic_modules = modules
60
+ end
61
+
62
+ # This is the same as add_acts_as_authentic_module, except that it
63
+ # removes the module from the list.
64
+ def remove_acts_as_authentic_module(mod)
65
+ modules = acts_as_authentic_modules.clone
66
+ modules.delete(mod)
67
+ self.acts_as_authentic_modules = modules
68
+ end
69
+
70
+ # Some Authentication::Logic modules requires a database connection with a existing
71
+ # users table by the moment when you call the `acts_as_authentic`
72
+ # method. If you try to call `acts_as_authentic` without a database
73
+ # connection, it will raise a `Authentication::Logic::ModelSetupError`.
74
+ #
75
+ # If you rely on the User model before the database is setup correctly,
76
+ # set this field to false.
77
+ # * <tt>Default:</tt> false
78
+ # * <tt>Accepts:</tt> Boolean
79
+ def raise_on_model_setup_error(value = nil)
80
+ rw_config(:raise_on_model_setup_error, value, false)
81
+ end
82
+ alias raise_on_model_setup_error= raise_on_model_setup_error
83
+
84
+ private
85
+
86
+ def db_setup?
87
+ column_names
88
+ true
89
+ rescue StandardError
90
+ raise ModelSetupError if raise_on_model_setup_error
91
+
92
+ false
93
+ end
94
+
95
+ def first_column_to_exist(*columns_to_check)
96
+ if db_setup?
97
+ columns_to_check.each do |column_name|
98
+ return column_name.to_sym if column_names.include?(column_name.to_s)
99
+ end
100
+ end
101
+ columns_to_check.first&.to_sym
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ ::ActiveRecord::Base.include Authentication::Logic::ActsAsAuthentic::Base
110
+ ::ActiveRecord::Base.include Authentication::Logic::ActsAsAuthentic::Email
111
+ ::ActiveRecord::Base.include Authentication::Logic::ActsAsAuthentic::LoggedInStatus
112
+ ::ActiveRecord::Base.include Authentication::Logic::ActsAsAuthentic::Login
113
+ ::ActiveRecord::Base.include Authentication::Logic::ActsAsAuthentic::MagicColumns
114
+ ::ActiveRecord::Base.include Authentication::Logic::ActsAsAuthentic::Password
115
+ ::ActiveRecord::Base.include Authentication::Logic::ActsAsAuthentic::PerishableToken
116
+ ::ActiveRecord::Base.include Authentication::Logic::ActsAsAuthentic::PersistenceToken
117
+ ::ActiveRecord::Base.include Authentication::Logic::ActsAsAuthentic::SessionMaintenance
118
+ ::ActiveRecord::Base.include Authentication::Logic::ActsAsAuthentic::SingleAccessToken
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authentication
4
+ module Logic
5
+ module ActsAsAuthentic
6
+ # Sometimes models won't have an explicit "login" or "username" field.
7
+ # Instead they want to use the email field. In this case, auth-logic provides
8
+ # validations to make sure the email submited is actually a valid email.
9
+ # Don't worry, if you do have a login or username field, Authentication::Logic will
10
+ # still validate your email field. One less thing you have to worry about.
11
+ module Email
12
+ def self.included(klass)
13
+ klass.class_eval do
14
+ extend Config
15
+ end
16
+ end
17
+
18
+ # Configuration to modify how Authentication::Logic handles the email field.
19
+ module Config
20
+ # The name of the field that stores email addresses.
21
+ #
22
+ # * <tt>Default:</tt> :email, if it exists
23
+ # * <tt>Accepts:</tt> Symbol
24
+ def email_field(value = nil)
25
+ rw_config(:email_field, value, first_column_to_exist(nil, :email, :email_address))
26
+ end
27
+ alias email_field= email_field
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authentication
4
+ module Logic
5
+ module ActsAsAuthentic
6
+ # Since web applications are stateless there is not sure fire way to tell if
7
+ # a user is logged in or not, from the database perspective. The best way to
8
+ # do this is to provide a "timeout" based on inactivity. So if that user is
9
+ # inactive for a certain amount of time we assume they are logged out.
10
+ # That's what this module is all about.
11
+ module LoggedInStatus
12
+ def self.included(klass)
13
+ klass.class_eval do
14
+ extend Config
15
+ add_acts_as_authentic_module(Methods)
16
+ end
17
+ end
18
+
19
+ # All configuration for the logged in status feature set.
20
+ module Config
21
+ # The timeout to determine when a user is logged in or not.
22
+ #
23
+ # * <tt>Default:</tt> 10.minutes
24
+ # * <tt>Accepts:</tt> Fixnum
25
+ def logged_in_timeout(value = nil)
26
+ rw_config(:logged_in_timeout, (!value.nil? && value.to_i) || value, 10.minutes.to_i)
27
+ end
28
+ alias logged_in_timeout= logged_in_timeout
29
+ end
30
+
31
+ # All methods for the logged in status feature seat.
32
+ module Methods
33
+ def self.included(klass)
34
+ return unless klass.column_names.include?("last_request_at")
35
+
36
+ klass.class_eval do
37
+ include InstanceMethods
38
+ scope(
39
+ :logged_in,
40
+ lambda do
41
+ where(
42
+ "last_request_at > ? and current_login_at IS NOT NULL",
43
+ logged_in_timeout.seconds.ago
44
+ )
45
+ end
46
+ )
47
+ scope(
48
+ :logged_out,
49
+ lambda do
50
+ where(
51
+ "last_request_at is NULL or last_request_at <= ?",
52
+ logged_in_timeout.seconds.ago
53
+ )
54
+ end
55
+ )
56
+ end
57
+ end
58
+
59
+ # :nodoc:
60
+ module InstanceMethods
61
+ # Returns true if the last_request_at > logged_in_timeout.
62
+ def logged_in?
63
+ unless respond_to?(:last_request_at)
64
+ raise(
65
+ "Can not determine the records login state because " \
66
+ "there is no last_request_at column"
67
+ )
68
+ end
69
+ !last_request_at.nil? && last_request_at > logged_in_timeout.seconds.ago
70
+ end
71
+
72
+ # Opposite of logged_in?
73
+ def logged_out?
74
+ !logged_in?
75
+ end
76
+
77
+ private
78
+
79
+ def logged_in_timeout
80
+ self.class.logged_in_timeout
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "auth/logic/acts_as_authentic/queries/case_sensitivity"
4
+ require "auth/logic/acts_as_authentic/queries/find_with_case"
5
+
6
+ module Authentication
7
+ module Logic
8
+ module ActsAsAuthentic
9
+ # Handles everything related to the login field.
10
+ module Login
11
+ def self.included(klass)
12
+ klass.class_eval do
13
+ extend Config
14
+ end
15
+ end
16
+
17
+ # Configuration for the login field.
18
+ module Config
19
+ # The name of the login field in the database.
20
+ #
21
+ # * <tt>Default:</tt> :login or :username, if they exist
22
+ # * <tt>Accepts:</tt> Symbol
23
+ def login_field(value = nil)
24
+ rw_config(:login_field, value, first_column_to_exist(nil, :login, :username))
25
+ end
26
+ alias login_field= login_field
27
+
28
+ # This method allows you to find a record with the given login. If you
29
+ # notice, with Active Record you have the UniquenessValidator class.
30
+ # They give you a :case_sensitive option. I handle this in the same
31
+ # manner that they handle that. If you are using the login field, set
32
+ # false for the :case_sensitive option in
33
+ # validates_uniqueness_of_login_field_options and the column doesn't
34
+ # have a case-insensitive collation, this method will modify the query
35
+ # to look something like:
36
+ #
37
+ # "LOWER(#{quoted_table_name}.#{login_field}) = LOWER(#{login})"
38
+ #
39
+ # If you don't specify this it just uses a regular case-sensitive search
40
+ # (with the binary modifier if necessary):
41
+ #
42
+ # "BINARY #{login_field} = #{login}"
43
+ #
44
+ # The above also applies for using email as your login, except that you
45
+ # need to set the :case_sensitive in
46
+ # validates_uniqueness_of_email_field_options to false.
47
+ #
48
+ # @api public
49
+ def find_by_smart_case_login_field(login)
50
+ field = login_field || email_field
51
+ sensitive = Queries::CaseSensitivity.new(self, field).sensitive?
52
+ find_with_case(field, login, sensitive)
53
+ end
54
+
55
+ private
56
+
57
+ # @api private
58
+ def find_with_case(field, value, sensitive)
59
+ Queries::FindWithCase.new(self, field, value, sensitive).execute
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authentication
4
+ module Logic
5
+ module ActsAsAuthentic
6
+ # Magic columns are like ActiveRecord's created_at and updated_at columns.
7
+ # They are "magically" maintained for you. Authentication::Logic has the same thing, but
8
+ # these are maintained on the session side. Please see "Magic Columns" in
9
+ # `Session::Base` for more details. This module merely adds validations for
10
+ # the magic columns if they exist.
11
+ module MagicColumns
12
+ def self.included(klass)
13
+ klass.class_eval do
14
+ add_acts_as_authentic_module(Methods)
15
+ end
16
+ end
17
+
18
+ # Methods relating to the magic columns
19
+ module Methods
20
+ def self.included(klass)
21
+ klass.class_eval do
22
+ if column_names.include?("login_count")
23
+ validates_numericality_of :login_count,
24
+ only_integer: true,
25
+ greater_than_or_equal_to: 0,
26
+ allow_nil: true
27
+ end
28
+ if column_names.include?("failed_login_count")
29
+ validates_numericality_of :failed_login_count,
30
+ only_integer: true,
31
+ greater_than_or_equal_to: 0,
32
+ allow_nil: true
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end