Coverage for oracle / oci_fsdr_mcp_server / auth.py: 100.00%
30 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-08-03 16:45 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-08-03 16:45 +0000
1"""
2Copyright (c) 2025, Oracle and/or its affiliates.
3Licensed under the Universal Permissive License v1.0 as shown at
4https://oss.oracle.com/licenses/upl.
6OCI client factory supporting API key and session token authentication.
8Authentication is controlled by the OCI_AUTH_TYPE environment variable:
9 - "api_key" (default): standard OCI config file credentials
10 - "security_token": OCI CLI session token (for interactive/cloud-shell sessions)
11"""
13from __future__ import annotations
15import os
16from typing import Dict
18import oci
20from . import __project__, __version__
21from .consts import DEFAULT_OCI_AUTH_TYPE, DEFAULT_OCI_CONFIG_FILE
23_user_agent_name = __project__.split("oracle.", 1)[1].split("-server", 1)[0]
24_ADDITIONAL_UA = f"{_user_agent_name}/{__version__}"
26_client_cache: Dict[str, oci.disaster_recovery.DisasterRecoveryClient] = {}
29def get_dr_client(profile: str) -> oci.disaster_recovery.DisasterRecoveryClient:
30 """Return a cached DisasterRecoveryClient for the given OCI config profile.
32 Created lazily on first use to avoid any stdout writes before the MCP
33 stdio transport is active.
34 """
35 if profile not in _client_cache:
36 _client_cache[profile] = _make_client(profile)
37 return _client_cache[profile]
40def _make_client(profile: str) -> oci.disaster_recovery.DisasterRecoveryClient:
41 if DEFAULT_OCI_AUTH_TYPE == "security_token":
42 return _make_security_token_client(profile)
43 return _make_api_key_client(profile)
46def _make_api_key_client(profile: str) -> oci.disaster_recovery.DisasterRecoveryClient:
47 """Standard OCI config file / API key authentication."""
48 config = oci.config.from_file(
49 file_location=DEFAULT_OCI_CONFIG_FILE, profile_name=profile
50 )
51 oci.config.validate_config(config)
52 config["additional_user_agent"] = _ADDITIONAL_UA
53 return oci.disaster_recovery.DisasterRecoveryClient(config)
56def _make_security_token_client(profile: str) -> oci.disaster_recovery.DisasterRecoveryClient:
57 """OCI CLI session token authentication (security_token auth type).
59 Reads the token file path and private key from the OCI config profile.
60 Falls back to environment variables OCI_SECURITY_TOKEN_FILE and OCI_KEY_FILE.
61 """
62 config = oci.config.from_file(
63 file_location=DEFAULT_OCI_CONFIG_FILE, profile_name=profile
64 )
66 token_file = os.path.expanduser(
67 config.get("security_token_file")
68 or os.getenv("OCI_SECURITY_TOKEN_FILE", "~/.oci/token")
69 )
70 key_file = os.path.expanduser(
71 config.get("key_file")
72 or os.getenv("OCI_KEY_FILE", "~/.oci/oci_api_key.pem")
73 )
75 with open(token_file, encoding="utf-8") as f:
76 token = f.read().strip()
78 signer = oci.auth.signers.SecurityTokenSigner(
79 token=token,
80 private_key_file_location=key_file,
81 )
82 return oci.disaster_recovery.DisasterRecoveryClient(
83 config={"additional_user_agent": _ADDITIONAL_UA}, signer=signer
84 )