Skip to content

Commit

Permalink
Reach 99% code coverage
Browse files Browse the repository at this point in the history
The only missing lines are those related to setting up clickhouse and
boto. We should eventually test these too inside of integration tests.
  • Loading branch information
hellais committed Mar 15, 2024
1 parent ce274ae commit 13fe76f
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 99 deletions.
7 changes: 6 additions & 1 deletion ooniapi/services/ooniauth/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,12 @@ check = "mypy --install-types --non-interactive {args:src/ooniauth tests}"
source_pkgs = ["ooniauth", "tests"]
branch = true
parallel = true
omit = ["src/ooniauth/__about__.py", "src/ooniauth/common/*"]
omit = [
"src/ooniauth/__about__.py",
"src/ooniauth/common/*",
# Ignored because these should be run manually on deployed instance
"tests/run_*",
]

[tool.coverage.paths]
ooniauth = ["src/ooniauth", "*/ooniauth/src/ooniauth"]
Expand Down
39 changes: 14 additions & 25 deletions ooniapi/services/ooniauth/src/ooniauth/routers/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,10 @@ class UserRegister(BaseModel):
min_length=5,
max_length=255,
)
redirect_to: Optional[str] = Field(title="redirect to this URL", default="")
redirect_to: str = Field(title="redirect to this URL")

@validator("redirect_to")
def validate_redirect_to(cls, v):
# None is also a valid type
if v is None:
return v

u = urlparse(v)
if u.scheme != "https":
raise ValueError("Invalid URL")
Expand All @@ -74,10 +70,7 @@ def validate_redirect_to(cls, v):
return v


def format_login_url(redirect_to: Optional[str], registration_token: str) -> str:
if redirect_to is None:
return ""

def format_login_url(redirect_to: str, registration_token: str) -> str:
login_fqdm = urlparse(redirect_to).netloc
e = urlencode(dict(token=registration_token))
return urlunsplit(("https", login_fqdm, "/login", e, ""))
Expand Down Expand Up @@ -152,11 +145,11 @@ async def user_login(
dec = decode_jwt(
token=token, key=settings.jwt_encryption_key, audience="register"
)
except jwt.exceptions.MissingRequiredClaimError:
raise HTTPException(401, "Invalid token")
except jwt.exceptions.InvalidSignatureError:
raise HTTPException(401, "Invalid credential signature")
except jwt.exceptions.DecodeError:
except (
jwt.exceptions.MissingRequiredClaimError,
jwt.exceptions.InvalidSignatureError,
jwt.exceptions.DecodeError,
):
raise HTTPException(401, "Invalid credentials")
except jwt.exceptions.ExpiredSignatureError:
raise HTTPException(401, "Expired token")
Expand Down Expand Up @@ -205,9 +198,8 @@ async def user_refresh_token(
authorization=authorization, jwt_encryption_key=settings.jwt_encryption_key
)

# @role_required already checked for expunged tokens
if not tok:
raise HTTPException(401, "Invalid credentials")
# @role_required already checked for validity of token
assert tok is not None

newtoken = create_session_token(
key=settings.jwt_encryption_key,
Expand Down Expand Up @@ -239,12 +231,9 @@ async def get_account_metadata(
schema:
type: object
"""
try:
tok = get_client_token(
authorization=authorization, jwt_encryption_key=settings.jwt_encryption_key
)
if not tok:
raise HTTPException(401, "Invalid credentials")
return AccountMetadata(logged_in=True, role=tok["role"])
except Exception:
tok = get_client_token(
authorization=authorization, jwt_encryption_key=settings.jwt_encryption_key
)
if not tok:
return AccountMetadata(logged_in=False, role="")
return AccountMetadata(logged_in=True, role=tok["role"])
96 changes: 70 additions & 26 deletions ooniapi/services/ooniauth/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ooniauth.common.config import Settings
from ooniauth.common.dependencies import get_settings
from ooniauth.dependencies import get_ses_client, get_clickhouse_client
from ooniauth.utils import hash_email_address
from ooniauth.main import app


Expand All @@ -29,6 +30,41 @@ def client_with_bad_settings():
yield client


@pytest.fixture
def user_email():
return "[email protected]"


@pytest.fixture
def admin_email():
return "[email protected]"


@pytest.fixture
def jwt_encryption_key():
return "super_secure"


@pytest.fixture
def prometheus_password():
return "super_secure"


@pytest.fixture
def account_id_hashing_key():
return "super_secure"


@pytest.fixture
def email_source_address():
return "[email protected]"


@pytest.fixture
def valid_redirect_to_url():
return "https://explorer.ooni.org"


@pytest.fixture
def mock_ses_client():
mock = MagicMock()
Expand All @@ -37,40 +73,48 @@ def mock_ses_client():


@pytest.fixture
def client(mock_ses_client):
def mock_misconfigured_ses_client():
mock = MagicMock()
mock.send_email.side_effect = Exception("failing to send an email")
app.dependency_overrides[get_ses_client] = lambda: mock
yield mock


@pytest.fixture
def client(
mock_ses_client,
admin_email,
jwt_encryption_key,
account_id_hashing_key,
prometheus_password,
email_source_address,
):
app.dependency_overrides[get_settings] = make_override_get_settings(
jwt_encryption_key="super_secure",
prometheus_metrics_password="super_secure",
email_source_address="[email protected]",
jwt_encryption_key=jwt_encryption_key,
prometheus_metrics_password=prometheus_password,
email_source_address=email_source_address,
account_id_hashing_key=account_id_hashing_key,
aws_access_key_id="ITSCHANGED",
aws_secret_access_key="ITSCHANGED",
)
mock_clickhouse = MagicMock()
mock_clickhouse.execute = MagicMock()

# rows, coldata = q
# coldata = [("name", "type")]
mock_clickhouse.execute.return_value = (
[("user",)],
[("role", "String")],
)
def mock_execute(query, query_params, with_column_types, settings):
assert with_column_types == True
print(settings)
assert query.startswith("SELECT role FROM")
if query_params["account_id"] == hash_email_address(
email_address=admin_email, key=account_id_hashing_key
):
return [("admin",)], [("role", "String")]

return [("user",)], [("role", "String")]

mock_clickhouse.execute = mock_execute
app.dependency_overrides[get_clickhouse_client] = lambda: mock_clickhouse

client = TestClient(app)
yield client


def create_jwt(payload: dict) -> str:
return jwt.encode(payload, "super_secure", algorithm="HS256")


def create_session_token(account_id: str, role: str) -> str:
now = int(time.time())
payload = {
"nbf": now,
"iat": now,
"exp": now + 10 * 86400,
"aud": "user_auth",
"account_id": account_id,
"login_time": None,
"role": role,
}
return create_jwt(payload)
Loading

0 comments on commit 13fe76f

Please sign in to comment.