Skip to content

Commit 20c2f6f

Browse files
test(unit): Add unit test for TLS auth
1 parent 51a1232 commit 20c2f6f

File tree

5 files changed

+106
-14
lines changed

5 files changed

+106
-14
lines changed

.github/workflows/test-suite.yml

+4
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ jobs:
103103
run: |
104104
ddev exec BOUNCER_KEY=${{ env.BOUNCER_KEY }} AGENT_TLS_PATH=/var/www/html/cfssl USE_CURL=1 LAPI_URL=https://crowdsec:8080 MEMCACHED_DSN=memcached://memcached:11211 REDIS_DSN=redis://redis:6379 /usr/bin/php ./${{env.EXTENSION_PATH}}/vendor/bin/phpunit --testdox --colors --exclude-group ignore ./${{env.EXTENSION_PATH}}/tests/Integration/IpVerificationTest.php
105105
106+
- name: Run "IP verification with TLS" test
107+
run: |
108+
ddev exec AGENT_TLS_PATH=/var/www/html/cfssl BOUNCER_TLS_PATH=/var/www/html/cfssl LAPI_URL=https://crowdsec:8080 MEMCACHED_DSN=memcached://memcached:11211 REDIS_DSN=redis://redis:6379 /usr/bin/php ./${{env.EXTENSION_PATH}}/vendor/bin/phpunit --testdox --colors --exclude-group ignore ./${{env.EXTENSION_PATH}}/tests/Integration/IpVerificationTest.php
109+
106110
- name: Run "Geolocation with file_get_contents" test
107111
run: |
108112
ddev exec BOUNCER_KEY=${{ env.BOUNCER_KEY }} AGENT_TLS_PATH=/var/www/html/cfssl LAPI_URL=https://crowdsec:8080 /usr/bin/php ./${{env.EXTENSION_PATH}}/vendor/bin/phpunit --testdox --colors --exclude-group ignore ./${{env.EXTENSION_PATH}}/tests/Integration/GeolocationTest.php

docs/DEVELOPER.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,16 @@ ddev exec BOUNCER_KEY=your-bouncer-key AGENT_TLS_PATH=/var/www/html/cfssl LAPI_U
234234
/usr/bin/php ./my-own-modules/crowdsec-php-lib/vendor/bin/phpunit --testdox --colors --exclude-group ignore ./my-own-modules/crowdsec-php-lib/tests/Integration/GeolocationTest.php
235235
```
236236

237-
N.B: If you want to test with `curl` instead of `file_get_contents` calls to LAPI, you have to add `USE_CURL=1` in
237+
**N.B**: If you want to test with `curl` instead of `file_get_contents` calls to LAPI, you have to add `USE_CURL=1` in
238238
the previous commands.
239239

240+
**N.B**: If you want to test with `tls` authentification, you have to add `BOUNCER_TLS_PATH` environment varibale
241+
and specify the path where you store certificates and keys. For example:
242+
243+
```bash
244+
ddev exec USE_CURL=1 AGENT_TLS_PATH=/var/www/html/cfssl BOUNCER_TLS_PATH=/var/www/html/cfssl LAPI_URL=https://crowdsec:8080 MEMCACHED_DSN=memcached://memcached:11211 REDIS_DSN=redis://redis:6379 /usr/bin/php ./my-own-modules/crowdsec-php-lib/vendor/bin/phpunit --testdox --colors --exclude-group ignore ./my-own-modules/crowdsec-php-lib/tests/Integration/IpVerificationTest.php
245+
```
246+
240247

241248
#### Auto-prepend mode (standalone mode)
242249

docs/USER_GUIDE.md

+63-9
Original file line numberDiff line numberDiff line change
@@ -119,82 +119,136 @@ Here is the list of available settings:
119119

120120
##### LAPI Connection
121121

122-
- `api_key`: Key generated by the cscli (CrowdSec cli) command like `cscli bouncers add bouncer-php-library`
122+
- `auth_type`: Select from `api_key` and `tls`. Choose if you want to use an API-KEY or a TLS (pki) authentification.
123+
TLS authentication is only available if you use CrowdSec agent with a version superior to 1.4.0.
124+
125+
126+
- `api_key`: Key generated by the cscli (CrowdSec cli) command like `cscli bouncers add bouncer-php-library`.
127+
Only required if you choose `api_key` as `auth_type`.
128+
129+
130+
- `tls_cert_path`: absolute path to the bouncer certificate (e.g. pem file).
131+
Only required if you choose `tls` as `auth_type`.
132+
133+
134+
- `tls_key_path`: Absolute path to the bouncer key (e.g. pem file).
135+
Only required if you choose `tls` as `auth_type`.
136+
137+
138+
- `tls_verify_peer`: This option determines whether request handler verifies the authenticity of the peer's certificate.
139+
Only required if you choose `tls` as `auth_type`.
140+
When negotiating a TLS or SSL connection, the server sends a certificate indicating its identity.
141+
If `tls_verify_peer` is set to true, request handler verifies whether the certificate is authentic.
142+
This trust is based on a chain of digital signatures,
143+
rooted in certification authority (CA) certificates you supply using the `tls_ca_cert_path` setting below.
144+
145+
146+
- `tls_ca_cert_path`: Absolute path to the CA used to process peer verification.
147+
Only required if you choose `tls` as `auth_type` and `tls_verify_peer` is set to true.
148+
123149

124150
- `api_url`: Define the URL to your LAPI server, default to `http://localhost:8080`.
125151

152+
126153
- `api_timeout`: In seconds. The timeout when calling LAPI. Must be greater or equal than 1. Default to 1 sec.
127154

155+
128156
- `use_curl`: By default, this lib call the REST LAPI using `file_get_contents` method (`allow_url_fopen` is required).
129157
You can set `use_curl` to `true` in order to use `cURL` request instead (`curl` is in then required)
130158

159+
131160
##### Debug
132161
- `debug_mode`: `true` to enable verbose debug log. Default to `false`.
133162

163+
134164
- `disable_prod_log`: `true` to disable prod log. Default to `false`.
135165

136-
- `log_directory_path`: Absolute path to store log files. Important note: be sur this path won't be publicly accessible
166+
167+
- `log_directory_path`: Absolute path to store log files. Important note: be sur this path won't be publicly
168+
accessible.
169+
137170

138171
- `display_errors`: true to stop the process and display errors on browser if any.
139172

173+
140174
- `forced_test_ip`: Only for test or debug purpose. Default to empty. If not empty, it will be used instead of the
141175
real remote ip.
142176

177+
143178
- `forced_test_forwarded_ip`: Only for test or debug purpose. Default to empty. If not empty, it will be used
144179
instead of the real forwarded ip. If set to `no_forward`, the x-forwarded-for mechanism will not be used at all.
145180

146181
##### Bouncer behavior
147182

148183
- `bouncing_level`: Select from `bouncing_disabled`, `normal_bouncing` or `flex_bouncing`. Choose if you want to apply CrowdSec directives (Normal bouncing) or be more permissive (Flex bouncing). With the `Flex mode`, it is impossible to accidentally block access to your site to people who don’t deserve it. This mode makes it possible to never ban an IP but only to offer a Captcha, in the worst-case scenario.
149184

185+
150186
- `fallback_remediation`: Select from `bypass` (minimum remediation), `captcha` or `ban` (maximum remediation). Default to 'captcha'. Handle unknown remediations as.
151187

188+
152189
- `max_remediation_level`: Select from `bypass`,`captcha` or `ban`. Default to 'ban'. Cap the
153190
remediation to the selected one.
154191

192+
155193
- `trust_ip_forward_array`: If you use a CDN, a reverse proxy or a load balancer, set an array of IPs. For other IPs, the bouncer will not trust the X-Forwarded-For header.
156194

157-
- `excluded_uris`: array of URIs that will not be bounced
195+
196+
- `excluded_uris`: array of URIs that will not be bounced.
158197

159198
##### Cache
160199

161200
- `cache_system`: Select from `phpfs` (File system cache), `redis` or `memcached`.
162201

202+
163203
- `fs_cache_path`: Will be used only if you choose File system as cache_system. Important note: be sur this path
164204
won't be publicly accessible.
165205

166-
- `redis_dsn`: Will be used only if you choose Redis cache as cache_system
167206

168-
- `memcached_dsn`: Will be used only if you choose Memcached as cache_system
207+
- `redis_dsn`: Will be used only if you choose Redis cache as cache_system.
208+
209+
210+
- `memcached_dsn`: Will be used only if you choose Memcached as cache_system.
211+
169212

170213
- `clean_ip_cache_duration`: Set the duration we keep in cache the fact that an IP is clean. In seconds. Defaults to 5.
171214

215+
172216
- `bad_ip_cache_duration`: Set the duration we keep in cache the fact that an IP is bad. In seconds. Defaults to 20.
173217

218+
174219
- `captcha_cache_duration`: Set the duration we keep in cache the captcha flow variables for an IP. In seconds.
175220
Defaults to 86400.. In seconds. Defaults to 20.
176221

222+
177223
- `geolocation_cache_duration`: Set the duration we keep in cache a geolocation result for an IP . In seconds.
178224
Defaults to 86400. Depends on the below `geolocation[save_result]` configuration.
179225

226+
180227
- `stream_mode`: true to enable stream mode, false to enable the live mode. Default to false. By default, the `live mode` is enabled. The first time a stranger connects to your website, this mode means that the IP will be checked directly by the CrowdSec API. The rest of your user’s browsing will be even more transparent thanks to the fully customizable cache system. But you can also activate the `stream mode`. This mode allows you to constantly feed the bouncer with the malicious IP list via a background task (CRON), making it to be even faster when checking the IP of your visitors. Besides, if your site has a lot of unique visitors at the same time, this will not influence the traffic to the API of your CrowdSec instance.
181228

182229
##### Geolocation
183230

184231
- `geolocation`: Settings for geolocation remediation (i.e. country based remediation).
232+
185233
- `geolocation[enabled]`: true to enable remediation based on country. Default to false.
186-
- `geolocation[type]`: Geolocation system. Only 'maxmind' is available for the moment. Default to `maxmind`
234+
235+
- `geolocation[type]`: Geolocation system. Only 'maxmind' is available for the moment. Default to `maxmind`.
236+
187237

188238
- `geolocation[save_result]`: true to store the geolocalized country in cache. Default to true. Setting true
189-
will avoid multiple call to the geolocalized system (e.g. maxmind database)
190-
- `geolocation[maxmind]`: MaxMind settings
239+
will avoid multiple call to the geolocalized system (e.g. maxmind database).
240+
241+
- `geolocation[maxmind]`: MaxMind settings.
242+
191243
- `geolocation[maxmind][database_type]`: Select from `country` or `city`. Default to `country`. These are the two available MaxMind database types.
192-
- `geolocation[maxmind][database_path]`: Absolute path to the MaxMind database (mmdb
244+
245+
- `geolocation[maxmind][database_path]`: Absolute path to the MaxMind database (e.g. mmdb file)
193246

194247

195248
##### Captcha and ban wall settings
196249

197250
- `hide_mentions`: true to hide CrowdSec mentions on ban and captcha walls.
251+
198252
- Wording and css settings:
199253

200254
`theme_color_text_primary`

scripts/auto-prepend/settings.example.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@
2121
*
2222
* Only required if you choose tls as "auth_type"
2323
*/
24-
'tls_bouncer_key' => '',
24+
'tls_key_path' => '',
2525

2626
/** This option determines whether request handler verifies the authenticity of the peer's certificate.
2727
*
2828
* When negotiating a TLS or SSL connection, the server sends a certificate indicating its identity.
2929
* If "tls_verify_peer" is set to true, request handler verifies whether the certificate is authentic.
3030
* This trust is based on a chain of digital signatures,
31-
* rooted in certification authority (CA) certificates you supply using the "tls_ca_cert" setting below.
31+
* rooted in certification authority (CA) certificates you supply using the "tls_ca_cert_path" setting below.
3232
*
3333
*/
3434
'tls_verify_peer' => true,
@@ -37,7 +37,7 @@
3737
*
3838
* Only required if you choose tls as "auth_type" and "tls_verify_peer" is true
3939
*/
40-
'tls_ca_cert' => '',
40+
'tls_ca_cert_path' => '',
4141

4242
/** The bouncer api key to access LAPI.
4343
*

tests/Integration/IpVerificationTest.php

+28-1
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@ final class IpVerificationTest extends TestCase
2020
/** @var bool */
2121
private $useCurl;
2222

23+
/** @var bool */
24+
private $useTls;
25+
2326
protected function setUp(): void
2427
{
2528
$this->logger = TestHelpers::createLogger();
2629
$this->useCurl = (bool) getenv('USE_CURL');
30+
$this->useTls = (string) getenv('BOUNCER_TLS_PATH');
2731
$this->watcherClient = new WatcherClient(['use_curl' => $this->useCurl], $this->logger);
2832
}
2933

@@ -43,6 +47,7 @@ public function testCanVerifyIpInLiveModeWithCacheSystem($cacheAdapterName, $ori
4347

4448
// Init bouncer
4549
$bouncerConfigs = [
50+
'auth_type' => $this->useTls ? Constants::AUTH_TLS : Constants::AUTH_KEY,
4651
'api_key' => TestHelpers::getBouncerKey(),
4752
'api_url' => TestHelpers::getLapiUrl(),
4853
'use_curl' => $this->useCurl,
@@ -52,6 +57,13 @@ public function testCanVerifyIpInLiveModeWithCacheSystem($cacheAdapterName, $ori
5257
'memcached_dsn' => getenv('MEMCACHED_DSN'),
5358
'fs_cache_path' => TestHelpers::PHP_FILES_CACHE_ADAPTER_DIR
5459
];
60+
if($this->useTls){
61+
$bouncerConfigs['tls_cert_path'] = $this->useTls . '/bouncer.pem';
62+
$bouncerConfigs['tls_key_path'] = $this->useTls . '/bouncer-key.pem';
63+
$bouncerConfigs['tls_ca_cert_path'] = $this->useTls . '/ca-chain.pem';
64+
$bouncerConfigs['tls_verify_peer'] = true;
65+
66+
}
5567

5668
$bouncer = new Bouncer($bouncerConfigs, $this->logger);
5769

@@ -154,6 +166,7 @@ public function testCanVerifyIpInStreamModeWithCacheSystem($cacheAdapterName, $o
154166
$this->watcherClient->setInitialState();
155167
// Init bouncer
156168
$bouncerConfigs = [
169+
'auth_type' => $this->useTls ? Constants::AUTH_TLS : Constants::AUTH_KEY,
157170
'api_key' => TestHelpers::getBouncerKey(),
158171
'api_url' => TestHelpers::getLapiUrl(),
159172
'api_user_agent' => TestHelpers::UNIT_TEST_AGENT_PREFIX . '/' . Constants::BASE_USER_AGENT,
@@ -164,6 +177,12 @@ public function testCanVerifyIpInStreamModeWithCacheSystem($cacheAdapterName, $o
164177
'memcached_dsn' => getenv('MEMCACHED_DSN'),
165178
'fs_cache_path' => TestHelpers::PHP_FILES_CACHE_ADAPTER_DIR
166179
];
180+
if($this->useTls){
181+
$bouncerConfigs['tls_cert_path'] = $this->useTls . '/bouncer.pem';
182+
$bouncerConfigs['tls_key_path'] = $this->useTls . '/bouncer-key.pem';
183+
$bouncerConfigs['tls_ca_cert_path'] = $this->useTls . '/ca-chain.pem';
184+
$bouncerConfigs['tls_verify_peer'] = true;
185+
}
167186

168187
$bouncer = new Bouncer($bouncerConfigs, $this->logger);
169188
// Test cache adapter
@@ -251,8 +270,9 @@ public function testCanVerifyIpInStreamModeWithCacheSystem($cacheAdapterName, $o
251270
'The old decisions should now be removed, so the previously bad IP should now be clean'
252271
);
253272

254-
// Setup an new instance.
273+
// Set up a new instance.
255274
$bouncerConfigs = [
275+
'auth_type' => $this->useTls ? Constants::AUTH_TLS : Constants::AUTH_KEY,
256276
'api_key' => TestHelpers::getBouncerKey(),
257277
'api_url' => TestHelpers::getLapiUrl(),
258278
'stream_mode' => true,
@@ -263,6 +283,13 @@ public function testCanVerifyIpInStreamModeWithCacheSystem($cacheAdapterName, $o
263283
'memcached_dsn' => getenv('MEMCACHED_DSN'),
264284
'fs_cache_path' => TestHelpers::PHP_FILES_CACHE_ADAPTER_DIR
265285
];
286+
if($this->useTls){
287+
$bouncerConfigs['tls_cert_path'] = $this->useTls . '/bouncer.pem';
288+
$bouncerConfigs['tls_key_path'] = $this->useTls . '/bouncer-key.pem';
289+
$bouncerConfigs['tls_ca_cert_path'] = $this->useTls . '/ca-chain.pem';
290+
$bouncerConfigs['tls_verify_peer'] = true;
291+
292+
}
266293

267294
$bouncer = new Bouncer($bouncerConfigs, $this->logger);
268295

0 commit comments

Comments
 (0)