padlock_auth 0.1.1 → 0.2.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 +4 -4
- data/README.md +88 -0
- data/lib/padlock_auth/config.rb +11 -0
- data/lib/padlock_auth/rails/action_cable_channel_helpers.rb +71 -0
- data/lib/padlock_auth/rails/helpers.rb +6 -2
- data/lib/padlock_auth/railtie.rb +4 -0
- data/lib/padlock_auth/version.rb +1 -1
- data/lib/padlock_auth.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8d0c8061b83de8516e459e26ef96d6e6565f419045c64e7730c4736e7c7c344
|
4
|
+
data.tar.gz: 69972dfbcda669fd154c109ef4512d1719e6dafcc52dba780ce1ec80dd4efbeb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63297a7bbed887a8120b3c2d7ddd6e33d8d23ddc83352d3d6141d92d23af6271f5c0d866061524649122e90cb67032f995126e5174a7cf7469f583f66674b0ce
|
7
|
+
data.tar.gz: f9d820e5872e376d05b5724bfbf675bf6597cc72065cff1ac56605cfec0a6de9bbd89f38b2e29b6bfcbd4784cac5095351f434a23d51ac60424da4b7a45ce93a
|
data/README.md
CHANGED
@@ -239,6 +239,94 @@ puts response.body
|
|
239
239
|
|
240
240
|
PadlockAuth will extract the username and password using the `from_basic_authorization` method and use them to generate an access token.
|
241
241
|
|
242
|
+
### Securing an Action Cable Connection
|
243
|
+
|
244
|
+
You can use PadlockAuth to secure your Action Cable connections by verifying an access token during the connection process. The access token can be provided via the `"access_token"` or `"bearer_token"` parameters.
|
245
|
+
|
246
|
+
Not all access tokens provide a `subject` method, it is entirely dependent on the implementation.
|
247
|
+
|
248
|
+
Here’s an example implementation:
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
module ApplicationCable
|
252
|
+
class Connection < ActionCable::Connection::Base
|
253
|
+
identified_by :access_token_subject
|
254
|
+
|
255
|
+
def connect
|
256
|
+
self.access_token_subject = find_verified_subject
|
257
|
+
end
|
258
|
+
|
259
|
+
private
|
260
|
+
|
261
|
+
def find_verified_subject
|
262
|
+
if padlock_authorized? "websocket"
|
263
|
+
padlock_auth_token.subject
|
264
|
+
else
|
265
|
+
reject_unauthorized_connection
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
```
|
271
|
+
|
272
|
+
#### Explanation
|
273
|
+
|
274
|
+
- `padlock_authorized?`: Checks if the access token is valid and optionally verifies the required scope (`"websocket"` in this example).
|
275
|
+
- `padlock_auth_token`: Provides access to the verified token, allowing you to retrieve attributes such as `subject`.
|
276
|
+
|
277
|
+
This ensures that only clients with valid access tokens can establish a WebSocket connection. The access token `sub` can then be used to identify the connected client throughout the session.
|
278
|
+
|
279
|
+
#### Example: Connecting to the Action Cable Connection via JS
|
280
|
+
|
281
|
+
```js
|
282
|
+
import { createConsumer } from "@rails/actioncable"
|
283
|
+
|
284
|
+
// Use a function to dynamically generate the URL
|
285
|
+
createConsumer(getWebSocketURL)
|
286
|
+
|
287
|
+
function getWebSocketURL() {
|
288
|
+
const token = localStorage.get('access-token')
|
289
|
+
return `wss://example.com/cable?token=${token}`
|
290
|
+
}
|
291
|
+
```
|
292
|
+
|
293
|
+
### Securing an ActionCable Channel
|
294
|
+
|
295
|
+
PadlockAuth can secure individual Action Cable channels by verifying an access token when a client subscribes. The access token can be provided via the `"access_token"` or `"bearer_token"` parameters.
|
296
|
+
|
297
|
+
Here’s an example implementation:
|
298
|
+
|
299
|
+
```ruby
|
300
|
+
class AuthorizedChannel < ApplicationCable::Channel
|
301
|
+
def subscribed
|
302
|
+
if padlock_authorized? "channel"
|
303
|
+
stream_from "authorized_stream"
|
304
|
+
else
|
305
|
+
reject
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def unsubscribed
|
310
|
+
# Any cleanup needed when channel is unsubscribed
|
311
|
+
end
|
312
|
+
end
|
313
|
+
```
|
314
|
+
|
315
|
+
#### Explanation
|
316
|
+
|
317
|
+
- `padlock_authorized?`: Validates the access token and ensures it includes the required scope (`"channel"` in this example).
|
318
|
+
|
319
|
+
By leveraging these features, PadlockAuth ensures only authenticated users with the proper access scope can subscribe and receive messages on the channel.
|
320
|
+
|
321
|
+
#### Example: Connecting to the Action Cable Channel via JS
|
322
|
+
|
323
|
+
```js
|
324
|
+
import consumer from "./consumer"
|
325
|
+
|
326
|
+
const token = localStorage.get('access-token')
|
327
|
+
consumer.subscriptions.create({ channel: "AuthorizedChannel", access_token: token })
|
328
|
+
```
|
329
|
+
|
242
330
|
## Installation
|
243
331
|
|
244
332
|
Add this line to your application's Gemfile:
|
data/lib/padlock_auth/config.rb
CHANGED
@@ -94,6 +94,10 @@ module PadlockAuth
|
|
94
94
|
config.instance_variable_set(:@access_token_methods, methods.flatten.compact)
|
95
95
|
end
|
96
96
|
|
97
|
+
def action_cable_methods(*methods)
|
98
|
+
config.instance_variable_set(:@action_cable_methods, methods.flatten.compact)
|
99
|
+
end
|
100
|
+
|
97
101
|
# Calls to `padlock_authorize!` will raise an exception when authentication fails.
|
98
102
|
#
|
99
103
|
def raise_on_errors!
|
@@ -167,6 +171,13 @@ module PadlockAuth
|
|
167
171
|
]
|
168
172
|
end
|
169
173
|
|
174
|
+
def action_cable_methods
|
175
|
+
@action_cable_methods ||= %i[
|
176
|
+
from_access_token_param
|
177
|
+
from_bearer_param
|
178
|
+
]
|
179
|
+
end
|
180
|
+
|
170
181
|
# @!attribute [r] handle_auth_errors
|
171
182
|
#
|
172
183
|
# How to handle authentication errors.
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module PadlockAuth
|
2
|
+
module Rails
|
3
|
+
module ActionCableChannelHelpers
|
4
|
+
module TokenFactory
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# Retreives the access token from the request using the configured methods.
|
8
|
+
def from_params(params, *methods)
|
9
|
+
methods.inject(nil) do |_, method|
|
10
|
+
method = self.method(method) if method.is_a?(Symbol)
|
11
|
+
credentials = method.call(params)
|
12
|
+
break credentials if credentials.present?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Retreives the access token from the params, and builds an access token object.
|
17
|
+
def authenticate(params)
|
18
|
+
if (token = from_params(params, *PadlockAuth.config.action_cable_methods))
|
19
|
+
PadlockAuth.build_access_token(token)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Extracts the access token from the `access_token` parameter.
|
24
|
+
#
|
25
|
+
# @param params [ActionDispatch::Request] params
|
26
|
+
#
|
27
|
+
# @return [String, nil] Access token
|
28
|
+
#
|
29
|
+
def from_access_token_param(params)
|
30
|
+
params[:access_token]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Extracts the access token from the `bearer_token` parameter.
|
34
|
+
#
|
35
|
+
# @param params [ActiveSupport::HashWithIndifferentAccess] params
|
36
|
+
#
|
37
|
+
# @return [String, nil] Access token
|
38
|
+
#
|
39
|
+
def from_bearer_param(params)
|
40
|
+
params[:bearer_token]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @!visibility public
|
45
|
+
#
|
46
|
+
# Authorize the request with the given scopes.
|
47
|
+
#
|
48
|
+
# If the request is not authorized, an error response will be rendered
|
49
|
+
# or an exception will be raised, depending on the configuration.
|
50
|
+
#
|
51
|
+
# @param scopes [Array<String>] Scopes required for the request, defaults to the default scopes.
|
52
|
+
# @return [Boolean] Whether the request is authorized.
|
53
|
+
#
|
54
|
+
def padlock_authorized?(*scopes)
|
55
|
+
padlock_auth_token&.acceptable?(scopes.presence || PadlockAuth.config.default_scopes)
|
56
|
+
end
|
57
|
+
|
58
|
+
# @!visibility public
|
59
|
+
#
|
60
|
+
# Retrieve the access token from the request.
|
61
|
+
#
|
62
|
+
# Does not check if the token is valid or matches the required scopes.
|
63
|
+
#
|
64
|
+
# @return [PadlockAuth::AbstractToken, nil] Access token
|
65
|
+
#
|
66
|
+
def padlock_auth_token
|
67
|
+
@padlock_auth_token ||= TokenFactory.authenticate(params)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -16,10 +16,14 @@ module PadlockAuth
|
|
16
16
|
#
|
17
17
|
# @param scopes [Array<String>] Scopes required for the request, defaults to the default scopes.
|
18
18
|
#
|
19
|
-
def padlock_authorize!(
|
19
|
+
def padlock_authorize!(...)
|
20
|
+
padlock_render_error unless padlock_authorized?(...)
|
21
|
+
end
|
22
|
+
|
23
|
+
def padlock_authorized?(*scopes)
|
20
24
|
@_padlock_auth_scopes = scopes.presence || PadlockAuth.config.default_scopes
|
21
25
|
|
22
|
-
|
26
|
+
valid_padlock_auth_token?
|
23
27
|
end
|
24
28
|
|
25
29
|
# Default render options for unauthorized requests.
|
data/lib/padlock_auth/railtie.rb
CHANGED
@@ -11,6 +11,10 @@ module PadlockAuth
|
|
11
11
|
ActiveSupport.on_load(:action_controller) do
|
12
12
|
include PadlockAuth::Rails::Helpers
|
13
13
|
end
|
14
|
+
ActiveSupport.on_load(:action_cable) do
|
15
|
+
ActionCable::Connection::Base.include PadlockAuth::Rails::Helpers
|
16
|
+
ActionCable::Channel::Base.include PadlockAuth::Rails::ActionCableChannelHelpers
|
17
|
+
end
|
14
18
|
end
|
15
19
|
|
16
20
|
initializer "padlock_auth.i18n" do
|
data/lib/padlock_auth/version.rb
CHANGED
data/lib/padlock_auth.rb
CHANGED
@@ -40,7 +40,7 @@ module PadlockAuth
|
|
40
40
|
|
41
41
|
# Rails-specific classes
|
42
42
|
module Rails
|
43
|
-
autoload :
|
43
|
+
autoload :ActionCableChannelHelpers, "padlock_auth/rails/action_cable_channel_helpers"
|
44
44
|
autoload :Helpers, "padlock_auth/rails/helpers"
|
45
45
|
autoload :TokenFactory, "padlock_auth/rails/token_factory"
|
46
46
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: padlock_auth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Morrall
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -104,6 +104,7 @@ files:
|
|
104
104
|
- lib/padlock_auth/http/invalid_token_response.rb
|
105
105
|
- lib/padlock_auth/mixins/build_with.rb
|
106
106
|
- lib/padlock_auth/mixins/hide_attribute.rb
|
107
|
+
- lib/padlock_auth/rails/action_cable_channel_helpers.rb
|
107
108
|
- lib/padlock_auth/rails/helpers.rb
|
108
109
|
- lib/padlock_auth/rails/token_factory.rb
|
109
110
|
- lib/padlock_auth/railtie.rb
|