Skip to content

Commit a8d3ac7

Browse files
authored
Merge pull request #8 from brightcove/update_2024q2
SECENG-1343 - Update 2024Q2
2 parents bc60490 + 6e20d0b commit a8d3ac7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+716
-140
lines changed

.github/workflows/codeql.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ jobs:
2121
uses: actions/checkout@v4
2222

2323
- name: Initialize CodeQL
24-
uses: github/codeql-action/init@v2
24+
uses: github/codeql-action/init@v3
2525
with:
2626
languages: ${{ matrix.language }}
2727

2828
- name: Autobuild
29-
uses: github/codeql-action/autobuild@v2
29+
uses: github/codeql-action/autobuild@v3
3030

3131
- name: Perform CodeQL Analysis
32-
uses: github/codeql-action/analyze@v2
32+
uses: github/codeql-action/analyze@v3
3333
with:
3434
category: "/language:${{matrix.language}}"

.github/workflows/integration_tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
uses: actions/checkout@v4
1515

1616
- name: Set up Python 3.11
17-
uses: actions/setup-python@v4
17+
uses: actions/setup-python@v5
1818
with:
1919
python-version: "3.11"
2020

.github/workflows/unit_tests.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ jobs:
1414
uses: actions/checkout@v4
1515

1616
- name: Set up Python 3.11
17-
uses: actions/setup-python@v4
17+
uses: actions/setup-python@v5
1818
with:
1919
python-version: "3.11"
2020
cache: 'pip' # caching pip dependencies
2121
- run : pip install -r requirements-dev.txt
2222

2323
- name: Linting and formatting
24-
uses: pre-commit/action@v3.0.0
24+
uses: pre-commit/action@v3.0.1
2525
with:
2626
extra_args: --all-files --show-diff-on-failure
2727

.pre-commit-config.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ repos:
3434
args: [--py3-plus]
3535
exclude: .\.tf | ^\.github/
3636
- repo: https://github.com/psf/black
37-
rev: 22.12.0
37+
rev: 24.3.0
3838
hooks:
3939
- id: black
4040
args: [--line-length=120]
@@ -45,7 +45,7 @@ repos:
4545
- id: bandit
4646
exclude: .\.tf | ^\.github/
4747
- repo: https://github.com/pycqa/prospector
48-
rev: v1.8.4
48+
rev: v1.10.3
4949
hooks:
5050
- id: prospector
5151
args:

.whitesource

-3
This file was deleted.

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# OWASP Domain Protect
2-
![Release version](https://img.shields.io/badge/release-v0.4.4-blue.svg)
2+
![Release version](https://img.shields.io/badge/release-v0.4.7-blue.svg)
33
[![Python 3.x](https://img.shields.io/badge/Python-3.x-blue.svg)](https://www.python.org/)
44
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
55
![OWASP Maturity](https://img.shields.io/badge/owasp-incubator%20project-53AAE5.svg)

docs/integration-tests.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ To set up the DNS mock to throw an error:
4444
dns_mock.add_lookup("sub.ns.co.uk", "sub.ns.co.uk", exception=dns.resolver.NoNameservers)
4545
```
4646

47-
The DNS mock is set up in a pytest fixture in `intergation_tests/conftest.py`, so to use the mock in a test simply add `dns_mock` to your tests parameter list and pytest will pass in an instance of the mock.
47+
The DNS mock is set up in a pytest fixture in `integration_tests/conftest.py`, so to use the mock in a test simply add `dns_mock` to your tests parameter list and pytest will pass in an instance of the mock.
4848

4949
### Mocking AWS
5050

docs/test-records/alias-cloudfront.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Alias CloudFront
22
* Deploy [aws-cloudfront](https://github.com/celidor/aws-cloudfront) using Terraform
33
* This will create resources in CloudFront, S3, Certificate Manager and Route53
4-
* Route53 record is a CNAME pointing to the CloudFront distrubtion
4+
* Route53 record is a CNAME pointing to the CloudFront distribution
55
* Delete the CNAME record manually via the console
66
* Create an Alias record manually via the console as below
77
* Delete the origin S3 bucket manually using the console

docs/test-records/cname-cloudfront.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# CNAME CloudFront
22
* Deploy [aws-cloudfront](https://github.com/celidor/aws-cloudfront) using Terraform
33
* This will create resources in CloudFront, S3, Certificate Manager and Route53
4-
* Route53 record is a CNAME pointing to the CloudFront distrubtion
4+
* Route53 record is a CNAME pointing to the CloudFront distribution
55
* Delete the origin S3 bucket manually using the console
66

77
![Alt text](images/cname-cloudfront.png?raw=true "CloudFront Distribution")

integration_tests/conftest.py

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import boto3
66
import pytest
7+
from moto import mock_cloudfront
78
from moto import mock_route53
89

910
from integration_tests.mocks.cloudflare_mock import CloudFlareMock
@@ -38,3 +39,10 @@ def aws_credentials():
3839
def moto_route53(aws_credentials):
3940
with mock_route53():
4041
yield boto3.client("route53", region_name="us-east-1")
42+
43+
44+
# pylint: disable=unused-argument
45+
@pytest.fixture(scope="function")
46+
def moto_cloudfront(aws_credentials):
47+
with mock_cloudfront():
48+
yield boto3.client("cloudfront", region_name="us-east-1")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
def setup_cloudfront_distribution_with_origin_url(moto_cloudfront, origin_domain_name, is_s3=True):
2+
# NOTE: All the fields below are required
3+
config = {
4+
"Origins": {
5+
"Quantity": 1,
6+
"Items": [
7+
{
8+
"Id": "MyOrigin",
9+
"DomainName": origin_domain_name,
10+
"S3OriginConfig": {
11+
"OriginAccessIdentity": "",
12+
},
13+
},
14+
],
15+
},
16+
"Enabled": True,
17+
"Comment": "test",
18+
"CallerReference": "test",
19+
"Aliases": {
20+
"Quantity": 2,
21+
"Items": [
22+
"vulnerable.domain-protect.com",
23+
"something.else.com",
24+
],
25+
},
26+
"DefaultCacheBehavior": {
27+
"AllowedMethods": {
28+
"Quantity": 2,
29+
"Items": ["GET", "HEAD"],
30+
"CachedMethods": {
31+
"Quantity": 2,
32+
"Items": ["GET", "HEAD"],
33+
},
34+
},
35+
"ViewerProtocolPolicy": "allow-all",
36+
"TargetOriginId": "MyOrigin",
37+
"ForwardedValues": {
38+
"QueryString": False,
39+
"Cookies": {
40+
"Forward": "none",
41+
},
42+
},
43+
},
44+
}
45+
if not is_s3:
46+
del config["Origins"]["Items"][0]["S3OriginConfig"]
47+
config["Origins"]["Items"][0]["CustomOriginConfig"] = {
48+
"HTTPPort": 80,
49+
"HTTPSPort": 443,
50+
"OriginProtocolPolicy": "http-only",
51+
}
52+
53+
distribution = moto_cloudfront.create_distribution(DistributionConfig=config)
54+
55+
# NOTE: From moto's documentation, this list_distributions() call is needed to "advance" the distribution to a deployed state
56+
distributions = moto_cloudfront.list_distributions()
57+
return distributions["DistributionList"]["Items"][0]
58+
59+
60+
def setup_hosted_zone_with_alias(moto_route53, target_dns_name):
61+
hosted_zone = moto_route53.create_hosted_zone(
62+
Name="domain-protect.com",
63+
CallerReference="123abc",
64+
HostedZoneConfig={"Comment": "", "PrivateZone": False},
65+
)
66+
moto_route53.change_resource_record_sets(
67+
HostedZoneId=hosted_zone["HostedZone"]["Id"],
68+
ChangeBatch={
69+
"Comment": "Create alias record set",
70+
"Changes": [
71+
{
72+
"Action": "CREATE",
73+
"ResourceRecordSet": {
74+
"Name": "vulnerable.domain-protect.com",
75+
"Type": "A",
76+
"AliasTarget": {
77+
"HostedZoneId": hosted_zone["HostedZone"]["Id"],
78+
"DNSName": target_dns_name,
79+
"EvaluateTargetHealth": False,
80+
},
81+
},
82+
},
83+
],
84+
},
85+
)
86+
87+
88+
def setup_hosted_zone_with_cname(moto_route53, target_dns_name):
89+
hosted_zone = moto_route53.create_hosted_zone(
90+
Name="domain-protect.com",
91+
CallerReference="123abc",
92+
HostedZoneConfig={"Comment": "", "PrivateZone": False},
93+
)
94+
moto_route53.change_resource_record_sets(
95+
HostedZoneId=hosted_zone["HostedZone"]["Id"],
96+
ChangeBatch={
97+
"Comment": "Create CNAME record set",
98+
"Changes": [
99+
{
100+
"Action": "CREATE",
101+
"ResourceRecordSet": {
102+
"Name": "vulnerable.domain-protect.com",
103+
"Type": "CNAME",
104+
"ResourceRecords": [
105+
{
106+
"Value": target_dns_name,
107+
},
108+
],
109+
},
110+
},
111+
],
112+
},
113+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
from unittest.mock import call
2+
from unittest.mock import patch
3+
4+
import requests
5+
from common import setup_cloudfront_distribution_with_origin_url
6+
from common import setup_hosted_zone_with_alias
7+
8+
from manual_scans.aws.aws_alias_cloudfront_s3 import main
9+
10+
11+
@patch("manual_scans.aws.aws_alias_cloudfront_s3.print_list")
12+
@patch("argparse.ArgumentParser")
13+
def test_main_detects_vulnerable_domains(arg_parse_mock, print_list_mock, moto_route53, moto_cloudfront, requests_mock):
14+
cloudfront = setup_cloudfront_distribution_with_origin_url(moto_cloudfront, "my-bucket.s3.us-east-1.amazonaws.com")
15+
setup_hosted_zone_with_alias(moto_route53, cloudfront["DomainName"])
16+
17+
requests_mock.get("https://vulnerable.domain-protect.com.", status_code=404, text="<Code>NotFound</Code>")
18+
requests_mock.get("https://my-bucket.s3.us-east-1.amazonaws.com", status_code=404, text="<Code>NoSuchBucket</Code>")
19+
20+
main()
21+
22+
print_list_mock.assert_has_calls(
23+
[
24+
call(["vulnerable.domain-protect.com."], "INSECURE_WS"),
25+
call([cloudfront["DomainName"]], "OUTPUT_WS"),
26+
],
27+
)
28+
29+
30+
@patch("manual_scans.aws.aws_alias_cloudfront_s3.print_list")
31+
@patch("argparse.ArgumentParser")
32+
def test_main_ignores_non_vulnerable_domains(
33+
arg_parse_mock,
34+
print_list_mock,
35+
moto_route53,
36+
moto_cloudfront,
37+
requests_mock,
38+
):
39+
cloudfront = setup_cloudfront_distribution_with_origin_url(moto_cloudfront, "my-bucket.s3.us-east-1.amazonaws.com")
40+
setup_hosted_zone_with_alias(moto_route53, cloudfront["DomainName"])
41+
42+
requests_mock.get("https://vulnerable.domain-protect.com.", status_code=200, text="All good here")
43+
44+
main()
45+
46+
print_list_mock.assert_not_called()
47+
48+
49+
@patch("manual_scans.aws.aws_alias_cloudfront_s3.print_list")
50+
@patch("argparse.ArgumentParser")
51+
def test_main_ignores_non_vulnerable_domains_2(
52+
arg_parse_mock,
53+
print_list_mock,
54+
moto_route53,
55+
moto_cloudfront,
56+
requests_mock,
57+
):
58+
cloudfront = setup_cloudfront_distribution_with_origin_url(moto_cloudfront, "my-bucket.s3.us-east-1.amazonaws.com")
59+
setup_hosted_zone_with_alias(moto_route53, cloudfront["DomainName"])
60+
61+
requests_mock.get("https://vulnerable.domain-protect.com.", status_code=404, text="<Code>NotFound</Code>")
62+
requests_mock.get("https://my-bucket.s3.us-east-1.amazonaws.com", status_code=200, text="All good there")
63+
main()
64+
65+
print_list_mock.assert_not_called()
66+
67+
68+
@patch("manual_scans.aws.aws_alias_cloudfront_s3.print_list")
69+
@patch("argparse.ArgumentParser")
70+
def test_main_ignores_domains_with_non_s3_origins(
71+
arg_parse_mock,
72+
print_list_mock,
73+
moto_route53,
74+
moto_cloudfront,
75+
requests_mock,
76+
):
77+
cloudfront = setup_cloudfront_distribution_with_origin_url(
78+
moto_cloudfront,
79+
"non-s3-origin.example.com",
80+
is_s3=False,
81+
)
82+
setup_hosted_zone_with_alias(moto_route53, cloudfront["DomainName"])
83+
84+
requests_mock.get("https://vulnerable.domain-protect.com.", status_code=404, text="<Code>NotFound</Code>")
85+
86+
main()
87+
88+
print_list_mock.assert_not_called()
89+
90+
91+
@patch("manual_scans.aws.aws_alias_cloudfront_s3.print_list")
92+
@patch("argparse.ArgumentParser")
93+
def test_main_no_cloudfront_distribution(arg_parse_mock, print_list_mock, moto_route53, moto_cloudfront, requests_mock):
94+
main()
95+
96+
print_list_mock.assert_not_called()
97+
# Implicitly, we also assert no exception is raised

0 commit comments

Comments
 (0)