Coverage for mcpgateway/utils/services_auth.py: 100%
33 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-22 15:47 +0100
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-22 15:47 +0100
1# -*- coding: utf-8 -*-
2"""
4Copyright 2025
5SPDX-License-Identifier: Apache-2.0
6Authors: Mihai Criveti
8"""
10import base64
11import hashlib
12import json
13import os
15from cryptography.hazmat.primitives.ciphers.aead import AESGCM
17from mcpgateway.config import settings
20def get_key() -> bytes:
21 """
22 Generate a 32-byte AES encryption key derived from a passphrase.
24 Returns:
25 bytes: A 32-byte encryption key.
27 Raises:
28 ValueError: If the passphrase is not set or empty.
29 """
30 passphrase = settings.auth_encryption_secret
31 if not passphrase:
32 raise ValueError("AUTH_ENCRPYPTION_SECRET not set in environment.")
33 return hashlib.sha256(passphrase.encode()).digest() # 32-byte key
36def encode_auth(auth_value: dict) -> str:
37 """
38 Encrypt and encode an authentication dictionary into a compact base64-url string.
40 Args:
41 auth_value (dict): The authentication dictionary to encrypt and encode.
43 Returns:
44 str: A base64-url-safe encrypted string representing the dictionary, or None if input is None.
45 """
46 if not auth_value:
47 return None
48 plaintext = json.dumps(auth_value)
49 key = get_key()
50 aesgcm = AESGCM(key)
51 nonce = os.urandom(12)
52 ciphertext = aesgcm.encrypt(nonce, plaintext.encode(), None)
53 combined = nonce + ciphertext
54 encoded = base64.urlsafe_b64encode(combined).rstrip(b"=")
55 return encoded.decode()
58def decode_auth(encoded_value: str) -> dict:
59 """
60 Decode and decrypt a base64-url-safe encrypted string back into the authentication dictionary.
62 Args:
63 encoded_value (str): The encrypted base64-url string to decode and decrypt.
65 Returns:
66 dict: The decrypted authentication dictionary, or empty dict if input is None.
67 """
68 if not encoded_value:
69 return {}
70 key = get_key()
71 aesgcm = AESGCM(key)
72 # Fix base64 padding
73 padded = encoded_value + "=" * (-len(encoded_value) % 4)
74 combined = base64.urlsafe_b64decode(padded)
75 nonce = combined[:12]
76 ciphertext = combined[12:]
77 plaintext = aesgcm.decrypt(nonce, ciphertext, None)
78 return json.loads(plaintext.decode())