rabbitmq_http_auth_backend 1.0.0 → 1.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +216 -27
- data/lib/rabbitmq_http_auth_backend/basic_resolver.rb +71 -0
- data/lib/rabbitmq_http_auth_backend/resolver.rb +1 -0
- data/lib/rabbitmq_http_auth_backend/resolver/runtime.rb +2 -51
- data/lib/rabbitmq_http_auth_backend/version.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: fd12d683b1642bfeee042ebe891b33d2ca4e81c2d7bcb55be0764e1f04eee17d
|
4
|
+
data.tar.gz: de3568b054e40b4c40c3c44e01787084bc134a28e4baec90e88e1ab1808a610d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff46159edf0371a1c8ace6e7f95a3f6ad54f679fd27f321ff7411a6e7be4d9cf8613636acc0117faaae4d58b24ae86049519db83b61582e96380fb22467bdb12
|
7
|
+
data.tar.gz: 910e309b702173ec6cd8420f136bf446b1e908fe33abc3191c9df44abac5f17d5c60f276eed581709b6a650c047e7aa4e55a1af63404684a2476ccc5085f3743
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
Mountable Rack application that implements a configurable API for RabbitMQ's
|
4
4
|
[rabbitmq-auth-backend-http](https://github.com/rabbitmq/rabbitmq-auth-backend-http).
|
5
5
|
|
6
|
+
[](https://badge.fury.io/rb/rabbitmq_http_auth_backend)
|
7
|
+
|
6
8
|
## Purpose
|
7
9
|
|
8
10
|
RabbitMQ comes bundled with the [rabbitmq-auth-backend-http](https://github.com/rabbitmq/rabbitmq-auth-backend-http)
|
@@ -21,6 +23,21 @@ This library implements all of this as a mountable Rack application. Meaning,
|
|
21
23
|
after minimal configuration your application can implement the four required
|
22
24
|
endpoints and respond with correctly formated responses.
|
23
25
|
|
26
|
+
## Index
|
27
|
+
|
28
|
+
1. [Usage](#usage)
|
29
|
+
1. [Mounting the endpoint](#mounting-the-endpoint)
|
30
|
+
2. [Configuration](#configuration)
|
31
|
+
3. [Resolvers](#resolvers)
|
32
|
+
4. [Versioning](#versioning)
|
33
|
+
5. [Default configuration](#default-configuration)
|
34
|
+
2. [Installation](#installation)
|
35
|
+
3. [FAQ](#faq)
|
36
|
+
4. [Change log](#change-log)
|
37
|
+
5. [Development](#development)
|
38
|
+
6. [Contributing](#contributing)
|
39
|
+
7. [License](#license)
|
40
|
+
|
24
41
|
## Usage
|
25
42
|
|
26
43
|
1. [Mounting the endpoint](#mounting-the-endpoint)
|
@@ -42,7 +59,7 @@ For **Rails** applications, add the following line to your `routes.rb` file:
|
|
42
59
|
```ruby
|
43
60
|
# /config/routes.rb
|
44
61
|
Rails.application.routes.draw do
|
45
|
-
mount RabbitMQHttpAuthBackend.app => '/rabbitmq/auth'
|
62
|
+
mount RabbitMQHttpAuthBackend.app => '/rabbitmq/auth', as: 'rmq_auth_api'
|
46
63
|
end
|
47
64
|
```
|
48
65
|
|
@@ -121,7 +138,7 @@ RabbitMQHttpAuthBackend.configure! do
|
|
121
138
|
path '/anvandare'
|
122
139
|
resolver(lambda do |params|
|
123
140
|
if params['username'] == 'admin'
|
124
|
-
return :allow
|
141
|
+
return :allow, [:admin, :moderator]
|
125
142
|
end
|
126
143
|
|
127
144
|
:deny
|
@@ -136,7 +153,11 @@ end
|
|
136
153
|
class TopicsResolver
|
137
154
|
def self.call(params)
|
138
155
|
if params['username'] == 'admin'
|
139
|
-
return :allow
|
156
|
+
return :allow
|
157
|
+
end
|
158
|
+
|
159
|
+
if params['permission'] == 'read' && params['name'] == 'messages'
|
160
|
+
return :allow
|
140
161
|
end
|
141
162
|
|
142
163
|
:deny
|
@@ -144,11 +165,70 @@ class TopicsResolver
|
|
144
165
|
end
|
145
166
|
```
|
146
167
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
168
|
+
Most commonly used methods related to resolvers are extracted to the
|
169
|
+
`BasicResolver` class. Any class inheriting from it becomes a callable object
|
170
|
+
on the class and instance level. The user is expected to implement the `#call`
|
171
|
+
method.
|
172
|
+
|
173
|
+
The following methods are available within a class inheriting from
|
174
|
+
`BasicResolver`:
|
175
|
+
|
176
|
+
| Method | Description |
|
177
|
+
|:--------------|:-------------------------------------------------------------|
|
178
|
+
| `username` | Returns the user's username |
|
179
|
+
| `password` | Returns the user's password |
|
180
|
+
| `name` | Returns the name of the resource |
|
181
|
+
| `queue?` | Returns true if the queried resource is a queue |
|
182
|
+
| `exchange?` | Returns true if the queried resource is an exchange |
|
183
|
+
| `topic?` | Returns true if the queried resource is a topic |
|
184
|
+
| `resource` | Returns the resource type (as a String, e.g. `'exchange'`) |
|
185
|
+
| `read?` | Returns true if the queried permission is read |
|
186
|
+
| `write?` | Returns true if the queried permission is write |
|
187
|
+
| `configure?` | Returns true if the queried permission is write |
|
188
|
+
| `permission` | Returns the requested permission (as a String, e.g. `'read'`)|
|
189
|
+
| `routing_key` | Returns the queried routing key |
|
190
|
+
| `vhost` | Returns the queried vhost |
|
191
|
+
| `ip` | Returns the IP address of the client querying |
|
192
|
+
|
193
|
+
The following is the same as the `TopicsResolver` from the previous example, but
|
194
|
+
rewritten using `BasicResolver`:
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
class TopicsResolver < RabbitMQHttpAuthBackend::BasicResolver
|
198
|
+
def call
|
199
|
+
return :allow if username == 'admin'
|
200
|
+
return :allow if name == 'messages' && read?
|
201
|
+
:deny
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# This makes `TopicsResolver` a callable object on the class level
|
206
|
+
# > TopicsResolver.call(params)
|
207
|
+
# And it's callable on the instance level
|
208
|
+
# > TopicsResolver.new(params).call
|
209
|
+
```
|
210
|
+
|
211
|
+
A "native" configuration DSL is also provided. The DSL provides the same utility
|
212
|
+
methods as `BasicResolver` as well as `allow!`, `deny!`, `tags`, `allowed?` and
|
213
|
+
`denised?` which can be used to set the result or to query it - note that they
|
214
|
+
don't stop execution!
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
# /config/initializers/rabbitmq_http_auth_backend.rb
|
218
|
+
RabbitMQHttpAuthBackend.configure! do
|
219
|
+
http_method :post
|
220
|
+
|
221
|
+
topic do
|
222
|
+
resolver do
|
223
|
+
if username == 'admin'
|
224
|
+
allow! ['admin', 'manager']
|
225
|
+
else
|
226
|
+
deny!
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
```
|
152
232
|
|
153
233
|
Not all methods return usable values for all resources. Here's a list:
|
154
234
|
* user
|
@@ -172,23 +252,6 @@ Not all methods return usable values for all resources. Here's a list:
|
|
172
252
|
- `permission` (can return `:configure`, `:read` or `:write`)
|
173
253
|
- `routing_key` (of the published message if the permission is `:write`, else of the queue binding)
|
174
254
|
|
175
|
-
```ruby
|
176
|
-
# /config/initializers/rabbitmq_http_auth_backend.rb
|
177
|
-
RabbitMQHttpAuthBackend.configure! do
|
178
|
-
http_method :post
|
179
|
-
|
180
|
-
topic do
|
181
|
-
resolver do
|
182
|
-
if username == 'admin'
|
183
|
-
allow! ['admin', 'manager']
|
184
|
-
else
|
185
|
-
deny!
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
```
|
191
|
-
|
192
255
|
### Versioning
|
193
256
|
|
194
257
|
Everybody makes mistakes and changes their minds. Therefore this library
|
@@ -309,10 +372,136 @@ Mount the application:
|
|
309
372
|
```ruby
|
310
373
|
# /config/routes.rb
|
311
374
|
Rails.application.routes.draw do
|
312
|
-
mount RabbitMQHttpAuthBackend.app => '/rabbitmq/auth'
|
375
|
+
mount RabbitMQHttpAuthBackend.app => '/rabbitmq/auth', as: 'rmq_auth_api'
|
313
376
|
end
|
314
377
|
```
|
315
378
|
|
379
|
+
You are done!
|
380
|
+
|
381
|
+
```
|
382
|
+
bash-4.4$ curl localhost:3000/rabbitmq/auth/user && echo
|
383
|
+
deny
|
384
|
+
```
|
385
|
+
|
386
|
+
## FAQ
|
387
|
+
|
388
|
+
<details>
|
389
|
+
<summary>You use a version in your installation example. Do I have to use a version?</summary>
|
390
|
+
<p>
|
391
|
+
You don't have to, but I would advise you do.
|
392
|
+
Editing the default configuration might cause you problems in the future
|
393
|
+
when you would like to have a clean slate.
|
394
|
+
</p>
|
395
|
+
</details>
|
396
|
+
|
397
|
+
<details>
|
398
|
+
<summary>Why does the "native" DSL exist?</summary>
|
399
|
+
<p>
|
400
|
+
To provide a simple configuration language to accomplish basic tasks. I
|
401
|
+
would advise you to use `BasicResolver` or a custom resolver callable object
|
402
|
+
for anything other than the most basic use case e.g. check a username or IP.
|
403
|
+
</p>
|
404
|
+
</details>
|
405
|
+
|
406
|
+
<details>
|
407
|
+
<summary>Can my path be nested? E.g. `/foo/bar/baz/cux`?</summary>
|
408
|
+
<p>Yes they can.</p>
|
409
|
+
</details>
|
410
|
+
|
411
|
+
<details>
|
412
|
+
<summary>Can my path contain arguments? E.g. `/foo/:name/bar`?</summary>
|
413
|
+
<p>At the moment, no.</p>
|
414
|
+
</details>
|
415
|
+
|
416
|
+
<details>
|
417
|
+
<summary>Does this library handle caching for me?</summary>
|
418
|
+
<p>
|
419
|
+
No. This feature was removed from the original implementation of this
|
420
|
+
library.
|
421
|
+
</p>
|
422
|
+
<p>
|
423
|
+
Caching is a tricky topic. It's hard to get right. I couldn't find an
|
424
|
+
expressive enough interface for handling cache invalidation that would
|
425
|
+
satisfy my needs or be flexible enough to accommodate the use cases I think
|
426
|
+
are common. Therefore I decided against implementing caching within this
|
427
|
+
library.
|
428
|
+
</p>
|
429
|
+
<p>
|
430
|
+
I recommend that you implement your custom caching and invalidation logic
|
431
|
+
in a custom resolver.
|
432
|
+
</p>
|
433
|
+
<p>
|
434
|
+
Also, use the <a href="https://github.com/rabbitmq/rabbitmq-auth-backend-cache">rabbitmq-auth-backend-cache</a> plugin.
|
435
|
+
It provides time based client-side caching and comes standard with RabbitMQ 3.7+
|
436
|
+
</p>
|
437
|
+
<p>
|
438
|
+
Here is an example of a fully configured HTTP auth backend plugin in
|
439
|
+
conjunction with the caching plugin:
|
440
|
+
</p>
|
441
|
+
<pre>
|
442
|
+
auth_backends.1 = internal
|
443
|
+
auth_backends.2 = cache
|
444
|
+
auth_cache.cached_backend = http
|
445
|
+
auth_http.http_method = get
|
446
|
+
auth_http.user_path = http://localhost:3000/rabbitmq/auth/user
|
447
|
+
auth_http.vhost_path = http://localhost:3000/rabbitmq/auth/vhost
|
448
|
+
auth_http.resource_path = http://localhost:3000/rabbitmq/auth/resource
|
449
|
+
auth_http.topic_path = http://localhost:3000/rabbitmq/auth/topic
|
450
|
+
</pre>
|
451
|
+
</details>
|
452
|
+
|
453
|
+
<details>
|
454
|
+
<summary>How do you use Rabbit's HTTP backend?</summary>
|
455
|
+
<p>
|
456
|
+
Follow the installation instructions in this guide to setup your Rack
|
457
|
+
(Rails/Roda/Sinatra/...) application as an HTTP auth backend. Then add
|
458
|
+
the following to your `rabbitmq.conf`, located within `/etc/rabbitmq`
|
459
|
+
(if it's not there, create it).
|
460
|
+
</p>
|
461
|
+
<pre>
|
462
|
+
auth_backends.1 = internal
|
463
|
+
auth_backends.2 = http
|
464
|
+
auth_http.http_method = get
|
465
|
+
auth_http.user_path = http://localhost:3000/rabbitmq/auth/user
|
466
|
+
auth_http.vhost_path = http://localhost:3000/rabbitmq/auth/vhost
|
467
|
+
auth_http.resource_path = http://localhost:3000/rabbitmq/auth/resource
|
468
|
+
auth_http.topic_path = http://localhost:3000/rabbitmq/auth/topic
|
469
|
+
</pre>
|
470
|
+
<p>
|
471
|
+
Assuming that your application and RabbitMQ instance are on the same
|
472
|
+
machine, and that your application is exposed on port 3000 everything
|
473
|
+
should just work™️.
|
474
|
+
</p>
|
475
|
+
<p>
|
476
|
+
If it doesn't work try restarting RabbitMQ and your application.
|
477
|
+
</p>
|
478
|
+
<p>
|
479
|
+
If your application and RabbitMQ instance aren't on the same machine, make
|
480
|
+
sure that the RabbitMQ instance can access your application, the
|
481
|
+
easiest way to do this is to connect to the RabbitMQ server and using
|
482
|
+
`ping <your application URL or IP>` or `curl <your application URL or IP>:<your application port>`.
|
483
|
+
Remember to change the `localhost:3000` in `rabbitmq.conf` to your
|
484
|
+
application's URL or IP.
|
485
|
+
</p>
|
486
|
+
</details>
|
487
|
+
|
488
|
+
<details>
|
489
|
+
<summary>Why does this library depend on Roda?</summary>
|
490
|
+
<p>
|
491
|
+
<a href="https://github.com/jeremyevans/roda">Roda</a> is, in my opinion, a lightweight framework around Rack.
|
492
|
+
I prefer it over raw Rack - since, in my opinion, the overhead of it is
|
493
|
+
negligible over raw Rack I use it as a more ergonomic interface to create
|
494
|
+
Rack applications.
|
495
|
+
</p>
|
496
|
+
</details>
|
497
|
+
|
498
|
+
## Change log
|
499
|
+
|
500
|
+
All changes between versions are logged to the change log available in the
|
501
|
+
[CHANGELOG.md file](/CHANGELOG.md).
|
502
|
+
|
503
|
+
This project follows the [semantic versioning schema](https://semver.org/).
|
504
|
+
|
316
505
|
## Development
|
317
506
|
|
318
507
|
After checking out the repo, run `bin/setup` to install dependencies.
|
@@ -329,7 +518,7 @@ to [rubygems.org](https://rubygems.org).
|
|
329
518
|
## Contributing
|
330
519
|
|
331
520
|
Bug reports and pull requests are welcome on GitHub at
|
332
|
-
https://github.com/monorkin/rabbitmq_http_auth_backend
|
521
|
+
[https://github.com/monorkin/rabbitmq_http_auth_backend/](https://github.com/monorkin/rabbitmq_http_auth_backend/).
|
333
522
|
|
334
523
|
## License
|
335
524
|
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RabbitMQHttpAuthBackend
|
4
|
+
class BasicResolver < Service
|
5
|
+
def initialize(params)
|
6
|
+
@params = params
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
attr_reader :params
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def username
|
16
|
+
params['username']
|
17
|
+
end
|
18
|
+
|
19
|
+
def password
|
20
|
+
params['password']
|
21
|
+
end
|
22
|
+
|
23
|
+
def name
|
24
|
+
params['name']
|
25
|
+
end
|
26
|
+
|
27
|
+
def queue?
|
28
|
+
resource == 'queue'
|
29
|
+
end
|
30
|
+
|
31
|
+
def exchange?
|
32
|
+
resource == 'exchange'
|
33
|
+
end
|
34
|
+
|
35
|
+
def topic?
|
36
|
+
resource == 'topic'
|
37
|
+
end
|
38
|
+
|
39
|
+
def resource
|
40
|
+
params['resource']
|
41
|
+
end
|
42
|
+
|
43
|
+
def read?
|
44
|
+
permission == 'read'
|
45
|
+
end
|
46
|
+
|
47
|
+
def write?
|
48
|
+
permission == 'write'
|
49
|
+
end
|
50
|
+
|
51
|
+
def configure?
|
52
|
+
permission == 'configure'
|
53
|
+
end
|
54
|
+
|
55
|
+
def permission
|
56
|
+
params['permission']
|
57
|
+
end
|
58
|
+
|
59
|
+
def routing_key
|
60
|
+
params['routing_key']
|
61
|
+
end
|
62
|
+
|
63
|
+
def vhost
|
64
|
+
params['vhost']
|
65
|
+
end
|
66
|
+
|
67
|
+
def ip
|
68
|
+
params['ip']
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -2,17 +2,12 @@
|
|
2
2
|
|
3
3
|
module RabbitMQHttpAuthBackend
|
4
4
|
class Resolver
|
5
|
-
class Runtime
|
6
|
-
class Error < RabbitMQHttpAuthBackend::Error; end
|
7
|
-
class InvalidResourceError < Error; end
|
8
|
-
class InvalidPermissionError < Error; end
|
9
|
-
|
10
|
-
attr_reader :params
|
5
|
+
class Runtime < BasicResolver
|
11
6
|
attr_accessor :tags
|
12
7
|
attr_accessor :_allowed
|
13
8
|
|
14
9
|
def initialize(params)
|
15
|
-
|
10
|
+
super(params)
|
16
11
|
self.tags = nil
|
17
12
|
self._allowed = false
|
18
13
|
end
|
@@ -34,50 +29,6 @@ module RabbitMQHttpAuthBackend
|
|
34
29
|
def denied?
|
35
30
|
!allowed?
|
36
31
|
end
|
37
|
-
|
38
|
-
def username
|
39
|
-
params['username']
|
40
|
-
end
|
41
|
-
|
42
|
-
def password
|
43
|
-
params['password']
|
44
|
-
end
|
45
|
-
|
46
|
-
def vhost
|
47
|
-
params['vhost']
|
48
|
-
end
|
49
|
-
|
50
|
-
def resource
|
51
|
-
@resource ||=
|
52
|
-
case params['resource']
|
53
|
-
when 'exchange' then :exchange
|
54
|
-
when 'queue' then :queue
|
55
|
-
when 'topic' then :topic
|
56
|
-
else raise(InvalidResourceError)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def name
|
61
|
-
params['name']
|
62
|
-
end
|
63
|
-
|
64
|
-
def permission
|
65
|
-
@permission ||=
|
66
|
-
case params['permission']
|
67
|
-
when 'configure' then :configure
|
68
|
-
when 'write' then :write
|
69
|
-
when 'read' then :read
|
70
|
-
else raise(InvalidPermissionError)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def ip
|
75
|
-
params['ip']
|
76
|
-
end
|
77
|
-
|
78
|
-
def routing_key
|
79
|
-
params['routing_key']
|
80
|
-
end
|
81
32
|
end
|
82
33
|
end
|
83
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rabbitmq_http_auth_backend
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stanko K.R.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-05-
|
11
|
+
date: 2019-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: roda
|
@@ -109,6 +109,7 @@ files:
|
|
109
109
|
- lib/rabbitmq_http_auth_backend.rb
|
110
110
|
- lib/rabbitmq_http_auth_backend/app.rb
|
111
111
|
- lib/rabbitmq_http_auth_backend/app/response_formatter.rb
|
112
|
+
- lib/rabbitmq_http_auth_backend/basic_resolver.rb
|
112
113
|
- lib/rabbitmq_http_auth_backend/config.rb
|
113
114
|
- lib/rabbitmq_http_auth_backend/config/runtime.rb
|
114
115
|
- lib/rabbitmq_http_auth_backend/resolver.rb
|