authtrail 0.1.2 → 0.3.0

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
  SHA256:
3
- metadata.gz: 686cc3a7c96d52e4cf5ac79c4268bdb0cd9b670978ac23668af4e8e0d4f11b08
4
- data.tar.gz: 073fd3fefbe1cee4eca8daa2ee3fe13ea2aefd1c3f3d1d868daafa1fe40b7511
3
+ metadata.gz: e54d90f6f3527e7f9f37276deda00150f33b472069b97bd66b0d27f0a3a44c6f
4
+ data.tar.gz: aa1cd0b4fc8e01590efbd51cd872a57a3ef6e984c844166f261ebd01230a771a
5
5
  SHA512:
6
- metadata.gz: 5b2afdc6ab493f2d8c3759d9d0d145b518f3447250889ce5013f737629d3bd89248ddb7413d8f75c2452a221ed950404355a9763814bdcfffe158bb89a7a2da7
7
- data.tar.gz: ac21a072dd8328cb749a65aedd12188de9cc93501d5ad54bb4ada4b0a56e24bc1cc1116f8d32dfeb3c8a3d28a066258ffc05bbec655c94ec08a30c3ff7e1fee0
6
+ metadata.gz: b640a2f9705502d2405fc15d1bf4bf6082cac388addef26b3592514af117508db8b5f35306f5bd93555472f25e58a86b42d1ade276083bf4b4c4db6dea284ec8
7
+ data.tar.gz: 80475eaba75303cffdf3313706a3a58e73718804414002559780a55a1041616de61da596f9b67f79b57e71998e9c27a8c590faefdb0febaaa9834fd74b897a55
data/CHANGELOG.md CHANGED
@@ -1,13 +1,37 @@
1
- ## 0.1.2
1
+ ## 0.3.0 (2021-03-01)
2
+
3
+ - Disabled geocoding by default for new installations
4
+ - Raise an exception instead of logging when auditing fails
5
+ - Removed support for Rails < 5.2 and Ruby < 2.6
6
+
7
+ ## 0.2.2 (2020-11-21)
8
+
9
+ - Added `transform_method` option
10
+
11
+ ## 0.2.1 (2020-08-17)
12
+
13
+ - Added `job_queue` option
14
+
15
+ ## 0.2.0 (2019-06-23)
16
+
17
+ - Added latitude and longitude
18
+ - `AuthTrail::GeocodeJob` now inherits from `ActiveJob::Base` instead of `ApplicationJob`
19
+ - Removed support for Rails 4.2
20
+
21
+ ## 0.1.3 (2018-09-27)
22
+
23
+ - Added support for Rails 4.2
24
+
25
+ ## 0.1.2 (2018-07-30)
2
26
 
3
27
  - Added `identity_method` option
4
28
  - Fixed geocoding
5
29
 
6
- ## 0.1.1
30
+ ## 0.1.1 (2018-07-13)
7
31
 
8
32
  - Improved strategy detection for failures
9
33
  - Fixed migration for MySQL
10
34
 
11
- ## 0.1.0
35
+ ## 0.1.0 (2017-11-07)
12
36
 
13
37
  - First release
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2017 Andrew Kane
1
+ Copyright (c) 2017-2021 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -4,6 +4,8 @@ Track Devise login activity
4
4
 
5
5
  :tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
6
6
 
7
+ [![Build Status](https://github.com/ankane/authtrail/workflows/build/badge.svg?branch=master)](https://github.com/ankane/authtrail/actions)
8
+
7
9
  ## Installation
8
10
 
9
11
  Add this line to your application’s Gemfile:
@@ -32,7 +34,7 @@ A `LoginActivity` record is created every time a user tries to login. You can th
32
34
  - `context` - controller and action
33
35
  - `ip` - IP address
34
36
  - `user_agent` and `referrer` - from browser
35
- - `city`, `region`, and `country` - from IP
37
+ - `city`, `region`, `country`, `latitude`, and `longitude` - from IP
36
38
  - `created_at` - time of event
37
39
 
38
40
  ## Features
@@ -40,20 +42,36 @@ A `LoginActivity` record is created every time a user tries to login. You can th
40
42
  Exclude certain attempts from tracking - useful if you run acceptance tests
41
43
 
42
44
  ```ruby
43
- AuthTrail.exclude_method = lambda do |info|
44
- info[:identity] == "capybara@example.org"
45
+ AuthTrail.exclude_method = lambda do |data|
46
+ data[:identity] == "capybara@example.org"
47
+ end
48
+ ```
49
+
50
+ Add or modify data - also add new fields to the `login_activities` table if needed
51
+
52
+ ```ruby
53
+ AuthTrail.transform_method = lambda do |data, request|
54
+ data[:request_id] = request.request_id
55
+ end
56
+ ```
57
+
58
+ Store the user on failed attempts
59
+
60
+ ```ruby
61
+ AuthTrail.transform_method = lambda do |data, request|
62
+ data[:user] ||= User.find_by(email: data[:identity])
45
63
  end
46
64
  ```
47
65
 
48
66
  Write data somewhere other than the `login_activities` table
49
67
 
50
68
  ```ruby
51
- AuthTrail.track_method = lambda do |info|
69
+ AuthTrail.track_method = lambda do |data|
52
70
  # code
53
71
  end
54
72
  ```
55
73
 
56
- Use a custom identity method [master]
74
+ Use a custom identity method
57
75
 
58
76
  ```ruby
59
77
  AuthTrail.identity_method = lambda do |request, opts, user|
@@ -73,63 +91,88 @@ class User < ApplicationRecord
73
91
  end
74
92
  ```
75
93
 
76
- The `LoginActivity` model uses a [polymorphic association](http://guides.rubyonrails.org/association_basics.html#polymorphic-associations) so it can be associated with different user models.
94
+ The `LoginActivity` model uses a [polymorphic association](https://guides.rubyonrails.org/association_basics.html#polymorphic-associations) so it can be associated with different user models.
77
95
 
78
96
  ## Geocoding
79
97
 
80
- IP geocoding is performed in a background job so it doesn’t slow down web requests. You can disable it entirely with:
98
+ AuthTrail uses [Geocoder](https://github.com/alexreisner/geocoder) for geocoding. We recommend configuring [local geocoding](#local-geocoding) so IP addresses are not sent to a 3rd party service. If you do use a 3rd party service and adhere to GDPR, be sure to add it to your subprocessor list.
99
+
100
+ To enable geocoding, update `config/initializers/authtrail.rb`:
81
101
 
82
102
  ```ruby
83
- AuthTrail.geocode = false
103
+ AuthTrail.geocode = true
84
104
  ```
85
105
 
86
- Set job queue for geocoding
106
+ Geocoding is performed in a background job so it doesn’t slow down web requests. Set the job queue with:
87
107
 
88
108
  ```ruby
89
- AuthTrail::GeocodeJob.queue_as :low
109
+ AuthTrail.job_queue = :low_priority
90
110
  ```
91
111
 
92
- ### Geocoding Performance
112
+ ### Local Geocoding
93
113
 
94
- To avoid calls to a remote API, download the [GeoLite2 City database](https://dev.maxmind.com/geoip/geoip2/geolite2/) and configure Geocoder to use it.
95
-
96
- Add this line to your application’s Gemfile:
114
+ For privacy and performance, we recommend geocoding locally. Add this line to your application’s Gemfile:
97
115
 
98
116
  ```ruby
99
117
  gem 'maxminddb'
100
118
  ```
101
119
 
102
- And create an initializer at `config/initializers/geocoder.rb` with:
120
+ For city-level geocoding, download the [GeoLite2 City database](https://dev.maxmind.com/geoip/geoip2/geolite2/) and create `config/initializers/geocoder.rb` with:
103
121
 
104
122
  ```ruby
105
123
  Geocoder.configure(
106
124
  ip_lookup: :geoip2,
107
125
  geoip2: {
108
- file: Rails.root.join("lib", "GeoLite2-City.mmdb")
126
+ file: "path/to/GeoLite2-City.mmdb"
127
+ }
128
+ )
129
+ ```
130
+
131
+ For country-level geocoding, install the `geoip-database` package. It’s preinstalled on Heroku. For Ubuntu, use:
132
+
133
+ ```sh
134
+ sudo apt-get install geoip-database
135
+ ```
136
+
137
+ And create `config/initializers/geocoder.rb` with:
138
+
139
+ ```ruby
140
+ Geocoder.configure(
141
+ ip_lookup: :maxmind_local,
142
+ maxmind_local: {
143
+ file: "/usr/share/GeoIP/GeoIP.dat",
144
+ package: :country
109
145
  }
110
146
  )
111
147
  ```
112
148
 
113
149
  ## Data Protection
114
150
 
115
- Protect the privacy of your users by encrypting fields that contain personal information, such as `identity` and `ip`. [attr_encrypted](https://github.com/attr-encrypted/attr_encrypted) is great for this.
151
+ Protect the privacy of your users by encrypting fields that contain personal data, such as `identity` and `ip`. [Lockbox](https://github.com/ankane/lockbox) is great for this. Use [Blind Index](https://github.com/ankane/blind_index) so you can still query the fields.
116
152
 
117
153
  ```ruby
118
154
  class LoginActivity < ApplicationRecord
119
- attr_encrypted :identity, ...
120
- attr_encrypted :ip, ...
155
+ encrypts :identity, :ip
156
+ blind_index :identity, :ip
121
157
  end
122
158
  ```
123
159
 
124
- You should also make it clear that you collect this information in your privacy policy.
125
-
126
160
  ## Other Notes
127
161
 
128
162
  We recommend using this in addition to Devise’s `Lockable` module and [Rack::Attack](https://github.com/kickstarter/rack-attack).
129
163
 
130
- Check out [Hardening Devise](https://github.com/ankane/shorts/blob/master/Hardening-Devise.md) and [Secure Rails](https://github.com/ankane/secure_rails) for more best practices.
164
+ Check out [Hardening Devise](https://ankane.org/hardening-devise) and [Secure Rails](https://github.com/ankane/secure_rails) for more best practices.
165
+
166
+ ## Upgrading
131
167
 
132
- Works with Rails 5+
168
+ ### 0.2.0
169
+
170
+ To store latitude and longitude, create a migration with:
171
+
172
+ ```ruby
173
+ add_column :login_activities, :latitude, :float
174
+ add_column :login_activities, :longitude, :float
175
+ ```
133
176
 
134
177
  ## History
135
178
 
@@ -143,3 +186,12 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
143
186
  - Fix bugs and [submit pull requests](https://github.com/ankane/authtrail/pulls)
144
187
  - Write, clarify, or fix documentation
145
188
  - Suggest or add new features
189
+
190
+ To get started with development and testing:
191
+
192
+ ```sh
193
+ git clone https://github.com/ankane/authtrail.git
194
+ cd authtrail
195
+ bundle install
196
+ bundle exec rake test
197
+ ```
@@ -1,5 +1,9 @@
1
1
  module AuthTrail
2
- class GeocodeJob < ApplicationJob
2
+ class GeocodeJob < ActiveJob::Base
3
+ # default queue is used if queue_as returns nil
4
+ # Rails has a test for this
5
+ queue_as { AuthTrail.job_queue }
6
+
3
7
  def perform(login_activity)
4
8
  result =
5
9
  begin
@@ -10,11 +14,17 @@ module AuthTrail
10
14
  end
11
15
 
12
16
  if result
13
- login_activity.update!(
14
- city: result.try(:city).presence,
15
- region: result.try(:state).presence,
16
- country: result.try(:country).presence
17
- )
17
+ attributes = {
18
+ city: result.try(:city),
19
+ region: result.try(:state),
20
+ country: result.try(:country),
21
+ latitude: result.try(:latitude),
22
+ longitude: result.try(:longitude)
23
+ }
24
+ attributes.each do |k, v|
25
+ login_activity.try("#{k}=", v.presence)
26
+ end
27
+ login_activity.save!
18
28
  end
19
29
  end
20
30
  end
@@ -2,36 +2,29 @@ module AuthTrail
2
2
  module Manager
3
3
  class << self
4
4
  def after_set_user(user, auth, opts)
5
- # do not raise an exception for tracking
6
- AuthTrail.safely do
7
- request = ActionDispatch::Request.new(auth.env)
5
+ request = ActionDispatch::Request.new(auth.env)
8
6
 
9
- AuthTrail.track(
10
- strategy: detect_strategy(auth),
11
- scope: opts[:scope].to_s,
12
- identity: AuthTrail.identity_method.call(request, opts, user),
13
- success: true,
14
- request: request,
15
- user: user
16
- )
17
- end
7
+ AuthTrail.track(
8
+ strategy: detect_strategy(auth),
9
+ scope: opts[:scope].to_s,
10
+ identity: AuthTrail.identity_method.call(request, opts, user),
11
+ success: true,
12
+ request: request,
13
+ user: user
14
+ )
18
15
  end
19
16
 
20
17
  def before_failure(env, opts)
21
- AuthTrail.safely do
22
- if opts[:message]
23
- request = ActionDispatch::Request.new(env)
18
+ request = ActionDispatch::Request.new(env)
24
19
 
25
- AuthTrail.track(
26
- strategy: detect_strategy(env["warden"]),
27
- scope: opts[:scope].to_s,
28
- identity: AuthTrail.identity_method.call(request, opts, nil),
29
- success: false,
30
- request: request,
31
- failure_reason: opts[:message].to_s
32
- )
33
- end
34
- end
20
+ AuthTrail.track(
21
+ strategy: detect_strategy(env["warden"]),
22
+ scope: opts[:scope].to_s,
23
+ identity: AuthTrail.identity_method.call(request, opts, nil),
24
+ success: false,
25
+ request: request,
26
+ failure_reason: opts[:message].to_s
27
+ )
35
28
  end
36
29
 
37
30
  private
@@ -1,3 +1,3 @@
1
1
  module AuthTrail
2
- VERSION = "0.1.2"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/authtrail.rb CHANGED
@@ -9,7 +9,7 @@ require "auth_trail/version"
9
9
 
10
10
  module AuthTrail
11
11
  class << self
12
- attr_accessor :exclude_method, :geocode, :track_method, :identity_method
12
+ attr_accessor :exclude_method, :geocode, :track_method, :identity_method, :job_queue, :transform_method
13
13
  end
14
14
  self.geocode = true
15
15
  self.identity_method = lambda do |request, opts, user|
@@ -22,7 +22,7 @@ module AuthTrail
22
22
  end
23
23
 
24
24
  def self.track(strategy:, scope:, identity:, success:, request:, user: nil, failure_reason: nil)
25
- info = {
25
+ data = {
26
26
  strategy: strategy,
27
27
  scope: scope,
28
28
  identity: identity,
@@ -35,17 +35,25 @@ module AuthTrail
35
35
  }
36
36
 
37
37
  if request.params[:controller]
38
- info[:context] = "#{request.params[:controller]}##{request.params[:action]}"
38
+ data[:context] = "#{request.params[:controller]}##{request.params[:action]}"
39
39
  end
40
40
 
41
+ # add request data before exclude_method since exclude_method doesn't have access to request
42
+ # could also add 2nd argument to exclude_method when arity > 1
43
+ AuthTrail.transform_method.call(data, request) if AuthTrail.transform_method
44
+
41
45
  # if exclude_method throws an exception, default to not excluding
42
- exclude = AuthTrail.exclude_method && AuthTrail.safely(default: false) { AuthTrail.exclude_method.call(info) }
46
+ exclude = AuthTrail.exclude_method && AuthTrail.safely(default: false) { AuthTrail.exclude_method.call(data) }
43
47
 
44
48
  unless exclude
45
49
  if AuthTrail.track_method
46
- AuthTrail.track_method.call(info)
50
+ AuthTrail.track_method.call(data)
47
51
  else
48
- login_activity = LoginActivity.create!(info)
52
+ login_activity = LoginActivity.new
53
+ data.each do |k, v|
54
+ login_activity.try("#{k}=", v)
55
+ end
56
+ login_activity.save!
49
57
  AuthTrail::GeocodeJob.perform_later(login_activity) if AuthTrail.geocode
50
58
  end
51
59
  end
@@ -66,5 +74,5 @@ Warden::Manager.after_set_user except: :fetch do |user, auth, opts|
66
74
  end
67
75
 
68
76
  Warden::Manager.before_failure do |env, opts|
69
- AuthTrail::Manager.before_failure(env, opts)
77
+ AuthTrail::Manager.before_failure(env, opts) if opts[:message]
70
78
  end
@@ -1,29 +1,19 @@
1
- # taken from https://github.com/collectiveidea/audited/blob/master/lib/generators/audited/install_generator.rb
2
- require "rails/generators"
3
- require "rails/generators/migration"
4
- require "active_record"
5
1
  require "rails/generators/active_record"
6
2
 
7
3
  module Authtrail
8
4
  module Generators
9
5
  class InstallGenerator < Rails::Generators::Base
10
- include Rails::Generators::Migration
11
- source_root File.expand_path("../templates", __FILE__)
12
-
13
- # Implement the required interface for Rails::Generators::Migration.
14
- def self.next_migration_number(dirname) #:nodoc:
15
- next_migration_number = current_migration_number(dirname) + 1
16
- if ::ActiveRecord::Base.timestamped_migrations
17
- [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
18
- else
19
- "%.3d" % next_migration_number
20
- end
21
- end
6
+ include ActiveRecord::Generators::Migration
7
+ source_root File.join(__dir__, "templates")
22
8
 
23
9
  def copy_migration
24
10
  migration_template "login_activities_migration.rb", "db/migrate/create_login_activities.rb", migration_version: migration_version
25
11
  end
26
12
 
13
+ def copy_templates
14
+ template "initializer.rb", "config/initializers/authtrail.rb"
15
+ end
16
+
27
17
  def generate_model
28
18
  template "login_activity_model.rb", "app/models/login_activity.rb"
29
19
  end
@@ -0,0 +1,14 @@
1
+ # set to true for geocoding
2
+ # we recommend configuring local geocoding first
3
+ # see https://github.com/ankane/authtrail#geocoding
4
+ AuthTrail.geocode = false
5
+
6
+ # add or modify data
7
+ # AuthTrail.transform_method = lambda do |data, request|
8
+ # data[:request_id] = request.request_id
9
+ # end
10
+
11
+ # exclude certain attempts from tracking
12
+ # AuthTrail.exclude_method = lambda do |data|
13
+ # data[:identity] == "capybara@example.org"
14
+ # end
@@ -14,6 +14,8 @@ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version
14
14
  t.string :city
15
15
  t.string :region
16
16
  t.string :country
17
+ t.float :latitude
18
+ t.float :longitude
17
19
  t.datetime :created_at
18
20
  end
19
21
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authtrail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-31 00:00:00.000000000 Z
11
+ date: 2021-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5'
19
+ version: '5.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '5'
26
+ version: '5.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '5'
33
+ version: '5.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '5'
40
+ version: '5.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: warden
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,50 +66,8 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: bundler
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rake
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: minitest
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- description:
112
- email: andrew@chartkick.com
69
+ description:
70
+ email: andrew@ankane.org
113
71
  executables: []
114
72
  extensions: []
115
73
  extra_rdoc_files: []
@@ -123,13 +81,14 @@ files:
123
81
  - lib/auth_trail/version.rb
124
82
  - lib/authtrail.rb
125
83
  - lib/generators/authtrail/install_generator.rb
126
- - lib/generators/authtrail/templates/login_activities_migration.rb
127
- - lib/generators/authtrail/templates/login_activity_model.rb
84
+ - lib/generators/authtrail/templates/initializer.rb.tt
85
+ - lib/generators/authtrail/templates/login_activities_migration.rb.tt
86
+ - lib/generators/authtrail/templates/login_activity_model.rb.tt
128
87
  homepage: https://github.com/ankane/authtrail
129
88
  licenses:
130
89
  - MIT
131
90
  metadata: {}
132
- post_install_message:
91
+ post_install_message:
133
92
  rdoc_options: []
134
93
  require_paths:
135
94
  - lib
@@ -137,16 +96,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
137
96
  requirements:
138
97
  - - ">="
139
98
  - !ruby/object:Gem::Version
140
- version: '2.2'
99
+ version: '2.6'
141
100
  required_rubygems_version: !ruby/object:Gem::Requirement
142
101
  requirements:
143
102
  - - ">="
144
103
  - !ruby/object:Gem::Version
145
104
  version: '0'
146
105
  requirements: []
147
- rubyforge_project:
148
- rubygems_version: 2.7.7
149
- signing_key:
106
+ rubygems_version: 3.2.3
107
+ signing_key:
150
108
  specification_version: 4
151
109
  summary: Track Devise login activity
152
110
  test_files: []