pact_broker 1.17.2 → 1.18.0.beta.1

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
  SHA1:
3
- metadata.gz: ddeb15f7e5f35bcccea163c2bdb0f96f0f76904e
4
- data.tar.gz: 3eec1a584c7dc3bf0669a08e983a620dd94950c6
3
+ metadata.gz: c780083d99fd7a3c73e53f16b703c3bfe5b86a78
4
+ data.tar.gz: aa8ef0eb97c2e18461179607d395c7b493e9f50e
5
5
  SHA512:
6
- metadata.gz: f47149c6ca610fcc5e76222f25b69cf78b53928d536459ed5b854bd63b8127bf2df8fe940285169c430c064fc850072430774a0408c93d88022520c3c6f0aef1
7
- data.tar.gz: 66e8590f37514286d4dcc04efdbeef38c1ad54e9b20a801307e1e9e908dfc5ff53ebea473e5c197172a46ed56bf16b3ffe419a7e22171656c9a508cfea946c9b
6
+ metadata.gz: 63db04af90da66ce5833f9f2de88f734529f94c7ebb759ffe4a8eb89f5a7cf5b439c221bf5464bf4d499f5e326038668dd58e5ebbff6f9db31ab7a9b92669861
7
+ data.tar.gz: 261ccb52f5819dc9d9eee9c1088bff11c0d6fb3269492d68e1de25f5687e66adc7a814a43ad7c69c8e3b883ec10ca5e0bf865a0e46bf5f515011384057e402fd
data/CHANGELOG.md CHANGED
@@ -2,6 +2,9 @@ Do this to generate your change history
2
2
 
3
3
  $ git log --pretty=format:' * %h - %s (%an, %ad)' vX.Y.Z..HEAD
4
4
 
5
+ #### 1.18.0.beta.1 (2017-05-05)
6
+ * 99e825b - Add in-built configuration for basic auth. (Beth Skurrie, Fri May 5 10:22:53 2017 +1000)
7
+
5
8
  #### 1.17.2 (2017-05-04)
6
9
  * b8f45e1 - fix issue with pact document link not displaying #94 (Matt Fellows, Wed May 3 11:23:09 2017 +1000)
7
10
 
data/example/config.ru CHANGED
@@ -27,6 +27,8 @@ app = PactBroker::App.new do | config |
27
27
  # config.use_hal_browser = true
28
28
  config.database_connection = Sequel.connect(DATABASE_CREDENTIALS.merge(:logger => config.logger))
29
29
  config.database_connection.timezone = :utc
30
+ # See configuration section of wiki for more basic auth configuration options
31
+ # config.protect_with_basic_auth :app_read, {username: 'username', password: 'password'}
30
32
  end
31
33
 
32
34
  run app
File without changes
File without changes
@@ -27,7 +27,7 @@ $ git push heroku master
27
27
  Your Pact Broker instance is now available!
28
28
 
29
29
  ## Publish consumer pacts - consumer side
30
- You will need to set these environment variables with your basic auth credentials
30
+ You will need to set these environment variables with your basic auth credentials
31
31
  ```
32
32
  export PACT_BROKER_USERNAME=admin
33
33
  export PACT_BROKER_PASSWORD=changeme
@@ -0,0 +1,12 @@
1
+ require 'fileutils'
2
+ require 'logger'
3
+ require 'sequel'
4
+ require 'pact_broker'
5
+ require 'pg'
6
+
7
+ app = PactBroker::App.new do | config |
8
+ config.database_connection = Sequel.connect(ENV['DATABASE_URL'], adapter: "postgres", encoding: 'utf8')
9
+ config.protect_with_basic_auth :all, {username: ENV['PACT_BROKER_USERNAME'], password: ENV['PACT_BROKER_PASSWORD']}
10
+ end
11
+
12
+ run app
@@ -3,6 +3,7 @@ require 'pact_broker/db'
3
3
  require 'pact_broker/project_root'
4
4
  require 'rack/hal_browser'
5
5
  require 'rack/pact_broker/convert_file_extension_to_accept_header'
6
+ require 'pact_broker/configuration/configure_basic_auth'
6
7
 
7
8
  module PactBroker
8
9
 
@@ -70,12 +71,12 @@ module PactBroker
70
71
  apps << PactBroker::UI::App.new
71
72
  apps << PactBroker::API
72
73
 
74
+ cascade = Rack::Cascade.new(apps)
75
+ app_with_basic_auth = PactBroker::Configuration::ConfigureBasicAuth.call(cascade, configuration)
76
+
73
77
  @app.map "/" do
74
- run Rack::Cascade.new(apps)
78
+ run app_with_basic_auth
75
79
  end
76
-
77
80
  end
78
-
79
81
  end
80
-
81
- end
82
+ end
@@ -4,13 +4,33 @@ module PactBroker
4
4
  @@configuration ||= Configuration.default_configuration
5
5
  end
6
6
 
7
+ def self.reset_configuration
8
+ @@configuration = Configuration.default_configuration
9
+ end
10
+
7
11
  class Configuration
8
12
 
13
+ REQUEST_METHOD = 'REQUEST_METHOD'.freeze
14
+ GET = 'GET'.freeze
15
+ PATH_INFO = 'PATH_INFO'.freeze
16
+ DIAGNOSTIC = '/diagnostic/'.freeze
17
+
9
18
  attr_accessor :log_dir, :database_connection, :auto_migrate_db, :use_hal_browser, :html_pact_renderer
10
19
  attr_accessor :validate_database_connection_config, :enable_diagnostic_endpoints, :version_parser
11
- attr_accessor :use_case_sensitive_resource_names
20
+ attr_accessor :use_case_sensitive_resource_names, :basic_auth_predicates
12
21
  attr_writer :logger
13
22
 
23
+ def initialize
24
+ @basic_auth_config = {}
25
+ @basic_auth_predicates = [
26
+ [:diagnostic, ->(env) { env[PATH_INFO].start_with? DIAGNOSTIC }],
27
+ [:app, ->(env) { !env[PATH_INFO].start_with? DIAGNOSTIC } ],
28
+ [:app_read, ->(env) { env[REQUEST_METHOD] == GET }],
29
+ [:app_write, ->(env) { env[REQUEST_METHOD] != GET }],
30
+ [:all, ->(env) { true }]
31
+ ]
32
+ end
33
+
14
34
  def logger
15
35
  @logger ||= create_logger log_path
16
36
  end
@@ -29,6 +49,7 @@ module PactBroker
29
49
  config
30
50
  end
31
51
 
52
+ # public
32
53
  def self.default_html_pact_render
33
54
  lambda { |pact|
34
55
  require 'pact_broker/api/renderers/html_pact_renderer'
@@ -36,8 +57,28 @@ module PactBroker
36
57
  }
37
58
  end
38
59
 
60
+ # public
61
+ def protect_with_basic_auth scopes, credentials
62
+ [*scopes].each do | scope |
63
+ basic_auth_config[scope] ||= []
64
+ basic_auth_config[scope] << credentials
65
+ end
66
+ end
67
+
68
+ # private
69
+ def protect_with_basic_auth? scope
70
+ !!basic_auth_credentials_list_for(scope)
71
+ end
72
+
73
+ # private
74
+ def basic_auth_credentials_list_for scope
75
+ basic_auth_config[scope]
76
+ end
77
+
39
78
  private
40
79
 
80
+ attr_reader :basic_auth_config
81
+
41
82
  def create_logger path
42
83
  FileUtils::mkdir_p File.dirname(path)
43
84
  logger = Logger.new(path)
@@ -0,0 +1,83 @@
1
+ require 'pact_broker/configuration'
2
+
3
+ module PactBroker
4
+ class Configuration
5
+
6
+ class ConfigurableBasicAuth
7
+
8
+ def initialize(app)
9
+ @app = app
10
+ @predicates = []
11
+ end
12
+
13
+ def protect credentials_list, &predicate
14
+ basic_auth_proxy = ::Rack::Auth::Basic.new(app) do | username, password |
15
+ credentials_list.any? do | credentials |
16
+ username == credentials[:username] && password == credentials[:password]
17
+ end
18
+ end
19
+ predicates << [predicate, basic_auth_proxy]
20
+ end
21
+
22
+ def call(env)
23
+ predicates = matching_predicates(env)
24
+ if predicates.any?
25
+ cascade(predicates, env)
26
+ else
27
+ app.call(env)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ attr_accessor :app, :predicates
34
+
35
+ def matching_predicates env
36
+ predicates.select do | predicate, basic_auth_proxy |
37
+ predicate.call(env)
38
+ end
39
+ end
40
+
41
+ def cascade predicates, env
42
+ response = nil
43
+ predicates.each do | predicate, basic_auth_proxy |
44
+ response = basic_auth_proxy.call(env)
45
+ return response if response.first != 401
46
+ end
47
+ response
48
+ end
49
+
50
+ end
51
+
52
+ class ConfigureBasicAuth
53
+
54
+ def self.call app, configuration
55
+ new(app, configuration).call
56
+ end
57
+
58
+ def initialize app, configuration
59
+ @configuration = configuration
60
+ @basic_auth_proxy = ConfigurableBasicAuth.new(app)
61
+ end
62
+
63
+ def call
64
+ configuration.basic_auth_predicates.each do | scope, predicate |
65
+ configure_basic_auth_for_scope scope, &predicate
66
+ end
67
+
68
+ basic_auth_proxy
69
+ end
70
+
71
+ private
72
+
73
+ attr_accessor :basic_auth_proxy, :configuration
74
+
75
+ def configure_basic_auth_for_scope scope, &predicate
76
+ if configuration.protect_with_basic_auth?(scope)
77
+ credentials = configuration.basic_auth_credentials_list_for(scope)
78
+ basic_auth_proxy.protect(credentials, &predicate)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = '1.17.2'
2
+ VERSION = '1.18.0.beta.1'
3
3
  end
@@ -0,0 +1,267 @@
1
+ require 'pact_broker/configuration/configure_basic_auth'
2
+ require 'pact_broker/app'
3
+
4
+ module PactBroker
5
+ class Configuration
6
+ describe ConfigurableBasicAuth do
7
+
8
+ let(:target_app) { ->(env){ [200, {}, ["hello"]] } }
9
+ let(:app) do
10
+ auth_app = ConfigurableBasicAuth.new(target_app)
11
+ auth_app.protect([{username: 'username', password: 'password'}]) do | env |
12
+ env['PATH_INFO'] == '/foo'
13
+ end
14
+ auth_app
15
+ end
16
+
17
+ context "when not authorized" do
18
+ it "does not allow requests" do
19
+ get "/foo"
20
+ expect(last_response.status).to eq 401
21
+ end
22
+ end
23
+
24
+ context "when authorized" do
25
+
26
+ before { basic_authorize 'username', 'password' }
27
+
28
+ it "allows requests" do
29
+ get "/foo"
30
+ expect(last_response.status).to eq 200
31
+ end
32
+ end
33
+ end
34
+
35
+ describe ConfigureBasicAuth do
36
+ def read_request_to_ui
37
+ get "/"
38
+ last_response
39
+ end
40
+
41
+ def read_request_to_api
42
+ get "/pacts/latest"
43
+ last_response
44
+ end
45
+
46
+ def write_request_to_api
47
+ put "/pacts/provider/foo/consumer/bar/version/1.2.3", '{}', {'Content-Type' => 'application/json'}
48
+ last_response
49
+ end
50
+
51
+ def read_request_to_diagnostic
52
+ get "/diagnostic/status/heartbeat"
53
+ last_response
54
+ end
55
+
56
+ def authorize_request
57
+ basic_authorize 'username', 'password'
58
+ end
59
+
60
+
61
+ before do
62
+ PactBroker.reset_configuration
63
+ end
64
+
65
+ describe "with no basic_auth" do
66
+ let(:app) do
67
+ app = PactBroker::App.new do | config |
68
+ config.database_connection = PactBroker::DB.connection
69
+ end
70
+ end
71
+
72
+ context "when not authorized" do
73
+ it "allows GET requests to the UI" do
74
+ expect(read_request_to_ui.status).to_not eq 401
75
+ end
76
+
77
+ it "allows GET requests to the API" do
78
+ expect(read_request_to_api.status).to_not eq 401
79
+ end
80
+
81
+ it "allows non GET requests to the API" do
82
+ expect(write_request_to_api.status).to_not eq 401
83
+ end
84
+
85
+ it "allows GET requests to the diagnostics app" do
86
+ expect(read_request_to_diagnostic.status).to_not eq 401
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "with basic_auth for :all" do
92
+ let(:app) do
93
+ app = PactBroker::App.new do | config |
94
+ config.database_connection = PactBroker::DB.connection
95
+ config.protect_with_basic_auth :all, {username: 'username', password: 'password'}
96
+ end
97
+ end
98
+
99
+ context "when authorized" do
100
+ before do
101
+ authorize_request
102
+ end
103
+
104
+ it "allows GET requests to the UI" do
105
+ expect(read_request_to_ui.status).to_not eq 401
106
+ end
107
+
108
+ it "allows GET requests to the API" do
109
+ expect(read_request_to_api.status).to_not eq 401
110
+ end
111
+
112
+ it "allows non GET requests to the API" do
113
+ expect(write_request_to_api.status).to_not eq 401
114
+ end
115
+
116
+ it "allows GET requests to the diagnostics app" do
117
+ expect(read_request_to_diagnostic.status).to_not eq 401
118
+ end
119
+ end
120
+
121
+ context "when not authorized" do
122
+ it "does not allow GET requests to the UI" do
123
+ expect(read_request_to_ui.status).to eq 401
124
+ end
125
+
126
+ it "does not allow GET requests the API" do
127
+ expect(read_request_to_api.status).to eq 401
128
+ end
129
+
130
+ it "does not allow non GET requests the API" do
131
+ expect(write_request_to_api.status).to eq 401
132
+ end
133
+
134
+ it "does not allow GET requests to the diagnostics app" do
135
+ expect(read_request_to_diagnostic.status).to eq 401
136
+ end
137
+ end
138
+ end
139
+
140
+ describe "with basic_auth for :app_write" do
141
+
142
+ let(:app) do
143
+ app = PactBroker::App.new do | config |
144
+ config.database_connection = PactBroker::DB.connection
145
+ config.protect_with_basic_auth :app_write, {username: 'username', password: 'password'}
146
+ end
147
+ end
148
+
149
+ context "when authorized" do
150
+ before do
151
+ authorize_request
152
+ end
153
+
154
+ it "allows GET requests to the diagnostics app" do
155
+ expect(read_request_to_diagnostic.status).to_not eq 401
156
+ end
157
+
158
+ it "allows GET requests to the app_write app" do
159
+ expect(read_request_to_diagnostic.status).to_not eq 401
160
+ end
161
+ end
162
+
163
+ context "when not authorized" do
164
+
165
+ it "allows GET requests to the UI" do
166
+ expect(read_request_to_ui.status).to_not eq 401
167
+ end
168
+
169
+ it "allows GET requests the API" do
170
+ expect(read_request_to_api.status).to_not eq 401
171
+ end
172
+
173
+ it "does not allow non GET requests the API" do
174
+ expect(write_request_to_api.status).to eq 401
175
+ end
176
+
177
+ it "allows GET requests to the diagnostics app" do
178
+ expect(read_request_to_diagnostic.status).to_not eq 401
179
+ end
180
+ end
181
+ end
182
+
183
+ describe "with multiple users for for :app_write" do
184
+ let(:app) do
185
+ app = PactBroker::App.new do | config |
186
+ config.database_connection = PactBroker::DB.connection
187
+ config.protect_with_basic_auth :app_write, {username: 'read_username', password: 'password'}
188
+ config.protect_with_basic_auth :app_write, {username: 'another_read_username', password: 'password'}
189
+ end
190
+ end
191
+
192
+ context "when the first credentials are used" do
193
+ before { basic_authorize 'read_username', 'password' }
194
+
195
+ it "allows a request" do
196
+ write_request_to_api
197
+ expect(last_response.status).to_not eq 401
198
+ end
199
+ end
200
+
201
+ context "when the second credentials are used" do
202
+ before { basic_authorize 'another_read_username', 'password' }
203
+
204
+ it "allows a request" do
205
+ write_request_to_api
206
+ expect(last_response.status).to_not eq 401
207
+ end
208
+ end
209
+
210
+ context "when the wrong credentials are used" do
211
+ before { basic_authorize 'wrong_username', 'password' }
212
+
213
+ it "does not allow the request" do
214
+ write_request_to_api
215
+ expect(last_response.status).to eq 401
216
+ end
217
+ end
218
+
219
+ context "when no credentials are used" do
220
+ it "does not allow the request" do
221
+ write_request_to_api
222
+ expect(last_response.status).to eq 401
223
+ end
224
+ end
225
+
226
+ end
227
+
228
+ describe "with an app_read user and an app user" do
229
+ let(:app) do
230
+ app = PactBroker::App.new do | config |
231
+ config.database_connection = PactBroker::DB.connection
232
+ config.protect_with_basic_auth :app_read, {username: 'read_username', password: 'password'}
233
+ config.protect_with_basic_auth :app, {username: 'read_and_write_username', password: 'password'}
234
+ end
235
+ end
236
+
237
+ context "when the app credentials are used" do
238
+ before { basic_authorize 'read_and_write_username', 'password' }
239
+
240
+ it "allows a read request" do
241
+ read_request_to_api
242
+ expect(last_response.status).to_not eq 401
243
+ end
244
+
245
+ it "allows a write request" do
246
+ write_request_to_api
247
+ expect(last_response.status).to_not eq 401
248
+ end
249
+ end
250
+
251
+ context "when the read_username credentials are used" do
252
+ before { basic_authorize 'read_username', 'password' }
253
+
254
+ it "allows a read request" do
255
+ read_request_to_api
256
+ expect(last_response.status).to_not eq 401
257
+ end
258
+
259
+ it "does not allow a write request" do
260
+ write_request_to_api
261
+ expect(last_response.status).to eq 401
262
+ end
263
+ end
264
+ end
265
+ end
266
+ end
267
+ end
@@ -7,15 +7,35 @@ module PactBroker
7
7
 
8
8
  context "default configuration" do
9
9
  describe ".html_pact_renderer" do
10
-
11
10
  let(:pact) { double('pact') }
12
11
 
13
12
  it "calls the inbuilt HtmlPactRenderer" do
14
13
  expect(PactBroker::Api::Renderers::HtmlPactRenderer).to receive(:call).with(pact)
15
14
  PactBroker.configuration.html_pact_renderer.call pact
16
15
  end
16
+ end
17
+
18
+ describe "protect_with_basic_auth" do
19
+ let(:config) do
20
+ config = Configuration.new
21
+ config.protect_with_basic_auth [:foo, :bar], {some: 'credentials'}
22
+ config.protect_with_basic_auth :foo, {some: 'othercredentials'}
23
+ config
24
+ end
17
25
 
26
+ it "groups credentials by scope" do
27
+ expect(config.basic_auth_credentials_list_for(:foo)).to eq([{some: 'credentials'},{some: 'othercredentials'}])
28
+ expect(config.basic_auth_credentials_list_for(:bar)).to eq([{some: 'credentials'}])
29
+ end
30
+
31
+ describe "protect_with_basic_auth?" do
32
+ it "indicates whether a scope is protected" do
33
+ expect(config.protect_with_basic_auth?(:foo)).to be true
34
+ expect(config.protect_with_basic_auth?(:bar)).to be true
35
+ expect(config.protect_with_basic_auth?(:wiffle)).to be false
36
+ end
37
+ end
18
38
  end
19
39
  end
20
40
  end
21
- end
41
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact_broker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.2
4
+ version: 1.18.0.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bethany Skurrie
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-05-04 00:00:00.000000000 Z
13
+ date: 2017-05-05 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: httparty
@@ -395,11 +395,11 @@ files:
395
395
  - db/migrations/migration_helper.rb
396
396
  - db/pact_broker_database.sqlite3
397
397
  - example/Gemfile
398
- - example/basic_auth/Gemfile
399
- - example/basic_auth/Procfile
400
- - example/basic_auth/README.md
401
- - example/basic_auth/config.ru
402
398
  - example/config.ru
399
+ - example/heroku/Gemfile
400
+ - example/heroku/Procfile
401
+ - example/heroku/README.md
402
+ - example/heroku/config.ru
403
403
  - example/pact_broker_database.sqlite3
404
404
  - lib/db.rb
405
405
  - lib/pact_broker.rb
@@ -462,6 +462,7 @@ files:
462
462
  - lib/pact_broker/api/resources/webhooks.rb
463
463
  - lib/pact_broker/app.rb
464
464
  - lib/pact_broker/configuration.rb
465
+ - lib/pact_broker/configuration/configure_basic_auth.rb
465
466
  - lib/pact_broker/constants.rb
466
467
  - lib/pact_broker/date_helper.rb
467
468
  - lib/pact_broker/db.rb
@@ -633,6 +634,7 @@ files:
633
634
  - spec/lib/pact_broker/api/resources/webhook_execution_spec.rb
634
635
  - spec/lib/pact_broker/api/resources/webhook_spec.rb
635
636
  - spec/lib/pact_broker/api/resources/webhooks_spec.rb
637
+ - spec/lib/pact_broker/configuration/configure_basic_auth_spec.rb
636
638
  - spec/lib/pact_broker/configuration_spec.rb
637
639
  - spec/lib/pact_broker/db/validate_encoding_spec.rb
638
640
  - spec/lib/pact_broker/diagnostic/resources/dependencies_spec.rb
@@ -730,9 +732,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
730
732
  version: 2.2.0
731
733
  required_rubygems_version: !ruby/object:Gem::Requirement
732
734
  requirements:
733
- - - ">="
735
+ - - ">"
734
736
  - !ruby/object:Gem::Version
735
- version: '0'
737
+ version: 1.3.1
736
738
  requirements: []
737
739
  rubyforge_project:
738
740
  rubygems_version: 2.6.11
@@ -795,6 +797,7 @@ test_files:
795
797
  - spec/lib/pact_broker/api/resources/webhook_execution_spec.rb
796
798
  - spec/lib/pact_broker/api/resources/webhook_spec.rb
797
799
  - spec/lib/pact_broker/api/resources/webhooks_spec.rb
800
+ - spec/lib/pact_broker/configuration/configure_basic_auth_spec.rb
798
801
  - spec/lib/pact_broker/configuration_spec.rb
799
802
  - spec/lib/pact_broker/db/validate_encoding_spec.rb
800
803
  - spec/lib/pact_broker/diagnostic/resources/dependencies_spec.rb
@@ -1,19 +0,0 @@
1
- require 'fileutils'
2
- require 'logger'
3
- require 'sequel'
4
- require 'pact_broker'
5
- require 'pg'
6
-
7
- use Rack::Auth::Basic, "Restricted Area" do |username, password|
8
- username == ENV['PACT_BROKER_USERNAME'] and password == ENV['PACT_BROKER_PASSWORD']
9
- end
10
-
11
- app = PactBroker::App.new do | config |
12
- # change these from their default values if desired
13
- # config.log_dir = "./log"
14
- # config.auto_migrate_db = true
15
- # config.use_hal_browser = true
16
- config.database_connection = Sequel.connect(ENV['DATABASE_URL'], adapter: "postgres", encoding: 'utf8')
17
- end
18
-
19
- run app