authtrail 0.1.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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: []