castle_devise 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c13e653cf7d00df4cdb2436431a031be5c4120d5e667ff2c5feb00effd374011
4
+ data.tar.gz: 8c4c4fafd623cda48e9f9c125c81cda8071ae81e7ec62cad74bc0476bd89c4ea
5
+ SHA512:
6
+ metadata.gz: 3066ab56d17f1d3097f4aecaa115162e0e9263016cd4dce602a0491d5071ad5fcb933871d6830147303ca859cd60e5c503cdd30dc23112e0b94c0337e4cabee2
7
+ data.tar.gz: b8c18958cc92790e26e4e222c8c7f34f4db8be72c1c55d54225ca23dd427bcad7082c1efe7208655dbe43c3d31840fbc4875797e53d7b074eef88e21d1a7d118
@@ -0,0 +1,18 @@
1
+ name: Lint
2
+
3
+ on: [pull_request]
4
+
5
+ jobs:
6
+ standardrb:
7
+ name: runner / standardrb
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - name: Check out code
11
+ uses: actions/checkout@v1
12
+ - name: standardrb
13
+ uses: SennaLabs/action-standardrb@v0.0.3
14
+ with:
15
+ github_token: ${{ secrets.github_token }}
16
+ reporter: github-pr-review # Default is github-pr-check
17
+ rubocop_version: 1.1.1 # note: this actually refers to standardb version, not Rubocop
18
+ rubocop_flags: --format progress
@@ -0,0 +1,25 @@
1
+ name: Specs
2
+
3
+ on: [push,pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ environment: tests
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v2
11
+ - name: Set up Ruby
12
+ uses: ruby/setup-ruby@v1
13
+ with:
14
+ ruby-version: 2.6.5
15
+ - name: Run specs
16
+ run: |
17
+ gem install bundler -v 2.2.19
18
+ bundle install
19
+ bundle exec rake
20
+ env:
21
+ CASTLE_API_SECRET: ${{ secrets.CASTLE_API_SECRET }}
22
+ - name: Simplecov Report
23
+ uses: aki77/simplecov-report-action@v1
24
+ with:
25
+ token: ${{ secrets.GITHUB_TOKEN }}
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ # IntelliJ
14
+ .idea/
15
+
16
+ vendor/
17
+
18
+ spec/dummy_app/log/
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2021-06-11
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in castle-devise.gemspec
6
+ gemspec
7
+
8
+ gem "activerecord"
9
+ gem "railties", "~> 5.2"
10
+ gem "rake"
11
+ gem "rspec"
12
+ gem "rspec-rails"
13
+ gem "simplecov"
14
+ gem "standard"
15
+ gem "sqlite3"
16
+ gem "vcr"
17
+ gem "webmock"
data/Gemfile.lock ADDED
@@ -0,0 +1,169 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ castle_devise (0.1.0)
5
+ activesupport (>= 5.0)
6
+ castle-rb (>= 7.0, < 8.0)
7
+ devise (>= 4.3.0, < 5.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionpack (5.2.6)
13
+ actionview (= 5.2.6)
14
+ activesupport (= 5.2.6)
15
+ rack (~> 2.0, >= 2.0.8)
16
+ rack-test (>= 0.6.3)
17
+ rails-dom-testing (~> 2.0)
18
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
19
+ actionview (5.2.6)
20
+ activesupport (= 5.2.6)
21
+ builder (~> 3.1)
22
+ erubi (~> 1.4)
23
+ rails-dom-testing (~> 2.0)
24
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
25
+ activemodel (5.2.6)
26
+ activesupport (= 5.2.6)
27
+ activerecord (5.2.6)
28
+ activemodel (= 5.2.6)
29
+ activesupport (= 5.2.6)
30
+ arel (>= 9.0)
31
+ activesupport (5.2.6)
32
+ concurrent-ruby (~> 1.0, >= 1.0.2)
33
+ i18n (>= 0.7, < 2)
34
+ minitest (~> 5.1)
35
+ tzinfo (~> 1.1)
36
+ addressable (2.7.0)
37
+ public_suffix (>= 2.0.2, < 5.0)
38
+ arel (9.0.0)
39
+ ast (2.4.2)
40
+ bcrypt (3.1.16)
41
+ builder (3.2.4)
42
+ castle-rb (7.1.1)
43
+ concurrent-ruby (1.1.9)
44
+ crack (0.4.5)
45
+ rexml
46
+ crass (1.0.6)
47
+ devise (4.8.0)
48
+ bcrypt (~> 3.0)
49
+ orm_adapter (~> 0.1)
50
+ railties (>= 4.1.0)
51
+ responders
52
+ warden (~> 1.2.3)
53
+ diff-lcs (1.4.4)
54
+ docile (1.4.0)
55
+ erubi (1.10.0)
56
+ hashdiff (1.0.1)
57
+ i18n (1.8.10)
58
+ concurrent-ruby (~> 1.0)
59
+ loofah (2.10.0)
60
+ crass (~> 1.0.2)
61
+ nokogiri (>= 1.5.9)
62
+ method_source (1.0.0)
63
+ minitest (5.14.4)
64
+ nokogiri (1.11.7-x86_64-darwin)
65
+ racc (~> 1.4)
66
+ orm_adapter (0.5.0)
67
+ parallel (1.20.1)
68
+ parser (3.0.1.1)
69
+ ast (~> 2.4.1)
70
+ public_suffix (4.0.6)
71
+ racc (1.5.2)
72
+ rack (2.2.3)
73
+ rack-test (1.1.0)
74
+ rack (>= 1.0, < 3)
75
+ rails-dom-testing (2.0.3)
76
+ activesupport (>= 4.2.0)
77
+ nokogiri (>= 1.6)
78
+ rails-html-sanitizer (1.3.0)
79
+ loofah (~> 2.3)
80
+ railties (5.2.6)
81
+ actionpack (= 5.2.6)
82
+ activesupport (= 5.2.6)
83
+ method_source
84
+ rake (>= 0.8.7)
85
+ thor (>= 0.19.0, < 2.0)
86
+ rainbow (3.0.0)
87
+ rake (13.0.3)
88
+ regexp_parser (2.1.1)
89
+ responders (3.0.1)
90
+ actionpack (>= 5.0)
91
+ railties (>= 5.0)
92
+ rexml (3.2.5)
93
+ rspec (3.10.0)
94
+ rspec-core (~> 3.10.0)
95
+ rspec-expectations (~> 3.10.0)
96
+ rspec-mocks (~> 3.10.0)
97
+ rspec-core (3.10.1)
98
+ rspec-support (~> 3.10.0)
99
+ rspec-expectations (3.10.1)
100
+ diff-lcs (>= 1.2.0, < 2.0)
101
+ rspec-support (~> 3.10.0)
102
+ rspec-mocks (3.10.2)
103
+ diff-lcs (>= 1.2.0, < 2.0)
104
+ rspec-support (~> 3.10.0)
105
+ rspec-rails (5.0.1)
106
+ actionpack (>= 5.2)
107
+ activesupport (>= 5.2)
108
+ railties (>= 5.2)
109
+ rspec-core (~> 3.10)
110
+ rspec-expectations (~> 3.10)
111
+ rspec-mocks (~> 3.10)
112
+ rspec-support (~> 3.10)
113
+ rspec-support (3.10.2)
114
+ rubocop (1.14.0)
115
+ parallel (~> 1.10)
116
+ parser (>= 3.0.0.0)
117
+ rainbow (>= 2.2.2, < 4.0)
118
+ regexp_parser (>= 1.8, < 3.0)
119
+ rexml
120
+ rubocop-ast (>= 1.5.0, < 2.0)
121
+ ruby-progressbar (~> 1.7)
122
+ unicode-display_width (>= 1.4.0, < 3.0)
123
+ rubocop-ast (1.7.0)
124
+ parser (>= 3.0.1.1)
125
+ rubocop-performance (1.11.2)
126
+ rubocop (>= 1.7.0, < 2.0)
127
+ rubocop-ast (>= 0.4.0)
128
+ ruby-progressbar (1.11.0)
129
+ simplecov (0.21.2)
130
+ docile (~> 1.1)
131
+ simplecov-html (~> 0.11)
132
+ simplecov_json_formatter (~> 0.1)
133
+ simplecov-html (0.12.3)
134
+ simplecov_json_formatter (0.1.3)
135
+ sqlite3 (1.4.2)
136
+ standard (1.1.1)
137
+ rubocop (= 1.14.0)
138
+ rubocop-performance (= 1.11.2)
139
+ thor (1.1.0)
140
+ thread_safe (0.3.6)
141
+ tzinfo (1.2.9)
142
+ thread_safe (~> 0.1)
143
+ unicode-display_width (2.0.0)
144
+ vcr (6.0.0)
145
+ warden (1.2.9)
146
+ rack (>= 2.0.9)
147
+ webmock (3.13.0)
148
+ addressable (>= 2.3.6)
149
+ crack (>= 0.3.2)
150
+ hashdiff (>= 0.4.0, < 2.0.0)
151
+
152
+ PLATFORMS
153
+ x86_64-darwin-18
154
+
155
+ DEPENDENCIES
156
+ activerecord
157
+ castle_devise!
158
+ railties (~> 5.2)
159
+ rake
160
+ rspec
161
+ rspec-rails
162
+ simplecov
163
+ sqlite3
164
+ standard
165
+ vcr
166
+ webmock
167
+
168
+ BUNDLED WITH
169
+ 2.2.15
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Castle
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,197 @@
1
+ **Disclaimer:** CastleDevise is currently in beta. There might be some upcoming breaking changes to the gem before we stabilize the API.
2
+
3
+ ---
4
+
5
+ # CastleDevice
6
+
7
+ CastleDevise is a [Devise](https://github.com/heartcombo/devise) plugin that integrates [Castle](https://castle.io).
8
+
9
+ It currently provides the following features:
10
+ - preventing bots from registration attacks using Castle's [Filter API](https://docs.castle.io/v1/reference/api-reference/#filter)
11
+ - preventing ATO attacks using Castle's [Risk API](https://docs.castle.io/v1/reference/api-reference/#risk)
12
+
13
+ If you want to learn about all capabilities of Castle, please take a look at [our documentation](https://docs.castle.io/).
14
+
15
+ ## Installation
16
+
17
+ Include `castle_devise` in your Gemfile:
18
+
19
+ ```ruby
20
+ gem 'castle_devise'
21
+ ```
22
+
23
+ Create `config/initializers/castle_devise.rb` and fill in your API secret and APP_ID from the [Castle Dashboard](https://dashboard.castle.io/settings/general)
24
+
25
+ ```ruby
26
+ CastleDevise.configure do |config|
27
+ config.api_secret = ENV.fetch('CASTLE_API_SECRET')
28
+ config.app_id = ENV.fetch('CASTLE_APP_ID')
29
+
30
+ # When monitoring mode is enabled, CastleDevise sends
31
+ # requests to Castle but it doesn't act on the "deny" verdicts.
32
+ #
33
+ # This is useful when you want to check out how Castle scores
34
+ # your traffic without blocking any of your users.
35
+ #
36
+ # Once you are ready to use Castle as your security provider,
37
+ # you can set monitoring_mode to false.
38
+ config.monitoring_mode = true
39
+ end
40
+ ```
41
+
42
+ Add `:castle_protectable` Devise module to your User model:
43
+
44
+ ```ruby
45
+ class User < ApplicationRecord
46
+ devise :database_authenticatable, :registerable,
47
+ :recoverable, :rememberable, :validatable,
48
+ :castle_protectable # <--- add this
49
+ end
50
+ ```
51
+
52
+ Add an additional translation to your `config/locales/devise.en.yml`:
53
+
54
+ ```yml
55
+ en:
56
+ devise:
57
+ registrations:
58
+ blocked_by_castle: "Account cannot be created at this moment. Please try again later."
59
+ ```
60
+
61
+ (See [devise.en.yml in our specs](spec/dummy_app/config/locales/devise.en.yml#L40))
62
+
63
+ #### Further steps if you're not using Webpacker
64
+
65
+ Include Castle's c.js script in the head section of your layout:
66
+
67
+ ```ruby
68
+ <%= castle_javascript_tag %>
69
+ ```
70
+
71
+ Add the following tag to the the `<form>` tag in both `devise/registrations/new.html.erb` and `devise/sessions/new.html.erb` (if you haven't generated them yet, run `rails generate devise:views`):
72
+
73
+ ```ruby
74
+ <%= form_for @user do |f| %>
75
+
76
+ <%= castle_request_token %>
77
+
78
+ <% end %>
79
+ ```
80
+
81
+ You're set! Now verify that everything works by logging in to your application as any user. You should be able to see that User on the [Castle Users Page](https://dashboard.castle.io/users)
82
+
83
+
84
+ #### Further steps if you're using Webpacker
85
+
86
+ Add `castle.js` to your package.json file.
87
+
88
+ TODO: fill this in.
89
+
90
+
91
+ ## How-Tos
92
+
93
+ ### Customize the login flow
94
+
95
+ #### Do something after Castle denies a login
96
+
97
+ We aim to provide sensible defaults, which means that when Castle denies a login, your application
98
+ will behave as if the User has not been authenticated. You might still want to log such an event,
99
+ and you can do this in a Warden hook:
100
+
101
+ ```ruby
102
+ Warden::Manager.before_failure do |env, opts|
103
+ # The raw Castle response if a request to Castle has been made
104
+ castle_response = env["castle_devise.risk_response"]
105
+ # CastleDevise::Context, if a request to Castle has been made
106
+ castle_context = env["castle_devise.risk_context"]
107
+
108
+ if castle_response&.dig(:policy, :action) == "deny"
109
+ # auth failed because Castle denied
110
+ end
111
+ end
112
+
113
+ ```
114
+
115
+ #### Implement your own challenge flow or do something after an "allow" action
116
+
117
+ In your `SessionsController`:
118
+
119
+ ```ruby
120
+ class SessionsController < Devise::SessionsController
121
+ def create
122
+ super do |resource|
123
+ if castle_challenge?
124
+ # At this point a User is already authenticated, you might want so sign out:
125
+ sign_out(resource)
126
+ # .... write your own MFA flow
127
+ # You can call #castle_risk_response to access Castle response
128
+ # see https://docs.castle.io/v1/reference/api-reference/#risk for details
129
+
130
+ # Fetch the Device token to use it for user feedback
131
+ # https://docs.castle.io/v1/tutorials/advanced-features/end-user-feedback
132
+ device_token = castle_risk_response.dig(:device, :token)
133
+
134
+ # You might want to fetch our risk signals as well
135
+ # https://docs.castle.io/v1/reference/signals/
136
+ event_signals = castle_risk_response[:signals].keys
137
+ return
138
+ end
139
+
140
+ # do any other action you'd like to perform after a user has been signed in below
141
+ end
142
+ end
143
+ end
144
+ ```
145
+
146
+ Please note that some Devise extensions might completely override `Devise::SessionsController#create`.
147
+ In this case, you have to handle everything manually - `castle_challenge?` should be called after
148
+ a call to `warden.authenticate!` has been successful.
149
+
150
+ #### Do not sent login/registration events
151
+
152
+ You can configure CastleDevise not to send login or registration events for a given Devise model:
153
+
154
+ ```ruby
155
+ class User < ApplicationRecord
156
+ devise :database_authenticatable, :registerable,
157
+ :castle_protectable,
158
+ castle_hooks: {
159
+ # set it to false to prevent CastleDevise
160
+ # from sending filter($login)
161
+ before_registration: true,
162
+ # set it to false to prevent CastleDevise from
163
+ # sending risk($login) and log($login, $failed)
164
+ after_login: true
165
+ }
166
+ end
167
+ ```
168
+
169
+ #### Intercept request/response
170
+
171
+ You can register before- and after- request hooks in CastleDevise.
172
+
173
+ ```ruby
174
+ CastleDevise.configure do |config|
175
+ # Add custom properties to the request but only when sending
176
+ # requests to the Risk endpoint
177
+ # action - Castle API endpoint (eg. :risk, :filter, :log)
178
+ # context - CastleDevise::Context
179
+ # payload - Hash (payload passed to the Castle SDK)
180
+ config.before_request do |action, context, payload|
181
+ if action == :risk
182
+ payload[:properties] = {
183
+ from_eu: context.resource.ip.from_eu?
184
+ }
185
+ end
186
+ end
187
+
188
+ config.before_request do |action, context, payload|
189
+ # you can register multiple before_request hooks
190
+ end
191
+
192
+ # Intercept the response - enrich your logs with Castle signals
193
+ config.after_request do |action, context, payload, response|
194
+ Logging.add_tags(response[:signals].keys)
195
+ end
196
+ end
197
+ ```