Skip to content

Commit 091ec92

Browse files
authored
Merge pull request #507 from ghga-de/develop
Prepare Release 1.1.0
2 parents e161b85 + 634a1ad commit 091ec92

68 files changed

Lines changed: 1679 additions & 205 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ development_notb.ini
2929
_build*
3030
docs/make.bat
3131
docs/Makefile
32+
.vscode

conf/ci.ini

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,15 @@ datameta.site_id_prefix.submissions = DMS-
2828
datameta.site_id_prefix.metadatasets = DMR-
2929
datameta.site_id_prefix.files = DMF-
3030
datameta.site_id_prefix.services = DMP-
31+
32+
3133
# ApiKeys:
32-
datameta.apikeys.max_expiration_period= 30
34+
datameta.apikeys.max_expiration_period = 30
35+
36+
# 2FA settings:
37+
datameta.tfa.enabled =
38+
datameta.tfa.encrypt_key =
39+
datameta.tfa.otp_issuer =
3340

3441
pyramid.reload_templates = true
3542
pyramid.debug_authorization = false
@@ -84,7 +91,7 @@ keys = root, datameta, sqlalchemy
8491
keys = console
8592

8693
[formatters]
87-
keys = generic
94+
keys = generic, json
8895

8996
[logger_root]
9097
level = INFO
@@ -107,7 +114,11 @@ qualname = sqlalchemy.engine
107114
class = StreamHandler
108115
args = (sys.stderr,)
109116
level = NOTSET
110-
formatter = generic
117+
formatter = json
118+
119+
[formatter_json]
120+
format = %(asctime)s %(levelname)s %(name)s %(threadName)s %(message)s
121+
class = pythonjsonlogger.jsonlogger.JsonFormatter
111122

112123
[formatter_generic]
113124
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s

conf/development.ini

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,14 @@ datameta.site_id_prefix.metadatasets = DMR-
2929
datameta.site_id_prefix.files = DMF-
3030
datameta.site_id_prefix.services = DMP-
3131

32+
3233
# ApiKeys:
33-
datameta.apikeys.max_expiration_period= 30
34+
datameta.apikeys.max_expiration_period = 30
35+
36+
# 2FA settings:
37+
datameta.tfa.enabled =
38+
datameta.tfa.encrypt_key =
39+
datameta.tfa.otp_issuer =
3440

3541
pyramid.reload_templates = true
3642
pyramid.debug_authorization = false
@@ -86,7 +92,7 @@ keys = root, datameta, sqlalchemy
8692
keys = console
8793

8894
[formatters]
89-
keys = generic
95+
keys = generic, json
9096

9197
[logger_root]
9298
level = INFO
@@ -109,7 +115,11 @@ qualname = sqlalchemy.engine
109115
class = StreamHandler
110116
args = (sys.stderr,)
111117
level = NOTSET
112-
formatter = generic
118+
formatter = json
119+
120+
[formatter_json]
121+
format = %(asctime)s %(levelname)s %(name)s %(threadName)s %(message)s
122+
class = pythonjsonlogger.jsonlogger.JsonFormatter
113123

114124
[formatter_generic]
115125
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s

conf/docker_development.ini

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,14 @@ datameta.site_id_prefix.metadatasets = DMR-
2929
datameta.site_id_prefix.files = DMF-
3030
datameta.site_id_prefix.services = DMP-
3131

32+
3233
# ApiKeys:
33-
datameta.apikeys.max_expiration_period= 30
34+
datameta.apikeys.max_expiration_period = 30
35+
36+
# 2FA settings:
37+
datameta.tfa.enabled = $DATAMETA_TFA_ENABLED
38+
datameta.tfa.encrypt_key = $DATAMETA_TFA_ENCRYPT_KEY
39+
datameta.tfa.otp_issuer = $DATAMETA_TFA_OTP_ISSUER
3440

3541
pyramid.reload_templates = false
3642
pyramid.debug_authorization = false
@@ -80,7 +86,7 @@ keys = root, datameta, sqlalchemy
8086
keys = console
8187

8288
[formatters]
83-
keys = generic
89+
keys = generic, json
8490

8591
[logger_root]
8692
level = WARN
@@ -103,7 +109,11 @@ qualname = sqlalchemy.engine
103109
class = StreamHandler
104110
args = (sys.stderr,)
105111
level = NOTSET
106-
formatter = generic
112+
formatter = json
113+
114+
[formatter_json]
115+
format = %(asctime)s %(levelname)s %(name)s %(threadName)s %(message)s
116+
class = pythonjsonlogger.jsonlogger.JsonFormatter
107117

108118
[formatter_generic]
109119
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s

conf/docker_production.ini

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,15 @@ datameta.site_id_prefix.metadatasets = $DATAMETA_SITE_ID_PREFIX_METADATASETS
2929
datameta.site_id_prefix.files = $DATAMETA_SITE_ID_PREFIX_FILES
3030
datameta.site_id_prefix.services = $DATAMETA_SITE_ID_PREFIX_SERVICES
3131

32+
3233
# ApiKeys:
3334
datameta.apikeys.max_expiration_period = $DATAMETA_API_KEYS_MAX_EXPIRE_DAYS
3435

36+
# 2FA settings:
37+
datameta.tfa.enabled = $DATAMETA_TFA_ENABLED
38+
datameta.tfa.encrypt_key = $DATAMETA_TFA_ENCRYPT_KEY
39+
datameta.tfa.otp_issuer = $DATAMETA_TFA_OTP_ISSUER
40+
3541
pyramid.reload_templates = false
3642
pyramid.debug_authorization = false
3743
pyramid.debug_notfound = false
@@ -84,7 +90,7 @@ keys = root, datameta, sqlalchemy
8490
keys = console
8591

8692
[formatters]
87-
keys = generic
93+
keys = generic, json
8894

8995
[logger_root]
9096
level = WARN
@@ -107,7 +113,11 @@ qualname = sqlalchemy.engine
107113
class = StreamHandler
108114
args = (sys.stderr,)
109115
level = NOTSET
110-
formatter = generic
116+
formatter = json
117+
118+
[formatter_json]
119+
format = %(asctime)s %(levelname)s %(name)s %(threadName)s %(message)s
120+
class = pythonjsonlogger.jsonlogger.JsonFormatter
111121

112122
[formatter_generic]
113123
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s

conf/production.ini

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,14 @@ datameta.site_id_prefix.metadatasets = DMR-
2929
datameta.site_id_prefix.files = DMF-
3030
datameta.site_id_prefix.services = DMP-
3131

32+
3233
# ApiKeys:
33-
datameta.apikeys.max_expiration_period= 30
34+
datameta.apikeys.max_expiration_period = 30
35+
36+
# 2FA settings:
37+
datameta.tfa.enabled =
38+
datameta.tfa.encrypt_key =
39+
datameta.tfa.otp_issuer =
3440

3541
pyramid.reload_templates = false
3642
pyramid.debug_authorization = false
@@ -75,11 +81,12 @@ listen = *:6543
7581

7682
[loggers]
7783
keys = root, datameta, sqlalchemy
84+
7885
[handlers]
7986
keys = console
8087

8188
[formatters]
82-
keys = generic
89+
keys = generic, json
8390

8491
[logger_root]
8592
level = WARN
@@ -102,7 +109,11 @@ qualname = sqlalchemy.engine
102109
class = StreamHandler
103110
args = (sys.stderr,)
104111
level = NOTSET
105-
formatter = generic
112+
formatter = json
113+
114+
[formatter_json]
115+
format = %(asctime)s %(levelname)s %(name)s %(threadName)s %(message)s
116+
class = pythonjsonlogger.jsonlogger.JsonFormatter
106117

107118
[formatter_generic]
108119
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s

datameta/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from pyramid.config import Configurator
1616
from pyramid_beaker import session_factory_from_settings
17+
from pyramid.settings import asbool
1718
import os
1819
from . import api
1920

@@ -25,6 +26,13 @@
2526
def main(global_config, **settings):
2627
""" This function returns a Pyramid WSGI application.
2728
"""
29+
is_2fa_enabled = asbool(settings.get("datameta.tfa.enabled", False))
30+
tfa_otp_issuer = settings.get("datameta.tfa.otp_issuer")
31+
tfa_encrypt_key = settings.get("datameta.tfa.encrypt_key")
32+
33+
if is_2fa_enabled and (not tfa_otp_issuer or not tfa_encrypt_key):
34+
raise ValueError("2fa enabled but no issuer and/or no encryption key found")
35+
2836
with Configurator(settings=settings) as config:
2937
# Session config
3038
session_factory = session_factory_from_settings(settings)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""add 2fa functionality
2+
3+
Revision ID: b5b86c536020
4+
Revises: 98911b881230
5+
Create Date: 2021-10-20 01:10:15.944795
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
from sqlalchemy.dialects import postgresql
11+
12+
# revision identifiers, used by Alembic.
13+
revision = 'b5b86c536020'
14+
down_revision = '98911b881230'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.create_table(
22+
'tfatokens',
23+
sa.Column('id', sa.Integer(), nullable=False),
24+
sa.Column('uuid', postgresql.UUID(as_uuid=True), nullable=False),
25+
sa.Column('user_id', sa.Integer(), nullable=False),
26+
sa.Column('value', sa.Text(), nullable=False),
27+
sa.Column('expires', sa.DateTime(), nullable=False),
28+
sa.Column('secret', sa.Text(), nullable=True),
29+
sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_tfatokens_user_id_users')),
30+
sa.PrimaryKeyConstraint('id', name=op.f('pk_tfatokens')),
31+
sa.UniqueConstraint('uuid', name=op.f('uq_tfatokens_uuid')),
32+
sa.UniqueConstraint('value', name=op.f('uq_tfatokens_value'))
33+
)
34+
op.add_column('users', sa.Column('tfa_secret', sa.Text(), nullable=True))
35+
# ### end Alembic commands ###
36+
37+
38+
def downgrade():
39+
# ### commands auto generated by Alembic - please adjust! ###
40+
op.drop_column('users', 'tfa_secret')
41+
op.drop_table('tfatokens')
42+
# ### end Alembic commands ###
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""added tracking of used passwords
2+
3+
Revision ID: 6a9f0bec38e6
4+
Revises: 7fdc829db18d
5+
Create Date: 2021-10-29 11:22:19.194633
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
from sqlalchemy.dialects import postgresql
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '6a9f0bec38e6'
15+
down_revision = '7fdc829db18d'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.create_table(
23+
'usedpasswords',
24+
sa.Column('id', sa.Integer(), nullable=False),
25+
sa.Column('uuid', postgresql.UUID(as_uuid=True), nullable=False),
26+
sa.Column('user_id', sa.Integer(), nullable=False),
27+
sa.Column('pwhash', sa.Text(), nullable=False),
28+
sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_usedpasswords_user_id_users')),
29+
sa.PrimaryKeyConstraint('id', name=op.f('pk_usedpasswords')),
30+
sa.UniqueConstraint('uuid', name=op.f('uq_usedpasswords_uuid')),
31+
sa.UniqueConstraint('pwhash', name=op.f('uq_usedpasswords_pwhash'))
32+
)
33+
# ### end Alembic commands ###
34+
35+
36+
def downgrade():
37+
# ### commands auto generated by Alembic - please adjust! ###
38+
op.drop_table('usedpasswords')
39+
# ### end Alembic commands ###
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""added failed_login_attempt tracking
2+
3+
Revision ID: 98911b881230
4+
Revises: 6a9f0bec38e6
5+
Create Date: 2021-10-29 15:01:29.844727
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
from sqlalchemy.dialects import postgresql
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '98911b881230'
14+
down_revision = '6a9f0bec38e6'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.create_table(
22+
'loginattempts',
23+
sa.Column('id', sa.Integer(), nullable=False),
24+
sa.Column('uuid', postgresql.UUID(as_uuid=True), nullable=False),
25+
sa.Column('user_id', sa.Integer(), nullable=False),
26+
sa.Column('timestamp', sa.DateTime(), nullable=False),
27+
sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_loginattempts_user_id_users')),
28+
sa.PrimaryKeyConstraint('id', name=op.f('pk_loginattempts')),
29+
sa.UniqueConstraint('uuid', name=op.f('uq_loginattempts_uuid'))
30+
)
31+
# ### end Alembic commands ###
32+
33+
34+
def downgrade():
35+
# ### commands auto generated by Alembic - please adjust! ###
36+
op.drop_table('loginattempts')
37+
# ### end Alembic commands ###

0 commit comments

Comments
 (0)