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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 96a75df203d47f917752b3cef73ec78a6e3f6a570db3c1e92f778c380276ef1b
4
- data.tar.gz: aee167ba2a0804d262a564b15a53bce8df4ccb17a243999750eec2e8cc8d59e2
3
+ metadata.gz: fd12d683b1642bfeee042ebe891b33d2ca4e81c2d7bcb55be0764e1f04eee17d
4
+ data.tar.gz: de3568b054e40b4c40c3c44e01787084bc134a28e4baec90e88e1ab1808a610d
5
5
  SHA512:
6
- metadata.gz: 1946c3abd0c748a6cf11c16a71e52d0d16ad85ac338cd813a6f7625320511a89bda3549abe8a3827a137c9839c8492203071b319c07717217cf9859e0ad4ee8e
7
- data.tar.gz: 273f0c29de8a6f6c31d8c2593e7d86bb21426e5da84c7079626766984eff535651079e3dac58202bec98b3989d7519a29cb01ef036548fa28d18acf52f38b489
6
+ metadata.gz: ff46159edf0371a1c8ace6e7f95a3f6ad54f679fd27f321ff7411a6e7be4d9cf8613636acc0117faaae4d58b24ae86049519db83b61582e96380fb22467bdb12
7
+ data.tar.gz: 910e309b702173ec6cd8420f136bf446b1e908fe33abc3191c9df44abac5f17d5c60f276eed581709b6a650c047e7aa4e55a1af63404684a2476ccc5085f3743
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rabbitmq_http_auth_backend (1.0.0)
4
+ rabbitmq_http_auth_backend (1.1.0)
5
5
  roda (~> 3.0)
6
6
 
7
7
  GEM
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, ['admin', 'manager']
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
- A "native" configuration DSL is also provided. The DSL provides utility methods
148
- such as `username`, `password`, `vhost`, `resource`, `name`, `permission`, `ip`
149
- and `routing_key`. Any utility methods `allow!` and `deny!` can be used to set
150
- the return value (they don't have to be the return value).
151
- Just note that they don't stop execution!
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
@@ -50,4 +50,5 @@ module RabbitMQHttpAuthBackend
50
50
  end
51
51
  end
52
52
 
53
+ require 'rabbitmq_http_auth_backend/basic_resolver'
53
54
  require 'rabbitmq_http_auth_backend/resolver/runtime'
@@ -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
- @params = params
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
@@ -3,7 +3,7 @@
3
3
  module RabbitMQHttpAuthBackend
4
4
  module Version
5
5
  MAJOR = 1
6
- MINOR = 0
6
+ MINOR = 1
7
7
  PATCH = 0
8
8
 
9
9
  FULL = [MAJOR, MINOR, PATCH].join('.').freeze
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.0.0
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-02 00:00:00.000000000 Z
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