Skip to content

Commit

Permalink
[uss_qualifier] netrid: DSS0020 - check DSS endpoints are encrypted
Browse files Browse the repository at this point in the history
  • Loading branch information
Shastick committed Nov 12, 2024
1 parent 68aac3f commit 20f9e56
Show file tree
Hide file tree
Showing 15 changed files with 276 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
from urllib.parse import urlparse

import requests

from monitoring.uss_qualifier.resources.astm.f3411.dss import DSSInstanceResource
from monitoring.uss_qualifier.scenarios.scenario import GenericTestScenario
from monitoring.uss_qualifier.suites.suite import ExecutionContext


class EndpointEncryption(GenericTestScenario):
"""
Ensures that the endpoints of a DSS are not accessible unencrypted:
- HTTP access should be impossible or redirect to HTTPS
- HTTPS access should be possible
TODO: add a check for minimal cipher strength to a 128bit AES equivalent or more.
"""

def __init__(
self,
dss: DSSInstanceResource,
):
super().__init__()
self._dss = dss.dss_instance

def run(self, context: ExecutionContext):
self.begin_test_scenario(context)

if not self._dss.base_url.startswith("https://"):
self.record_note(
"encrypted_endpoints",
"Cannot check encryption requirement when DSS endpoint is specified with an http:// base URL",
)
self.end_test_scenario()
return

self._case_http_unavailable_or_redirect()

self.end_test_scenario()

def _case_http_unavailable_or_redirect(self):
self.begin_test_case("Connect to HTTP port")
self.begin_test_step("Attempt to connect to the DSS instance on the HTTP port")

parsed_url = urlparse(self._dss.base_url)
hostname = parsed_url.hostname

if hostname is not None:
with self.check(
"Connection to HTTP port fails or redirects to HTTPS port",
self._dss.participant_id,
) as check:
try:
response = requests.get(
f"http://{hostname}/{parsed_url.path}",
timeout=10,
allow_redirects=False,
)
# If we can connect, we want to check that we are being redirected:
if response.status_code not in [301, 308]:
check.record_failed(
"Connection to HTTP port did not redirect",
details=f"Was expecting a 301 or 308 response, but obtained status code: {response.status_code}",
)
if "Location" not in response.headers:
check.record_failed(
"Location header missing in redirect response",
details="Was expecting a Location header in the response, but it was not present",
)
if response.headers.get("Location").startswith("http://"):
check.record_failed(
"Connection to HTTP port redirected to HTTP",
details=f"Was expecting a redirection to an https:// URL. Location header: {response.headers.get('Location')}",
)
if not response.headers.get("Location").startswith(
f"https://{parsed_url.hostname}/{parsed_url.path}"
):
check.record_failed(
"Redirect to unexpected destination",
details=f"Was expecting a redirection to https://{parsed_url.hostname}/{parsed_url.path}, was {response.headers.get('Location')}",
)
except requests.RequestException:
# Connection was impossible: all is good
pass

self.end_test_step()
self.end_test_case()

def _case_https_works(self):
self.begin_test_case("Connect to HTTPS port")
self.begin_test_step("Attempt to connect to the DSS instance on the HTTPS port")

parsed_url = urlparse(self._dss.base_url)
hostname = parsed_url.hostname

if hostname is not None:
with self.check(
"A request can be sent over HTTPS",
self._dss.participant_id,
) as check:
try:
requests.get(
f"https://{hostname}/{parsed_url.path}",
timeout=10,
allow_redirects=False,
)
# We don't care about the response details, just that the connection was successful
# (a 404 would still indicate that HTTPS is working well)
except requests.RequestException as e:
check.record_failed(
"Connection to HTTPS port failed",
details=f"Encountered exception while attempting HTTPS request: {e}",
)

self.end_test_step()
self.end_test_case()
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
from .token_validation import TokenValidation
from .crdb_access import CRDBAccess
from .heavy_traffic_concurrent import HeavyTrafficConcurrent
from .endpoint_encryption import EndpointEncryption
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# ASTM NetRID DSS: Endpoint encryption test scenario

## Overview

Ensures that a DSS only exposes its endpoints via HTTPS.

## Resources

### dss

[`DSSInstanceResource`](../../../../../resources/astm/f3411/dss.py) to be tested in this scenario.


## Connect to HTTP port test case

Tries to connect to the http port (80) of the DSS instance, and expects either a refusal of the connection,
or a redirection to the https port (443).

Note: this test case will be skipped if the DSS instance is configured to use HTTP.

### Attempt to connect to the DSS instance on the HTTP port test step

#### 🛑 Connection to HTTP port fails or redirects to HTTPS port check

If the DSS instance accepts the connection on the HTTP port and does not immediately redirect to the HTTPS port
upon reception of an HTTP request, it is in violation of **[astm.f3411.v19.DSS0020](../../../../../requirements/astm/f3411/v19.md)**.

## Connect to HTTPS port test case

Try to connect to the DSS instance over HTTPS.

### Attempt to connect to the DSS instance on the HTTPS port test step

#### 🛑 A request can be sent over HTTPS check

If the DSS instance cannot be reached over HTTPS, it is in violation of **[astm.f3411.v19.DSS0020](../../../../../requirements/astm/f3411/v19.md)**.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from monitoring.uss_qualifier.scenarios.astm.netrid.common.dss.endpoint_encryption import (
EndpointEncryption as CommonEndpointEncryption,
)
from monitoring.uss_qualifier.scenarios.scenario import TestScenario


class EndpointEncryption(TestScenario, CommonEndpointEncryption):
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# ASTM NetRID DSS: Endpoint encryption test scenario

## Overview

Ensures that a DSS only exposes its endpoints via HTTPS.

## Resources

### dss

[`DSSInstanceResource`](../../../../../resources/astm/f3411/dss.py) to be tested in this scenario.

## Connect to HTTP port test case

Tries to connect to the http port (80) of the DSS instance, and expects either a refusal of the connection,
or a redirection to the https port (443).

Note: this test case will be skipped if the DSS instance is configured to use HTTP.

### Attempt to connect to the DSS instance on the HTTP port test step

#### 🛑 Connection to HTTP port fails or redirects to HTTPS port check

If the DSS instance accepts the connection on the HTTP port and does not immediately redirect to the HTTPS port
upon reception of an HTTP request, it is in violation of **[astm.f3411.v22a.DSS0020](../../../../../requirements/astm/f3411/v22a.md)**.

## Connect to HTTPS port test case

Try to connect to the DSS instance over HTTPS.

### Attempt to connect to the DSS instance on the HTTPS port test step

#### 🛑 A request can be sent over HTTPS check

If the DSS instance cannot be reached over HTTPS, it is in violation of **[astm.f3411.v22a.DSS0020](../../../../../requirements/astm/f3411/v22a.md)**.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from monitoring.uss_qualifier.scenarios.astm.netrid.common.dss.endpoint_encryption import (
EndpointEncryption as CommonEndpointEncryption,
)
from monitoring.uss_qualifier.scenarios.scenario import TestScenario


class EndpointEncryption(TestScenario, CommonEndpointEncryption):
pass
7 changes: 6 additions & 1 deletion monitoring/uss_qualifier/suites/astm/netrid/f3411_19.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@
<th><a href="../../README.md#checked-in">Checked in</a></th>
</tr>
<tr>
<td rowspan="66" style="vertical-align:top;"><a href="../../../requirements/astm/f3411/v19.md">astm<br>.f3411<br>.v19</a></td>
<td rowspan="67" style="vertical-align:top;"><a href="../../../requirements/astm/f3411/v19.md">astm<br>.f3411<br>.v19</a></td>
<td><a href="../../../requirements/astm/f3411/v19.md">DSS0010</a></td>
<td>Implemented</td>
<td><a href="../../../scenarios/astm/netrid/v19/dss/token_validation.md">ASTM NetRID DSS: Token Validation</a></td>
</tr>
<tr>
<td><a href="../../../requirements/astm/f3411/v19.md">DSS0020</a></td>
<td>Implemented</td>
<td><a href="../../../scenarios/astm/netrid/v19/dss/endpoint_encryption.md">ASTM NetRID DSS: Endpoint encryption</a></td>
</tr>
<tr>
<td><a href="../../../requirements/astm/f3411/v19.md">DSS0030,a</a></td>
<td>Implemented</td>
Expand Down
28 changes: 17 additions & 11 deletions monitoring/uss_qualifier/suites/astm/netrid/f3411_19/dss_probing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@

## [Actions](../../../README.md#actions)

1. Scenario: [ASTM NetRID DSS: Simple ISA](../../../../scenarios/astm/netrid/v19/dss/isa_simple.md) ([`scenarios.astm.netrid.v19.dss.ISASimple`](../../../../scenarios/astm/netrid/v19/dss/isa_simple.py))
2. Scenario: [ASTM NetRID DSS: Submitted ISA Validations](../../../../scenarios/astm/netrid/v19/dss/isa_validation.md) ([`scenarios.astm.netrid.v19.dss.ISAValidation`](../../../../scenarios/astm/netrid/v19/dss/isa_validation.py))
3. Scenario: [ASTM NetRID DSS: ISA Expiry](../../../../scenarios/astm/netrid/v19/dss/isa_expiry.md) ([`scenarios.astm.netrid.v19.dss.ISAExpiry`](../../../../scenarios/astm/netrid/v19/dss/isa_expiry.py))
4. Scenario: [ASTM NetRID DSS: ISA Subscription Interactions](../../../../scenarios/astm/netrid/v19/dss/isa_subscription_interactions.md) ([`scenarios.astm.netrid.v19.dss.ISASubscriptionInteractions`](../../../../scenarios/astm/netrid/v19/dss/isa_subscription_interactions.py))
5. Scenario: [ASTM NetRID DSS: Subscription Validation](../../../../scenarios/astm/netrid/v19/dss/subscription_validation.md) ([`scenarios.astm.netrid.v19.dss.SubscriptionValidation`](../../../../scenarios/astm/netrid/v19/dss/subscription_validation.py))
6. Scenario: [ASTM NetRID DSS: Subscription Simple](../../../../scenarios/astm/netrid/v19/dss/subscription_simple.md) ([`scenarios.astm.netrid.v19.dss.SubscriptionSimple`](../../../../scenarios/astm/netrid/v19/dss/subscription_simple.py))
7. Scenario: [ASTM F3411-19 NetRID DSS interoperability](../../../../scenarios/astm/netrid/v19/dss_interoperability.md) ([`scenarios.astm.netrid.v19.DSSInteroperability`](../../../../scenarios/astm/netrid/v19/dss_interoperability.py))
8. Scenario: [ASTM NetRID DSS: Token Validation](../../../../scenarios/astm/netrid/v19/dss/token_validation.md) ([`scenarios.astm.netrid.v19.dss.TokenValidation`](../../../../scenarios/astm/netrid/v19/dss/token_validation.py))
9. Scenario: [ASTM NetRID DSS: Direct CRDB access](../../../../scenarios/astm/netrid/v19/dss/crdb_access.md) ([`scenarios.astm.netrid.v19.dss.CRDBAccess`](../../../../scenarios/astm/netrid/v19/dss/crdb_access.py))
10. Scenario: [ASTM NetRID DSS: Concurrent Requests](../../../../scenarios/astm/netrid/v19/dss/heavy_traffic_concurrent.md) ([`scenarios.astm.netrid.v19.dss.HeavyTrafficConcurrent`](../../../../scenarios/astm/netrid/v19/dss/heavy_traffic_concurrent.py))
1. Scenario: [ASTM NetRID DSS: Endpoint encryption](../../../../scenarios/astm/netrid/v19/dss/endpoint_encryption.md) ([`scenarios.astm.netrid.v19.dss.EndpointEncryption`](../../../../scenarios/astm/netrid/v19/dss/endpoint_encryption.py))
2. Scenario: [ASTM NetRID DSS: Simple ISA](../../../../scenarios/astm/netrid/v19/dss/isa_simple.md) ([`scenarios.astm.netrid.v19.dss.ISASimple`](../../../../scenarios/astm/netrid/v19/dss/isa_simple.py))
3. Scenario: [ASTM NetRID DSS: Submitted ISA Validations](../../../../scenarios/astm/netrid/v19/dss/isa_validation.md) ([`scenarios.astm.netrid.v19.dss.ISAValidation`](../../../../scenarios/astm/netrid/v19/dss/isa_validation.py))
4. Scenario: [ASTM NetRID DSS: ISA Expiry](../../../../scenarios/astm/netrid/v19/dss/isa_expiry.md) ([`scenarios.astm.netrid.v19.dss.ISAExpiry`](../../../../scenarios/astm/netrid/v19/dss/isa_expiry.py))
5. Scenario: [ASTM NetRID DSS: ISA Subscription Interactions](../../../../scenarios/astm/netrid/v19/dss/isa_subscription_interactions.md) ([`scenarios.astm.netrid.v19.dss.ISASubscriptionInteractions`](../../../../scenarios/astm/netrid/v19/dss/isa_subscription_interactions.py))
6. Scenario: [ASTM NetRID DSS: Subscription Validation](../../../../scenarios/astm/netrid/v19/dss/subscription_validation.md) ([`scenarios.astm.netrid.v19.dss.SubscriptionValidation`](../../../../scenarios/astm/netrid/v19/dss/subscription_validation.py))
7. Scenario: [ASTM NetRID DSS: Subscription Simple](../../../../scenarios/astm/netrid/v19/dss/subscription_simple.md) ([`scenarios.astm.netrid.v19.dss.SubscriptionSimple`](../../../../scenarios/astm/netrid/v19/dss/subscription_simple.py))
8. Scenario: [ASTM F3411-19 NetRID DSS interoperability](../../../../scenarios/astm/netrid/v19/dss_interoperability.md) ([`scenarios.astm.netrid.v19.DSSInteroperability`](../../../../scenarios/astm/netrid/v19/dss_interoperability.py))
9. Scenario: [ASTM NetRID DSS: Token Validation](../../../../scenarios/astm/netrid/v19/dss/token_validation.md) ([`scenarios.astm.netrid.v19.dss.TokenValidation`](../../../../scenarios/astm/netrid/v19/dss/token_validation.py))
10. Scenario: [ASTM NetRID DSS: Direct CRDB access](../../../../scenarios/astm/netrid/v19/dss/crdb_access.md) ([`scenarios.astm.netrid.v19.dss.CRDBAccess`](../../../../scenarios/astm/netrid/v19/dss/crdb_access.py))
11. Scenario: [ASTM NetRID DSS: Concurrent Requests](../../../../scenarios/astm/netrid/v19/dss/heavy_traffic_concurrent.md) ([`scenarios.astm.netrid.v19.dss.HeavyTrafficConcurrent`](../../../../scenarios/astm/netrid/v19/dss/heavy_traffic_concurrent.py))

## [Checked requirements](../../../README.md#checked-requirements)

Expand All @@ -25,11 +26,16 @@
<th><a href="../../../README.md#checked-in">Checked in</a></th>
</tr>
<tr>
<td rowspan="38" style="vertical-align:top;"><a href="../../../../requirements/astm/f3411/v19.md">astm<br>.f3411<br>.v19</a></td>
<td rowspan="39" style="vertical-align:top;"><a href="../../../../requirements/astm/f3411/v19.md">astm<br>.f3411<br>.v19</a></td>
<td><a href="../../../../requirements/astm/f3411/v19.md">DSS0010</a></td>
<td>Implemented</td>
<td><a href="../../../../scenarios/astm/netrid/v19/dss/token_validation.md">ASTM NetRID DSS: Token Validation</a></td>
</tr>
<tr>
<td><a href="../../../../requirements/astm/f3411/v19.md">DSS0020</a></td>
<td>Implemented</td>
<td><a href="../../../../scenarios/astm/netrid/v19/dss/endpoint_encryption.md">ASTM NetRID DSS: Endpoint encryption</a></td>
</tr>
<tr>
<td><a href="../../../../requirements/astm/f3411/v19.md">DSS0030,a</a></td>
<td>Implemented</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ resources:
problematically_big_area: resources.VerticesResource
test_exclusions: resources.dev.TestExclusionsResource?
actions:
- test_scenario:
scenario_type: scenarios.astm.netrid.v19.dss.EndpointEncryption
resources:
dss: dss
- test_scenario:
scenario_type: scenarios.astm.netrid.v19.dss.ISASimple
resources:
Expand Down
6 changes: 6 additions & 0 deletions monitoring/uss_qualifier/suites/astm/netrid/f3411_22a.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
<th><a href="../../README.md#status">Status</a></th>
<th><a href="../../README.md#checked-in">Checked in</a></th>
</tr>
<tr>
<td rowspan="1" style="vertical-align:top;"><a href="../../../requirements/astm/f3411/v19.md">astm<br>.f3411<br>.v19</a></td>
<td><a href="../../../requirements/astm/f3411/v19.md">DSS0020</a></td>
<td>Implemented</td>
<td><a href="../../../scenarios/astm/netrid/v19/dss/endpoint_encryption.md">ASTM NetRID DSS: Endpoint encryption</a></td>
</tr>
<tr>
<td rowspan="91" style="vertical-align:top;"><a href="../../../requirements/astm/f3411/v22a.md">astm<br>.f3411<br>.v22a</a></td>
<td><a href="../../../requirements/astm/f3411/v22a.md">DSS0010</a></td>
Expand Down
Loading

0 comments on commit 20f9e56

Please sign in to comment.