rabbitmq_http_auth_backend 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/rabbitmq_http_auth_backend.svg)](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
|