mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-10-05 22:05:50 +01:00
Try and fix OIDC (#1127)
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
"""Tests for the OIDC Test Connection handler."""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from shelfmark.config.security_handlers import check_oidc_connection
|
||||
|
||||
DISCOVERY_URL = "https://auth.example.com/.well-known/openid-configuration"
|
||||
|
||||
DISCOVERY_DOCUMENT = {
|
||||
"issuer": "https://auth.example.com",
|
||||
"authorization_endpoint": "https://auth.example.com/authorize",
|
||||
"token_endpoint": "https://auth.example.com/token",
|
||||
"jwks_uri": "https://auth.example.com/jwks",
|
||||
}
|
||||
|
||||
|
||||
def _mock_response(payload):
|
||||
response = MagicMock()
|
||||
response.json.return_value = payload
|
||||
response.raise_for_status.return_value = None
|
||||
return response
|
||||
|
||||
|
||||
def _run_check(responses):
|
||||
"""Run check_oidc_connection with requests.get returning the given responses."""
|
||||
with (
|
||||
patch("requests.get", side_effect=responses) as mock_get,
|
||||
patch("shelfmark.config.security_handlers.get_ssl_verify", return_value=True),
|
||||
):
|
||||
result = check_oidc_connection(
|
||||
load_security_config=lambda: {"OIDC_DISCOVERY_URL": DISCOVERY_URL},
|
||||
current_values={},
|
||||
logger=MagicMock(),
|
||||
)
|
||||
return result, mock_get
|
||||
|
||||
|
||||
class TestCheckOIDCConnection:
|
||||
def test_succeeds_when_discovery_and_jwks_are_valid(self):
|
||||
responses = [
|
||||
_mock_response(DISCOVERY_DOCUMENT),
|
||||
_mock_response({"keys": [{"kty": "RSA", "kid": "abc"}]}),
|
||||
]
|
||||
result, mock_get = _run_check(responses)
|
||||
assert result["success"] is True
|
||||
assert "Connected to" in result["message"]
|
||||
jwks_call = mock_get.call_args_list[1]
|
||||
assert jwks_call.args[0] == DISCOVERY_DOCUMENT["jwks_uri"]
|
||||
|
||||
def test_fails_with_signing_key_guidance_when_jwks_is_empty(self):
|
||||
responses = [
|
||||
_mock_response(DISCOVERY_DOCUMENT),
|
||||
_mock_response({}),
|
||||
]
|
||||
result, _ = _run_check(responses)
|
||||
assert result["success"] is False
|
||||
assert "no token signing keys" in result["message"]
|
||||
assert "Signing Key" in result["message"]
|
||||
|
||||
def test_fails_with_signing_key_guidance_when_jwks_keys_list_is_empty(self):
|
||||
responses = [
|
||||
_mock_response(DISCOVERY_DOCUMENT),
|
||||
_mock_response({"keys": []}),
|
||||
]
|
||||
result, _ = _run_check(responses)
|
||||
assert result["success"] is False
|
||||
assert "no token signing keys" in result["message"]
|
||||
|
||||
def test_fails_when_discovery_document_missing_jwks_uri(self):
|
||||
document = {k: v for k, v in DISCOVERY_DOCUMENT.items() if k != "jwks_uri"}
|
||||
responses = [_mock_response(document)]
|
||||
result, _ = _run_check(responses)
|
||||
assert result["success"] is False
|
||||
assert "jwks_uri" in result["message"]
|
||||
|
||||
def test_fails_when_jwks_request_errors(self):
|
||||
jwks_response = MagicMock()
|
||||
jwks_response.raise_for_status.side_effect = RuntimeError("boom")
|
||||
responses = [_mock_response(DISCOVERY_DOCUMENT), jwks_response]
|
||||
result, _ = _run_check(responses)
|
||||
assert result["success"] is False
|
||||
assert "Connection failed" in result["message"]
|
||||
@@ -413,6 +413,43 @@ class TestOIDCCallbackEndpoint:
|
||||
assert error is not None
|
||||
assert "issuer validation failed" in error
|
||||
|
||||
@patch("shelfmark.core.oidc_routes._get_oidc_client")
|
||||
def test_callback_redirects_with_signing_key_guidance_on_empty_jwks(
|
||||
self, mock_get_client, client
|
||||
):
|
||||
fake_client = Mock()
|
||||
fake_client.authorize_access_token.side_effect = KeyError("keys")
|
||||
fake_client.fetch_jwk_set.return_value = {}
|
||||
mock_get_client.return_value = (fake_client, MOCK_OIDC_CONFIG)
|
||||
|
||||
resp = client.get("/api/auth/oidc/callback?code=abc123&state=test-state")
|
||||
error = _get_oidc_error(resp)
|
||||
assert error is not None
|
||||
assert "no token signing keys" in error
|
||||
assert "Signing Key" in error
|
||||
|
||||
@patch("shelfmark.core.oidc_routes._get_oidc_client")
|
||||
def test_callback_uses_generic_error_when_jwks_has_keys(self, mock_get_client, client):
|
||||
fake_client = Mock()
|
||||
fake_client.authorize_access_token.side_effect = KeyError("keys")
|
||||
fake_client.fetch_jwk_set.return_value = {"keys": [{"kty": "RSA", "kid": "abc"}]}
|
||||
mock_get_client.return_value = (fake_client, MOCK_OIDC_CONFIG)
|
||||
|
||||
resp = client.get("/api/auth/oidc/callback?code=abc123&state=test-state")
|
||||
error = _get_oidc_error(resp)
|
||||
assert error == "Authentication failed"
|
||||
|
||||
@patch("shelfmark.core.oidc_routes._get_oidc_client")
|
||||
def test_callback_uses_generic_error_when_jwks_diagnosis_fails(self, mock_get_client, client):
|
||||
fake_client = Mock()
|
||||
fake_client.authorize_access_token.side_effect = KeyError("keys")
|
||||
fake_client.fetch_jwk_set.side_effect = RuntimeError("jwks fetch failed")
|
||||
mock_get_client.return_value = (fake_client, MOCK_OIDC_CONFIG)
|
||||
|
||||
resp = client.get("/api/auth/oidc/callback?code=abc123&state=test-state")
|
||||
error = _get_oidc_error(resp)
|
||||
assert error == "Authentication failed"
|
||||
|
||||
@patch("shelfmark.core.oidc_routes._get_oidc_client")
|
||||
def test_callback_redirects_when_auto_provision_disabled_and_no_email_match(
|
||||
self, mock_get_client, client
|
||||
|
||||
Reference in New Issue
Block a user