dc6079821b
Docs Tests / Check for file changes (push) Has been cancelled
Docs Tests / Test Documentation (push) Has been cancelled
Docs Tests / Documentation Linting Checks (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.9) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.9) (push) Has been cancelled
Continuous Integration / Check for file changes (push) Has been cancelled
Continuous Integration / Wait for docs tests (push) Has been cancelled
Continuous Integration / Code Quality (push) Has been cancelled
Continuous Integration / Check for changelog (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Upload coverage reports to codeclimate (push) Has been cancelled
Continuous Integration / Run Non-Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Run Broker Integration Tests (push) Has been cancelled
Continuous Integration / Run Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Build Docker base images and setup environment (push) Has been cancelled
Continuous Integration / Build Docker (default) (push) Has been cancelled
Continuous Integration / Build Docker (full) (push) Has been cancelled
Continuous Integration / Build Docker (mitie-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-de) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-it) (push) Has been cancelled
Continuous Integration / Deploy to PyPI (push) Has been cancelled
Continuous Integration / Notify Slack & Publish Release Notes (push) Has been cancelled
Publish Documentation / Evaluate release tag (push) Has been cancelled
Publish Documentation / Prebuild Docs (push) Has been cancelled
Publish Documentation / Preview Docs (push) Has been cancelled
Publish Documentation / Check for file changes (push) Has been cancelled
Publish Documentation / Publish Docs (push) Has been cancelled
Automatic PR Merger / mergepal (push) Has been cancelled
CI Github Actions / Run Tests (push) Has been cancelled
Semgrep / Semgrep Workflow Security Scan (push) Has been cancelled
152 lines
5.0 KiB
Python
152 lines
5.0 KiB
Python
import json
|
|
import time
|
|
from http import HTTPStatus
|
|
from unittest import mock
|
|
from unittest.mock import Mock
|
|
|
|
import freezegun
|
|
import jwt
|
|
import pytest
|
|
from _pytest.logging import LogCaptureFixture
|
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
|
|
from jwt.algorithms import RSAAlgorithm
|
|
|
|
from rasa.core.channels import BotFrameworkInput
|
|
|
|
DAY_IN_SECONDS = 60 * 60 * 24
|
|
|
|
MS_OPENID_CONFIG_RESPONSE = {
|
|
"issuer": "https://api.botframework.com",
|
|
"authorization_endpoint": "https://invalid.botframework.com",
|
|
"jwks_uri": "https://login.botframework.com/v1/.well-known/keys",
|
|
"id_token_signing_alg_values_supported": ["RS256"],
|
|
"token_endpoint_auth_methods_supported": ["private_key_jwt"],
|
|
}
|
|
|
|
|
|
@pytest.fixture(scope="function")
|
|
def rsa_private_key() -> RSAPrivateKey:
|
|
return rsa.generate_private_key(
|
|
public_exponent=65537,
|
|
key_size=2048,
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="function")
|
|
@mock.patch("requests.get")
|
|
def bot_framework_input(mock_requests: Mock, rsa_private_key: RSAPrivateKey):
|
|
jwk = json.loads(RSAAlgorithm.to_jwk(rsa_private_key.public_key()))
|
|
jwk["kid"] = "key_id"
|
|
|
|
openid_config_mock_response = mock.Mock()
|
|
openid_config_mock_response.raise_for_status = mock.Mock()
|
|
openid_config_mock_response.json.return_value = MS_OPENID_CONFIG_RESPONSE
|
|
|
|
openid_keys_mock_response = mock.Mock()
|
|
openid_keys_mock_response.raise_for_status = mock.Mock()
|
|
openid_keys_mock_response.json.return_value = {"keys": [jwk]}
|
|
|
|
mock_requests.side_effect = [openid_config_mock_response, openid_keys_mock_response]
|
|
|
|
return BotFrameworkInput("app_id", "app_password")
|
|
|
|
|
|
def test_successful_jwt_signature_verification(
|
|
bot_framework_input: BotFrameworkInput,
|
|
rsa_private_key: RSAPrivateKey,
|
|
):
|
|
encoded = jwt.encode(
|
|
{
|
|
"serviceurl": "https://webchat.botframework.com/",
|
|
"nbf": int(time.time()),
|
|
"exp": int(time.time()) + DAY_IN_SECONDS,
|
|
"iss": "https://api.botframework.com",
|
|
"aud": "app_id",
|
|
},
|
|
rsa_private_key,
|
|
algorithm="RS256",
|
|
headers={"kid": "key_id", "alg": "RS256"},
|
|
)
|
|
|
|
with pytest.warns(None):
|
|
resp = bot_framework_input._validate_auth(f"Bearer {encoded}")
|
|
assert resp is None
|
|
|
|
|
|
@mock.patch("requests.get")
|
|
def test_jwk_is_updated_daily(mock_requests: Mock):
|
|
with freezegun.freeze_time("2012-01-14 08:00:00"):
|
|
bot_framework_input = BotFrameworkInput("app_id", "app_password")
|
|
# Two calls at the beginning - on to retrieve open ID metadata,
|
|
# the second one to actually get the keys.
|
|
assert mock_requests.call_count == 2
|
|
|
|
bot_framework_input._validate_auth("Bearer token_invalid")
|
|
assert mock_requests.call_count == 2
|
|
|
|
with freezegun.freeze_time("2012-01-14 11:00:00"):
|
|
bot_framework_input._validate_auth("Bearer token_invalid")
|
|
assert mock_requests.call_count == 2
|
|
|
|
with freezegun.freeze_time("2012-01-15 11:00:00"):
|
|
bot_framework_input._validate_auth("Bearer token_invalid")
|
|
assert mock_requests.call_count == 4
|
|
|
|
|
|
def test_validate_auth_returns_unauthorized_for_invalid_jwt_token(
|
|
bot_framework_input: BotFrameworkInput,
|
|
rsa_private_key: RSAPrivateKey,
|
|
caplog: LogCaptureFixture,
|
|
):
|
|
encoded = jwt.encode(
|
|
{
|
|
"serviceurl": "https://webchat.botframework.com/",
|
|
"nbf": int(time.time()) + DAY_IN_SECONDS,
|
|
"exp": int(time.time()) + 2 * DAY_IN_SECONDS,
|
|
"iss": "https://api.botframework.com",
|
|
"aud": "app_id",
|
|
},
|
|
rsa_private_key,
|
|
algorithm="RS256",
|
|
headers={"kid": "key_id", "alg": "RS256"},
|
|
)
|
|
|
|
resp = bot_framework_input._validate_auth(f"Bearer {encoded}")
|
|
|
|
assert resp is not None
|
|
assert resp.status == HTTPStatus.UNAUTHORIZED
|
|
assert resp.body.decode() == "Could not validate JWT token."
|
|
assert [msg for msg in caplog.messages] == [
|
|
"Bot framework JWT token could not be verified.",
|
|
"The token is not yet valid (nbf)",
|
|
]
|
|
|
|
|
|
def test_validate_auth_returns_unauthorized_for_absent_header(
|
|
bot_framework_input: BotFrameworkInput,
|
|
caplog: LogCaptureFixture,
|
|
):
|
|
resp = bot_framework_input._validate_auth(None)
|
|
assert resp is not None
|
|
assert resp.status == HTTPStatus.UNAUTHORIZED
|
|
assert resp.body.decode() == "No authorization header provided."
|
|
|
|
|
|
def test_validate_auth_returns_unauthorized_for_non_bearer_header(
|
|
bot_framework_input: BotFrameworkInput,
|
|
):
|
|
resp = bot_framework_input._validate_auth("Basic dXNlcm5hbWU6cGFzc3dvcmQ=")
|
|
assert resp is not None
|
|
assert resp.status == HTTPStatus.UNAUTHORIZED
|
|
assert resp.body.decode() == "No Bearer token provided in Authorization header."
|
|
|
|
|
|
def test_validate_auth_returns_bad_request_for_invalid_header(
|
|
bot_framework_input: BotFrameworkInput,
|
|
):
|
|
resp = bot_framework_input._validate_auth("Bearer invalid")
|
|
assert resp is not None
|
|
assert resp.status == HTTPStatus.UNAUTHORIZED
|
|
assert resp.body.decode() == "Could not validate JWT token."
|