Skip to content

Commit 5add0f8

Browse files
authored
Merge pull request #2895 from fractal-analytics-platform/2891-remove-email-password-encryption
Remove email-password encryption
2 parents 83e170c + 6eef546 commit 5add0f8

File tree

7 files changed

+15
-128
lines changed

7 files changed

+15
-128
lines changed

.github/workflows/oauth.yaml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,7 @@ jobs:
7474
FRACTAL_EMAIL_RECIPIENTS: [email protected],[email protected]
7575
FRACTAL_EMAIL_USE_STARTTLS: false
7676
FRACTAL_EMAIL_USE_LOGIN: true
77-
# FRACTAL_EMAIL_PASSWORD and FRACTAL_EMAIL_PASSWORD_KET are generated with the following command
78-
# `printf "fakepassword\n" | poetry run fractalctl encrypt-email-password`
79-
FRACTAL_EMAIL_PASSWORD: gAAAAABnoQUGHMsDgLkpDtwUtrKtf9T1so44ahEXExGRceAnf097mVY1EbNuMP5fjvkndvwCwBJM7lHoSgKQkZ4VbvO9t3PJZg==
80-
FRACTAL_EMAIL_PASSWORD_KEY: lp3j2FVDkzLd0Rklnzg1pHuV9ClCuDE0aGeJfTNCaW4=
77+
FRACTAL_EMAIL_PASSWORD: fakepassword
8178
run: |
8279
fractalctl set-db
8380
fractalctl init-db-data --resource default --profile default --admin-email [email protected] --admin-pwd 1234

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ TBD
1111
\#2882
1212
\#2884
1313
\#2893
14+
\#2895 (remove email-password encryption)
15+
1416

1517
# 2.16.6
1618

fractal_server/__main__.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,6 @@
9090
description="Apply data-migration script to an existing database.",
9191
)
9292

93-
# fractalctl encrypt-email-password
94-
encrypt_email_password_parser = subparsers.add_parser(
95-
"encrypt-email-password",
96-
description=(
97-
"Generate valid values for environment variables "
98-
"FRACTAL_EMAIL_PASSWORD and FRACTAL_EMAIL_PASSWORD_KEY."
99-
),
100-
)
101-
10293

10394
def save_openapi(dest="openapi.json"):
10495
from fractal_server.main import start_application
@@ -325,17 +316,6 @@ def _slugify_version(raw_version: str) -> str:
325316
current_update_db_data_module.fix_db()
326317

327318

328-
def print_encrypted_password():
329-
from cryptography.fernet import Fernet
330-
331-
password = input("Insert email password: ").encode("utf-8")
332-
key = Fernet.generate_key().decode("utf-8")
333-
encrypted_password = Fernet(key).encrypt(password).decode("utf-8")
334-
335-
print(f"\nFRACTAL_EMAIL_PASSWORD={encrypted_password}")
336-
print(f"FRACTAL_EMAIL_PASSWORD_KEY={key}")
337-
338-
339319
def run():
340320
args = parser.parse_args(sys.argv[1:])
341321

@@ -359,8 +339,6 @@ def run():
359339
port=args.port,
360340
reload=args.reload,
361341
)
362-
elif args.cmd == "encrypt-email-password":
363-
print_encrypted_password()
364342
else:
365343
sys.exit(f"Error: invalid command '{args.cmd}'.")
366344

fractal_server/app/security/signup_email.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
from email.message import EmailMessage
33
from email.utils import formataddr
44

5-
from cryptography.fernet import Fernet
6-
75
from fractal_server.config import PublicEmailSettings
86

97

@@ -35,11 +33,7 @@ def mail_new_oauth_signup(msg: str, email_settings: PublicEmailSettings):
3533
server.starttls()
3634
server.ehlo()
3735
if email_settings.use_login:
38-
password = (
39-
Fernet(email_settings.encryption_key.get_secret_value())
40-
.decrypt(email_settings.encrypted_password.get_secret_value())
41-
.decode("utf-8")
42-
)
36+
password = email_settings.password.get_secret_value()
4337
server.login(user=email_settings.sender, password=password)
4438
server.sendmail(
4539
from_addr=email_settings.sender,

fractal_server/config/_email.py

Lines changed: 8 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from typing import Literal
22

3-
from cryptography.fernet import Fernet
43
from pydantic import BaseModel
54
from pydantic import EmailStr
65
from pydantic import Field
@@ -31,8 +30,7 @@ class PublicEmailSettings(BaseModel):
3130
recipients: list[EmailStr] = Field(min_length=1)
3231
smtp_server: str
3332
port: int
34-
encrypted_password: SecretStr | None = None
35-
encryption_key: SecretStr | None = None
33+
password: SecretStr | None = None
3634
instance_name: str
3735
use_starttls: bool
3836
use_login: bool
@@ -53,10 +51,6 @@ class EmailSettings(BaseSettings):
5351
"""
5452
Password for the OAuth-signup email sender.
5553
"""
56-
FRACTAL_EMAIL_PASSWORD_KEY: SecretStr | None = None
57-
"""
58-
Key value for `cryptography.fernet` decrypt
59-
"""
6054
FRACTAL_EMAIL_SMTP_SERVER: str | None = None
6155
"""
6256
SMTP server for the OAuth-signup emails.
@@ -81,8 +75,7 @@ class EmailSettings(BaseSettings):
8175
FRACTAL_EMAIL_USE_LOGIN: Literal["true", "false"] = "true"
8276
"""
8377
Whether to use login when using the SMTP server.
84-
If 'true', FRACTAL_EMAIL_PASSWORD and FRACTAL_EMAIL_PASSWORD_KEY must be
85-
provided.
78+
If 'true', FRACTAL_EMAIL_PASSWORD must be provided.
8679
Accepted values: 'true', 'false'.
8780
"""
8881

@@ -119,49 +112,18 @@ def validate_email_settings(self):
119112
use_starttls = self.FRACTAL_EMAIL_USE_STARTTLS == "true"
120113
use_login = self.FRACTAL_EMAIL_USE_LOGIN == "true"
121114

122-
if use_login:
123-
if self.FRACTAL_EMAIL_PASSWORD is None:
124-
raise ValueError(
125-
"'FRACTAL_EMAIL_USE_LOGIN' is 'true' but "
126-
"'FRACTAL_EMAIL_PASSWORD' is not provided."
127-
)
128-
if self.FRACTAL_EMAIL_PASSWORD_KEY is None:
129-
raise ValueError(
130-
"'FRACTAL_EMAIL_USE_LOGIN' is 'true' but "
131-
"'FRACTAL_EMAIL_PASSWORD_KEY' is not provided."
132-
)
133-
try:
134-
(
135-
Fernet(
136-
self.FRACTAL_EMAIL_PASSWORD_KEY.get_secret_value()
137-
)
138-
.decrypt(
139-
self.FRACTAL_EMAIL_PASSWORD.get_secret_value()
140-
)
141-
.decode("utf-8")
142-
)
143-
except Exception as e:
144-
raise ValueError(
145-
"Invalid pair (FRACTAL_EMAIL_PASSWORD, "
146-
"FRACTAL_EMAIL_PASSWORD_KEY). "
147-
f"Original error: {str(e)}."
148-
)
149-
password = self.FRACTAL_EMAIL_PASSWORD.get_secret_value()
150-
else:
151-
password = None
152-
153-
if self.FRACTAL_EMAIL_PASSWORD_KEY is not None:
154-
key = self.FRACTAL_EMAIL_PASSWORD_KEY.get_secret_value()
155-
else:
156-
key = None
115+
if use_login and self.FRACTAL_EMAIL_PASSWORD is None:
116+
raise ValueError(
117+
"'FRACTAL_EMAIL_USE_LOGIN' is 'true' but "
118+
"'FRACTAL_EMAIL_PASSWORD' is not provided."
119+
)
157120

158121
self.public = PublicEmailSettings(
159122
sender=self.FRACTAL_EMAIL_SENDER,
160123
recipients=self.FRACTAL_EMAIL_RECIPIENTS.split(","),
161124
smtp_server=self.FRACTAL_EMAIL_SMTP_SERVER,
162125
port=self.FRACTAL_EMAIL_SMTP_PORT,
163-
encrypted_password=password,
164-
encryption_key=key,
126+
password=self.FRACTAL_EMAIL_PASSWORD,
165127
instance_name=self.FRACTAL_EMAIL_INSTANCE_NAME,
166128
use_starttls=use_starttls,
167129
use_login=use_login,

tests/no_version/test_commands.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,3 @@ def test_email_settings():
5656
)
5757
assert not res.stdout
5858
assert "usage" in res.stderr
59-
60-
cmd = (
61-
'printf "mypassword\n" | poetry run fractalctl encrypt-email-password'
62-
)
63-
res = subprocess.run(
64-
cmd,
65-
encoding="utf-8",
66-
capture_output=True,
67-
shell=True,
68-
)
69-
assert "FRACTAL_EMAIL_PASSWORD" in res.stdout
70-
assert "FRACTAL_EMAIL_PASSWORD_KEY" in res.stdout
71-
assert not res.stderr

tests/no_version/test_unit_config.py

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,6 @@ def test_get_oauth_router(override_oauth_settings_factory):
161161

162162

163163
def test_email_settings():
164-
from cryptography.fernet import Fernet
165-
166-
password = "password"
167-
FRACTAL_EMAIL_PASSWORD_KEY = Fernet.generate_key().decode("utf-8")
168-
FRACTAL_EMAIL_PASSWORD = (
169-
Fernet(FRACTAL_EMAIL_PASSWORD_KEY)
170-
.encrypt(password.encode("utf-8"))
171-
.decode("utf-8")
172-
)
173-
174164
required_mail_args = dict(
175165
FRACTAL_EMAIL_SENDER="[email protected]",
176166
FRACTAL_EMAIL_SMTP_SERVER="smtp_server",
@@ -186,23 +176,13 @@ def test_email_settings():
186176
EmailSettings(
187177
**required_mail_args,
188178
)
189-
# 3a: missing password
190-
with pytest.raises(ValidationError):
191-
EmailSettings(
192-
**required_mail_args,
193-
FRACTAL_EMAIL_PASSWORD_KEY=FRACTAL_EMAIL_PASSWORD_KEY,
194-
)
195-
# 3b missing password key
179+
# 3: missing password
196180
with pytest.raises(ValidationError):
197-
EmailSettings(
198-
**required_mail_args,
199-
FRACTAL_EMAIL_PASSWORD=FRACTAL_EMAIL_PASSWORD,
200-
)
181+
EmailSettings(**required_mail_args)
201182
# 4: ok
202183
email_settings = EmailSettings(
203184
**required_mail_args,
204-
FRACTAL_EMAIL_PASSWORD=FRACTAL_EMAIL_PASSWORD,
205-
FRACTAL_EMAIL_PASSWORD_KEY=FRACTAL_EMAIL_PASSWORD_KEY,
185+
FRACTAL_EMAIL_PASSWORD="password",
206186
)
207187
assert email_settings.public is not None
208188
assert len(email_settings.public.recipients) == 2
@@ -222,19 +202,6 @@ def test_email_settings():
222202
**{k: v for k, v in required_mail_args.items() if k != arg},
223203
FRACTAL_EMAIL_USE_LOGIN="false",
224204
)
225-
# 7a: fail with Fernet encryption
226-
with pytest.raises(ValidationError, match="FRACTAL_EMAIL_PASSWORD"):
227-
EmailSettings(
228-
**required_mail_args,
229-
FRACTAL_EMAIL_PASSWORD="invalid",
230-
FRACTAL_EMAIL_PASSWORD_KEY=FRACTAL_EMAIL_PASSWORD_KEY,
231-
)
232-
with pytest.raises(ValidationError, match="FRACTAL_EMAIL_PASSWORD"):
233-
EmailSettings(
234-
**required_mail_args,
235-
FRACTAL_EMAIL_PASSWORD=FRACTAL_EMAIL_PASSWORD,
236-
FRACTAL_EMAIL_PASSWORD_KEY="invalid",
237-
)
238205
# 8: fail with sender emails
239206
with pytest.raises(ValidationError):
240207
EmailSettings(

0 commit comments

Comments
 (0)