ppss-auth 0.11.1.1__tar.gz → 0.12.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ppss_auth-0.11.1.1/ppss_auth.egg-info → ppss_auth-0.12.0.0}/PKG-INFO +3 -1
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/changelog.txt +7 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/__init__.py +15 -13
- ppss_auth-0.12.0.0/ppss_auth/alembic/versions/20260109_000ec266dd6e_add_salt.py +32 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/constants.py +49 -8
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/models.py +109 -161
- ppss_auth-0.12.0.0/ppss_auth/ppss_auth_static/edituser.js +65 -0
- ppss_auth-0.12.0.0/ppss_auth/ppss_auth_static/ppssauth.css +26 -0
- ppss_auth-0.12.0.0/ppss_auth/ppss_auth_static/ppssauth.js +223 -0
- ppss_auth-0.12.0.0/ppss_auth/ppss_auth_utils/createdb.py +129 -0
- ppss_auth-0.12.0.0/ppss_auth/ppss_auth_utils/otp.py +48 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/ppss_auth_utils/password.py +7 -3
- ppss_auth-0.12.0.0/ppss_auth/ppss_auth_utils/usersession.py +70 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/routes.py +26 -17
- ppss_auth-0.12.0.0/ppss_auth/templates/change.jinja2 +31 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/change.mako +25 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/confirm_email.jinja2 +24 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/confirm_email.mako +22 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/edit2fa.jinja2 +48 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/edit2fa.mako +44 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/editgroup.jinja2 +21 -21
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/editgroup.mako +21 -21
- ppss_auth-0.12.0.0/ppss_auth/templates/editperm.jinja2 +15 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/editperm.mako +12 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/edituser.jinja2 +102 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/edituser.mako +145 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/enable2fa.jinja2 +29 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/enable2fa.mako +27 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/layouts/masterlayout.jinja2 +1 -3
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/layouts/masterlayout.mako +1 -3
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/layouts/midlayout.jinja2 +1 -1
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/layouts/midlayout.mako +1 -3
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/layouts/public.jinja2 +3 -3
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/layouts/public.mako +3 -3
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/listgroup.jinja2 +3 -3
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/listgroup.mako +3 -3
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/listperm.jinja2 +3 -3
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/listperm.mako +3 -3
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/listuser.jinja2 +16 -5
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/listuser.mako +16 -5
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/login.jinja2 +14 -10
- ppss_auth-0.12.0.0/ppss_auth/templates/login.mako +44 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/login_nogrid.jinja2 +5 -5
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/login_nogrid.mako +5 -5
- ppss_auth-0.12.0.0/ppss_auth/templates/partials/auth-apps.html +38 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/partials/otp.html +50 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/recover.jinja2 +9 -9
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/recover.mako +9 -9
- ppss_auth-0.12.0.0/ppss_auth/templates/registeruser.jinja2 +31 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/registeruser.mako +28 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/reset.jinja2 +43 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/reset.mako +14 -10
- ppss_auth-0.12.0.0/ppss_auth/templates/shared/splash.html +27 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/splash.jinja2 +1 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/splash.mako +1 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/verify2fa.jinja2 +21 -0
- ppss_auth-0.12.0.0/ppss_auth/templates/verify2fa.mako +19 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/views/auth.py +266 -399
- ppss_auth-0.12.0.0/ppss_auth/views/crud.py +593 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0/ppss_auth.egg-info}/PKG-INFO +3 -1
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth.egg-info/SOURCES.txt +14 -2
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth.egg-info/requires.txt +2 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/setup.py +4 -2
- ppss_auth-0.11.1.1/ppss_auth/ppss_auth_static/ppssauth.css +0 -51
- ppss_auth-0.11.1.1/ppss_auth/ppss_auth_static/ppssauth.js +0 -181
- ppss_auth-0.11.1.1/ppss_auth/templates/change.jinja2 +0 -28
- ppss_auth-0.11.1.1/ppss_auth/templates/change.mako +0 -22
- ppss_auth-0.11.1.1/ppss_auth/templates/confirm_email.jinja2 +0 -16
- ppss_auth-0.11.1.1/ppss_auth/templates/confirm_email.mako +0 -9
- ppss_auth-0.11.1.1/ppss_auth/templates/editperm.jinja2 +0 -15
- ppss_auth-0.11.1.1/ppss_auth/templates/editperm.mako +0 -12
- ppss_auth-0.11.1.1/ppss_auth/templates/edituser.jinja2 +0 -67
- ppss_auth-0.11.1.1/ppss_auth/templates/edituser.mako +0 -66
- ppss_auth-0.11.1.1/ppss_auth/templates/enable2fa.jinja2 +0 -25
- ppss_auth-0.11.1.1/ppss_auth/templates/enable2fa.mako +0 -23
- ppss_auth-0.11.1.1/ppss_auth/templates/login.mako +0 -35
- ppss_auth-0.11.1.1/ppss_auth/templates/registeruser.jinja2 +0 -31
- ppss_auth-0.11.1.1/ppss_auth/templates/registeruser.mako +0 -28
- ppss_auth-0.11.1.1/ppss_auth/templates/reset.jinja2 +0 -39
- ppss_auth-0.11.1.1/ppss_auth/templates/shared/bootstrapcss.html +0 -1
- ppss_auth-0.11.1.1/ppss_auth/templates/verify2fa.jinja2 +0 -24
- ppss_auth-0.11.1.1/ppss_auth/templates/verify2fa.mako +0 -22
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/MANIFEST.in +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/README.md +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/babel.ini +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/alembic.ini +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/env.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/script.py.mako +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/versions/20201026_52f4d4eefdfe_unique_permission_name.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/versions/20201120_6c9e84ab8280_unique_user_name.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/versions/20220329_44fde88fa438_creazione_colonne_per_login_history.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/versions/20220331_6190d529682d_result_reason.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/versions/20231016_3f4032dd2d1b_added_email_to_user.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/versions/20240110_4b95deb2d91c_tabella_reset_token.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/versions/20240209_7d2e85bbf831_add_otp_hash.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/versions/20240304_483944c8ff05_add_phone.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/alembic/versions/f724fac25359_creation.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/locale/en/LC_MESSAGES/ppss_auth.mo +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/locale/fr/LC_MESSAGES/ppss_auth.mo +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/locale/it/LC_MESSAGES/ppss_auth.mo +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/ppss_auth_static/loader.js +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/ppss_auth_static/template.html +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/ppss_auth_utils/__init__.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/ppss_auth_utils/db.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/ppss_auth_utils/emailclient.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/ppss_auth_utils/i18n.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/ppss_auth_utils/scriptutils.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/scripts/__init__.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/scripts/alchemyutils.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/scripts/cleanup_db.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/scripts/create_user.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/scripts/initialize_db.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/scripts/sayauth.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/scripts/upgrade_db.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/email/activation.jinja2 +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/email/activation.mako +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/email/recover.jinja2 +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/email/recover.mako +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/partials/userblock.jinja2 +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/partials/userblock.mako +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/partials/usermanage.jinja2 +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/templates/partials/usermanage.mako +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth/views/__init__.py +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth.egg-info/dependency_links.txt +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth.egg-info/entry_points.txt +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/ppss_auth.egg-info/top_level.txt +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/readme.txt +0 -0
- {ppss_auth-0.11.1.1 → ppss_auth-0.12.0.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ppss_auth
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0.0
|
|
4
4
|
Summary: simple auth scheme for pyramid, based on Mako template and sqlalchemy backend
|
|
5
5
|
Home-page: https://bitbucket.org/pingpongstars/ppss_auth/src/master/
|
|
6
6
|
Author: pdepmcp
|
|
@@ -23,6 +23,8 @@ Requires-Dist: alembic
|
|
|
23
23
|
Requires-Dist: cryptography
|
|
24
24
|
Requires-Dist: pyotp
|
|
25
25
|
Requires-Dist: qrcode
|
|
26
|
+
Requires-Dist: Pillow
|
|
27
|
+
Requires-Dist: requests
|
|
26
28
|
|
|
27
29
|
This package aims to give and easy pluggable module to provide authentication and user maintennance in a Pyramid web application.
|
|
28
30
|
It relies the Pyramid+SQLAlchemy+Mako stack. Implementation for other template languages is on the roadmap.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
from ppss_auth.ppss_auth_utils.usersession import UserSession
|
|
4
4
|
from sqlalchemy import engine_from_config
|
|
5
5
|
from sqlalchemy.orm import sessionmaker
|
|
6
6
|
import transaction
|
|
@@ -12,10 +12,11 @@ from pyramid.authorization import ACLAuthorizationPolicy
|
|
|
12
12
|
from pyramid.authentication import SessionAuthenticationPolicy
|
|
13
13
|
from pyramid.threadlocal import get_current_request
|
|
14
14
|
from .constants import Conf
|
|
15
|
-
from .models import
|
|
15
|
+
from .models import PPSsuser
|
|
16
|
+
|
|
16
17
|
from .routes import configRoutes
|
|
17
18
|
from .ppss_auth_utils.db import checkDBRevision
|
|
18
|
-
|
|
19
|
+
from .ppss_auth_utils.createdb import initdb
|
|
19
20
|
import logging
|
|
20
21
|
l = logging.getLogger('ppssauth')
|
|
21
22
|
|
|
@@ -48,21 +49,21 @@ def initAuthDb(settings):
|
|
|
48
49
|
|
|
49
50
|
def getLoggedUser(request,addinsession=False):
|
|
50
51
|
uid = request.session[Conf.sessionuser]['id'] if Conf.sessionuser in request.session else False
|
|
51
|
-
user = request.session[Conf.sessionuser]
|
|
52
|
+
user = request.session[Conf.sessionuser].get('user',False) if Conf.sessionuser in request.session else False
|
|
52
53
|
if user:
|
|
53
54
|
if addinsession:
|
|
54
55
|
request.dbsession.add(user)
|
|
55
56
|
return user
|
|
56
57
|
else:
|
|
57
58
|
return None
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def getUserSession(request):
|
|
62
|
+
if not hasattr(request,'ppss_usersession'):
|
|
63
|
+
user = request.loggeduser
|
|
64
|
+
usersession = UserSession(user,request)
|
|
65
|
+
request.ppss_usersession = usersession
|
|
66
|
+
return request.ppss_usersession
|
|
66
67
|
|
|
67
68
|
|
|
68
69
|
def add_renderer_globals(event):
|
|
@@ -109,6 +110,7 @@ def includeme(config):
|
|
|
109
110
|
settings = config.get_settings()
|
|
110
111
|
Conf.setup(settings)
|
|
111
112
|
config.add_request_method(getLoggedUser,'loggeduser',reify=True)
|
|
113
|
+
config.add_request_method(getUserSession,'usersession',reify=True)
|
|
112
114
|
|
|
113
115
|
config.add_translation_dirs('ppss_auth:locale/')
|
|
114
116
|
|
|
@@ -125,7 +127,7 @@ def includeme(config):
|
|
|
125
127
|
from .views.auth import getPrincipals,ACLRoot
|
|
126
128
|
authz_policy = ACLAuthorizationPolicy()
|
|
127
129
|
config.set_authentication_policy(SessionAuthenticationPolicy(callback=getPrincipals) )
|
|
128
|
-
config.set_authorization_policy(
|
|
130
|
+
config.set_authorization_policy(authz_policy)
|
|
129
131
|
config.set_root_factory(ACLRoot)
|
|
130
132
|
config.scan("ppss_auth")
|
|
131
133
|
pass
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""add salt
|
|
2
|
+
|
|
3
|
+
Revision ID: 000ec266dd6e
|
|
4
|
+
Revises: 483944c8ff05
|
|
5
|
+
Create Date: 2026-01-09 12:17:03.593447
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
import secrets
|
|
9
|
+
from alembic import op
|
|
10
|
+
import sqlalchemy as sa
|
|
11
|
+
from sqlalchemy.dialects import mysql
|
|
12
|
+
from sqlalchemy import table, column
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision = '000ec266dd6e'
|
|
16
|
+
down_revision = '483944c8ff05'
|
|
17
|
+
branch_labels = None
|
|
18
|
+
depends_on = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade():
|
|
22
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
23
|
+
op.add_column('ppss_user', sa.Column('salt', sa.Unicode(length=64), nullable=True))
|
|
24
|
+
op.create_unique_constraint(op.f('uq_ppss_user_salt'), 'ppss_user', ['salt'])
|
|
25
|
+
# ### end Alembic commands ###
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def downgrade():
|
|
29
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
30
|
+
op.drop_constraint(op.f('uq_ppss_user_salt'), 'ppss_user', type_='unique')
|
|
31
|
+
op.drop_column('ppss_user', 'salt')
|
|
32
|
+
# ### end Alembic commands ###
|
|
@@ -15,11 +15,11 @@ else:
|
|
|
15
15
|
return False
|
|
16
16
|
return hasattr(v, '__iter__')
|
|
17
17
|
|
|
18
|
-
def getBT(version = 4):
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
# def getBT(version = 4):
|
|
19
|
+
# v4 = version == 4
|
|
20
|
+
# return {
|
|
21
|
+
# 'xs': 'col-' if v4 else 'col-xs-'
|
|
22
|
+
# }
|
|
23
23
|
|
|
24
24
|
class Conf():
|
|
25
25
|
|
|
@@ -46,6 +46,35 @@ class Conf():
|
|
|
46
46
|
raise e
|
|
47
47
|
else:
|
|
48
48
|
return default
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def getTimeSpan(confval):
|
|
53
|
+
try:
|
|
54
|
+
if isinstance(confval, int):
|
|
55
|
+
return datetime.timedelta(seconds=confval)
|
|
56
|
+
elif isinstance(confval, str):
|
|
57
|
+
if confval.endswith('h'):
|
|
58
|
+
confval = confval[:-1]
|
|
59
|
+
confval = int(confval) * 3600
|
|
60
|
+
elif confval.endswith('m'):
|
|
61
|
+
confval = confval[:-1]
|
|
62
|
+
confval = int(confval) * 60
|
|
63
|
+
elif confval.endswith('s'):
|
|
64
|
+
confval = confval[:-1]
|
|
65
|
+
confval = int(confval)
|
|
66
|
+
confval = int(confval)
|
|
67
|
+
return datetime.timedelta(seconds=confval)
|
|
68
|
+
else:
|
|
69
|
+
raise ValueError("Invalid timespan value:{}".format(confval))
|
|
70
|
+
except Exception as e:
|
|
71
|
+
l.exception(u"Exception parsing timespan value:{}".format(confval))
|
|
72
|
+
raise e
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def is2faConfigured(cls):
|
|
77
|
+
return cls.issuer2fa
|
|
49
78
|
|
|
50
79
|
@classmethod
|
|
51
80
|
def setup(cls, settings):
|
|
@@ -68,7 +97,6 @@ class Conf():
|
|
|
68
97
|
cls.activationemail = settings.get("ppss_auth.register_requireactivation", "true").lower() != "false"
|
|
69
98
|
|
|
70
99
|
cls.newusergroups = [x for x in map(str.strip, ( settings.get("ppss_auth.newusergroups", '' ).split(",") ) ) if x ] if settings.get("ppss_auth.newusergroups", '' ) else ['signeduser']
|
|
71
|
-
cls.saltforhash = settings.get("ppss_auth.salt", "ImTheSaltOfThisLife")
|
|
72
100
|
|
|
73
101
|
cls.forbiddentologin = settings.get("ppss_auth.forbidden_to_login", "true").lower() == 'true'
|
|
74
102
|
|
|
@@ -80,8 +108,14 @@ class Conf():
|
|
|
80
108
|
cls.passwordminlen = int(settings.get("ppss_auth.password_min_len",12))
|
|
81
109
|
cls.passwordrelist = Conf.conf2list( settings.get("ppss_auth.password_relist",["[A-Z]+","[a-z]+","[0-9]+","[!,\.\?\\/;:_\-+*@\£\$\%\&\(\)\"\'=\^àèìòùé\#§°ç{}]+",".{{{len},}}".format(len=cls.passwordminlen)]) )
|
|
82
110
|
cls.forbiddenpasswordlist = settings.get("ppss_auth.forbidden_password_list","")
|
|
111
|
+
##TODO:
|
|
112
|
+
##add salt, pepper e session TTL
|
|
113
|
+
cls.sessionmaxttl = Conf.getTimeSpan(settings.get("ppss_auth.session_max_ttl","15m") )
|
|
114
|
+
cls.pepperforhash = settings.get("ppss_auth.pepper","")
|
|
115
|
+
|
|
116
|
+
|
|
83
117
|
#cls.passwordwrongmessage = f'La nuova password deve essere differente dalle precedenti {cls.passwordpreviousdifferent} e avere almeno 12 caratteri, una maiuscola, una minuscola, un numero e un carattere fra "!,.?\\/;:_-+*".'
|
|
84
|
-
cls.passwordwrongmessage = f'The new password must be different from the previous {cls.passwordpreviousdifferent} and should contain at least {cls.passwordminlen} chars,
|
|
118
|
+
cls.passwordwrongmessage = f'The new password must be different from the previous {cls.passwordpreviousdifferent} and should contain at least {cls.passwordminlen} chars, containing at least 1 upper case, 1 lower case, 1 number and a special char among these "!,.?\\/;:_-+*".'
|
|
85
119
|
cls.passwordexpiredmessage = 'Password expired. Please change it.'
|
|
86
120
|
cls.passwordexpire = int(settings.get("ppss_auth.password_expire",0) )
|
|
87
121
|
|
|
@@ -111,12 +145,14 @@ class Conf():
|
|
|
111
145
|
|
|
112
146
|
cls.botemplateinherit = settings.get("ppss_auth.botemplateinherit", cls.tplpath("public", True) )
|
|
113
147
|
|
|
148
|
+
cls.splashtemplate = settings.get("ppss_auth.splashtemplate", cls.tplpath("splash") )
|
|
149
|
+
|
|
114
150
|
|
|
115
151
|
#bo template inheritance
|
|
116
152
|
cls.mastertemplateinherit = settings.get("ppss_auth.mastertemplateinherit", cls.tplpath("masterlayout", True) )
|
|
117
153
|
cls.sectiontemplateinherit = settings.get("ppss_auth.sectiontemplateinherit", cls.tplpath("midlayout", True) )
|
|
118
154
|
|
|
119
|
-
cls.bootstrapClasses = getBT(int(settings.get("ppss_auth.bootstrapversion",4)))
|
|
155
|
+
# cls.bootstrapClasses = getBT(int(settings.get("ppss_auth.bootstrapversion",4)))
|
|
120
156
|
|
|
121
157
|
cls.testurl = settings.get("ppss_auth.testurl", "/test")
|
|
122
158
|
|
|
@@ -160,3 +196,8 @@ class Conf():
|
|
|
160
196
|
cls.issuer2fa = settings.get("ppss_auth.issuer2fa", None)
|
|
161
197
|
cls.enable2fatpl = settings.get("ppss_auth.enable2fatpl", cls.tplpath('enable2fa'))
|
|
162
198
|
cls.verify2fatpl = settings.get("ppss_auth.verify2fatpl", cls.tplpath('verify2fa'))
|
|
199
|
+
cls.edit2fatpl = settings.get("ppss_auth.edit2fatpl", cls.tplpath('edit2fa'))
|
|
200
|
+
cls.hoursvalid2fa = int(settings.get("ppss_auth.hoursvalid2fa", 24))
|
|
201
|
+
# turnstile captcha
|
|
202
|
+
cls.turnstile_sitekey = settings.get("ppss_auth.turnstile_sitekey", None)
|
|
203
|
+
cls.turnstile_secretkey = settings.get("ppss_auth.turnstile_secretkey", None)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import secrets
|
|
2
2
|
import sys
|
|
3
3
|
|
|
4
|
-
import pyotp
|
|
5
4
|
PY2 = sys.version_info[0] == 2
|
|
6
5
|
if not PY2:
|
|
7
6
|
unicode = str
|
|
@@ -31,9 +30,10 @@ NAMING_CONVENTION = {
|
|
|
31
30
|
"pk": "pk_%(table_name)s"
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
import logging
|
|
33
|
+
import logging
|
|
35
34
|
|
|
36
35
|
from sqlalchemy.orm import joinedload
|
|
36
|
+
from pyramid.request import Request
|
|
37
37
|
|
|
38
38
|
metadata = MetaData(naming_convention=NAMING_CONVENTION)
|
|
39
39
|
Base = declarative_base(metadata=metadata)
|
|
@@ -45,128 +45,6 @@ from .ppss_auth_utils.password import getPasswordDigest
|
|
|
45
45
|
l = logging.getLogger('ppssauth.models')
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
class constants():
|
|
49
|
-
SYSADMINPERM = "sysadmin"
|
|
50
|
-
SYSADMINGROUP = "sysadmin"
|
|
51
|
-
|
|
52
|
-
def __createPermissions(session,permissions):
|
|
53
|
-
permmap = {}
|
|
54
|
-
for p in permissions:
|
|
55
|
-
perm = session.query(PPSspermission).filter(PPSspermission.name == p['name']).first()
|
|
56
|
-
if not perm:
|
|
57
|
-
perm = PPSspermission(name = p['name'])
|
|
58
|
-
session.add(perm)
|
|
59
|
-
l.info("permission '{}' added to session".format(p['name']))
|
|
60
|
-
perm.permtype = p['permtype'] if 'permtype' in p else 0
|
|
61
|
-
permmap[p['name'] ] = perm
|
|
62
|
-
return permmap
|
|
63
|
-
|
|
64
|
-
def __createGroups(session,groups,permissions):
|
|
65
|
-
groupmap = {}
|
|
66
|
-
for g in groups:
|
|
67
|
-
g = g.split("=")
|
|
68
|
-
gname = str.strip(g[0])
|
|
69
|
-
if len(g) == 2:
|
|
70
|
-
permlist = map(str.strip,g[1].split(","))
|
|
71
|
-
else:
|
|
72
|
-
permlist = []
|
|
73
|
-
group = session.query(PPSsgroup).filter(PPSsgroup.name == gname).first()
|
|
74
|
-
if not group:
|
|
75
|
-
group = PPSsgroup(name = gname)
|
|
76
|
-
session.add(group)
|
|
77
|
-
l.info("group '{}' added to session".format(gname))
|
|
78
|
-
groupmap[gname] = group
|
|
79
|
-
for p in permlist:
|
|
80
|
-
if not group.hasPermission(p):
|
|
81
|
-
if p in permissions:
|
|
82
|
-
perm = permissions[p]
|
|
83
|
-
else:
|
|
84
|
-
perm = PPSspermission(name = p,permtype = 0)
|
|
85
|
-
session.add(perm)
|
|
86
|
-
permissions[p] = perm
|
|
87
|
-
l.info("new permission '{}' created for group '{}'".format(p,gname))
|
|
88
|
-
group.permissions.append(perm)
|
|
89
|
-
return groupmap
|
|
90
|
-
|
|
91
|
-
def __createUsers(session,users,groups,defaultpassword = None):
|
|
92
|
-
usermap = {}
|
|
93
|
-
for u in users:
|
|
94
|
-
u = u.split("=")
|
|
95
|
-
uname = u[0].split("/")
|
|
96
|
-
upassword = None
|
|
97
|
-
if len(uname)==2:
|
|
98
|
-
upassword = uname[1].strip()
|
|
99
|
-
else:
|
|
100
|
-
upassword = Conf.defaultpassword
|
|
101
|
-
uname = uname[0].strip()
|
|
102
|
-
if len(u)==2:
|
|
103
|
-
grouplist = map(str.strip,u[1].split(","))
|
|
104
|
-
else:
|
|
105
|
-
grouplist = []
|
|
106
|
-
user = session.query(PPSsuser).filter(PPSsuser.username == uname).first()
|
|
107
|
-
if not user:
|
|
108
|
-
user = PPSsuser(username = uname)
|
|
109
|
-
if upassword:
|
|
110
|
-
user.setPassword(upassword)
|
|
111
|
-
elif defaultpassword:
|
|
112
|
-
user.setPassword(defaultpassword)
|
|
113
|
-
session.add(user)
|
|
114
|
-
l.info("user '{}' added to session".format(uname))
|
|
115
|
-
usermap[uname] = user
|
|
116
|
-
for g in grouplist:
|
|
117
|
-
if not user.isInGroup(g,False):
|
|
118
|
-
if g in groups:
|
|
119
|
-
group = groups[g]
|
|
120
|
-
else:
|
|
121
|
-
group = session.query(PPSsgroup).filter(PPSsgroup.name == g).first()
|
|
122
|
-
if group is None:
|
|
123
|
-
group = PPSsgroup(name = g)
|
|
124
|
-
session.add(group)
|
|
125
|
-
else:
|
|
126
|
-
groups[g] = group
|
|
127
|
-
l.info("new group '{}' created for user '{}'".format(g,uname))
|
|
128
|
-
user.groups.append(group)
|
|
129
|
-
return usermap
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
##the caller must commit this
|
|
133
|
-
def initdb(session=None,createdefault=False,engine = None):
|
|
134
|
-
if engine is None:
|
|
135
|
-
engine = session.get_bind()
|
|
136
|
-
try:
|
|
137
|
-
PPSsuser.all(session)
|
|
138
|
-
except:
|
|
139
|
-
raise Exception("no user table. exiting!")
|
|
140
|
-
if createdefault:
|
|
141
|
-
l.info("creating default")
|
|
142
|
-
systemperms = [#PPSspermission(name = u"admin"),
|
|
143
|
-
{"name": u"edituser","permtype": 1},
|
|
144
|
-
{"name": u"listuser","permtype": 1},
|
|
145
|
-
{"name": u"login" ,"permtype": 1},
|
|
146
|
-
{"name": constants.SYSADMINPERM,"permtype": 1},
|
|
147
|
-
]
|
|
148
|
-
permissions = [{'name':p,'permtype':1} for p in Conf.perm2create]
|
|
149
|
-
for sp in systemperms:
|
|
150
|
-
permissions.append(sp)
|
|
151
|
-
|
|
152
|
-
permissionmap = __createPermissions(session,permissions)
|
|
153
|
-
l.debug("permission map:{}".format(permissionmap))
|
|
154
|
-
groupmap = __createGroups(session, Conf.group2create +
|
|
155
|
-
[
|
|
156
|
-
"useradmin=edituser,listuser,login",
|
|
157
|
-
"signeduser=login",
|
|
158
|
-
"{}={}".format(constants.SYSADMINGROUP,constants.SYSADMINPERM)
|
|
159
|
-
]
|
|
160
|
-
, permissionmap)
|
|
161
|
-
l.debug("group map:{}".format(groupmap))
|
|
162
|
-
if Conf.adminname:
|
|
163
|
-
root = __createUsers(session,[Conf.adminname+"="+constants.SYSADMINGROUP],groupmap,Conf.adminpass if Conf.adminpass else None)
|
|
164
|
-
usermap = __createUsers(session, Conf.user2create, groupmap )
|
|
165
|
-
l.debug("user map:{}".format(usermap))
|
|
166
|
-
return 0
|
|
167
|
-
|
|
168
|
-
return 0
|
|
169
|
-
|
|
170
48
|
ppssuserlkppssgroup = Table('ppssuser_lk_ppssgroup', Base.metadata,
|
|
171
49
|
Column('user_id',Integer,ForeignKey('ppss_user.id', ondelete="CASCADE"), primary_key=True),
|
|
172
50
|
Column('group_id',Integer,ForeignKey('ppss_group.id', ondelete="CASCADE"), primary_key=True )
|
|
@@ -223,6 +101,16 @@ class commonTable():
|
|
|
223
101
|
def firstByField(cls,field,value,DBSession):
|
|
224
102
|
return DBSession.query(cls).filter(getattr(cls, field)==value).first()
|
|
225
103
|
|
|
104
|
+
class LOGINREASON():
|
|
105
|
+
OTPSKIPPED = (3,"OTP not required")
|
|
106
|
+
OTPPASSED = (2,"OTP Ok")
|
|
107
|
+
OK = (1,"Ok")
|
|
108
|
+
VALIDATIONERROR = (0,"invalid password")
|
|
109
|
+
BLOCKED = (-1,"too many recent fails")
|
|
110
|
+
DISABLED = (-2,"user disabled")
|
|
111
|
+
DONTEXIST = (-3,"user does not exist")
|
|
112
|
+
OTPERROR = (-4,"OTP error")
|
|
113
|
+
|
|
226
114
|
class LoginError():
|
|
227
115
|
def __init__(self,validlogin,enabled,failcount):
|
|
228
116
|
self.validlogin = validlogin
|
|
@@ -230,25 +118,39 @@ class LoginError():
|
|
|
230
118
|
self.failcount = failcount
|
|
231
119
|
|
|
232
120
|
def __bool__(self):
|
|
233
|
-
#return self.validlogin and self.enabled and self.failcount
|
|
121
|
+
# return self.validlogin and self.enabled and self.failcount
|
|
234
122
|
return self.result() == 1
|
|
235
123
|
|
|
124
|
+
def __result(self):
|
|
125
|
+
if self.enabled is None:
|
|
126
|
+
return LOGINREASON.DONTEXIST
|
|
127
|
+
if not self.enabled:
|
|
128
|
+
return LOGINREASON.DISABLED
|
|
129
|
+
if self.failcount:
|
|
130
|
+
return LOGINREASON.BLOCKED
|
|
131
|
+
if not self.validlogin:
|
|
132
|
+
return LOGINREASON.VALIDATIONERROR
|
|
133
|
+
return LOGINREASON.OK
|
|
134
|
+
|
|
135
|
+
|
|
236
136
|
def result(self):
|
|
237
|
-
return
|
|
137
|
+
return self.__result()[0]
|
|
138
|
+
#return 1 if self.failcount and self.validlogin and self.enabled else 0 if self.validlogin else -1 if self.failcount else -2
|
|
238
139
|
|
|
239
140
|
def blocked(self):
|
|
240
141
|
return self.failcount is not None and not self.failcount
|
|
241
142
|
|
|
242
143
|
def resultreason(self):
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
return "
|
|
144
|
+
return self.__result()[1]
|
|
145
|
+
# if self.enabled is None:
|
|
146
|
+
# return "user does not exist"
|
|
147
|
+
# if not self.enabled:
|
|
148
|
+
# return "user disabled"
|
|
149
|
+
# if not self.validlogin:
|
|
150
|
+
# return "invalid password"
|
|
151
|
+
# if not self.failcount:
|
|
152
|
+
# return "too many recent fails"
|
|
153
|
+
# return "Ok"
|
|
252
154
|
|
|
253
155
|
def __str__(self):
|
|
254
156
|
return self.username
|
|
@@ -257,10 +159,10 @@ class PPSsuser(Base,commonTable):
|
|
|
257
159
|
__tablename__ = 'ppss_user'
|
|
258
160
|
id = Column(Integer, primary_key=True)
|
|
259
161
|
username = Column(Unicode(128),unique=True)
|
|
260
|
-
|
|
162
|
+
|
|
261
163
|
###EMAIL
|
|
262
164
|
email = Column(Unicode(128),unique=True)
|
|
263
|
-
|
|
165
|
+
|
|
264
166
|
password = Column(Unicode(1024))
|
|
265
167
|
insertdt = Column(DateTime,default=datetime.now)
|
|
266
168
|
updatedt = Column(DateTime,default=datetime.now,onupdate=datetime.now)
|
|
@@ -280,67 +182,95 @@ class PPSsuser(Base,commonTable):
|
|
|
280
182
|
|
|
281
183
|
phone_prefix = Column(Unicode(8))
|
|
282
184
|
phone_number = Column(Unicode(16), unique=True)
|
|
185
|
+
|
|
186
|
+
### add a new field salt for password hashing with a unique salt per user
|
|
187
|
+
salt = Column(Unicode(64), unique=True )
|
|
283
188
|
|
|
284
189
|
superusercache = None
|
|
285
190
|
permissionscache = None
|
|
286
191
|
permissionsmapcache = None
|
|
287
192
|
groupmapcache = None
|
|
193
|
+
invalidusersession = False
|
|
288
194
|
|
|
289
195
|
@classmethod
|
|
290
196
|
def checkLogin(cls,user,password,dbsession, ipaddr = None):
|
|
291
|
-
|
|
197
|
+
# Don't hash with salt here - the salt will be applied in checkCryptedLogin
|
|
198
|
+
# using the user-specific salt from the database
|
|
199
|
+
return PPSsuser.checkCryptedLogin(user,password,dbsession,ipaddr=ipaddr)
|
|
292
200
|
|
|
293
201
|
@classmethod
|
|
294
202
|
def checkCryptedLogin(cls,user,password,dbsession,ipaddr = None):
|
|
295
|
-
|
|
203
|
+
# .filter(cls.password==password).filter(cls.enabled==1)
|
|
296
204
|
res = dbsession.query(cls).filter(cls.username==user) \
|
|
297
205
|
.options(joinedload('groups')) \
|
|
298
206
|
.options(joinedload('groups.permissions')) \
|
|
299
207
|
.all()
|
|
300
208
|
if len(res)==1:
|
|
301
209
|
res:PPSsuser = res[0]
|
|
302
|
-
|
|
210
|
+
# Hash the plaintext password with user's salt for comparison
|
|
211
|
+
password_with_salt = getPasswordDigest(password, salt=res.salt)
|
|
212
|
+
failcountquery = (
|
|
213
|
+
dbsession.query(PPSsloginhistory)
|
|
214
|
+
.filter(PPSsloginhistory.user_id == res.id)
|
|
215
|
+
.filter(PPSsloginhistory.result == LOGINREASON.VALIDATIONERROR[0])
|
|
216
|
+
.filter(
|
|
217
|
+
PPSsloginhistory.insertdt
|
|
218
|
+
> datetime.now() - timedelta(seconds=Conf.loginfailinterval)
|
|
219
|
+
)
|
|
220
|
+
)
|
|
303
221
|
if ipaddr:
|
|
304
222
|
failcountquery = failcountquery.filter(PPSsloginhistory.ipaddress == ipaddr)
|
|
305
223
|
failcount = failcountquery.count()
|
|
306
|
-
valid = LoginError(
|
|
307
|
-
|
|
224
|
+
valid = LoginError(
|
|
225
|
+
res.password == password_with_salt,
|
|
226
|
+
res.enabled == 1,
|
|
227
|
+
failcount > Conf.loginfailthreshold,
|
|
228
|
+
)
|
|
229
|
+
# res.password == password and res.enabled == 1
|
|
308
230
|
else:
|
|
309
231
|
res = None
|
|
310
232
|
valid = LoginError(None,None,None)
|
|
311
233
|
return res,valid
|
|
312
|
-
#return res[0] if len(res)==1 else None
|
|
234
|
+
# return res[0] if len(res)==1 else None
|
|
313
235
|
|
|
314
236
|
def passwordExpired(self,now = None):
|
|
315
237
|
if now is None:
|
|
316
238
|
now = datetime.now()
|
|
317
|
-
l.debug("user:{},now:{},expire:{},res:{}".format(self.username,now,self.passwordexpire,
|
|
318
|
-
|
|
239
|
+
l.debug("-------- user:{},now:{},expire:{},res:{}".format(self.username,now,self.passwordexpire,
|
|
240
|
+
not ((self.passwordexpire is None) or self.passwordexpire>now)))
|
|
241
|
+
|
|
242
|
+
notexpired = ((self.passwordexpire is None) or (self.passwordexpire>now))
|
|
243
|
+
return not notexpired
|
|
319
244
|
|
|
320
245
|
def is2faEnabled(self):
|
|
321
246
|
return bool(self.otp_hash)
|
|
322
247
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
248
|
+
__principals = None
|
|
249
|
+
def getPrincipals(self):
|
|
250
|
+
if self.__principals is None:
|
|
251
|
+
principals = [str("g:"+group.name ) for group in self.groups ]
|
|
252
|
+
if self.isSuperUser():
|
|
253
|
+
principals += ["g:admin","g:sysadmin"]
|
|
254
|
+
l.debug("++++ principals:{}".format(principals))
|
|
255
|
+
self.__principals = principals
|
|
256
|
+
|
|
257
|
+
return self.__principals,self.isSuperUser()
|
|
330
258
|
|
|
331
259
|
def todict(self):
|
|
332
260
|
return { "id": self.id, "username":self.username,"enabled":self.enabled}
|
|
333
261
|
|
|
334
|
-
|
|
335
262
|
def setPassword(self,password,canexpire = True):
|
|
336
|
-
|
|
263
|
+
if not self.salt:
|
|
264
|
+
self.salt = secrets.token_hex(16)
|
|
265
|
+
dig = getPasswordDigest(password, salt=self.salt)
|
|
337
266
|
self.password= dig
|
|
338
267
|
if Conf.passwordexpire and canexpire:
|
|
339
268
|
self.passwordexpire = datetime.now() + timedelta(days = Conf.passwordexpire)
|
|
269
|
+
else:
|
|
270
|
+
self.passwordexpire = None
|
|
340
271
|
self.passowrdhistory.append( PPSspasswordhistory(password = dig) )
|
|
341
272
|
return self
|
|
342
273
|
|
|
343
|
-
|
|
344
274
|
def getPermissions(self):
|
|
345
275
|
if self.permissionscache is None:
|
|
346
276
|
result = set()
|
|
@@ -383,11 +313,24 @@ class PPSsuser(Base,commonTable):
|
|
|
383
313
|
self.groupmapcache = set(grouplist)
|
|
384
314
|
return self.groupmapcache
|
|
385
315
|
|
|
386
|
-
|
|
387
316
|
def isInGroup(self,groupname,whitelie=True):
|
|
388
317
|
if self.isSuperUser() and whitelie:return True
|
|
389
318
|
return groupname in self.getGroupsMap()
|
|
390
319
|
|
|
320
|
+
def needVerifyOTP(self, request:Request):
|
|
321
|
+
since = datetime.now() - timedelta(hours=Conf.hoursvalid2fa)
|
|
322
|
+
# since = datetime.now() - timedelta(seconds=20)
|
|
323
|
+
success_login = (
|
|
324
|
+
request.dbsession.query(PPSsloginhistory)
|
|
325
|
+
.filter(PPSsloginhistory.user_id == self.id)
|
|
326
|
+
.filter(PPSsloginhistory.ipaddress == request.remote_addr)
|
|
327
|
+
.filter(PPSsloginhistory.result == LOGINREASON.OTPPASSED[0])
|
|
328
|
+
.filter(PPSsloginhistory.insertdt > since)
|
|
329
|
+
).first()
|
|
330
|
+
if success_login:
|
|
331
|
+
return False
|
|
332
|
+
return True
|
|
333
|
+
|
|
391
334
|
def __unicode__(self):
|
|
392
335
|
return u"<PPSsuser ({id}-{name},{enabled})>".format(id=self.id,name=self.username, enabled=self.enabled)
|
|
393
336
|
|
|
@@ -424,6 +367,15 @@ class PPSsloginhistory(Base):
|
|
|
424
367
|
resultreason = Column(Unicode(128))
|
|
425
368
|
username = Column(Unicode(128))
|
|
426
369
|
|
|
370
|
+
# result int
|
|
371
|
+
# -3 = invalid otp
|
|
372
|
+
# -2 = ??
|
|
373
|
+
# -1 = ?? blocked ?
|
|
374
|
+
# 0 = failed
|
|
375
|
+
# 1 = success
|
|
376
|
+
# 2 = logged in with otp
|
|
377
|
+
# 3 = logged in without otp
|
|
378
|
+
|
|
427
379
|
|
|
428
380
|
class PPSsgroup(Base,commonTable):
|
|
429
381
|
__tablename__ = 'ppss_group'
|
|
@@ -501,7 +453,3 @@ class DBVersion(Base):
|
|
|
501
453
|
else:
|
|
502
454
|
version.moduleversion = moduldeversion
|
|
503
455
|
version.dbversion = "1.0"
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|