Skip to content

Commit f4bc468

Browse files
committed
chore: refactor, update dependency
1 parent de5b0a5 commit f4bc468

File tree

19 files changed

+201
-211
lines changed

19 files changed

+201
-211
lines changed

README.md

Lines changed: 20 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ There are two methods of 2FA available:
1111

1212
## Requirements
1313

14+
Python 3.11+
15+
1416
This extension uses __Redis__, so it must be configured for CKAN.
1517

1618
Compatibility with core CKAN versions:
@@ -29,61 +31,31 @@ and I'll help you with that.
2931
To install ckanext-auth:
3032

3133
1. Activate your CKAN virtual environment, for example:
32-
33-
. /usr/lib/ckan/default/bin/activate
34-
34+
```sh
35+
. /usr/lib/ckan/default/bin/activate
36+
```
3537
2. Clone the source and install it on the virtualenv
36-
37-
git clone https://github.com/DataShades/ckanext-auth.git
38-
cd ckanext-auth
39-
pip install -e .
40-
pip install -r requirements.txt
41-
38+
```sh
39+
git clone https://github.com/DataShades/ckanext-auth.git
40+
cd ckanext-auth
41+
pip install -e .
42+
```
4243
3. Add `auth` to the `ckan.plugins` setting in your CKAN
4344
config file (by default the config file is located at
4445
`/etc/ckan/default/ckan.ini`).
4546

4647
4. Apply database migrations:
47-
48-
ckan db pending-migrations --apply
49-
48+
```
49+
ckan db upgrade
50+
```
5051
5. Restart CKAN. For example if you've deployed CKAN with Apache on Ubuntu:
51-
52-
sudo service apache2 reload
53-
52+
```
53+
sudo service apache2 reload
54+
```
5455

5556
## Config settings
5657

57-
There are several configuration settings available for this extension:
58-
59-
- key: ckanext.auth.2fa_enabled
60-
default: true
61-
type: bool
62-
description: Enable two-factor authentication for users
63-
64-
- key: ckanext.auth.2fa_method
65-
default: email
66-
description: The method to use for two-factor authentication. Options are email or authenticator.
67-
68-
- key: ckanext.auth.2fa_email_interval
69-
default: 600
70-
type: int
71-
description: TTL for the authentication code sent via email in seconds. Default is 10 minutes.
72-
73-
- key: ckanext.auth.2fa_login_timeout
74-
default: 900
75-
type: int
76-
description: Login timeout in seconds after N failed attempted. Default is 15 minutes.
77-
78-
- key: ckanext.auth.2fa_login_max_attempts
79-
default: 10
80-
type: int
81-
description: Number of failed login attempts before the login timeout is triggered.
82-
83-
- key: ckanext.auth.2fa_dev_mode
84-
default: false
85-
type: bool
86-
description: Enables Dev Mode. When enabled, it shows the actual code next to the code input. This is useful when your environment does not have SMTP configured.
58+
There are several configuration settings available for this extension. Check the config [declaration file](./ckanext/auth/config_declaration.yaml).
8759

8860
If you have the [ckanext-admin-panel](https://github.com/DataShades/ckanext-admin-panel) installed, the configuration settings will be available in the admin panel too.
8961

@@ -94,9 +66,9 @@ If you have the [ckanext-admin-panel](https://github.com/DataShades/ckanext-admi
9466
## Tests
9567

9668
To run the tests, do:
97-
98-
pytest --ckan-ini=test.ini
99-
69+
```sh
70+
pytest --ckan-ini=test.ini
71+
```
10072

10173
## License
10274

ckanext/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# encoding: utf-8
2-
31
# this is a namespace package
42
try:
53
import pkg_resources

ckanext/auth/cli.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import click
66

7-
from ckanext.auth import utils, model
7+
from ckanext.auth import model, utils
88

99
logger = logging.getLogger(__name__)
1010

@@ -20,24 +20,24 @@ def auth():
2020

2121
@auth.command()
2222
@click.argument("username")
23-
def reset_secret(username):
23+
def reset_secret(username: str) -> None:
2424
utils.regenerate_user_secret(username)
2525

2626

2727
@auth.command()
2828
@click.argument("username")
29-
def unblock_user(username):
29+
def unblock_user(username: str) -> None:
3030
utils.LoginManager.reset_for_user(username)
3131

3232

3333
@auth.command()
34-
def unblock_all():
34+
def unblock_all() -> None:
3535
utils.LoginManager.reset_all()
3636

3737

3838
@auth.command()
3939
@click.argument("username")
40-
def get_code(username):
40+
def get_code(username: str) -> None:
4141
secret = model.UserSecret.get_for_user(username)
4242

4343
if not secret:

ckanext/auth/exceptions.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
class ReplayAttackException(Exception):
2-
"""Raised when a replay attack is detected"""
3-
4-
pass
1+
class ReplayAttackError(Exception):
2+
"""Raised when a replay attack is detected."""

ckanext/auth/logic/action.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@
33
import logging
44
from typing import TypedDict
55

6-
import ckan.model as model
76
import ckan.plugins.toolkit as tk
8-
from ckan import types
7+
from ckan import model, types
8+
from ckan.lib import captcha
99
from ckan.logic import validate
10-
import ckan.lib.captcha as captcha
1110

12-
import ckanext.auth.exceptions as exceptions
13-
import ckanext.auth.utils as utils
1411
import ckanext.auth.config as auth_config
15-
import ckanext.auth.logic.schema as schema
12+
from ckanext.auth import exceptions, utils
13+
from ckanext.auth.logic import schema
1614
from ckanext.auth.model import UserSecret
1715

1816
log = logging.getLogger(__name__)
@@ -26,7 +24,8 @@ class LoginResponse(TypedDict, total=False):
2624

2725
@validate(schema.auth_2fa_user_login)
2826
def auth_2fa_user_login(
29-
context: types.Context, data_dict: types.DataDict
27+
context: types.Context,
28+
data_dict: types.DataDict,
3029
) -> LoginResponse:
3130
tk.check_access("auth_2fa_user_login", context, data_dict)
3231

@@ -45,7 +44,7 @@ def auth_2fa_user_login(
4544

4645
try:
4746
success = user_secret.check_code(data_dict["code"])
48-
except exceptions.ReplayAttackException:
47+
except exceptions.ReplayAttackError:
4948
return LoginResponse(
5049
success=False,
5150
error="The verification code has expired",
@@ -61,7 +60,8 @@ def auth_2fa_user_login(
6160

6261
@validate(schema.auth_2fa_user_login)
6362
def auth_2fa_check_credentials(
64-
context: types.Context, data_dict: types.DataDict
63+
context: types.Context,
64+
data_dict: types.DataDict,
6565
) -> LoginResponse:
6666
tk.check_access("auth_2fa_user_login", context, data_dict)
6767

@@ -88,14 +88,10 @@ def auth_2fa_check_credentials(
8888
):
8989
utils.LoginManager.block_user_login(data_dict["login"])
9090

91-
return LoginResponse(
92-
success=False, error=tk._("Invalid login or password")
93-
)
91+
return LoginResponse(success=False, error=tk._("Invalid login or password"))
9492

9593
if utils.LoginManager.is_login_blocked(data_dict["login"]):
9694
log.info("2FA: User %s is blocked from logging in", data_dict["login"])
97-
return LoginResponse(
98-
success=False, error=tk._("Too many login attempts")
99-
)
95+
return LoginResponse(success=False, error=tk._("Too many login attempts"))
10096

10197
return LoginResponse(success=True, error=None)

ckanext/auth/migration/auth/env.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
# -*- coding: utf-8 -*-
1+
import os
2+
from logging.config import fileConfig
23

3-
from __future__ import with_statement
44
from alembic import context
55
from sqlalchemy import engine_from_config, pool
6-
from logging.config import fileConfig
7-
8-
import os
96

107
# this is the Alembic Config object, which provides
118
# access to the values within the .ini file in use.
@@ -41,13 +38,12 @@ def run_migrations_offline():
4138
script output.
4239
4340
"""
44-
4541
url = config.get_main_option("sqlalchemy.url")
4642
context.configure(
4743
url=url,
4844
target_metadata=target_metadata,
4945
literal_binds=True,
50-
version_table="{}_alembic_version".format(name),
46+
version_table=f"{name}_alembic_version",
5147
)
5248

5349
with context.begin_transaction():
@@ -71,7 +67,7 @@ def run_migrations_online():
7167
context.configure(
7268
connection=connection,
7369
target_metadata=target_metadata,
74-
version_table="{}_alembic_version".format(name),
70+
version_table=f"{name}_alembic_version",
7571
)
7672

7773
with context.begin_transaction():

ckanext/auth/migration/auth/versions/7917e1c52a37_init_2fa_user_totp_table.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
"""Init 2fa_user_totp table
1+
"""Init 2fa_user_totp table.
22
33
Revision ID: 7917e1c52a37
44
Revises:
55
Create Date: 2024-08-01 15:38:57.177385
66
77
"""
88

9-
from alembic import op
109
import sqlalchemy as sa
11-
10+
from alembic import op
1211

1312
# revision identifiers, used by Alembic.
1413
revision = "7917e1c52a37"

0 commit comments

Comments
 (0)