Entra backend resolves OAuth tokens via MSAL client_credentials (OBO flow wired in future sprint) and passes ACs through for Bascule. Kerberos stubbed pending hybrid environment config. Stub backend for dev/testing without real IdP. Signed-off-by: Tyler King <tking@guildhouse.dev>
84 lines
2.6 KiB
Python
84 lines
2.6 KiB
Python
# Copyright 2026 Guildhouse Dev
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
"""Stub credential backend for development and testing.
|
|
|
|
Returns valid-looking credentials with short TTLs. NEVER use in
|
|
production — these credentials grant no actual access.
|
|
|
|
Useful for:
|
|
- Running the connector framework locally without Entra/Vault
|
|
- Integration tests that verify the credential lifecycle
|
|
(acquire → use → discard) without real secrets infrastructure
|
|
- Verifying that transports handle credential types correctly
|
|
"""
|
|
|
|
import logging
|
|
from datetime import datetime, timedelta, UTC
|
|
|
|
from gsap_broker.credentials.resolver import (
|
|
BasculeCredential,
|
|
Credential,
|
|
CredentialBackend,
|
|
KerberosCredential,
|
|
OAuthCredential,
|
|
SSHCertCredential,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class StubCredentialBackend(CredentialBackend):
|
|
"""Development/testing backend that returns mock credentials."""
|
|
|
|
@property
|
|
def supported_types(self) -> list[str]:
|
|
return ["bascule_ac", "kerberos", "oauth", "ssh_cert"]
|
|
|
|
async def resolve(
|
|
self,
|
|
credential_type: str,
|
|
target: str,
|
|
ac_context: dict,
|
|
) -> Credential:
|
|
expires_at = datetime.now(UTC) + timedelta(minutes=5)
|
|
scoped_to = ac_context.get("accord", {}).get("template", "stub")
|
|
|
|
if credential_type == "bascule_ac":
|
|
return BasculeCredential(
|
|
target=target,
|
|
expires_at=expires_at,
|
|
scoped_to=scoped_to,
|
|
authorization_context=ac_context,
|
|
)
|
|
|
|
if credential_type == "kerberos":
|
|
return KerberosCredential(
|
|
target=target,
|
|
expires_at=expires_at,
|
|
scoped_to=scoped_to,
|
|
ticket=b"STUB_TICKET",
|
|
)
|
|
|
|
if credential_type == "oauth":
|
|
return OAuthCredential(
|
|
target=target,
|
|
expires_at=expires_at,
|
|
scoped_to=scoped_to,
|
|
access_token="stub-access-token",
|
|
)
|
|
|
|
if credential_type == "ssh_cert":
|
|
return SSHCertCredential(
|
|
target=target,
|
|
expires_at=expires_at,
|
|
scoped_to=scoped_to,
|
|
certificate="stub-cert",
|
|
private_key="stub-key",
|
|
)
|
|
|
|
# Should not happen if supported_types is checked first
|
|
raise ValueError(f"StubBackend: unsupported type '{credential_type}'")
|
|
|
|
async def revoke(self, credential: Credential) -> None:
|
|
logger.debug("Stub revoke: %s for %s (no-op)", credential.credential_type, credential.target)
|