acme_plugin 0.0.13

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.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +33 -0
  4. data/app/controllers/acme_plugin/application_controller.rb +34 -0
  5. data/app/models/acme_plugin/challenge.rb +17 -0
  6. data/app/models/acme_plugin/setting.rb +10 -0
  7. data/config/routes.rb +3 -0
  8. data/db/migrate/20151206135029_create_acme_plugin_challenges.rb +9 -0
  9. data/db/migrate/20160412195212_create_acme_plugin_settings.rb +9 -0
  10. data/lib/acme_plugin.rb +146 -0
  11. data/lib/acme_plugin/certificate_output.rb +17 -0
  12. data/lib/acme_plugin/challenge_store.rb +18 -0
  13. data/lib/acme_plugin/configuration.rb +27 -0
  14. data/lib/acme_plugin/database_store.rb +11 -0
  15. data/lib/acme_plugin/engine.rb +5 -0
  16. data/lib/acme_plugin/file_output.rb +18 -0
  17. data/lib/acme_plugin/file_store.rb +16 -0
  18. data/lib/acme_plugin/heroku_output.rb +19 -0
  19. data/lib/acme_plugin/private_key_store.rb +24 -0
  20. data/lib/acme_plugin/version.rb +5 -0
  21. data/lib/tasks/acme_plugin_tasks.rake +15 -0
  22. data/test/acme_plugin_test.rb +351 -0
  23. data/test/controllers/application_controller_test.rb +26 -0
  24. data/test/dummy/README.rdoc +28 -0
  25. data/test/dummy/Rakefile +6 -0
  26. data/test/dummy/app/assets/javascripts/application.js +13 -0
  27. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  28. data/test/dummy/app/controllers/application_controller.rb +5 -0
  29. data/test/dummy/app/helpers/application_helper.rb +2 -0
  30. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  31. data/test/dummy/bin/bundle +3 -0
  32. data/test/dummy/bin/rails +4 -0
  33. data/test/dummy/bin/rake +4 -0
  34. data/test/dummy/bin/setup +29 -0
  35. data/test/dummy/config.ru +4 -0
  36. data/test/dummy/config/acme_plugin.yml +19 -0
  37. data/test/dummy/config/application.rb +23 -0
  38. data/test/dummy/config/boot.rb +5 -0
  39. data/test/dummy/config/database.yml +25 -0
  40. data/test/dummy/config/environment.rb +5 -0
  41. data/test/dummy/config/environments/development.rb +41 -0
  42. data/test/dummy/config/environments/production.rb +79 -0
  43. data/test/dummy/config/environments/test.rb +45 -0
  44. data/test/dummy/config/initializers/assets.rb +11 -0
  45. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  46. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  47. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  48. data/test/dummy/config/initializers/inflections.rb +16 -0
  49. data/test/dummy/config/initializers/mime_types.rb +4 -0
  50. data/test/dummy/config/initializers/session_store.rb +3 -0
  51. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  52. data/test/dummy/config/locales/en.yml +23 -0
  53. data/test/dummy/config/routes.rb +3 -0
  54. data/test/dummy/config/secrets.yml +22 -0
  55. data/test/dummy/db/schema.rb +27 -0
  56. data/test/dummy/db/test.sqlite3 +0 -0
  57. data/test/dummy/key/test_keyfile_1024.pem +15 -0
  58. data/test/dummy/key/test_keyfile_2048.pem +27 -0
  59. data/test/dummy/key/test_keyfile_4096.pem +51 -0
  60. data/test/dummy/key/test_keyfile_8192.pem +99 -0
  61. data/test/dummy/log/development.log +0 -0
  62. data/test/dummy/log/test.log +25582 -0
  63. data/test/dummy/public/404.html +67 -0
  64. data/test/dummy/public/422.html +67 -0
  65. data/test/dummy/public/500.html +66 -0
  66. data/test/dummy/public/favicon.ico +0 -0
  67. data/test/fixtures/acme_plugin/challenges.yml +7 -0
  68. data/test/fixtures/acme_plugin/settings.yml +56 -0
  69. data/test/lib/acme_plugin/configuration_test.rb +13 -0
  70. data/test/lib/acme_plugin/private_key_store_test.rb +30 -0
  71. data/test/models/acme_plugin/challenge_test.rb +6 -0
  72. data/test/test_helper.rb +23 -0
  73. metadata +309 -0
@@ -0,0 +1,24 @@
1
+ require 'openssl'
2
+
3
+ class PrivateKeyStore
4
+ def initialize(private_key)
5
+ # this should eventually be any one of many backends?
6
+ # these could then encapsulate the method of retrieving the
7
+ # RSA key string. see: http://hawkins.io/2013/10/implementing_the_repository_pattern/
8
+ @private_key = private_key
9
+ end
10
+
11
+ def retrieve
12
+ pk = OpenSSL::PKey::RSA.new(@private_key)
13
+ raise "Invalid key size: #{pk.n.num_bits}. Required size is between 2048 - 4096 bits" unless valid_key_size?(pk)
14
+ pk
15
+ rescue OpenSSL::PKey::RSAError
16
+ raise "#{pk} is not a valid private key identifier"
17
+ end
18
+
19
+ private
20
+
21
+ def valid_key_size?(key)
22
+ key.n.num_bits >= 2048 && key.n.num_bits <= 4096
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AcmePlugin
4
+ VERSION = '0.0.13'.freeze
5
+ end
@@ -0,0 +1,15 @@
1
+ require 'openssl'
2
+ require 'acme/client'
3
+
4
+ # Sets up logging - should only be called from other rake tasks
5
+ task setup_logger: :environment do
6
+ logger = Logger.new(STDOUT)
7
+ logger.level = Logger::INFO
8
+ Rails.logger = logger
9
+ end
10
+
11
+ desc "Generates SSL certificate using Let's Encrypt service"
12
+ task acme_plugin: :setup_logger do
13
+ cert_generator = AcmePlugin::CertGenerator.new(AcmePlugin.config.to_h)
14
+ cert_generator.generate_certificate
15
+ end
@@ -0,0 +1,351 @@
1
+ require 'test_helper'
2
+
3
+ class AcmePluginTest < ActiveSupport::TestCase
4
+ ACME_VERSION = 'v0.6.2'.freeze
5
+ ACME_USER_AGENT = "Acme::Client #{ACME_VERSION} (https://github.com/unixcharles/acme-client)".freeze
6
+ ENDPOINT_URL = 'https://acme-staging.api.letsencrypt.org'.freeze
7
+ API_URL = "#{ENDPOINT_URL}/acme".freeze
8
+ PRIVATE_KEY = %(
9
+ -----BEGIN RSA PRIVATE KEY-----
10
+ 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
59
+ -----END RSA PRIVATE KEY-----).freeze
60
+
61
+ def setup
62
+ WebMock.disable_net_connect!(allow_localhost: true)
63
+ end
64
+
65
+ def teardown
66
+ WebMock.allow_net_connect!
67
+ end
68
+
69
+ test 'is_valid_module' do
70
+ assert_kind_of Module, AcmePlugin
71
+ end
72
+
73
+ test 'if_fail_when_private_key_is_nil' do
74
+ exception = assert_raises RuntimeError do
75
+ cg = AcmePlugin::CertGenerator.new(private_key: nil)
76
+ cg.client
77
+ end
78
+ assert_equal 'Private key is not set, please check your config/acme_plugin.yml file!', exception.message
79
+ end
80
+
81
+ test 'if_fail_when_private_key_is_empty' do
82
+ exception = assert_raises RuntimeError do
83
+ cg = AcmePlugin::CertGenerator.new(private_key: '')
84
+ cg.client
85
+ end
86
+ assert_equal 'Private key is not set, please check your config/acme_plugin.yml file!', exception.message
87
+ end
88
+
89
+ test 'if_fail_when_private_key_is_directory' do
90
+ options = { private_key: 'public' }
91
+ exception = assert_raises RuntimeError do
92
+ cg = AcmePlugin::CertGenerator.new(options)
93
+ cg.client
94
+ end
95
+ assert_equal "Can not open private key: #{File.join(Rails.root, options[:private_key])}", exception.message
96
+ end
97
+
98
+ test 'if_keysize_smaller_than_2048_is_invalid' do
99
+ exception = assert_raises RuntimeError do
100
+ cg = AcmePlugin::CertGenerator.new(private_key: 'key/test_keyfile_1024.pem')
101
+ cg.client
102
+ end
103
+ assert_equal 'Invalid key size: 1024. Required size is between 2048 - 4096 bits', exception.message
104
+ end
105
+
106
+ test 'if_keysize_greater_than_4096_is_invalid' do
107
+ exception = assert_raises RuntimeError do
108
+ cg = AcmePlugin::CertGenerator.new(private_key: 'key/test_keyfile_8192.pem')
109
+ cg.client
110
+ end
111
+ assert_equal 'Invalid key size: 8192. Required size is between 2048 - 4096 bits', exception.message
112
+ end
113
+
114
+ test 'if_keysize_equal_4096_is_valid' do
115
+ assert_nothing_raised do
116
+ cg = AcmePlugin::CertGenerator.new(private_key: 'key/test_keyfile_4096.pem')
117
+ assert !cg.nil?
118
+ cg.client
119
+ end
120
+ end
121
+
122
+ test 'if_keysize_equal_2048_is_valid' do
123
+ assert_nothing_raised do
124
+ cg = AcmePlugin::CertGenerator.new(private_key: 'key/test_keyfile_2048.pem')
125
+ assert !cg.nil?
126
+ cg.client
127
+ end
128
+ end
129
+
130
+ test 'register with text based private key' do
131
+ cg = AcmePlugin::CertGenerator.new(private_key: PRIVATE_KEY,
132
+ endpoint: ENDPOINT_URL,
133
+ domain: 'example.com',
134
+ email: 'foobarbaz@example.com')
135
+ assert !cg.nil?
136
+
137
+ stub_request(:head, "#{API_URL}/new-reg")
138
+ .with(headers: { 'Accept' => '*/*' })
139
+ .to_return(status: 200, body: '', headers: {})
140
+
141
+ stub_request(:post, "#{API_URL}/new-reg")
142
+ .with(body: '{"protected":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eS'\
143
+ 'I6IlJTQSIsIm4iOiJxN0gtQ2txRHZ3ekx2OWRBZ05rSmQzM2FiVEpFa0ZHSjhXbGIxRnZ1Y1F6MEFYWX'\
144
+ 'JwWUx5ajdOYUNyQm90V1NaR2pFSnRQZ1k1M0xWWU1ET1BiOTktLTZEazNXVGhkT203U01JTlZYWlZ1Ym'\
145
+ 'hhNmtoY1pFWFA1NEdic0NzcFBmNm5OcUJCeEhDblV3V01GOElRcWkwTVdSNHFOeG1LZEVrcE56dGFCd0'\
146
+ 'xLU0ZWUHNRMHRGeXJHellhOEw0TkJqZWUyaWlEdWM2bHlMTkp6MnhfUUZMQWZneGw1cXdFa05FVGxNNz'\
147
+ 'JNQlRsTTNrR1k4UjN2RkVNVEhQSUtCM3VQcHdScE1qOEw2M1JLenpmcmM5Q0Y2TDRNaG01b05GUENndm'\
148
+ 'JDRWF6T0ctTEpwM2Q4bVlTZjBERE5RNlhoX0NnTG5TbXAzVWVmckpiQVFUZDBpSk4xa21TaV9fQmxOR1'\
149
+ 'JDS1dFZDgyZzA2aHgwbVRhOXVZZEQxMFNXaVF5UHZIbDRzWER3M0JMN0VpOVlPNHpoOUh6ZkpzUVhxY2'\
150
+ 'hzQnZVZ2dEVG9IZVJwMnhmS0hEcmFFZ2JPX0FxaEMxRkdkTUtPUnJMWnBMQm1oamw0MFVvMWNLUXZsbl'\
151
+ 'ZJZFJaQjU4QnoyZUhzNDVKN0ROYktsQm12cWZPQnJFN09nOHdEbFUzWFpIZ3dRZkt4TUhBV29Qc0d2RG'\
152
+ '1KRjRZdFRmZ0R4NmZWS2VNbng5cXpJQ0plRlZmYnkzaUc4dE9XUFNKWFZUcXZ2QlhiQnppT0h4bV9sOH'\
153
+ 'pma3UwUmk3RXYwWUU2VEJGWDZiNDRES0FpVW9adkUwTm9taXhhYll2ZDAwWFFPNndOMF9pdkN6Tmc0VV'\
154
+ 'ltaDlZUzJyM1E3YmloNFkyS3MyWllxdnNkazFnLWZiNGZRcyJ9LCJub25jZSI6bnVsbH0",'\
155
+ '"payload":"eyJyZXNvdXJjZSI6Im5ldy1yZWciLCJjb250YWN0IjpbIm1haWx0bzpmb29iYXJiYXpAZ'\
156
+ 'XhhbXBsZS5jb20iXX0",'\
157
+ '"signature":"aQ6T0XVo9jS_jXlvQ6bjAfqcrMYpQTPE9_CD7v1hDBUzKpSoygAJmrbb0kSumMkWf-r'\
158
+ 'acxG5i7tcD4ed32ap1OsWUoPGWhXkQifAqToYMdfBzjwaS_OfjPpFflPOZmUvOygtGt3LTsdhA27PCSC'\
159
+ 'saZDlozz2143b00QhZ-gVkFRJEwOMN22ByOsL-1_R_UEp7mqwQKzeZ_nsW7japvGWcru13bzqiD2b069'\
160
+ 'kwrfksnMIMSjFWnJPnxCLpY-DQn8kCBeJfljW-mOJyZFck1ko0KBiOEbY_k0IJ0aspwg9lGRLkVX-wWV'\
161
+ '8Q_e8gwoLjmaXouUxAl2E3wNInXRJkgDOMfEUSOHzxI6WFYLzhVKVl7ktP7zx21my2vL_J_nROTDaVIU'\
162
+ 'qJgdUgEZ40KR_Kjd_pRKPcB8kHyKtDnCopmrPXLu0QCuHYAn_M-cYgkFOyvplJNodaZfKamLuwChywPl'\
163
+ 'DC5tr1BQvdlUVp-cwr_C_KU-Kpkws924xI0ah8ksuwsHpkp2458aVEIeDEEw7FgHZXUPKXaJcBIHjQ1R'\
164
+ 'vnm062Ub_4LR25TrKTgftDCftK2YtN4LA-jtlfOrdM47xZatAzhmFy_vFIIu_-phh5he0nn8Mx2byjsZ'\
165
+ '1M-DeW0Wl9_zxhhOo1gtmFhtguCKw3W0mdcdDZmhRleNS-HtYA0w41LA"}',
166
+ headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
167
+ 'User-Agent' => ACME_USER_AGENT })
168
+ .to_return(status: 200, body: '', headers: {})
169
+
170
+ assert_nothing_raised do
171
+ cg.register
172
+ end
173
+ end
174
+
175
+ test 'register' do
176
+ cg = AcmePlugin::CertGenerator.new(private_key: 'key/test_keyfile_4096.pem',
177
+ endpoint: ENDPOINT_URL,
178
+ domain: 'example.com',
179
+ email: 'foobarbaz@example.com')
180
+ assert !cg.nil?
181
+
182
+ stub_request(:head, "#{API_URL}/new-reg")
183
+ .with(headers: { 'Accept' => '*/*' })
184
+ .to_return(status: 200, body: '', headers: {})
185
+
186
+ stub_request(:post, "#{API_URL}/new-reg")
187
+ .with(body: '{"protected":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eS'\
188
+ 'I6IlJTQSIsIm4iOiJxN0gtQ2txRHZ3ekx2OWRBZ05rSmQzM2FiVEpFa0ZHSjhXbGIxRnZ1Y1F6MEFYWX'\
189
+ 'JwWUx5ajdOYUNyQm90V1NaR2pFSnRQZ1k1M0xWWU1ET1BiOTktLTZEazNXVGhkT203U01JTlZYWlZ1Ym'\
190
+ 'hhNmtoY1pFWFA1NEdic0NzcFBmNm5OcUJCeEhDblV3V01GOElRcWkwTVdSNHFOeG1LZEVrcE56dGFCd0'\
191
+ 'xLU0ZWUHNRMHRGeXJHellhOEw0TkJqZWUyaWlEdWM2bHlMTkp6MnhfUUZMQWZneGw1cXdFa05FVGxNNz'\
192
+ 'JNQlRsTTNrR1k4UjN2RkVNVEhQSUtCM3VQcHdScE1qOEw2M1JLenpmcmM5Q0Y2TDRNaG01b05GUENndm'\
193
+ 'JDRWF6T0ctTEpwM2Q4bVlTZjBERE5RNlhoX0NnTG5TbXAzVWVmckpiQVFUZDBpSk4xa21TaV9fQmxOR1'\
194
+ 'JDS1dFZDgyZzA2aHgwbVRhOXVZZEQxMFNXaVF5UHZIbDRzWER3M0JMN0VpOVlPNHpoOUh6ZkpzUVhxY2'\
195
+ 'hzQnZVZ2dEVG9IZVJwMnhmS0hEcmFFZ2JPX0FxaEMxRkdkTUtPUnJMWnBMQm1oamw0MFVvMWNLUXZsbl'\
196
+ 'ZJZFJaQjU4QnoyZUhzNDVKN0ROYktsQm12cWZPQnJFN09nOHdEbFUzWFpIZ3dRZkt4TUhBV29Qc0d2RG'\
197
+ '1KRjRZdFRmZ0R4NmZWS2VNbng5cXpJQ0plRlZmYnkzaUc4dE9XUFNKWFZUcXZ2QlhiQnppT0h4bV9sOH'\
198
+ 'pma3UwUmk3RXYwWUU2VEJGWDZiNDRES0FpVW9adkUwTm9taXhhYll2ZDAwWFFPNndOMF9pdkN6Tmc0VV'\
199
+ 'ltaDlZUzJyM1E3YmloNFkyS3MyWllxdnNkazFnLWZiNGZRcyJ9LCJub25jZSI6bnVsbH0",'\
200
+ '"payload":"eyJyZXNvdXJjZSI6Im5ldy1yZWciLCJjb250YWN0IjpbIm1haWx0bzpmb29iYXJiYXpAZ'\
201
+ 'XhhbXBsZS5jb20iXX0",'\
202
+ '"signature":"aQ6T0XVo9jS_jXlvQ6bjAfqcrMYpQTPE9_CD7v1hDBUzKpSoygAJmrbb0kSumMkWf-r'\
203
+ 'acxG5i7tcD4ed32ap1OsWUoPGWhXkQifAqToYMdfBzjwaS_OfjPpFflPOZmUvOygtGt3LTsdhA27PCSC'\
204
+ 'saZDlozz2143b00QhZ-gVkFRJEwOMN22ByOsL-1_R_UEp7mqwQKzeZ_nsW7japvGWcru13bzqiD2b069'\
205
+ 'kwrfksnMIMSjFWnJPnxCLpY-DQn8kCBeJfljW-mOJyZFck1ko0KBiOEbY_k0IJ0aspwg9lGRLkVX-wWV'\
206
+ '8Q_e8gwoLjmaXouUxAl2E3wNInXRJkgDOMfEUSOHzxI6WFYLzhVKVl7ktP7zx21my2vL_J_nROTDaVIU'\
207
+ 'qJgdUgEZ40KR_Kjd_pRKPcB8kHyKtDnCopmrPXLu0QCuHYAn_M-cYgkFOyvplJNodaZfKamLuwChywPl'\
208
+ 'DC5tr1BQvdlUVp-cwr_C_KU-Kpkws924xI0ah8ksuwsHpkp2458aVEIeDEEw7FgHZXUPKXaJcBIHjQ1R'\
209
+ 'vnm062Ub_4LR25TrKTgftDCftK2YtN4LA-jtlfOrdM47xZatAzhmFy_vFIIu_-phh5he0nn8Mx2byjsZ'\
210
+ '1M-DeW0Wl9_zxhhOo1gtmFhtguCKw3W0mdcdDZmhRleNS-HtYA0w41LA"}',
211
+ headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
212
+ 'User-Agent' => ACME_USER_AGENT })
213
+ .to_return(status: 200, body: '', headers: {})
214
+
215
+ assert_nothing_raised do
216
+ cg.register
217
+ end
218
+ end
219
+
220
+ test 'register_with_privkey_in_db' do
221
+ cg = AcmePlugin::CertGenerator.new(private_key_in_db: true,
222
+ endpoint: ENDPOINT_URL,
223
+ domain: 'example.com',
224
+ email: 'foobarbaz@example.com')
225
+ assert !cg.nil?
226
+
227
+ stub_request(:head, "#{API_URL}/new-reg")
228
+ .with(headers: { 'Accept' => '*/*' })
229
+ .to_return(status: 200, body: '', headers: {})
230
+
231
+ stub_request(:post, "#{API_URL}/new-reg")
232
+ .with(body: '{"protected":"eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIiwibm9uY2UiOm51bGwsImp3ayI6eyJrdH'\
233
+ 'kiOiJSU0EiLCJlIjoiQVFBQiIsIm4iOiJxN0gtQ2txRHZ3ekx2OWRBZ05rSmQzM2FiVEpFa0ZHSjhXbG'\
234
+ 'IxRnZ1Y1F6MEFYWXJwWUx5ajdOYUNyQm90V1NaR2pFSnRQZ1k1M0xWWU1ET1BiOTktLTZEazNXVGhkT2'\
235
+ '03U01JTlZYWlZ1YmhhNmtoY1pFWFA1NEdic0NzcFBmNm5OcUJCeEhDblV3V01GOElRcWkwTVdSNHFOeG'\
236
+ '1LZEVrcE56dGFCd0xLU0ZWUHNRMHRGeXJHellhOEw0TkJqZWUyaWlEdWM2bHlMTkp6MnhfUUZMQWZneG'\
237
+ 'w1cXdFa05FVGxNNzJNQlRsTTNrR1k4UjN2RkVNVEhQSUtCM3VQcHdScE1qOEw2M1JLenpmcmM5Q0Y2TD'\
238
+ 'RNaG01b05GUENndmJDRWF6T0ctTEpwM2Q4bVlTZjBERE5RNlhoX0NnTG5TbXAzVWVmckpiQVFUZDBpSk'\
239
+ '4xa21TaV9fQmxOR1JDS1dFZDgyZzA2aHgwbVRhOXVZZEQxMFNXaVF5UHZIbDRzWER3M0JMN0VpOVlPNH'\
240
+ 'poOUh6ZkpzUVhxY2hzQnZVZ2dEVG9IZVJwMnhmS0hEcmFFZ2JPX0FxaEMxRkdkTUtPUnJMWnBMQm1oam'\
241
+ 'w0MFVvMWNLUXZsblZJZFJaQjU4QnoyZUhzNDVKN0ROYktsQm12cWZPQnJFN09nOHdEbFUzWFpIZ3dRZk'\
242
+ 't4TUhBV29Qc0d2RG1KRjRZdFRmZ0R4NmZWS2VNbng5cXpJQ0plRlZmYnkzaUc4dE9XUFNKWFZUcXZ2Ql'\
243
+ 'hiQnppT0h4bV9sOHpma3UwUmk3RXYwWUU2VEJGWDZiNDRES0FpVW9adkUwTm9taXhhYll2ZDAwWFFPNn'\
244
+ 'dOMF9pdkN6Tmc0VVltaDlZUzJyM1E3YmloNFkyS3MyWllxdnNkazFnLWZiNGZRcyIsImtpZCI6IlFwSG'\
245
+ 'dDOWxCZ0ZEX1A0dV9aejBNd2x0V1dUN1g2QlRZZnVPNUlob1VrUDAifX0",'\
246
+ '"payload":"eyJyZXNvdXJjZSI6Im5ldy1yZWciLCJjb250YWN0IjpbIm1haWx0bzpmb29iYXJiYXpAZ'\
247
+ 'XhhbXBsZS5jb20iXX0",'\
248
+ '"signature":"T4aKq85rcACJdyEEx_Dw90lLypyPba6GSyG1YlFjCMwM7qdRlCsb3YIJE_Eia-A9IVl'\
249
+ 'cXKc2rzvVOPvGB2bYmPCxep5o7uy1mkC7hKJhSEw97mT_sidrLamEKIrYtnVrW0KSO3EKEY-rUSMIeOA'\
250
+ 'qLuZosSXLCEDlQTLqPUJPrhm8pDBRLzEqUO1HIMLfOEH5bWwXHofxL_QqUQjzMqIh_VWqy08MxuWEThD'\
251
+ 'UyKPewBx1E_Y0H-vsM_D39SJA04s9fnIGyOlXISL1LZ9pFZ_W5rF25_P9vwks9m7E8iZFo-rFc073DsM'\
252
+ 'zc_-5VbUgAoAqDZA69q8FTkgUkA6pu-vZsxeIb6OUNS6wxt6U4dqYS1aBXnhLeKvbIb7NqFmY8erzvcG'\
253
+ 'XBvab1F0ndg6sw5PmrDZyOzcCKdA9eQk6LqCnfh8TcoywmJiqm2Ck49BUUe4t98AjvMNhaHel4Vn4HUX'\
254
+ 'GX5xOEmt7gtsIE6YJP04ZoRKeWCrbYwjYIfLNlsbXpZj5oXPzBxOvwBuS6KL2HweeUGObiBsxRLsc1Bo'\
255
+ 'A_Na8Y2HtkWeZyUQPY1G3eSTPbBKR94T20LhcDSdNInzIFIhE5qI-WWCgHws6jB1K4Iip58zMgeTjGsD'\
256
+ '5Rc8ttBJwfprac8hBqMST_rzo-gn70b-iT3PJkasUbm32UwOxXtavJ5g"}',
257
+ headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
258
+ 'User-Agent' => ACME_USER_AGENT })
259
+ .to_return(status: 200, body: '', headers: {})
260
+
261
+ assert_nothing_raised do
262
+ cg.register
263
+ end
264
+ end
265
+
266
+ test 'register_and_authorize' do
267
+ cg = AcmePlugin::CertGenerator.new(private_key: 'key/test_keyfile_4096.pem',
268
+ endpoint: ENDPOINT_URL,
269
+ domain: 'example.com',
270
+ email: 'foobarbaz@example.com')
271
+ assert !cg.nil?
272
+
273
+ stub_request(:head, "#{API_URL}/new-reg")
274
+ .with(headers: { 'Accept' => '*/*' })
275
+ .to_return(status: 200, body: '', headers: {})
276
+
277
+ protected_field = '"protected":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eS'\
278
+ 'I6IlJTQSIsIm4iOiJxN0gtQ2txRHZ3ekx2OWRBZ05rSmQzM2FiVEpFa0ZHSjhXbGIxRnZ1Y1F6MEFYWX'\
279
+ 'JwWUx5ajdOYUNyQm90V1NaR2pFSnRQZ1k1M0xWWU1ET1BiOTktLTZEazNXVGhkT203U01JTlZYWlZ1Ym'\
280
+ 'hhNmtoY1pFWFA1NEdic0NzcFBmNm5OcUJCeEhDblV3V01GOElRcWkwTVdSNHFOeG1LZEVrcE56dGFCd0'\
281
+ 'xLU0ZWUHNRMHRGeXJHellhOEw0TkJqZWUyaWlEdWM2bHlMTkp6MnhfUUZMQWZneGw1cXdFa05FVGxNNz'\
282
+ 'JNQlRsTTNrR1k4UjN2RkVNVEhQSUtCM3VQcHdScE1qOEw2M1JLenpmcmM5Q0Y2TDRNaG01b05GUENndm'\
283
+ 'JDRWF6T0ctTEpwM2Q4bVlTZjBERE5RNlhoX0NnTG5TbXAzVWVmckpiQVFUZDBpSk4xa21TaV9fQmxOR1'\
284
+ 'JDS1dFZDgyZzA2aHgwbVRhOXVZZEQxMFNXaVF5UHZIbDRzWER3M0JMN0VpOVlPNHpoOUh6ZkpzUVhxY2'\
285
+ 'hzQnZVZ2dEVG9IZVJwMnhmS0hEcmFFZ2JPX0FxaEMxRkdkTUtPUnJMWnBMQm1oamw0MFVvMWNLUXZsbl'\
286
+ 'ZJZFJaQjU4QnoyZUhzNDVKN0ROYktsQm12cWZPQnJFN09nOHdEbFUzWFpIZ3dRZkt4TUhBV29Qc0d2RG'\
287
+ '1KRjRZdFRmZ0R4NmZWS2VNbng5cXpJQ0plRlZmYnkzaUc4dE9XUFNKWFZUcXZ2QlhiQnppT0h4bV9sOH'\
288
+ 'pma3UwUmk3RXYwWUU2VEJGWDZiNDRES0FpVW9adkUwTm9taXhhYll2ZDAwWFFPNndOMF9pdkN6Tmc0VV'\
289
+ 'ltaDlZUzJyM1E3YmloNFkyS3MyWllxdnNkazFnLWZiNGZRcyJ9LCJub25jZSI6bnVsbH0"'
290
+ stub_request(:post, "#{API_URL}/new-reg")
291
+ .with(body: "{#{protected_field},"\
292
+ '"payload":"eyJyZXNvdXJjZSI6Im5ldy1yZWciLCJjb250YWN0IjpbIm1haWx0bzpmb29iYXJiYXpAZ'\
293
+ 'XhhbXBsZS5jb20iXX0",'\
294
+ '"signature":"aQ6T0XVo9jS_jXlvQ6bjAfqcrMYpQTPE9_CD7v1hDBUzKpSoygAJmrbb0kSumMkWf-r'\
295
+ 'acxG5i7tcD4ed32ap1OsWUoPGWhXkQifAqToYMdfBzjwaS_OfjPpFflPOZmUvOygtGt3LTsdhA27PCSC'\
296
+ 'saZDlozz2143b00QhZ-gVkFRJEwOMN22ByOsL-1_R_UEp7mqwQKzeZ_nsW7japvGWcru13bzqiD2b069'\
297
+ 'kwrfksnMIMSjFWnJPnxCLpY-DQn8kCBeJfljW-mOJyZFck1ko0KBiOEbY_k0IJ0aspwg9lGRLkVX-wWV'\
298
+ '8Q_e8gwoLjmaXouUxAl2E3wNInXRJkgDOMfEUSOHzxI6WFYLzhVKVl7ktP7zx21my2vL_J_nROTDaVIU'\
299
+ 'qJgdUgEZ40KR_Kjd_pRKPcB8kHyKtDnCopmrPXLu0QCuHYAn_M-cYgkFOyvplJNodaZfKamLuwChywPl'\
300
+ 'DC5tr1BQvdlUVp-cwr_C_KU-Kpkws924xI0ah8ksuwsHpkp2458aVEIeDEEw7FgHZXUPKXaJcBIHjQ1R'\
301
+ 'vnm062Ub_4LR25TrKTgftDCftK2YtN4LA-jtlfOrdM47xZatAzhmFy_vFIIu_-phh5he0nn8Mx2byjsZ'\
302
+ '1M-DeW0Wl9_zxhhOo1gtmFhtguCKw3W0mdcdDZmhRleNS-HtYA0w41LA"}',
303
+ headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
304
+ 'User-Agent' => ACME_USER_AGENT })
305
+ .to_return(status: 200, body: '', headers: {})
306
+
307
+ stub_request(:post, "#{API_URL}/new-authz")
308
+ .with(body: "{#{protected_field},"\
309
+ '"payload":"eyJyZXNvdXJjZSI6Im5ldy1hdXRoeiIsImlkZW50aWZpZXIiOnsidHlwZSI6ImRucyIsI'\
310
+ 'nZhbHVlIjoiZXhhbXBsZS5jb20ifX0",'\
311
+ '"signature":"NIo2YSDVmY-ILSdUXu4r1sBi31YYEHGvAz0t9IskSjCDl3A2C7fKXXejxLEU9aHvjR8'\
312
+ '9ZwrQtdDjhSVvZ5tCOkN8UhZ_jo2Y9iDIoNijd7t11jCxiv9epgQ83cUXtqgYLQnfpNNFlxd24yyLNNe'\
313
+ 'K6NM4mIhf5fyji6skTOrv4TPg4ZZzx107dmPmGsKQpSo2uRb1bV6H63qOwqjfp4LYM_HrHTH-L_HQTgt'\
314
+ '1fV4pmlTYlmaK__OLgxBXdVFgSN2yAUXPl3b9xYsGq3yEdXlGFv_f2iNbfhhiFHl_ZbRsjbLY5QU5TRa'\
315
+ 'Y6w5LjVkMwNLuusAeR5SwkOjGYQw-PQ303xuCx2WhlcIVlz06Lex9zrYH7TVc1Tfl5aiaqw4lABJoFu8'\
316
+ 'YLWx83gQZbeyBJJ612e_oNqsbmd0RWytXzS-qydLmpjl2KS7U_877JIoZPePwqzbuNoUmeVfqQcCGcpM'\
317
+ 't1atBAoBVgOKW5cWlEhZD4BRY_q-dX2hcR-7T1suLdMpEc1b_JQr0EVxgz0rZWcE3xAtlQLYZtC7n_nW'\
318
+ 'B4EiQzRiiP1mgPRwdmASmAAMp7ToW53lYh-vLxpHX7CzLdug2AuvFkG6ajaGFMzZaJ4dyxf0GbznSNyV'\
319
+ 'ulEJlxSt81MVthCX3JjUtRDcJHZx6tQFR1Gm1RUDE7Sob0Xe6jZKfqRE"}',
320
+ headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
321
+ 'User-Agent' => ACME_USER_AGENT })
322
+ .to_return(status: 200,
323
+ body: '{'\
324
+ ' "status": "valid",'\
325
+ ' "expires": "2020-12-31T23:59:59+01:00",'\
326
+ ' "identifier":'\
327
+ ' {'\
328
+ ' "type": "dns", "value": "example.org"'\
329
+ ' },'\
330
+ ' "challenges":'\
331
+ ' ['\
332
+ ' {'\
333
+ ' "type": "http-01",'\
334
+ ' "status": "pending",'\
335
+ " \"uri\": \"#{API_URL}/challenge/JmusiS7mAL_OZ1tIbwQxpYadpM9E3Azbywa6KSveuEk/93\","\
336
+ ' "token":"-Jbrff2stnTiZXFFKJHXtYrZof2dqlQaegRbeG1t6BY"'\
337
+ ' }'\
338
+ ' ],'\
339
+ ' "combinations":[[0]]'\
340
+ '}',
341
+ headers: { 'Content-Type' => 'application/json',
342
+ 'Link' => "<#{API_URL}/new-cert>;rel=\"next\"",
343
+ 'Location' => "#{API_URL}/authz/JmusiS7mAL_OZ1tIbwQxpYadpM9E3Azbywa6KSveuEk",
344
+ 'Replay-Nonce' => 'Hdhg8ovViG7ipkQrQRW2dsDbK5vxhGd_4T9HDqg3u4c' })
345
+
346
+ assert_nothing_raised do
347
+ cg.register
348
+ cg.authorize
349
+ end
350
+ end
351
+ end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ module AcmePlugin
4
+ class ApplicationControllerTest < ActionController::TestCase
5
+ setup do
6
+ @routes = AcmePlugin::Engine.routes
7
+ end
8
+
9
+ test 'if challenge request is invalid when is smaller than 128 bits' do
10
+ get :index, params: { challenge: 'dG9rZW4=' }
11
+ assert_response :bad_request
12
+ assert_match('Challenge failed - Request has invalid length!', response.body)
13
+ end
14
+
15
+ test 'if challenge request is invalid if it is larger than 256 bytes' do
16
+ get :index, params: { challenge: 'a' * 257 }
17
+ assert_response :bad_request
18
+ assert_match('Challenge failed - Request has invalid length!', response.body)
19
+ end
20
+
21
+ test 'if challenge is valid' do
22
+ get :index, params: { challenge: 'rpzxDjD-8xrr5I1G_JBTEToVMYgjNjfSs-XZ62tRtgs' }
23
+ assert_response :ok
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.