feature/secrets-encryption-cleaning (#673)
* removed simple-crypt and cleaned up usage of keys for encryption w/ burnettk * renamed var to SPIFFWORKFLOW_BACKEND_ENCRYPTION_KEY w/ burnettk * pyl w/ burnettk --------- Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
parent
1eed6e2444
commit
fc503ec76b
File diff suppressed because it is too large
Load Diff
|
@ -27,7 +27,6 @@ flask-mail = "*"
|
|||
flask-marshmallow = "*"
|
||||
flask-migrate = "*"
|
||||
flask-restful = "*"
|
||||
flask-simple-crypt = "^0.3.3"
|
||||
SpiffWorkflow = {git = "https://github.com/sartography/SpiffWorkflow", rev = "main"}
|
||||
# SpiffWorkflow = {develop = true, path = "../../spiffworkflow/" }
|
||||
# SpiffWorkflow = {develop = true, path = "../../SpiffWorkflow/" }
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import base64
|
||||
import faulthandler
|
||||
import json
|
||||
import os
|
||||
|
@ -14,7 +13,6 @@ from apscheduler.schedulers.base import BaseScheduler # type: ignore
|
|||
from flask.json.provider import DefaultJSONProvider
|
||||
from flask_cors import CORS # type: ignore
|
||||
from flask_mail import Mail # type: ignore
|
||||
from flask_simple_crypt import SimpleCrypt # type: ignore
|
||||
from prometheus_flask_exporter import ConnexionPrometheusMetrics # type: ignore
|
||||
from werkzeug.exceptions import NotFound
|
||||
|
||||
|
@ -111,14 +109,6 @@ def should_start_scheduler(app: flask.app.Flask) -> bool:
|
|||
return True
|
||||
|
||||
|
||||
class NoOpCipher:
|
||||
def encrypt(self, value: str) -> bytes:
|
||||
return str.encode(value)
|
||||
|
||||
def decrypt(self, value: str) -> str:
|
||||
return value
|
||||
|
||||
|
||||
def create_app() -> flask.app.Flask:
|
||||
faulthandler.enable()
|
||||
|
||||
|
@ -161,25 +151,6 @@ def create_app() -> flask.app.Flask:
|
|||
|
||||
configure_sentry(app)
|
||||
|
||||
encryption_lib = app.config.get("SPIFFWORKFLOW_BACKEND_ENCRYPTION_LIB")
|
||||
if encryption_lib == "cryptography":
|
||||
from cryptography.fernet import Fernet
|
||||
|
||||
app_secret_key = app.config.get("SECRET_KEY")
|
||||
app_secret_key_bytes = app_secret_key.encode()
|
||||
base64_key = base64.b64encode(app_secret_key_bytes)
|
||||
fernet_cipher = Fernet(base64_key)
|
||||
app.config["CIPHER"] = fernet_cipher
|
||||
# for comparison against possibly-slow encryption libraries
|
||||
elif encryption_lib == "no_op_cipher":
|
||||
no_op_cipher = NoOpCipher()
|
||||
app.config["CIPHER"] = no_op_cipher
|
||||
else:
|
||||
simple_crypt_cipher = SimpleCrypt()
|
||||
app.config["FSC_EXPANSION_COUNT"] = 2048
|
||||
simple_crypt_cipher.init_app(app)
|
||||
app.config["CIPHER"] = simple_crypt_cipher
|
||||
|
||||
app.before_request(verify_token)
|
||||
app.before_request(AuthorizationService.check_for_permission)
|
||||
app.after_request(_set_new_access_token_in_cookie)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""__init__.py."""
|
||||
import base64
|
||||
import os
|
||||
import threading
|
||||
import uuid
|
||||
|
@ -11,12 +12,21 @@ from spiffworkflow_backend.services.logging_service import setup_logger
|
|||
|
||||
HTTP_REQUEST_TIMEOUT_SECONDS = 15
|
||||
CONNECTOR_PROXY_COMMAND_TIMEOUT = 45
|
||||
SUPPORTED_ENCRYPTION_LIBS = ["cryptography", "no_op_cipher"]
|
||||
|
||||
|
||||
class ConfigurationError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NoOpCipher:
|
||||
def encrypt(self, value: str) -> bytes:
|
||||
return str.encode(value)
|
||||
|
||||
def decrypt(self, value: str) -> str:
|
||||
return value
|
||||
|
||||
|
||||
def setup_database_configs(app: Flask) -> None:
|
||||
worker_id = os.environ.get("PYTEST_XDIST_WORKER")
|
||||
parallel_test_suffix = ""
|
||||
|
@ -134,6 +144,33 @@ def _check_for_incompatible_frontend_and_backend_urls(app: Flask) -> None:
|
|||
)
|
||||
|
||||
|
||||
def _setup_cipher(app: Flask) -> None:
|
||||
encryption_lib = app.config.get("SPIFFWORKFLOW_BACKEND_ENCRYPTION_LIB")
|
||||
if encryption_lib not in SUPPORTED_ENCRYPTION_LIBS:
|
||||
raise ConfigurationError(
|
||||
f"Received invalid encryption lib: {encryption_lib}. Supported libs are {SUPPORTED_ENCRYPTION_LIBS}"
|
||||
)
|
||||
|
||||
if encryption_lib == "cryptography":
|
||||
from cryptography.fernet import Fernet
|
||||
|
||||
app_secret_key = app.config.get("SPIFFWORKFLOW_BACKEND_ENCRYPTION_KEY")
|
||||
if app_secret_key is None:
|
||||
raise ConfigurationError(
|
||||
"SPIFFWORKFLOW_BACKEND_ENCRYPTION_KEY must be specified if using cryptography encryption lib"
|
||||
)
|
||||
|
||||
app_secret_key_bytes = app_secret_key.encode()
|
||||
base64_key = base64.b64encode(app_secret_key_bytes)
|
||||
fernet_cipher = Fernet(base64_key)
|
||||
app.config["CIPHER"] = fernet_cipher
|
||||
|
||||
# no_op_cipher for comparison against possibly-slow encryption libraries
|
||||
elif encryption_lib == "no_op_cipher":
|
||||
no_op_cipher = NoOpCipher()
|
||||
app.config["CIPHER"] = no_op_cipher
|
||||
|
||||
|
||||
def setup_config(app: Flask) -> None:
|
||||
# ensure the instance folder exists
|
||||
try:
|
||||
|
@ -211,3 +248,4 @@ def setup_config(app: Flask) -> None:
|
|||
_set_up_tenant_specific_fields_as_list_of_strings(app)
|
||||
_check_for_incompatible_frontend_and_backend_urls(app)
|
||||
_check_extension_api_configs(app)
|
||||
_setup_cipher(app)
|
||||
|
|
|
@ -162,6 +162,7 @@ config_from_env(
|
|||
"SPIFFWORKFLOW_BACKEND_ENCRYPTION_LIB",
|
||||
default="no_op_cipher",
|
||||
)
|
||||
config_from_env("SPIFFWORKFLOW_BACKEND_ENCRYPTION_KEY")
|
||||
|
||||
### locking
|
||||
# timeouts for process instances locks as they are run to avoid stale locks
|
||||
|
|
|
@ -3,7 +3,6 @@ import os
|
|||
from os import environ
|
||||
|
||||
TESTING = True
|
||||
SECRET_KEY = "the_secret_key" # noqa: S105, do not care about security when running unit tests
|
||||
SPIFFWORKFLOW_BACKEND_LOG_TO_FILE = environ.get("SPIFFWORKFLOW_BACKEND_LOG_TO_FILE", default="true") == "true"
|
||||
|
||||
SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = environ.get(
|
||||
|
|
|
@ -52,7 +52,8 @@ class UserModel(SpiffworkflowBaseDBModel):
|
|||
|
||||
:return: string
|
||||
"""
|
||||
secret_key = current_app.config.get("SECRET_KEY")
|
||||
# current_app.secret_key is the same as current_app.config['SECRET_KEY']
|
||||
secret_key = str(current_app.secret_key)
|
||||
if secret_key is None:
|
||||
raise KeyError("we need current_app.config to have a SECRET_KEY")
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@ class AuthenticationService:
|
|||
self, code: str, authentication_identifier: str, redirect_url: str = "/v1.0/login_return"
|
||||
) -> dict:
|
||||
backend_basic_auth_string = (
|
||||
f"{self.client_id(authentication_identifier)}:{self.secret_key(authentication_identifier)}"
|
||||
f"{self.client_id(authentication_identifier)}:{self.__class__.secret_key(authentication_identifier)}"
|
||||
)
|
||||
backend_basic_auth_bytes = bytes(backend_basic_auth_string, encoding="ascii")
|
||||
backend_basic_auth = base64.b64encode(backend_basic_auth_bytes)
|
||||
|
@ -300,10 +300,7 @@ class AuthenticationService:
|
|||
|
||||
@staticmethod
|
||||
def decode_auth_token(auth_token: str) -> dict[str, str | None]:
|
||||
secret_key = current_app.config.get("SECRET_KEY")
|
||||
if secret_key is None:
|
||||
raise KeyError("we need current_app.config to have a SECRET_KEY")
|
||||
|
||||
"""This is only used for debugging."""
|
||||
try:
|
||||
payload: dict[str, str | None] = jwt.decode(auth_token, options={"verify_signature": False})
|
||||
return payload
|
||||
|
|
Loading…
Reference in New Issue