1
0
mirror of https://github.com/dkmstr/openuds.git synced 2024-12-24 21:34:41 +03:00

Improved passwords security on DB

This commit is contained in:
Adolfo Gómez García 2022-03-07 23:10:10 +01:00
parent b477b78d61
commit 05a04997d6
6 changed files with 51 additions and 30 deletions

View File

@ -32,6 +32,7 @@
"""
import logging
import random
import operator
import typing
from django.utils.translation import gettext as _
@ -968,6 +969,8 @@ class UserServiceManager(metaclass=singleton.Singleton):
poolMembers = [
p for p in meta.members.all() if p.pool.isVisible() and p.pool.isUsable()
]
# Sort pools array. List of tuples with (priority, pool)
sortPools: typing.List[typing.Tuple[int, ServicePool]]
# Sort pools based on meta selection
if meta.policy == MetaPool.PRIORITY_POOL:
sortPools = [(p.priority, p.pool) for p in poolMembers]
@ -981,7 +984,7 @@ class UserServiceManager(metaclass=singleton.Singleton):
# Sort pools related to policy now, and xtract only pools, not sort keys
# split resuult in two lists, 100% full and not 100% full
# Remove "full" pools (100%) from result and pools in maintenance mode, not ready pools, etc...
sortedPools = sorted(sortPools, key=lambda x: x[0])
sortedPools = sorted(sortPools, key=operator.itemgetter(0)) # sort by priority (first element)
pools: typing.List[ServicePool] = [
p[1] for p in sortedPools if p[1].usage() < 100 and p[1].isUsable()
]

View File

@ -49,7 +49,7 @@ USERSERVICE_TAG = 'cm-'
# This will be executed on current service state for checking transitions to new state, task states, etc..
class StateUpdater:
userService: UserService
userServiceInstalce: UserDeployment
userServiceInstance: UserDeployment
def __init__(
self,

View File

@ -39,13 +39,23 @@ import typing
import logging
from django.utils.translation import get_language, gettext as _, gettext_noop
from django.conf import settings
from uds.core.managers import cryptoManager
logger = logging.getLogger(__name__)
# Old encryption key
UDSB = b'udsprotect'
# Separators for fields
MULTIVALUE_FIELD = b'\001'
OLD_PASSWORD_FIELD = b'\004'
PASSWORD_FIELD = b'\005'
FIELD_SEPARATOR = b'\002'
NAME_VALUE_SEPARATOR = b'\003'
class gui:
"""
@ -905,8 +915,9 @@ class UserInterfaceType(type):
) -> 'UserInterfaceType':
newClassDict = {}
_gui: typing.MutableMapping[str, gui.InputField] = {}
# We will keep a reference to gui elements also at _gui so we can access them easily
# Later on init method to update the class 'self' with the new copy
# Make a copy of gui fields description
# (we will update references on class 'self' to the new copy)
for attrName, attr in namespace.items():
if isinstance(attr, gui.InputField):
_gui[attrName] = attr
@ -939,10 +950,12 @@ class UserInterface(metaclass=UserInterfaceType):
# has its own "field" set, and do not share the "fielset" with others, what
# can be really dangerous. Till now, nothing bad happened cause there where
# being used "serialized", but this do not have to be this way
self._gui = copy.deepcopy(
self._gui
) # Ensure "gui" is our own instance, deep copied from base
for key, val in self._gui.items(): # And refresh references to them
# Ensure "gui" points to a copy of original gui, not the original one
# this is done to avoid modifying the original gui description
self._gui = copy.deepcopy(self._gui)
for key, val in self._gui.items(): # And refresh self references to them
setattr(self, key, val)
if values is not None:
@ -1039,10 +1052,10 @@ class UserInterface(metaclass=UserInterfaceType):
gui.InputField.MULTI_CHOICE_TYPE
):
# logger.debug('Serializing value {0}'.format(v.value))
val = b'\001' + pickle.dumps(v.value, protocol=0)
val = MULTIVALUE_FIELD + pickle.dumps(v.value, protocol=0)
elif v.isType(gui.InfoField.PASSWORD_TYPE):
val = b'\004' + cryptoManager().AESCrypt(
v.value.encode('utf8'), UDSB, True
val = PASSWORD_FIELD + cryptoManager().AESCrypt(
v.value.encode('utf8'), settings.SECRET_KEY.encode(), True
)
elif v.isType(gui.InputField.NUMERIC_TYPE):
val = str(int(v.num())).encode('utf8')
@ -1055,10 +1068,10 @@ class UserInterface(metaclass=UserInterfaceType):
elif val is False:
val = gui.FALSE.encode('utf8')
arr.append(k.encode('utf8') + b'\003' + val)
arr.append(k.encode('utf8') + NAME_VALUE_SEPARATOR + val)
logger.debug('Arr, >>%s<<', arr)
return codecs.encode(b'\002'.join(arr), 'zip')
return codecs.encode(FIELD_SEPARATOR.join(arr), 'zip')
def unserializeForm(self, values: bytes) -> None:
"""
@ -1084,20 +1097,26 @@ class UserInterface(metaclass=UserInterfaceType):
if not values: # Has nothing
return
for txt in values.split(b'\002'):
kb, v = txt.split(b'\003')
k = kb.decode('utf8') # Convert name to unicode
for txt in values.split(FIELD_SEPARATOR):
kb, v = txt.split(NAME_VALUE_SEPARATOR)
k = kb.decode('utf8') # Convert name to string
if k in self._gui:
try:
if v and v[0] == 1:
if v.startswith(MULTIVALUE_FIELD):
val = pickle.loads(v[1:])
elif v and v[0] == 4:
elif v.startswith(OLD_PASSWORD_FIELD):
val = cryptoManager().AESDecrypt(v[1:], UDSB, True).decode()
elif v.startswith(PASSWORD_FIELD):
val = (
cryptoManager()
.AESDecrypt(v[1:], settings.SECRET_KEY.encode(), True)
.decode()
)
else:
val = v
# Ensure "legacy bytes" values are loaded correctly as unicode
if isinstance(val, bytes):
val = val.decode('utf_8')
val = val.decode('utf8')
except Exception:
logger.exception('Pickling {} from {}'.format(k, self))
val = ''
@ -1127,11 +1146,9 @@ class UserInterface(metaclass=UserInterfaceType):
obj.initGui() # We give the "oportunity" to fill necesary theGui data before providing it to client
theGui = obj
res: typing.List[typing.MutableMapping[str, typing.Any]] = []
for key, val in theGui._gui.items():
logger.debug('%s ### %s', key, val)
res.append({'name': key, 'gui': val.guiDescription(), 'value': ''})
logger.debug('>>>>>>>>>>>> Gui Description: %s -- %s', obj, res)
res: typing.List[typing.MutableMapping[str, typing.Any]] = [
{'name': key, 'gui': val.guiDescription(), 'value': ''}
for key, val in theGui._gui.items()
]
logger.debug('theGui description: %s', res)
return res

View File

@ -47,7 +47,6 @@ from ldap import (
SCOPE_SUBTREE, # type: ignore
SCOPE_ONELEVEL, # type: ignore
SCOPE_SUBORDINATE, # type: ignore
INVALID_CREDENTIALS, # type: ignore
)

View File

@ -31,6 +31,7 @@
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
"""
import logging
import operator
import typing
from django.db import models
@ -165,7 +166,7 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
access = self.fallbackAccess
# Let's see if we can access by current datetime
for ac in sorted(self.calendarAccess.all(), key=lambda x: x.priority):
for ac in sorted(self.calendarAccess.all(), key=operator.attrgetter('priority')):
if CalendarChecker(ac.calendar).check(chkDateTime):
access = ac.access
break # Stops on first rule match found

View File

@ -32,9 +32,10 @@
"""
import typing
import logging
import operator
import pickle
from datetime import datetime, timedelta
from uds.core.util.states import publication
from django.db import models, transaction
@ -336,7 +337,7 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
access = self.fallbackAccess
# Let's see if we can access by current datetime
for ac in sorted(self.calendarAccess.all(), key=lambda x: x.priority):
for ac in sorted(self.calendarAccess.all(), key=operator.attrgetter('priority')):
if CalendarChecker(ac.calendar).check(chkDateTime):
access = ac.access
break # Stops on first rule match found