authtrail 0.2.2 → 0.4.1

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: f88e2c20a95601d9da18766155a4eb0300ac193d7be16c56b8f293e42237163b
4
- data.tar.gz: a74f7435a461fce5c2f2c12d98cc3329aeb6f45c6e54eac6192cd5d04dd1a857
3
+ metadata.gz: 22c5cb73374854a16a8581aad0618cf66033a7346784b16213ed58bb74d56b6b
4
+ data.tar.gz: 6666d786ba53acf7169c39e02eefcfdc7ae4211f26482bb47f142ca31d22885c
5
5
  SHA512:
6
- metadata.gz: 3a572225e8e080da90c400293ebccbb6a7808f642f2469b79e0777ed37470ccec13ebd31a6f6b57d4fc6b89d037f25c1ae1980298b68b04bdc258ff71037e578
7
- data.tar.gz: 6558512fa9aa0b95932a95165c79533672f91c612116666cec6afe2743fcb7cd8357e9b230dadcab6ce503d8d8e622566c0d188d9b92cb016c37de5b46e3a09e
6
+ metadata.gz: 6c429f790573ad4814b6c92eeff96cfc03b9b283046c5e1c23c425346674071792607c2f1c2f762ab588acaeb70badab8dafccaea38cc92c0c6944f63b7079fa
7
+ data.tar.gz: 9bfd5a70268d39c89f9792b3f3b6435935b55c11f201d690991053067e456b214463f912adce3dc879cb39f515322139a9cb690d7ca89ee98debb1640150d32d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## 0.4.1 (2021-08-14)
2
+
3
+ - Improved error message when `geocoder` gem not installed
4
+
5
+ ## 0.4.0 (2021-08-13)
6
+
7
+ - Disabled geocoding by default
8
+ - Made the `geocoder` gem an optional dependency
9
+ - Added `country_code` to geocoding
10
+
11
+ ## 0.3.1 (2021-03-03)
12
+
13
+ - Added `--lockbox` option to install generator
14
+
15
+ ## 0.3.0 (2021-03-01)
16
+
17
+ - Disabled geocoding by default for new installations
18
+ - Raise an exception instead of logging when auditing fails
19
+ - Removed support for Rails < 5.2 and Ruby < 2.6
20
+
1
21
  ## 0.2.2 (2020-11-21)
2
22
 
3
23
  - Added `transform_method` option
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2017-2020 Andrew Kane
1
+ Copyright (c) 2017-2021 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Track Devise login activity
4
4
 
5
+ **AuthTrail 0.4.0 was recently released** - see [how to upgrade](#upgrading)
6
+
5
7
  :tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
6
8
 
7
9
  [![Build Status](https://github.com/ankane/authtrail/workflows/build/badge.svg?branch=master)](https://github.com/ankane/authtrail/actions)
@@ -14,13 +16,22 @@ Add this line to your application’s Gemfile:
14
16
  gem 'authtrail'
15
17
  ```
16
18
 
17
- And run:
19
+ To encrypt email and IP addresses, install [Lockbox](https://github.com/ankane/lockbox) and [Blind Index](https://github.com/ankane/blind_index) and run:
20
+
21
+ ```sh
22
+ rails generate authtrail:install --lockbox
23
+ rails db:migrate
24
+ ```
25
+
26
+ If you prefer not to encrypt data, run:
18
27
 
19
28
  ```sh
20
29
  rails generate authtrail:install
21
30
  rails db:migrate
22
31
  ```
23
32
 
33
+ To enable geocoding, see the [Geocoding section](#geocoding).
34
+
24
35
  ## How It Works
25
36
 
26
37
  A `LoginActivity` record is created every time a user tries to login. You can then use this information to detect suspicious behavior. Data includes:
@@ -47,7 +58,7 @@ AuthTrail.exclude_method = lambda do |data|
47
58
  end
48
59
  ```
49
60
 
50
- Add or modify data (also add new fields to the `login_activities` table)
61
+ Add or modify data - also add new fields to the `login_activities` table if needed
51
62
 
52
63
  ```ruby
53
64
  AuthTrail.transform_method = lambda do |data, request|
@@ -95,50 +106,83 @@ The `LoginActivity` model uses a [polymorphic association](https://guides.rubyon
95
106
 
96
107
  ## Geocoding
97
108
 
98
- IP geocoding is performed in a background job so it doesn’t slow down web requests. You can disable it entirely with:
109
+ AuthTrail uses [Geocoder](https://github.com/alexreisner/geocoder) for geocoding. We recommend configuring [local geocoding](#local-geocoding) or [load balancer geocoding](#load-balancer-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.
110
+
111
+ To enable geocoding, add this line to your application’s Gemfile:
99
112
 
100
113
  ```ruby
101
- AuthTrail.geocode = false
114
+ gem 'geocoder'
102
115
  ```
103
116
 
104
- Set job queue for geocoding
117
+ And update `config/initializers/authtrail.rb`:
105
118
 
106
119
  ```ruby
107
- AuthTrail.job_queue = :low_priority
120
+ AuthTrail.geocode = true
108
121
  ```
109
122
 
110
- ### Geocoding Performance
123
+ Geocoding is performed in a background job so it doesn’t slow down web requests. Set the job queue with:
111
124
 
112
- 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.
125
+ ```ruby
126
+ AuthTrail.job_queue = :low_priority
127
+ ```
113
128
 
114
- Add this line to your application’s Gemfile:
129
+ ### Local Geocoding
130
+
131
+ For privacy and performance, we recommend geocoding locally. Add this line to your application’s Gemfile:
115
132
 
116
133
  ```ruby
117
134
  gem 'maxminddb'
118
135
  ```
119
136
 
120
- And create an initializer at `config/initializers/geocoder.rb` with:
137
+ For city-level geocoding, download the [GeoLite2 City database](https://dev.maxmind.com/geoip/geoip2/geolite2/) and create `config/initializers/geocoder.rb` with:
121
138
 
122
139
  ```ruby
123
140
  Geocoder.configure(
124
141
  ip_lookup: :geoip2,
125
142
  geoip2: {
126
- file: Rails.root.join("lib", "GeoLite2-City.mmdb")
143
+ file: "path/to/GeoLite2-City.mmdb"
144
+ }
145
+ )
146
+ ```
147
+
148
+ For country-level geocoding, install the `geoip-database` package. It’s preinstalled on Heroku. For Ubuntu, use:
149
+
150
+ ```sh
151
+ sudo apt-get install geoip-database
152
+ ```
153
+
154
+ And create `config/initializers/geocoder.rb` with:
155
+
156
+ ```ruby
157
+ Geocoder.configure(
158
+ ip_lookup: :maxmind_local,
159
+ maxmind_local: {
160
+ file: "/usr/share/GeoIP/GeoIP.dat",
161
+ package: :country
127
162
  }
128
163
  )
129
164
  ```
130
165
 
131
- ## Data Protection
166
+ ### Load Balancer Geocoding
167
+
168
+ Some load balancers can add geocoding information to request headers.
132
169
 
133
- 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.
170
+ - [nginx](https://nginx.org/en/docs/http/ngx_http_geoip_module.html)
171
+ - [Google Cloud](https://cloud.google.com/load-balancing/docs/custom-headers)
172
+ - [Cloudflare](https://support.cloudflare.com/hc/en-us/articles/200168236-Configuring-Cloudflare-IP-Geolocation)
134
173
 
135
174
  ```ruby
136
- class LoginActivity < ApplicationRecord
137
- encrypts :identity, :ip
138
- blind_index :identity, :ip
175
+ AuthTrail.geocode = false
176
+
177
+ AuthTrail.transform_method = lambda do |data, request|
178
+ data[:country] = request.headers["<country-header>"]
179
+ data[:region] = request.headers["<region-header>"]
180
+ data[:city] = request.headers["<city-header>"]
139
181
  end
140
182
  ```
141
183
 
184
+ Check out [this example](https://github.com/ankane/authtrail/issues/40)
185
+
142
186
  ## Other Notes
143
187
 
144
188
  We recommend using this in addition to Devise’s `Lockable` module and [Rack::Attack](https://github.com/kickstarter/rack-attack).
@@ -147,6 +191,18 @@ Check out [Hardening Devise](https://ankane.org/hardening-devise) and [Secure Ra
147
191
 
148
192
  ## Upgrading
149
193
 
194
+ ### 0.4.0
195
+
196
+ There are two notable changes to geocoding:
197
+
198
+ 1. Geocoding is now disabled by default (this was already the case for new installations with 0.3.0+). Check out the instructions for [how to enable it](#geocoding) (you may need to create `config/initializers/authtrail.rb`).
199
+
200
+ 2. The `geocoder` gem is now an optional dependency. To use geocoding, add it to your Gemfile:
201
+
202
+ ```ruby
203
+ gem 'geocoder'
204
+ ```
205
+
150
206
  ### 0.2.0
151
207
 
152
208
  To store latitude and longitude, create a migration with:
@@ -8,6 +8,8 @@ module AuthTrail
8
8
  result =
9
9
  begin
10
10
  Geocoder.search(login_activity.ip).first
11
+ rescue NameError
12
+ raise "Add the geocoder gem to your Gemfile to use geocoding"
11
13
  rescue => e
12
14
  Rails.logger.info "Geocode failed: #{e.message}"
13
15
  nil
@@ -18,6 +20,7 @@ module AuthTrail
18
20
  city: result.try(:city),
19
21
  region: result.try(:state),
20
22
  country: result.try(:country),
23
+ country_code: result.try(:country_code),
21
24
  latitude: result.try(:latitude),
22
25
  longitude: result.try(:longitude)
23
26
  }
@@ -2,34 +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
- request = ActionDispatch::Request.new(env)
18
+ request = ActionDispatch::Request.new(env)
23
19
 
24
- AuthTrail.track(
25
- strategy: detect_strategy(env["warden"]),
26
- scope: opts[:scope].to_s,
27
- identity: AuthTrail.identity_method.call(request, opts, nil),
28
- success: false,
29
- request: request,
30
- failure_reason: opts[:message].to_s
31
- )
32
- 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
+ )
33
28
  end
34
29
 
35
30
  private
@@ -1,3 +1,3 @@
1
1
  module AuthTrail
2
- VERSION = "0.2.2"
2
+ VERSION = "0.4.1"
3
3
  end
data/lib/authtrail.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  # dependencies
2
- require "geocoder"
3
2
  require "warden"
4
3
 
5
4
  # modules
@@ -11,7 +10,7 @@ module AuthTrail
11
10
  class << self
12
11
  attr_accessor :exclude_method, :geocode, :track_method, :identity_method, :job_queue, :transform_method
13
12
  end
14
- self.geocode = true
13
+ self.geocode = false
15
14
  self.identity_method = lambda do |request, opts, user|
16
15
  if user
17
16
  user.try(:email)
@@ -6,17 +6,47 @@ module Authtrail
6
6
  include ActiveRecord::Generators::Migration
7
7
  source_root File.join(__dir__, "templates")
8
8
 
9
+ class_option :lockbox, type: :boolean
10
+
9
11
  def copy_migration
10
12
  migration_template "login_activities_migration.rb", "db/migrate/create_login_activities.rb", migration_version: migration_version
11
13
  end
12
14
 
15
+ def copy_templates
16
+ template "initializer.rb", "config/initializers/authtrail.rb"
17
+ end
18
+
13
19
  def generate_model
14
- template "login_activity_model.rb", "app/models/login_activity.rb"
20
+ if lockbox?
21
+ template "model_lockbox.rb", "app/models/login_activity.rb"
22
+ else
23
+ template "model.rb", "app/models/login_activity.rb"
24
+ end
15
25
  end
16
26
 
17
27
  def migration_version
18
28
  "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
19
29
  end
30
+
31
+ def identity_column
32
+ if lockbox?
33
+ "t.text :identity_ciphertext\n t.string :identity_bidx, index: true"
34
+ else
35
+ "t.string :identity, index: true"
36
+ end
37
+ end
38
+
39
+ def ip_column
40
+ if lockbox?
41
+ "t.text :ip_ciphertext\n t.string :ip_bidx, index: true"
42
+ else
43
+ "t.string :ip, index: true"
44
+ end
45
+ end
46
+
47
+ def lockbox?
48
+ options[:lockbox]
49
+ end
20
50
  end
21
51
  end
22
52
  end
@@ -0,0 +1,14 @@
1
+ # set to true for geocoding (and add the geocoder gem to your Gemfile)
2
+ # we recommend configuring local geocoding as well
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
@@ -3,12 +3,12 @@ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version
3
3
  create_table :login_activities do |t|
4
4
  t.string :scope
5
5
  t.string :strategy
6
- t.string :identity
6
+ <%= identity_column %>
7
7
  t.boolean :success
8
8
  t.string :failure_reason
9
9
  t.references :user, polymorphic: true
10
10
  t.string :context
11
- t.string :ip
11
+ <%= ip_column %>
12
12
  t.text :user_agent
13
13
  t.text :referrer
14
14
  t.string :city
@@ -18,8 +18,5 @@ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version
18
18
  t.float :longitude
19
19
  t.datetime :created_at
20
20
  end
21
-
22
- add_index :login_activities, :identity
23
- add_index :login_activities, :ip
24
21
  end
25
22
  end
@@ -0,0 +1,14 @@
1
+ class LoginActivity < ApplicationRecord
2
+ belongs_to :user, polymorphic: true, optional: true
3
+
4
+ encrypts :identity, :ip
5
+ blind_index :identity, :ip
6
+
7
+ before_save :reduce_precision
8
+
9
+ # reduce precision to city level to protect IP
10
+ def reduce_precision
11
+ self.latitude = latitude&.round(1) if try(:latitude_changed?)
12
+ self.longitude = longitude&.round(1) if try(:longitude_changed?)
13
+ end
14
+ end
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.2.2
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-22 00:00:00.000000000 Z
11
+ date: 2021-08-14 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
@@ -52,120 +52,8 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: geocoder
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
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: '5'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '5'
111
- - !ruby/object:Gem::Dependency
112
- name: combustion
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: rails
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: sqlite3
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: devise
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
55
  description:
168
- email: andrew@chartkick.com
56
+ email: andrew@ankane.org
169
57
  executables: []
170
58
  extensions: []
171
59
  extra_rdoc_files: []
@@ -179,8 +67,10 @@ files:
179
67
  - lib/auth_trail/version.rb
180
68
  - lib/authtrail.rb
181
69
  - lib/generators/authtrail/install_generator.rb
70
+ - lib/generators/authtrail/templates/initializer.rb.tt
182
71
  - lib/generators/authtrail/templates/login_activities_migration.rb.tt
183
- - lib/generators/authtrail/templates/login_activity_model.rb.tt
72
+ - lib/generators/authtrail/templates/model.rb.tt
73
+ - lib/generators/authtrail/templates/model_lockbox.rb.tt
184
74
  homepage: https://github.com/ankane/authtrail
185
75
  licenses:
186
76
  - MIT
@@ -193,14 +83,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
193
83
  requirements:
194
84
  - - ">="
195
85
  - !ruby/object:Gem::Version
196
- version: '2.4'
86
+ version: '2.6'
197
87
  required_rubygems_version: !ruby/object:Gem::Requirement
198
88
  requirements:
199
89
  - - ">="
200
90
  - !ruby/object:Gem::Version
201
91
  version: '0'
202
92
  requirements: []
203
- rubygems_version: 3.1.4
93
+ rubygems_version: 3.2.22
204
94
  signing_key:
205
95
  specification_version: 4
206
96
  summary: Track Devise login activity